From d8e1d04583007816f5dc77595d322ba669075ae3 Mon Sep 17 00:00:00 2001 From: pvtroshin Date: Tue, 21 Jun 2011 14:25:36 +0000 Subject: [PATCH] new version of tcoffee 8.99 not yet compiled for ia32 linux (currently compiled for dundee cluster) git-svn-id: link to svn.lifesci.dundee.ac.uk/svn/barton/ptroshin/JABA2@4298 e3abac25-378b-4346-85de-24260fe3988d --- binaries/src/tcoffee/README | 50 + binaries/src/tcoffee/bin/binaries/linux/t_coffee | Bin 0 -> 1941017 bytes binaries/src/tcoffee/install | 2004 +++ binaries/src/tcoffee/license.txt | 348 + .../t_coffee_source/CUSTOM_evaluate_for_struc.c | 460 + binaries/src/tcoffee/t_coffee_source/TMalign.f | 2554 +++ binaries/src/tcoffee/t_coffee_source/aln_compare.c | 1284 ++ .../tcoffee/t_coffee_source/aln_convertion_util.c |18008 ++++++++++++++++++++ .../src/tcoffee/t_coffee_source/define_header.h | 785 + binaries/src/tcoffee/t_coffee_source/dev1.c | 133 + .../src/tcoffee/t_coffee_source/dev1_lib_header.h | 31 + binaries/src/tcoffee/t_coffee_source/dev2.c | 43 + .../src/tcoffee/t_coffee_source/dev2_lib_header.h | 30 + binaries/src/tcoffee/t_coffee_source/dev3.c | 36 + .../src/tcoffee/t_coffee_source/dev3_lib_header.h | 31 + binaries/src/tcoffee/t_coffee_source/dev4.c | 42 + .../src/tcoffee/t_coffee_source/dev4_lib_header.h | 30 + binaries/src/tcoffee/t_coffee_source/diagonal.c | 475 + .../src/tcoffee/t_coffee_source/dp_lib_header.h | 842 + binaries/src/tcoffee/t_coffee_source/evaluate.c | 5477 ++++++ .../tcoffee/t_coffee_source/evaluate_dirichlet.c | 599 + .../tcoffee/t_coffee_source/evaluate_for_domain.c | 311 + .../tcoffee/t_coffee_source/evaluate_for_struc.c | 2854 ++++ .../src/tcoffee/t_coffee_source/fast_tree_header.h | 144 + binaries/src/tcoffee/t_coffee_source/fastal.c | 4272 +++++ .../tcoffee/t_coffee_source/fastal_lib_header.h | 367 + .../tcoffee/t_coffee_source/fastal_opt_parsing.c | 258 + binaries/src/tcoffee/t_coffee_source/fsa_dp.c | 2541 +++ binaries/src/tcoffee/t_coffee_source/header_list | 13 + binaries/src/tcoffee/t_coffee_source/hsearch.c | 290 + binaries/src/tcoffee/t_coffee_source/io_func.c | 1532 ++ .../src/tcoffee/t_coffee_source/io_lib_header.h | 1120 ++ binaries/src/tcoffee/t_coffee_source/iteration.c | 610 + binaries/src/tcoffee/t_coffee_source/makefile | 11 + binaries/src/tcoffee/t_coffee_source/matrices.h | 1009 ++ binaries/src/tcoffee/t_coffee_source/parttree.c | 1495 ++ binaries/src/tcoffee/t_coffee_source/pavie_dp.c | 1411 ++ .../t_coffee_source/pb_util_read_seq_util.c | 374 + .../t_coffee_source/pb_util_read_sequence.c | 562 + .../src/tcoffee/t_coffee_source/perl_header_lib.h | 8586 ++++++++++ binaries/src/tcoffee/t_coffee_source/random.c | 94 + binaries/src/tcoffee/t_coffee_source/reformat.c |12795 ++++++++++++++ .../src/tcoffee/t_coffee_source/reformat_struc.c | 1095 ++ binaries/src/tcoffee/t_coffee_source/scoring.c | 655 + binaries/src/tcoffee/t_coffee_source/showpair.c | 560 + binaries/src/tcoffee/t_coffee_source/source_list | 55 + binaries/src/tcoffee/t_coffee_source/t_coffee | Bin 0 -> 1941017 bytes binaries/src/tcoffee/t_coffee_source/t_coffee.c | 5531 ++++++ binaries/src/tcoffee/t_coffee_source/t_coffee.h | 31 + binaries/src/tcoffee/t_coffee_source/tree.c | 459 + binaries/src/tcoffee/t_coffee_source/tree_util.c | 5302 ++++++ binaries/src/tcoffee/t_coffee_source/util.c | 8569 ++++++++++ .../src/tcoffee/t_coffee_source/util_aln_analyze.c | 6379 +++++++ .../util_analyse_constraints_list.c | 41 + .../t_coffee_source/util_constraints_list.c | 6277 +++++++ .../src/tcoffee/t_coffee_source/util_declare.c | 1942 +++ .../t_coffee_source/util_domain_constraints_list.c | 65 + .../src/tcoffee/t_coffee_source/util_domain_dp.c | 569 + .../t_coffee_source/util_domain_dp_drivers.c | 681 + .../t_coffee_source/util_dp_cdna_fasta_nw.c | 974 ++ .../tcoffee/t_coffee_source/util_dp_clean_maln.c | 384 + .../src/tcoffee/t_coffee_source/util_dp_drivers.c | 4596 +++++ binaries/src/tcoffee/t_coffee_source/util_dp_est.c | 89 + .../src/tcoffee/t_coffee_source/util_dp_fasta_nw.c | 1831 ++ .../src/tcoffee/t_coffee_source/util_dp_fasta_sw.c | 64 + .../t_coffee_source/util_dp_generic_fasta_nw.c | 378 + .../src/tcoffee/t_coffee_source/util_dp_gotoh_nw.c | 2413 +++ .../src/tcoffee/t_coffee_source/util_dp_gotoh_sw.c | 585 + .../src/tcoffee/t_coffee_source/util_dp_mm_nw.c | 371 + binaries/src/tcoffee/t_coffee_source/util_dp_sim.c | 1163 ++ .../tcoffee/t_coffee_source/util_dp_ssec_pwaln.c | 476 + .../t_coffee_source/util_dp_suboptimal_nw.c | 1725 ++ binaries/src/tcoffee/t_coffee_source/util_dps.c | 44 + .../src/tcoffee/t_coffee_source/util_graph_maln.c | 539 + .../tcoffee/t_coffee_source/util_job_handling.c | 362 + .../src/tcoffee/t_coffee_source/util_lib_header.h | 2802 +++ .../src/tcoffee/t_coffee_source/util_make_tree.c | 1472 ++ binaries/src/tcoffee/tclinkdb.txt | 357 + 78 files changed, 132747 insertions(+) create mode 100644 binaries/src/tcoffee/README create mode 100644 binaries/src/tcoffee/bin/binaries/linux/t_coffee create mode 100644 binaries/src/tcoffee/install create mode 100644 binaries/src/tcoffee/license.txt create mode 100644 binaries/src/tcoffee/t_coffee_source/CUSTOM_evaluate_for_struc.c create mode 100644 binaries/src/tcoffee/t_coffee_source/TMalign.f create mode 100644 binaries/src/tcoffee/t_coffee_source/aln_compare.c create mode 100644 binaries/src/tcoffee/t_coffee_source/aln_convertion_util.c create mode 100644 binaries/src/tcoffee/t_coffee_source/define_header.h create mode 100644 binaries/src/tcoffee/t_coffee_source/dev1.c create mode 100644 binaries/src/tcoffee/t_coffee_source/dev1_lib_header.h create mode 100644 binaries/src/tcoffee/t_coffee_source/dev2.c create mode 100644 binaries/src/tcoffee/t_coffee_source/dev2_lib_header.h create mode 100644 binaries/src/tcoffee/t_coffee_source/dev3.c create mode 100644 binaries/src/tcoffee/t_coffee_source/dev3_lib_header.h create mode 100644 binaries/src/tcoffee/t_coffee_source/dev4.c create mode 100644 binaries/src/tcoffee/t_coffee_source/dev4_lib_header.h create mode 100644 binaries/src/tcoffee/t_coffee_source/diagonal.c create mode 100644 binaries/src/tcoffee/t_coffee_source/dp_lib_header.h create mode 100644 binaries/src/tcoffee/t_coffee_source/evaluate.c create mode 100644 binaries/src/tcoffee/t_coffee_source/evaluate_dirichlet.c create mode 100644 binaries/src/tcoffee/t_coffee_source/evaluate_for_domain.c create mode 100644 binaries/src/tcoffee/t_coffee_source/evaluate_for_struc.c create mode 100644 binaries/src/tcoffee/t_coffee_source/fast_tree_header.h create mode 100644 binaries/src/tcoffee/t_coffee_source/fastal.c create mode 100644 binaries/src/tcoffee/t_coffee_source/fastal_lib_header.h create mode 100644 binaries/src/tcoffee/t_coffee_source/fastal_opt_parsing.c create mode 100644 binaries/src/tcoffee/t_coffee_source/fsa_dp.c create mode 100644 binaries/src/tcoffee/t_coffee_source/header_list create mode 100644 binaries/src/tcoffee/t_coffee_source/hsearch.c create mode 100644 binaries/src/tcoffee/t_coffee_source/io_func.c create mode 100644 binaries/src/tcoffee/t_coffee_source/io_lib_header.h create mode 100644 binaries/src/tcoffee/t_coffee_source/iteration.c create mode 100644 binaries/src/tcoffee/t_coffee_source/makefile create mode 100644 binaries/src/tcoffee/t_coffee_source/matrices.h create mode 100644 binaries/src/tcoffee/t_coffee_source/parttree.c create mode 100644 binaries/src/tcoffee/t_coffee_source/pavie_dp.c create mode 100644 binaries/src/tcoffee/t_coffee_source/pb_util_read_seq_util.c create mode 100644 binaries/src/tcoffee/t_coffee_source/pb_util_read_sequence.c create mode 100644 binaries/src/tcoffee/t_coffee_source/perl_header_lib.h create mode 100644 binaries/src/tcoffee/t_coffee_source/random.c create mode 100644 binaries/src/tcoffee/t_coffee_source/reformat.c create mode 100644 binaries/src/tcoffee/t_coffee_source/reformat_struc.c create mode 100644 binaries/src/tcoffee/t_coffee_source/scoring.c create mode 100644 binaries/src/tcoffee/t_coffee_source/showpair.c create mode 100644 binaries/src/tcoffee/t_coffee_source/source_list create mode 100644 binaries/src/tcoffee/t_coffee_source/t_coffee create mode 100644 binaries/src/tcoffee/t_coffee_source/t_coffee.c create mode 100644 binaries/src/tcoffee/t_coffee_source/t_coffee.h create mode 100644 binaries/src/tcoffee/t_coffee_source/tree.c create mode 100644 binaries/src/tcoffee/t_coffee_source/tree_util.c create mode 100644 binaries/src/tcoffee/t_coffee_source/util.c create mode 100644 binaries/src/tcoffee/t_coffee_source/util_aln_analyze.c create mode 100644 binaries/src/tcoffee/t_coffee_source/util_analyse_constraints_list.c create mode 100644 binaries/src/tcoffee/t_coffee_source/util_constraints_list.c create mode 100644 binaries/src/tcoffee/t_coffee_source/util_declare.c create mode 100644 binaries/src/tcoffee/t_coffee_source/util_domain_constraints_list.c create mode 100644 binaries/src/tcoffee/t_coffee_source/util_domain_dp.c create mode 100644 binaries/src/tcoffee/t_coffee_source/util_domain_dp_drivers.c create mode 100644 binaries/src/tcoffee/t_coffee_source/util_dp_cdna_fasta_nw.c create mode 100644 binaries/src/tcoffee/t_coffee_source/util_dp_clean_maln.c create mode 100644 binaries/src/tcoffee/t_coffee_source/util_dp_drivers.c create mode 100644 binaries/src/tcoffee/t_coffee_source/util_dp_est.c create mode 100644 binaries/src/tcoffee/t_coffee_source/util_dp_fasta_nw.c create mode 100644 binaries/src/tcoffee/t_coffee_source/util_dp_fasta_sw.c create mode 100644 binaries/src/tcoffee/t_coffee_source/util_dp_generic_fasta_nw.c create mode 100644 binaries/src/tcoffee/t_coffee_source/util_dp_gotoh_nw.c create mode 100644 binaries/src/tcoffee/t_coffee_source/util_dp_gotoh_sw.c create mode 100644 binaries/src/tcoffee/t_coffee_source/util_dp_mm_nw.c create mode 100644 binaries/src/tcoffee/t_coffee_source/util_dp_sim.c create mode 100644 binaries/src/tcoffee/t_coffee_source/util_dp_ssec_pwaln.c create mode 100644 binaries/src/tcoffee/t_coffee_source/util_dp_suboptimal_nw.c create mode 100644 binaries/src/tcoffee/t_coffee_source/util_dps.c create mode 100644 binaries/src/tcoffee/t_coffee_source/util_graph_maln.c create mode 100644 binaries/src/tcoffee/t_coffee_source/util_job_handling.c create mode 100644 binaries/src/tcoffee/t_coffee_source/util_lib_header.h create mode 100644 binaries/src/tcoffee/t_coffee_source/util_make_tree.c create mode 100644 binaries/src/tcoffee/tclinkdb.txt diff --git a/binaries/src/tcoffee/README b/binaries/src/tcoffee/README new file mode 100644 index 0000000..e042d9a --- /dev/null +++ b/binaries/src/tcoffee/README @@ -0,0 +1,50 @@ +README for T-Coffee installation version 6.70 and higer + +UNIX/LINUX/Mac OSX + +T-Coffee requires gcc, g77, makefile, CPAN, an internet connection and your root password + + + 1. Download and save the Package + 2. gunzip t_coffee.tar.gz + 3. tar -xvf t_coffee.tar + 4. cd T-COFFEE_distribution_Version_X.XX + 5. ./install + +This installation procedure is semi-interactive. It will prompt questions here and there. You can interrupt it any time and resume it later. + + +The install procedure carries out three distinct tasks: Compilation of T-Coffee (C program), Compilation and Installation of SOAP::Lite (Perl Module), Download/Compilation and Installation of all the T-Coffee companion packages required for all possible T-Coffee flavors (tcoffee,expresso,3dcoffee,mcoffee,rcoffee). Except for T-Coffee, the installer will only install the packages that are NOT already on your computer. If you want a lighter or more specific installation, you can try any of the following: + + + 1. ./install tcoffee + 2. ./install rcoffee + 3. ./install expresso + 4. ./install 3dcoffee + 5. ./install 3dcoffee + + +While Installing SOAP::Lite, CPAN will ask you many questions: say Yes to all or type return to keep the default values. If everything went well, the procedure has created in the bin directory two executables: t_coffee and TMalign (Make sure these executables are on your $PATH!). + + +If you have not managed to install SOAP::Lite, you can re-install it anytime (from anywhere) using steps 1-2 + +If you cannot log as root, or if for some reason this procedure does not work, see with your system manager and/or go directly to the CPAN repository of SOAP::Lite. You will still be able to use the most basic functions of T-Coffee. + + + +IMPORTANT: The purpose of SOAP::Lite is to allow T-Coffee the use of the EBI webservices such as webblast. BLAST brings many functionalities to T-Coffee and if you cannot install SOAP we suggest you go to the Installing BLAST for T-Coffee section of the Technical Doumentation (in the Installation section). There you will find alternative ways of using BLAST without SOAP. It is also in this document that you will find all the information required for a full installation of T-Coffee + +Microsoft Windows/Cygwin + +Install Cygwin + + * Download The Installer (NOT Cygwin/X) + * Click on view to list ALL the packages + * Select: gcc-core, make, wget + * Optional: ssh, xemacs, nano + * Run mkpasswd in Cywin (as requested when you start cygwin) + +Install T-Coffee within Cygwin using the Unix procedure (see above) + + diff --git a/binaries/src/tcoffee/bin/binaries/linux/t_coffee b/binaries/src/tcoffee/bin/binaries/linux/t_coffee new file mode 100644 index 0000000000000000000000000000000000000000..581db9bfaa23a0c348e1e3f646432c863eddb33a GIT binary patch literal 1941017 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

3bUQSFI_Xw5uvONkgwQ6x(Hke-3O%Qy#Jou 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%0DhpC5h1gihSV-s6k(rX*(R(pqa^n|1eAnTx^| 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

Wf3mGvIYn4lZfZ> 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ⅆ6r`4us;y6U730MnLH4m!OMQP6xHKEnbF&y6H z%CcoRm9T3GHZi)DI5ljZ-iMgls9tSjR%QGv8M+PzkICBG?ERBTZwXF)aHNm3@-3O2%dtCjU|+y4R97x`~SbH6vrM>qFLgpO6VWybDKW` zFUeEx-VL8B-0R^}wR<6aO1RbGQ>{zui3xc;Oqt>y2%o09U-JY*`?)1(-GVkxpL^^z z%qpGgzWZr_!22*ezy_W~AO2v-`wF876v>Yd784HUtN5II^mxQ3X zYeaxvEx%IghxhAZn~iSBN=&lRwAMcxDO2xShRd~aR_QEKYooWd#`4=hG#vt**Pmk@6H8~#o7g)qGlE8N479s*(N`rsl<%#@IgyQsuAW?V2mFS8my z6ha!O7M0FnR+A}of6BU7IZ`K#7Qe&{Db)whC^1VSHu3+!HSTt~xp*j4aE>?K*pH== zNCWu=MGdW0zE04t7qqWK#v+LPQ&~BXAZ>#3(}#W)A9uPD&~ za%k(a&-)H~cG?T#AcJ0H>w6e;?ETYKQm2aqgxODQZC#gyl=R|rXxEI?)3=L z4wnqgEfXsN_>7YLs+0dH{d;-fb%ppym$X`Eo|W>IZRVh$89cGIh|H#5`y=H3wWQGZ z0~<^~8o6|$AkrKBGl7wL1+SO27nROR_^`i3-DIAa@4s#_0_QQ16;Ipys?1-zS6@u^ z9S?quzK{@iPRUq_(g2EmDFy9VrV-tF?<&)sH%rOPt~rn7Q&yKaP|w|UiIYK_@FU3U zb}*Mcz8}T+E+GpH-JI>>XJ`({wDesJ*VJMT2G_lqObs)ueNEjJ(QmScV) zxRiTNvj=N??ucOG&X#oC9ua!@ zta3kA&bccMCRvX$(=p}4*69kicb8r5ZWNdJ7-~>mmz7B3XC(ezeRq?t$Kn0n!pBZv zA<@kWM8*Mk>7UJHwBh<3u`iRWZ)mm*FWq3eq{DVY}aqE%{Spl2sQ{n>3xj(Je03Sd{NdsH1Vs@uPod?HTBio!Jeg|dx+h>e_HZ1kS+_fGne z*TB@bSd_g{sg5vr16A0sdYN~Z_*{(E4g~%wF8nj^rDH$Pu;s28`f}s0SdH@3`=^wt zSfFSFZfiePs{k! z!yeFeAEI3Vhzmcb1ay1e-1if3cz{)i1`^nLzWhWO8-}>Db@M9mk0LjqSZK#M+628m zFMi$`TRh^%3BZNDQ2twxBD=`b3IO}CwwM=Y;v842DE&nRZS!z zm@I?Hb7M|b03rj^p6>^F3+(q*SyamDrc4TD{K}4?U_nV)T9gh&^8+lKRTGoZHD2tG z+4~;D&SrIlsv-c%Z?RXb=pp*amfPILL6& zxxh&AoIf|Shr=at%`bS94oyzu2ekcTwq7`wjJ*xhpj;oEJOYCkLyV`X@l&nl0J&rHDatGU0lg zoWxMiH2oA#O4oThZ6+(n!GD&mV1;{DohCCJof0*v+s&?s^u@TJ3hX8+Sr$1Dn=V@} zpz#M#x_xvdPzm2Dx{r|Ww`~RkGof%)8c>z3X?ys}< z##T@nuvCM`fxYq1&%(lAGC7dMFof)`Fk>U7PN5We`;)ihk6rOda{dP4&f-j2H!&I| z1g`3wwR^2*2JvXy3R0NYyFUm}SUO%v z`l>2s})Tx)iE`t>|?Z2gjlOo?^MLL@9p))9^%)KjoM zTJ#ll%F(GQG&34=q~Z&F%Q~g)Z8}xB$OcHK5N9P}r;a6etn$3#MmAzMB~pZ`b$9;O zy0!rUFW-y=bX+rcrA&-sdk-HC_)|0UO&~e{LrDs4IY?buWmB_$iK4TnKfD_W?sKh> zz4AHTsX&p}krK$=O)yf;MTwDQdV{DA93;jdjjA`S3VC6&vfBcawV8r9-!L&a>o(LrJd9s;a1#y#XH4sX`s~ z9A+YjPqB&v^&C|Ht%&exeBK0(h7OtDZTw>bH5yD`ku%kPe`u&ii~ZM-H?zqYSk-ZN zXL-pyCJS8qWC%vgy=@1rs+fb5 zyRpLIyHxMx#+m2?B)JO}j?Wg_9u^WcUaCU((3$T13V%FSLZMaFj?B${e>gr>xyId!1tJt)KkGGqpk(}j4frYHur~C`M&5V@He;p8x%`Iq)@M$PFV`D zNVP*5|FSZ$7Cv3CVqvvzCie$uEj%EX()LZ^Z?xq>#E*E_&bwL7~izW z!WWcqG(w%r2;fBu1L0Fw@);y6396icl>9sPH=ufhe9hdXe+G+VEtZT?EKl2N?WAWv z2OHPh(hVKTbq+DK6Vrdm+3HOb)ze>27J{IjP41*h?I^75_y@)Tb?un&y{&8hO`#f|jONyN90*Isjur>tE$!i+ERG+THPb^oODJ7?6>|esuTWq`)sqcPs$Q}Eq5<3QqS7+^eabfRV6&Qq6$`rS z^WD}jp*D}&i^xp4K%ZafzQa?u^^3vnyL+k!8^b}&y4MtW?f%rllWc<%DeWd7DY<|@ zXSn>BI3S=A!k1_mXC5ORp87Q2_UiGF0=}c}%RRVfV+K2DHumZ_b7Pe@pVjU))-u!X zzecMMjwXLVLMIZu`T zq8|^@mOD%=ZgUd}*QYZ&w;}XHKjOKc=O41i=h5av(Cs`sA*Bop$zTy8}Qx*AjP0SdaqnE71uRY7abI&oi< z`o-!Jx+ZV}R(EL7wLOgn*1I2Xqt&@9H&A`<1R_x##GKPV%udY*zYnHnyX6X|hV^ma zInPBm_2ERVvV4oD^_-}izWH%yFe}=q=$e)0%MhJ4Fg{I^G{N)8m^qWg^ge8jipcB3 zhAS|hCZ3#r&D9qQY&B2*&!Cj>ej%VHyrYn{Q+2hfRPtT~BgjOsnQ%X zjEeiA4)4+KA2rIEVY@G~++mcbB~nJeHRj|mIEZU(zX zo%E(~n5eqwVvcHPTrFY!GlKdjC!W0YimU4`xZ?cjVN3sgbs^>_mV|w{I13joX~q|} zap}3+d>GWWRfG9a*w}7CW6A7bo~*xkMm_X4t*bF;DHx0nZ3TFjJG50@7#`v6JLBTE z>b>$ZbJ=)G|2(Yx_pH98oc&y=7(#1FHn?@o6Cp*PU$gj%OQ)YdqkdXl*yW^m`+o(# z905?J=57~yE~+{;JEJ=6(SLLJMeED^4)d%Fce;*1k)+(<0+OWT$1&4A5 zq<KT-f_A$R)h#h0J#dwjN#o%Hd}> zk?x=tEmhm@YHPURhm3F+8r{5qc38$_`l>wS^6j1H`js%FXUq8feAw)fVY4@PL8RtuFfiBbe~EY9 zAw{!^LM9Nb&2zsve z=$b(>OmAjk4&kyW*44{w_r5&%KXk7rnNUGieEo$>P1760j;{aJS2~(V=Lq4693fe}zhX39pfo&# zki!Xo;Gq8i(KYAv=-$;tElBqcmBc&mG1)OLJK0Yebsh_ge=^IqliqLtCw;0lj-EL{ zgYOsCUTL+5=Vn5F`($>OYI2boa@cNs-PqE9r+6lj9$#fwza0n|{NP+?7gJEU%!d?G zgIKqVh14EyguU7$LxuYm%Vo~%dgLEb6ZON1nn+^qXPcE$Jy|IYf6Yu2%m#*|s{3Vt zd&`tN991sf1hV6bi?0#;$c@Sv+5ccv)n7BJzaRMja8y6}lu;cSjw*HcS4Q>!OtgG< z!2ijpSfzb+uA)KW*UZ(^pD?PS;i&%d3yliD#(0=;pCvRjbQ2t1Yz!I;Wn(vL3l+gG z)l3{J=9_MoCEIRNk=ruulk3kQyX1XlJ9oOIV_`2!f?mY`FM1)SW3HCzGr~%ryDOMM z?eUrh|3qD|$g4{%x#%h_TBcnSiq&rIvgr9b0GI|JAa^%d1eB-MA$m*yi&-mPc*WH- z8m>J4*h|=foOxxvEIHFz2mc_?T~VJqXbrUH0oX2R(0=wEF26uX6D zp8d`I7S!zApR^7kb5ZZ0Mfp*CxH`7ZVc+xQGCr|3R{{5$+X4Y>;1F>!Y%XVN6Uc+lt z{?T@Ld~UmrZl+}=afj~*)u6uK-m1-SBJ=i)e;b$G1lI`5`z{=hm%woB;61u5&smwnN4mBA|3lr$D!$KX-3r) z{Y=x@Fw62YkuHi=oGiq2Bb0or0^ee}b)QYfim8jJ@1+wpso6VSpJxN(Sm%rSeN~1c z9Ws%TOovWnFzSBTBQ;&C!o+iws70s}+rq>#O4JHb zi4TW~LzO5UT8Vdsi363WwVo1h3KRP%QM$4cuL%KpvTo$w@&j(qJgNn-%uTAPcTn}?X)ine zI}8umL)qjk-XO8f-d2f)VTKpGWw=R3Dl(WEL~59-e8e);4>wt_gkJ?EzN;z+SeVrS zr*W}dk8uEt6MWE*Ohw7 z>LB$()%LHjwh3S9+uy}7C_G%*-V3uG^_6Th-w3klPTBOQVYY&xZ+<#2?Aw;x3=zciQUzmS!O1;)b*^@z7;z1GYGAL5?8L6g6F(lse)SwS2w>yu+##U+Qf*uWw|(rFolC{Z@Cq8p9VCL&OULrdw&r*?we&vm-OkRXBG(!seb^@EmJ@=U zf5_$}n>f)?OruXT2 z>bBpv*Eo3|(6x>edyFn!@qaKZK(X$6^EbLzD4!jj3{{zfB;;kaGw*+Q;PcXJr_osAA)FX7P`^1 zw&LRclyV^+9yV{!o}ghDD^BoK9DJedAMIh39oPeN^i9zAkiKUhlBMrUgPh&yTcO=W z-;aI28x1eK)#$tB-)12&q^KG}H=zM08Tvh~uhDNAX>QL|J?Xb;)>rAbll%ew{t4Ts z^*`Y+urMlhqYCYAr>3g4djW`~KNwD+UFNz`eUqsXtAwPuE}V$FESDaLNFnVK-i&T7 z$w<}Euuw%oLGw_G*pF3LU2*fR{$>oeAt=Sv8Db#FgklTtUNqf`$W9u(N_+X=l-% znz~#&Qwuxpp!LUDmFC#{Pg4PV&qw2fY#;eSmTWhJ*IBad{|RKf9?b7XDw|gusr35> zL~$IS0#fWTB`A}#b1>;#s$E0zo4>=f#XM5?;bpJ7N+WZrs>Q`t}#5A$dA zO{7lg8=wyr;DLW#v75qYv1ibZ(9u*k-5u?8!hIHJYP>dA!i)T{xU-h_$D8x!OfE*i zL!jE7@n>98se7h{j8YlU4cDTWUsGP=PpELml0m^YsC}jdE3$j6A86mESd92Y#7n2j zUF$?qddOI-#i?-0igAEr;2#h$j_5@Hbj44~7uLK-3&J2}l_QHASC1B>Q1s>@=m2#C z|1A2cwJLH&-&jIXFIy_ctx3g=FKJBW*7v0M_oR19u^aQMX12+oEoihi3I6(rw!wk6 znTnfUtpiMRNYkPi(N;Wk9cNijj`@A>=4z1i3Gx~+XQA=C2?x#dWp+*DjCu>|tX@GE1()R+aIJ?;U zk)eqHy<>Obp9xqCl6Z;_8#@ zA~yi<7Dkxo_upSQR-%yLvMh;*LE(zlmKU@05BM-93v_icBbv?~R3X}*mKuCKipfz; z6uph&(lz>u}m4y47iLyt429(bVb4!2sf^YQ7P@Y$W%k1XoLOt}kt>&7YQl7)<5( zAgcX`Pw2Jk1Ul(%uxALs|6V!%S?-1>^=&f#M!}qo!m~0_B!5Sl9=z4v_*rm(q>$db zyH*PGdcRXBLCbm|Hp$`*#m=-~cW0i#EdnUUGoh653=$kqd;r$5mf?f_(dN}W4Bc8& z_km0QTYWHQ2{Pc0m=q!yT?!!FRIoe}<5o-w8QATFLT=A8eo^8I%;BgV&ne}^75&5L zgXM&E%YUt4dc+;~`nJy0uyeQqPd@0s`)e3Hj@6$kPq>#?*fkk&liB@;zCf|yvMj0x zk>6|h&_=Aa;sa#V6;XJaM(39T8L(=)=20e}t>aSXamCdKx*aDvU#FVvf+T_rKxB(R z+ia3*QSe55d~zysf?oux<~}FJ`H?-jO{pyA?Gy9+FVeT(6dgXfbo%U} z3Gk#QHSs%ze&0Tfb$ZJ)GxyE>mdc1%=%6zub1B|R=F%5O|A~^R%+v-#rL8u6GFTq{=V*m$iZq77$X zhWe4$zpOnjgBSaLLV5yyfg)45-gc1}c_ia3Z-_Ix>4_Psx2AcRss|2u9_8=uJsZc} zc4B_AbYja3G4I9M=Oj6RSw9rNSG2=g%}R-Q7r)iWeRx8F(xyV}aIjG@u*jN`(Z?gj zBj-hM;vTDn>D)FJA%GPRiXqLTPf3o7 z*Vojo5CaR?z@AT;8y1sM5UaY1QMRa1XuoD%!IEhYxTVl7x zv5+75{VLa7e@Knriz}DPn?CPs_)WIJ$hJt~(H*T?|HblOtZ7<~M=-bIMQ=UNriE}2 z{yrLe0vL?+ljU4D6rC^p(^0t(1ihCV_v)w#){l$~BpKN5*a zv}{^bK^dqx$Uo3~EkH$J4j?AN%ql9MjiwF)!p6Le8O;9#G|?I13h-EKZ5D;-2YSff zP656MK1KXLV(142XgZ>dT0;Cx39)wyLU34s(sjd%@bW(<;h!;u)0f745H`mWWE`B2 zZ1JljUJT|+Xw1glItanqI7O8a0dXK@xT#u~Sonuiq&%9I*ZHqcl^Uv{P2r$6hW&W{ zhMcBSncw&{7*I_O!_r4_cwd1Ob-(~b_~;9uO_z%S-3Z{upd$W0P|S$vtw#gyd}&Ig zPN6*@B-E^k-twN2Ia-=~<|))Z=#RQN?@#KtQxll%l@60F5JQ$}U+)rJ(}ASIfUz0X{c+YPIIVbb3Eo-vfL$(^fX~CfkCHNkFFsPG{ck$6Z3e*{d>a!(N7`nk9Yq?@QAM^`QAOMJp&uWpC|A4GBR7ItZHVT= z+g!RpIgjj?D9_~mdc3#0KHc6`{c083f_~GzrZq}@W0%BNmAHDB#0^S(beBZ&c6T?4 zj76}=c&Ld|bFF-8YU|b1-pf_360Y15%zcP6X>goGVF{TL9n!B~B4|OJ4B0vybx15n z=WS%h_@Fl8-kJpQ2@*W&pRpX~aeUKz`QX(EA(_4j`K;O(;-pyTZV5jOe3LND-Ytkh zs@DZwcaK~5-1~rQ+*uYZ!wy?TetU7gBvy=dg z8~9bTnhQ1C%CDMLH@w07c!T%!27jCOhm)>;a2y9UEcZ&2mQ0KzB^LL4*eO8agfXj};{U5=qU@*A>##sS99&;s(4m2C}3?AyZO+!79FQ8>(}!r=tip<&r@j`9Y1L)!bOtFd7R8of78a%>;4*^R{gh48TOm#Yq(BYej?92nfE?v_cxytMWAD>^C#Nh#xwgKD&YdSk$(N~ow~rWJlZ^hPHI*(`CJ48 z_ZV5we|Sy)tFZ!B2hF8r%ueO<=v}SNX!Iwu`qUUTrJfsE5E(AWY~ZaXe_af=M@5?6 zL_UYiZsSfQJ-(W4SY%O7QV_^C+B{L)Lkv;)SCfh#w9|WUWWmI5?Nq*M@~JZg@!>mj z&0pC&=&L?vF)fDLnEzV7oBNr()`{j!7h0(>#N%jl1BEob@l<3e*mw`$mPYua>o3cb zFz7Pi6-U2L-Bx-L6{Ao?w}UU+-Z|2Xe2dzYXuuNC%bHw%({{0MB}bbtWDMN6h{41j zxKyi?2gI!~U$D~v)nCC_gBSP=E&$F@WjDXiNRLr65Fi+~=SB9(%)#neQ@4_!yDfB= zI^zR&isuCMbXShP4B$-x`^ZlMwDB=7zTZwivPZHqNX=587dZgUz>Az1ZMh$LI@&)M zs(m32vlwWDxyUADk+E&{cQeiEW*csT{an{hM#8p%fV85=ZcTgIY{>E`DjT$EOZglgi>n6&YxDej|M5}wyvZf6uLJ^W1>sc z+fJ@VrWT1gJO)}5{+{iTd~qw-z80Q*mL9b}@Wx$e6 zAXCjM-@!gj28}d;ZCqz1(VlfbvZ7gI6ya}yA1P?s-m4)^`y5ty%Gx(AN2deb^YO!Ym!mqk2ba#IW zU)Jd5p77;Wz5FD6*`Svj!+c4%Qo~ftJyxbqN(wRC;bC$g^=|3j5W39 zLlhOFk&#~CVrEg|6v{x(iVI2SVD8$Y^Jl?zTApeAYi0%yg1^9*WwzqTBAQmx#F^o| z9!tb{!A=?oI514JAll-yl^Sa=*!(KaN4@k{99aAm9Yu^Y^BNgcyI7<~p;^w>u6Zr! zgG50JNd%RXCloFl_=H3el8TA?vV>&COU%O+=mFfS)kF0l#eS+o|7!TW13Fcr%(hm)dEy@%aoP)eStYWW%bJ?G|ws6>CeA zEJV(H#E@eMno!7O?&7-`>UN4{xhN8b1~B?9H=|!dtEuYDc{G5s)=Wk^au!=6SAQ~u zeOmk|{vJDXoG#rs^9*hba#Q{;j-dmLSS(K=kNa}Nr`^J?lX{#|S3d~Fv-RZn{wA-s zqT$X@_dN`z7zlmtpSN4wFdU&Wg0RKj=*aNoV|laoVM>}h^BWII)NLF3jFPTrb3gJ4 zGKz@zaWAq!1lI8)x2Heh10JT?MV9`d*VM{j+@JrZo>*Lz7rF3) zHBi7L{&BC;!#FY=I$MzYH*^>Oy8pl5V`tjocMfVU9fldeA^|A~(A#fWP>veEW$|H} zVE(J-dd?AqC^$}+@bOx0A&3~WL|j)?%^z>x!t%d+vC63<8rcW=SGSOS-=Qs6Mox;m zS1%&$hp^P$*RiED2P%6=_%~Sx>b63+GSd}~t7}DoZN~OKzQ&hnWX;FXqO%8cE0W&} z>qqPGiuygGld@nQeqGtDj|hK0>6zJQvGG&L1KE%Gbb17nHWt(}w3Gg8YPgm`Wjpqb zmUTcyx&Wc_%a5az-N(_|zt;DsNaSW-BlDs|)_i|mbP{KnIVSdvOHR-+v7_2~Uh#4C zyw%aNWqAF~VJO&o?MMEWN&n7Z3~eCW@}!@rPSh>aqkx$3BBgF$xR8#U$py2g|7CFg z^kpsxiD4GyegIvS`0?y-A|gzlob1O}q0lTxCy9IbmP;efs{xBEClxoo<&PbR0e}9l zN#jZm$WyAy&=*Ftv-HgDixU2|Q>dq7aDw~9vojW1QzMP7x+KvwVohFssjQVTg~d>v ztFJ$Xm=!AkRofW9@7`#-h@R_OtrKD`O?mk_>*i_2m8)m1B|=r@a|#qF?GZx@0R!We zmkx~HI#WZAMUQIBiq93lQ9{ecUbc68QHNYt%p`Y=EB z!+gxJd1c;ae)0zm+Kw%L_N3H|PH%I3kgHrZ`#6Jt!XL;Y?FvPX*G^QCE^Nk}Tu;y$ zmTcN+E>~^d=0V%zz++9!oTrlBX9Vw#fcVT zSMDHG4H2p9M=;Z)nET12`O~jjSTKsZCXeP%ziR#zjRFrQkLFK5T^*xc8=%i7)XL%& zY3*(VOy#HOa2=0k>G40eSKG6_+Meyz{>SzP?b_Z3jn5^5`?@y^2{qWVaad=)FM?S6 zNsm?eod&R?Q#8_Z`bWz$(K5Ko*;i_)b;S_N*<3LL$0BVUdCoqQk=MFt*-CvvS%lqP~G60Vn3k7F;gVdl}&4O{SB2 zC@&?y1ab06YC-3hUw*l5&7sTZzBPw`^^P#4u4voxIdi1Dan)a}R{|X_kEQWH3liT_ zP>kVhfJASsW|$&o_W8DTTp;>NwNM7L|I1#cs*#>XZ+wGy0{C4TZI<%M(*@DyK78S+ z;gSW>=G}M}Tuaze+#Al>VK33YL}06Eh>|vb{}(SoslM$0vd^hlXR>m0^u~MCLsY}E zXnJy_ocOHK^c9ivRMQ;NF$TxH*MqL#bPU6DTQ6XAzosuk<8wtH~oLqy?cC=)wTbhkQt2-e1Zmz8ft1|8x%1p zwuwN^zyK2r8e5crpxCIz7Aw_6Q6YdyEaMnRPxX|x+R|2AkJ_(TFU4C(xCQTkHxw^a zt3G2;DIOI;<@f%q{Y++p)ML;0_xt0Q7tHfK`@Yv+d#$zCUVH6N8oZWIKZnY_()7s> z$+}(d8?}K@ntfqgvWCwLdXRxn3%4y*M^O3~qNynGlm9^7E;}OAKm$8O)$5glo9ynp zRf=qR@c?K1A0i-1e`v9Ul*)*sI2C{pQOxojl{UX;Im#iSceZqZrL2+Mkw-W^ZCyYH7UC*S zm*YMIUa%an6s%4ZYl9}fF$c-JjR5_rvP!*B?r_y&b~37fT?|t)qD&-ilHzIwfEnE} z)JV#o4U~t2V_hL?P=LT*j(|>)A^pa3`I*ElLHTIEGqO`XZazT`BtOb0wYl*Q)ftoM zr+N~7y!K&i+m(OXvS+kcHLV<-mNwnn%YENgI;6!NHCt1;<8tcDKUGP`x>m6ZS1`AK zwBiGekyX*$vla-g0UT>{*}tFEcxN=|@woW# z^2S5dT^3t%)RDJ^hmJCkaUU%wOrX{i>j(KJa3Pux&v!^HR` zhih8GZMMQtb!x{K>w*8&%fIBa;=G%6^#rWQt_YR+#5`8QII+R5%4@!tVzr{Ns}`Pp z9=Bk)4q-lK_z9O$-w&9U$~xii$o+9&H{EiV&TH+LBLg5yG+FeE4~EI>Y~8Mr>_5Z> z+qDMo;UlI%-HX4tw|nleCF8tBt$gBq>|gw!T4inRk-GMhxr|p)+Vh-`Whs~(1q6D_ zW8Dxh_yCgzIJsUTHCQ9T|YQBKRzZuF}5H+ra-I5F@^rkud9=r zDWA(gGr8f&--}VL?p~20UjT38_qzr3G{5I)Pkl|r6-AAwwtO^ad{hECQuvhWy7#oH z^KSP+w%?DOEKH16)D<>zah=&Ul#ce=N0#~<%Cw_f|FTY=W_2HBRCDFb$7{3NWeyLl z-+pCBu#lSm>JFS4|4VkBX-_*buKRnr!oXeL0bHW^qN|SQm6%rI7L9pg918_3_@K4< zRfz?*nz7}sN<4-yv8kb_aAwHheU8=Uee^tmJtE$TQ$P!;0*_;|X1n}8t_uPAI@U~ZlnmQ~`#986`zLbI46(W2LL{IJm0&Y* z0_G+5&AK8{aB_6;hWILcbPwAwcmpdAuT{&SiEeQw*MM8PPmf?)hEj?3Fc+C53J?eL zL)Umi$Cg|%4{`iVqu!!%czOG@J~=J&@L#vB)kAMd6D#1wf}B%@S31ryEsl5!PXNv~oo z+@q>^Ozp(FkC4;0s+2PSY%8VVLI3ubB`1NbV`^CgZ>_>X{=lq{q7ktAWr4Ut3Tj%_jI#nk|^2{s?s@irf8&McYLR}xRa79K8XLb@il?2bV6d%*zMyI1${*s znjeP@wRC`D(e1I;A&;o`>eegzoYp$Bk9R|~+d#Lzs-jF<6qX`+rTp}*4>x_1T_5_uJNGduWFGex>)7Mi#GzHK7t_?P zP*v+$tV%JRwFaFmVL`W5$(A<$A@!pJ=w2+jkkT+%^iM-f#2_KoI-7BX#SVMawh$xj zSy}5xqY9xJB*Vd4_o1rrF>lGw=#@6i01!2Hgjz@Mspy>hx;Sz1gNtl2{GR{k-Jimh z-fyRIFoU)J3vE~{axw`^#K!NaqEeiSeyWX^;kZ3S-s}opD{ys%7V3fKB)j6JhPNX; zH4u@C4GoWik_dBt1~sdS@2-mPnwT?f?#}9*vvx)qM=Y*CjKrl9nN*SoWb@gs9Lu8n zoX!aC7aw8r1HUP&&@OEl9WMaC>2@T3kaRK8idfN|W1KbQPOGJuVYw$+e5%nhSGUHh;e>7nNe<~7C$bu}vxnKnF zqG69p-(u#g@yCEd9H?^9XvGtJJgmVT*6usYW&LD&nJ}YyuG{jfG+;hKM2(9 zg4;G>;;JBA>!O=YOk^eOEad5&}8@A!aSXFKIzs;~18X<8&WrNUS3k8)lgT~Kb7HyW3UN*+#p%ct{t7%t$!}bVz zXseSa0)1|z;vx*LFBip#UsM=rdKZiF-`mbOpkiGzo6B0+9sRcUhSd6irO3Glmtk(I zKP34|SfMqbDVrLQyp|^j5MlUdgD=^Na}R}-FwW#RLv~qsxU$qvZr?GvCSX-X8#rcO z-!Im5wa%A4Mp=;_Y45H1E3E+V;i5soa2nynD>6=Q8pLSeJ< zj!xJ_!pu)P3sgSOu_X7FEK>JKH3ztsb&V^@%DO7rm37(dnHS)3A#^ED2=>cL{@h?d z9f?SxOd%HknSf|(rJOxOS+i_jO9+p}bl=u~*53BgCpcDCm!F7*7@JD8e5=Nzu0f|x zPkzT~LlWAc7$73hWju`z-{7DB8y%crhJ()jp+D0B4BptrA&{IG6loHOZ?HsOK;^;; zj1~TAmHKb_rY}cAdcj)~6V=sdMCm!#19>gq4k^Q^a$3?pllD*K)$F zNODTC83NqIes6XBG4fASCfS5-&094M@P7O(_ z&RA=+YZD{Lc+o8!q*9#>a~RHo5^E2cbN%=54b##QC4hU!PohFMtihzgcIYIefd?cD zVG7H{tcQ^kDd2JVVzb~~4sPwA2%&lyet;^g#84zAb&$+0@_G}oPen&GV>sphg` zIiqJ_VVy1Z7`j`Xo}q$gvN;NXSa@ubNSO%XT=n6=7AF?NB3~74w1TzqbIqx((f$nT z>!;=v42vc5HdnQVJa1BX$mo7qUMV6=Z7woKZY;jNI@_1*qSXN;Z9-1Lw@G>m3E;~E z=mu&cRSo@pGqmB z8RSr#L9C5bL}<(Zv3+;)`p?C%ySdX6$wRTGQpd`(~8=c(hel4@TEs+&+iv`;qtykRx!r!G!=z^h_v)z}F zHp4$XJe1|<`_!)M=};CqYnF$d>|`3FKdiw~zFLAFPF&;C7j=%Y%YSE_%1fEtj`~F; zqs_<51AW{oWLRnCL~ZqJHfv*lYLVTzQnP%6Te|(u z4?bl)^D9G0{0vz5zQfF?=XQh@r5_8+fL&~nLw5gmR#gQI~VRPG}S{cjy@IM4(kUf2nAVrmPTOae7Ss2#f&`4*gS7MZ$V`j`CtV{A^iuodPpLz4M2@*!|t#fYJC!X4EN(a>U+ z75gDy^ymb73tBs2O2905XHvyLhkuWY~2xk^!v0Uf(?D=t+Z9(f|f2Mar^N z;rwZXegawC{;AAW6mo=#7bzV72(H`tcLWFcoq8QbgEkFfwm*EUG;vS@`(Jb70!|gj z(BN>IQcWw3C6)xbx@;uQ`!v<-*17ZIBRP#k5_0~QVE>87rL#M;R$*|yTv;5cg@E=@ z@BZP1Y}~Cg1&7!26QdZRW4!xED!3~Mo@~KJ`K^_qL!*hjTvVLi;*l1Gx+Izi5kmKl zA%tl?7oqybRnZaj1}m=ORf{H-obI(OAyQCM!WeMCW`l8qV>;Q|UYcoJ>U>j8G=7Vz z*(bCX-71jk`_7>8$O+3N&kTN zqCl0=ID$*TfK2^aMVHsQ(dq$kl!OUN2vcnjg=eTZ0E>AJMPwK;ngLx zyrKQGCW&OlVu(0cW$ek&7FvecSM{ks1f|l8-$$u*-4=k3zSL{kq@i)!7ObMO(Md!q z#zLR|gZb~QXPQeE&Wv& zaUg8u{(hgU#TV_^T&e%zRjH3)8s-%3?=R|7N%_pVeu;wX7GWS7tn30_XjWQh)y8u2 zwCO$|5o%kc0}+}>OIFZt3~Lzp<`T^vds)Csatz}N%3N>3Vl&Gu`W!deg0YmH6~hT( zZCZ_~z!{z1&<@Zi7lS81LI)`>Cs~+T5J&M&7kr?do;5ckNxgik9=p zG8Fcj6TFJ+)QDWRUu`9hdahh;VTAxK!H7F_=s1x8UOc{m-7z#<6bYSjs2Bu6tozZU z>h4X37aDiGy1|6@_y4dqbCfZ|$sA}Z*=vB^Y-fqWT7m)Ato+#p)+-1ak(GHC)IY;gCz8aV?!tR zsLv6_>Eim!509@OynXLb?`LO#fhpFT{7xX2|7xle%ab3o$H?@qXW*L;CsO<)`AxED z7?#eECilN17RpL4p^$)oPiESi&6bmOWE3O8 zCUFJAf~|+8hrX6OFCvMHO@63k!L#^95S)e&rxCDdUPRZ6ZEu3$atr3A#$Lo6WN-k3 zug>17Vo|R{kJKM1-EcdQ**u;i4ePBkO_H!HLl!6y!;H3tP=k z<7;0ip`H>TYFjBI$m|cMAeGS2F1JRfsi|nlc1V8-$*~bdZp-iw@OP)^Sl6ZTOWBHc zRpz>{Johke-LSr0!>eUmzd0XkNnK8Z!9VsBx^e+oIRJ#4E=HL^@Nlu2LY#~YZ#-Dc z=Hyhcg65+zLez<|pOL{(d+fm{yFDtqQ$QCmH7lwJJRUNF^MvN|+cZFq5v*9yp!M;Ph_960}c0$x^FDXPI_{=}l z@;BV$U)UkqPWzryx!8c!94&JVMazO&LKtRSbjC8sjR;zhSoXSry0PTD*ECK-gL3Md4P~3=)1Z8CNSF~%iz&5BFdIn_IVUJcP zrg8|p;E0E^YF3YDZyQ#py*F(D_YH{G{8JO0rz9XZ2>6MbSkC#sR&}~MabP4dd;qJ_ zv()}FW-D9PO#ktcZQ2AiQL^VbkzdY0y|B|8nv1A4xTIiSOzm zblT(Vh>u1O&&ae!n6T_rjDgIZE0mGWda8(e>-4=8`fo?#oBjH-Pb|&kEse$AWG*~> zU38?6?IOzkL=w(xlELN%KN`o*^qGiv*V>jXV#tVk8yZJ@rH{v7V$x`n?}_+RmOj40 zyNhN`TW@^3^zWqHiV>5%z=}$Rk)NPUsyV6 zL*_8ZhnkMg9kO2UwQPn%B=ZysvR1-LC6hhPxA1iFI$jWmVWq{U z(r+yKfYHQNT%P?lRyLD zf3sHtw*>OfBaQf+sBu-|+66pBZ)bBkXs~t3Az5rqHBkfm5!<&Mlw9s+`i*Vbwh>#nJr> z2vuulN@m!9n;Y1fkW4k1$%NFTb;vablf5eOpGvO7ZL;sg><@2n%C{0H`<5Or-&ml1 z%n(h>lH}QlIKYy?2>});bQKWqz0C5q^;`*4#0&OE>*fOAt0)hfmnH8xghEe2RrOe_%^5HS9e z(~SRXmaXAo|Kb&2%J@IZHOBvYf2>Ql7vrbaCgKW1gn%|tmPle;;RqL@Z4jmNmdF5()B<5Pk$NHoAlChn zi0(I)M{<%s&_FEtMStMakl}_nT3TgB5Hw^%o;5@#a`i_Awm{(-4ZdT+vszD8wplOy>3yrc!F}$v zL%sNOP?x;sdrZo>!P2@$nX$Dj&}fX?(wC{C*BmD$jWNODX%z2lNu+^MrsDawrCm47 zggKHJJp%}~R8dcq6Vf~P)98E6@A4h^AB>C`SLC(IpQ%H#n*w;;>)bLx(h7mg;TZUb zg?cAQbZ`)3XA}H8--7${wmT8J4PFTyk#oJoxM`|MMiJB;iNE4sZIw6F2+gC5ZYj~? zz`xK1jz|}4yQZ#oW(!sJjn&;?Me<(8{|(+yl!xEX1$5U<G1YT2vNkbwoAD@_0BaYtf`Z^tuO-&9c7~Anyv>G>X}j z{e%0U4{2nYp_!q3=lK4_!EyRMF3*N5u^n7c7xJSx)~li|qPT5qPtCr==+ zJ}IkxGyI)bS%4%84u_Ck{kI*~#(vf;ujOFMw|4Fd+32_QAwZq7HoCENHM=$*l4>#) zs?rV6)Lc{{SMBFDcfn2htRx(uXp{2E&vOt=&OuE#I&`_t4~17+NG(jB*>Au3cn^eS zlOAPFiIAhx(DD-og&fr-!$C%6ZFX5*BD6jrH`-XdN{%ZcFX^nrA>Q>hv?D#{CQaRB z^NaTOrKC_HBwzCs(|1iW%UA9#IWlB5GGVRWnAJf$Yg1(tPCbO@Gr28IwQGl^DYtS6 zCrve!OEn<kkV@|>?y`ol`3W=#bi^AM({od zb0Cl^K%=<-XE_+KqzYm@t@ntVL%%|ib+pO=#^T7e$raGvmM)N@-nci_$$huZYu<*` z;0mHm^xmM&uNw;;$^=*Vmf_}91nmF-D^k_?3#h^{t^FYUe4~G@@f*HvGj)Pw_25h{ zeKVaB5Q!yzE(wHH&)2LPhJQ+U*KVOSsLL0C7^2mVMo)|*9vUECG1Cc>Eklf~KnY`s z#+vp6yAV@Cu0lwX6lHb@m-nmypk$Z8~#+TnDCFSDVf#x z1-pdNhIX2~x!{Zfgm!8nXm<{1_chzUcN_K(9!9v^LoHAf54(qxkwMF*8G0Q-KfLP( z@+?z2;x^WHca7Gayn=3W!rXlK0TOKtA;^yW1oqB%VY; zTkwMs*A+^_VuZ{{JWN0JqFQKbB3(v%H}NQJOi*K6+g*ZQ~L#a zPB^rha7G2xV3vU<;wu^SoN&@iOTOVoA2dvfI8KQlgN#e>udWe^+OEB$Fb z=~JzC{dO(>6&PVH7HJN@{$bGKYSFSJE9pJ{Ik%^X3a8}T7P&D_di2yE=8@YCssli( z&#pu31;~U<(GcH~Kf;&|n1AUaCRxc|mcc-jHT>#-2QXk70fXmzH8X`U#y3R%GZ5y@ zI{{RHP!=!ho)Nz`h_@hh&=M_8u>k*8#Y>1xR7!=@vOhwH384Y2zpBQ+Zm6;Pk&vJj zEIWc$i@#krPyDUr3ggxsi;2XqT?0Pw=-?5*Mj!EO^e!=BrZMtZ;>sHTJO8@KPsCbU zKHyi)_|hWXX!}!(wbkx==1&YhmQkr+X&=-aO;pX0Axq04*3^4T77(pGQeXI=Ft?>x zn@A}5C97A&|tjy;E0~!as_7x z!Rgd<6#R}5nbhCuNxfXb&lr9)BJDn(m?eS{m5#pn9|u{YJz0vMA$C2S!yti^WYjc8W>CwyG#a-<^&l^@@=yg*ayE75R_thaI)crF943$D5X^Gtc%+k$)eXNTt80!h ze#Ytjn4K6is8J}0iiUNdXk2_1JOGUju1@4BQ|&z7LQW$d&&X(q`Wu&ECl+;TL89n3 z5qw@lP2JhfZ|;xSCe|RWA|a78gnQ`RLZL6L`p>14xnXzBgizD8b5iNUzdfj5)@6BDvDO^2!Krm^fq^l+ zjq##M;T{DGIy7&|2M~W}-nRxEYeYcbNC+4x6`Qx@uZlLsPGgC*tT@N0s$+JTl}=~_ zUb^Q8`z)rCd)2HL-L*F*7dUM@7UAQH_v-K*oD9<8=Kl1|5lbymxKX3VpB_Z%1_J3S z%6U3l&O81nO8c;d_mzFt}1bglb z{+@is*mP=3vdhoFZ`!HsWiFvslw=+B@K!6rB<(F1(eN zKS8ko8eNWeZB9}mXfO3RdT?WZwkzd7Vb{~4QcrH?49taXn8GK2(0d1>P0c9b!aq@Q zwJBLiQt!GS?!b>av-F=wW3j?fa*C+?B4lP2*k)w0&RM!@<3MMeO=oJ`{?U?R6jFU+iJ7IX<7E~ZgqBK8 zr3qOY%cxC%_cw=eg3A0O zEg1%yBwKA^R5}MQM|-^HZ&`B(-V!AJ@B1k+9=?&!)-gewxC%qOqP!~meGFhy?Lb*M z@WLQhyUR71PnW`)pcEs66gRmP$MvLewKs`fB?cZCq`KUt+H;G#BKJ3tIslN`j;3=a zAEUpMm17Lhkbp-B8^|)5@1k;@_$u2JBf{O3;Vu5$xa_F6_=tx$t5`tOx811Kf1L@n z>I$zTRDX$4E0pSU|K}GG9uNPOuh!6Sm=Ud^1=`y+-c!vUE^}y7Ni}=CVhgQSL%5mL z?3!X!A&$vT#XxsGNG0HHM326hwmEHRMU;8f6KVE8>1sP_%}Wx1hJ8448y;* zV!$U3$(H%K_bGDVe_7y3x9brHKS$lhTUES+^grRv?^LpQ_y?9O{2LzD(NL-DskgWW zQXhGQpDereCXlya{;Ii{)*oqEQwQZ~b!tF)#iGI{L8|R)^=l8SMm6}&KRAqX4W4|j zHFzt5l=^o)tii7-l{NT2-u!&)*GYF6ei$IL}mZS?R@FU@y@ z3K_L=y{s5Su|Vw3@Y?4B`x!F1k(V_^G+rVf|DmxJ?|H2qun=~^qsX7a1!zgM0&MqM zlklb}zC1!y8`bZW@T|9k6&I_{Y2oLiw6&?1ffM&|z5RPIoLh~_ojgSBjTFdby}0wh z1c?CZ_4XLm%EPa{N8k$ol=tMtEWp8)c`j9>OEq7qPH?H}lq5=(cb8@DK}Tszl>&5L24q!j3n+iLV%qcww1n#JQ9N)^Fk?9$v$5290Pr!)U}` z3DsX>)GbQ&xqq?5D&`YkMk7AT?(j<2eGv7I*%0-HJ}<&hNwL+5fmf5H1@E4H0=iH* zY?JIGS!rV z9L_ z+fSH%BD5V7dE~MDN>&{RXgF7q=FX7uNsXDa0R18|CQA3l#YlXc;bLJ$Hx3KlkOzJ^ z)|B508-+Gt<0L-f;c@(CVB^Q988!|lRDX$4-&Cs4{nvhA*jUV$Hs3$>CWA_AAP;jz zay}I{YA*_G{Oo41aZ4H-4qbAj{zpvPOCH=OzLllv8={uzTL!-M_NQvDXw2(O{JFHR z&=@XH<*3FS)JVz<@Q+hDMb&km%Yb`qe4RYcqM^%|)2zDB5Ct{>SNKwdIbMY$nbY8? z7#kLJ=#)JQp<+9b5!$IU*a@xzJ_@8eO7T!jbDti<|IPb}!ivMaiHFDHc_lcyrb3@% zl`H~oG$EFNeA22k(%J;j9dx_Qi)QGdAR8-o-rDdBBH zw!Hqlb7X6%&qi8o(#tG)z&T$YaAxV4HA0;1&1=M^1T#0kBa^D@-ojJTZUH`)SgA%) z|J&3ruEO+$(Z5Fhj<&GjL5te1gn4MzEP3~74&*$N9Df-cS zJmFLEr!du$i`234HD}@>HP*Be@4n3D_-?QH54^~vY%xzeo8O`sIj^XDE|z#m2?5f; z3w}K`>ukTlju1bbUH~>%@#Rn$PVG&&mr_EHS(*w(z|WQ<`q%T`M==q=}s4 zQl&0<5KNe0Q1N4$^X2)F5Be;1*D)a!VEQ57+ij&UxZ8FW#hPfjq-l zyB?Fvp!Z+XMA7fp~0$iJv`m1ie*PMMI3YF;L4?09P_(5Hmavrdt9O|;3ozrx?Vy!pXK7zme`{~B16g5uIYMwKAMjkkY zW;_s~h32Eq8u=EghJCki=e0o#FPle~NRxlx9cO%@g;x($3m>+MoPpqf{Y+jj3OJL% z)NlZ9k5MNZW0&8EHyPRCtX!|&y*AA?IP$=SZ`B&~2JGl*8@mDjLj!w2sH@L=HBhCe zK=@L@CmD58<~09@U#R!2uLzT`R^<;>CB1Zb;}^27Pa%!%MKKUUDD&_d62^|Sx4d#}!>0De*L>JQJTUX}o=Ue9#( z4garJ|IR_ZdjFf6bnpG3dOg$CFBB|;8T)0x|JP%m+4~<;y+NC9P9q}nK=^J)8Ct($ zH;3IC%)8J28ld&;eNcv+jC$<0tOq_@;p(~RE7tQ@^&1>2PQC1Ne*b1bx<4`NPpY2# z_E}GRP-@vD!Aof>q&W4GpY_}qDcy+~^++L+hTH0W){}x#+1VF6D3zu{ic=x^W&5b- z@%(guB=e^0dHR1{PwhVHsmrKmWUqQ&{$JO#U?27D_R{?^g-8z`ytB`GQVb}~iF)9c zdf6u){34^C+Fp3D^DEXfYF2>Psh54$b8JRE)xF@>7vrg~!nac0NaMlseZXz?fxXB? zeRY~lh?a^<>FIc;82h1LUj1pO2WZ$sqf;UK>}Irg^&g&^u6{#My`JgnE7F{CUo0Y3 zS!wE}_@JOc`>cL#|6aYnJfr%Kpn5&i)qnlVd!NFpboDd8OlTOV>eF(-3xQOXrpd=% z-80rR{zo~W2jX%D@-MmKro7B9L+@w#^CzUCzBTB!p6PZR{}sD!8(5;HX5p8~m_gwl z&UkvSCiqzy)h`dK*E3!HwyS!;u&+Vyf%+BA!PFW-dwW43v-%DFG9lnEtV;KOMNqw- z=|R8rD^~yGZ%lEVWCoIBxgA6|So$?a0S$p$2Uq zi2Eu65B@tablj8W%78vqS6rIs2%! zkE>PXuZ*kK^D=6cVM@@~|NM%zrlf{+Usvp-*6VYvuPT4#FI8*zx#_-&q6M|y@)c{n zn{)zxaq1<1Ul2aT)oK*;R@K^&QEO?s)_cEVtv!8BfjWQtKKiuX_(PM2-|BFY})YE}6wSE<%GwWg<$|5!9Vh1!BCq-UCLY;^7U zANfWPt2}yPfM@$!;Qo5Q%vtQ8no<2ys9ms5GNN3xWpenQqV#6#G?(T+awC4|Eax1l7)vBXT09#XV>#neAKD^S=`r z_k{^<8TCl7?a*KK9RKguvjxs-jB@5aW3Bl>8iTlGYKnOu{<*6-r z7Obh;xu*#-%T1e?7+)fbh70I%B)&fhY#|UIUo2JF zW{Rzfk1y2wZSEcYv%8krf8+#oPx0|J#A&hGe%O5Aj1IX*d%rtL%_Z!$MA`~7K7Jan zwg`-mpTVoG)8gaLmx~Q7S4MWCvU+2_vpd>OX4mrvf&)vRqohP@OhUBAx>pp30{+Wa zd|=Zyi`uz0mE)gX(i^_nv}+Gr&a+brF}4(2%1z1XE(UEEru*l*lAB*d{i-glr%wOy zkpexAVY%{<5vueDEW{&J0$n0!=D#~^%dmGJtY#8Ea4tXbS9PD<%qnv>%m#FQK4woS z;-057rT*px92e&1D>Fvpot3{)MC`EYb%j*tCmr)cQR&d%xt zSL_s_#z(s@IxqTe_t!X|E6upJlw)0?QX<$Hlfx>M?2SLQMyLg^o+SLJ-{@M^U6u1& z!8`Q@>bv3zg&6KLFIzFdn{u1@& zgvo491t^PFIm3_AoTavvCg$vSBA#Q1#+c-UZoum010oT1t!j0Y2~8lS+w zVq8_~GNqH~<=^fSwT!Ts8%jEeL3u1Ud3UX1BLgic)v0WV;q_{&U&tc|Bf4gHY*!{goE#HD8Tl zy(h*n_f{9v@=YrVEakS~_7%rY0TOTHvWt22o4J^JeJ{wUndnCWM01a)RN+?E_o6*1~F%IaH3+!fZ)DgWBx;vMq<);j+O z47@-j%zyCMo;GiW@%i7hdV>~GzyFtcj2W|yoWX#7et}@_wh{b~ghY$X-0*rM=eWfv zi9Dde!GhwcI3M^s?w6?al{u!?yS}KhcC)+npzhn7at0D^YXk%(+)W*m07(s^Lw2 zF4_)K!oun~rA5nL?Eg+pA~ zX?Gj$VIMi!EU8W%{7Ge2vawhY2dPCqAZBu$VSf7bd+<)|HJSEH|a| z4<>&@PyS8*CuH5h@e%e9#|*JDRKOAG0;K5l&rTOGG_z(3E2S`h^%XMXI;JC4fJ!Uz zpF6In8PaO_15>4}t}n*O>%F<^#)+6XmiZ?zm_g>({F~GH;%fdY3wm|`e#@89{jt;@ zbRTKqeSdm7f1C2(oX&qNEpFU9f4C=q(*oeBA`VX%@hcTEHC+U*^HeuRDuaeolK(ey z?*MgDeUCRaQ;5HLh=}B<0VDwzV+*@(QRoD~P3Z2c@kes<{Y>&8eClq8WX_&HyoLCx z6_;If@wv0lyXex`%5$%{=&}pWopoL;tWv7uv~f-@PBv#<^uwR5tJDP_;bkiF7TOw1 z)M5|un!kVVA{P-K>sqj)Fe_{M&n9wgVOB{9Kkx5?=M?xxEN7{tl33FS&{O;7Y~2@T zS_36UjZ+Q3R}Ddiead?Es-BkC(9+}?q~#O@(okhN{*j9PcQ4zu$HXV( zOn=4^qPqS6OPS(1>Pg_HA?H`tp+tdCnb#;9X(~RtCMb&HhWq|ehdQ|{5uQnk3^*i4 z_!qL-WV9$;OKC0vD4n52t4$5oRcX>;SEamV zRCZOe*q9L^b@!E|es4IK5+8#+AKt=ujLWb!C62sYs1jbUpv0g@d6;n8Rat%lg{T)@ zO>@Bp)zj5yJ*%$KfW@u?%L&e z(m)7Yd>hZM1$Ta(FaEj~+`_k&y+D)VDF&fyfiN34FKSmg<#a8$iOO8^r9E#q1&vC| z-D3L_!647sX~=@7-0){}=#oRl*-Z@aYEfnd6u&FdCcL_z;qSAPG@Z^BWr)98x*8_*ADwMs417G(`{`b-J8(&_LG8iYt!i_ zq|+5&OS(stZeoz`=5)HF(&@^MC*6%ocTte8A)Rj56+IwWHk5R-_-to=(@Hbc2-cks#e?cAUuidrdms2BrH@L-b;h?zwcjsp)iEmF`KU z`!GoNmvp)l(&@GzhuOCAiE}y5oX$)6?l*zq|)7`AT=D(p3fN zPD-bHFrBVg>5d~EbaliV$5Hc3?TZj$k?=mfEOj;BkNUwv65%GYC9_Gp*L~yhoxSdp zp2#X-zr_9{`qb~YLQ`OMVn5a)eOF{3*>{)hDLK@4fUfa-FSZmR19wyTk%hYyS^qMA zoE5aN+&-U-#t)6v?Wd4LWhjona$LFbo)yR0n|mcV+f|ZzKVM*pYxfpPjA&|~!NQro zA=G)z>v+Y3x=eI+5S8U=0S_%pojejVAL$%i;y4_pXUGgq${wqmfS?5esK z#}JQXDRnSYTtw-xS;!TUF83u#(s! z+FPE%75&?1bHo>d&5EuR$2!UcwAqY_B{)=4!*xcXqvZLtJP}$*nqt0B;KU&>>A(_y zTe~1!e}v^Ue}7HuaKAURaQ^?nIxRT`Kq*s+zuFQuydVe7#o+TpmoZ(qiiWe{%^P+? z;}SP4lJQygq>`fUyPbjA@sG>EEZj!Y_C28xLaFEoFL*j$_}q~{SK~w zr!e;gR9(Rhw_fO#ZrFkGZ5K%gee=(eKMz){IUbnyU4i`(gOSA zv+&pJZdkXT(_P=c=Odii-r5HLLl0Di=A#%%Xc0&i#m%Xmb=`#dabqp;!$mHRUn_&; z)rpBShV40>ksbDtn?Lx1>|0e=P$o2LTE`jETrFN0u+aLhP@5=2#k`{VFFK2CIa-`v zIR6fge6=&sd;G;meZ1%F=~amqwZ&aT$($-)U6q&)Ky?FGxxeYhtb4C6Yn`3#U-E5f zOejA2ec{QG(X6b%bTgleYfGwwx!=l^NKKwttJa3CoRPrRH57~g-R}!c9AzZybcls2 zuBJ-pU_%M($UGK@xhNDv6;IVqin99Tgb4J#VJ4HZX-)pwt5a!o(Lmh`MgT`zKO4CC zYE8ZoPEx6|I&9PK*EDGpV0q^J+Kt3lwj>q*i#b<-8&7x`u+}k$usCwwU zx(hD+;mnJET=n3ri+?ivr90OUnMuo116=vSo$@QDFbZPMUC0jF0r5A3yP3@rFwKfN9 zyL8(*Gi7a6=exzxc=y6LK)(44L8JHQH%6GBTbYPk)&Ds$?)X_i;_AdL=J&js?>75( z8iDFyxlMyq33=D7#>aAebM%0%Ub8gjDt5^TZ}IuO%U9&0xq6ZI7CeRooL`dL+LV=* zj}0_AKB5qPX1UL|c~b#RyIfby={x?{ddvD8lzdqxA>o=8e z%8Qh1<;)4naZi`GJ|q3?jQ3d??=#cyFH$#ctbJ3ki7$edrT_z~(UUdQwKX}L@W8H~ zp4vd>AAS2@)uTz_>o{i(mE4+~K&m#%ne!c&$lv*+9Z>kvtx)-+*R0RUN|usB@H~D@ z<0ykY7;(q!+>;qYmlm9{6IQ5Nh*_IO-L+`rd_@ze!SI{5| zKYIP$*0a}bm7#VYS?Mj&z3xQfjfUSrw_1`RofNfET&T&nn82?xC|8))e z2h^+G#1*^Us2{$ay>${5O6GynK#d}q_vYzAX}=hi+= zJNNT`27+c;r+n8bMr-mvXkz%TqtqyM%pXbNu2Yo4;7uNQ5H%-Xp>qU>TbRC#YNv8t zNiP54IyGkUKe{&%J?OW0S+r)R02)3^Ns=6(wj_TcXaDaLM6{Lg9YtT|N(kS+R`ZCG zu9bXg^lFT^R3wN)+_X7x_bdWS^ zlF>U+zJYVmhElDXA=DS0(lq!x&!cA&rv|&{6vAqcKHtLhKJDlkJ@2(gPjm0;3Qe36 zp5*cdPuJ`kmxlOh;p(3E+HlOhYYJN4O8c%2yQk~^$c*&mJ@3=P!(Cd9YPigWGqDBM zXDjb?#=r;>pCkw*PrIf*ed=VgsFSa-Kk7dwkEgrR7{3J?F3V! zM)(WqV$grw0o`~3zSA`} zOPtJZ3_-YWMwpP$$dVj^y1-wh%?y@Df%+ieuWn7H4FKIW+sLr8CBAdmCWhY5+4I8@ zKw4#&%tk9-Z`iKGRtV#zwtq#-bJ)|g}+*p#{$?xvFX2Q)HQ>W#*sERR)tRC3;!!o+1| z5pIIA-RU7JeKh&euCSJmR(xar%hVH`7G2%;{rGNw*?Ce|W^pR&8Snmrw${zar%pjjI#_3r`Q znm#+9p~-1@Olp!USAN4iy3wJk>GN2_p9E+mqYSM>oAB#XR<0a-vjHqdMe;(O?JP+j z#DcX%7D=ygm?=tOB4D3%m$zfpLg>6nfVW>(^Kl}kbtslj;Fh`^K z_xZw-gAJ_wXp2sI%NZIKag2|KbHn;u@mEnpbdt=WZ1NoGMsw-?N@zxwf5{-J-^0sD z(0zyNfA9KQt-cEC`#SY42L<@DdkfNdLdj53%d`Tn`w!fZ`u*R?B4^Tkb? z@pe1&Sd?jO7ELd7z0%|nZu^6YWirGxGhT6VHq{0Y&J~zd@(VGx*lRuw#)c7tZT429 zhRE|TslokN**{oHa*s{>kLVupIPTiw-#lF;Wo)q>XwB2ODn*#1FQh>IGa#gUU9TXO z&K&l{_!qc*h3R}uxnhlzHjnX_w0jxNZg>o6?qQ>y!mJBJ$)+xNEti3HG)Z*>`nR4q zF01__+J$;+v^OM(unxQYFAMC6KvhL zlHUA0S@kQYxau1gQPibGCCA>o*rNumUEC6B6C^*>q7;f1R1TCIw%Ec?3@Tgj!v?wPoD^y5 z7#M5Xb3nsiy072sJa%L=2J&wnd^>2RqbFv^*l@1F!=p|I~#7)=nv z&1pJ0yYcGC!_<=Xh)9m3FQz|zA1*_ZypmYX)O-QL*Jcd)Kc7BSJiYQ)G<}lY_%+*SB)&2i!pn?@P!GT-I2V^yJk{_vof0RYM1J5Efmgb8rP0Je=K1hdh%7kaHh)q69$(Fw?VL*u>$x6=NeamJ z>(Q^&X2X0mttzC_*stN;2uM@Kpp329*wB$|qcr2R4j+2$cR-^?^`Ul}iPqI?o(b|e zf_gX*h_s)_um9j7+*dmcvbqL2rY*`f8Y}*6yEM%Uh?bs?6$x@*gr#;^KDB2(qsi}8c6lLh;XCfPWkIKALTDDh146SL z#)O)7U)}KMl>7@Sn)kn^&#(4c&XM#;>3Jo(V-a$@)p+Ohm|+Uc0HfqD zr4FqzWL6ctA^9Q*3#2;_2cUd4yktExDAJz?{$yJy;uZbZ{!Xo&N+L{qIDkJ@?VYl} zn!7)()dd-9E!XUk3tEOsU zG6XzK-mHt{MdL3)adW)8&Y+{6dE7<6kZY78*_&F=`jnCASaHYgx8MHp>l@!`o%Fr^ zA{84nGaJ^mp82UoG_A&?QCD6nzTz1?tV(p!;+cICt;53aVRZzt>{NfX0*Xve$pw)! z*`!nNdi6}+CwqFf#d;QuuliTFcmF2;>;6SiXxE*Q=lU0M{mWj>T~eW+e_8L=e@XAI z6pLWkU%Wf=UHxwDE53U^QA-z$a`Bks((*0pQ4OtTzfPH>6^G)-ja6@J!F~FU)vcY7Q*eY* zRMkDv6h?#bK`&u@6Tr)cgd-kG8csrAB{@ejYxorbUB z^M#T2M=dj2>)ADjWqinYXu}au;cvK@!+0&UR|9dwAdO#q!`ahUTb9p$r~C~sJ;)s1 z)BT2pB`wUXVCy$_zZoD#il0o5IQz1mG138 zulW+*qTrydfWNP<*RASGTT0kITu}b0x{7ve%bqT0@Kh;4p@f@(`c^kXwQ2V@!ysam zYkxn>)}@gTuIFT;eAckZQp*xRyS}oan47=HKfvQ1}X866D(ISo$K}(`cxRlQ3(=t}d49+P375M%Xj#42-=oBmiG+$(o24v8D&4U z1DHiC9=5x}WHiLyGv+K(*pzxpVzNc9bJv|E+!bTUlBUGkq+2+%w^zlVW%X~UsCiP{ zeO%K{4qP1pLea36JsJ_TTDqcL@{0*o=n557@!H%7R~!v5@!IEc(G|16e*{s!X=k6P zrbNU2V=F$K{}ee?Ks4tDJI+MitbtPn%v&iv2Hb*M&7zo%ub?_+ZZ!`*EA{l+8~8uM zRWOYT#1Ph671*ybaWM_|n)5(q0k=#AmgBl98vg(iiQQ{{EPHK6GeI<0)Br0g3IgW4 z_Kp`{?A^h6>$<;9px2_2caTed!idl_@A~b$q`D>e5TAURut>$)`V}i^SXOlK2hqWP zbnt4N(6)vu zCmP74VE^;Iq9-YOukPF}NS9UBb&w<2%)$b;CX%ysqhUy3%Z2ag9y%%jinQI&X=j zs%qtf(T7}DRt@T#U=m3;; zk>Oa&FkKlQ^_HB;GYZSAS&nq{Xl9lX7Q=PptidwFzd?8kM%L;?Uo|;-9bI;9@>&{s zPe#D&C{n^C+#7o>4=QLGKbiUvD5r$IXA$;nm!llJA<5Zd2@=Z1=N9mcRJ=FmB!+Jp z@0@yx!tRREr58rcUQ|X8M?htK7~>= z7YY@sutm|5@A%)f0=<@5ps>txzvB-HLZ%X8MN-XLik(#Q9VF*M1olwpv99!>6W(3# zW+RikzAO=u7w3};>QYpMNT%MB-ApCE3%IY9G7yCexRRL*SszPgPj4b+Zl{{ z#-VO3>CkyDG*j_O;Z)$=;k+#I~hyV;U^>8g%gubMiJRnK!x~f?~LW-eNdGX+L1k= zI{sKw7Th|U1&I?*L(viEmy~!dI?+p&+bNUIo2aDDZ?mRI+C;e4QquMR`El0&_j%C& z&GvPt9pvQtrwkAv9S6hWAR*Lb1y66fG5~NjJ<(Z8^%t#80Ep_uZ`Jbv9+?1$_6C5h z8vZZ(e~b0nYndVtJZvAJYl*iQ^RlcKnM$!X`mW|z00WaPs}udVkG1aq(;lN%@nG9w zwLRRa)>z`~85)D?#Buj3QQT2n&C?pR(zg+&(q-&Ar#kMgZqoh53j}r0vQ{Z);@tFJ z0`zBAF+xVjUJ9$KnJzV)$moq-d3`{xN4-U|FO@Z_gYBwV-J`4&)~YP5 zF%m;d?n$o>B5n&J5}`J*sioe6xrmCyk5(nBpJaxQZ1e6K{`2@wB*@d(Nh>TZ@P%z^ zOP6%Z=pn+9u28OCtD067sDTxwjdiHC@b=PglF_?b zxy8^-;(Az(95*CG;6zt6rQRUKE#P|S$#ILv7$*Ih2V|wq9!5_znL+_QVKQaRBB)m| z;-ba-pQP{MeVyb)(;V&v#i`FyA{;^L;w=Ju5V!E{~QW z@-oST$zBjl_Q%tcz0xMTlc;;zU(Y}a>}vSPHqnH~ftNL``x>$5+0{19N%JLhT%%)i ze1@*oC}Dytg!{rZ!5x}QleWjU%`@2Muy>IfmYpKhIj++l1OIA|{=eZNrm4m0PRfEj zXU=!TbYq&D?$UiHLhG37AxRE%uH1X7ho0YirZf5XG1V(Gr#jko*!`ExcLs1{&wMYh zj(5!8#&m|e;#Wz-t}d)eBIcSME_dhfd$qew=ACoREEj;+SSZ;es{EDU=}xKjz@;k93g z_=StO+z$gSX=;7K%4Fd-ABa`lP*My+Ylj_+rTUUego=?8 zBFZG&4iP~rZv37mPbC;N62fcAr6yBcWsFqC2q+4LeU+&!AW+KFm2{K6N1;>}r;=4L zLiLff424KPcr?Y2>_TRtK_)z3PIgT$sFucr8$y${;RVV)5XLdjz9p3Zu5!YATAils?Bk=&MSc9joh;$q^HM5w%&9ExKrbwZUD5D_8$@ zo2pw!nh3^W5jR(0wWn`)u&()+~{w@D+*6Y)YTV; z#w8{d<^o$RX%Yq7C8SsNmQmY!apl~TM{{u zH?l{Hdl%T*o|iy45-K{2_kHeYCu4R(T?rHM(wtg zB4v}90I_Z?LTX`0#3yPU+?s-uF5s3GIm1f7F`FfvLrdX07$fR((`ykH@^rpE1|f7-PoO44qKU&7iWYs3GQ?P zfGy0>mGJ4`1ZlSrb63C#e$-N&H*_h6%1cM3*Q5R|%nKO{g2eRZhb_oDElAs%^m8R>nmfvfD=Ss`}D7(T;7b23){9Rhscpf483zkMbj)Kt~s>&}8yYTtFAU zac_gT12Hvis43W#y?WY)F`Ma!)%cOUA`-3bDc~>A^w%UBBR_FVpp)Q2Nt2VlLjC}v ztal8&8zlUB zw%RkN2I4`aG%SCWa*alF$a*1cFcee#b(|OJI>{tQ_yue71(w-){age7CK#Doa{w`n%Aa z#t-#6jxl@~-J3!;4xUx%LrB~SRIu;UWNfg(xTOVeXazwwZutrUDitsfBW$fX%w@St zV0BOUqLY>cXo>+psVAbr2{|4XUaBp@G6IRf6y`{G(T;NN-`(=a{GLXVhwbIETgr=LDo@nxJwq4XFtcv;sDT4ze=FT)4!hwMJj4YG*e_9x%Z6 zIcwXG95fliFLo)qw40}T32E7hNNz8rr~sN9<0W|sp~xUVgLeuqnV$)Kb77f~{MF74 z(r5vD?-RtZe%KS z9q$XtFDjicL2KUV2MycDM~k#O%rCn`wO~m5T>@73ayd(l>H2u`mEKCrR{=BkFXXHF z*?oK9)WC%EvimMG&MHJTq;(nOi*DYhd}JZ&=X}2LTI{njDqKwkEu~>8FZV$z)D2<1 zzF;l5&w|7HuC93G@woCr)=GdO#QAp znU&SMcPhw!tIVNBGEvsy(cZa*x0I==#JxyPS$pyJ^M}0HzpnG@e{&W0{y{x7J=ytW z_~t*Xpt&-9vwX(TH+`J_`+q`mHHH%=%)3V;z4ByIseKt#(fPNqp&z@3J{dODJG7y` z&#UfpVco9{tvmaIA)WRep}JR-2u+_>>+0g3ZATWtH7)?oI(LRmedd72KhxuXgpUt8 z;PF&F-Wxs+?y?EbXuM93vz~K(Z#>}fa42HuC&I_SKHzbs9*+ti`v*M!yBhy&_;~&S zk8|0do#VsDQxACDrMCx^aGhy6>43-YYK0DZ!;L(8z~jAo{7eg}NqBqLo%-%*hso_B zunk>=o;Ime=rOCW9q^(UR1+27X(8(r}J&~LkF@KMIM*^E>VK3egqbkq8jzT*ZT zWxQ3hokzoY)cH<0Bb7GF<`cq?U2(~fW-?}^7u{5P$8?;?h9aKg_#ckTav2l7mphj} z@A5yMn92@Rzh>`1->tkC>febUQ!>K+lJN8(84wIp&47aYk0GCsx28Y8ZQrMzCsuYX z;Pp(fvCOg(HowG;;#-cYPr`5pFXR42YRJxS(E@hO;I`NIxP*t+oYG9rqs5+D^*}o~ z;XMs2?y_UrrBM_iDvPZ;X5$r;f~#KILt>1ANmE`v1o!$U z$A5JacN400_t2$}J*c~Jr|9m%hi7zGb9X`+cMptTe3~AO`m`QBu<6ly-HkX}clZBz znktR-7#if_BR?eijxAJx- zC+^*KhyC2~Tl=|PvIR4;@^Aclw@O9M-Cc|MjeEB~=x*@Xyu52Oa_l+#)|2&;aH=97L zkqvlDEiB<;T4CH8#G0;-n5#ymx#x`8Zs8vdkbcG zi3V@l>_ix%hN%y#t^n#HWrHYToyj(UJ$cX`sZ5&g6!1zsIi;~Fk;bM7X16d-Mv=t~ zGP?A)wmV*kF8wb-qr_;FQl2exmInDB`R%ZyX&cmV?r7 zQp&r9GESSY*tkZK3FSOw*J2DB-=Rw!n^?4z43IbQ zeSM(i#}NaZ*Yq`0`&*PIkrj%>;jjD>>UB8mRB$G&=~(vPI%#eTvABw2!!XY@{mfL$nlAwpe?p9_BTcjG~;N0XD#D0fdyB$uZ>HTnGI zr+}5^r*IBGeL1}B1i=vBpDzdWS4wbUm&B839?tMczr&{kwlje>aHrM~JA|ZZ=E}o~ zM7amk$$K{WZRzhGz1r*Tf6!Lmb)!h|5}cp(W<5PrnyJV7YC5xRUv|?O){Pwc3hL=F zPtBjzKiIt2+Z5fe12@D_KchhoefvIWr?8nlu={+H55esc)I3$mY`>QrEpKPW= z35s#PEkC;KN6eJDOj~GN+oaDkr)-T|v|&(7ViFw8N1N-C4+Rn&sIXjj-D?8?V@9)zR*5Td5;nB`=XS0S%q~h$x z`ols`{BAleT!X+~UWbjN-rE5QtF1bsb*lzMvNy&}ey&6^e;uvSPb5meU48*G-ZGbL z%xy0ZTe<1cM<3n$e9VFix?dg^PtLe$cz^F zrRmvN+rY5qZT^(}s@2hRSI4T>#H00FV}ma>KcWw1kS6Gk&omfpcJV!tQxJDgN!bV0 zbZ8be`SsyeGRH*@#XP!LU!WP&FH4+}g7r+!zRp&x#oD3C*d!6UAUG0!2LJi2?SyZC z_9P~vw#ZME%fvDnh=)kxkDyFq=Ol@$%sFN*b!-pG6Bq0gscT!y2(uH71HmQM3~I4j zLiOgAw{GYg0NPXZHFi<0*8_KCAf-cCoy(7ZgW!qdn?ce=fK(w6H9orRB_sobs2yB@ zh~N5*LDX~H;k1c9^+gHRBkg$%j*5x4FIt%GvfuQ z7MwE>n`?Z`P=~1)qyPk}iVb6H^P&p8# zRaLgG4>i2_x8MN@tl9fnP8C<=FM0@1kfwro)rCa0 zJr+H8R({o*=y_XXRXf->Z;@`q7H$)ts1vk1?E9S}oM~bKj%QTa z=4N5knny*M=p*6(THjpPSe-rDpOF{wo9KQ|Qw^W=UVYSN&-22!m0{dSFjH&*^>7Tx>>o+xj$KB zv~G7|GgC_5V8D{h%L-2Z-%o3sO5H-D5PWDr+U(JaSG7wM$(e+c3qi71S5q;DN#0+S z%NAOf+NOWBw&;Sedl}^vR@=I|?-#V=D1-a!@V}e|7361|75s1UrEIf^(ga4A{Vlak zA9LIEHM#`xKfxWwj_0_;f4+_bl*4U`&e}GNfsP1B#%=|9nnj3xH$n=)O53G(>s!Qs zxNRDHNFP`4|3J$(*^iHjO!jAv$veBT5Yy!N@3Mwh)F%tmo6=!-^n9bFM$OZ%44u1d zlKdIv5r2{PV5B_e=eLPbNiv5twE)ySMQh}X$-dy)X`^{nwa zwxP9OSZRB4Znzf#^FniW;4!!rak{&coqj5yEnZG7nh*Kpg%H*;{~#r<;$F^#PKl8e;~^Qz2n#Dz%z}9`3exjZ+RkXl|AZd~-xHA``5@bX z?N&-fM@U`lT)lsrTS0sdpxkKntJ~QBHG`j2*sC3Q^1s-Dk+nlMAXz&ADp6TceHs%a zMOc@-)|;iFJ@%UYlYEXP$tNM8vXBpTf$2L%>v$mH$Owy}7U) z2Z&|+K5}oar{ag~&7-U>x){1Q@1h-Xd%bojy|*dMv`EfHf^Rc2F1p0Gn`s+-|AEjp z$y(!HekuGT>U#{=(RS&*Pzfwsq~Gl=3oA&q@j^UVI}lHv4*~|M;XT&aYuLoE?ycBE zCXS|PonK2SxE>tikMD)+jkbSV3kw`xGPPqM_CU?XsW|1lJ~dkVjF?n*vq@=lB)iP# zOnT%s$S`(kA;H)H#+OtjVry`0|FCKVs!ag_;zOsdC%k>EX14~S9N9pKVu3d$zi%|*pL_ts^v~xI7{DX0zZagFhCXWIeGD1jbtZFS}^VznSC63{TO^6z9*ng`_#z&cg zBvG}#`A@-dMd*CIHNnNBl%?U5^?uP*?`33GH=ohYL(ai-eKd(DAY@8B{g*_t8s-IN z(=Yt)iT6}0+86xcx4j(0;L{ew61Q^9$a%Nw7~&x+pAtqpRnf>$^_)>*Cf-0kV@0mwN4*)p>iK> z>_0lBhsl|x4Du^^RohxmuJc|cdvS6y5n5{(y%@cdP~Ei}&83%tN>;o4yYh}xWcelC zYwEn0W8O0Wa|0r48(r3V`(l0zd56huG)>;A3Au7Z^w@t*P;2I8;Z(nVgj|Ko8LfU{ zlO3p)@wACADdBfMzXkj*;5QFcH!|)$m+%0?S4qAvA8siQ5+-*~!?_bb@fH%yT%7yF zEX4^cl}p2h=<dKT_|N1hJ8v!J-qW zP|O0q`N6Fm#b>9}qz^T^04+7CwS&(Ta-b4>Hec}c4QX#gRd6QP1T&z{FZ}=vigtz z?&q+u-K%CZi2HMZY5UsXHUM21o~8#G`M&C%2ikz>d%V_+s( zc64+0cYNKFo!X>!Q(3p&n#~*)~JuUox-I5>zl1nUkO+QeS6(>e+(cb2A>4}kL zwNF}@lGOlRur#<1@Q3<-OF!G-_}w&4xVli&$RrXp2HVpZ zxy8aVp}nSIKrVkjEEoGtPRaaGUD1BJM(VqfqK@`X=QD?VMcn_beTIObW3+AX)VOY# z=Wb`pXMECU7ms6*v$ok%@>$dx+nM+GhOCtY80ZOR9Hy49W09HuOXll()@u7&nLFw= z?U&3cRi$lG_e)!m1_1{VsN9aA*+rxC|FIc zJ)NnGzR!Y<$pf|G5gqgrj3yPdZP`^iFbwv*;0W?S{c)2~wS2Dou7|Ns(KF8D8Zhgf z=pX1FDj?)xV$n#$Ci`e7-)#hfSl$W8-@aFKVIwcR(RZW| z%IPV8kve|&f}E^=oJ9n;fOEsO2F~5lvZp$01jSM!0D0sJu)!8tO@=%RgmTID^at29 zTNwd!JmEvg5LFax9TCFjenE3-*mN^Cw(k)Kk69ZH9)Cc-`yueSq5ydO^dkn3-{HFN zr+ifikCOMCJre3VXpOA%9v!qrdV5i)2G?DwQ!FQ4y=WYyk^~IfI_E&Jfd2}HsWejF z>v20~GvT`=j~`}1>w9lM{m)>RqG8?>^@O>lhXgURQN+EM*&$_h-rl&khe*yq{&Jj{ zNI3=d-asHfJsno}^xSv()j@i}7A_Os4r2md(rVStAl>`?`}8KIYpJHvlT~^lrLc%` zkHbJ-*O80x0zb3k_CEYm*eIY2XAi{p%~|7>p{m|nCyPoYytY{`f_fVe4Xz1dHlWw& z8b(B2-*Y})Z(r$P>6hGC&s12)_6t_?;HlSCZ{DMa07im;c$BARl#YFhi~-^L8K?-C zZodYV+}Bub+(Yigg4}VBV4rS# z@3ROJ?2PbKKzfOGC>GU*g$H|PWNA9zuGs^^^ACk@m6{e{>ezxjhf!$<(`6=r$GO06 zloLhzCvv>~3A@Lot)^^Z?u&s_+Kw0|DNIvS~hEw;Ubay zAQeczlxTc>s{h~Se4C6ouf)(-9b1$Mx%D|?A3>`s0n3cX2*43JLl(t)YO`cwsQ2?p zcU+a-GKoizX81r$LxR3MQdQSjUxhsik8^BMXe*;+XWflTF=zg17CsuU8qRr0vPDg8 z?7>r0PQ~ON>-DO#Hr7vI)BvoWBZU=|0nWVLTo&a0hUYOc8XKdnU)6 zC;UNx^K>TQJVIQ57hxxeK;IO_qx#6Ld+aBBYoC>h{|wP>)FZpG3=xWn?H-GD6x%&KQH;h%G*Al-Ew-SBDBtX$H|AlOC|QpgMb&bmu9<+ zSCY*$oczHcpv|O5AIjsW*TgNiyi08}ESQp4Ul z2b7v4FrS!$6-5zd*f0^IQ(BZv?QB~rK(SAO^uQ14r!#7%;pdq{fFC74%77nCk7mt4 zAgkrHRZD~|=&6zC#^(SXLpEcK#T#`m4NT=h`{~@9|E!SBt(2x==1DJiDfht<_w5fe zBjGSDd2#MnsZiJW=X(E#1~83}^U37Uzlbx}%ARI&bb1m+Bs8t=6=>A!M$a=rM0JHy z_J@$wM0i)CDc%co$h{(7Zr~EHIt*mIwUzqorZ%oc<}xUyl^6N{I0nW;2LYxPNqZ1r zj5(3LU=fDyN$!ZDX!~k*6;LA0mf5noK&>@%E4>gKe-g=M8=m?m{v2h`g@&=J51Kxk z0My9eC{SB%riSLbc*?7>e3=lcKF}DOpJFtJpt7nnmI1A&w-*8lJ|Qjan8;%FGSwq( z<;Xe8Og(Ze&?AX1IQcHi20pgbQmEo&0V&d3(E=(mrghgG-&_KC)TDr8%?j(9PHC-S ztDUc%0`4aCV`E5IT1JXoeT~ur&$2ejfBD6ntZ(FTuky9ZfH|a9-3&q?kUCZxmcd@r z068lUfZPUm$7Yd11Toj;r>o`2nhVUnw&axtC~yZ^|8f3{E`7?d7y;(JhPCc>07Ov9 zW@1O=iqr$E%@5G2NS@Hx+kyjs#)8%-33#DW#Q>`cI!D#&#~?jeQN8#|G&`sU$kW)* zFTECXId5w&rD zUZkG{QDHW{2#0Q$G@T#!8==+ABYhb!`hod0)q2kcZ{o6P4o&f@4J{8_C5qGaoU$kq z=`h16@MOS7+>b}6>M!$HO5IYF!&=%D zEMjot!%Xkc|7;o_2JJg|t_>P^&{_@}cre9^hmDEve>Aw{d9=3PRt`O42f445v+@!8 zK-4~I`wGPNqYNyVpVRR8QTVYy`0+ND!SLgaTp;`YcW#IuS8$)kk4q`d#E%QP58mLA zyrDF8cTWmGUQPwPIMVoW6X-%w8X;aJN@V;7`Tv}n!Ck>Zh5j+85kG&1@mEl$)qdPD zRrTJVja+88a^R0sj@6;g(&*F=oH|M$LP9)=4e!6C;@UYi8zd?vki)Xmc;kx3|;Jn{J-3WID zp%sJk#?+L9fa(!xjms7#k_s0%>J)-sH z$fIc4dmpmOah^EBXQ@|MigBk*$-!y(y*h6ftY~VzyK_+}yf}2t*V~%swQe1<=6j-L z&txn+XZIbj?5dJl`EhG%ZRG_74{~XA@Fd6IIQ_NcI8f&+#~%1nr#!NLv) z3-^B{EbMAtU+47!03kT+fD|HHg68-;N2F~edRneYGF9;_ldO1Vp4B`BCjZW$tAUjQ zsgzH8>6&Qsh#{m1kcEED+653zC_|^5`4AvlFCfaKWoaNma zHUW|l0V|itREDrkK8l~aD7B@_4aV@dMRo#b5WJuAx4mm%ob$K+2^aX=-p&t6L9Ln# zejW6;y@XOBRXNK}QjJD!?o2;h^SX68f{4`8U_rOl{3zJ7K8d%jD|HUH-INHau$U@D50KY11uW2oXpjxs*yliv$eFrS-3}rS2ov_n6TftzOYJY;+07nzXPrX0x z<5<*7J|2Jmq4Z}85Muag2>mG&964oxgr?jg?t`m;w?F;)T6YRR4Sayk?EjelobmsO z{={Pcoc_q{@&A|p{N?8#MSosJr3=)2Jo9^ie#|qa9L{ij^1$^8d>T$llfztHAcI z*xuitM(l^Y$Lee}#2%MCf}vnAghHyggz&c^@`^1ezPJRjEB1ad7)!o~a->Mynu&gu z06~!>L|~+lZYta%#(~+wz9Idn*ba7zF1v@y&b|&(FHglgfP*tb9sU{qtyS#&$B%gs z0zMT4e2Nh8xDQ9b(~;AJZVmG~BrL3(j&+#+;TU%e#ZcD~_oFaoO*WH(2?0PT)^hBH z%dq!tB~DtiLi~OpKA*(N_;9&6*E0OIg1gU?s@ycwzvL2atF-2iekNVoZI_|GI(Y0q zwHL_Vh%Oyfbbhd!0+<1msPLK_%m6sZ|1+F2`9xU%z2;9wRPCU=5ql^rt0XokatI8j zdTY_Wd5@#34QlzwIHN_^I4OG$n(Y=e+pag$Z)2F2l>`h0K`RV?|0aY3b@7gK^&vgM zaE4B8Je50rUR2T5HvYX*Zm$e$J$u5tVJ958rh4{Devq)L&zqHF$EtbP66|rsGx~bW z^g9Q&*g^RVR!GMgg`cEwswBO)F=73xT%vix7(Pc{YV#Fx(NtO~19^=W z(Bg{*jR~RNu?%DW-}b<<;0wo2aQomlvP=Oqxu3k}5X^&|bjC!`Fs61c<0zBa7$rcx zrHRLDtNw&6{uX}P`6x{I4h=e(!xe8+$|#N}`!GPVy+BrIfQ&gVh%95WBb;kQ2YI3h z!QwY|^AJURUhv|p;blpp?Ok$w(Q`@jjphy3_I_b=her6^=>k;o7${nJj{0N76@NU0 z51EnsyKm;`2$*QSXG~>2o~$Qr_{OMI^^p-0w&{sJ4p7+hMH@ArXEjPX|4RlBbZ1$? zZ(i3(SaP+W`xW~9<_WGDB{=2;*A3KS)FWQM`w)I~A?fB`t+05!&8A zBD#Ddb?J(-R?Ms<3@t8Ysq@PS2IDtUCWtW;@iHQz9x;<9?)Q{j+#ufy{J#WaTCu?Y7Wa%q;GDk+yxDkTaT_Wa7O}9bgmlFN=7)n5*r3pYwKM zfA3>aY_sbEHs(3{@Oy0irzZ^26xm>Unlw*xQv_al%3SE7o4y|o1B9)CdLk$wYF`24sIG=fv+i=5E&6{zR=5bGcEw0ixaRdWv^>obtN*=pt7R{g>9EoA?>7A)1 zD=3w;HfrW+c33F~`p$ZkZK#ukwVpIOW}P~vte1P8#xr8}RAau<0X|R}xi2&4L&JOA z(NA)Ec&G?rBIx=pEO74PGw{3XS=(huFZbtfYAwfbfF4Kl9diqJKy4iw_2Aciy9buM zFRKMZ=FG~zxo-bB{3o6b4Ha~ufwg;aH|S4%0h+-kNqvBdWx|TKH?xGeN66nuON*Sw z9kN*}!lXvL!tG3ZDnt_bLac)cX$!OQNX|&eLqvrTbR`jrszVBrZzue7W)pmuEL=wc zYlrWnUqU>D-2kFwgiDSc*8d+Nzu~Pu_~E8Y@E*I6%*J0(=B+zalW^-9mK-OJjuB5X z_E8YK1qUy=-KxZ-ujBoOye02SD-~^D$!iStE`DOfR1#qoPevva+p&&F$oJ)yKZDtj z3<=9A*^Z5~YS%a>pzt^Ph8mL|%kikrihEZUdZ&>;NaZEod0^7WW293luj=;BBCI6= zv5i%|8SVJIE>^04*17>kEd$xfIk$cyXgJ#OR~D-OX(x~=@I2`GwFzW3bZ=+5Bi_{$ zA!0|S7*o3Hrnc!>!G>3MOOx3DGvmY@e>$j-^d1{z4~D2C#T#^Nky^>ygh?fg4Q#1` zwQ3n3_iy;^amLa&jddgE8~H$Vsvk*ZE4uoh0;uj1P&Fl(w_kDiI=Ja(Tdst+x~UTbnIE|>sYud({Kj5u{%ikr8T0X{U)g+2quKu3 zL%`TypOHG|RsbG~yzs%*Vg{Ae?RKpwuwG-S-x5GgiK+>hU}yzJV^b;*UMp6Gg6OiR zd5o7{2Ka-2R;M8!@!hOSo+(G_{He1I&RwdhZ2xfDtJfnz5LsEt+(TedM;C7- zS{4wg*YSeEQEOrUzs+3%IKojxIQq9~hMGz==7dRm~u(EYy>_1>1n8P$r- znVTuqE(!B<@)AaiP`5CopT4ryQe6(QmxRU=^UNx%8uhbR*;t?-f|<~JY4-CqexPi2 zwEZslkGMCfg*x82Ce>sN^L%#OqzhG+JCncuaDo}U+^JkP9n#4@8wg@Qmd0RF>B5jI zAbTz>kKQ>DRQ_QPIu-F1M^e2fx0Jv77p|}OH~2jvjG|g7eaEX){pqvo8VO=R3rL*~ zYR3I>Z@j`lZdLp9$RTgY3&e=pk^^=_REGC=B4@(gRIK-xmPaHZW%&msd>kgBS%q5w zg&4<}a%5KAJGzNLx+T4|Eq5qCQiQ@Wrm()Y9$8`XVpV|`%WLkMoFqKJ%WbC7xSxBK z2H{USkDrQ-4jqUBiX(#tpi>XBgKZac$ZFLG&Qnm}wlL9le;De znKNptDKcM%3;=R1(5FLup75!-!=d)C8Y#B2-89A5;_?WlZ+svsQ zgxnqc5kc@009oj`_vegw_ogpE7`yC&f5W3iq<(}F%YzMi$lpbi379&AsFWm222_uRT?;J%%nBs)C7{vpxt>Q!&r&?|YjJbd;HTj)~Nzfcdo z+_Sg_5EA^LP^t5mi7gYmEP8>v+8hz$`2Yxq1PvnwQz$U^aJ_`&qy*Kw#XN_OfUy&= zS6IEqitw|x%+_L!#WP}Ql{2>TLpaxwqSQCO+9yaxF14?Fk~_l%UhZGH3{G~RxH457 zd`boBPn@>wE&Id~@xPHAC%&V@Bg;PsY7>;>qe^Y;}V|PR_w~;Jw^tl8bk>MD>(|V(hfOnAgJ` zLU;G=hyVXK;OAGtf$)>0ES%wQa~W*j&PzhkehYE`Q#Q*l*bc47sViV*}CX51qe;`3!jPIrx(dSP&@JL z$f6^0&LVU6yGOTP5p+*czdaBh3@BuK_1@cJtBLXp606x4~eyPL&_ri z>iyv<$dBHsT#z142&*HpY{V&UvxoKH;?Rwb5h8MPAvBIP#d9RcSW_2Yg>u%p$H+XG zi37&HB)TzQNu0r#(e?>o1~2z0N=3`(*;0Z8*8f9GJ>nUDyiptNCU+Y@)R~R%9aq8M zzh^7`bFS^JV2dkwKn0qaV5Aj{x=rs*Xy-3x?L<%RT&`>adU6{FFBgZG!6Qk5$f)_; z`xCyvUwLiq4DO+rGwGts?h<|SN5$>=N&Mw02ZrDL?Y9Q}3CHW+A9b=T2BO}7k)bZ+ z8P{)f?dQJB--&h|{mB~dn62C<8f8>|x~6mymj!Ie27y}e?>mHZtDi2RoK#ER`e2pN zx0h@0_!BnkRi*bI$B_IH%eakuFJS~mA=>c{pJ+-3$oc3EViY3l)DRwez5dyegg5Fo z>bJd(ki3nmiN+p|drwY(uihWO-i~#RJ*Y|C`#d2;2(OCX;9gSj{4WgeN5i_tzkmqY zwWN>DUysm|@AXFSBu(`6h=p006F1tWG1$2qdYex5FUwE1EvCUqtqk^?U8dKQ9g+Zs z=bq7bGK9y_Mit7j6yHE55tc=m^-P(6KMT7h&C+8@FGvq*_ zkHOXl$;hSszDoEY0qQLXX23kw`m>5rQew{5QAf)PnK@m9{c%b~kD)VGTTu*Eyvjt* zEG_OYox6hB%Z-0F2Q3c^qLfcOT4RK1MJZ&E$HY(b|sfYTI`(VdKdJd_J?l z2Rxr>)Zwi)Y>7zkO@>TO&98XKDI`Q(V() zz3aN@zpn8@nv2z_xt^@XuU>WadJdfoI#vjq(B*!BWb+ez{^<+|#Tln?Mc*rQEcpd| z&U&U769HloNiPVW4Tj+aY5|Zep)G7s^9!x%6;7Db@mtH5vZM@_=r~rDz9OX-#mF!? zLnayfB6=by>)W5`nJnNG(IUCnm>jk&aJyQ;_aC5@|pVI+FzWA5~yxA~L}s1~C){Ddbf_2P+q8u`^WJXEE+pK|bU z@rc_>Z7YKy#&##Cm6J&=S}U}*?B`SqdbjT$n93Kmy(nMoi- zM%$HchVb`j`!S$U9-XE~(e@3@G$&LX&s_y4w<4Udao9CEWRPMSuzl-a^NX?MtT&OU zP#C@uO^)IviKTw-2hYIWHTL_Xc5{KZ{`35_y_zq^t-kR^Krr8g+5V$o40M>5xHM~G z3$1eBv3=o-9j`8Yu8IKqmhCvHSPz!nl*wJqiD`xIaAF zE-goF@jK9e0gB^0qn*U>UMDUEEW1C3jc0d-U*R#5gB-(YFsv{7&PgCxrK`!`TY*zv zEF$(Z-yfMeDq6fJ{)1Hs4i9gBs?I;iCqDYDJU_4M;g(Xa3hI*IESOl(@~LFxrfl$5 zX6mCgtn!jYhpI+`eO1tpmDauBJv=e5b(1Sx&rD6r-pWa%(dCD+La;FB?-&Pj_Cj#t zEqfT70v~qYD;z^Oo|k(n59|D|FtJD-i`HcY*FLcu^y}r0=0WT5{wem*Rw4HgiqNjg zl-GEqFk$CHORd+@DhX&${~j{#|`TT|LxyD(x7`FkUujxLrJVZXFN%B4Szm5yvD@ z7uGOtr!HJT^i=SJt-A+S{XvSui+)KGOl3x3-ag4&!JeD<3^;9HPwsFE^v~H}BriNG zd6Qrki)Y$r#!vB>M0`An3Nh}jYxxgB0D<{ulJ?<=ww=l=C* zlGnlyJnkMhGJ>$i`Kqz_y@jX)Ppn>uve0h}f%DN1VF8k+DvZosK{_`Slx&^(k~QbZ zWQVF!RK>-QYy2sDDdV40`m9ArNlGI%q!~>4mPEb(Crb(8w-({)AfdU39bFiVSS;@J zTSYQ3tqlfRVLGvo*2?AUS=l3>u@Il8(!98bJu3R3ru1LxOP%EJ{yM2$LjBanE|cpu zNGH^5k}>q)jxQ*hgY3Q}G4=d^7AGBIxGxTRdw$23ISvxP1iKZon%Y<(0n z_qvP_st17|e_n{HYibZR7+ ztL1Ko*)2V{|LNLozJs~N+w29?>bHC;oL^ik(i6LxSsb4^v76Hqn|tX~qE79*K5~BL z{Jg5-+aQFjlV#n{9nBkkeZa&ZM7UW$gPNK9=U>csu=W4Xe0z&NbiR*=vHHK7?+VxM z|K)tY@#M#uZ|T;872|BayLscE&UZ?`hYNWM70A~kRPQCgQE0;qNv#j&f6GnI$+g}t z3%7jU+abC8KqXvyGxr4w6ZEgO4L#PqPnLm>7h1lA&ZFgu1epNY&h3P=(=A3}V|8lZ7=#2W?4VyzD40a4nT%7<`?A zfcy?wt$5b{6YcM|Nnd^fV2rk(%rn9x2q(Lg0=9Nqh3Ef|`IRM$UDRN*^l=fr^ODt{ zf??^26e(1YfSXeZ|0+?8&&15w9>Tvu`_ul>J&G4RX#e=HFjjD#bj7KhY9N%u1_OHL z<5Dvi(4%^;JN(%{EPrJW$-Fi<;aGhZ(K;7p1cp6JJVU{-=BF^1y9AaN0N7)v#qo+9 z1DZGb9qu5xXvZ^rGMEk(WMM=hV*fgyCACxGVX1tUGI3vfl5$2z4z0^MHWeD?&I}PH zmLfevWyR{O`>U$sH0?zU+f=Ykl5PvK)ry-75jpuSSA73)9xZVohfO_CmFt z(XR7Hqil$4tkdS3VZI|BhL$JH*0xIU4UkC96SRR&u-EkeTHrsJWV1SHywx!bQ4ivn zloZ6f?3cXLgBDmogDeRfqgJSXQ2@CG6f5CE>okG3l) z05NFk3;c?nEZuJNox7EK1k!rHO$8)bxKO>n*m+uFjAJR`t5U&96Nh+4CXx@j;G~Zg zL4;*j1QkSv={(Zq(g6-OUAbS=(8P?$B-zhg+|!WYqPABT=W%>2>C{z(Dp%g%QfPu_K!|N{EeI7=IpU=HO)|Xk~+c{ z&HA$7o%~XTCtX0Vacr)NPI@#w7-PELrka_J)rB98 za&*1nsmuK5(dkfLA4Z>Q{2KzJPSf#?f=!le|&ygtXL;tng` z8de@Q*QE?_mZU)M5p`9Xg6U(eTsq2nu$c|j_83?s!qpQ!uSg6lG7 z>9%c}rEpYF|AkSle40`H_G6F7&;1i`rB{zIW0V)IMHPF3oy|0ze83h2^?73B?tz}% z>!}Rh;f0Ss<|%2kHz=~1iBswPfv{eXpgF;&1vrRGB^??1%Y&By*do#PUG!Vu$mQ9| z;t?q6?3=v@t2FP517@iOE_sHuv z%)x>JmPplqEkK&X4fF%4^MizcO;K>ruz^Xsv@dpSNG4$Y^ z3-(%vWTS|d^`ctLy|zHg!PO(OrsZTsqBAx}FHrim=!GbX(O?($J-}iJbL6??>k3m#>?et7==>$T}Hw_elmmHc??wb%d1^-9^-U7ou}4l)`0v~7kZuQLcsLBRs)p9i+BhrH-uJGh=o^kh1Ni@Y^ISR+j)vV-ONtlo;1?nsJ^vysR6?lw-a z@?Ns@RuWR12A8kg3t1x8{X3;|tl9R`ukuS~QSWUmznvpF7l1c{)^)qdQ5b2y(wc81 z?!E@CF#!Z9K=Y#ay0L3c$BpXVQY= zetmK7bt7`JPXcCu2CSLLptD2q_xyCepCKW?ZyKI5WmBk+ zxZ`0XGU&|y9Ov^RJvS`Iq^*BFH?)UW(RM{vkQ5Jul|o8i<2|Mt56^GOxE{!|2}o z#mY(#^f5FR*!Z3#?+vkz!Gq9!Fi-#Dp=c-fI^!ws-3SjWZL!sUDOl!e_nk(On?;)- z!{S6qn@-N=4U>I{-_h7HfA}y>T1aC$!XO|0zZ^cJ?c(f6iq`UF$*pr^$;$>}$*TrP zk9!G)7Y6%Q3m~!2oaN-%5hv3^!e780JT6S=dh{p}3^k9}^Lv9zrBw?{tteS&UQoE* zEg2RWSv{=j1gCIJh&P!gO<98!jix77j5@= zm$}7XXX2{ef?IBad9l3%ZSQ`Xoz>KvNa7!!ND?Gj&s9-9nz-W5an^bdTjT_qViFX? z<4-7}H*WNTGe4uUlcv4cYyY;!Zxu_d2Gxf=>YHPWyfb*^)V-lBBcdO?--*kg)y z6+d06R`ad!bgmG1LvSR);t$Ro7Wq|dSj6N1$ZCfE9SFp zK%q4irI4m*zeN}yNB%68N8vl%kAxofAL!1*l-`0es0J< zp0G%PnWU1-eRmD!)2>)g`;x(ZEVtEtpJ;wL*0UtFk-1FmWG+)%nak8(<}$UJxlHfo z78dHm>8r>C%6+317=H(8g~)5@&;A#5{n4d+SOn<_mx_WyIId*Ku={`K&OhdSZh{?} zW?#$q!Uf z@msm)aBb;#Ms$Ay#-~e>>D^UZo8Q7qHuoeOLcxg7*l##IQWEId;gt2QX6smgzhwsf zV}?`K|NPMP`cQitiBD|d+^S)4lf>vfe%}j*(Of4CwMC%?(19V z{{Aso2MtCrKdkUqtMFYJ?P|T}ygov}5NbItMTWQpwmW2_*MpYZg-8CSLC$uv`-(8i zNm0&nq~qX*W2Ser)=EV7djU}HWNzWHzFx7t;?@2mOcAm!Pf>tXxu4}x%f%$-Z^8v6 z_h9boai;aF%YrLF0T|+rp!l6GimT@5W;L%-%}-MFjEbP$N+KQ{e!pNd_c6+VJVj>Z zIo=blVp8oG)qLL0H|$)ARTrF*4W?N&a0Ld2R*zYueo6tl#zhp(Vcfyh3qfVNvV-ve zim%f_FiCt`WQpgaPql&(yIboAL=~@wJ?uY)f-I|s)-|MqSI=Ox--?p@6%0WJwosP zsASkg;{I?Tv_zOw0`JLb1#P+4@;JM%Ty)@~gtyB%6uC8D^2$mr^U9fWH-+0QN%;59 z=2{LeoR&29n@kv@LrDS_e%_#GeH$5e<#zB=a19O!F?MJXH$W^4wDA46FnQxB@6^h? zSQEVP4G`*(vP95JnbZT;_Ou{-DcY3OZG*+qFDOI*jBiD71%yc>n2jq~X|eQmyK-Sv z)Gb=TCcZ#tk>9Rg{^>CFTiqqDFAwB#*?+o&_d4v^v(-yY@=MuOuR($j-52*O`JK2= z2g~WTxIex!x_r8bPTQJ1@8#r_fvVMu*0s3~!2PcE2-?HjsUDLOv-SJt)?@fI!?Pzn z+|wB@sFHK4_MngirMy@N`z>D}zBICW^7=?#t9_0F)_)DNrAeU|i4?`6 z+0n(=V;*{XexX+L>iqBB#igJ`5toPaM#Y{GduVXw!$>d(+Njo zKf#k%x{a9#HicIWo$yHm!Jp^32eaMns_=GR@QbisjeGFldaz`zFbh6y8L9-W%xvQ^ z6teD-?1Cy7W`533A{kko$bKf_x!_4{_l06m?5MBy(#5KR8ANZSb}CCp^v!oH*fNfb zuaE0^4|a*lXuC_}!)BTR@LLXtb8J`DgT?q}f|~9rmF__!q6Fk7B?SZ+=is=P9ryl& zlQp}GT=*PdQ-b(Lbl*4ey(3}?f?FobQzb`$M#2!kp5V@zV6cuZY&;5Rz<5Sm(RPVY z>T;n*znCuln!H5LQQ5Y$n2autazk+F=0vCtp2`G7#?rc+BUFPxRgJK6aJU*ft(WUO z4k{Ltz>Px#7+~D{eB6T#IK{>j9G@PH4%f)5$F9&+@}c8!z0s{YR8SW)x|o3^^GBP?fG7`M@XF<794YpbatdL#^Q?ST2b(~mFVO;*-8|9FG6pF)@K# zE4n&&$zN?WgZ8I#s3G|a{cB5PwA!=6FFXz0bu_+*->BGvy`^pJjoCUU2Q*j}Ijwb< z!e!Xn1W?wNw{GE-2n7>d6zoGzKOv7!q>R8EV@a8_UZhyjPCda1!z9x61g|#k8St-$ zQ+OtLoiB*9WO*$k00K@<$k4R%~(n z0~qHFiA%$xe~QFTkX|P{a$>k3v5Ar5MLQInC=+UJRdadkU6&HR66V0eL9Zq&4CpEd z8o{UjISipk5)_Nh0Y36|XJH|ha2{QeDx&EToS+6uKtK84l*)R{ndPDa%GXkGDJb6( zg030V2ZimI2RW{N8U+IAqwHb&7^_=-O4-99eOF)V#k#$i=?=T?ZGMqQ5ELRP_=CNc zm$)V4DENjt()3(yZ<+4qijI#t6m>R@Z`O&YaoAR|2VD_; zQq{Jm(eCre8bV$PhOVTmz2A`dyC$qyC5~l7^ON+;9PgN|^RmZ~1i?*l$)!$&4W}9S zI3MtCd!-<_=Q#m4K`m>7(Yx)C?Hc@{$&1d^s9gUiiCe=4Lb?{KDclb%^p5kqFJ=#M(V`+W8j}z3z!m%O2Le z5q_;DFB$74#NwN{TC0snSTEvNXC23Zez_<-4;1;0-=sS~LGQ`$jfIe_ysUE?v##^;t}O~0e02yy3xrawVpsjCaoVA}`nZX9Sz3 zh*mLVbPuHk___tb*$<-mW7Z&zF9ol%1UkVwPV7_D2sByv9!F0i@4+_;wW3x~ZJWH3 z4=2)Qrwe^ppBJ3saWo!Di=-)SU&UweLd`_u7Lv`Nxn z6DQJ`#Il!xuT%Ekl(NI5hqg}34-kKjn&Mt2Km1Cx*-Ixv)$&6j91&KmKFcIkh zVkoP;(ICis`Hx#J31dvrL26|Y1gGdA86L?e#6us0G4SkUwNrAS8QG%vG|5&t`;*OY zY$b-x!_`VT&_dGrw(82P=ucNmmd%C`cN1~6zIhW}J%fUTpO@eP|C^bJe)~{ZGgE#H ztp>8JeSO4J2+h3brH(qgo|lbzCJP@@;FCjkpIM(oaCqU}4` z&8iY@znK9uORH_r%!jlvcjrh81G&!0A8z^%5DA|@wzut_)@ZwO^|ZZ{(!{LpTbpWY z*%d4uZ4u*QYs>_wwK=KQ{9>mjp|v&4$I+o)C))n9S{&5v^ljtbftMdc@3JvHj=l!< zHB`Cs8yP>NC+)q4D6cvOK$qkChM8*RHG06~4|QVPzr4u1p^I-#saH^Ex6DZR%R~K& z(B7!Kc@28P>epZ&;JCVc_~MiPl2WVy5(S#cLB)!Fs2900~Av6&g)q6|v%@C;NcM#T-Y&o3>4tZ~>kvMjZGL zy@j?zE}M1`668dhi(;2$M60q;RTijWtp7Yt_#8dW+b}t&Th_wpo#-x}RJxb!;fQVz zX9MhGricLtOPM}OH)AGemQ0SIBhaU?Az&%cntsuDBvb9w3NHab|K1gV;6e;KrmKUs7ygVcUkyEVog7Oi zXc)TWtl^K?GV(xu!nr>a3qm)EjI6>NoIZhw8*x`D`EtoC8?;6tiHWv%hSX(eFdg53 zm?TOecyt61mvjH|7Bu~XP~*@L?3gdoa_ykve0K1g%SBnzMJ~H@@I6YAU?H_m*#fVX zpj!^7k1o3kEQJF6LEZCD%5cHG{>9)>g?5#<4p|*o2?O}h_^1w|IJNJvy4Hy3s{Roa zsi>=AsK&GVslI1(F}}9yiXy-`(K69> z9XZyzm$pfL`$BF<~UAhs@f0qRX!aT>9^bdA&M=fvmKdU(~152kA+3 zX?GIvO2atlHD33RecBfhA-hg{GS|wgtVd)lG^lkUJva7;U}tuw|7@;B)JkI9aPgS z9V%(7F3O62uN#w2EPI0#!5pTsK89bEjbI_b6X)$L^5t2ARgmOG4NIai=(*gAz z!qwar`sUZHPdEBQ1s=C+aDH)~StWbzsoMu27E_CBM_0WC5^sQL$3(iL$wwg%wyJy+ z+^T&UOdL3jAz3Ec6yzFW1KnFK5)TwuT60GDNRv<(j4@&Wh|p~{Fq`5^47<_qLY}sl zE@n{a!qhEq&7)AfgsyZVYRFq~YBAeGq@qKy6x zPLmq#=+UiIXW=eueTY+vZRrqWqV4Z6vk{lU)?w~6 zOJMUMh0MYX)?kRq2TM`Wdf_$@I0ywb&xbJP<=ihmXJ*pc?s+>9#43Jhne?Fl{Jr zU>>O>VGTXXXgLbgrH~Xx#;u*$wmomOykQgC*e808j&9(dc^a0o6UDC@aHCGW*7n0y&-X?qV{WqOCo%8#U2%&t{yiLPb@W_R1 zSH6g6#6&(hcWDB6R%0ZJfsoIJF%NllCMy8HL#Skv%ea|Z02PC!MLlgyaLhv zK7d#?s!P2cOy0cU2WY$P6IjIRQh%D!fzQ*X;ZpoLA#Gh19K-kgFxjD4I8@R!TVvMF zV|Cf!7xLCZoX)ygU6fJlvUH3W9a+OMGaB@ug{vuQ?ZUZOnD`JIb=gh^ZNen@?9M>Prm>e)619vx=KPmHwDM3;So0cb?w z`GI9hug4o@sR9@PSU)vgUhl6^a2A9EI#!ssQtrY8>>)71%*~DA$?uMf)aBOLgA5&6 zMEYM+Q64|Vj~|cH-X$&M?7`zBSlHH4MeTipVHLGi($sAfm}1q0@=#ujS8+ZWIZ(^t za?1%(D$g^#JvtUWuS>LmxqLi}^PW4n6J|GB@SNdtl+B<%mN~@u)0#?OKNCbzL5YOR zKKBINpP+oC%EA2!#&bklj~!dc@N%kPO?5u3n;FeTjHhH?C`?U8yz2Dm@k_^z&CO6!ug$8x0U9;&b`$OaPd0 z%y5np6_D6Q3eNqmrI)Tw9lSP;arA(|KV?gVXm@e$AKwhA1$Pi4md%k0n>$3v6ut14 zbkVHH1=NzMm4<^>MqSPOX>vh9{o|lDx{&~RxWUX5`xA)DK?1?_w>}Kp-^nr#1mCO^ z4ncl&xAVA_O>tU6XlQ4U&@Uff2^L&9gd$wLgTZ6L7`vuzACoE9VASvTI~R`LzFpkk zC!py2x#4lpBD;F0b~b3G?{X`g@LVLEyWpssFamV-y=CQKOn-Wjdwno}V+Q^WB^@cz z911Q9u9AKj6zq0#8U&1|=jxDu>CR>F6?cn~C6rSIqt+97D(*23 zi-TT8N-ONU(j)_vVHG`;iMc zRB%o~q&%ML4bs2}g;|2$tv+;jk%* zS5-upA8Lf-BB83@Yc6WOz=#GpjwR8G4Hd-Uk?_X7(}hb*F*IXto~{FcNN5+&g%TR&KO`LWd)7)4wDgv3|CDqYJDUV zAuM1HZ>Of=5N*^5Ag=;8#UoV44NgQz3JEV~D)L`O7pDvf+a8 z^m@Xd(g4p`6l!S%zf0vM1}%w`rtsQ786ZPCaQ&FYdeW>kN{Qrm%pVNce|V|F@b(7# zlDlQqavCQCaMqL+Z(zm6@$qAiwEjhVLQ8e}%ZnVDYj z0xeM3e`-9bQ9#ueWR8P@sjt!+^;KFkWB?{(KqG<+<=&II64;?P2YIx^C>Gf$G_Gvu z(|q!?EsA!;jpk2y{JpV`j|vX`wy{vOCblNrQYj9K&M(gWT7SqvahJ(Ku@XdHIceK* zPyX3OXq%@S^=IFVI*m6!gm*Hev;qF<2-{YVGo3@V@8v@oC=P{imfPUe8gUD_<8?BV z1Hos*+u6a0&$|Z;+=Ih-0M`}lIYWHP&fqou0@LLOirWD9Jf`SFsBd4u{!IC=n7pe{ zE0cHe<{+I5vToCr3X}df)WD)iSxqGK3%>Sm?4uyN>10C2dnxU#`t-$F!DAlqi#y!W z<|<_tGuU;qdzr{fHV#^J8E#U6iuT~mT`7NvK+`(-$^rR+GqZu3&j~zqXP61(0`V+( zapS*+$7am`MsZ9zqF{>(g1cdoGE0hr+pPp%jJ+Q^1SIz_DhsZ0MaAh_<-wKv7gYu` ztY{VrY=BtVN1t^JLl?<|}ZES-CAEIcP0yUG&z>E%v0vfAUZbL0?v86h( zhzLj$%i%CUTW#sBReQC)w$)-=uk|&A@DlK?L93vs;QJZl3upy=!Ti6!z0V{AT5Ef6 z|NrOz2Qurhq83!dM=@Cjvx0|VE6m3!>5a_3Hw7@yND>DoFi3TsxG?|uL zDY$OYNGz+UTt?>O2G76FbSK#~4mCO+mb|m-C@*i*fs)}d4HHy|5+dL(&naH@VnDIM zDJV8m40G|TI!q&VT!Sw4`uBg)lFUl`cu(*cY+>FKJO*2sKR1tJ!CThO$P-Oh83$m? zo_!bUW&9duuYs))Ow6zgzeC%&{5AK7tJJ|#dz+qMWHPL(ZzNr{|t z7|65@%Ni!g1Yw*Jq>jwbMVfiTRG1cg$sO}obTbULNUd6jc5u>6=8GKA!ZU7ydh>kH~Z%OZuh-r0*oU4I7srw@7}+cE&-c zNs6wrs}FM()PWL$Agn?^?qCF5P#&*b?S>Y%pJZuaz*nve9s@ny4Z&l=X8wVB)WCnp zoWqjC1y4Z^wG1X)tfcXPcPyif0(rSf8E zdN__Ao*k~;YRwnqdnR0@B#|v(Mm3(ASV5ESU!2w}fli|3vg(5L z94?gw=}W8uqR~{GF%|>g5^}84qb%7^Aq6w%N`e<)G`kyXaPO>`dzg1d%$*#D%}AJ2 z$4rnjFtmJvqotfbdM@F8DE^JL|7}@YogMOl)`K8}EQHz1Ga+*Nvg{|Xs29FExg#N; z#lb$JOu3({p>bE#!_`Y<1?mDo$$I*F*B%1)r zB0}i>EXbU$NV%_=vtHZ$2lPSPYt4`IRnHUq9ybENgY_eoxnuiaa9G0}oCHX^4^Ew& z!j@X6P+SF--R=Kwuj%@s3@B4O|KKLhJ*%QcoB}fhWI|>p$JjV^a!7=b6WHu>?i=e} zcBP}EN8USkko2iCtrl1G)C_8n# z{1I%hN4=5M(+n=+ZQLBMx%&*Q1aD#{M*?8*?*gcRN+;@$|AOAV?0=4{2=b?g@9NE- z!hB$Iw*ocwKhItO(nvNWLD=;wy>(iD$}bwj3hc1iSs&%s9Er>GSu7INtsSLX+TW&4 zryD(mj+&d#P-bCjX4vnu(J*YxrE{%Rv7A5xq^u{JHYK=CI3#m^DDvd|dNG>r)0z6- z$hx_&!eUlhJ8N#Dk@17)cZ>B1#IPp1LKQmbRh_piOmJU{x=-tP$sV?2@q{~|?U8!+ z;O8B~4kb$Sxmw9_3X#<`207jL?Dp3*R1P7cS2An_qpYocqNr5LI(g=Ovn?#dT(VYUP+1Uva-y;44?SK%fC5s}!0xS|_bg40FAz5>>Yo^$Q`6@=2+ z7KGBt0L4s${SNDp)yX0!Sv0^K=#6m8+<}?#tD>2yt0b6|P&C`@h8qrV!dC>ik+^d2 zZ)j2aE76wsk8|43FGy!w-a9V+LNsHosp9U7HoVee|Dj8u?=%|Gu)y6G^J>cS!Y?`B zm$t;V&%e>+lsxH;S)QH73&~cMR0il(oeeA~Fi44zkL#j;HvUb&MgacCFPQ@45~inp z@r)|`R@hAGke~{vM2sd$Y9ZZ2lq88Oj!|3h{IVXpmy1htVa2>jR#NVdS42b=Lfed7 zD@q7oM_kcA?-#FVI|Z9~MYfn|E^d*cAkDu`&VpiXWHEFAr462fUL#ocapM3MBc}tI zeKCj1yN$mEc))HGsi=|YQ|A;+>fS5t$ ze3A`J1lM`aAwRXHtp3=*M6Z5cEFaC<5BC0V(;8uon*oAi5*aVj@MqoP&$eJKD*g;+ z6fZ@_K@o8Ya{g}65Xfu$U){&>{^$Q`2*dy#_elsDF?Xko%{j%Dr|TA-{HRy~+2KEz zEw@~^@AAKEOKHAaLU;m>3_nK8IR(QVk<(gU<9vh8Ps-)Q%Uu1T-&GGr;Iu(bkL3DS z6UZy=LJbld$R5|2t8|i=t;I*Z8XO-%1xh)O{c7&@Nc-9wd{w4x0R;wA>_u(^gm@-M zT18UQx{r@$rc|xUj9aD2wSsM^O)>P%(ahPaGV%U2ZzM@)tJ%DHduesXAM_FQh4o4>&D9cQ)XWT9CwN~H97Z}>rI zIgUHz#>U=t7S1C$5N%F5chzYMYpvvgD@!?R#!+lBF@T@nYA!=nP_1&v?Cf>eZ^DJ zOdXyi4b9AqtoA;IM_g#~ny8y$+fR}#T9f5a6aVrw5%zFyW+mX|K4{DSUbEyW6A1< zZ+!t*Sfb>SC$D(WD}Ld7=9~L-*%LOqM&U>UYUF>;3^xinQ@HJ293~`{t-%M@GWJA=m7Mk zQMdH_W`G9m+wfRq%UnEWY|VacpAoV;3e#TrM>9SsUmnsbE{6HaSGOQBD||K{gyo@g zq*;xmQGrRQiD%M;N^1JR-vJ8;G_61E(U$^&rDuN%0g*#`Uie2Kn;ZLaSe_hWk!PD< zV;^4r&2ciy!R@X7j|@v&T*_y7$13J>syA|&R%vf;MTvH3{4L+!iCcsho42vm-Dp1D z#n&VL-Eu6@@AUaSiHqPs0O#ViwFNuD)3Iam)ljvnnG|Db(!?ZA^)9|c`^1z zUYKs-Cu=45nYpJJhfqg}FCE*aw`S(K#Xn$db8q*G^BVj0yl-3bzTIZtCiC8&&pqQQ zQKHkltjT*hje>)hzceqMyqAadzg%QqzM1ZC@PPi8-{K`s&ANF@Pxb;wbBf@^1F$%1 zt-=*F@aQF#hYIuXoPDS^4_W(AX&&y>!<4F#QW?uV#;9myv$IU+7NnxC!>tW#@CXb~ z&FU}CO(tCO5s?V7xBy>``I4%q47jhY+F`D@8~HBL;v12nqG!G~?#(N&cz{~%o%97N zM&O*J`b!IG!YIF$(@Ru3ie{@g(rTC+k@fEF?BBunOjsZ3W<wpno! z1hOqFp)!5IX`PXC#mkOj2H$vzpoCWCyP6hW@qC_Ty`dshJ59QYp`c0kaq&uv{FBgR zS~BO2y^`FP55K-r%*EJQWb#{%Huq^>`rotn({%r>AYFMbu=k^MKiS@o(fxRPU#I)g z<{nt0Wz{sylZ_Hh8)QS`tHX*!%l&q>_`IqyC@Jv?R1Ts;z1CiAmI$Zy>paWgOu6Xh z3ew#tY4D!_yH`4ZZa&1FUx8&iuP@`ZEIMp%3yqjpd@0FZX$e-vaGg{sYY>M0PA*RC zW9$cd#n)3x@?H}7E2~4Qh@~>OS1Im08#R6DBJbj;w0y?!y&_8QU;PbB;-hZtcVVx1 zst`g1e$BjY@^8q??|;K)_34l*2Q$=^Od7hn3nG=8C&yQ*lvnJ3H#d2`K`(HxgS%#; zdBy7(k}l)yreJ-2h^jh6_3p@!A-k)?kq?@;iut;QUU8871~LEMbwJ=0AdbbYS@BX*4!RFMzlF%N=&pEtXs5TnS2ei#@c3jg$ba zb8$c7MWShmd5(GaF4@jAK2n#IDILOH8ISC~qAQLM={&Df8~8XC>W)X&Yc6;26!SQ} zdzWrd%x7lN=Jo8_m??i+rskL!Vr4w?fU{I|m-VPH>h7>iLo!oZxIE?^7^O3?8qCEG z1jYyEznZzAH?I5omcGf3;)wPX#hcwun%?Sp^b;^2F~pWt!!(H zYcCRLPP&*^P>a))-7IQj{5J?Tko_UmxZAu?D)b7->&5~7fv06s#}?rEu+|N^Cpb&m z(0OKuvH#4>VR~uOER!D8-Dc4JLcK0ErUiL83gd*iNDfDDH^>Q&3NgXaUbppjp=El&I9ocf2WzeBHfc+$7I1|%u%ZQD^0prC}tm(B@dAd)`(;G6!-OEmkMJ zF(qxi=@Y44OI+N2UPyj}>KXc8G!s55v0}lP5g`JGfpv>W#)+{vW?@@z^Fwj9)QnmG zsKg>2&XVgOF?dtX9&Kpl5(5Np$T|&$yUDx73N)2y}XHL&cr?bz*uCvlX;5gO!#mJb;jBbSPS@= z_i1seZ7jnS#OTLd^us66n%J;Z)p>E;SP*?_?tqy4H1U<9?(4O$Nx>T<((YU*6Ne!a zP?no!FxbX1QOcgooR(`~%sn0r2^Jwj1r6~yx0C{_mP4xCG5o^kj$F<>7aFoBGE=BF zDL_k-XjlGt-9Cggdw^(fuJgkW<0E(Yf%-kjSs^gq`KX1`*hCFwWk0s7o&Q(x>pjioOqa@qvF1nU`yic%@?CNzJQTA;`$sL?#+U9$tCfzvO8P>JKZG3I4 z%XT^1-%h!2C5z6lY`=kIQ?#8$7_TQ&Ih{CR!HoP2bDU@)BD< zQD0ltye}A)x-zuS%9WmQdve-!th5FsidN_Y|E0lbLU8|(aEsoA;-pLk8GyIjtQOnrN9_hlKS6x9nFGr6=+`0K2v{UAo5AQKzn>%vIdqJxXwAjY_!6e$sX1YbpK_zoC}li*%{&?Hbpp?2=crzoI?u z(|EE&(sk6X-mbbv5!9CAbCjJbzseP7{%3Nbn|pXy``U%e`@e$L`%C!{!;RouIy9Wz zEyahch%5Jsa?mpx#VKcZ$Ust?S7rYU^#Urz&4Qcn{EBEewr?!e|3@MJM5 z5qUJdH8FZfH?N%5CuttcCBpxylsJhJ>$xw!hnL=8$@B_Z_p+5h>GhO&K0 zuU-?)*4IgHS}t!y|9_m2$$f@HD>1cJ7}5_OTn_<6`cuHy%?HyL`cVAVS81d-nN7|| z(lAv@tFJRxHY~z)RGoaBOfAFL@Ed9=zEhW6zqr;>D%JGC`PaO!-J1O)j3npby|F*w z88Xp)K+lmnAHOZ(T~OzzKSf8__IHO|%@}3Q^(9_IsasFLp@uSmS;n=3E38mMCD%%>)m*EC>xhKgeJ=5F6Vf2R-?I59 zt1*gF`ELD)uKKXO?e3~C2_1dVyIu9Ax+L6-am7<#VP1CCR|eN=T`6mqjT7G?9?0zs zd`AZKB&ToRWoTeDGp{&074@SO?|-qIwEn0HAz4hOV(Sd!YW1Kij6nj+hJS>~&?z1Q zr4I_;ve`#QGiZHrz9QwkTbNkkmM%orz%Bc06Hq?1ZU!G4GBp^=vT16{%fxZe4IkgM zMZ7(b+UBo1f{K+vtA=_G3`+c8lbSS3S(g_wu1V6vQ|`NVKE>R(hOTk96h*^~ARDL@ zxS}ikeQGNRGB-b^b}|YhyaBYW?KO9RvdGS;VD>O}TsEc<(P563A#tY%!cyHI8~Ubt zK|Z(qDskqi$m-^&{f>jxyt%j>RNMT4rnN|#1_Yf@nU4iS-j|yXmtq{Z4JbSApeWQ9 z;rrBNK^^>HcV0n>RvMn=S;(_umAJE1eT_{Jhl6>h`e`D=m#p9GQ$#pIn^9j|?atuSh?-8F&W#&WpVP=Z1v>4puI zBD?1!NN7{yk$H!-Ju)Bfa^_*af)}+t;%>%rp`7B_&GjzqdJ2E|NS7!~F54JDi#`7Dj2RpF8r2z?XUuhQkDjKYMzz@{J+ zS(Ru>j!dI zH!Ifyo^&u|VBM@3g`1*zgKP1sBgdbHzvGq@2)5ZMj?Y15G*Fv%=qXAflPl(L z%WLOPbzV-i)jz8QbZc1)aLoE2JwI@liGS)QjZ^vnyp zqTwl&eA%q7=yZM66`g4>Gjw4XaL+O!I;G)4v@nU<^>qUZyen-fzgH=VrfyAjo3w&0 zcbx9B-R;hqk@wjN|Ila2iId~1?aV3v&}XrD%6v8@{ttZ?pBSSP`G9FLok1uMcM}k1 z2Dn!Vpi8<6l(nmFx}l487D{y%O784gHd~^sD`cU?l2E%oIsgbZk;B5e>jOWYE7=UNB*xo?dhNj?%I*tCW~?VHsQ-*|3( zllP>QWlEeOp3Z)TMw(ws4lJ?we|w}q5mnIW_D_TG`jlJoNtTHATyOue@g21<2>Ztu zlY$(?7+*tL4ITZb`oQ=GWAV4fx8-u|K!PPg$4bXm+*eazovd{u6JmtBc>>nxYKI?x zQT*k$bF(v9*sbJXf2F)K_8h z%gjft@4*z%Hy^vcf0DJ`62?zDYx-D%{{}t%yOSTT)f=C;NT=MoSs%Snn{4|m(o8Ru zu9jwe%mUq_6G`Y-X6M%Geb?xJDd0~1BHMaZCG7+lW zLUe|RY2JeU(F@VP6d?a9hQ%%;!lcB9)?-UXV3q@VZNLz$$C_6G7z}6E&oF;-Fnl61 zrAgF3&|<*;$$9v9SJQK|9UKud^hryR|D12=lMaF0HSu&Y4hfi&f`p_GORvTUG77Va zS(XziI69Wc5(8g+_w&!W;7ViUMz;74QCF#k&m>?`#sZy!2slKrAQl zb0wcB=Q(}6n`uf=X^SaQG8RTuxlSiISao1PT=u0ucKzB%Y?7?RpQhbE0{=di_mj`e ze{zcb-3i@4k#iJVbnO!&$Rr3_@m&i*6a*l#rc$GUNDc12IW zKO#df#fbWUc)p)r3QxtXeJs5UR5s^y1oSdTKryxazn606@FZVi%afn_NkdNk@-O4; z0^J#W^#AX8yqqNZiGlg|c)WyFHvE6h<9$-H{t2`Lje&r$KU>FolXCMpIm5pFGunZD z!qb|4s#K!YJ-@-OE$KWcIMR}2WAp7SSv|A6EvK>jgt z{%^E=-+J~NhI6xzyr})+yz|OttEj~L9^Ma~rHjD}Yt~`aykm#mT2s(|1akgFuVw^i z4!x<<@do0*Fm@-$9j9WbHTFQ|_?*=QJYVxO|Sn^!Em7n2;`(LRyl*v1HNuyr1jS8yy+dBq=Tz?akjIaja^ zI7bb*dyLxFK%krO08f6YKc)fAYQQ_c-M;~+eq;lF5frSRnFizxR$`IMF<6mjd>O3d z9Xv2QF;<@vJ=Mq-57-CoSN(WH?Y-Vpm0UPyK@2A{Lj3uV$B9>xG3Q*u&ni%YJgti zhj|&t%^kZ{!N;7WvL7p-|H5m1ALC=~ah~MZ1do|J=6yhVl)9P16LKMQL8CUXrs?oAAtz#0*xbl0u!*;0*7#3L^khX8}lEsG{5oG7_89t@Ip-A`qt%;_1nRcyb zE1HJB$MA6h7yadjmQxWE=hIjPjyKnbw>b zFsGBZvj6TZ{V6Fa@BB)t)K?h&E#SiZm|8NyD?cha?93U_VW-Y?7R{y#+1bwGnh75y zE2L%ICY$QP>gEyn>#xB^p!!LB4#}ANGEq$6I2p}isgF+p4lTxYwtO8aBz3YI%&{f& z8E~xTEQI`;5W&q2Gtbs|lcvWao#}6mo?4#%n*6xT<{M0T&F6g832v>U`NY-K?7>@c zS!p%flbhI7Jv`yXxtAxv@CX5Y7GAl+BY4}%+atI>Ij3lOdH^?TE-fMBmZ-aVxv>kz zD8EgCE#(&URPB*&!ml83QjI)48hpQj^NieCjjs94*;J_4*)t(VC!P` zh}V}y?k7Hss*605el@Z=?HhoBZt)VJbTa>OomEzjqe0w7|Frohe7&LPw`S;5Se#lK zbG0!uChss2W1w1IXd;JDU(CCLIW)D}4jo72Czc;zg881%Uwki%GEf!vO%u42X|PH5Pb>Z4vwAOOw}@4 z3gS9PF96%hich$=@I!;h@By$bJvZdpgY=t%C;%|l4jd%(pFRPqh84qlT0W&^ePO8A zKVdHv88;+N4Q0S#N*gZy!d-m?=16#BYCZPedkW=;c@j;6`rw*SH!A~Q*+^)N#_VpR~2(?+D4o)rDS>59&u2VM#j zKqlm2;NdL&4V3_ATwokRWte$2DW>$3q7@?RC73s?evZ?R_)6^=Zx(w1suK$d8W3i3 zAHNoyJYSQPd(D3#*pqhtS_&XMg#tWoj{HVGNS_Q5`n`xyXF!Br8a=r@{VXOVDQwc~ zc=2b0{3__dIbO5N_iKB8!SACsV=lMsf`_ra8}%d4HX|D-E2g(}fFk1}!Qx8ZLR zqm&^0)^uFc^xB1#Pk7=NORwxgJ`BLhEGIkE<8IREPG@$BxjAlKtf+yrTV0w109rek)lc>O7JSR&x37HFr+=D{@Ftw+ zO}T$=pAM%fG#;hXGb6;eRLc=eWdhEkn&I-7Y*Mf9t*YdqeTMkbIZA1v5GK_F@T@u* zp|>JJm3|FxF)S^IjHtHSj=WZj2#pd5nQ4uU;+g`UXVvjyb%84N&o-W*FlY<O0x^T9A_86ZKNUKyJv`}fiwg2Wnq|)w_vh9T6Sc>)HBzAt_VBy5pa7I$%p zW=iqOu)5D{2dj6>m@;r{tuVrUG*R^FS`hw3f8L|Ly$j}6;ii(HFK!XdP+kZoUZ|LeCSKDNV;mev+NSkfNZk>#|&r5 z*Lc#j89{(fR=@;G0r7#W?Q$nx6JH~cK)bKO2;EFOGzD^tV`FvznULQDXbj~kXf89a zn~py`QikTl=Hfh_?xSYvdF6-6rekoYv1I>+ddESsSZD`C;xG{eTEq+)T~DCu7T(52 z!_PXcw!OTKMdp;JFEXQ@A|pcP69E~4f{ElL`Y3n8t*P=K{9o!QxB+=gY9TgpGG@~i z5~hm$-!HG-6~Kf0&gIVc4>6!I4H0Ng6=+z*W*Y9-fWZJtkpwE7B|>eT3KRyBj+Onj z23CaBst9mNI8@aQpk{(LZ4W@18Bk4)=&<+5)ADhX&{P7HYLD7aIrbN;`WehChv z3mzrW7W&clYmTQ1Eb1l_f*}f$Bs9@O0VsGBSqVjooXk%#V+Ro?1r3aO!=lbL2%H#} z9uAhpTQM&`gqtJ>0gZkn+VTN5`WyIuKN91#{*lC}yEb0*wQy|o^r~6TlK&z_w`pgY zxH^Ly-Zv_6r*zq{tY~8r%R^-JJvvo2Fy%g)EMg!}^q>DTy>N@j*Rr=aeKArLo&|Q* znmPVFmsloM%(u*&ci>z0QV?aA?@76vl0~u`txdQCIoFkNNA799Hqm4SG`g)S;q!}c zR2dlF8UtVSTltO7oQ5!%10hjvWR@L{MNXW1pn%aPC)AWAqH2(|gPW3oXfPC8ly2Cs z%$>%w!|hcINU|&1k_S}sk^rTkeJr=$871(VPAdnonI*@GRcwIJ{GLalV-5oqG_}|t z!NH6(OSEu?x)V*^^yFERq#N+Ybo;kHtm0>YA@XgAb4>rJjbaEAPOOKJ_i|8}hWqHj z8{$Hfbv9W!^X2O3#2TF|<%$JNmdjC)N zi_5&pz!thauZ~uoW?D693>TSzkHT{lJVha9%)#-Cmd^0#AdFR4*yuG9UE%crs-StZ ztvXj-6~o5=K-CB9O$5 zm)eEnv=P~-$pUF^f(xU9KYN|!b-QC0NY|lO z^bQ7XEnf=Kp2#O)t2gLmeY+wdiFr(?UtpSKnZfL#=8(|X!Q?PDdNSBZ>1$1hxUskD zi>~6|aM7PXfn=D?65a3YVgT0SBEWqT|8W|#|7{vryolV{Z(!JFkjs4nD>l&Bo*IKV zb4Yd~IlTIcyP2`@ARFA`C)u&8b_f?K6^FkdH=NK2)+W@R}Ax# z(aq)Qu9!>UtFs@0``Qq5R}bA3S?%8Mu68DJFa(e5(tI4ZlPd3b+I}oJm|bsLH+=SQ z3$@sDtmQzu`-l)vo+5) z>CeKU6mcl2uNwYhgY-)Es&GpJCzMX>pG|3H!*BYH>C=m}^-K*{H4P&`iz+4Q6e@f$ zxId9AUAasInuIVP85eBW-$*~Ox?^K)74w~h!i43o;RqFegcn8#U0TLUOCKcoUr}@~a?*}7c8+u;K&%R)C4*TzxkVWkhbSP36C6S+ut4$EL3^6YvfI>N?~qr2 z$d1YoskldgZm$mMqxwVA`aIr#oU}ed zqf)n@v_9}?E3J!lFh|bSj_pf(mN0lIaQTn&a%k38@Qh&$$UdDqmj^O zAbo$c8j>hk-V$^3HM!GPN}uJl9%QBTQa##pnjo3y794rQghB z4m5Bd;q@E<+JzKGyJq{l)=>gAFCY`mPMH;PS)rsgNwh(61to1m8*^RHf8yxM*%w zX$M#RQK@)6iSH|Q)qJKXrAb~t1v42duir$p)}xWvRg8q(7r5Z+>uN4W zUe}HO)Y1-fwfrnu^{ObfP+oOrL68H%dr2z`labf)ZZwYRajSaEY3?Pn|^@-y*0h*iu>T)kV`F84$4($l;n6<}z&hY3C7vyl_ zR(^yWez-<9ki%nOK!rH|ooiqmY~MBDRwR$P%_TAVRuS2RIi9VK)oqq@b*CE-M>gP| zp|W$)l&Z6x)&wmwXd8>nq9?sPk~0;tMG~w4+@S=)Ha2v-MX{fg78?!doFzZxHrW)P zp7hRU+Mxz!)7b|1+)p%@s1@dazi9qAPdRxkkk8*B3GCUqwR0~rQuzD}quzHUea}AMiqw}JW2WmgE=jLMZrTzn zQkl|qR0HtJSEt;ElSPPb9^ohsPkJ2BaL2I4ItGQ3k=GwcgdWiBJ+VV1JdoF$Z_G)} zrq%NMV!;rLoZw`}fh_s*^9HIa0Unx}fbcI|LMU@nPG*#mb#6EM6DvQb?xh+ElN>71 zIfpgZzpC`8;dJ%x0}wu}a_M3&jKO-d`wYeV0&tk;(eeLNV^T(h`Wf z{P8B26>lUbe1YejFpS)C^F55?po2c6iC%md7bC2EP^ssAg_TPO^$RN!wwXdkz>Y*K zaWZY>Es!ojbl8uOc)NH{H0>jpCOJZU;qvSyfGiMbv$-WEdS@?xc!%X(fOmZZLY11G zV(JqsVnyMF*;;am@__6YmpE;A@|e8>TsG^Qnz(@cXbZaPSUb7vsw)ewmBF|J)g6hCn^o+C=KPwgkrcBrgdaP_v|%(LS4 z?f0qCdE)iAD9wnzUH%HaL-f7VioP!8OJBm`r&}*FE+Ul%xn1)9!}T@ienC5 ze75<*io)iT`_0f4pJLLNR0)A04<$wvHW_|R250f*u$NF&G&qAw$?B{;ztA-q0I-kd00{D2XK?Y#bDPB=6PT2syM74 zyT*ECu%hr?_sd>r?8W+`tN1%y^yk-;oD+p#0%5XWN8;@hg{us7iYJge8%EBLdgCiH zr-cxOjnJDf3=bra5rRv(K?r_gi-h3bA^k$I?h%50E)s&PA2UMmvpi=1eZTW#0Y5%L z@u`9+2csmh&JsBWqvo=E0A~&cfv^&R(N-avq+Hg<5eU>16o{=gLkG2Zpp^~igHk3$ zUQZHqEqyUgjPRXe@Ei42^NGm_K_KFk)RR8Tupwwrw)wyKFN0AKRXsKFge#j6{zHkm z`jBak7Hu3Z7!5hIRzbsAuc1P;v8Kv2%$Kaya~)DP!o-fe%{gcBMZ7_h@z2>}hW|Hh zxzl!gkdlDoHxAF8w%dFwVMxA2cG>e8dF7vi&onH!{|Di7=`aQ~TXT8FNsjdIOI7{`KcHfeBF24@F0Cfp5q*x08}`A79p z=agukol#~KQAQ`lmeDTR8-}A^R2r#ArICty1JOUM5gYd;O>*Bs53=!ZDVESI9G4Y; z=d^W`*;#zQdcpSl(LXgxn7=rS4`R7@+QMehZ?2BgH`v7LwfhJkR>LGlQ5vQit}@7| zBHv@ulRWw5K0OHr8lzO;;uH8a<$Or{RG20(9jRI&frX>gvpKn-&MBp z?P}*L?VNBod@{{&uKFcUXi#~hlcMY-trd0LcdJRpE&D%TO=E9A0S6SkL!k5hk5F3VO?lqq?mO3vATB&~CQ>{aj7z_MyF-_p`u_3M)u z0(d=He^mHCUa1D%YrOkftB+QtAfk*y1n8CY3=^@#APJVd{>i)z^hm1ULslQv>K#OH zAFGdzrP3Fnw4~k{`HH05%nP~rWgAuupRMTX;7S9%qpt8U>&Z;;#*&XUpO8)jXQll45R#ZMs;U3fhpH^^tu-bJNO` z6ftqH89zv*>$Q`#@6pxt8B{2vL^=x6t+QwdA|G|AF^DFOC{R4R2`$@(vuQu^y*n{+ zI6J3;5*x_)%Y9*v*RI96QWd7k#b*yfH$uN>h)~T0gp+cGtsL?N-T}K*G&A_qxMEDK ze!eJScSJY+!5Ax?4gLhi3hFAIP@|+L$v0NOvRdk#)j-Jr*m|;cTK@y;gmZHH%`p76 z(q9GMB-`i!WQXWTT%%F~5O3k#F=O&1}sZ&9k*ySjroz=ThvK8J98AjV-4v z>g?0RE#kiCTqa+jlPFBfbga|4>R^4%$jwr@eToUMe!AJ~qP~EBHg%z)m~Qr2P1y;i zGfoM5yy&f*s!R!-Y9{0a&N%-Mq|kKz(&0n}ipZGtEoBJU2K zjJzAC)=?xHEy@2jA4?-|lq8nJjmz-hETFJ}Z!lC5hB&R4u$n8fdXLyj)bO^x%O~(@qXLd1VaIGKwjS`oDv z#fzGhzAVNL)Ok_wBBPO*#(c3#iIWdCN{L}y{##0k>qIs4l@e=lqQ#!q6-#KQS`ear zq8lM#rDrB`os;=-PGYq>hb_O=0N8*G(m70q37g6oJO%o}nsiF0hy$?oJZt1~gJm}C zzdkUxVV}rt*f)}t+pvHCcPcwyH}TD1@2{IkSlz@Xll7x@6MY-@2rc_=*b8gy_I_hU z?N)Elqh+eR_%B?H;MirJ_Z1wsg>!;qPOIVnyiGFTD#j(hrKT}0rur0dUr1JGyhWR5zEM>4JKSlV?KlJRr0nO*D^ zs%S-S7yFB*S$2`k?o|(<>1bfEkltT5X4lv)K8vs2LsI-ABqP?{z0pX&4J2e=P~Ar_ zP-AlXoU(QYS z%ei;`%78qOb1&y9PmU9%gSVo_fYLGYG(>W)MD7U?ub!KcC*WrCrQ11IO0u1gEehk% zed&IZ+p+_4lH1o5SG-;r!uLl{LP zUlHgu=04+hj@qSM7(U|-y1@;938*ka`B0%=ow>u(YT360xOMh?9tX0d>>$FjiFs!F zH@IkLFV^n{3dU-`m;DlTnNY4BAX`zKE^j7CDiKI^%4DtS?7XDy=ma_%=)J&BHF68GJXmTm7qfbUuLui9Iqh=+ztk8-#SC+^OnPXM-C%3A0`G z$6YK5S^icb$0SjycceT8l5OO9c=r}C;VPS>IsLv24Qf?TT%vhWsP0{42 z3+sejqNPLP?-kI=~Xomc?ol<&H zJOn(&6|^l(dS7nLnK|DZlIu&}Gml0jS!Q!DZsY|FPK`RlI~=Sc1CX(%esuY5PUcmT zfw{BvJ#G?BbE|4hDQs}h6B))jCjkjm!|PBp!qgGx3Ft)#mhiKch6 zmy^#7i=h$7ooWQ(6=x6j3XAH)QT+7!TmDO9p+%!*Z6XhKyjkT9netPlVV^2<9l%|Y z{XB&m$XR}nc%2+&U&8G)fsfI$_!Gz5QLjeefMH`HT&VTX zA8?aYzCjWL?!SGbnr-k9LCGJ7u7#*QpvRo#yF<5_S5ET&XlBY_+|ASO*j;Ly|9j@MsIUh@ zy%05`NLPX0%uBMQlw~fb$vuZ+7`RLYsSIoi^p zph|8DIlAh?Y7(Bcn*Y-BUT7Yn8agtkeGt#2syKa@UT5R8_Y5&mjzxOYQ9feAsSHlX zl(f9ln;z5BTRZ=G;vqyM8{PY(&csb!1*Xv1Van}!cr?9m+P(?kvlsItE;D4xYyM*o z?oc~~4V6tiAemHA+ab`C-!D65>Whu&%gNfhIjCX~rRD=I?kH%g2ql^<= z-xRglS9lB4NLfYN_tZYYeb$y$%Ro_I!o|AeNbD#HHtK(Mt%|xw_+>EA58bZue8YM~ zjs1~_t`@!3pV!jC?|%3n#H0NO@cY}bkH+uM{bE1-9z;SOeqV?v`8V+UkMDmpe*cX0 z{~msC>i9nZzoY*gej^M2pMc+=!bg=w%TI{kd->p_@cU~pnx7EAzxaT~?}gYZ?StQ+ z`F$RKPrvPx;dj42nFwwKquXx6`zGAIDX934TzFp=Z9~(It8!>x9%1+AM8&%&+&0Z6 z>xlge*X5!68o!!HAv-MUTK{s1fLep#4pZJmjrQ0Rhs@U%_+9Vp$h||aVb*;6;&;60 z66r1IYLGUAt>!19-dSaFS8?nK{1U4Q3w$(;D8p)MSA!v6F0!FFjx(NAs9bO}RaO2M z*od;(Z9^bSd_zI{oMp5`Rbc&WX;Sj#pv5NF1j4&P#~?7jXWI?l5{l&STD9L;T(k0{ zz>nsK4cF_x{+9YJPLcYRJL&pl;B)^+Z;Pa%@sD$kZ;EQ;G%L)K_~0#K z!K3K%I)JmTYq`QShdMaLUs<~q-e{Yp*~5RwUS-^z)rTnyb#P4oIY}cMy}i5)+4JPxOaMBXioBOTmZHksEzP$g zF-iDAh9J4C!1~ax!-sbB(-(4Hel2j{p4TJLp*+7XQ@$$1O1ksk{6}}~5Ib2O>iMzO zH!GZ2M?O8RR^9>o+`Yzgf{}TU>2z|r8V;^J#sq;wD)D1Kg%>4343c$%kmr~$ZsuNB zJn$SI2QyjmL8WJWo$o}z61!IEEUkcNkyro}D+I;3rmsO~DG3LIRz{CE68{aCpc~xg zKL&tesQHwOQhy|MCdQBal8Q!9(P6q80&jE%o4o}j5z(z-23Hu)7JY&mjazNBb(SQq ze7ArJ-`wL(EssUsOkbqQS*b0ngey2FTqq@C+isx5 z$W{|OJ8xv^80FAE)0ON|p#5_3J&@_?ReKWd+al(^P?v)?N%#G93{4FzzyCcg6`H!8 zX5(p%|GAx-7%%&0{Z(z9TCOewY_U*Y`J+I-O4GDc$hGFKY3&mW?*6g%ymwj8v0G58 zNGK?~URQMAUH(aTAuj&_ec@ybuvjhL zy|eMKLAkdB0ir|(e@!2_-K*a{diMu5Y=^tv{~_#~!5oO0yJj9i2wtdtZF!<;@7;GJ zC=oC|vHInrWD#NLapMpRz3pF_7DXu1VT5?()n+2X^CiQX2hj_cBhl|oxVr-!2e01( zA{bJ{GKpRn=LKhPtnEN8&{H1B(MSuC&GV0zjOTVM9^2~(&d05>-GSzrXoEk`t1!@{!&8GQ5!8sSWdAj=5WgZWxytT+nlq6|92# zuM0ni^RaN zIWz@k!i&9GBEJNw$iwW6gsc?Ud^^}U@4G6C9BkV~GjY}=Q?HRRRrR`Q2Li3bQkhi9 z%3okch>ib~g+TjPT;CNwT!I!=g;SA@eeH-kjj^&lV9UU88L>?09=IRe!w zn}Bd)wnkvU3{el!+QyU#Cgw_)HzqLLvl?Ud60QtJPOw`EHCc} z6Qu?^@1Q-NfrPVi9o3kVh00e(KJu(V>$AyO_(NLCUAMDP6jiM&Kd7NAERxRh7>9lt zJSWU5Vyo;&Z{o#ifPc&cZ>a|7v`i_*m6aZxyfRxtzmr%uir`lRqcH=BzXH9r(caKG zU46Gs`BD3ngZDTq4WC2P+Qvdu)U;c_SXhu9#e+0b7awO}Wm+S6W@X6}puI9LQ05a& znrU~b$tm_S+d!(pA7}{H8ftqovX%ohBFOj?h#AzG(DV=k&b<~PFZ@>Qz^uF}NTZ4U z#=;Itau=@U7ft|hXcAEGAtltyb&#&m9Bzl)dTAk~D~oCxyUw0bb53n}1+?IV8M>Q# zbWf*57lpx8_(pU9iKd+-5lQ7dLXng1ZV(+gusfYn5=a<+4@iY?6AaR~^V{jP9YFog z;t;CB?fn1kU60FCFL+Cv!;ci|J3G)|!QB+d zGh+I_-KD7s0da{I@{(cgSymb#BrJ^oYlo-<6ePt`1VL%)fAzr|mT-)4zcsk4p+bY^ z*WakJsK+10omQ(6=K6+T9lWV%XS90#18=e!EA8WvJbEpHK14ZRodrPFIBi{wq_cRn z##3;n^A*Fh|IQ=aT!+zynuAIE=({nPk#>uvLL^e_Q?NJ@0DSxiXX!>&W?XimT!pWI zc*ZME^~Q|y-+q;jIV;0emegftALQQ;>q;;rpf_(U!Oyl}B?$-jva>QiA{O$c9v|81 zKlB>Xy?F)em-h;t;c@=~rHs7Q41XW5Xus;Kc!YDMh>-&yYP^ImIhf1{q(3X5U7{9H zMf-iMlF(ek@?^?8;WkUiDn=yP(glxm(FkW*40viO+n4XK3sS$nFK$odBw-T8AST>* zO(3m`#DS=NU=CA2z-j#+qsZ#zv|hnYyR=iQ^y4qS!;B`3gTJ}Q4tq(I_5FVHFs2Hk zUgqD&13==w+*x{q(Ba_M$&0AfV6q*R@+u~{&&6vuvZ8)bROK^X`919Q7kVR$q6A=# zdf|IoUWsxFvE_C2XHnyyrfFA;A4SR;1g)7e$m|&*cHU{?<~41MMaKNW_(XM5ozcu$ zy-BU{;Xk?IW!QWz;{R=lOg-dab+ebu#1xvSlPBibrIu)vGx!|Os1jwqktWlA8#2j1 zU1LJqzyFGatiw`X2@~GJljb*zDwbDjF4O8i(9%MBaA?#kA4qc(D`>rXA_YGSf3d!#bL;v2N|wK~~}0owoCBtIJHQ;r!I> zpXZu=r9i$ys6(^6vw6+_A89b9tHHVi4Yn!Ebg@KtzXq2%ZB0T>gsDk7qi4j4H~iPu z?Cv$wUIKaL4R71%;-GLv9+wBL_5V8VU1`{|m$1<9i_bY}`~BKp(AbDN75^ zeY7Mman&dmw)xe-0gUA6FC2@&rJXAi&JyUZseB&XR23CvhDaB+4p3V*Xkyh}%@n?hfOeaLlAQd*gMiJHAaYajG`OqqWupU~mUST12a?mN1z=ZsWlTBzq! zhQCnc+f?Mm^q2kPn7Hox=}S!km?xhCXgq`#o3SDU4!G`EHLs zO%x3-^LH?91fJ5W06G+y15i=(uM9jSKb4hOh>U}hHCjprQ1UnU3>8La;n)p3l932m>X55ttCz>m$`1(bCDReTdhScT*P^7?{Y?H9R?1?jM| z^8L#@2u=G6a3$X(+>`GW^6A`FBfFdP&NQ-*g|9c{_vBzChN;GZW-|DP|6EJrke~2| z!dIEXi-{?Ryf`)^43Z(A^^ho9IhajLHTvZWFd9yLY;4 zkbsD4m2_g?vpuVYjr>lIe> zM(xer0tnO>;uQb&4Z>LNiV5}AJ=~|Ay%9{3XEB0>W3LxlD@HONdLoML8XItz&`xrf zrw@ihsfX~7$Rt+LI3bSGRx52(X40ybcgEls&4z~i#@Ch7^Rw80B6r?uD9 zS{tI9wl-fKjjWA1sqOnz*_?@a!xOYq{Qd<3)0YJdY?pUmxZFSNMTn!@8+F>x8xZn~ zc^U?};4yYUsOY?^aycegz31rKHAA-$=6oI8dh5^BC{_EqxhZTuD5#eHz9sK;aQ>iI zJ{5aQ3bPB=pzi@lli(b~JH+M98Pp7VsaNU}x-~1ohz-piEwtW0|BKDf+x*P5{`@@; zn+BY|JuBl)K%Q;Z^kKNBp^d!rh0o0`xNGknXB6DM_YY?jv~Prw@JG%jvftQ?&JxF0CH!a$8;oD&mhV-lX2B_VBp^&7S1hx<253Nzb*?C zHf|e@Jz*V6_`jH;DcU^8^xGf({EptttdQ9#^zSetr}=)J{~6x6aRQXb8?_uY zcEt_D+SS%USJa)Zwza{X^d85661lw7@C#ewmnp^i1KXF;GBqcgw)yRJiK(aglGyzg z3Q`$&`8S(X%SoElYe_A#FTt%Y7J3t1ben&nIOIP0+L~4RXY7}Fo5~!sU*erg{5*-? zwZ;uj&W(r;!*uYjWsUKtYQ%AWK6=$aFmJ7r6zJbdip;I_pii{KOAN5GIVxCnL`&y2 zTovC~W`ZU&^S2Id6;m5^I5=)#0g|#Od0w{Ut})~X?J2CasuDI*D_HF#F)1gELGuix zZF{6I!I+l$BRM6-bm-_eLyTpS;nxMidnO*jo==TIq{IS|GVr`3dqT<=Sk=bga<%9B z?hA8^N>J?$Oc~W)B)439OvAIzpwK3O)_;r8Zs(?HYiSw_$u>}0-XTdoeNg#tUxl^9?>k~mA} zPyqBLuY01%)`#;w>R!yXu5xsJkmsILr7wcYAmP6ti06it5$onXF8p2*?2YH=Xh}}; z*V59mhGyPmn&~Wg+I)L&|0pLiHAlrW=_-Jg8*GfHRVB6&=zp1JF?T0}9jo4x18*PL zsL*AbSIlsbf^U#a3+X zu$jA~`w%i!MOzR>)E3%6MK#Eke4=KV#uyX}<_X9|`?Zzd*A(DqKw?`{O=|=fY9<%I zS6AIY-3%>O_<&^r4^GRWkbbQx&cYeU5wdo-^YZH4XshW1bsm+SIYwIunU&)$+9kZh zCle!Y-Q<;M38za*#m;qMxobNBf#%i0_S~t{DpyuulD=g0^{SRemL2jun9g-ja2?`( zt+1fyBpQaG^{#Mu@n88BlHbfXXhqhCkCrCQShubZA26K#IgBL^+>john+ZB~f-@2P z83Tpza&@x#cXMvhM?o1_mh&maSR>i>;Uhx1Vw&%Y*FMtLJMXK3{ENBAya}?>)~BhU zUhJ^zGb4{MrY6bI>SU-R>fFI0+ng`7^@x(84`Pvb7L`}*S{Buc+Mc!-Xe5I}4|3$SFJ@!Fj;O~DR+8$(Y4PNS7 zDT1!nOJt<*Q+dngd>IyL8*QEc>Q=jGHd$opBl|c4)7azmcyO?eGES@Ut_==|K|!Bp z)>YT6sq@ZJ9N*eUdJd~!Fy@$0dKdyZ3XM=CK6u`j7K}ME)cmqtH*i_EK7<4{YEk$| zlU3?}t)@+@84A6?sOy;iujeCPu$;R%S{fC=C*EjOSghC61TXq_+j6Uix|yp0A-MWK z3m!W3urzpB#DnF;X9hr9-j_0m6m!Nk7@yqwcW-Wrt>r1G3So$PWyYx>HnxNm(%)nR=ZqPG{@F9|7tc|OGD{%b-|O!f2h&i;$mcV za2vjGdHUN*E4F)vx*g!O6$%cKJu!Dr)S18*bh{kVf~+|^dk_s;GuYz}nvG#C*D z2`qgwOL&>#U7eMiZ6F{H$w#5AHsC-*lSnKg)=t$#h!J=dH05my%}~m@jE4vgL|l zFk4}iqk{u(JT-KbDO4Ak!S1swe*WN=;(vd(rXVC2*%G|`yPnw5+mM;UX*{pFaROzP zz)c7cW>bw+&50L>?j?qtkJ%#EXc56Z}`jl zvf48;D)lgBJ-jcgsF|`(@5_2jUjvR()*dY^VE7Sc4^3GkeOY%Ks;5#vtE?S;S&M^G zKh>A@!M?1+l=T{$)oHyPP_=X7%`{>gRMmFv=Vb4rmwm)?c31KAZKz-PQ)mg%doEh? zButKyFge0Vsp19MtY_~n*@Wd3NHZ}+zBB{yQG)AkcStlijE{MTn}nNp}V zl2*|3rC8?Q;6BEV8!!7`S%?@`0=IYm|HIhXz(-YF{Xa`KvSM(9M2!|P+SLZ38Wc4V z&}`VqE-p4!&{$DpgBC4Xs)sH zwAFgofS{tFqWr(VnY)`!#OMF;(d@l*=jF_qGv}N+bLPxRmC+=c7Hjb8pf0X{D6WXR z7nj5vxD(JFgR+&`H&tX3-|YrP76lbX{xzb1VM)>c$2e`lRE_3vzYSkVp5iF(|MC`j zQ|hE+7fVr ztvq`knZipdA%XNZ%?Z#~8^d>kLzUX#f&taiwppH;jh3yQU%~rhf-b|He?sS>B(a!@gZR=uNmsN(NMh zgjMWa)|DZUJ+o39PWeEeo=88!smnBdTE_q6WsRHS+12>-slwP4_r2mhzIiXT$8-*g z-9F>~iqlA=JG&fx)BAXZ+7W#@1(#Ea`&Bl#Amm}GY_20~{^^{0HjISsdiY%!>FmM~mzs78(i8kAV&Z4d<8Ma@r4b`EfS zB!=xB2vu9-B)4(){^;1^G2unOrwRkPoS-;(FQa8;U3qg`&olHlH8)@#de5RC+I%ax zXFJBzQku)DzJQUAQ(Z57!opn8`~$hVg}|L}fn(wI0lt+~ANAI>w4r?>@IP%7TA z1s%t18s#5dr3CjV=XhsQ&?z{Nx3OOy!{2$oN^g^~icyNUGZ+WGpM4MAZar!4(L>2V zi*#I^qM-{d)f`35FL>uARYyn_oTkz74Bgc`NB@gtj^dALKMRHhu+o)^2ja!=jz41p zUHa%B>VshfESptrJy^PZKN?kq$|-mI`MqVwe^_m%d>7@?Pe2qtf3yBJ@^`DrwQpZD z%v>Jvs<7R#5i6{q^<5yPz(GJb3wB}oMy{KlkWz$xCpQtSx1+bCxU=M8K(WA%D%Beg z<4V03OFuX$MGtCPw$A$-Z+hy823`$6#@`J@N*DpdKPBeuX$eLGu@Rmbk$}TpNvn6w^yx+8Q@dFIpwAm-kDE{F4)SJ7ilTVyx^#cFX)j^g#e4=%622O zGTbVeq1ctWS|YL`17SR#D%8dw4U##*N*UHP$sL0%V~-hkFm_erTqOmoY&}w582k?K ze+T)$hw0a9YJOK?>}(YdjJreQ?vbjw)E&ccjk%NV$4=0BB_&`<}K%xQ--in=}7uaIfXN3y1srzJ%(u4%n>r4DGb`T|A&APED_@c>C9j+@p z34O|Zyt>odyG6$0vQ6YLMTZndyd9+RUWn5h4lv;>27hU)2|Y3RzSH?d_32D+&CDM= zZhde_(WAc%nBb~2?y!C?B;d@2QsxX;b-HPzE(j1slSr%s)H-xR>3?;XkZ|?i_#ex} z)&HPreb~%%r+1M7>WYG)J`5dc#a|O@ASQ$e{FYsk*fH2xy2EY9nQzb~#6BZOuIqj- z7QCZ7COh3(LSL|Rb|IskS`o?9FEkJBHfoO(J`P6?CY>%~%gTVf4eddyOvL-i-$mxH zweSDRC3)Umol;81-*-OL47D+3UK-ue{%vVmmojM>?V!}`qeO2mrVg4(rcjn(BrG+1 z@}tg9Eu|vS)XWItbu6)0+Vgtk$i|g+qt#Ms4cmFFz|aIfYA-XNyb}LIDdx(U^RIT7 z_RwhpN_L4nKYk$aIB&K8mrdVnCWhFSdlo8+r`ag44D(QA9Ckb{9lZztdmj}Hji(lw zHrr46pG#1!_EGf%f79m9KJWCu3Zz95wH!|^>z{3&pKYMBiQwTP;G^h|F!GjlA@2ep z89S4;N}Ki?&1dhI)j}a=D-FSd^%{|!am(3{^oK3ur?_C}CSg@P3RmYxdFH=7Z|e(G z%zCyIRJ1rP9Un;fP(me@KP z2Xz-L<% zBzAjGlZZa3^6^!(uD$Js>#n(BI!m1ELAu(l%iGu**+Ipo=2?i5**9I=nCHE)6^+6# zhl@MrwClDr+`u#g77&@0Oxa>=@tbu+oRC)zVT#(K7J z8>ZiM?e!c-Ys^bU6(GO>2D_;2ng^rBxl#-vsTN|WzoMDAt8-)iibI%1WTFN@$D$3| z^qzPZ0g(lk!?+(bkCR7#<0~48SMdMAN^f2hPVhDP4&P4i)EbuQA;E3Fs{_VxK{ID# zcHw`|T#!ec0t1ENC7Z39PkdoEV9mh}t^bI)Gw{4od20!eYnhW*-VK50j;43vLPiId zQD-AKj!|Qt!iHSUwyu7!AxPrYCXk2vgqR4o-Ha?H^&0f+1|Hd1p^*q*7#r^K0JLjq;v|I=BN}j<&s!I+CfM z${lqw^TBuyJ1|AS+xqeCF;Xs$lXIyXyl-UihtX6m zqV2Q}c`n5(k&Rb$AYnE&ZG&!xqE2@jf2Lo)8@@yrb9E4G@+V8+VAPP)tlLTBA6i+!kFMTJ{eD%t^0(s_E zJs*i@o@%&5+QSvf&Qh}vSDdA^OfSITbW#-x-|VA zKKOLm>tB=gx5A;+I$ULFw_yL`k1wS%g?8OQmryc{55s zG6FZ=9@9tx#Ndc7bH ztLEJ(q+>txOKOK*)zPR5q%J#1WPSwbW47Clrt7iAW_TM*Y})UYmT%MS^+TfOSs$qk{gSS#_StlbX+R$w@nVzbDHeZxQ=Iu07$p02D3|2hbolcm-iAgs& z&^Wa~$Oq38ZkGADVX;?DR%MrGONBSXP?1GuP7^tK*c_W+GWm6Y1mVI~G%m!sNJDSf z=e_s7{hm(=m#F(=YK$46^%+oayH}^=T}K&A8Iz8`oP;{heZ$)PGlOH+@3ZZep!#OU z*5v{mchpdw_nW6?fkik$8RHns5u(=_Bu@ypCr=6B+8N6ajQ(J?o$9;2H{Qdj2+eSkZRtyluB54XjWBrb?vyTSEc;8=Ig!)T%s??m{x9XMiG$^ZDw` z%pxD>ji!^vfakLUf08k7jAnM+^QUy~kGsL+GQ%o1&8mLLfb^MJG~KJ3kIK}%SflAv zEvw;}TVF0kh(jEfl1J}Ky0a=0?)l!I*J%25v7yQ`HR?PU!|!!@A~kH|+!I+eo2BJ4 zn?z4vv0kqRkHxHTWs3E_o>RQ?it>5*FATnm0;Z+a+Dl%0 z_&4gtQb9l;gXJN)6MzA$6rD@Z_$}}O722$N;;1k z=a@L|SSx7*G1I}1ro$|CZ#gg2PkYBvu6@R*m*d|WI|f>`lLOOXkm*oe0li{J1(ORY zf!PH8o>-n`T^GBB70@Z`ImlPsL)FKeQ5@buOesVZkfD(My$;dNC3EQhGIoLWJ@g-Cr_Nn4nCYYt>+0-mOF0d(UzTA1oZ zj82^n(V3b9+47WQjE2AmJA;+AF^Pa*6g@ z%?)?_x{)#+h+|~rXd#@VxWo)yj13gzL#o3xzzT>Ls}lw|1=+s%Xhcno^AwIpOcqZ0z$KVI`tl1Z zF#N0GqLTK-uoW5S%3>%crI@%%0k{gL$#qcAAl|)Ic#&?dsr*#zm4ykJn$NFsxJ&nG zw(~~pkEW`yYH@{g!=)vZtfPBdB>Ne;Qe0$km+TBI44$doY&@@swVJsY%CgOxNWatr}jekm~#=hd(HdZ1^Z!;uX)FO2Xw+TP<_Af zEw*5uW~F7B`W<4u_YJa4z3mp#p^$=`2S~M?1|Lt~WU|^h<5rtv9XAu$!J<4fnV^S1 zj)2sEPHmb~!Zir~#_HbbVL2zov=}pUbo_i3xt}7i5mvRuOq*bdxaK+p#1#c6VKZiJ zx5X>XsiyLV@_B1TbDDA)EOW0kLS5de>1SD#+MPvze-Q)!4xRt@I3=vu9UKO4jOI)36HZ#JD0@pmfP3-Lk$cz2&DIE#UmbKH{bMP9X*%(jFzaQI8;_;hqzwVY>ues@l z#HyJyue;@%S=ZhWUwgy!TN}Q0%XOG%7b{cTY5)CE+6S)+tzB~J6?xZp-?gSFFYo3X zH{R9GZyr}6+;Yu#ZotM>eCu@^tB%3ndEuw@fsSwR0z=JmvP~C`B~zBL%+iYQ-u=H3 z!rpB^<3YrLxxA6_e&NrO$J~cC3VL$KFaOf0yvG%+OBq*L8}+ceRc@cxdeleRHEF_W z(|OluciVg!rTFI+a3Vk9{zb`gx7@ppSNXb$W=qI7hkQVl*Zu^97j@cN)mOLROEgGj zn@*;Nbpw4x1dyv3t#WsA3AT=t;3%WF zFV%dH%4Zj&l2ItOkJncDbtUuOAW~~d!o5vVm=bPtY20~>dvd++p7RNu3ntK1E0uKT zWo#}lSg#SzS-51-nRGrCGERI9Me9Fi{?fnpZc${ug&$gMtTo+^BjQU}zx^{7bGw?^ zW9XV_Fe&}rd8vI1Wf*~}kM23RTA$mMQLELTkWFK9=}&aPYh!viB&!L?SryuT)7y^P zsr180&)M&@!TdP-|ANkZwQr|-2vs7|yWub&v)2z`1T=kAPyP{V=T$Rl@)MnFm%FP&1cJ_>JH$$pkDUO` zaYdXgxl3ZWg^b>8rk(*+E2Mi*-3K5w5Y^O*$M>l7?)c3F)ob6&vs)75mNAYbH+&4E z`^cOBC*+v{f8s@{ai5Of+{4u?1I5iYiDip$o$4StIK@@j)qFBX;-1W_{G0QXGpOnL z?&_eJi2bVUGA0X+HdEg4*zAhx2X5!O>YS=OcqgD+}V~hU)o>ysccuirM0@Kam2 zn3AvhhaZ<3w~=){4`qsT*Udv@MQJc5f;cmd;^wRO13vK5JHZ6^)iIh&;Yw(v!us|C z8f2F3R>%9yva`v^5Hjm4;wd6I8P`Ma#Pc}>w4X3!IQ50wUNqX&_&ZNVaZ;UzHMW=T zRF#QtE(^rKdo}}O9SVOr2}M`;{jps53Po0*OW*A3q)tV)dz=3N*LadXEY0~R??OtP zq7rr45=$xJ{fPX08l+DbW%TiyOf00Gc(`4IGwWN{F-;k!}Logp9_!{Bevn10v{4tRQz5Y<~EbZKLK!v zqJ8F_mzeSUo&8WTy5sS|Z})!kp4SKML%f3ht^LUNnD-ENm2IFAXA^IQXeQMfDTnU) z_PFHV>cBi0?uR#;y2r9_sSGP~GwgQY+8@G^so{9Du{pS<6kH#l!R6ZH0mIt|T`>`7 z@F|{JX4+^!n-7#4X8JOIvj0i7w^!Rw0ewoXF)ezdj=*->Ff$VIt&wtdpbJemqX5nU z=^zbaUZ+!r3K5TxEuJZMy}4p5=)6%Wke|-mTu!g_7>O@R$48nwVUQf zw#D5$m+Bi%FZpq|4E>42WKfN_#tVuU4BK+WV;G zz~GQzAq%Bp2m+dCWxOFkgTt^qN5YHa8YYmZ@od*PdaFlU%iFcg$LyC&G(0Qqmo{xH z07e37PQ2xZQ~VX^0Fy zksmKvk1%4#3d^h;gGZ)+LSxicVrr|?R#=3su##|_XIR+T%TCBhjjrE75r&`|RWH-i z`^LXNgzj-a>ysYxzV(*UVW-~Idg#*Ry~uy6@S^5v@Ojj{T6AbR#g!VV-+>?miC9mL z6ajO(j5@s=kZfiKGS9mLwH^IBeTocl@RMr+F#VXZ{*8ZS7`F9iGemzM)uzt?J-rOq z9XRr^bw<)!{RG)La$=AWFgfR?IbR-~noRwMP`7!0m<+e3&^<5i-cw$n%~B?%7hbH` zTpVvnrhcIjgn)LE0C5I4O1{P-d(0(ZvB(aM$c{F`7@VmLHsG2j5*e;yEsQ5BORS=J zfM^p_BKt35zfdJu^St|&{NmS$2x=D=-NAB|XEnRs4VDK6m|n0y8c?`}kx`>bvHwY2 zHMe!ChzaEYx0;R+F6BkU>^L(TAR5<)O@EiSVgd~z$|Cst5W!A}z?{DKAc38jJi%CI z7?Kv4~NKkhsqPyJ;WNI~nAr+kH%|3Bhxf2kl%b9*m?gNCtI ze3$Wj?g72N>79MpM>hCXn=lIhrepCG{son*%Ecxr~2&E3_l;M$O?xTe~!4AKZUjY8GH$Uj{GWr!k6-=XbOLZT*jZHF6YnC zEBI4f2g1(mi?GVhd2jW{m&}^|@nx}8lI_(no-{VyZNeeL=HpOy^6s`W(%2i|N$&Wz zKH)WF(#G&~xOozWS<{hE7(T*0#ds<-Ph#(b&6BWxqCg587+oUg5;Bf-I5jNh|#>u);7GR@yW&9W1v8t;Duc@eC&ra3B zqQz21`ZSXJ&M)dC+MTTrtqbvaE?WTiFe_Od;39Wa-$ck8=|2^DC;3k@zGRvmOqylXet#4^F7967?Y%+* z=DQ)U$3B!?nf@nF_y;1*#lOuUTO7vRb95oGL)`bJ?PZLx)!2tzrz*xpE^=7F8ubhF z3Y3GDC8QrMD0WRZ!Hu}!qNG{gexr9?q~$IbW*8l8?Ws(XjEs)w*Oho{RG@M%`dHI* zCae4!6DuBaN_$iNd`I@CWb=i*{SCCDnNBZkeg7dP(eSG6vv5PZCEgb0)BHB8 zt(sDAt+F{IlTvD*ydRUv#EYsaYgXVlCZ5xi$iJ$rw{~IFyCqY*0YM6` z$%aQVn>15ZiA8f~Z#nOLlKlpqn(~Yc`~Tw?)aGZJW7vC9yX))yQL#OflF1bEHj%_G ze#mU<(ElRa_lA$VbrMe@$NB61f?SHYT9cuqsPii4?@gyldi#)}Chr#V`(1pg_p^5; z$=NQJ=5(=@Mj%EVj5LA0umTw>R)DX0h4QZDD$ElEDp$>O3VQ@QzHt=6K~( zT8I{*AQi^YtwM8Vz}Q0QD}{5ZqUH5HW(B`kiSCIQlu={75^{Fe zY&A7G`8~%8A8-ws*tumak$S{~<-C2@d@kNvs@4Mdy!;oZrO7C>*63 z+qAW51Cg}OOt=@s8}>LgTZMgZcb%wrV9#%4@_TEg6wT|lam?aMofH)(-MnsXqghYT zj=_=lI#0Ryw*Ak>2vz*MlDN~<5qIWp;x2D~pCA3K*DN>}?5tt}VNvWb#|*PQ7t~kL zRdc1`o8Ew*n_kl$omcA3POfu>I$1h&B;53m>%;ZPG(ih&jf|v$LE{EBZf?b){f$Ph zNuj6i)J^lp6@9tsT(@Sc4()JV_Bdh;er)C+jjsJNRd^$*JN%f)IWX?ajUIVpBe)I^ zR8f0P9%*5goMiU`JIpIfiiqgvT*3guKvCsEU?R!Cvw^wO;l}UNEY4IJk*f(1gmJswdeKzlgL+1^7D?Xd|M~BW^=*{|U-kT1c zx5$fqHgA-?HSmI`r*j?^^bj2vXkJ= zw4})nS!0#fkk)RIx*aDX?PX4BA$AwKCgO>ZWm_!bXVW)A!Z@Eg`QE5(`6k&bWUNsv z7fe4k5+AF14RuC7q2w487;!fZ9kzk+#{VJo4q^#;4wv?hnksq6Rz!Z&R+HE4utYDP zoLXhXli7ir?EKy6bR{)zS@*x2*qyh?=I+`{jGGtLVbECKO>A62r{Ks9*J1j(We#Zb-{m=sOhdVRy^_;r2KX_Xq z9wWzd!21c1Vc%oQ7-I|D+}lWb(JdSp%`ZF#aR1TvLDOTlCLdTjdUvL#9tHXhFIN0& z+U|#+5&Z$Ulw$qxL$DK-b#-Di_@a-Z9iV7k|2B`w6z=Kt<$d&WBC~SQ={piV>@J&# zn~Bu-HN*_a)Jv1bj!?oh2+AB1YIi`lqwt=aAwQ;lFy@}cRFK%r!zFX^5BQZ={*CGh zBRoQaJ(L+?Mw?4;ycA{o_Tv4dBD%d-`wycQ4n@ssw<@(lL~W^?zTxqCQ0#m zcYEJ4Nf#DoIEz>lI4Fd(l(H-~@k+6|uA>W3TSPH7KH%Bxl@kb~Wc0zmFw@xE=sBGj z7{w7E>4Iq(RV#~;!j^XNZ(1MV*id03=3&B^;ICt**1@JOTUwa!=}=hW2v)TBsTpw^ z9N=dhMvS^^jnW3_w04+jji!Fj++uUsOgWv}^@@IIMr4?*nx&|Su%z*JMA*PcfBuM+ zQBj`;1P~3>lHT)E+hN#aNBVkd%hK~?8$Fgm)7{^!PFr@?Db$HXTp3Gab9`PSSn9^1 z-8gn+hL26VQ2Tw5BU{l^kA70sN_dLP88vw)f{uNYoex2t zJZ_5ETc1qb-a?G7Kr==jHbv|_w57-||CJ~Mn1R6WKeHnkt=t(-{nCsUy)=el;-g@E zuQ8mc1c-3!S%9F+ zU^x~Hp6~~1e;D+H+ouGp7@^-W2cu?k3PiyqFh!e!ZPE1J@%sEaZln&uUSbHOccOYj z^r2;a9d{6ZKJDy;=A`c)x=RUlX*6DN>e2wyrN*;AAC%XqthYPrinxdkX2>w~q(8st z{n?`Fi!sP()Y2Xg8U5dn2a3AxTdriul@>f(6e)i-Df-gKko~A#x-YuOofNEbzY>CM z4fYM)vRytugsS1P!GYVIw))D{HcQK>d%0LjEfr-C67g=foFGJE1VX6wlOfCi57)}Z z`E@LzFkix~Lx@Q-kMj#x=~p>P6JY>aFcL$N5`ibfE7mc;tHLW{kuzGiHy*)}rZX_H z=%|iRG|qyXp_Ft=fh9g~eJsF<8QjB~i+x)CYx|!pBN<4; z2E@iY{I*d|Y}f8EPGOZte=+;3%m5JHxLl6sW0f6MZ&RBo|?VKXd0`P46Y74+! z%RYz3zsv{fi$UkPVKmH=+8yd_8KJF#So4{w>NA~u{CBYsoT^<5^cQnCOGCNTIq%|& zv_K2KESVV}J1r7wdRbL)^7?~#gNZ%|gMf0N7Ru_Xf^qM1d%%;zKF6~ZaK5PUSk7E+ z3b+23NmEuG+&We_8gB}>$(1mCcbLBn(YXeTlijbBfH`BW(0FA~%D8<7b5S#H%))U4 z8o#7dAUPy5x&wAH3?f-k>s|E&ZI`YvB-{d?<+&NtpE?oZI5Qn@W7j8q_Z9G#98mBi zN{y4&PGl5>d4{q+OG3w55)vqZ{}q&H@96`Ifno}*c%y*?MC7G+vJ(ajwLUrw3S%REZXee?`yq6-Al|4+BfH(6w8Oeed^HR%OWE@gl5niZmk9fld!uCO3a@f!| z;yM(FY3g;{1XG~JWUAO7z+y}VShRJ(0Bp^2%+_Iu@gTGcaC5$u%hd&CRnld`;mJMI z!USL9r1+5F$>D`h& ztASiL#ogk+S)Qmk?*TTe*IlM~8G=*9uaD0_Gks`A4Rl1IB6IlM0YFXK3?ab3>HYFyJ3jo_Rw z=ri)uSS2xL$W*zl*LcY_!5LE}^cO@rou@$R+y={CLAQp8yp5XZ#-X|i#D%UdbkA{% zppz(q&HL~zZS0Jr%td&9vA2_SFDgyCxEVY7NKz!YGsL}&q8AmJXLMM+_L8i5z2C_h zQ0+vy;KDTf-4c3SHQ9NGtIhCwD~;t>GmSp-T6K(B?)BJ6rN0{o4_axI(UU!WkWqn= zFt67>_Pk8VatMmU?P}Z#g2lvBY&CXQo86J_YV88%SrfM`IM~lxcHpgB(-C)SR(WF` ziJGZU$=p@elr!S)tf8#$hax^0GntXw?$lND&pSWds*S>pcfQBpK^UY8WDSary|8#r z4cFl|S6F}M>z5{-e<$*c^N+s&~Lkl7CW#ON0qxFb|4@`K)C2FWNc&&Axy4<=ob-BC+>mVvOS zb0J3QK6W|3C+bIUFU)P&Is1>j@naV3+z<5f-8ObmI98nb8!gqsrb=w5LQJ|`>l+pl zV%Hqu)t0Y!%_5CG$%akOpj1_g$#>GAd_FkqRzYCp4SNXM2BeZDZwrtbxh={u96x{QisIn0NrL!i757xYG1!nqt>5 z(>X0E%dDh17Pn>QTfqG)(nX<3^I;atNkj3-;~+Wr)TrO?VS3j+K0hI%BVIa`R3(l_ zZCiNIKOVQ*r#vxf>9r(n^OJaN?R{LB$tWe)o)1zAk4rOOr~+mXjBvC>Kvvoin+%M= zi-uQhtXvUUWFNb0SXdoi)5@x?K(nC1wq-EvFPWAFcaYazWV|m?hrg}qM}z}SIL@Z1 z1(pG-dZZ0}J<>wu9?9h($t}*N5nEckK?F1qd~?U8VnYTwhgm^ z0EE>J%eh%I;lS~w9wsaQ-Si^BhFcBZfm7A7$j#_X0$sStD8<&QjGFVM97!|@No2IV z5uer00YT;atH^es=RFn+EVE5!6y?&G^K3>_zlw<^B(`dYLy%bDvbv>`gz*e;7A&qc zvI0`qyqiVCp}|tg+_gh2u*r|!EwC2(VEGFO!1`-Of8V%JL&a3QqBW{ccJhQ<58?^qzY&y)U!>mUJ()6te5GAoUe%rSZib`%trOywv# zrv)p#XTGN`pwkN+0!T5BpA-U7r6NWv(WI_bKs*XaQ3{rO|K;bu!sh>}A-8^Y&Lxkj z$CNjms6Mxr!@MiWVc1>0{raws=gjaPU7&*g2{8YtnCh5?5q^MzT^y0^5t!O2&oZD| zWc<0%;5JdEJqJv!_95Ih5Mj|`QHc=Q$T=tfxLGA36~I=w?e9h}BH#^gQUT&>61A7L zJ-p5$-UNqpgG1w;|I8<`a1Z=>Xh>ZMY3$qZ3l<5{9t zmFQ)cS`;oDwu3Zx(TXknc-3vFF|FpASCvQgq-UljlR%h}*|tVL+Eze?6x4e=!awd} zbkyYlznZUHc*fIKld>n!D^Su$VgiG&G-NR2vpvP=w)kiFEa^^Sf#)ylBykf8ZpL&; z;@OW5YmBHI7Dg|73`b66sT?;a*^PfN*Q zivDZi@P8nj!}~UvUam>$cUIickmQ5ZC@yD4n2&-Z5 zMp@Z3YJn-IZ3rEXb_r|P*2sK{N8J$0467*LV0ROmkQMA4DK)~^z0}T!<)$&89kASR zzf(wHQ+K|!HB;VbUnqk0Qu^Ws;FYFKCaSv)8o^QD4w9XR{4f)C4ulsDRJ1NSrH^rx zMRgL1FXco1*3@6mFT<@L1!ZI%S75R}Lc*j}@dkc)A9ol`ra&;A)|JpYHm|w$^iG23 z%ial_v?2!HW%U>U4IVq$8AdqA;ISxD$7ofKLAt4(#i?H<5lJ{EEf2=L_}Wa3!u*U$ z&bW>7_DmAoxVrQrXH2JeyJ6)xi5omRn5^XHCWr*P0q0(SdR2W|TbN)hf+S$}UBSW9U2n^L0W<{Pe4N7lRT4H!yvi%TS=d~L!|^^iLTOvayiTbKrl`3% zE-!D-T6iaSFBF&cbhg;$C1L`Mm_X<54nY)d(^*cfBPHEC_>fp&Rzhqdg%{p~dH_WJ z$eJE67j0@8seMqo74*BMWVzsB8DTJ?(w)?$RYsNK6|1N=QNJPD5n61w6J~4#YtNU} zeU^mr{1e=}IDP*7Jlk`1S{+WXJdBOCH8qxUn2Lc|VOn&9CG;QE6?~O~lbtcap1;yz z0fs`f%mABMLz{-uG8C)siim|aQ7Dxeh&%rUvS;cVmeXt{j^5*3q&TD#pXliLh)p3lu!Bg9ZqWx;m4>_n3kD}309XpnpSH-{B{#!undz- zXEw8ecO|)vQR#H?=HwX)5Lpx(0Z&oR%snMoabk31vF`4i?0gEu9_928y;CE)gGbz4 zdcL5^QDxL14OuF7F2}XkgiV|jLp*Lza`;*~z_=q15Cfq)hUMZu*D0uEXlRNN8*cNRU8};su3{5JxC+&4i%!NoEA!Q6gA)6**b;627E>v@bhlNQZ@u+ z_+N`aTyHXDsj;T@T_Mn>c}2@gqGidHmWK?vLh%n7+73cAB4jlG4g=rAve*J2YGCHJ zh82EAHIr=EU|D@3ZDhiq5RsbjC+TTqwTgarzcrbf7cv(BY6I&z zf3LiR1DpiqhuYC=xpfX743^zEZ0BKglk=%Hx+R^$NUz~-J~1Zo$7Em*V{@0>O{gVv zLw!p0=KiY9O}5dtD==z&(^5f zyWGIZPmI@?ujKM}V6^oiRH0a9>AYu5rSAFon*!{)8ml6AVj;EzXMl^vhfxjbC4iOC zdwQRMIM!KbV4jPm4~5@(RfC+d4aQw=PW;BJqMG$3ea>)Nv|D>U&eSpI=@=&7DR_}$ zBYfXDDatxnC$0pMl!{2$n8hZInGn9 z`$KthnyNA^QcFNw#;T0lp7#gklM~)aG{o*()wSA`>YHb=&C|F}-{&^2;ir0L6Jc-Z zk~<_-y)#Ns+LUHmGIhUgMGdfJpshdeM3@ODlI5MIqd(o=#Q@GnJkfQXJo^aVf$#Lo zGBT5e(c!H1%Y3IK2151}Ms)jic?IOk=hi*D)+CJWh@N=E_IN7zqnKMtl$~(fXm|}^ zR`@=_4c$(%jY~);2I9*JUv3`dW|bdb?o4UROAjD>>Xxr@h|n3Gv5zi4Lo~J_UCKAi zo;A)VjZv+D%Dly=@kQogZ;s&85Ujpz>Qo4zj0vxy=iu3uSM7T%+IjFq>x3B_@lo^| zXUn>^YuR#yz@IQadnep#_7{sV(-((Rl2}n^V{D}S;Zhe4QX~+qI-GSqWl?9^s9<$> z>=g2lt7Suev^zE`G@TcucOiQP7#w)X9h(hvHuvw-`qNFHdLA+P`hR`Ee*OQq)riW7 z@y#uQ24a=oyeE4eR`~bg=-S~1x{ZU>i6Rm7;?3~h=wD3wn%R8q;m}lGwKMG$1sPH& zf+P|(!S9W_rXF$kaoCvR`nI(3kbv*{vhCJ`6H_y98xFO^oE~CM;33*(D#x57)9#qe z+kjp}Z%_G!4l0GV96;~c$_`-p2Gth3-GvA<{$F1hZP`Dl@tj_O2oA)#LMDSnq-J@j zmwxI1N?V0+-wi!Ku1U=up8gAKq=~6Hw+%NjY1ZcL;gH{P-vA$KJe3EP>@k zIm||!ybO-xdqa!CG(e?&dCbLUWq3@5cgtBE>0T4rW9neb7RQy=0#Givk>_T@bFq}+ zK*a6@B5a@c-U3;tY_gcqN=nO>c`!g4au@YiS+?Vrde6_Y*_T4B?7ws2RUn9j5y;vq-MquX?}DKK(NL^dmjx za-mJsW3r0{)q1yQbABuPbY1^4%Q9tRsTl{o3$q!=_0RZCGLog2Mz|kg?j@kPIK_R` z!gmFc@7YUB1@CmrnICP%u$K&%+Q@hArWn=A^oL@j_6bI{5k|!(eXDW)Wd4ZY$csFG z(>XK4u-=3%Ax3(>kE6XtZ7EpvUScTOJ&lX5`Av%NXkNB$28(R7#}5xLIf2nf#So3? zuG=4rfk7TgiP0)yTIA77Fzw4Nm3+$|c765Uy;-D@p$c!EUJ(ZMx%6=UxBSE`F^u|5 z%JHN?3GVZj64VF!YpTkY`aqS75`HGQY%8yNk7UNkdm#I?BKvfYo^r{clZLWnQ0Lu} z%{e3cbanqSsZ1F|1{Y*Ap4~s=bTalQgK+98Q2sfjP$UzR{6}+1q3(Yr1^F*cOf}9M zF8qM`3h#q2N-kxjQPL?z8i{%6EP#a3rzc(|X%rjru1*CYjqCs$PLLgCI6`~99pJ^_ zIlUK)?mi^Q51nc|^y`VKm;`7?Ok+p{h>XarG6Hmz zFF>mhpxp0i-g?TRzlqMcG4fiU;Ey#DRKsossD$SR?m6Co06o}WfNscv#|qFaKRXtn zi~to=`)N&T*6?&O{W0e)bN6FsfB+VgD<#zslNFMY*bn5hfM8^!2w&H>?NYzl4tb7T ztY`}+op!hkQ*0KH-~}OV1-OAjnu7uq!CWqG7Gk`-PeuxoX{7NXu0LGRy}kKt{9$yY zmGezhlDD>)Ka7d@6xrEUXB0v>_EvT0!KOGq8PxZttul(LQD20==Kb8%&Z>_@Ba>ur zUVJ%k00=-bci2!|7%-+SKQMaNQa(H>p9_o$Sb{@pH2O{31-07~#G0e(2+Y$O(Yas! z<8daBdgFeoR$}h?XTI@n_*D(gx zjkV~LOB4%Vf#0xBi&n{|c&u`cB3=XsbXN(99QacU;l)4WuY^fOqJi^KoG%^~f@clm zoDOS2`7{a#MLl28nH-2FkOYSu2jH%XG2i2GyECxy8UvT=sGXP^a|Q;BDQD-o7^Luj z3_l!ORzG4L5Z4g)VOk`XKdrSMu-MrmNc*^md+gZDgH69o-Ey4sonS_C{uahbr~wul zPB7AQmnLFKEFbVqc(DX01V0{uvqT%Cx(*M&XO}wiIblRizp6sl-u~&q?y5rl&;eGY zA2q$ASo%VVVTJO0Y*G|7f7xyoFLl5GE&LwqqxSK@27I34T!7M2IiUGep=R{6(bSkc zXV1vk_d`s)&K<#)SV=IDs%EIU6*DmJb*Zlk5EWzp*^K+oWEs>`j4NGA!i%2<(%1+d zF;`fqUZ-Yx#SEL=@Vh;m3i^BV$g-$k-CU zGdPN|Lf$g68V-Eqy!9>BbS;yW_*Z86zY!ZY%LTeQx$^JfHWSqZ;LFfT8J46wBD`38 z(#CYq6Lqe9FpH-?@@FA@-T2*(fEpHP=eKSK*P33{c3tQ%# z5G-uoDZG@r$E2!1iB;~IOB_*TYwDKac-lMV8QS^wNn)KFdYimGMOemX_r2KjJuT9| zKFl()DjgqVhX`-8xU>R1>5M?A z&j7F1rqnCT#ni5=%w=k4e8X^rEn;dV^bn3%l|B`54reFyYsaBk!=V{N4qHeMM^^cE zr;Pts#($Ch7p|QV*+G7f@GFK4!<6Nc=3&ja#)u)0!eVWLT83NSX8S|HuZsAEbxqIfkWuRn9?eyQ{DRp=v1I=FsMi~h zi}*Ey1N$V8VxFX~_aDt+r3VVc%Ee(|)zi4e!LsV(VI{NVc6guo19xx1r%mfG#blXR zx2$ndles>I^#qB+lMCMoVK1mr30 z!>e!5q>00(OJUQ+!Kgb>Y-E;cIXYqkJSIOTJ~B;=WR~Dcjbc%ah0-wU2Vm5qm!ceQ zeeeW3rHTy8#;uMmNHk}57RvHxMn)Nt9d97uJ*#Cntam|#Bjy~ZU)MaGqfi}!*C}2n z1|C}nF6bp}rSh$&w{+-4*pUTk@tu0mow?gbA6zPMbs&&^GNCMk-?h=ex&$K6E$kAr zK3Vwb%dA^yB8O3Xxs2Kj$$v{u=t-N+rg7($$LS4c6yAd0eK;6Dm++GLW-Ndq!O=9- zvS5)$rV4BVRB<>LrR%^m8YZF-lui>$v+$h)?4zu|UTRE5MxOKsQF261cVw(=*+01X z-qcqPMpMO=9O5bqFV@Bur`S#NBS=X$yladp9P{Vy5$?s3VrU5ELUvpNfh{$JT}Fn1 z8kn`BHcPYsV=xkRCG%zxoGChDoe?NGVAHR|!Vgbrl?O;oUUUQmE?Ol?{USZ5Unjva z5t6aMZfC!hk)P=k*sA9wK2oYvQfeGh>L`Q^66zL107fjG+AEe)#p~SaV9Wj^=Di5W z#69elNH1B%M8Seg6e?dTJsEC0m0=UPS4eKuKECpnujH+k>SOJ;NvyMLzRnq}?*>bn zXU9|D#0~aUCRWecQTMQsP|oZtM?X8kLDWugu!_k#IiVY?n1qvC6HGX7%Lau;6l&RD zf|Ea8Dwh=&*|dM|8ec4Bt(PwyZ^V*c_3i(yvx56x>iM~3(o;vH?yybDrs2s7iBe@& zU^9$7s_-7+tK`uP$)h?ekLtZ2E0rcI6jMvaPHWw?@@O{no7v;YSUL~Q-)2KTQiJ=l zy7{E~tgf|}zmaDlZ`7S(hp;<6%ARDx>)^D;qlvG>mNt)m)hl=u;>o*`M-yVFHF7_X zS`3o;q+{fhT9#@Y6d>dGz!d>?($f7Kf;u-}y!6choy37-(Z;I^}1C7lpyKmMlNy zH|c))D-=q)XIJrqqG9h(P8FVmpTg;*JFNaAb+tRt@fYkk-2==|OD7ImU66J`)4yOq z_~n$1`G$4sU%{%k$}tM?l?j&;Ay63Ji$Lx>)Xzwe{Jikb)`9AlV?QwS(5r(r|}c z4@aL7GAEHT|AucIq_^?qlbqm44qpo$7B;YNALwF{utsE&PW9JZjHm=cPi0_V5))~F zg=ye-{nUK z5vL_mGb177%1lOh7R2Z5IedTPwTKWFfvP=KxIqJ!OeK%N)hu=d+nGZWE_=IQzbwfrw%o`4F{Z8_C`R^5b=c7LAAad{X2wzJT8tzjyM>s6=M-%MyMo zf8jg4=!CG14q4G!4I5nTm1Vi0cqB^iVZeQtW8H{(Du8u-*3ZXSI% zi8drCjb&1Ys&xF7ZR~IJ|7$ zVsJjiK+N)KbhPpldy-Urq9EgTl}|i<%jcA+fYe(0s6P_y5*&rHSkZtc1nA zEzAHeSihY1%m!g5KFd0Bu^^@`e?pAZgwXsqGvcgtngy5khULY_{U7k5E*6tlLt!y4 zeoHw2=s8`;ZP^_VjU`$t^BPAhPDO~5Q%YfREy7ErxD5wB)_7u~r6RBC?-}A$fu^TT z0nuvD7PhF4MZ=37Q3?Sa0bkyKQ@Hg>$d#uX!mURO(=GdNB-By3?R8*FI`5@l7L0^r z-O8^>|3kla>M^8Gi45sq?vwt0L-(n11JXaIkWbGLY#$oXkoz>Cv)y-KDR>tWm<%dJ z9^Sia4BBR+u+*7T(KsxH+s+4AbI4bx5&h}HQlL-Geyz7q>+P!5C$1PZdn>5b)CiZI zZL4j3__NfNLmky$%N$M?Nzr^>`XhRU7=RP~Ge41P9Go{g#8wQch>5UXj~b+R950rn6L*bb8XyP#j1&lRiF1b2af`qbUl5Y_d|5-j1_`$iqw0pq+oww2bp~|CYKZ}?s?lxS8GQOWVxR|QOB$cIkDN& zMWC5?n%;PPsg@m5n%NOm(B$}K#7eR6uX$(nYhs3XQood0UYHa$Kbx70ZJ;*1coOZx z>z_3j#P=NI2G3A>-1#V;nimW&UXBLtJjIYBYo-n-b%wAEBDfVsu8Jx0cjZ0dI&Y)F@TT zHexH&E$&Y2?T|C=H$i7ckqpx@r#=+Rr=}!<(^kh)Hw9WY3~(MY&ej+*G7;B=7i50h zX8)?1@ZvPOkLK4Dxs$0M(bUxgYHs+zQ@U0s27IuzB62^E=o@#%Tiy=hxWc4z#tc~aBfm0!;T~W%Pua`=Y zU}4H0he|XA3E5(|&=7~uFkkU-JS~}bAnpcV;Kc9WB@|JplQJ)sA0UMr!p&)xXPTbk z>FAxm53ueUh4G^X2z+8e>`AT3Mu{S>hf|AWuqa~OggB@8uBclW!DJAOja?I&Pm=Gu z2pI~MAXfS2VPLW-PV2s;oLYo-gJechL~6!~V0{eJ6o;en4I48Q&e4%C?ysB`47V;I zUo!CT-Wla}6)_xK`v(6KDY2aPtEvDTJ#&B-AH96oM0KbHA>vdQVx8xwD4fzo7D9YU zJm1a=jhCjm8(iR27uTe2MgVebF=w{LoU>?TK6%Z3kY});DBvomEjWU?!7He!ICd7X5r7d-~2-p|krsSoaHd*{zE5Gkv5!}Dx5bpDH@UM%k2DMJom zr!|PGEu{S^B2XDF1isoc(;Bl9Vy%$myr^N?_%*X=wFdy$)m=cz+7aaFDK{5wx`%;I ze*hpEbjWT+n8!2x?I3J}OW9~CyeLM6y}-wue|!HvQry@QCOxf9eG^XGCHGNhM$ie- zA;DDb#vTYVu&LN_8dyRXJz&7pG*{!M#<2iu_L1;L^mI|H)Y{tQu z2F4IYghhU%j`7R8#Kb=wXysLXdIXwGtg=4Xw2J;Eok_)-zs=v$=$D!aY!2OUILN)D zRL5=P?y0l1r)^<+a&Z;=FHEj#cS^+pd<-n$tG%?XNPeyHiSRa&+H*Lak`hQr1pa zCTUmGV=N3)#VmB_eQhZHN9L18Xrw)aX6%T?>4|8hvB3S7Htdj%6zc{?9euDvs2h!! zgPJaXti?j}K)w_5h71tK=U}rL=s(T&J_#sI%l`%IH-X8FEspqd%=Qja45n49CW2+1 zm;~a1ZdA^m0ZwN(k`Y=xOpcp?Q>)PD&Hx#D(JSy_n)fml%_mDb&bb~CW$~Zl8c}nc zJfHh?GNW(;J&gXv(B7I5Md01)6@;Ic-c4z<`P{*q{-wXpSm)|2=(n$W%O>aOEb|Kc zszo!roBE~9@~$L>cIHzf^;z|W_YU6mFMSV6U|2WF0JaWn z*Xb8oS}Xky6Pj#DJk=4%N6L#BsCRIZ7KH3Ukst=?y-kADy*8umb>>^XX%#+uW(hLc z5^wkrTrQ&k974>@`xz>*nO3NdQe?D1^c)g%RKJB-E)|+@GnAml4z2zDD;JYS`qr?W|1 zO$|AmuLpQl-&ZeOZS_LQ8(I|8l3qCCAouXt1Kg9{-ev=i`Y4OXnXLA(M@ClZlm7t;y(w~YYR}O zm1wGY0GUNd(j7g1_0Lx)oi+AaYupVv-4%rJ_VQ7hWaiuYKaMn)eLZbz1RGo1P#H!I@ zf=qU$fH)0lzHJw-B|-|PA`;U6={`nXIisnWM+B_qYlo5ViC-H+52q}bdDz~e0Ta#3J`1U$elV!MR2DDD>a{|Ij~%q7 zvMlk_&`MiE&{t0RUau-_CP#|}C_v4I`#`o80n1?G^iIHr+cwJIB=ucg@2YmugpVJP zWgpkjxg2yc$Ci`FTO7{^abPf>uAJgo^Rtdo(e7yCoBgI3wcK~9@T@x8!1vj<0JOCdHogS4eWSJF}7`m z7j;u_uZWRu+?{V_!X|2@8>+ZhJ)V>r^WP*`HJOR`t6(y9p>$+wJ<(T^f0cpU>dD;< zh@c%?(Rd?A+f*O)AypZ01t)Q?(UdPE1%4n#ARdseVm(5RnE^kR3qdEuyfbxMPAxt9 zR|obQFGrZN)j`rHVaYT4^ituX7KK_|#;_K5Muru+U*n8yb4)qdk6;a;OAd+Ug}pxM zCWsIecZ;zu2RHX}neqeG`LO|?VKdKLHsf6wwU+jJal+ZK7@xVgO?l!Xm6o~0;VbeZ z7^j|es7E=hB+ENe!I74Y^7v+-cvCAY_1<4E zuVvt4PK7u716>tp4*+`K^j{vKgm<-hu{cFTmyX$2LpRe&Yazc0Cd-3r%9uDlUr+Zn zul}m~iwGpm>GYqt;TFQn9qkmCr~3-~s*iv-Gt#$d(fR~{Dy47jk+!f z^)EdY>dI9zjk^8@1Lmt=uX$VY`f9T)Dds)VFHzm|9v~6PD_E&Dt8bE&ZSGwz!p-b= zOJAStJegJ56Af?6-E2R_rK%e(9e*$=(3^gNl~1*#&&Kn|yOe~iYHp}B&NX3me4bN zp|$irHd?N4ea*YSDvQ9~-jaT;h`D-qkeC@QtR>V<1maMxGLBjHM5Sjn@n5s1GiKS@ z88uur`D*xb9{Z}{9lT-+(#SwS_wysje(@e^__WBJL+Ie5ZRy~zeM%N4s*f2vpuPgW zj&GVl8slE>sE%}y(nkSbZn9cFnNh&MNf*H59BJS4DUj8^d+U<+eU&L{tq__-YAsj$ zmf7~}@KtpKW!BnTA%7k)u6C`(*Aj1d$wZ?{SS)4izP&cz<33>&t$?Al zK&jEOIlrI2{58spAI8E;c*Yr92U^S!R8nd8J_pqCZgm+w7JKg+Lr>NK{Ig(q$<2mm zvO`(JO7HTqL=mUQArZ<#%7{F+=$FPtvZ`x2zd9=`x-{n#TFrTV5c?1*`iC|~_($A) zc($B#6dP*mdX9j9#Heu(>AhqlUzm^=LF7rm%UW!$pvGd%K$az(U_?8NiI(*t8MmkA zIYsVJJq>k+#2bcUB$mn8Y%pW1D$$xmsrN}}VM#_*F7taaD2{H=jzJLVReVgmVa)f* zsb>>WzZ60CePrZ5ciG*#pU$`Cs#}?v6LZGh=_&-07I6At&?TpPbxJ;kF;sTV-0S9tS+00Pvjfx@a|w|5me@Av8V2@oQ)Q1qI)^-^=f8lt`=W=kr{~iIazD2 zMqGBY83rP7sDwkBbgQgB`<^M_>$4&d&DRcod-d5FF~{^N2R1~tdWS+AQQ!0|;t)}Y zPv>g0`bKt9K}MT36afv1mV6K^8(Vs{S@RujR^S8xXFk80f)#-^c21(?>09GhYB&$P zQuZ9!H;QH3h60!k8qd!8Jw23;B>Xf@v9?$5*Vji;~PWm%P8u2+y zJ>gI-W@@zN;xUr(BiLhN$;%Fl<#{ZJ7xauwxWn-^btV*dPcXJ;CIu5?Blh9lS^Myu z@Se+E>`m9rD8dZUCcRC-UVPd?X9D)( z;$N9yufa}i#KU!@VYY81#!C&@w6O(n>8ru1(N|w~E-m&Bp5xo+%z8_ANg5+N8f4fg zYLC!JMu{Agt33J_MLH8g>7l9-Ypod{i?or3{oA1cREx(ss2@@c*LC~GdHgdu_(}_2 z{Z5HMYZ~${)r$>9*Y|GdjL5ZGpbBd8i@+@}8->hf0@y)@rM+L4kSc_o$|y()YHv=iD5fWjiXa8F@^1B7D>HjU>XL1qo=(sxKsI z#_3=BM;Qe(oAMDXkozC(9Zb5vU18Yk2sBq3ch88sUnN|_w^*UD)!K1lOL(rdAxo9SGZI6?Xx(@HVHC#{}%qzM2!numq<|x`Q}g zn{@NMe|j1zIoT0H!w#fk>9Ur?ghe84cP>s$@5Q-|Je6hh{v|KBB5w>y^e@3Wy-4)oebFTB^S;0@u{dxA z@^Y3=2iCs6iNVvpuNkq%>kja{_Q1uLj->i8^4ykqG=&_0%1Ny4urz<0H9JMUx?N!-k%y5f^WXD&%>^Skkj zwWb@o&p3RD{gD3tE}l?}@?FME(BvW>IBw^@zsoe@u$Uh4fgSu;yLXGO1h6Z$nV+Z){{ zr8P329(uz_%*bnPchH~k;(v$wEwAMDQlDL3oz7>oysDQ1G+S6wU97c?;|u3si+SY$ z-aAd}?b1rz96rB{AMJ2V{138mT4cHb*7tn*!8@d}vFUffZrJ*3sqgSjK#HGgCuJqS zHXo8giAG_w>mIwZ@?t8&#GRE{P`zgtRMX`FGvjksQ(;p``-I44HIloOdW)shulp{g zsHvX^%%c>_T}R>I0RU~=S>vqYQ+V-BLAt;?YPy7+ny5)#pYebJ+!e4cJ)0tNzh_q>t~ZfURz+$n+LSwd*fK3_AN=ct22+k~JTSlr;9 zG3T2_Xk+$m0g4t_ohDt~J;dBzA{%!8lr9mBD^UhkM` zo3Qq8CV<&9P1yV|=^_AF2a(PWr`;~^m2&t`xM=X776)W;6$CT|(7)rfVrNy|EI zKy>gO@74`Lvw6ThlIXm`vr~9y)E(yg&OB;Y8LejXiy<}{T20;Zow1u@X;)&wFAj!Z zR?D*9`7_82uyLB{21(O%mRvZ_)CL>x$QiJuyI=u!M*@HNFS67UlMrdd*&VCn2wgBz z`M2Jk0-_q(rPW?F%FvW)t3b4?)z2nt<@FJ+cidRDpl{0h|E zrIo&sU9^o*Hx4tF&S8IadI#y1Q*zc-<|B9(ECDmE0il$2(^eAVMCaCr#>6D(R(s#&F0AegLjyRPE5 zK47aY-xgciYQ>5+pd{fj-~&c$Es6p@PYen^@*v9Z{h533J|r99+y9@J=H8uq@0>Gd z&YU^t%$YM!aYKTo)abnZGK?k(sc<;AjZ_vL7!sYXczs31e4oKVbW=MQ8=S} zMB&tFH26_Cf@kB{h>u5!(2hAgKxi}wJz{`ItPrC#t1vM@fjAQe@>17{WLB>%Xs`6_ zD{-hku`6ngU07LXD+s49a9btyrPzf-Sj|tmB(_{xO+zPCvUdS1Yb6VgGOzGkxG{QI zSC8g7mHi>avAfB@hF$fjYa7)ri;xVMDumYX{Q9G1V@*ifSOZw}EdaaDOCW4`_>{cp zMu`AtYylEvjoL2OP@B>JP&SDWz->H=-sVI?)J8wnhGG7U-WtsSWKjQyb(^AHDhS$e zo6xo$l&<3~8*gKudJhzEGmbG%eB2-;z&O$uj(Y}4z_o_;zY}*x|Hu_wbf*5ZBxyL zj1o_!T0Nsyb%O>Q+#l`tNf zjs&1BNBK905A;$Enf}SUKFPc7CEYR;od8lcGm-4nSM?Ow8%#&?ZdLa$J_D?MDV&(H z+x$8C;sf1Ze3lo(i3zr$L7ToURKC*Yr()eP&#vwjg$Hhh>6M?#CM7zO&hwKJkyoug zhF7_gY%r+s_Le*fE6Gm9b}{nkZDv?$KKGKk&|6zl`Ki9YNi4at>rVErS2~;PFV`q2 zG8OAJkd#;NB+#{8;Ahjr+G8N;q!sNp{qkEf{lWv^cTY7|{-PdTJ0;n*FVJP3Mc~u= zxeWF7p~nv}4%Do{J$;rAxDffnW zDfhhWMH=tI*r(+RH{~8eIJ4>18{MY=Eh}M8a-TB$7561VdT<`w-Yn4e@ZjzlibBqc zK$CJir@)5GH_cey_2BmtbxPf{f~9Bnsn&Ox-s`_gu)Jsgs==J~`mH#^wDv2fltt3KgX{dL|8*6dupL z?vnpun;)>V$r`^6s?y8fFqWO)_6TsLQ1y=Z;qX8F_9YzQvw)+p=SQ4Tb2(k+{)jVn z_Tb9F)2W;T`boNPEvb zD3m3(q%m{q&Vb^EF9rpgUglTwfNA*}5`5e6#VAfkKDXhEs`?oXUxcIojI~`pd-|i8 zdy&4CaQ(8b11_JfxOP(B9NKVNP4p9D*jDu!;ug*LfTRx$>u}=4VCOFoEiV5_h4`6f ziTGIJiO2yljG8_k+Q#>Usp!*zOJi$ha3H4{xYd4pI&bT%Q+j+Q`Lm}l`|?G6+OtZ8 zh$P1htz1E8&X2^S3&=YWWF>~K993$}&B7--o5CV{h^Fm4O%>OF3o#Nc1lb~eL3Tb< zTO`qy_OdyTm#C-NGD##p)KpNAPV`cJBBFO>5Pey9q8HLRF40dD(SHijXGfnv0sqH7 zQ>*J%UT@sz*X<&|h&u{WrFE=!XzxR}9w7opJG5i*W*P&5S7#;gturBT=2=XT(2~?F zhd6NtU%axEZ;RM`e1ABuj*8Bg0-&bYIp698@k$Ct&806EL>zhRK4z-UHz!~lbe@L1 zN!EImYOP#-`RvZqc$Vh>Lf?2NbYUcMcM-U|u4kLc1{Z;u{X_Kantr%f;FcWok%V=e zIaKxDU7?G!D!wGb4JS=CXwLpHs%Nnpio)?rZmV)`RX{K$qbVVA7zNr;&lw>2x5DwU zv+MyAGmvrdv3IeNK6Wm*%Iy(fB77o=Xmg~!QmT256Ke)@Q$1t%ZtGZ6a6;@U6S|k@naE?nlr2VNN`z9RzT2>|qhUaY+e3a{^7r;QeY`QpOK9DbKJFErq=V z%8#$(d*wOpN6Rd6S{+NFm=TaIM{nKTns5uYs^BLS&_}A=)?l7fLF0-BD7c*$7W07K z3m1Q{-R_gsB-S3&K^gkz+^sFYIvtMJ=kPkZ<%_>l#^%bl&MmwO#nfYrf#y-HaKx7g z3y!eJud02P%}uMr&KsuoPI#>RVR1m<_TNaH@iyKo?`^&db1q(dSO?taRu(kh(Ko{% z*UsIvO+107N9^ZI)HJ)bcKlI{mb-=S;JXC?e8f{!-Jwe@r`zSdV9I%mfgsYw6A{`4 zyJ0sU8@CNb9jJ~c^nP_brkZ(mzP&6FI=k;)z+We3DG|S0M5B5UqoocCnEoQDWaPar zZhFFSXfw;<*yPkF7XDao^28>WHuJha{#Wub2`)^`KDJ4zZAxjgkjLTj2h~c);vKkS zx)mHTwJXFvYVa1q+9eQw+_uNrf&IRYEy=8i9BKwl7wQ}bX^AuRMRVSfs?zP5J1(a( zuNGD4RUztg&a~%<@p`B#F#tWhOm)6Ity`U67E-6%bAi}-sxxsxKS0_#Yd?1GR-alA z$@-V1@mTCTOL#FpY7SCxuF?QljyLDjz$*yfp=}rY+tAnGB#h2Qiq2=3{NfAP(yzA8 zrpnfHGDhTD7`df@{;_E*sj-xvbk{PT0Yh0Lv3%IZeD-RZkXgW^_!9Lr>C)^$(#pTh zj?Uk|DjCJ99C;X)o6aL>V?1Fw!ifcWog_@?5`z`9$$94BZIwb(0fATbtx=AF@bCxq zesp7`*0Pd+?)k`7d8G%0R)zP=%`u1YI#7&5{dA`Aqq)tpCyOEjEueTp;B)z{CQ{~q_TDm^C+5fzH||-$?SYi(~{)`^C9=lma|DY7l=u_@Vc>^ zl-|J;MDU~Ra`2_}5l}`QPVsLkK5Zm&@|{!#nUcBbcm}1^!s#w-JK>O)OhF@AA<#oF=RLQ*?Mdag(TZH{GgyMRb_HfxzlPhK(i#^Xgzty_31+ z?6awW>6}hv_^#F)RGYFgxs|=AAo{h=IK z;GViq1a30c;90{AEKF67 zRSo^)HR8X(Hmon+9{+hh9>()Zhpv$cJBY8LKQ2D+RN`|J!vqum&Jqeq0S*r=}j%E zwfwNNZaMgb+O?QZ(gsFHntpB%H6gQ}bqt>WB#6o>s2EDqc?ca9fyqCm{s>II?(3Gx z>&pXA6cjh?Jfps}Vdnw$uQ$C||4QO4+~RNG4aqgL&_2)0W$w^JEKIh_(=1XJz1#H< zy*7urqa+9KlYqErE>Gp>XEf%=K5sq-RO<(P5*W00K^=eFKMDL~=_i37%LRSVF{mup z?~gW^zx;CY^#=QGy~K4vn|}tiO7-Kmz=iz^cTLfHsL2A&vqN>0=I`eL(+(W-E#K+E!Y z|C`CI#{mb8JBF~57hTo3eMod^*IEG!JA}D^nCgN~<*#$?aXe%R!3CXJ`xHsD0j zxSknPRv43Hfr0|^IeP-);|D9S;j)3-Ux6_8@XTtQKBGf+NJUrziAV(|2~;r`+)ArZ zo!C#HH3&jcwz&OT8$Mu{ii=QNIoQtRLoUC6CAYTgHzVMTz!OCGsDp>84_~8$*U@u2 z2YODVZ@)K=J~1bwlb_7!@B3?1~5q8`eVT0wdj+QVnnkf}oEX{iiV^f?WT*StZ_3moli-3sIrBSoh>is|LtXH3w4 zKl-9@uU)5X0C3+%b9D!%uJ7_8TW5--+3L4NG7Ol;G^XE-R|Mt&KIqk z5gANyU39f;NIPTO%wej8)4AQ{HT#a!$LxMyrK8&1RRL|$%{6ZwMB`>|4uS=GtJ)o? zYJ6v_wN=nIbJ{DVcX4@1wOG~lJeFYWAI<~mqbwP(6>TI+Rg!1qAXom8*l&PsLU z3t4q8@b+Jibv~11BgFmmqY9BQ44VG#0mzzBHNU{axjaFqQGN~SH`|fc)dM%h^T-m4 zlx@$;T~_|wjQ7YD-oM(}H0=xqV}HJS<_H~Iw~2XcU}tI`d z3}RvZ#0NxC90@jGa8RXd$t`y#?=TUtTHppCbmdj&c5z%;o{7OtTA2)$f5>U<&vzb_ z6vQ4IN7zmaz3YlMk(gfwijjEPO0-rr5^H;el66q9EF8a(jd7pi!>)3kw_c_H0TTkL zSKxby?rDiwOCMpIs3yZ>ztIBfg4k+}jS^XB^UG9B`npq*CHSW~wd5 zK$8;45-K_ePN|?ObS^*?1rA=~5Fc>I~^8Ec#-U?P^1nLu~86>HlrcGx2C%`Pymc#w+v7m(M5| zxXyV6;e!Z6b9zD;)3amQv`jG2Qe;)Oer;K97ukeg=MUgq^p$~Yjhy*ifAR3OiL*ju zLe8@`d^bPd=X4FI`lEe*p3|6jOD-99rD57f(amICo<1nze4_l_@dJ@&hcF$i0u*SV zn!f>)pyp^3M7aE&=<9$d+_%#v+;a!1^(nMoKdUCEv!0h-O~(D}`geWDE-O1oOBQyJ zBhgtb=rlx}giMRD6T^7hjno#=15LZ+dOV2R)_(k{T5|5yKf3m!Uxe$-v;V?1>a@j? zpS2w@Hs|(sAWScB?-ROo)yO`iOz838`#;V0puNwS`mxbfBlEI-a#n4&PpX|k?IZI? zU3K9Nt48+sB0=o-Vkb5UK&guSNUsE;;@`P-wMRnt!&6+fO+!Vl8E$pP}5 zaKg;3)$WJlfD`i>iRJ6OPj6T!6;obwsE+o0>+O|K2@6*~jh*jJ*YBBIRfVSO>!svY&Ksh6yu7kGKuC_}?-9jk1Y(_h z8NXy9hSF4wS20th_L7CLE=xf1$3-aS<@nfUXUv>k@v$$NotVJP#SNg%B+KqCqjU-D z%=>v{r&PwbzS9RV0nZuwqVQq-yLKF^9qj*c^h11Cc=V>Vg`JNWzb1~yps{jcZoKlT z^2&u?g95Q(z>SYxNJR~e%b4`bBDJqNW1q^H^cS>QrH3)Vq))_}HL^AD-)kS(ws;jv z19$^{Pppy)RTwmp+W$a-f&&7T+m-&&dNpb*o2#8ShJId^7!!k>VLCg|l52zRn18j= zhxTGweieN$cUp7j9n?6pa-OFhMQWq-aAEc_g@DJkVMBHHg`| z`fXqOE`wB1)?9+?fj8!xr}o$5X>H~)ZsL^-yXh~H#I%=M5(^3a|KjVPXux+SptGyh zTuRNZR&y_Ro?P?i6WLEy&R002$A+BGywfVneFF=9w&x_!ECDy@BzrXB2$;FWtem%#`w<$+tio}PlL#cnAS#@f@xli0` ze`$D^Z*H$B0|xP{H|Y|6+zu>(Dgjie@k?#TA?TpEczTIOPO2VQ<~4O7Kv+!*?0ZE7w^E++jQl53^P(8?>2)urd@9NKmJlj(V1N& z0a3{F82c3ju%AW}Sds+6nrRzo7t=|avW4#Ut?LKpEG~QSJlBiJ6mZLy&vtjNg(~9eYk@yejSZm>(Rp|Uj z)^UY>Q#&K=_7nCQD~O4ABIYqZq^_c5T@%dQ?nRSKLPcm)5s|3^E0J%fu)5$HR@-va z!))j9TpnA@JGqo#5+B>(=7u<L*rkVl^xLzb` zDsF&ZBDK?9T+NPU;KT+Q-lNU1T|836Bz=^7^hCZx&OFV8GFsw4C@Nn%!)O~qe&2H| zLJr5vN=1UYsrvpxeU{Uk?A|Z@VJyy3@91i0p50E1f}}Nu96lSPP`L#{C;p>gBnCb1 zvazFqrqlUIp^thPuPS0s_h>K5E|8eQGv#s~BNXW%^x^48y83_{&;+WIr^9(A`hkwd zxQkk}+R!!~d));=`~x}6Bee)dvf;<`8q2p%&vTx4R$)p=h;g)rzCs_VZMT7Z-tILa zwc27#50a!ccWI7dA__Ei7*EfKN4#00KwPz*V>%r|lPVHiVo{kqyJ$ z1FfTv`At<0#zg;{$G1`jank(+afi?rKkBWGSF%F zNEmkBT)OjH0}ZiN&Zcc&IXi`qzN1uDz*1-XwjB(gTqA`}v1Yf#l{)eVcmkH^VZx1x z{@r7-eC^RH@-Y-gxnsiom`1sS88R~DS1A_L5?pL%e(*jjxU&(8baugB~B5?(}#b zTr53?A2{tG4-MzQ5FKQxio6hQL|D;hUZdCW2sdp&)j8-Q80}C40fN$xF z_>^FWnI^R7sY%EnIJtaTw9DfOm~x=doq})1)%RR^Il&W>jd_i^zMyE0kuCB#h7m2~lSHeWvn}w4_S8bN-WGV9kk{%5^Z%-Qcc`O-cytSx z%-n2$CCE#p4!-VNt%*X?Nb`XGn%x)X*WTR(wHstI0U`>9N;cXw{d3~o7$R!bYj0{`5s<|$g70yELD-T0MHsS;S1l~gJbGJNd9=sOmp`impBx$l{sYMOg4FRdZ=Y9LL~ zLt0CdYuB4~ykT2upATJQ_P34QsmA^!iN%{>*~g>@+Ea<_Tzvn{*3BFGaT+HKvT zJ*kdLhjyiX!zV2G+{YV$3SWXBD%I%glHleM;i>;)WzgftypchD$L;=1>em6+qrOP-0Vf?= zfjqXE=0l5fphdyClDr-r!sQ=EH}#+c!qXjJY3q;w)`+T!#QT-yvR>7AdSQ-TgH%Qw zOf3cK;PA)!T9Jo5IWf>w$8bhy^!HXGNAj~eaTVh9#9}w8m0gE~Dpa;I*mb<^FMZ%H z`f0LUiTQ&%1jmMScFu0S%Nr2_oLQ*TDTpOOf4)ke|sVdaCIoI4^YuxCq z{4p<>i7KIi`Q8#9#3vljoP>K)ZGm#w@2-)*bBW44Bfr!&^53P*HS){MISacP`4wh= zYVT&`qmTJUzI!+U>btsU5~QBs8TmD4?PI`7H}a>LC%YF-HS;rzTzlL652e`8GHBSL zw{HeEdNB62Q<-L6|A1<6sLPC>1^WhWzZlCBewh$)9- zC#USk{;^2y0XF9+S=-2_crc9rj8zI4ge=hGwFt)}dFD$dcF*W$=&fKGVfs&f#oe`S zUAIUrdxB{q(#LaIjn+sC$3vJXHVVC3`1-S-xUEq%Mki0T2q!sEM*%IMilHJ6fx+O!8SCTfEp~ABTB#+C?E=;l{QIjUN z9D#H^Or)toCQ`vt^QdA*ITBo;sY6Ut?pf>3fZ}P>*g{$zpXc#BiI2n~4ZIX`KKD&o z`5m;(Lm-f~sxP1I+toF$UF~zPZ(Mid;ORKc;l-Y|baTp9JCu1e5+8s8=Hlqa^dvDr zqn7rrfB508H7!-r*XonBU?4#Q+x+l97)6#EP~mUr?A;s;v{O~8iUzKP=KL;iT7Al# zc5P;BQM+cdjOsStjPzwcdR6YHz7f6W;X9K}sKfhC+m8qeXGB(u`Jd7ZeDjD{W0y?= zv2R(XVc@b}Gxb=6i$ozTC4Ce2nbMx8ct6w(&sf%pnCf2XM}tI>27X9ktjMv5A5XM&FW?+YqCt)$xA#td8&zeUpMgFOtL>Pnz53l-K2D< z&QUzl+*RtE!pTW3DSt_{mtiTFW?0HXAk$LrtJw{*CN1R`-tT59OG5dUa;avt5;OK4 z(Jj+b{s>yyIA<$$vslW9*_lCHD69Bh)JggueYrzgE28xo8>eD}R9OGFaVl<*O5@2@Cq2}!mD8ZHY~m5Naz4-#J4Z}jI2HhNUG{IcNh-+$xArZdgXjS9Y4X@j>z ziD{&jLtENyjspzuzxF8#yt5MZ)mvIVt4#C^Ry)^~Mx3(>t?Ix{iFyA$45aw!f3qK) z6*MQ?kpB_I?lRc3JY{mhc4Zw*_W2fbsdy76IpA&I{%6YK`*Gakpvcw*55|FVzEcXOEy5*PyCC;{+llLRZse@<&*C1xVT$8j&?fC24bo+OaXx1KbJ|bc&WW%Lf9wh{$^Jp~qWHj__#{2ilmJ;L=B%-N*M zZt^={ss_Dnbxqv9GYR_9G4ykGnuhbR!O007Eo6)zVAtdrDh#_K?D_qRcOFuL! z7?sFtuP$GD-8m6wb=Lv5eO2Xc*AM5zLg~oy(ZT5->gda%Yd$`UMy!>io_Ok-yr=nn zNZwkU^Q@%48GVD#Zm{xNu`0(A`LNd7**3mcYxE?eC&R=cLWz)xH=_oy*XDP9e|A;* z>gz+;axT1(g@@p@BnweHA!6h5NPm4%8+SF~e`^E7AzUj)6 z+rd#e(@*B~QoAwL!ml8k4}stNDdUCn0^j*ayoG{=7G;SgKAy0+P*kh^T$#TMU-;6= zU(_~iH0OXAcvp-W&Sf!+J-B%lC>DLs;WQi$Hx2J!B5V&OOs#{4E6O~tZ*~{ns z3YL;3g^r2wrmdViO$QQ2`HSol=$PV3jFV!LHM!sLv0mmgYuhkp_$1=w6`T8H=W3!* zZdaU`Hfkw82pmI>ar!u~vY?!x$y#^LNGhj=JlY;Vaaq?}nf?eH`CsX*urW;~T4pYE zw!xkgE5fk`pFjP_u28C7Hjq*h2(T2WgX9#^ z9Z5{F9tT9$INTf5iT-^AH4@&T$PW2+LIYpmaCX{X*|$2DbGB36sJ#ZcRcs$vVPS~Q zsVQ)|s%F{XZC`(Y?|ghM6pOU)a3{_@`dU|WD*m4R7*0Fh1Nkm1l@c7uVSNA+9&pZx z;;Pym=InXi5;OTmS4=<5I>aJ!h*_b*2z@{Lft+QPiSe{=L~*6F9r_;j{gZN0%PIqp ze8M3N;qsN0oDm&3w`2Ojxem9xWn8e2jn4Lrgk-qO6>t!Po9@)zxr zCYfr2gnQOlfiUf5kqCMy;Ge`)+2pfsxFE`P*AusJ-mquamTxOnuOC%AxmUi>Mxbe3w2z#tXFClL~oIYTo<xlx+{j{q=`6y=HOqDj75}V+)9VAQ^qWr)eBY=n4 zBR&h~9ZbXGIy1Yrh9(AFY&r-og5SjS6%6G5)=kIj)o2%Cgp=Jg%2*HQBK^Lr)sQ(5 zok=*~d>ff%U1(+&vN_t8#5-m6;yB0H%akW#+TrNI_lM*^ge7kSh%lCFJ9= z36fXUuCVyME9@=Gd@8KXAdBTni)9i+>-7M~@W8JW`wZ@=7nfG$K)4;%+iw4k6*yzzU5sjX5tG@ln)Juu|# zXO_OsV396sJ5)XQPu@%~sW1=PZ`(ztG7h(pNl-C#_b4Qbf^sGBgYHzwgHmlmc9_`O zFj#?x@GRoAU4q1{z4=Rm%2&Y0%L~nxUlRaYJ~3xTC!J{C;FmBfGtX-@h|1U%>g0coD+iy1aNH6qq6@Gx2;K^W&`LDT6Xx{yFPeiJzeIvq%Vw)KL?X zE90~>Sw)j{OhWSmcy@0hmvA1?)vZ(HR?z-u9;i`MT*jhq`*^CmVa}be%#HRX%tM>W zbHBjtf95^dqFVXsMkh0Qdir&$CLND(hW*y_V@`1^bkDPWKR-)0&(X@}xr7hh<80@G z55W=YNS5Pp)4k4J4w4P~FE{o%@e;H6%_*r!ZibQ#l9)nsM*An);@q+yV@uA~r~Jbu zX5(v6)2s0)&!I>(9ERd`vq)2B?TEpe2j=K^kd_i6n>^$oAF-o4`?~dz)Q>2c??TvA z!%gIVk(E{>VFlNEPTDJYN%YNo75|dp0{(t3Oak`ov3V-0$&Vk-SAsx~PEcxp$vJ+i z!l_R6&3U{}oKPKK>#e|Tr!gmJuL5)_K^>L`8R8)5{#YTCR|UHcb$v)H3$^M)62AlW zdc1NwhQA<|2csL}Q`k}%Wj&^?Kd%4n@(HSHaYjw5S+<_UfLF{FzomIPOX`yCcDBJF z_fW2`{aKz47?85Y?$f_J9NaaDw2?TdnSJAV#kvL&A-Wc@crdgr&~nqEyUpL%Y1q{> z?3Sbd)vg~&@kzVQy|$P|4*DV<-QJi-LaF#&uhqgDHyc$%(Ot*LO9I_U{F-qR+B1f6CpENhN zOSw$v;|938*czQkfG81Tln8V6Je4lXAC9EB-ySu~W1dc6frOlyvQxw)?t5caZH@OC zJTi|XvD6f{9EdRp#Sl6=WOlR=%qLT!cr`+djvfSJyO@XI9We-cBjJ#9xf6J}T7{gn zs#KSZic4r@8r@F5&lNT`5G~@31}Junh&MG-`-y`zCW19S=28Cu0r%{HYILvLe{GrE z%{*+W&g_F6wGkBH8W~t$%rRE(;QcDM7sX2wEPS0}Y zxWjh}^Rc2H=n8v(O6AHA9=x;8wrJQK3L37szJ6PONqV$tudMc_O>?WLrDRpw!EY!b7 z@@_J`Jdx#d%hY(m?Sf&s#u>9T*tw2(bufV?hT9{9B`$fX1|CqcAm=S@cMl|x0NX?% z{X27oJN>Rs&G5@{oYmquQ@En|H&MMTpJQPuIfP9*gZnt4e3T?PFmx8|dvHh{bM}PJ z{zT32kxMou?efl+8aLY~-c0axkCa0Ei!TU@}8=69Oj$@=93pS0*^A$gK{;v3S+lRKr4{X(D zCAmr)mlv3;{4Ny~u_x3iGbR zw4&mM3aluoEZ-JrI)QRg4%}91vmECu<~0xpm0m8~wr*fYVn9A&C6^8!n-dz$_vKFqn*I$m za*mM?at?Z62zD)UHo)%2(NE|?it9=k2=ypZyA@QPAQ8dLi1U&5nAp{Y0)$!pM@p@j zxN@`2rpAV}am53+tq%7%hXa$eAL##qjqU7#D;S6^5SE64g9F@*zJAC(!DYp z$-tdYM-}A0;EWDB5h6aMF|VW>-<^@rvL8msII`DTE+X8%^*>48DU6?85RRW4MCx1nHeKETSSLP8uRa`({Xv?J@&I_;!Idd@@I){J4wHh0x(V3m| zcn6zbLk{+1KZ>{6cIa+`zdlo}SDA(lN_c+6>0fNBeyuGU%MlY(D3_)EG9;@`JXEX$ z?y8)15eIwX&6bj_%9J6?;u;v1tL?bY%|{&)gHixUOVTl!+#!kki;DyzZq?bKc|>nu z(HAjS+jOZywa}E%WQ`xj4bR*>ss&lfawsD-?dNP~xty6;Rd*eej89<}7h_cCZe@01 zAAb=l4{8tUNM_B8g@ju7EM)Pp*iWQ(?NnhtcMI5n+;G zmo{l~KI9M~^xEPh*d8=1TzrHXCa|X~GYn&JbbUm``Oth*rNqIXoYBOHdcgT`C`&Lk z<_pnfO&_Ooha4z-^(?j9~(^OO8MHnNBU{%vgykvDt{o1S6o zf4lC#_K_7j7bMa?GWY?5ifg`JjX39&#db%O_LYCdZERmIQp!56qm_n+fX7nqCtTsw zuqCisFSS=rb}v)h%Ov+w?_P8$24BY-^pk(wO6$?T_DcE0xI}ab+`fvxRnAsc8M@9y zzCpvSe^lC~vvQ*(Lg@Fl`=d|v6xU7HUg_2CVxt9#Dpcso^7rd!jEbuZ7Vri6Ar1_c zFRg#HS?PFMchJ^qX9JRO=_h}xe~OpxRkh_yqepRnn-A|Gel&RS>JMucX9*f_L7 zZw%ZCM4G0Gzp4AvfN~N)zV80$6FtTS!e7Aw0HE?`{8o-qcPK31)q0pJ*39o#{M@eA zV^kuZbMp}$nt|zrP6dkWYCSpYSoYQH&I*)`y= z%Iq+5d#_o%ARctFJC*l;_&Z^f6IElv_8!cdw)0-IC~dQf@wUsjf!ITofk9E{+tP>O z6uCQLmSHPQJ*s%;a}@7tJ+E6IlzWB;3OZZ z8=)18q-<7$SR+=L=bw?&?2yXR&fj7!rp~#tbqAV`0AlNSQBghS74}hK^86&P@BveOK$OjBlgg z=+=(?y>^s!{)_JC+iI`U)3^`$m1@wP;#C?gQWaiQdF^s`B3pVudZ)6cGeIr8TJOwg zdHq^GUkSbXXG2aDP~+e^DJt#!wwoY#mDp#@N;RXb%X5_URw()2H+_DdhBRwS5}1Pgm>d z*VD0^WS{=jK7CbB1IeeSkw+srnKv#clend96h3e&>tQ^dDL-O`4HzeO{t{b0wex6O zSEuSqin-|F8ruFO5Ni-cKEW2;)%uCvOG?-56z*$lj&v@yU*vwm7byy7);vo!-^Y9O z@UMF#dbZPHzw zJIsj{DmWbEkN}9UQ}k0@VgAM)ieY^J!TaId53|$5{&n}0UWe;11e;6gB5Iq(d=BV zRV{ZN1*_3qc8iqYSToh9fA=qdNcB9$)*F4>u57icR#U1k;&;1Ww6j7+woq#cIwO{u zi`&^T@`U1b{+B!35XIko3e=%m<}t_K!bW$U28hlI+_}ItFY~lLwvb!u=Rs^fw_OK? z%a^Du(DY~9n2(c=*^o-O&R?c$5}KAzR)V0Y_%s2E$_%-!(PEox9^zde&DceV zY@S6D545Su#KbmpKLE+AC=h10y-%pckWc+7OK<)*n>evnP4WysbGAq)TDx&jLhdYK zkk+r??e_aPek=cRWj@{hE?+z;&C>2ST1UHvg4nxet;-DcAF&4Vi_I=av>PMPnR%yX zC#_u>E}yh~N4U(~+(DhD6G#oir&lK?p@XcqNRs#BJ#(olXZr#MuN+e*WHDUs^0ydb zf(oSi-pogVCq^F{Nkk51=yxUZbJz>npW8RMC9`#X2lrnclB;6r>Ys9}gx7kd)86-~ ze>j3I{nn4fN6K!a_R~aum<3GMN?<#6f}gPRi8i6O(QKf%gh6b&v%g^Cr0{(2u-E>^Q-pd{)^(u?vCeKksf zb9Vvq*GUBR_XRThN1U%(YvCNTzSZ_dplLjqM-od)En96c{}Qnicb9@+B=NXPUHS7Q z?PXXW;=S6^hEy`Af@td$Rrf5_v3+T^)?C{w#e&2&9jlzCPOKQRW??l zvLi&^+9g8HdYUxM54;(_lEs?gT*?#DvfthSu=ZFPzf^HNrZ33WTByf($CY3s{(!*X z$bv$0hzH7LT&;kV^Ju(0w^)AIADIP7B{}N6&Nf7fg^8KlaZOX+G8X5%Woo&_9xd2 zR3TxT&8fJsg|D2AzL+rcsKv71MpFfay9yeHpP^L}7;>ZCfAC#O{kO%6*9j~VHgiA}DV{m%J>qzzasx7lQzdliyh0;Vpv5BcGR;z5A=L zzS`Dt%(9tpHt?_BI2{?VmYU$UWep7otuPNleIkMI>KsyH2&cwZ`bGw`uE3#eT39l_ zr9nxw?v2zwWQ$w!dDc3BKSS4>tJC=raW$=NRs_CO^Tu)_K=Sx@lb2hey^Gqfp^eJ!8$wjb`pa z+W!E|3hEUMNWU?GrepXeS1cZ9g7d2r^DObh;5wPOpl3oHWgTHTcNTSbox$+q!2}xz zSr8Mvh|^Kk_m&RsSi6kvjvi6f_nvk963*0|)7Xbd%`d0jNJJI^VfF}>0|HH#K!B$8 zfu^xs&B5XpyrF@X^`D1pa`Wo%GZzcjxE3fBgaf>SIfAJ~5`CLq-VQSYjf5oi^A%bz z+=xl5s(nuK!KW6f;+?!-b=}ekiOBKPWM9J>inGw3npbAMg=?;t+H;qE=;KU2C(a76 zvgX9uog=}K#jr84&+98fpOafQc8Y|uT;euqK~=o}YdRZEWJg2+u8u?)#WU?fz#QGV zE1_~g!(4TQ7fuQ^9YP)M${sg4mLtr=H+{OB&&Swxic-1#)g^v=xK7r)5hw4N&H;AJ z6C7dpI09DNbi_F4#0%c=mdR)Yv9`9s&^ zeyei2@RKiMNOS1qS=&d(M+6&p=T3)iV~QiJHlMSd{DZl>bf)49+g=Gg(&22!Ux$~x zfknF9r`LzM*`B*$X>@a#6|qp`_M__05m!a3b!_LdbNbd-ZLfA-Au%RCJBDZe$ar2b z@JM^$k^OXtTjS0nAy0#<*|2o_E2LuP4E3dWs#kSh1^Lg4=M{j+7>1IvH4j_{0_15? zdlhs`U?8y(Rst2h&Qi|?ERwh2ZsY}1{k4vdBV@TIma?t$Qd-Lf0wt`vsVaVw;$7R+ujCJK_tOwTCKn`I6Z3vk zsolF$0?tYFw}m#^Xk@(l0b2fi{doVIc>T$F(kW>F0pj8#ox83UM`Uf}%Vq1B&{N?(AfrN&%=I>60I<-cba$SAa{P79jqI-oq zVXgMmzCv?4ALVn;F7y5Eu6^gKc4DtD@SNTc4~fYky3gs(Gg!E8(H?{2Wa$ z=rh(rc=z!w=o$~|GuI5Gu^HORN?{|_U8@N0_V$gYVUd;|JXZzQoO$G*P@$YqnPTpKi#oJ!LAIAJcY^&{jRsiqzSb9=1QweYA1tXC$L_ zl|VA{z2_-`k1XUZVW6k`Y&oDfs-i2vdS5Qh|kymmuCH|Xw<66N*0c1nMDp&g( z{g>WQ z=YVzk(d= z%mqr+hqGdd>huoBck=JDGf1EX#yxsm4Cp5$hJ4!Y8al`>LoytLcz^Sb>G@w+M! zCU(kE8t2r9B|NaqxrLfM&4I($-Vm$Cr>#c9eQuf51RyyFfz_YGF<^nFnLO9|YYUyF z#G6fh*qw#XNen9^O+g1XmV4~lsvML&yBQ?6amViH`>7MurqW*fZD5wBp6uV(^!|NW z>iZ#k`re-WMqovE_}dXPSS1}UVAAcE7tf;l??J~2nLvS`9D+Wyb zqwX@1f1qo+9-58NdcOG{1@w>|9uzDv$5TMR7V)DwLYD+Qlfh;?aSvpwoTYvSJ@hW} ziuQxpW`;hK6gdTbk4Md(L+3p+QBOEOPJHk+b!YlR;X}c!hSPo;XxeCdmBY()W*I5R zb%Y%J0KYv64bheP?{hEztksLgw!sqN!*XEt$z%m@(nRArPASjJBYk=vsnZGeOQC~~ z{?en0C3&g5vST`-i(^-#6P1s+x&Czgt-@1dR$)qcqiS(|wda~od7t-^u%dVAHP^+k zj%RjxqOtNN8~M_CIhgv@vc_*bL4lMf4r2}q`D>*b8538n;5*!h9twLN6X4@D8Nw5n|21VcBsFr zkiTTyN(_sEB>H4mRo_br$)RI~dgDrh1BRPNe@1L@IcraS3Be?mja~U1YG9<1@*Ky9 z)e5pDv<{^FpNdc4iEwf`)XQgH690bx>i9MEGw~lfCm|SX<1f3~-UORaD+Hmp34Hl{ z=z8smts*2-d22f3d41*M=(;2l58-B6njat5m(b928OLl{d0(n3=_}iFZG^zIs|Y-) zlp3y?iX2Jd;dRBu(ZB2bYrPpHyU4(i{qfeMZNI5@Rxj7-nS<>SRGq9DB}P~pCF3a$ zaph@#`G;{rF8ZWhyY{l)@MOgW(1dA?e)BdJ3+CtayctrU^}u2Y$ZhqiV8l8f{Y zSAQViQ0qN&YY6kQNr%V}{gh~MJ~_?Rc_d?Qwgb1?;W$QT>;g0G@7_>uJ#M?!=gB^F zB}Gb9Te-S*AZ0dA)!h9s^P^P=cAHnYXUuweNr&^gKe|cZBW2Kfp{bxlPH6ci|I9ne z?PDME`(AycaXw$&6nJ86jt-e9*AWcsIAr1_yPbq?(m5hqUHRmmzn~t_TmO)>(`3YP zBJXs~8`&`8yNp}~EZ9%UpWk8AR=ZB=;92LnxfIEPt^=!b%oBDrPP4N_@GX@2>{i$B)9Qk99p+C9dW^?xh#%6}9q}*q zVSHMfrZ*4qK`CIU9^1^xF0f{c_$^EUz18ev`xjfM0 zz(y4v%?cZ-y(9LrWP-gsUc<#Y6WtsisG}#C0avp%Lsq$W*+HB}kY_{HUAHf*JN5!V3mBcGlGRG}Z#c>XK zoX6GN3b3@goY+*A{@gEhbFEl}sX#%h?Um00G{>Clzv4e^(1&GyY37Fu?1$q09CH}2 zpiGKvo-(<@?D(r44d|8VBz7%lnH?#pYzjQP@^4ztR-Q9eAw8~!5{6HGvDC+Ju_w*O zyWl?__=*OH0^Bt)HivSb?_z7#4OpWDpMGviE=RwwWdnC?HSn2At=r=3l(IHLmrO5k z12%=J0yXhB?u>ru4*MO+&O;jGmeGfCS-NnuTV zAZJCYD1LX1y|_arzGRlFICrR?ED`n+l(p*=csH=l^4=u9?re}5a|9*u26Qn60JR)x zsct6Dm&7IyH3{*sSK7^qO8KXptPgAwfOo`#@g>5*yuy848h7Vn(NEJb_^K(@PBC$I zVK#QfZA&>ws(27T=&FAVW>-JK%)BKEJ`M#Vi-%lsb9XXKG2rnSxtBQg(TJMMY83 zs)~^ohoQoub;vc*`YF-+B5;VbTsryc6N@HJof27e>D6@;>&9PxX=L$r^_PyPoQlv_ zrXac_!H6@ua23N<+i%m>3pYV78U^OU+crwb3-zkSLSCp>EwWE}P}QtQLOl!G?G+_z z5E!2*j8DqxtYYSKXDqv%aPd#!IcIt2TxL|{ZN#T{8T1av`|VmVn6xvfG>>@{KTF89 z4yn6>_FP?STRU<5RhQOZd&ShqqVZQmyO*pGim(p%wnp=SAQ7R?@a zp7m0-?i|G;?5nRSyn3T~dY)QQG-Tq``iWQ9S+20S7hQXG)#6J}cG=swvwnE?*_C4ENNXkUUVG`)*F{<`zvkMjit4VuG_vUAYp=evXh`j($l{5$KO0~F zizySUp5!&IMd7N&=Z1=gTsx7DTQqh2Eu(=_V_6!0N+ZQb zlGAY7;V>YBUG^yPHDB~X4=q2s^w30YY2wo3>GhxCv+Gy;cgvUzIB4_tKSGC|+WbWkicFc-V>VzQ{FT0OEAMOr+vof}!?k!|YUm=>NDUE$qvMWw4Me$s=D9DGV5o!jZ*E3O{Kn3?o)8h7~O%RxN@REhEB(z?rIks{kGXK-^bT1C$9snFK+n zh@jW@AZXoXE>`X1PXV$9g>bf5CpWaAv%N- zHx0=#zq`UcC9bJBLK)09hKv49AE%`uH9jNcD^$L@ek8uB7B$ptJx<(J|7N7t{ZOk` zswX6WPyD-$ZmC>9_^SwEn=@C-7@MOl$}w_bwev+r-JA%MR`*>!>b`9cbuTp|sGAz1 zEfM-vc(*VM>^2XKk>vj1TOu-^v*F7hjS=<$RCIy7n^k{tPaA9rlmn;;}={zX`6(((rGBi!W9e z-;ZdMqvsbb%FpJ>T1>Px-%bioogy^-_z0elhO!~`-%yW8I9EGg*_?*04}+Rnv&Am= z!R&grNF$6FTF)jp*dzv07l{^|#$941u9%3dqp{87=wF!4NFrF_;$?Pokeq zd`V_&*B3Kg`%{4{`t80|_HP3yv`D;%@x16e;NkJOFYZfyai2K>C>x07&tU0SJ!gU6 zenVYwS8+Ya_;6{nfDv13!7chLq|<&sR?&z9@{kh4?*+0I_fxU}JszM+YAK)yn?TdY zKXzxEDLt|90eZNMq}`mSWf^ea+HbK~mj#Qt1Kg%h?g`WbR&9x_R;%?sCU&gvOVfk9 zd(wL_K+}ZWYZqk={Pu+)Q?kH63i#a^PY{dKASM~{N?`5_ z^^;fy=VpO8|0p0nWZMMq#jaskGmZt2{mZfQE|TGUza5?A<`2YJv9M@Xxn> zwtLZvKWoNmU;ICK;iZX4C2YC%ChK&+`Zsu;7(qF$b|%|)A$p?4c7e9>vVRVN0QWZ){&*jj~@xE14Wo(IqKH@X0ePM_?G%3xtmPxhP&WY;*+N`?7anqJx~0=DBn@({rO-zT1YZ-$4( z6b}o*^Yylm4@>V5Dy%oZKR=^W=6aoCuW6X|&)^b^*#X6wr14oHr9zymohl5}BL5~U zUtW@dlsPyPp*bEx_L_!Jei}mQ1LaV#>UE$TC6tBG*FDU#BJ^xQic8WU=A}XO=C5Nc zu+%{5NdmtlWkxUX`h{*u_REjcAi|e9d*{nR-H2cAwXC$vyD2%-yD9Q-g6p#I<)%Y@ zzLbt@etvO^8`7GdMQ;DVGoBS4x@Xo*TJOG?3g-XE)oJ8B_F4173`Ceilo!jq@#7x& z_!^XJIZKT_^RJpcQ=`MDd5RJJl2k8*p^l~yh5Gs^y!7=9T1@N-yZa1lq2iBpaY2*1 z%p-ahk=c_BKlgA*C&OrPAW&oF^fP2}iw1r=o+{@x#pEOgEM+rtF$TIKr>h!Qu%x*> z-xS>`yZeLaTe%O}ul&h4trK^lou!CpJwXXDP&y50*NgtwlXCgFJ*C@k4q?PBEEa^; z+o{v+n1p(e^2HpLrlF=`l!dMSC<01@P|MT$)b~rJ98^8&Im^Q=ot`;h<|5L;rb;TF zPsQd}H9gp>d)Io7nM17E;zqUqU-4=4@DXI6$EE~*e1s+VGzp)bY3kFS>GQ$k;`Jtb zwCw*CpTa(F&!y96Q=l6@TEsV3?lV49tpBd5c>90RU)k^(-5npL_cE`hDNlQ*&ti{% z%wF;FrBRW86O3e`Pus!W=<})QbIv~FBaealYu$f=Pd56LcE{&!;j=hRv)VI#)_C-h z?)?7;|I9ter;j(jg6gk9`;5<8i;v`wv$EG|+wY-NSIzOdDt%}jCRBj#8cfh!S(i-f zIjNye*#gfpvDZD5>OVee{|CG}JiLU4Kjf$NPshugl!?%M4$AM2=dlFKz4!JA+zX!_e=`gL1Xtsik^MboP`ui_fL@`9im9$IdMHx zsMZ4ezp0XwJQ6VQlhX2sKujY+PGtrOrg|i>*K~x^Y_oK3i0+95$!X=-(Voq`Jqrn1 z_Dhif8DaLy4X%usxhKfJlRY(3+xqq7hHxh2xAzh9>@_wr8Q#ibg(TbTqY$jwuP5ZE z`(?EGwS9zq-~SEr+$@ksXF}ezkC1=8Cu;X>b2j(b%Xt}XUbl~sANcp@JPL=OOB zn8j;>;Aqr9?67lKSdymUE++l;bfP4zdq(QGwEGIkVy??ny_)rmDNoP#qL5pCqa0he zS5oyH{}*Iort@~ER<6@X^=ulcJbmLj+b>BnWSQ!c^zv_#&fauVZT!mjR9RzaN}9@* zhCmii)!<*cmVKM0V9NX0lWl$YMbo^_4X*b3EZrEoK!_x}h%T}C}`LSIYq^LVBgA_#`DeScuQg}wn@Arz(!+HZb zP~_hPw`M`;*i3}}Ri1%Rp@)#Y?ir!By(09IkI?hQE@r`^uk~b>JHN=F(8x@LN<4(@ zwHJianPojNdle{`&UEL1qPIQFf}64+lmkL(%(7yy%wpj$`fN{-eI6GY0YLXG zrFJcR7E7lhJB!ngL+H@^5zxkm@_dUrkT^KGfVNrU*1`Y6+sue8ASX=?T5 zX7D@@V*1qD1jMvHIpvg$KH2U$KJ7IPp)6DF$je%^Q}1 z&{hv2d)+faQ}!L9U+7i(BDgvWLYHMCbZ90*#zV+n_l(eHwSSLXdqa~aE{AL3RtPQV z-;+sR_$-4$H-9&SLYq8{9!I6y#5?aC>!6YwruPK&}BY95s)&Dol3F=^6IQ z&e9A%T<7tjz4pR~o;Ys>wLK4vhrRKT3R2mc1;6HxGX};LnFw`w2-#~d2&E5<_7uT- znhVt*lRZxWA$8SUDCQ3k4{|qg{x5)ai+1e^G&#%qH^B)W&~%CZkB=5uUc?fqFwg@)E|+-*;#;|4$v@(@dO~!p^L4Ln&45@K z=*d`Xw`6VOO&JjF?uF0(i#AU3Af|KGI3T9!2?q_y80>A{*s|9&qG!<)@=NwM*nPt? zHP~loA;B{rW*~GE8@zpflU?p1WUsv-ls?$M30A$%f(6IAlV8!6P2RL@vLJLC2>BSK zLA<|bpA50UQe5B<=RL{e(qK<6Sp7j(h;uR^+A;RM{{rHqED$fq4)Ly@5Jz@{xCg=F zH$ONh3&giKXKmx`o)FLfFCdm4(vzy!0x^x#j~kT1Sj`?|*=t%ir*nEbW7S!#B(<`5 zzkb0(E71I#U`-Z;-so~?k*Tz~8-t}psU7UMQs2JMB1tLguR5fU_sIb522ApMTu-{+ zz}&p&__UZmd*9==H#jRxGk3lZ#Dx|@>r}ol7mdt{LQPK;X6+S){a1O4>`X=T(;LC5 zUVLNv((Vl|3WCt;2!)qJSy331hJxl)JI3zegVdPr$?rb7i;`4m&Vs_Hot6rM(0Z>> zI3Euv7^rvoXF)VSoewUd$c^hB3Qt3qJI-you!K|1Uadkg4X&Q zDm8aUdJrfByrs-M+dWFk)msGPqr4GehM%qGX!f%O>ZY7^NH+h}3(4w+W-Q=@OaBCJ6M!6^mLhIu~;h{6Lq7dnc!qUB>u$DJ06$(AB4VJF! zxxwh^_be3zp>>&17zhe!oO0#2GdN|I$0_#Oi{SDW3SSWXJ+e!3ivG6e;0tE+G?jp1 z8bYrWrx5A|0j+X~2V6vm)qTq&MHbg%05K1 z(6IBCv=>W;!g<1qS6aJ7&c&4(*dLvSJyknecAp}7gTy4rS8*$&U8I73YHNswd zX@tkn&3l!9$wnkM9b{wZ3*UyS$t5{s2B#3}6#=`Bdw~~$TgYs)=aJPjV%m6uIDH*z z?OW;HOOI-&znOYW3LnZQc?7c8Uh(^Xw0#R;RK?Z*MWM#{NL0{RA6zwQ1Co$LRNl=( z0=qQ{F$s#LHf)j&SxI(db{B$Lz>-+ED@d!h+SXPrt<+j;zf%7szy?$vzWO1)pV(^a zT?Ij~g3tVazcX`p??M3kegA)2*?Z^Cnn6k7F}2B;1% zcWn&W%#`gO03a^_vQ=Sd6=j^#57V+U0QIT?TDEn-eET8g%D8!emfzix)^h1rY}q$J z%eFq6pIjueAF|gB&~jUP%M-t1%b_E+Y%5f$KIaTQl>GbNOzU(0S8Vx)BeiT>n5mY3 zfb0j4goTcl4@2LivVSYeA7(yGZ!D>o{B(d8k3)+N1!>J$X{6z(`7$206_EKNFo0)E&e}7!COX#@uBQ_ORL^c7 zfbXuy@mr3Ti@svZFaBpO-!nkVgVI|b^%YxA{AVq19iZhO;)pFrpL37ea?fXI^vFW~ zP;BoRpyiX$a%#($^(%*JcNo6Y^85rYL_xVJJ*p;^VwET3X#i965C2L*cWh^C|d(0zefgW#Zdw3(nrae_CxkS z0967Y(vD5`{TP*6u`y{N?mRUO#0(9h{2m#^dkzB8)?8D&itXbQ%-=FAC-kD6L)q(r z=hFb1oeq$7isCi-Jq$n&e(!kzP5lQVodWM*{qjrz-14uVOKbUa1~wh0&)QG=)Imh}DlK;oK!iNDj7{fgvF~ZrX?2ZEqspf2 zG&V6bo5=5BA#CQsfYT2;P~cEDNlrTU7|UKY0EA1orvWr39iTm$P2~4506E#@Hb8Y) zHu>OJ+Wvim*d^au0|2!5S>@(qlX2#>vY!_>U-#osj#Ijd70pV+-2n}%{C)*cgGT~2 zi97ot+dT77zM3we{xX+M#!I2S@C??U&roNk4aXtfeeGz(YA;g4g4y~`dk87tLyBW4 zymfSjeET4VJe1rvi>9=j>H$E$eH+LvEMr2#y%Nr3E!?2#HErzY|PIm2{y zE?bmoxa#X^Y<4~%v}pzXc$)@Leh-7PbOVZ#LE|D3KcvhzO!G8}+7q|dbD)1}W_dT{giFsze4 zwig1zuPl8w3^29_13u~^Y*D070K0@85U$KflRjHDfbx5E>C-a@v(3?&JL&#?Z1tgP zTf>uta9u8&j5DXTRyVM<+jGZ)U`xhhsq&)Z(a35!L6Za=`VF*!Q-^pY4No1qnZMB&m#P#T z_d9W;wZ@GZI8{gFe8|o)VC6bz0M${JZj*8^;qYoJslc;i2wTi%i#Xo3cRhLS`-a@o zVO31P=cpXo?w^KBoe%Vfy-*mC?>ptZEJIxn1bqUxR9vGVs6N9I*KAA#*x~(>T z8CrCp;8B!Exjm?f8cBv~Ao6RzTm&$9HI{qnri`))>!d4L-Ey;SS1u3MVZZJoc5pT% zu~fY4{RycC6~^OdE(YJnPII)m5e+UzgE;VshdoVrP$~=8@CLEqMFMza4PJ0*=OF8Q zDj~c*Rk7*`OUsGPq;KlP=6|6Fy2i*uz&{V%>E5vDid1n07Y?7Qh^3l=?3JaoMmS}>WSG6Tm=fGH4xGb zuqHHci&TkAq}egv(91JuaBa_`t5bbQYeEjcK@e+=Eg_)~(AkSomY!7<9}ybwWzkt@q)gZ(JpeQf1MPtr=ze$+);TG@PI6 zu4bi{blxQ&T{?Alzg_?G+fbD&x-;=ToTCjiKFopqL{|6g`*8ycPaPFuY29!vN7uUC z49+l6)8^m{?wkmp8s`*lJ+noLtT#sz`|8YP>mIOc?;m5Ywczg6W$SY1K)~&PFZyBe zhK-*L-}vc?BcAkc&&GHk@ghd!t2}Y}*Hi4{PI)|)m4P<((f6CI*M>u{y(fWT5ykM^ zjb2=f+^(fx4$4~oTpo{R{%k#9BA(r`>ocs`Gzz*mtYKPNR{2|c+?0*`cVtI-_d8i# zzmh^v(ib;}6Gu1A|>ZT-o2B z$iW@4xH%yQ6A3AA9h19{r1s!)SDe1@j!tj4hX3pf+^M#Pd!IpZTsw9{4cS_4$7T5W z@}>9!8Wiv19l*ji){|J-=7hEZpGXR1m(A0-D=;<@S0CnFmA?kFZklu7*MKHMlbB<{Y@AfXa>;I;1xoPB5g z_ribogVVRZ{1HY->V)O4U;PgBT?_hRl#tCq=Ipou2rHL0XD{7#jP(tXuwmYuksUvY zpbwRltnT+NrE`_rYb428C?%1)o!P!_^)@=-W|2clzS;O*KUH9c+ zI`5_yGwA)^m^>WYU4++TyT{;PX1RAb;n;0`vWIY~`elYGMh1Ob3nr-x@FwSY%J0IA zCEvo8oIir6!Fm{%2>^_&uJ7TEB4mYRxh}){sr_Z>x#@+iQ3ojS%W~%=J|-F(m1f1l zL_->dcqa$w7Mp2UlP5sReh*j5#XlB?+hGmeK%#_)#lO@E$4Ww0_dPTOfMrfcpz19@ zAqzg1_^S{PY64r0-Ed}xRnx1;I!ms_RAf!vY7VkySTBvoOdZ{v7^|~v0RMW{jc)SI zA03Fa;{HC&lNqf>;wi8*M$@VX?a{RL>oS_=VnC?T^a5O!G<4>mc^bg6hcvzRaMuc2{R@WR@z}E7QHFaz@ zMGiJ;T@1D)Xq4r>Cm}^mkn_=kCsv2AoLIAh zivMb zV2Ab3UHkeIP1FuD0E)Vlr}z^{F(@LPkXr8OM!J;R@dz0Z#nt4OXE1>hjd>_z-BA|+ zR(rqjU9L~yjyI&6c+Yo7pLEBLDT`&xDJPrZlaZT)AI(_$<<}zrECaS#8!n;85&Tdc zIFGYh&g0!X@PN*;eMUr%TC#C%n|+;h0M<^3YiELR$QMw>CeB1+QVA_;=v7>nZm1jSq zk;dYYjds=Gi!9y(jp|5#>+$h8pg(#nO~j;{@V3pY;bRo=rAgq2Dd4-mgD+%D)ZP8W zA`kSM*W9s++&Q+c5`P3dK#*b+F@8X!7{(wOc>_vR#0J0Oj%7f`U<6vPULv-nfVq~a zT9It+{GMabTfYSB`@z< ze}r0q`(45tqx`N;Z_jRN^NWbLf51A3hVcH37nKk{fx5c zgDM5?hjZ|Cj{Z7$+_vwZL@NsK`o6HGn@O~s@^SmKZmknN_?FyGVgkj8r-LQQFADZh zAcL7#qZ0CR1fG=GWkpLr!DRCkrY!(E%c{Hgfa6wU1MyrJ--gT}r2zLy zfB1x0ZT`4tvu<%?HbV8>V8+Sm447mb(mz-UQy@0!g!@OLh3Z*=!MG2h5{nze*WlYCbVp3@q2 z?1q=+Wdq7q#L8Z_Id9IG6zBCMZiE7-r0Z`G%4)@CLHq;doxoCJ=d+^RQAZ@{Io}?- zL@JTX?|r4XdfBFs48(cX1%;#yDf zb?JL}-Okt7PsHo?1YS4u^%=g7=W8!t<9xl(!s|nP{S#j^@yZssFw{2*quAx(5a0a_|FgfP3f> zCHOv&*&~(tCS;D)V#MGM;T=@xW?8r0xK~|c29=T*4?p%UW=qufFbEXC?HXXii^__( zb4dOK)xiObdxap4}G55MU-5iGm<^A(>=@Lqt4@a zK8A@@4Or$LevIC<^?Yb5&y`>>!`-BX%NYVW?q-v$w+p|(DJ5f^zSFb!Q+a{k3;9t+ z(O^!nm{C825OKwB$So2Dz5+Q)(Fpycjs4a)Kimh&iI2y4qSMUqaB+X*8aHdvUj<*? zKLjM@vDVxo-XwPpOmveS-7=USI0M()yO%yX*fp*qw`lSE@EihM22WEKejntgMIS3I zaz&@*S9b5B-IUK__zRy<5nU;7mC>D$O}|7MPe`Nw?Sl9zDt@ha7u=JhqHp%rLjX`C zeC^{8siaGXv&t>ZbgpsVMZ>T2>Yt~fo}=|utOu=6gg`};;TBh{ya@HoQuFC8(xfL= zJ~noFkvn$nSeb4xrRG?Z;5DX?`aE~zR#JqJx??NmU|ROz!e;!qV}o%%_TVSAUf>$n zRA^dL~J|gz-Yq?Uqp3pb#4*q zs+|n(ZhL0<3{(d+dr*=*Xd)Ac9=)j(E6&!L^Wh~y(Hx|LpEh9n2IbdK|NUu^Fb{W) z5Fg{ku7NE<{#v$ZtTi9sS#*{p#0$_rs{v`ASX?F}y%7{SIL4ws+=ICXaB$;f^oJj* zmpXabi5KgesiLfvBHn%D7BRI?RG(hv6bJ5?j$p2L)>`4LmD}B-Ka^UZ9W4N{C~IBf zsPz$iLUqI_@zRb@z{*Fe5$-L5R)YjfC5%A=-gc_DBK5WhZ{ev*xxDqi6uUo5^^`GEFMF;0v>u=qI>*+Upmd4uwEe0?~^PK>We=N#+tgU}gX#5>m5c=I!aLCzRT6Cr> z_E0-K-QBw)C)>4Tb^R9TAa)22pfQO5ZZdca7+h;d7a?4scmq@wUXo<=sur-k`(rM$wPF6O~ zJ3>2*zUz>X>hda#MPeoXE1o(K>zrks@~}c%B{wZvxHB4~kXW|daFy=Mx@ySE2(<3G z&CSjDz`0>x)~G%EKZx!D080SC#skBn&%%Xo48O|Q_{lLNu)^SqF7F~}520hEGC)E9 zZ$T2?-coNjtGB1s+sYG#W_SGbK!5ytLI(d{=bsc{twia%+{cmgm^Ba;Mpk8)yrIrJ z!Q`lO4Ze|(*$S(xP#Zq}QhnT@nz#pV`?5xM<*vi~K3CQ$H{H$=^4^7NG~}zID+%|D zNJFh#b*)>~;CTzukhL<$YUBW!$Wr7#ir9F8j8>~>6f0bpy9#OWC|kv!e-6!a6YAq# zQ?X?%6YYK);~S>dDaWW^Y%rOhv|}so~+$3 zE0k2D2hbt@%ha%R4I&GFpTStuEsnb}zZxF5LhyEy(?D}soAAq1( zLGQZ8@D&$Ov8S_v4|>n;!8dx(x?g}HPj^UI5^#Us82C$gps5l{z{CZTaEn;)V&3OL zMFcu;VfD~Gp1DX`>r}0En|S3SGL+~Rj$&vGbPkM_`k%nkHKr0e2e?;6&X|cnj-a}U z7@C=Kg(Lb6_4QZ}3cxph2Uz6Tr#jL3hWB5l#98 zM_?W9my&z&E1qRHk@ws^?H#_xU|V~{-5chW^|-L!6J5?vkOL%zw>1F10!vkAY$?s= zW%kh3hx(MhQw_zUeXOdj-;4W>pdC_iVe;bjuGsV(R(~7bK<7GE3>V2| zv9fZ4dkN>7rN}U7Us=|u4Ka6_-HTXVZe4t=DITxg`Mdk2Xso>qwEUJ* z<4WD0SXGW%i_~2woQ*?)MAulrI@lc>x(yT1!;a$PK3Kd7<}&WJ@3%_(sh@4~#HP1n zw7H|@?bf81K7{%V1yM6&_nZt+4$Lygv!<~%5(;};7eFznt3XeeAmCv$)HnQy)yj7+ zB(`HX#D572fTU=>CQpeWiY8i>^7#+=jBlp{G8&*vV^LN?oPJ>CzUXlOC3D;^Ik-^u z2q~Ne12Cy9LSFR0tw_VBlshsn7vgbQSuQW9f}%V>&r|aJtKGk?W!` zYjwSw#r{GE0DY{{_fToBc0SV5F>FP-$Q zLM#f=jg)~=$CZ2bFRQB^PL#NWhQrbE{36xSVGpoy?T!_ z4D(T$od`8CtLxHt`upY7fI>W2Z)0(+c*BasX|Pz`v5QyUG1BO}eFyfW@Hr;LbEe%8bbdD?>1JcfpUq{I*iteFIb=CZvaVoCdiCPUs>J zLcq+yFLcVR<#%A>Bdd`0;O-r&%{2IHnKi5H6Zt;D8f=Qo_bpOv4YYS@`*^XBj*YjX zJ6Z9uR?8!F?S*b>be&ykE-T|Nv7 zyVh60Fd`GH9f^-K5o6-%H|W4e2NU-KG0iK;%P(2Y6LgUb;ZB7utSeU8=~oMYD!fcq z72u=*zfY{iQWyC?xlW~nQyAxTP>|ElP0;G@SKxNqK5lRLcz0~j79!ce>VkXe#*C$( zel7BD;v1Oht4iYzq-~uNhYLLks9sPz2vCHe`~!mGgW;I!l*jXgmnc_uTl?O`ipOWK z!C~|ynzvT3RHNtLsGI{YgKXJbT{EMu+*1YUVCE=4xM;mrw`32Wo=lwwN?Somjht*( zu*E2=a-lk1@@DAE)@7>X*ORFsmb_RuzfzoMs`)KO4N50|%%o&DH9ZarbYrkkCi%It=CKMDOI zKr0B)0jje5PUYP9Ce{Kmcdtcm!`hHVSNs-h>>ZTww@79d+KNJ$GkY&bb@2vj>@S|g z!re5Y5~qt}e1f(2EG4&J!^F5$7L^AjD*q1lzUu_V-d#VJL8S(pby9Nit~LB`gOn=#)uzU+>bmnzlE9ZgUVqoQj4-ylkd>M(Slm%%lw$u)0by*Fif7M?)!Nen~4Me{UX1d~x4l{6ZE zN^{a$$fBD+?C)R8(6WT}s>C>mQV%)(4Vls|?pi+5aIN8LS??OmCNhnn*?%4fXYaAh z0^)5Q&9$({5+>i1oUR76XMJURN3g+L-<}dbgE6Y};r52cZ6rp%MOM_4O$*8Y5XN(A zve|bQpga*Xb~2MpnZHfT^fzXDMr7rr?aOS4KDNa|3cAmgrvTTv~OA=4X2t?cpIv`sc7^3E3^b^Qy9oJ7QK|-Hk40#axL{mU~ zrqiL!uFE|DnQfhNyynA%%wZ}OrH{X0Km03;;FWyL+V%8a372?X)VQf*E23YZIydXE zP)D364_m8#tp@)nWKz-?pWnjg=pE0aD{&qIY%SH99*5UrOZUr2r@lv<3Jk*tm5%4PIM}FI?x#)*2BXm~0bRST9rt_z?Rur;A;Mb3!0bWBirD%C#3Cvv zC5>Bf!+m9Ue??Z=7uF}gQs7>Se3;p{B41_n|17}|7w3P3Usx8fVKCx1;3Zxuqu}fW zS#Rdowb*(PW5lJ_;xO3j_!dvz9)& z-(KiXRk)f!P~7x_L^`IRj+*)|Fd%6Px85;Xw@!vzgeEn+f(Qe9o!4HRQ=w;&Shnzz zur#s3PJET)8n(?K>r}9VUWT^S*vQ&)>G1h%|3tGFD?7=Lt zbaBoxS<54Mj5h(OKGNFS^A9TP*`nY>d2ilwOyHW$Q=qs;AGIED`~=@reO!7JnOqOC z8t=M>t5Xc2vPPeeOc2QT->L*M8@KyJfy}J&cH*Zzg92G;=!p+@b2JZ(_7k7j-=DY$ z6PE2RWPOZ{u^u=RW4!i7eu3&6yLfMOq+xaEFjz5B^%9engILXUD}SkaKSp%f)#5sa z8kO&Y3BzYrbT; z8i?6pz48K9FaQks#2tMFxQZ9O!o4}xab!C1*&KwyV$8g2Ro$90=%5nyU5(1D%THH9 zUU%uxk3s0DidS$0I8<}<`&bYJN^rixpCQiznBzs%d~CgW_Q(B+f6LOG=F{_#O<8am zfWaz9*U>Xsh(XW(g0GBxS%F{nY_2<|`Y`OUeVB?G()y6uIY1wl4U;}(b(IX}xJ-rV zv*qx&WdDGuQ=k8wbc+0tI{hjjEKYTbSiBxs5T)IZ?rk}?Bj7FBJaw><_zqsl&_=Csc&Ng8&fbDKcI2Br;tL z;|{Wn3n>mS)9!Z|X|_(1;m|4CQd$J?Mf@$lU1pJA=H{RXWO}R$4xx**H4<~-L-u}c;jC~bFI!I%-YdZ#$ zO8P)*k}&MpF=`g-{__j8M-m?)lNhKZN|lE2GMEkVmq7$3j#G)ki zky$X8F!XraeVt*mq=?W5g1}#+yAR*I?ZI}RJKByujzw32lpSzs=4>f7Tg;1!P-QN9 zeGaSBGyt1t!1pOZ_3ZJ+Jj&eecem|i!jl{lf z!m`=%(a9@xLXxD*hKCA`r}XWB#(X0QZTHgmoq8?YJ&m@;$6Hx#j<| zCEu6_A^Cpu8JnO}70W9>LSgW0j~?#S60LYYCMLQgw`HiANm5_Nj)25DFdd;DBzAG+ zLwll{11HgAuok$wgFq-cn5jKe8A5CQa0_#>g?|{GEP&BTO*(O-$bw0;mLf(kL-}0F z{{0a{re;Y7+aiHdM}?p%ZUFS=PX(l%(=ursYlzMl0+Rwt&$fi_`dt2z3{>bqUfZ4 z5krv7g;;+`;4kAbT>BELS$rh zkApdx$bp^Pynf$(RaJF8Fa$Wm0)zx70Bfr-EeYWoJF#zV+dizy#U%}{ zbbON7vMVvABHT33-MGyYljJRfX=EA8rgB3Syq!`_*78D`d+TyL`)*M7WNgfwxhAN9ZgQ|K^uz{h^; zz863bu*5declYby3+oSh4QB~w``DU%%y(SFsoVW;AQ9VypfK{2w!Wwpbhp_$5>sW2cPtFTsMdwEh}Di!`p4+>ERBqzQ7)^Pw$!;=`oybgDN;&RZXBAV#E z1gKNuc`Ll`)&vY`MJEWz`L`*O&pnQc>yZ0%E(8rWERy&PcWlV7@eYi~KZGh5eHGpp zP*ZL1g*G=cY#CQv8iKSP_T-G z)Sg&4cdRFN!w~2_zff@>Ckr=CGc_w=zGhtgxOqj3ANRx_At4m}&z#7WVg$SZlU-yw z{Bh}P`BU&-ae3nX92HNfW_$$4V0k2K`QIQEz;$LBf=GbC@ZV*rMbke1FAQ<;*DQ4R zi!4Otsj3IPzcx;FoP-R#11v<~lpxzsR@r)FQk(Wso8JF9-3wZqzHJ|~Yr850y9)kc zg}FcN<(FX_7a@Xh91Jzom(~4qBw^Qpw`Xnp@Vne1LC(B zVE}L25HDg-XwfA~kdC0V!Osu``13HWZ!F&4HxzxdW}u*ov9eZvgO8gMufo3|VTl+u zsEF&dJwN$^>*yW zXL#IV1@)(y(ulHg8w=C+1Wh z?rUgJ{IaIOJuz?2|GYnO~hhX3LTUY&&ZlFzxGtiE;llu`kEV@yMV2K;{ zCT`6VFLL!Z3?bRwd>@Q5X8f1*>`30SRi7rsP-2bbhEUWpe5~~yRZsU8uq7p`$Z$wh zxREHb-4x-QpQH$XC{2XJS${in_`>BtcsX}l zr}hGHo#+_$?&y1Qi!6Q2CyqfsQj~{O40rd$?dYlp|EL)EXRgD1cC*^maTS&r5{*ye zQ&K$``8Q^qfbnfzhFye;bxb6}3Zs^S-3O;Qw@BRjEphsvG#}OWP5~*^M6!X#@?Ma_ z9Xn|@KTS-2$~YIFUQ(Y*(@VMeX`T9%$4@26QY-lBUiB$6{nJ){x(S~cn!re2`ap`g z>JQe&D<<)m7mmcFq!)~bzGB^p+*(`u{u$YNrzYEU--jVxfUL@-e(hdh zs~XB7X&_3`ZB&ZtZc&W+Ih|Qlh&~4QSiky-XhVrzAFHu}FQRKe#rVzdg@2R|63(54 zbn8}0+mxu>i9!1AN@YHM8dEiII3R*`0_b7=4Ga?992;`(DHo!(-O;@pKOK$;l<3Cj zo_If)VgDzXm5;|q*$&`}KHtmOWb1wub3vPg%{k=#>oA5T02 z+sJ3OcX-wX!#;n&^tQU!!}@CT1;QcET62Lv+%nz_dwR7sV|scfE(}IGU=VuNOon0D z?rZeB8=s^^=<~KJJq@is(^XMb58U3$gf$hO zs`C1Z@+x=V^g6eh?`>^`joBRRfaMj^eUlzth1~AmsV&~XT%QRzZ0O+^Z}zwP5Coot zo_I40+EdW$ER#~u1J!}zQ6>&qu%TDj1O=kmFui7tFo1SilaqX%v0<;DjK*U_-oTHC z5ig-o5Oi4+G@E_l#un4vM{Jp)aECh{X$(h@!F0lYH;ebU#Ii0i-MzsMvkhjS>5hT~ zogjf~sU4kYhoLYBB=9Q(7Fk;IVQ6M})`f$nue047fcvC1Py&QbXRYg-gi>Y*;7w+N zVu#q^tuSRHVH&Xh=&-Z#r6P)|QPEo8wGm&Skr;Es*e=cS^rrgWi3Z#AJv|B_ZzE_4 zLw0N<$b!%g#jkb1&%}iQVDm|6kL=Un1CIlM^-PE_@R^O?fZ3D+B|7XE{E}=ZMLpHd zMNKK{>3)O4v(WKu3=I?UMGgMIX1I-F!)jR3dN?nn7iiOi1Q^x8xHr(`z`DC9XwHVU zzu@ZVuyc?{y8=ADppwwYc5QfiQr&My_ucuPH43b@M%Ct!6pZn+Kr~TR5jYvrZ{k{FXUctBV%*vc=Y`WRPI@8;{$M1GNIQ8 zW`>(3;DqBs!qKBYcoCcBpYJoZfo#Df&)5CNM@M*^menSzK%`I8)b(P0nZ9a}}w zSqxorYkh~W8J)$5tIlz+F9<>!cho~h5!t2rp0#r^y2BkDaX@{veXOT9T;JRggo_T{ z$Am!oqfSpxQv>@N;efAX!Wy4R{I@r``x?v+kjL+H$6c+hO5Qs_I)fng*e$zz=W4K$ zQV7&uuwX$UhMp~j6#o?l(Q`^~+{1ObN@P;oPA@bt8V+gdU8kla@@VNEM$ z%wSUlemQVH24QQ^*=#YJ?P&!|Kqk$1_bON+k8L7%_?m#QFdDXr+{Efz&7e)>j=7$A zN0YCE7!)E8c|C(&9QFo(8n=o&dgznUA)D}C5k21>y+#w6g0&+0o$M`Ba+&~vXKj-| zFqeIA-ZJIv5V~|5YgkWV)du3U%(KUCeU4XZ^tBI ze|Sx26@f@&0YoX9b|)Dm(&#g(xThFoGz2XBlA5M4M>H7Cz}-tiki6(1B!xRW-U2rZNQF^?d8u!%840v|8|OigV3f3s^~7OA zDE6RVwmQeNu2pB*Tv}?xhMX?|03I0+py8PUfTH0<&~Ommq04Rm`~zrbAAJqb#D@GE zKc2M(VShU?(h4s#C>R3TAvRS#5H}RMoISHHXzK&Ki1a6@(*;oio`HyFn zjJI9}K3J@5fm7jnbu6XC>E?%{->|M;n_Nm+j|CAgmPtCTIiG&e z4_yE#pViPB^sEU*+Ab++gI+V}Wj$*G2w6(G1UcPGMKb4w-EqCl(n;5UpI(`v<^<4X zy#OA4tX~*(!+iD$iuM+uy#VF}wN@aMYR~Y*^=gUFdI7mSYncO!C5FnSBxkj-A*WhSnh*qN}3kx@{L&zby83_^{}U~dxVts$wk zRk)m1;p9b%UU$H1f=NgR#q68ln?j})@U|hyJI*U_t)Je72pJlx2f6f85lgv=qz?w` z*^8v5U#6l%Nr7j-uNd1e)~*U2wO+@Hi1>qQ9jVFzbg#?_Snb> zNVtmyEY9@}1$Y$EEIaO?IlC$0d6wR*B`}d0mrwsEmqxZ>rJynv$U!kCxyH>b%Iew! zmo3Bbny|(vVZM(cfcsL|##|GfX2wp;?|ve3Cj7E+XH9IeCjF6%#dz5=Sk?}B)EKmB6!70Gq$ z4T@YZAq-oL_`L|P`Oz;vqd5;>4=wuFf1oV-v#_X;HN4b`I8XGI!y)c>w=2YD)BC1& zGWJ_N`@ukP0#7K9VFM%MK;W(@-X%L7)w<4Z`Y(~=1fpuoVD2!apPdL%n;xGdM_n~v zL45`27~c+2!o=_D%7gA@oyR6mcd=gh_yZj5(!G7*S=fQ|C^p}Wgb#aP*7t@yeI?`Z zuiA<|MbFCSfN_uFz@@79##vdnUWkf4vH3Y=u`2-P_C;qAoJ0L~kE{##oNo^jpqi^E8VeKImNr+A8Tcg@Q241{RnYu{psHy^y7#%e*ON*@MH5K z`k-XdE9hn8c12#`+5wBXmksS^EecE7tSC{1R!JYq=~Cu_Jl%#}z5>!SvZi&5{xHtE zbQL0~qK_vA!NVmE*^}w!zVSLWp7h#!c6=OeezNB2)Ol*fJv%;}%a=1%YWKTXAW_Sg zp%50`UKHW4oUp=|l{N?~;Nl_2(mg9*-bSc~nqK~hEzHifxx~x#6m6=AKD-1y!zkT~ zA9!w;--JEkj9`M-COvcrK6bcv;N@Ys(8QN<-qj1grSmX77uF020p0%gxmT&^qSaX7 zvg4%erG&`OAbO5Pm*S;>K)J(quI7MUotuwZu*9_DJbdud2|jh9!d@O$s{r%O5G0=1 za(+j!0}{HB5Os~g(-J%(#N+F(*ds0Av|jFTi|)Y*b$d1*!1;8?j@T9*glsoRfwAa> zti^7Rj6x#C6w025M_G#95IG&ouv~NpV_5pS&c-HBV}f{4_&)nR>#17q z##Nzc9)$5Q6e>0m!Dz2o)hkH^JFZD#9z?K_Z}Hm(w1G7sb?De=aLXY?xT!MwMdh-^ z83JZjcN01Xvb6pe$RZaQLq={{pd>;Q7~i2LtS@K`hG4GytxNurR1-MI)9wsdio`A*Nxp7p^%z09bXMHfygxENF9P_F%-4!<*tVcM3kjYbrMF0Z09I&F7D z2xkjHSF?jI7_I>28teHVLPo?LVFT_SJ8S^zhBBH=TVF79c>1L1sV)&?EtnK+0kK8^>u0r6E@6yKVTcm#bY``udqXB+X>lY0O_ zk6CbS#P17Ff>su8LXS-QBxEkV3=zVwbCb;(ef%u0w5gaO4p61%zi5-Q86H{i*B7y3&4Oszvd5LScZoOBu?90^_| zj0Nk=hm$n=#%>M?j1Jig2sC+mu^|xK0Zoi~W$z1v_1129r>CZzq?!d)rDbE`st7euEiVossy%AN%_y zh(nEZ^a}f@;t*q)(2mo3k&wnk(mWVaL|ZH&l$xB=`Q<0-OZRbz7E8>*=XjpRSf~Cn z1ED1jaRRMAU{;2_?bf>w*%e5_|}*w@xhw*~ypbWoYK<({63 zY4z3haAkYeC>M5p7)}qBtsZM=Dq97VYsN_d*BHUoIS?Txj7T_MlqU(M9;?}0T4p3x zKB&|Tp8q+DYoCmiagXJ)O8(XZqPG5IvqRx~fC}HQI*5%(eNx%G`^QxF_F{^NV-7K_ z%E)J22E=M%Vg!~yu(18w4>9OFfpbsnd)e{pA5@DpyVzN1YSY}yu0PKDCKgQPfC|JL zJqNfr&B{{I8a6sYH9A=}DhRdm(5`N0BbL(Q`T7*NJ9NG9CSv^;GUvO`eA%B^?5y*@ zS?3GaN=LpSb;{Dyb9(8i1Jx;wr5m6_zY)eB(rG#4W)+2DaU)$w!xo2s1Z zY~o}_s`~X98;YJnr|W(Rm~xIWj3gO8*3v(u#u&zuj3n!(_tY4JEvww{@cm*ys?Ex4 z&GK2*HRZLnp57T4X&h&so>pJI)CY@NR{~k2^J$5q94jptZL=`is^M61V-%J`Ge)jH z_6uj{-pnj5pF{6{A6-rKt#Y)xr47li2Nd2`BO}z%q0k30egOrIwfYsbwN-RKco|j( zRXETXdj^j&=gl$_b%g5@4c7`?7h{l}G*HMkr&#^a4ke;xi)Vd>tG3QGA)=2FSO*`A zH3Z5-;Mv{7{VbTgKn+DbI3=``79L{dV{9=KAKvfi&8?fzo0ByJw*UfHYyn6>X~eE{ zeM*VGCGne=0dT1Xct@M+{DWx#TeFg2T0ToL2z-7TILu%{1sq&L+DW2)cOW!Wpd319 zM8AT5cdn7R%n9X-G>lqwvnz?n*hx2j2kYff|81Os9SHHKAebk1h3dn{)@iO!qyzte zLoWVp-GOs;O}|f-#vEh)Y?X~?YvsGT18bxM4Xs|R-h{Ef0Q53sSM>lsD?$x&R74^9 zv8NQyLHMb163c$)!13qg)CaI5m?Le2g8s3q06mN_4ZVS>kkC&|hrS&10MVaI=s(fW z&ykvNX6NNPVTP{yPhc_11MW+Z^F6GK)t9c6{_G_yAwb+sUYLVCwYY zASmYaK{SB3*eV!iY<1v)d%b-Kf+zaWKt~_UI{eWGk8(2`;zbyy2Fs8~AV>fV+JQi~ zE>OUBoi4y?Z&e|W6$Np+3`eT+R_(h+b?z}>@T+;NikFgR*xsLhzCs6LF0X@Nlk*ks zp8FXB9iV;2>opBys-3Qh)POp4;(SSroZ%qDv89R(qgEo{Vx6x_7p`RCTXf<$4f*~g zlS%x$TDUMf0@f;!MQyJKU3*sG-)44Gw6dj#}nxCtoN3vnZWwVJ6h&5L|mMl zp0(7jI3sY$w7P7{sG2HIk4v=1$_6Z>g~DpQV3%v(80?flO&C1hK!}Tgrn{#Jn)_7UTcTerR*lm0YDemJJs?f#ujE-w;S4LHR1{U4QA2i((f9H^M8}Zr>9O- z2s#1D@jEmw3jCyE_~rQTbi&yx;gt9TI^hIKNJI75Nvfue_n{_k#3lc{-6A!e68|%_ z4JK@tgtUUe398`DEGTY%^AYj*Fk#h3LrWV?6o2 zs}%KcddhlRrl*|VACjbdI6YN>DhZR{W0TrvLZrw6q7Nft7)smde_=^L&gcIlypM@H zK0mCg`u+7vRh|AtKhAqj`ecvbTD)wDaCu@FN^nSvp2>^1t&MZli1{2qdX~j`WJz4& zH&@Ar$iy@mu?5nFGGgt$T1MQ*r38nJ*!%g%lo6HDxSVF9M|N`SN3CkD>r=GGVjT9? z_qOTr{Ej14jpqwAblh6x=;;x>&)&sHAJ5M;A`kJ#^X8`KB>F_FV$qo z$s&~W98Zck*?$3XmT4n_ZZV#*eJUmdkgyfGSn&Yn#S?24%^IQ4IeKygn*D5%qFFID zz#h$pr#6#Z5x;{4Zv`#NVg>H^H47r%as96q3*PdUX2Bl-fAP*QK<_914i>zd-(!<@ z)f~iv4}xV?FGu2#v&1D7P><@C@AN4~d5Bek4U9gy%it7g{hTM?)2-v=_;0D!5h>6V z!m@v>*BT5s;6|ZxfrU=my*-HYs)s3!l|-|$EfRu<#f>l^BvfLZJ>J|LmKUn5k=C#u zi-3q4LI?-KNYcDS+?u1JRv>7gfVOjG51VRu%1)UVr_%olU3f}&;e{rV2IJzd>V(Ht z!YT2$b;4gHAyViN;d8Wj@S`S2@cg_H(j3+4`ON?Z`ojPBIYWLyz zG1?_GK_%QA|Dj8niX$Zpl2$*jPBfcy%aPE+Jw`uNz#2p;-Bj$)QS_3=EjZfbpnXG;CF88wxzy85Ex%)F*dqqh9=ndMbe%T2zN&nllfv(7c8 z0{3o@dOgOMj`HQKoV+bTRpY>gwyRs#agFEcZ-z*GX}-SmT)`kJD#V zOJmc^)o-Pz%2OsOm9AO(soGWJs+8RFR4k7goDz9)fXc8IQByLFBrK*$J)e8{G7W+* z0GeiVMXFa&`UAoGfVWL&k*+$@l3g*)+DxM%;%^Pt`vZontc<2HN(&tJwmJhRf=nmS zI^6*u!$UND8VyjJ>itbvan3Y|je?7d@Bnla6sOU^*BK04q)R%WnVxCrde|5eS0XwU+2w*?KY;N;#lry*ig8mC=LA)VlJjvU&h!0&E9F2o*q}KusD%1tsY) z;Z1V~o7dJPc3-Ad1dF&0QNSJb;byepgmp}MdGWgK+rt&~dPODyR6a^dTmK_LmfbU3E zXr&7m@PJv+t1;{|#|*$qUEF9(N%2w!f3_Vv`0dR+-K)9vD=d}@$N-trgkHna!LEsqLwuB-wbo69$fR`{4 z{h~{_c#;wWdW>`RgULvBbfP+~7bRwMWNyR^@HQ1X%|WxwFmPYIDCMvbVLFnZ-=+AePMdvn;Md=pF&BA*#saK_!=?|KD1)5 zbYXj|1CkQ64Cxg}ch**7LS4k(@414eBrVL@d7-PF-AH~( zo3juFn8pWrAy3sbPenQCot%_87vV)G+r%zmd&x=<+geGcVV7{Ct<4LKJ5#EtG!nwf) ze`Bby$v0YHN_{yLkEw5&#^^|>V|1v++u<9XN*=9%qh5iw9AN8?q;eX`M<;IDgP^g- zL_s(hX-DW{I!53RfkY!`c@ISn7LVmbNc}}g_OV5U&XCKE>o!*)Ek8l5I4 zakZ;K4HqXAYJwR63O$?XFC25#Q!8DE0?^*r2Dah9&hEnc1&1d&9wMi(ac)E5Jbz)x zC%sV_baiO}4Fro$Q-z%Ec-y=fqJ)l5x;j4E^ad|9dDHkya!c|6ondZapeC=*=MBu$ z`BLI=AT?YhT6K-9>azMV^>tclYVSbtB-K;1d2(<%Chb)9DQ!g4v>E6NA^5-1he0ye zR~Ybx70cqop`Ab?X7`ZlKv<-Cr_QCNSAoR1=uc`sAVkWZfHgsUs;})wDA`W;1Df)+ zl^XD!wl+BlgCW=6%0x(zRL>YU-Q;hC1a_z>GLVz`ot3yNE5pHd)Zoai4=KzvI1Tv% z*ZJEDTOy-d+S-tFw4r{Tbxfa85V0pZd`-PLvq*;ax$T$?k;n0N zNT$Zti|ibDJmfRO$(?whAxcHG#IWx+3Cp|DD4{LJTwf3#pbmc{4o5Y>LkI#fGLNtI zT{|Aa-S9;kTm2B>0i&vRQeKmh3G1;5|2Jk_iT~qwfj?dGUtkuSn4d3DP@@^|0wZr^ zNM1(*GZ#*&m@)OT3zHQaRWnSu)Tjs;t|}ZcUr}3$wcIPG(>~>imGwM$vR-wwUc+Sw zbgBvbYt&DxHyQ(tf$?UWcOG|Zcss)WW1>oB%THMV-e$i~zPd0*fIdF@0qzjlOiJm+9V6Fd|YKy$4#r_QLX zc1?vM%Qkdct!TDJT`*`?dIJm1X?|a8Q;5B-Km?fpgNj0|E%|GRGz4deop0p%jJ!5I zZ>ygY2mhr#qY}p_$0I*zAzYGta3tDkOtNKH^1)6dsU=Zpj-2+mPd+fGJ(QCVOiVge zY?B*lFpb4L1{IW7MVW=#I7F)WSk%8HRrxI2bay=RLrwV=fun(_H5j)12V>SjIfvgCwj&9m!Vd7g!`oIc z8B^#akWIhUO|6`i*N*B(qjN~s%;d%1S&U}ADbFC&gbc{ddZ^q+TfOKo$^^lHnL49t zYJFwxG>5;-xB!1}gPAquQ!zX#;p;HmkZ6>ZPnkKL?y(wI%~fo2{CLmwsu?xq_0wFQ zikUU#itHoDSvS-Giz@s!t!vd#6M1m9lp5{412R_A>3>JMiXe7 z3o^GsmZ(fRUxU9ud0&o@Q`9NCVj5r$hQg@LW+@F30Ai)gH&u4Uin!)}?IehH9GT`E zfi$zcre;RXc(V@ukPRU0jM%T@&LPhQc>{DP0%NmDcIKfQ+>;JcPIJ|{D#nZX#&%nS zjS!9CO|?-S{cjIKWOAPyYOhjwN`ie*ZjHB;m1%|>5t}yG7w}2ZQ-RbwtaU(G@J zl4>NT{DQ`gg`sd^gFo0<*ywF5^fneo=8YC##^@&OO>GT&n+my=kYux!K$svcC{Y;j zw{;Y@bu{Wy3;gr^qiciB;RW6fpXARRIl!NJr3)*_Rny0t1AH7XDYMp9ZI5rD7RThb z`kFGe3qox|Z18bUY7-=VC=8=2Gu$SaW~ph2r75ogma(~-6>-1wNN+0-7#L}KWlN!K z(9RsN?f*EDB+z>1b=-AN+`=l5o%ys)=S9RStE(&!2uJH~6gHzA_yo*WS>PghDGXj$ z=#7kC~H0`J+X%9PR7$HAcc-oSYCE zUE!)LudP${Pm$m%dzvu?*9QUY@Jfi!WJXO{dCeqG6*Mjg&Z_b&>uSo&C)G~H+%VN$ zPelsJ(sMNcb$=zLumOW)-oi+zB~lRKNV%qcv^X$ELv%p=j}G}dptX)>|7~wUfee2N z11L7w^agCpkr&*E2gNs)@0u{q+`AZu@ExrLYj>2J+X`XXde{aW{ZIL0L`_Qb&)9rU z)8Qa4hf3`gK8Jfk*;dt55W&DRWQ*|h4sUyl!aa}eNVlix4U&0%fF@J@U@mw(CBj`Y z5>ssr@>nGQreN1{QSpmE*y<|`Eok#8|44hJVKi-VP(ag-vW+sXu))_c&)4c(C_SMW zEL2M76O##ir-bHQXc=wZKtZTu{%A2&M>{n_$m_#NYfTq~h|9D~9Y$Q#h$%Dksi%zQB|N0=Pr$=L=C$=MbM zk9x;EB3>%S!Ih|ruzxt9>^PgRG(DOG^?4!rNoN-uzrf+`?;uk%fi+0Gz|k9oRKJ7Z!%EH8fhxPrG}Dw-L74+!p`5*0w6RMS?j6vRJdw9byu0Q)ls34kC^-Mrnau6RVkll z*ZSN1(185mh0wvgAsm0Aion`CKCgfV9RI-y5P>lAOv<~cDKAg$)!;K>(dvn)CP4@h z&_paKoH){fQlgo(Q_aB4n9@hsf2G%4>Ekv6vl3f$G%jpJICCTa0H&^4DFGJn{4`?p z!n`#NV`?x04+U*HsP)j{vExH*UZrg{F2ov~pfEFKGMlxLwl-+Hbu#Neh)oFd=a$6Z1nO zuGVluc7~`as_x8&R@r1ugKBBkQol3|TS+mey340thNYdU6@*_aSm-B>8vJ31Lj7&W z^sUuSYRlAuz4N_bMIJJwRe!Uvu+Yqx^Bux4L)a(Z0$?43zbQ0Aiy>#dmD-A!hF&jd z@#AzK3@c9n6IZhrWa2POwgGzBE>u<1Rl$g?&WQSEpB2FK3cPcDAvux+qOKYB`T}4m zNPHefkxxodcLod2$0%tsy-iI#V<-t8_%RUnHin@ZntnN&2}eFKUqBriViO0)6hMDO zX?#-_n9Uywv1YZ76EKtfAX!E)F_|b4ko1228aUTJhqm5^-{vrccU;oS623ifv{ej!~}8BoXkJ zStl*pyuZN5CNT^fDL5N^jb2>?4(Py_W*j9#6UT)ABB1=pqf7|!g-#G?Wr!my2|C;P zUovE7(sTlkfKw<7;SP}@%#ncUS;;+|qT+>*lDZ=Q(p)AiL3fJkt;3^&*`vPE@s8Tm zyFXYk*&pB+K4~`$>s2Ho!{X#B0>fd{-rnj5+CUEQt~sCleDx>}QhVQmNR@*OHr9sm z5X!t@Al5j1TIK~*iZW-X`DVtWF&uQ`gWn_+zFGzo&#t0_7Qm3t=&*s9teasf6{noS zbaridjc3M8EmH}PJ)g|f>H)g0_Ol{4EIKVe4xLysk56J|yjc~*9OoB9Bsu=jSlz;Q zHQxgsqIGHo+*z161L2NfYr$lAU*STUmX@YYDVpy~PnE?7Ojd;Vcp2#s^59O+>gaD1 zQBMa{up=Zw>MP_kXKUXSoYr5ZUYr;vK5?Bri8l-@IC4XcJfj8ZBA+DZSulW7ZJNm~ zw8Pc3>6kSO6=tu_^fa4rr*RIkMYhbakZ9m?jC!nrP!u7LoMBgKE6O(gZ1p8CG~QIs zHRaCHLx`SYIan?^Ru7)9ZGFi$#4%68N~M-V2NzfY=vL#&1pF@QVJWTvT@LG)vwJ9L z2K~V4^n{UKS^$pLz>jvJQX#YHGK{TL32k-pLDAim9zA_GGs8m9d zn^H++C0kgi?$~eew%U&(ChQlH5yHP18}f_rH^t6|ImyUtrCY<+Q`5579)Uhi(wRQDI-3)lrjQXN%qk6ot01NE~7W?Wv)99(MH{jXCiGxNx zw#SvJlzOy$Wj#`6)Y4gir@G|hl)>T7~11#f-^}Ny|KbipmeyFJG&HfA9wSh1D7UH+!0=%2jc- zkvTc9qzK9KPot5Eu|!<}b%mg|dt2oJAkV}SP%CQ8Js zwShfq$;?c)pK3=;OwMX$gIYn&TrPjkBDNE^AOY+ zqSjwot;Pr#KGPujrKy_oX=G|XgZG=%|BRxd;$ow?sJO_$e|W+lUh#zVA}|E%z`w;8 zhs>&CM8{xtpcYZO97Rzf(Jv zYbT22#rpT6dP7E;bNw@9qQ^68lbk9X+la&qc)BXOt{ymSR0{bzm6q3x#Y#^Fh=xWK zn*j=y0#4IUXjngusW*xW$APey&vaFh^uU}g4eIM^Tv*sch9VoeAP`0st zKt;HsLR2LEtyYK@f(Ut#mm`#1f$GK?nStZYVk8ieMd}yByp~dgLLje^^$V6YdG$xr zG#ai6c3x*>A`sMtF?`i`;ErsR{{#Qv-|6MjjhRzw<>A||sh6Q!OjB6ELz$taO;pC+QL6#~~K8_KnSEL?2 zY~#&9qz!&aQ@klye`+?r4JjA!H^a5Ud=!h4uS(@Z2HPya+9^&9^flr5NC7&z7B#zw z>iRsNuU(l=Fu_M5T-b!MrGp-nCj#|T%qloi_1o|tR6l!;>~_xwXv9QRfE`t#@T=sw zz+WSA8vg6jmg-oa=za~p@B$y)0fI|n2ihN<}U&selAFjz9EI`b{~Au#4NgHO9w40Ap`A>3N0L? zhJG3xF${9yY;T)SF|%<-vgd{51ToP3pe+X}O50+fasy8+PQydBjCTK%sY&!`+T4?; zMOs_`2W^vUSUyu!Du>QBJFgK-7kMR!X2XE8?YESZoPo>aMiIqS9@XDK^Xx!VsWzvf zAaMRmEx#mf7a1jh3qnL0DbS&*M=LcN0!phZ(`Hswu#hdMkYBV8C?1j*mWiD;mCISL zSTC$~z?@pc5p|7fLHPtx4`>rfr&I93fD)U4ztp{f%W3>o##Pd`O7`c-`Qg8Zainw( zVpdcwXj$5&6EawhT83)^JHH-yi#Y{{HYS2J*qd5a%buO?o4K<{I zUp;l68C85o4q-T(AKR6dYSzLdMDlY=R!`9UkzkLr9d~7#)6~ECDvOb*OS`Ap!Th|Y5kgk`xk>R>3uiPEGvtNu z48)upZZRe!;#Qdwzy?ey+C_ADlwW}eD$+oAC@mk1Gt%p*`K0E7D^06U@(o<+q4|zb zDe!QZ`~z3c{7UYtf2-+i!ub47Em=?=Yb198aA0ZM*K@3bMKr%`O1b;w8 zKxBk6AOfLV1Z4)4(0smY?Y)2d_dCZf*S+1-oyqvtwa@we_G9g}*Iuu^_S%3SOAcx;6SyWEPQfnnlig8|q^!tNbu^`lH_ zS3G06T|n#>2zhhC`HGA6h!oKB!95qL1AYSkYunri-;qM}_mgS=)|~#ie_cQSoBNHY z|K;$!@iYEjzklWz8;!q$uldewqw#OgG_L;sztoui{kQNx|HX@~+XToi>wA`MS6Pwt%V9f{IuF`- zMY+udK_X^O<7j-{#-SaIz-qzs-spA@8pM#OP^0~RyAeY;J&;?6FSl`15X6epAna1I zi8Vr0ILA8WE(&t!n8;KD?mA^R_vUZ5=e`Q_y+wri;*ySkOzPK!yc))e(U8!Q8q?Fo z$Fqe3X_y`t_87H#ywEvjV}Gaj-M|7mjV?Gqj192#yM=ttOfF7I1x+*#_B|@3@ti}) zJKN7*rK5Ksd#C)exqpPijTm9f^~UJf#rMD2kn?(ze~p6|G{!|3Yg?kY#_lWbb7&K8 zvZLEGfYz?AWqsNzG$5qVy#KxyoWRloZ!FE-Lnw)>+?!iiX)NISY%I-uTr96VxOGd= ze$d!jJD6x}>_4AqC^iR2<(h6FYG_1__I#tg-DuBplz^Q?+~T{$s5F8y(TFpmf$MNv z$Q$3diA}i%*GT<}LpGB*D8o*I&j_F~Ud|!g?-%@zPyDljevsZ8z?l8BOnh>Zhv*{w<4TfH2CVnK zYY-01Zq}>zC01ek(xpaw4|jZ{{bgRTIn!QY`x7@7Qr@^YAS`tbI%`LPazv1U#s`WE zBOf;I?5|`;um&z#iU=;BO2P3)#4HM03eHBb+ZMH;f_ihs!)+;TwsJV9f^+f|vZxnZE0of_tf#Z!PZmv(P$$IJa`Lwp}msS@hzIp&e0lM6}*%DL5E4fIUz`=vFJff(A1dd3Rx5Q z2CS+vaC7eN3SqhG-8(2m$XMnh#%b2ta^93r>$yfO);)kymGgK(X1uXN_n3Ytx z2+9I)orFISR?#4mQQ0)aq6Q%3d+bOLOpMMx-S6VdGm)Vywgws(I7%Xzh7`qM+7EC@ zs$aT9c+bG(=zI*RrXw1O;k*h54s&3fbmBorTG^Y`DUB>ya^BY#HeCH zJ#_wTRC|E1YHzMLIF%B`Ok<(*qW$INvB@v}_}Kn>H~&gI4R&0Xm+$KjXXf;0<(__9 z_%V^8mOOK@u@sIrF3*v)woxc=Ex&Ks?`8Xqw}~gW?e~iPp0nQ%_#K&O`z~A)!d#la zk6S+i*lkQ75oK_(p|uH1zO*?OUzu|#d*1V^7;W@~tWqA<V1U3{N~bg#5yK&{U#uAieEq zBru8HWI?A5Oj$&fAv?s$v= zr}Ut|k|CpaiXp?ZrGb3}@6=x!|G=r0AP35e)QLmEL5Os;?PzGw4tRqiS<8tACAR&6 z2r&?*tsSKSS=Z`!$S+-@2|HBY=f#cvBkr){9NaKJB>zWuISgtD!~jXy@nfW4F37kL=}q<}AXF&90Kh~agkNu4TrbOie{TbG!uXGERm8$z zY^?AQt2ImTX;;oMk#!06s~Jc4OeaN23pB8xL_;T6lcML$Yy z=rdzS)(Oi@?T9vGKQQ*7!r>`HTihHmr4e_u?YKf!0MFxC-Vj*KFUVV6%+BCCy*W>s zr6tUkLOY@XbMC-~5M=`Hn3x@su{vBtxmZQar<2I;NBwmlKu@lEKat= zY<)t*ceN)xzeV`BNZ5WLA9377IqRJrH5m3oj5C>Iz}jJ0!&(d04rXcAPQUeM0Z&rz z9yu6iRBwcEcdVzb#gpT~4;zaNN>(vY3gCfSo(_QN&js6%VYUh3oC2guC7M1>vWCVU%{36@)snVgxjzYC0`5;U0)93PMswzXrje(4GctbWv@uf|$OoNnRs$ zQE%%kILU9-I z>a^=;;SILf1ZWjbjp=;jp0z_Mx_G!hq^H2i1%7P5MHD)R703$FFF{5(JPl-NfuwTS zu&5H-AW>L}e_$^zd|bzB^pAl(5F3bAa!SQR7Pz(0Tdgth(LNkvf4lGlHJT+|!rF0T zpZpJIyP%gu&M$3LWVTTWhxKXN9Lvt7pb3|!n%jrF?X@-A2G)kKc39A_K(FjljUj|V zSDh47U`>XN5u};mQk(6Ey|LLP&bTkkexd+qFs+u%;g;G|!TEdmO=Y^EMJyIs^XLwX z=nimLJ9EBVu6gSr#${(U@S03L*?uWzBA_0@=PQDVF#+C8YpL@j0X=Y|B~y#y4mSGC zi+y&bxNt|uoD!*Y5kdLxf-FrGLL7Y%n#QL9VqBH;H(4&)W!9N1i!8P?R;U+U6Viuv zDr)1Yg!|CUNO6N;n2}-3yTS6;rdCEu$JT+B_F}i_E=}E znAqBXF+)5L@aW7-T%g);13naq7i+IZ&>94J3TIwJT<(o}I}DdB8*tt3G27g*VUU7l z7v_`Tt$2)y01ccHaShS9PmS}3s8=~oHjjgGqvO*q&@OdDac{UtDgBpTP z-nv`>#CZ#fj;zMw>ZLBxKT(h--RF zPH9_+C}Yf;tO1Z_s{yQlB2XXqj{|)7wqL@?g<9Fqrmd8r;To-yQIg7TCmxr|4J5|u zcr7=!r(%bdS!guOjbr+H`qah-1~_wJ>wG0m!97eWBbU>8HNbWObH)^o5t;&x$CB~b zg;SRaAn%nDlb-0ubCIcA%zT~qkcn@9XFO0`y1W-hLuJ50=p6DEjeOM@>HFQ>z zC3cW+G|e0xp=_H>$BM$%s#upY0yPlRC!KzcM#`mpffRHbun;bh5{na7C!erdhVZW- zOU<_?#9v?*{lJWz5b{Fk=&5b!Z*O7uaRYBh2{qW+Db*oJqeMqluM3W;9)}W?HZ2Zv zk)536R-1+%In@KHP2*JypEd|q>hReeTG~C*&l}r4=%VSKw`ugC?M?hU(_kZf5PqNQ zk$bc10KBpPqup{?T0&totf278{BsJ$J@CUwkfeXVPV>Dzol+uMvSLUTU+qM?YL zm*dQV@6raTv_-C{m!cJi(Uty; zOM$czq@aSc`B`L>q(~h0Ubj^3T%FP1`Rbh;u46f%bI4|H&#pXJSo-ANmzO`jbK|3% zquNh9-aCA?`>gxo>H72NzliR0;Hi4gXLjO=g_#|b{i~mU1IZZui?}O1s8v|je3bSSTg8g6;tFCk8F&r0=)!%48BQQG2xnd|-R=6;NR!u+JUXlExcu*W;P#P&(HrTz^ z24r;hkq2Pw={mv=9ECjzCmpeg z#zzj+g2ppIy0W}r+&<0JVY*g{4c~T4gIaz$Fh>y0W$(6Fp1e}fR{Xl~MWaVwCq~68 zM+O%CiR+~pCE|JesO|n|Q3&%g7F{QVjK?7uf(`CrGsG(yYJyLNcE_6irt zPh(ATXhRkR3*Ta3g+{#)ad0>lr!QwWIWsOlHuLy`>>eGf>BcALqHx4A*SLv}_iRH3 zcW_8T0Z|8v3Fr31j`3&s6WdWFy#Lq%X-^;daH*r43JBn1LEh+~Qyv!g$N| zu}UzWt;85r4HGs zTnqoH{dM1(;1G`H6aG~O{5TPtgpH62W(gn2ykaNs5jC^)Nip=?sX<&MJ8yn^ zdFV-KQTed^^JAgrm^P=06#qc9=W6%4wj#XU6{wXkI1%ez5hOWp3XX+Dk~E$s118Hz z5-iW3`C`6K{PX>=j(&DJ0;;2w0Z^OZP8;)U<7pd{upWZ z)E?jj&)12tk`hyBS4BbK0Ik|J%|stq8*%*n{d<4pul;L(fxo}<-S2+;FZ=U9F#S6k zKl8`_H{CEHP^?$VScfa%c|Na}-fBUce$=g5o-EUw2UH|Tn9sGa% z{lC8ZhrV?Dr9XcC?|kaz^dC(By%9{b#QK+JmXz z`;Yy$zkK~y|MXA(`JcW0--h6L zAD+4X-~as2{nYc{*1bOcuRP!T+TZwNUVgegZSYLDzg7IgfBMUH*{_V=$9SM=;>r~j*8{S*K3)&J!Wx4!WHiAN}J0@CUB`shfM(zx_{)K$G9G?WzaI4Mov3CMG}l!WX~v<3I6}S4J;q zU$T!c*VdJ%YUYL#Q)SP`I+sU@{dvEbS!c5cu7Touh{0wIvhfj-d+gh{e`4$>IU`D` z3m1x^>5<}7w!|)>w%|?F!_hC|aF8a-5|=QZ(qm^N7V%bwUGV&ZI6S=4svhlIS=xoL z)D{tLx8`rMbv8e9mxNYRjrU7|5I=o$dEVXu9d_4h%I{;lopMTwkK^@T;FJdZ zapl3%!rVrr8?!ScK5D!JdpzDH;z$u6-mVARgg$f}T>-u`OLO7%JsocGx1_sWBG$8gYiaRb z8((X9eCxsO2eCA#rR`dz@M?uK>_Tn)O7r2P!rxNiJM2Od2d5M!#S^kDA^Md!1| zS-C?q+TtHYHSX*^cWC0b#^}M$F>W7ThYtdrT+v_sq}uwZ9IS+*+8>pfyN8^tm65vp zik9>zmC-2ftgPH8-kHbM8s&49QffFamFgHI`lizp)p zc(uhQIMw!!UpDr;FS*2oJE&rO=`tDbZ#EQq-fleiU^xKquw&Ahs6Uu&n3s&AE3*^@ z7Q4rSW76ZAL+g!%3oA3ECT@66u3pI4`zKMRJZUMHWn*f}7i-%Bpkr#|Vsx3*33o?9 z*3i+$aAS0%F|NM4PXpQCpIf@yVCS^Kxp7vZ@^`fxh-0FY$HyJt+J>ppZ{xwjJex-x zKwm1ST}2w>&({ve8J9*GuVonHJAtu!OrX}dLUzAgt;tJ;a4{@2kY`^AS2w7Q@VFya zYM zM|#rgZ44Z+H{^9y&Oc>E#UreGa5-mHy=-ztTe%1KZppbt$QGBD8ziIL z-x%LGIL2}#3&u{{S7~i+`dV#VrLfX4L%>&6(LN6}u424N3fbfMd7v@6dCdG=-Pp0` z{Gp^druAVwe7YJiYtPEhs@lfZCb-*|j}{Ukquq;*t6DAAqcth;2@Y+=bEeqvE4bF%ih7*=EABAwbv% zor+m58$omiK`E)#Xni<>du5dMWL$>}ZTKFhihhVlOkn{<=`Z)wt z{a#(c(olMYq#hc*+WaKp8tFpwnA%Ja=_jgzePL`(aFxWZTPy7wslE>GQU7-o`t!U#{Ju{MHigt`s`$`9g;#p5(a5*Ip|SxNiUUYlw|zzsn3k)fs28i zSqKXyP}Bx44qW7uZI8wzk*qG3*74fTtHujVjF@zoyjweCPuE_)9P4t6n7-N7I9vPs zB#g4_DlC0*c_q~NeVBm~m5vK>fEwguvfM~OH1Oa62a+P8*N%<}4}!1hJBJ`@FGyUl zrfbrb*skX##Ls<7M;#*b?fxltPtZMa-;N!04y3Jrqp>neb}ZP}wV45y4L-JkYd7L2 zsbGNjK1Y!@T{|4$;+P-jx|=V2Y2bt6ivt*0T+8F3<4f&ZjgR^N)?LpwuB2Bm7Z*DZ zmS=9y1(xGaIDOe(XtP2d*jY+s5Wy@Q7F)>5$!kv+`ol$-x&StBf^~X-4b1}sM3TVW zQ#jo%eH&av!V9#?ca?&kVEK0Pkr}?A6V(MuIi~o9OPqt@Qv=5q*VybrxQz|M503Of z+7OOL+epxN^W6~K&!)ZIBRD%t5Z_o}^<2m_xxT-DB#)S`EowwA-QGM{t9+U4Juad0 zmS3g3p@AK6=dH=r6Yp*)-^ASx@gm*M*$4!y=Ij#FwlP_K#YI4zg0z*ReU1j&BNE~J z0gRm&264EGsU5y@T*5Dsnmppxqjgm|H3}qqgVIGlafPZl7c*%iW#oWBgrYDVmf>Pm|Pn$(1QyOf{h`(?TW*mU(HP^t5y=1Q!by9f2n- zawG;4QFBJh z08CtIIFfWW0rN%9q`1{(3L`lo!;jbhg4JKNTN#R*q%|M9)MX>F=f}qvVpp|i5XF3< za98udeLQzVja$1Pvq8N7g5Vg&EmFL{hTbCf*43qC+q<1^fd*h(le{*FtRC`-WP#Y5 z>@M=@kiAqqVy@nJz&;2i4p1W{B#4;Vk;-_KUJMsvAr?ja?%luNW>-F{nOL;&bT#VBX8b(&|^p7@<(_ep2-h^RbcFZ4%K%aF96}K$$ zGK@r~OjyWmw-D>*j}4Kd3#ijv(136AYIzk5yDumOBqM%xZOYtuHk9{09N28DWN|5*8j-xB zvx?D$US-5cO@q^GmE*1sSSiZO*io%mE$Xl~Ggb8Y_FB5h8iUS%`p`*KKnTqQ5DO@Y ztz11=Gu#KKiRiglR3Tk)FMPW%AQp$eXbzM>EcSPiO;B6eWR$TC+T<|jP6MrI@xoXP zxw_QZ!kmTM=~SM4vR!U6-h#Irbh&~js>=RkJgBSVseX(Lk1lixVslT4qT znoE}+J)FBcLk{Th0)#f4YCoGF0+p@_uzsf9j%+043c*zv}}uLaX& z|8TIVIBoH%zt|{7^IMIafwCExVaZZEZMT6pPLn~ZGEO4J;MXfBmw>B{O#IuOcg)&y)KtX?r5Fz zNF8a}c4dW&(L|-*<6Zf4S@j1-gA8>O!_h8DA!Y3P@s@?WJ{l`XVuHWO)h4wVz-0$a0>;aFNyvv47Q9}C%ZhaF4Ee!U-`r>d!P-Z`#Fz>Psr}fa zwIR!mlVp-1#SljyHl9rt)$8U6Z{r@ctk-e4TJ0y&3FFx3XpToDiFMc(;E0{4q$52c zGSwU<+FF=;KUC}^Uww1GbycdPwQ{W}V)4H75ft&-cB41oaIirae#-ucJ7vC0H?&;c zef4}Fac#asnBf9BqO~PJW66@Tu!9TENszG$Tjlnj#|XfXv%oX zd2wNid#4-}=>-R7PvbbyS}>oh*%4}VjZ;VK9Tqw(9wXzBdxn&XTdz#rU?T{f+gfBg z380Ad!z@bBWaJ>=1O3KArj*Fx?XCyoC$igIgGYgvw7`>wL>$9x=uG{@m7lm0+Sw<6 zqggs;sMHB2V5*$Igi;UmsM1R)-Cuu;hFdMX#0c(mdQpE?Jk?!jii0ND$nCt2*6FdW_OjAYx{CvuulQ2j?sm*=Gn@xqmKN60ZZ_Wd zs-iGe+_fB+(rS5U*WB@$?79k+E-OtEf~!K+=7>{e*ls3L~L3gcz--g>+kY zf!Psn?$%=Iw^^5V=xi6z>D*eXhWoXm!(ePqfiEO7(k^58scbT`7gy!C;Irn>GINf2 z8`CB#?|ez8^EW23bmtx;-0mK-gChMVqUlnXjZ@i1KK@$xf>45LA!Q{5?u9_RLdF)E zJ%|)g0de1W@a8Pl3@dmpYR=4thQs+9TUVs z3f%I0Vfxrts6z4?zFAY+pI{MS#3|lKeJ*fMA}GNH#+TAAK_z*TvR6PK7v-p<1j7$7 zQz^RaeE8-Ezi1Js#b|lzK2~yJ)|7jXFx0F)nGac;>z--{Jq6`cD7JP#!+>j54By)2 zHB9dVRwW{Qe6#a>d=Jyj@RZ6eo?R~7Un_-eYmeKm^P73K*Bmdd)o1JX4ebREA@>rA zTa*(UdH)1<&gq7vO9$0GxLvJj!in+!GqyA4rw%~oDn;|{Kq zd@ZY8V$AzUj}xD`sXk0{vx4a>g6q>m$Cg^FJ8s%P_BeUACR%8rotMg%%eTpv=|#3$ zn1_!{Ns=c!kefAo#C0Nggb#}+JNu+grQBB{evBAa@C=aD5|20}wP0Uht`eoOUFdAy zy}mQJ?!#SMMX`8G6zKAvso{%@a^mP`9^73qWz%F5nm(_G?4sBwJ8R1HaD+`g@bS{( z!tJa@D$a9fj9h}0zo)zW2+hECYY5?t2C?me-y#xJMEAx9D=ujsKoT@Czb{?cd7`jM zPS!lHg(}!c`@}NHnS@ek2KQOzSc^}3%9T6#X?s7NtQA|(?zn!^_ItVGUduOO#Tqgt zG?J+)+4>(2=sQmB;u|l9?kp~^4A-9Ao2x!~z(txoX=-a8+G$I^Al2J=`xe1>+VCvGI2pKr z8Zs1K5jNMq^E*Rf_6049OWDq096v~~Q!Qo1s04@M# zfQOHJ@fi^)8jN*9zn3q+xhJZe(o^16fC^lJgtuvauYcovC77SNX%esWZ=4sOtNHF` z|8~KBLhfgP`f0sYPI?i2TDI9|!V)1DmAxM(ZAjV2WLHfyV;+UToVqd3!Su=w(jl|yL>UY>YV zy!&qPPUQ*GcXf1pI4m?W-g;`N*O~I8O(QPd^1PXIe%|{wRNP#|q_7I8Sj< ze`wDPVJALXTL{D%>5x=0C=H{%M)1X}F20@_|6ooibgm8d6thd#RCaX_PHb4Kw&Q~- zMm25=39@~q80ZllD5lS#BU*<)-MKb0c9m0aEjzb$?M+R;oI*E|ps2U{RobckT)j!F zSKinn2Y>sw_(}g3C*IiN_SDsR`QezjaQ55N34LY|Y4FO_{vLigUG){&#~a}|oVvPX zr{vJ4r2KvLjWxPt*7YeZ<7+!O^xWk2QG9at+&?X^`UJKNaqCTmR0jizqoJEuHMq-f-JQAZI?CNXgd&5tdumvf5JrTY^Jq(CFV8UtJy_KH0;_1Pnc$7LIAyihgr^Xm$DW z@c0%W>1C>yI%~DA44*VPCWeaQ4Zw9f{si!gA+^*!dKh)ZM*-TQ)PjvO z9@cm(75CmoM?-I@hU^tL*XW+#S0z65;qqnI4vh+%Xj>=EwbusK>&vYGQP5Z)HrF1B zUQ}xG4aMF+rRrW*5A9Fm&>Wa_GBoGl$61B0UQ4yDz#m_hgE+C~jEI=9V$ecd2y+=6 zDN?J3!}pt{j;uWz0u>V=*V+hutsAb^Bd*rLRa_U4YjeBAH7$Y|4FK^9_Q2rUYt4AJ zyqnVdl6vZzd}0fodO@EGZ)m)1lU{_eCe^#&I6T5cx4H0g@0aC9^ZM`SUxvqr%3@g! zTVrBUw$=@c?Y-gRB;a$99d7PBFl43?GA(&=U>WXL-l)n!tknP|eQWT%)-CJ~>u!>$Aex2u--P*Z3aUdzl@^33W5UPMRA#W3A?M z`ik&u>_`MW8(Q6jaj;sSwVEPyv4uk4^u;0fk}p!p7nPDPTIhY%q6ewyL8a({7fn1b z^54icr*~jzZNRE>v*vSH!NcaW(FxYS=+D42$ zBEquChT1Vc06740karGWjnU57?)Ii$?(Xkx6C)%Z(nJIkD(zBtFu7(`O2XMsCbp_C z2;Avc{$LHCMqAO>)-Ym{gCgtguaj}G^(A$M%q*XLpeO9^>8vUnvQ~v1qt<(?&G!(- z-xvQw)uPG)tQ#o#yYtzCXgYn2pM1!Jg)woHk0R_UKKfci=duj7;a7)W&yvNK=KJj| z&OjwSdS9fTT5D0`>w^UjqnH8tT(@TwQMhyKl?o(y6yxz9}gn$3oxcZ1MI?b+)8G6OeF<2wft3Q9jQTY+~_7 zJA5$y9G!`HGR$v*Iy@e256bX!GC;x>YbEd@pC_1BY=}aLeJflPCI{2EKJ_bO0~#ut z8-(^Ql)&X}(s-crinD=zm^fa+$Ulwf9dBQr3>(tdR^MYlCqYQy;4r>Rq^k!3VHx1HmZhc*MD;77#8uE@ zP*D@w7}gFTJ8Pcbirrz49P6>u3u0G0kfmk?3J(n%I&9Dw3a&7@zQW#{d>^?M;cA4c zH?gd3{a9k`mJDtG+I-1MQVF-X6~bypcPgNLIoFAcA{xD=0;rl`%x!Rmzeej<5bI?y z#(5R2q-5DwK?-k!B5PHBSY>(5Z7Sv#yotUH4_2?3<}j!cLUHxhH6LAs1E+xFEd0(@ zkD*vEGN3>TaY6O|g|}^R#}*5lUvZ|Ku~`HMil>$EwPcUbPJKcXubJMqJe#&(A|3kS z*H*iaf>WSYR7<*OUi1oPCz=N&@Y3Eczu6rZ+2XrU7Z0yI8sAd?w3;CASA-G?O0fgJ zg9>Vyh1=9N2L|iaR)7RmwYhisvNRrp*UM`1!vnfQIYfU2mZtee)40Ni3OJOF5I6VG z)B!p*WJ2R@25Ow79FAkq8j$mYz3Xy@1i!=X~G+Eh^(>Xa$RF-uW7NQ7M2rYky$b}Av6Fu5ys#qN~CT#3s zRd%emZY#pDCOOPjJd?s8;}c^7(LIMU;hyoR^v4$%4JfplPT_|^MVmn5(nRYgm|gm4 zG9;9asOXR_mH4OImJj4wDbNiyc`M*4wt-Nk!@!wv#fvkQW(&MPIJMIDtGR6(ovPh5 z>qCZyzQuhL7C{S^kk+@sZoeFWCiV-FWm^wv=@Im*0|d&IG+wpD#&}J7Bu7F-LD@p9 zR(h~a`B=;c^HYo5iGgdA{>-x}AVULvSPGasFx3NF$)Js7)nfIoHnqlgY>|XEoMh;u z7`*t7<(S&&K6Q#!NBQg3CLvKTHcx-KP*g`#mNXJFT|DeT`DeM0i^1XOcqtqV^|MpB zrK%>vvZ;W=W1kBF8Go`8anvOU*-IlY1tpMV>t;b-%Azuvee00Np?vO`4dM!*MO^~I zIYy>uvxaJ<{S7#lbw^f+8oC$~L>vbbMjd%-TpDG4@uSQR;gF(z55_}rtvVM0Uur$; zqmZUxT{?Oq8-oa^ip&Zxhwh67=Sn`}+$uIdv9G9>T;j>HFL{E$4VIrWDk$C$|9R#H z7?}>s3mI&>c8(eUY^yb5D>~aMUXTD|cc;@~O_VlEc+McxI08coQwsYC%0sq4VEt9m zWT9I$qXYik;*KuFu@jWb$LqT!BPI${*WlIG_^=^UfY&gmU z6Oo!IK+jn}KK`MwXYtzEqP4)tL~=cSg`T7*S-BJYz55E!mVuxbt?95o!Q;yGv@EbT zFY3%wp`79=jEuUC0iFKJ(knhl+#R`!tSMk2Och5al#f>%M@(A>JPJ5oV_&XqKUKHPj=uc(Vax9fgkEY-Z zm03J7eJjdC4S+(nILl78wNiqe$Ty6()G$ohh&;m=z(k3apl=&;!ZFvZRYzV%Lasko zwEXDa9;$2RrJpmo>Ok}XXaVp8>47ri?aSq`F?8Znj$pzwncHLb+(d`HGY!Kw#Iay~ z#9kFfs%233$9a*YA=DdEka$l+G^OWn*_2{uw~vmG`nH!|zGb7_Zuykssr8`(p}%>{ z<_Hz&3!a{z)sz&pI_hBA3ia#-yJm35~b|le$w(ZP}yFcb@)J@9^}J zdegtZqnAfzcS_85#!tP!Gm7#m^f!?9jmo`psjUg)+FB25O?g+n?hDaNBEoe7_#Z6p$JyzeQ__q&^$1`G#DgxNB^^%Y=lY zS{obVDRZ`HM-SI|xY}GDnw?!G3d5e2Wvq%G1{R_C5;QNmXoeX5)}TVvk-<&UfOIy^ z|7M$bL$--`W!Sdy1_DPhDH(S)UCMdOgOxOCB(E>7T8aTP&aWw%y>dQXCHc~)l>F55 z-hZlG_Pit*ePQ$lNsg3ajqm%#Rg9JJ^2mZ>eJmF%5M7W zXIzMKxW;$Ow9gegSL2~4!tRNB=gbTr?7H=}ofnilRPzc8BYkW!+O<`p%(q9M>dxy= z`CoVS*vQ3w=8@BJy{uD9&!5&cc6Q;Ly$ zoR}|p!05kUS-_0<)7bGORkLXLh}C|Td@KZ&J$;@Fv|-RN*+q^Hh4 zb?`Y0Mn&bhDW`UsJis@6+R?t*7Z`AHnEG#TV5Bh-`c~b46po&@5lo%X$GS{+pT7-P+u9x9H zjoIp(Dv{`LYt0lxp&A3wnH0>(e)Wy4(;OIqzfEmXTvpp};W&Q-#xADPpltygVvai7 zd!(q^TN4?Jk@SN-GL>=a-PRd`^O1~9{N;uCd3-G1oFm&LMfC5qeA=j?(VC$ ztB}ez(Y{3vTXGDVHkk#Bpm|~g#uy#n!5PD2sOJ*$17YRO-ko2V!|lTUfYJk)o1kge zIz8pybX~56@Zbo~ZktJwor(KLw#uNmDd6=L5Im=x@zmC!4~It_xfqK5*j{Sjx*n86 zJh*I6Eznq%xFP%QI!GvO8n0m}Q{68#Dlun6q%vGnq_k>@4~(W zgh!DT+p@7rSFhvP#7`d-+blYUU&mQ=NeO&bi6(7Juh!yr(c7A6BhFR?a2xLpA|?RV z3z^I4-nQ&{Pix_+S312-_1LG$623ktlECa+Y3(S0@mfck5X&56>U@LFd$8Gm zRmXC8>Xn4$rg7=kpzAsPI&ej(w*#+O?;t$&N;KCD?7cPU%2K}`qH5LKN32}$B|T65 zz$ql1T7!FE@7IMZ1-%`3rF!$>saMh)>!D1j>{!xFZiW?#n|Le)mI&pDTi1N zAppF(x3I6Bc&N~$`NK76n_hcuhZAy}uUwJnCTDL=R)kdN!Si5X4QRJiOuh%9gtvPL zX9){s>$Aj@Jq@L4_QeN%+CgdPX~zoJo9e=N6nsEyz0ir)bB@@19; zpp|cX)??bTb{b%_w^Ad~MCb!Jtbn008b`ibC4IyLGMw-=kd5d|1caFN2F4^LB{&(9 zUfM5Bdf>1o%cMuBIsKgA&6Q$7_ympe3+Y3IEg1pY>G8Ya+L$4xk)U-7R-QbL8d{b> zl0u}Pchf+Y2jV_-f=T7M{4SThu!~cE5hRc4=$y?~KrI_j`A29wG#Ex4_CSP`ceE5h zmONk8l@L&qmV&vFctr8&F={Rjrx41IW>3~`d%waw z(<FV;$PwC;pmPwp#i0yjsE6T*)!jcgZpJ))fV#GIRx7@h<4KK+QvdKQn=D7M!dW zQH1?!?r6+KJTRy)*MSn7aQ5j znwF6)QYt;>BCUYBveW&5;kdek#1_&|s6tXe8)E+o39HRR&@g;r#UrMOM$l97=gJhG zhuo}&LEv-dMv&-HR9<0&KGTu-oizr$Xj1Qo)lxjn6>+(|Y-3f;yT)(yAC!J$vjGJc zqCs$fbx;3dO_LBRV;Hl>4B%*?LJF>n_pvPH&?y14G!#>ys&e~9ID>iNvFhEIK9^{w3{6#yEd0pXpI9l{3=g zmH2d|yx?t%^z->9?CmG&H_rswCaq@CH)|mRXA+r=b0JlVxpGNVg{E2wGloKf(qi14 zDbfq$W<1c5t|)Q?x3sWU3Yh>$gzv4_r7=%><**CUpwHpRdpRgmGcZI>qYtJnm->rc zB|{N^$siVc+v|{|Zyk2>FgMY~-mIi8`%;)A-ZPCYItVal`4kAz+qg<2AakDU^(|kxWiq2Bl^0Hz0IXwQT zN0lh~u;wHu?u-xXl@?a-8mVY_kzh;(Yo0DEOV%4GW#WoyekT6vq>{IkO#y}QMBneEW_q3^S1*kO}RbgaEy7LVmcG{yOi%s6l-8)0U`zcs1ua#cZHuKnQG zEW_B{`3ICt?f6LPk}XvnxL-5{QEtq6fpVi6G%HTrUM|7J&!QoL=wGz6+Qr=vD}WE0 z#J6@+hPiprs$>UBj-O^9hHlvU3Eh+u_PqVftSk{k$31U!wsw>{D;x3`vPQi(6MvyQ z4gQ=Rt#I?a^`iQz8#O=&dZr%a)gdaPt`q7}AEj`waF0ZfayM&%72K4lpP--RDvq@m zbsT5%Qcna-kVvM1WCF*;Kh=oW=yv*%ur*oHNV;Z+nf%4iRd9^3)Jwkij8^?eIy{5b z)+pG~U)I$O7_HeO+m&HV#*WOfjTfXxn_f{oN4}}^gzF2~0m=0$L+2UXuM`8p$yAxr zv{K|{vTbNxh^>C1T0k;QS2JX3T+Zh`qgv_NC#6YSo+N8KOro`=?Xx|ujFPBI29Mr^ zF8v@SFZ;vW10wh>=}@4H2;+IrGH^5c2Sq$2Cb6Rgm4HTq8Hipfp$m%2jr(`Nh~61| z0|Pabms@9kvLVD^B>3&H0!J4(!{{S^*Y{Ae%^Kms12>wx=B|8gO@$J27dk4`l!UXk z-&Lo%M-;rG?(K`-*zwpeRJ}JI;Wwrf94a4{uGKj>?mi_Lgr}+;;){dBG)Cfkhteu^ zaH9fy6|!(B5O~wEYL#>E#%bvIGvQT$hZyos|i88tlU)86Tx8~;BH}B6B0bfOixHmL;ck$z* z-eflDqF?p59#*XaZ5q>j$77e$q6o`05{9nlRWjwy0a=zi%n8wlfo9su3(Wb~6-7|S zhYG;jk156#VVD?SXgF-AcZ=rAZ2P0RrDakFpIQbWh4p?gg(%MrQY5c!b*Ji05ON6Q z?OnEUAZy*W+vn$=z4h=rogT2@Gabe!xAGF9k8)N7hkpjfxthN5iYt9AaBn2;o`x#` z6Q)Lm&93!hfo~OxgX2R|)^|8wnA)|a;c`wXBE{>Iu*jkk)5=yz zqGdxM!Ui?uaLZN~Ay@Iag!RML$cK-{3#k(W1B6d>zQM7@RARXGE}?(A23TnX+IF#a ztUWaNwZV~8l0(hQ_wS;$4~`5P*OwMy?MA28t|lkX-{kgQwZ$*b&E4+-@q@Q% zPiwH+X1{?S96lM5@)xGyY((m+pYt?3(A?TNd2hM%jrYiA2D0+a$~-VN5dE7b|+!eU9c_g2?QJDTfIU4qZSm}0e^Uz@f_M#M1K zRPW)}Mju@sT3ug$xcb7vgfd0Osw=k0KR}9K8P{rQY$XwnXsj2q z&bs6N1}e_ApbYz_l`=p^vMPRNO?qkD&%8Lv40Q0Nb%+O+hDBcG%3#onEf_uzfwSc( zeHo$A-q5_|vc+w2SoS40!y+omMgDvO zl`w0poE1`toO?|)pHIAD*-G}AUHyELJqhK6wXuo>e0pfY_B~3VnWi`Zk`_*WSi_4d z@Yv?AjKqnpl%v%aB|Fs-0IMU1w0Wx)xbPe;6M}{WtdP11_&%#s74}`gJYMEh7`?cF zFnwAEDErD4?ILFwMR6vVtm!5FSw|i`g=$^x%*eNECLgD789wPS5`7Lkoc8-XaF~=n z1&9wMS76$%*!S(^99<+?eM&Dsk@r#|+ccE7=w)(Hwfa(Y5ym5InnBWML~riNYFa0! zcjO~dKbxH$;)u4nHmo{BZ|*17d_z|{-s;q7ibA~~U_4J(=p?D1Q_-hU;r!BkhN#Ia zV`TUk(+ZqOpC;2Mf>c!)(bpohoj>9pZUYWq*G}7$VsHv>^5Fnl#rBbz8Wi;QjiLBP zl(*pz>;f71W4OpiiL^FJ(V#;>_hTY0u0sPN7jk|aNI_}RCd^of_w*#2MI9?5W5li% z%?^6>8kgL#wX{;m%9~xh#~rSA88UpGALEb#HzeLy`nn_~jbGM{%3>KK8rj3|sp2-* zHgUMBM@XZgqOl5oyb7l8D<1+w!C7xr@mE~1=H*9;2R%x=K4NneZyELm4kZE=Npu#Z zjvr>zeA*M~48~9kZr3!JV1k(9lEV-IhJSbyXSzOg6>EbQI|iW$A5&~X z?k&9>;{dqNussYeTwa6;KPfWmKzYO|9VVYZ?d34f#jV9-GMy$Gh|jxjx13}CduE?; z1?i9THwfc$MpI~WeC0?A@d^R!Qhe5jg0{1|PL|$85%N8G?6UM>eIm3vgcZgY%!GwU zBjZAVdwL-CXj$r!cu?{Ig$6Y@A@DjpVUkoZMpKxx-<$3!J6V>^_V{CiF%A&#jZ>XT zM4FBT0Bm(^^~Gg}4IFCIG>tlz%9`OFrCiG@@qAJWW7DG|mSaDz^|}5l4<-umyO7MJ zSgw4Fiu~?;17Zn1j`3o1kBd)Os%Ngl`$6y9I>rrP=jrfPO3U_M%0>5vcIG$nCu~3A zUQrVH&g^V&?O}>zz;SwWsiXV7HjCSb`^N{mDoY$dZpTYoJFRzhsT~oio%X>R*W@W_ zOp?EY*3RGv<=!|ByC3cz=LWYAFaxYB2Sa|2tk0M|g*FKewUI7tz4!W>>lG!v_Jb|y z9>L)^lGsj!QAB6d=?!;YxK+<=k+Tjebw{Cc%&Vl4!kM#UqgsI(-rDBwjlKgyKt)v@ z6}%)P@n{=_$Yavr5O%?@qf-zXlvmz+ee&Kd7~y-b`LJlpIRKlB(+=jnYr)TL9}1bm zqeEwK%&P(FaZI+Y$2d5WacD8Tv{MxQMaHPP)-dnwXtBk$%d6yuQYI*@)gVt? zNYq+1)?YmiVGYHT5PX@m#d_K11jN|4D4N2#WJuA+6#Iyt^zhgi?}Z*rwK-K;b*Kvm zZ^o7(riPs%i>EBT;)aUKP{JJbg+EQoSpzWmg^fs>{VVGwq?qheKYLp^&Hc1 z{$be4FjAh}^HowAizylPiEv3~c=z3>l%K`akCeGjN&Bpn8HQw=Y>ls8tJ(RrJ<&uj zE}{+76)u}YH`H8U3D4ggX&!9(+J$BuI9o@s5v`maPC_-+^2M$aVten@+1~I;0ETjX z<*XcjWF(2VY=CnznD{Ll*sPf;9NCp_+bFq}v2Nmk-z7Gc+oxYSlfros*ibN&YaGmm zsxpaligmf7*m89-@iDiYvr&Y}@NiATtu1C}uzfLW9I=Ackk-CV$wGKZONoEQBM5pe zS}JFUC9lr=mfS0gsf@%yoF*6W!kyA$_D)gL8nwAxq3V0DgZ63-T*UR^E>Y9c6TQEg z7pm2Ae^=jvSZb1LksG!#kUA)ZI>c0BA@UI7ILe1{nGIzH!?H0L?N^-^<3UZA&wH(w z7XSvR-rL@rzp3x@ zH+^pG>1}C6E`EVXUyPG@6`Ld0gbt=^_AX9Jin)X*7MTFW5?pH&6p z*0hSKaITev1z-hwi#fV3Y8y_sNLVRNxAhj9iY&usFSfs;Dw>+CPn1u4HaL{d0;KJR z9UPH*ou923AU|wY{jSxvt%n`7ci!?ZG0El*qYAy!2#}uGZzrn!EvLeEta`$UswUw2 zy$p0G43wBuEyGWE3~Q{w8-M{|8$|}+h;^TjE%e@}?590t9T@IL5^f9#TNPn;WDNOa z`X6PQs!UhJ(T6>60uYe&ne&{(U5=6LAQb{AM>PClnr;YGOPc0i*Ni{L;>eV|vej0T z!M<8QC>|UrVV7}A>1W0QZD&!-7lqE3aMy|p(qMM=aP(5YK>_chXI6PD_p9x!9q5`8 zvD|F^CpQRPb9~cSZR#|#S_7ua^RQT@nOCH2McHJ|Mx+Z=#M~1{jkV`ompshb)i&|y zSs8bbm}w7hEgp)YI?qn5_0dD)so|-!R|R!ysYF9P*yDO|qJ5JmPKhP!VS<~kp>rvZ zE#SCPS`&7DP}7nCbD4R4Q2S_w+<7y1=Wj1)fvX4o)D5~-?kMy20r#9^cql%Mw14za z%f}&pBCu@j@YFaz=h}04A3aQ8136c5;XV-*W}nP88R@~Q1Najg06GSqOEf{|)6^q= zo49XdWS%<1(oEcN9MNBG^kh?S4fn&luodcMsE-zCF3_EN*p0^=3toXtXxm$J)IBkV zeBvA-rG)9XU^J=A63<1clEkfESvs~DGug}p*Vs&;5`{b38)xD9LX7~3MRD5R6XE1B zNWF%qpTJ#iKFQpZj*w`01~>xa47)mZ&dYAoP_7;KQVP4-A}}P$5eAO@)yV}YKTH?+ z_ik`h$8EV*cqE@Sy_N%jKx7?DpwgU8p{6{#T1n%)Pb8m|>x_6Z4=ahctIk=kk=9Vv zd6$UVq?d9~2k`TCD=X6W1Au?y0El;=*I*7tcxuh%bELoCzH?{bXGT(R{~9$lwSco; z4P~bzsRoe^`V`_4J_5g%|3~wp<>zR0^Dnu|d7f5!n$enZikh?0<53~L=IFQ^%t2p| zCDOxzO5Gc47YD5Fv0ZR)X5l8z#6b6wssa@6pBidK*L{4?BC+>sn%u?$Ab{#F0*;@6HGPaYjYHQwrxn**Yvc|1f+#e3%+Ehe*1lM0bJ$ila^yH};SBj*_KO zX&=?CYzefx0)nmaXz19BAT@%USJ$9K zDuRei-M84?3!c){mx_m67;gk0DX!FQ4X1}l7d166M0KaZ%d;;ib#zPeqec< z+q$!&^vUTl7fkFQlF4ODkKKc5kF`JOIiz_$X`#Qq=u$gAE?>-1>liHCOJP$fHrRl& zHUpA0w4@%zhMeeqCRKo}tv;et!l1$seUPyHa(L;HUrCe3=g-Y0Y#||Ofc_$c5tgI> zAOt=OFMw~JX;CXZV-dq*k2)Ji_9gjqJYryUyjY!%f#Q0n$0X-X&%A|hXYFvqZDylW z$t~#_U(4b?@_3u^uW?h&^rQEc_2+^?6t}A)l_aFXY%`e1>8s>}nyCtE zWSl!@EU9fNW49Adm1FP*{B*c#yRg`8}mF-=LNPL4yFQXwlYSjD6<1 zsmU*Xpfr;t#vN$hoV)ShwuOj`f$vFepTKKlT#wANo>~miRtrCV9OY8rXy1$Y#$E2I zNC4Qz;Ae|zgiToO&m6%R8>j@ioE@IgH(oKe^LgSFX(R4Z%YJ@iB!{K4$)!@7DcioM ziA;?}>msD>wBQ1!HbzisS~A*tLs(>_q%4rgP*FyCpTDiLPQ5j#lelr6;6HzBWu1C! z+Tv7v#rfNcHR>&C^z?K7hC+pUJ8>`l{0+q#^_F~^&)<%hueJgyh^M~O3@8-KdWWlJ zV%+}l#TbPy7m=dn%Xob_k&9`vm{|~aPM>0|C58V}2Yn({P-2CTEt4r;m+&i9FI5nk$#bb6wIN3w4tJCV`y@x86 zw5`E}Ce};w!)D?i5lAH_toZJ z*cd-aufvCt8n)J6>r#0mh~}1suGVa8o+`eg_S7m=*S`5b1w3w?iw=|`5MdbpWvUo- zu&u8B>cc*n%hJcXv;Tsy&&y_X7*D($y{;-28%~_I!nAELrK}1Tpe8ker#LHv!#c2wg->!l#}4l>be$dA6#WF3ZK zWguh@$l5q!UonoCg_Zi#Gg3bqs(Lz2y%8Lol)l8cQ2@CZBN#83QQ=b!vgzQ{bfbQ# z@)dHm(HT?M>TtjZA1pjr=5E50PJ5OVbYzOh8AW_vPr?jfk3FeVa3F|^8Wf-{DsY-_ z+6IuJNa5KY1CmC};w}N=SeIDCAYNSOYLRFZuhnmvY1#9pFQB&0v$f4taR7ChJH&Kp zi@camNovr*xz@%uhV@1{aR=DFpFTO4H2V=`Y36JT5<8WV^a z+$ctMwGiJ}LN0QN@N#E0TC7Smz50T~WGU11DNXsccpg)3c^EKD>m7#)4WXj2a8_!c zIjjt~oI|FD90ukImNpt4)e_d=;B^0ZDk-k-OUJyr`sz;Y&f#fp?Nqm?#%lZi_GU9U z$=ywCK5c>X(DD^nG|lD9Z|(4w)6+%?!x7WL`#Ak%C+u&_6&bf#qQjIjNe$3Dq!JaX zT+3ut-O-%xxir?MYqEah9In4f-KXdBgvuLe4#R(tJ)md#Eb&Vsv5L99=N}H}!!4-t z4*O%;9@O{Q7n|jasj2%M$?@;YuewuHceq`|*XqFj@nO-tKYw%f&iq|s*X*mENon6) zT$u9*(_D0ai_E?4yYtH{u}pT4j4TGPsD~lziF9Xwx-@s|=KNA?t8>Jq%%_wrtA|X$ zYBK=0w0L`I<{q2t8*RI-X?vsXS4NE;D16GQ&faY`Lkf#nZ}#ro%tG7lyRoBAb8&dK zQN@ke8_!zJxrL8T2F<_QzPmX4W!X#Co|oC!-Q<3l&PJu&?7f?`Iyaljs-gzyjfHRR zFSJ)Yk%r2NIlR*huVC7-isOVR(AVCrVZLlDeyuj>O-w4$(iiz;6x>4-cORAzwJ!D4((adRKrFFgtj6d2U62n@yYp z0@vjxLLto3jk`0;EA4wTUu`ceJy=*)W-gx?-z*N_N(jlu2Ft;=uy0GB%gzmPo(R8eEvYF%LxuHr>j7_$u7e8uRNkpKc!! zB%~XT(vgBo-IirfPv*#wR}E5sy1UbQ)_K((y3`F%-d*3pbJu>kyE7Rz(4oPXFTqZ; zi)krG$LkX;p4THXE;uf!D|^GAjs52o6BMDb-B-RV(Cl+BQ)zlWFK=bqQDok8lkCl~ z5#QqK1-bKe#sRN0XXlvK_Wl7`cJPL=-!VAqH>`|IjM%xyq2|nRYp8EQafON2AZJOq z=TD8^IIARi?aPud2`Klp;!Lm2XIXxBX7 z#3}|u@p1*@(rJ2qU%AznVP#2GOvMJ9YIJ-o>f+EO=GY~KUhQ>Rn0(>!b>c?>vszJo*6(Q)Yh|4P zZN+KLhp()^?LC%$B+n=hHrVtfYlGEXZH)t|H}aET1O!J;ETYyz5o`E^ensdal~H#; zafNpDV<@pBP&i`bShV|Pq`x}-+Id4#gEB|{BD2yRY@Sj*phg+XD!if>~00&3e zp4JwsR&1I6!CtdNIXJ4@DA(7z*_swT26qhktl?ee9zHVe`m!H@@zu`uI?_xv&Ic(* zk(73aMO^Kyo)6CGns?u?zWoM|gSBnHM?0IAaJh$Gz0IHxHrF+1@$!BXR-G^Ar-G!B z;&e38@b)GrI(s24-<$<#1u!Fx@I=A{0o6lWp9|E}0JZ1m2Ga<>0%q?L_#9yRLGn7N zg{{iyl6%wqhjQ6`hbNBKw}rP(0ObM&4Q&Yn9sK1(*Rxp%g0;mv*;C})%T;8TFVC#o z?)K^39(1=u&jFPc0MG0lW*C;p;Hb6X-x45wSX4f|EQ`47g_Xgd*>jztW*oA28Q8L@ zu2Be1Q(+ftYT?8s+YjOzS~94?Hpjb8Md0^y1QFm~Apkg$?&C~mApfvIyR{W!VuhP-GCMtj;w?03l-7e?X14FCBnZG*|&glT0VXeMjP ziQOU^dP365r)>)b9>RTMdT#YL5qqS2!TY(lB8gP(t1PjwIh4g|a(W4hJ+AC9LdCTS z{E_AsA;}c?50K_aJXR3TcTwpQH_%_gUszal^I@k;?v3y*Z3?mo zmlJVOp+i|4V+WlBKY`ZcY_a0006p^0!%mh^1h0ADV{Gkuecs~M=0I!_PNI-O#~eP% zJx_PVP;}T-J@i!8Pl{?8yhdSRC7zDchLi;dxc{bgyixfs6zInR7$Su^7gL7v@|(QY zoh(^>^OS`;wcv7k!jkalB91WSjf^po!H1QX3W+rYu2o}ZV+&@{2(Zvs&DyK5w-Zw; zMFbp9*xdGeJc$I&At2}=8wJx4(S++N_E{1V`@*yaC6!*mAkZtyTTY&^Gv5l0c4zyo z06I53aicNAOJQfp;wT~`_d&8Mhn&$Y|RC~Oh1UF+4CdI+;x z+)GCnE&T(K26ltnZUF&J1Y zp-IwX*_+>ZN&o|DtjI;&K1Cq(wLSVn2zBBjBh}Gcu+F9^wm-iz@+Bgo`#gt7y!-q- z3hUxv=ZQ|A|IqTOm5filnN9VU{^4X(xmnkTPem3Lbi^LMG*bMgQ?7o1oas<2;H`O+ z6ec_$-8V6ww8kcnHef7gbDUC>%vfLF_1sV8NL~H#F6UcswVZoP|4=PwDIKSJzOWy= zI(k^wK@c?~P4g66%8VwdC+?YS!wQJk;z4l5NktqE+u& z6IaRyw)vBP)jm)8eeI>bhYB>($KF!ZqjmQKG_!J5W#+A{rW!t5J`=*1eoT5Q2CG&q z>iL%f_FFc8`4)cN1S)lT(3N)bQED{-wxbWCd!`q>l83~@Gb=OAo_$4sA0vnojz!UG zu|8H_PB79GilVQ^-doHm4rRsC)M78@MMjF%hzwL}QJuGaegk9)PLQ`qD&O$+Wbd^i zR>vOk$hYms4d3HvLnJb>eg8HgIV%sALrC>mmP@^#+B2k9`ks#nz$0d@h0P%a$3G^U{MrZ7Up;u#~ zdYj%~I{2OmMdzdtxOdRpP%Ni^KDT%|r{wTfW8!C0%aA$U;(j--HV=?PQSdi$-xH4W z?)IkUhk!@kHaA|MkQm!iTXzmQSf#~i8pKX#Z|jKL@4VLVwJ#Ex;|QeXIJZs=%$wQQgSkBmb>#>@60H^(2@ zK6jjvk*0RNd*G4&d|>Q03^UP!+u?KAiGslfn-PofH+HA3&I*jU?B zlpHsf=>$$RPE_W;i|wQ~&)?yh77%LIvctz8AVzX!v_5QhMfB zgck4Jtqj0sUvJ~+{^5~6k%1Sz@~g(Vf2c%H1pBw-jwuhK-Cnj{O4c7Dxzlf>u_kT$ zjipDpv}={3lMqz^>1Ya*W2Co3mqF+1DZyglnZ#cgATU%RSzrje@g+CckF zq>WN9dJvG_e4mDY=IFD*`#eM`>Ev^0@%NCG-&AJQ=`Cgzxm3hUz8mVh8~<;2@pdTdcMu&eIh@5A4$;e znlLz<>)7N)bKM|Mf8Bi&3>x zDRv4ow1Q+u4;P7t=LQ|m9WBb=Y5n;8ZQvxu(!Sc<(VsAR0`P=l)+C-C zU=~OMt;Epkkzpty$$J?k6gf1;$7Y;tfv;s|ZG;cb>LSZaOZOcme``;)R~Fj~X^GaN zRijw)9YqNO{)M1D=VA(sA_#-WNd}iPsul&)S3dO@AQewCv)JKOFpKnuO@35_!q6aq zmZHOl5IJ(Kba`lS4Ya6Yv}$ zk4i|t=7}L%=Ws>0(m{Nfn$HdfFw&w6Z6iqUwP_$YaB)^>Er zjb{qLvr7Ow1!l#S*#EVBXcYhg+G~yyM<2-^4i4A$p4rvevG+jq7>x>I50pSgnuNIk zS9O#?{XBzVY+{UX`0PP1BC?c|k5iw%^0JOYri8NlT0?=zv0m$kzTVC+s?k@^#gs?d zl4=P)CbR4Z^qnb}b>4vkM$QfC!>6&4&&E9D(D9ZB?Xb@n-{Z2>>Wj!!W{oGuTgM$P z-^z*iB00K>kJb*i*VaiKcl31a2xGvH6tQV+Mj+p$UEEUb0W%riu^cD29^8JQq+2&E z@s?#WA)8F?X>0K2gM0Trkt;Z>O2(Mwm8F@R?fWw;cU}*JI%~1|`1GowT3N{-by>s;uXN!!fOkP@j%5UkNQb2hxb=>e;q5M>pb#b9K&}spV z)+Y2^+EWYmd$havEwza1^78=x3xKAk;FGYSAVRRi}>U~6OC>^>I1 zk+sd*Ftq|6{jTNV3M=`xQoxZxV9;97U+1)Z+7#1Ep6HRmIr6ZTuHDRkph+|zem$dk zot3J^7acgQoEV5{NsI{P1d?=UjGy75F}tb9UT$xaHeN2e4gN9^t5U5vc}hi+sar+< z)+&Y@&hnf6(vdWQh!d@2M?#d0V*=mR<^*cP#?v*$iSvC!UwK8|W@5+6SA5^lS5HIc zDX5C#nwo5Lw3&b~m}&M6ZPZbqXRXKa4m5FF4c>p3)_h)5{8VK^l$>3gWe*ImCNqlh zpW0uaCuT|YG^Ej?)nyXW${BTHzNF^Y_aR}SiLX`1QaT!XEA|uvGmI?4a729>s3K|^-NBi( zAt41Eg}_<9;Gsh)Xt8{8S9iW4-Go1r!i1s19$GSJlJscM0YUbsoXkphYOpesR@ghc zfCIY84eu8MNPPX~_*aw%akYE7oKb3=sEnF25V#ZC=9MS%Szbtbx#};ke|_WV%=(kH z`fAr((%;ON=v~H%E3p+vZahGUGIyzO3<_cXmD#V1)zR`ni&OX(Zce?`y=%=II!{6+ zb7nG_Kp!926&z!J$rO)E^w#7g?~-#g*0s60&@+-a$m)8iI$A3n)RJhP#X&2A#<{2) zdvBIirNF2(q9JHOKy;dob4n|d;Z*2VxTDyBmcz&M$*QwO6Ppl8%jVOBDcR}aaJ{lrqdzO`#D*{6IV+JnSWs)KqXKMCy`=<-jVkEN95 zbY)*+DS2X%QUi4%5hA+S!-{8_CPtkqYFTG5PP3EfP;OaVy#8>WFCvT$gQ0z02_2VNFZWN0_(7yKLB1ftQqrs?YFfZEx#Mgo7VZ#S}}?%MwR#LF~M*I%<>a?@VS{dds?F zYu-w^LY=(cgy0C<4+VlVd%2&8Nk%hRlF93pXf~fA zhQ0@wjnMw!G5Z^#WTi|u@$9U$fc~16AKaDI5X!!Vre*4u$-itFZjg)YXl>_3z7G42 z+4oUGuM=orhfgLf2^T7vLnW2$@X2J%%yr>$Y+DX9J8%rqg<9zmL>KDxBRcaO((^f8 z%f(r0?pado>C+x579J_$DMFu(G^)@%(q>W6q_Zxv<%sJt((`9V1VE^tCGuE}RTF4^!37>mdV5jq}aAa<@6(T32**5X^Z@3)eG0TidcDWZaGrd{{NqvZJ=s z*;?Cp<#q4`q3@+0qTlN_C8e&YzIZ7#> zJiu6s?JawId3Ko?>(aMWZ``it&`8vG2=J_T4)<8{sH}UODI-d~f`<4$+OBpBkben# z3{-rwy>)!JW)bdWSbV{WN#-Eix7Ec$t#`wXcm;QD7&Y53kfxuZck9!thoPzAlgDba zkRNGle}8MIGlo;J7+qAmrzj(j!-TsobXxlxIIHlIo;=ovp7!_8(S966NEs!7KK+#K z48v1#l|4&{J|fX*U&EDQ!G2JB9_L;pByStd44(v(N?#a^bri`tRum#VNZDtzhD6?; zSUp%ujqNBxzgD`=Qr>AEYBd@mRym7n(D63Z)xA&lkBfTnUo0-hv>bVAvCeJMI<*_X#Y(FJXGe22Pg#eVgh>n5a2r{Q?=;k8XJrO-ZB{r* zX{^6Vvd(tcMI~0enzc_;Ywf2}iSftVzyzNa5i*Fd2(4KVg6%fgOY;jrYMhZ?+p!y6 zxC2OQ(4D65h`#hVcWpG;B;Rc5S23hr_ba-z#LcTvnsh3D|Ael>;Le)=pS^eAYwK9n zMc2RZ6vIN;U~@6Tb`oL{3jsDe+$P{$44$$K;<5vRDM1{E<@sjkcOL1y!uh_c>h2mt z65zy{bFaOY=ZuiX=&r7=s;;iCuCCVmaBb=q-xXmta9ItG76~{mw@E8&me*zUY54-V zS|NxETQ*%mm{87ecxTsY*yFf*7#=Fbq*co!q!l(KnvW!|lN3`wNf>E*m09!c_;vP< z_vD4&vC--9=+VquDixuE^ke@RJ&fg4r#XS?!xY`waxyC{FYv+~r{G;%j1)A)8FzVoHKLDC}Tas+^(zm>A4)P(taV4)l!j(xT{DQweylHID`Z0xTmte&(2PJPQY%-F( ztk0V8q}o%AWmJI*WRcp30q_OB; z@}M0Z3%*z-K}WH;9?5K829By!BA&eBmls~A9jJhHwK^l_0Er`0j1HD-6|O$&Ckvj^ z4Pgj;w))p~S0>s!XdPjL@v4BJkt@rg*TznuY+gyOVPY%;`zBnMK{=JqOb`^3-W5N! zGBF1S94m=b5f`(Ud#o;%7`a;+q__!3!w(^kOn4Ewc}FZc*f@M;z?lu>#-S~WQs59r zW*pIajV6th?vX}u2^dkNLS#yw8-;!30l^AgI3R6|2Zf^Mt1bWYEkgOz^@2ZiyVx!o zzNrr&r(TX(@EDN;?4o>>k9oT2q*Fc?O*GRCQ(ePJwEunFzt|{-bcki!GP7mNOXN;RMIh$-}GbXuV9xcijuNe7M zeRtey9;OvwiOFG}Z*muWd*->dR^@B&ADS@+|k72Fj0|$v=AwaJ@ zM^%>n7XE@q1!an8K`th+64=GI^V^&jMYTtd%4h?h@1biTx88z|6|rT#H0N8i& zX?YnXU74JLe=+Y7Mp*okx;Ppgb2zk7j3GiQ&y1yjL_;>;PD>O;IhNNP5HN{ZAwES- zj3%p}dxO5>4L+@9K|Uy`C?u#!CYYRX-N4NUM4hy|{g)ibzyPM>AP_EoeZdG4a!`c9 zECBXcGH{!S=T{|Mis|wt<2oMDrpL$Q&Q@@}hb3HE%!G{@&3Ix?d+XBmaPSV*XPAQ z%H#p@l)OC4n{;6;5DT_vcnD$5`$RypdBhG|avzkv4jkzj*;o)W0T9?{-kva4L9<|N z_ZzH`H;Z~32@@1|JL#|?JPc%m7o;m7Z@61IE}Ql`du+uuv2xNtPeB)~s50DHYrP}UX650z$ysB7?!^8pMA8}yv|K48w0r!)Sk!dJB> z^*IYr7fbOHrsLAvN8_bwErF{eaGw|^Q8O2VdPq=$;uIZ$j4KV|iEyryT%?CI(u1KC z(}vJZKJUAAxtq)@?H+nxK*|L_0(fAIf?+9re*x~#}+e;Ko+AtRE^Dc5aIRhjQO(Ut6U z$?P!iCd2(}7f8#qFTo63as(Kch+_K__-XRzou451R(!is|oFiBkKDPNR06(2us*f833u+ z$sl(DN|2F!U{>k%`uFP_KduMq3H*<24>xZl1*(=a)(5y{k~it_g#7^xY#x}?zr0xm z%QOf`(c~Uwq#F0}qG1BpVCa*k~vtO&6crJ*xbPw_LjAUfTW$S9mJ^N=}ox(F;D-@gnrN6tVhE zuI=F!f0U4%V8P76J`G+$w!~5|%1?Q9qO4oNWt7=RUJ>!@wlRrzCthgwtizA3&T5*| z$3|CnmbPj;D;w)kiwL%1EdfWCc<|9|SX0P*iZ|!1a8@AAA?4MSCJu!RtW-*kRrA^Z zqQv(m08~buh!g4Lc{!p>hLulpt|S?J{}8fc5d8z*CSLS=av4Vya0#oNs)NK7jFLl- z?xnHW$8{R8^^ABWf?!S`c) zKgM@nBukYp7b_&OB2?x^G=UldJb)P7C){7GQo#(sf-lOq?oj?x@@*3O;T=jNP4bzz zQHam+&G{wgadHsKWKr-sg=rHLkxrblK6EqZ#pg_&6QkWP zJ9|!y9v`%LvHU;q$L2ii$baLh6#0L0BQ~m4H<7CLLrI+zNx$lSHHN@a+F2Dm+V7l5 zgcHUXijsYh!vA{HE`+-bK^a69&TxSe90(#*H&TPZj2f(u8urFwqKr3z51`Y)b*c_3pDnK64`%M7k|G>8WzX((fMgf!)%k6a8gO26pZ zTAAMwpjI72+GqK{&8Pwvc3qiL37>!G^3$W)hnQ6+XQYI@7g}opp0fBPE|LQrkV{TQ z9uT7W#8R-Wa2?*K$+DPNYMuxjuvTNe_i@%QZCxT2yj;Qlmr0N{t4So3oVh3OppcEsj7)&9{sKy^H}0#z^6lykO`! zk(Cd}W_ig7a=w)3EwEOe&ibduO?mOezmQcY_tvovX8S&aFJT7zQcwoTfC7cQzpENOe`(mR2K{REc^(nn1M$*hY9P*2om*l$}2|1H5-9Gt~h-m@dlg3*=5iP6QS2|6VB43;V2$|;B8A-wFN5HX7G7z8=c z?mK~sLR}yeF71SmYSEDfVA05(UjzlP`mn4T06A z^(qno7Tl2i5XgHKq5`gH+9s(cQH;Ol7Emm+R9bDEW;Ha z{B1blhi7Z~XDsRlHS$j7-`k+Wy&_{}NJe_elOx|fo-41UN7MNd^eti7(g7$pn}}$p z((($L15K_k79NMoPE?$WFQpQtCHI0Y1rEnO16SAT9Fam{F*^cN zC8!CT$=m@9&z|evlspT7;omF6gD49 z8H5?~P+WXp;(Yd>ZfeSQm!M+c9!xXk+g%B1klE|<S`G4`MgLZK+MWO0R7Y#v>ub;aCe6u}|ft9o8|9z%B zO;t5pIlY-Be?M*o!{7q0V!YF@{|N?HxP7C?e7~`ln)`r{1!r(>!_ymM^7^!s3QAL0 z4is&(R7uPsASVXswz=d+i#Azrd0g$Ze;msfEzaKZZUPXbMvJCqZ-4Rly!F0Bg4Zzp;1@dNAy&{f$M_VA9Qzkctz;nafrd=aQ+I)i-{?&j2jj zRhv^*#xAv^QtJyDo+M;M>HDRnP1#=5CiHWVWy+d^j8neL*{6J7W)MytFIgWK7k;gLxh zS1ax0v0AW+ewEJq*R7)nJhRj18-!Q*Brvye2lR^w*oQw@m&22OF-@ zLir!FRZLvY``+YE()HiOZjHU~FiquqJLA-M)pFv6#5aP7#$uE=VHwTyh&U%; zj$_sRaiJG@-zO+kBUj3s1Q3eRl`DH2$m9^#e|QvDFucIkJ?6qeW-&HQgP)%k?NX-y zSRUv!A@q^oGM5yRt%tPmIAacHey4$q4glVp1uC0tO7_9*5#eP#o8K5672@wTzDFJk zWt(Oo=399Zb5;Z*1zcqpib(gv$x@1?K0Pv0dEVy*i$5Rf`=T;EG9O;NIECjlw1X2f&v~x+(cXMISxlV0uL;L@ z;J9pK=bn8UwskO+hHen!rs)@_iOiThF1b4gRB)8YexP~&7`6>#6p(&{=relc!ab>^ z6Yyrk0Rc2EixI)i5X2@X7opWMq(NVX&+#RlrXE9JY#=a1`JeM<>(yR4LLkc zRF9$fwN!!l+x9C2p8K!ywoP=CjyQ~L*5y0>cK*IM@-HO&6_D>xe&q*dbw(CN1*cc2 z1wc@a?~#L)VEJV}<2TGDcGO>|n3tH{dUN0CyN#E4XO*a1rP**&cjKi$R}bm2v%11W zCQI9!$AK=LgLEY6)4XE<=_W zKHpy2`eA9y&aO#m`N*|jy^l;SdeSBcZAtLEVB|!ur@TCf(i>)80Y(YP-M1q*mIdlq z5P~9z2w!Y#haq6t`KT3TY-#Uub9-fHZ7zGgy_D5){dh~Gcf&+x5VZe+`Gr}bUaP-a zYGB)I=k<2ARNq+Je7yr;d`@YA!35NQE)I!>TnLLgkX?spr5@u$05#hT$Z_?LRWT?uMr=@4R>9Q<55m><)*05kX&>!sS=W#YRJzIR4UY{f7u-I zFH09za#BB9^ydK6%Bqh zwq)}EG8O=H+u&w~!s&HbBR0_|6QO7UC@P;f^|M34Gz#aG8`~ST&0Kcd{#PB8me!Eq z4tKAz{M_8?$Bg4KvNmM6;<|tmgQVSrk58sU6H&OcZw zq|!XdKAc=0OWfs$D}7%-J;4_1RQ4L@B@u&((84NCYiAos<*&b1H|n+3sZ8xe)IU9q zz?h>J8R&!*f{E)&Ff7>@&XjuAjt(g%pD*=s9DTTwHuSbvxwkd5ds}VZ$R-yl%9!l2 z1r*4QJ6=t6qQeJ+oIZ~JS8CB*DcCFAP!hDrQXxFN7b&SIK$VbDN>XTBQ&V^rn=7W$ z?%lO7$N+CLPprIleW@DNvdRDbR0ENKP{6J)(UdJm7dKH2t4LC<51k5xq%O-KI+F`b zY4Hc?_a#W^yasB2#KF6@w7nyl25dCd29KA1z znWPg!$J02vaS$=YUIx;?vG43}?09}X74_4^(=h2!baF}xY@kx=QB?N4S6P|6CI#y+o!C->}F}XV!qB01Veo*>r49O6J$uhVEao_rJYyTIf2J*KWsn*>;o$WWj z4;b(eHack9SS#76wy~}+{AiakPcXrI(=(YX^C{wgXfBsC6km8cPopUeCeECSsOxZe zMBH7KybToPI*mdZZlHKkpJ1*M0!sek;QKs};tP8_`zj!kA0+{{4v}7YfU>Bst}LzZ zG&F~mlL|U+_Qej8Y+TaI01g?N^_5_%CSJztZ8)VO<@y)FF=wNS!KGe0TrcM*wj0G) z${LGAW(`+PRB9zCD6&ww6>Kqii|V&_3o8A>48g#I$lALxqqn2E{;4zx_DkzOT$eQA z&*DO3ab>Hd$($qlzcHY_rwj-na>%h+{tZm(L6pO^D77ff0UI8hd^>Dzp=Cd{GGh%B{Vhn|s~nly+;ipBn4915WQ$w?PZee<4zCwVGXI1Olmpo=(@KM3qz==~VL|54s?W zJimfaLjjh0&fO`?)*#aPg$QrE3}vMnexwSH`>>&Pqc5#AXp}RQI%^HM3Jw11N$?cw?HEbjf_AuZF%ArYFU? zMCzdPjJKbj%EeDoUYu}xaP|KFX{*^5yd_78?dXBW(Nl*x4OY+IH2h5*fub_>8FHfT zO(Q94S;7N2{n>c{4jz^)C#p2M$Cyjm{FLeSDFB(W{>q&z+BH`P6=eTy`Y!bnzGh6x zrAi)Whm01v1t%?Js9`3FJb+7`Qg8?Kav(^NK$(PX5)hf_xEbn@mI+#jAaB)ak$$(& zi%(9D+6d<;WpWTM6+AuPZ=M#*UR@yOADgp2i+KpN$nJ4=6aX>{T&s@O?ZI&U#nRRm zw?*otOtyH^fhy7_7tbM;^cXJj*0C^u+9>h?7k-+IvrnQl9liH;*N+sRX&@{t{j7|| zA(g5abH;JmS8n=}s|!-GIOKTW$B?2OcYn8*YKv*>H;n!exnfg;ig;jXQ1IG<_`qm0 zbBFN15j)AkqWxf!BlHhC*9|7ppW{L#J@Lobh{#A>(-v;t)Zvs1qCsd{fhbr_1Y(`$_DN-IVANfPD6!8HdZKSBgMJBk}{1mN+*N$(%``;szCX;ZJtA<5Go&5QbG(FhvmZ=)i_Z*gnb;7bk@10geC%> zi4Z~--~d72R|dV0D2Of#t?|dZgOfv;IzSOfyc>XpsMuao6em1S44o5Q25f<$PqC{K zF2R_Y{AOzMEi!CdyrMNC?4~;FhX`16(%B03M75Kg~;1Bz^Cl%i)ge z;UO7I)?9uKB4rRcqTqS)HQ*1p_*yKRxDz&@O}qD6(2_a7f3tEcc53$gmS!oQPG!0* z)-HR#u8+n_?H2Z#kkLchz_gah72nNHE8S~2m93n$FV2z8<2};MGW7?nB7}0_HcS{u zBKK<3GxIKt8^7d&k(1D|ae_rmQ>>xlRFmgo&zOOcHa5y+T%(eVi*WHsZizvp4u9fp zwQ%7LQeSJnAHJ>hdCR`Fr+53szA0i5kjN)VH@1*&U9~O`^nTq=Bz-l0u}*7WPhHoTx<&v8NS`%<+xzqMKDS z8>n{8%Ffan3*rka_B z8TdDPoS_wxLoY4XA7d{pCQYKf?lajv8#?baJ0E$=Hr716?mGsS;@3Z>E?VkU8twMT zUhX}k-yG>1#~{`HUN(&d)JX;+$V&UixU>hqHDpwxNfqxY#OISan70c-XBv$bg&LSf zv4+@D2kOc@j}tOsQM74v(M=@9hT5&)WTnn!wPLUg5t&Cx5>{lxV%NqbE)H3h2qi?N zG0T$t<_FMX$8vFRI9?O_Nb%{15vxGH-pld|ONIba0^g=OxRUaK_OUC|XH6FB3j)L0 z&``H|*lNV(Y`2BIhy$`3;ow*MQx_k3fP!5#Q^ldlr1^@Bb_Y$%gfEkEcohifl=5-V z%3JHTi<Fsto8;oFD#zeuO?$?$U=`7ubFHr(`~?-gjrhNEoLL z#!88yQ7~X98|k8`*pmv*1TfMi!p464>B-p%?jb_bG+Y7t_%TifOdqs9CbiVt%?jw*0_wIpqkJvotQY`0F$7&P+WfF$O<5k z**ZjIBpIaV8P-sI6JVpT{0!3{tMGwTlK#M>w}sHOt?zNij^WKqfZ@=42#4O@Lyxc! zOwO-?JaqA~B~{0QwVgo<7*l)lzcl`^0b;*Up4G#CKoA8|>=Tt9*Q)4mMUy%HhI4f9 zVJW)Bs%g?_EakMDS=}&ylOoLB0%;n!DhgT6^1gaIZz^eH)D~*T7mTH`Qoewcl8+!o zWT7`<2u9tgT^XG9R#!&pXO$HyQGP>E+8 zIcP!yqDCE9AdBJc*Y*0+_O`v#WpEmTNL~Kr#vtkOuN#8@Gy1UilVODZ zA2IsI`UUGk&hn?c!-&!`WT}~dLyXi6tPmT6h{lMcA-4+hqdS)60GBXp3f~O_T*fYf zDNa%|j1O>d&c4d}j&L`)i+4BNb#zNY;v43pFFV53r4&{eRACif0d9KqTG#HP*vT=a@M6aroNtCF45p08#!sFX*wSG~2iReQl@rJGSC;Ophj+yXzs&}eP zAw7oVm-xqaq;u60`!`kYOqI*@71#=e8!d-0EQJc9TMvD*2#pM}Jl?QgmseJoFi~&s zfa-_Z2ksH$MF3*9Vbr|2YkNA=bCz(>3BVGA%>+}?iLyr^9 zFFav{3`wMM31g6zNPynXi-(P}7ggzg)nLG#n*$*VFD~xg0lq)UzSCz1h*cM!k z2qBQoTwo<)Lj^+^kkk2jXvZ6n_$*jAgHp9JZULp&>^T4FfXwkqd`&9GM?JYAc$Usg zvm@z%_JvBGuXOQUM&_Hn_F@a2KmUk8viF!c%E~E}3FaEL8|yd^B(|EEJW0r7f2O#} zAti-Q#M!y_GkVfa+G1xZUjWhy${*7rl3^GRk|C&!NyA+1z+k5UE47}AsWI#YQ$$BP z9D)u~ThPpKc?85I8+%?poX6nqAlXYpc^o<}7F3x0u@?tmHa$9FaRv%df%`=bVcif& z0T=zzB$Wg}w4#9`{a+DJmM~@=;&RGz7serYce0$~P z^#gpo-hA+>`k;$IvgT<+q9v{_9%xZl3P;-RQtWT9SMF49Wp(u~;C8lZcfzi=uyvZOy|c5jegm2j-cQThZ|+iVWqo<$hH}Mj zFTCEqp>%A$wz{=;mvTGXJ9q5$#_PMl`(fvIi!LRSul zz3B<%%5M{`pQEe!cawFSr6x>aSK8?^5ok`sSS& z{Nu`c{nZTsbG^BX`nnU>?ljnM(SnBA`4u7y(=2W$lNOg2UcYR}q7R9El!iC`32skL zDot!(*S22%fGMoLiX`uNLihrAM!W*F*9-4Hs zEKZNc;>P+C^Yu|);u1~T=km<_CFU-H8v;AO&R@c|KyK-yuMTn)>%w%g%7|tK>w(f| z*Mw}=zeio3p2{Y%;=tbsM0#M15?@xH@U{q|wUyXBfXtaE7D;beABvADCFVi0wU~B{ zi7P0Df|43_wuskSna_NIG>+MPEVKG|ic7u_M~R!Q}y#jWp*uN;w*IuzhHD zvtN*kqm?ky*rTfp#cxp1q{^&D(jvGlHb;8kcd)=IH=#tT;7bA;DNZ@P?b~UGy ziCDnKg$&-J%dfw?R8S~Ie_R!4Hk1myXrMUy`qs^bfuj z>x^_-I1vS>wN%V7TC<=YI4CL4bYLYukOk4HH8!5%#L8GeRsz=r(0Jxffec&pL>TxS zmHuD0eT7UiosY$dPdkHzeTI<;8A8v3+r_)FOVJ4_&f7wvNVP&SBf73TQy;xef$qNW zy9useB!zBDT&ER1d?N}jFx3OYUJ!x7VJ15h4pvkypyq)MmH=U7{XAR4DW`0e9NAKa z3AQ77T8Pyou5#zd&LWG2q3NKTH@>*O-v%r6@HS}qi_<#ng zse~9omuu#58ByXok*!W-uQ;o~GomR1_)F?&b@iO!nV;3n^(n{Yd04ff=aZi_cIq3; z%S%fo4Zhu2T}&s+I6Fp@FlhVY0f(^?&nNDGR8(;C#yRPW09x>UiC!W_`4Y26*!K+y zu}p7a{Uz_aslZwDmzMPY;C)C9n@a6Xo=oGvc6t-qV7{%3Wl0Xh2D>PRpL>%B@5K+? zzS=*XMlVI(8I{no)XECg@Ow}_!B$QpXK{({Dh%$X>yXU6jUObc1y)& zZ(dRl2jP&PT0WESIsEe#y$H-t$4ZX*>@xN{(UL5;h>LmrNoQrT?;FpV@o7ReaH21t zby`&G#JgN^n4r&?C70WmosVf0^T~eC6PN?vT74XUxxA7SDtR;ngE<_> zzzmF)9J=vsI57irlZ6d?Af%I)3b)Kw(t(j9e6$};VtXc-TgYovq12)a zGC1(pO;DdjTmus{=69k92u=ZCvklU}w_~|}Ij+enyQfoj8YcN_^5+R9g$rfD`Fcu7 zUb4AVUs+yRTFmskj%f_Jc9uwj1VODwZkE53Ga!t3>X&Ow)IgARC~DjU@uKmqDF-U< zU&9Y?Y-8T!^$u!38BMUwicu~b(3+_3Nah#ZQ60;JoCOX22r)p_uQr9EdSm)`}$K$Z9hX3O~{^KE{)Yq1FUTrL?jd_#yGZzZGQp@9>!AC6f$rr&*6ybrBq%0TT(+h^6b2 zT!zB~7gjJ&l z;|I>`edJz4yM=9impUd?9e#+{nB);XjG{>R8&b;fN(1dIDl!Lfu8)5deF4G6oASH6S5J;q1B$Q7Gp)rG9h{ zCI_P69F}22&i}E0Q9C)>Q^5W@qGysG2d0ViP-Fces!P9dYDS_eQ=xMiP?KBS=J5v` z9A|CFb+#;#Im^t{z_WjKY|~vfPk+po<#5k9>fpo*c7Rq-H1A0^Ry?4DGAm*Rpslsm zHTr2XsGav9-h6t<~CDE#ePG1?s|rItAbV z*gv$~^KX0UZw(Ido)_uCpAZx5`@U?o&(BWwC$jB1+{vUDxlCl6bJ^zN!bFBtP&k!M zRYhhtnf;oC1y)3AXnP2nOzwWc7&}5*0FW|08N&^!O^g7LG*)PA#ww|X+yaF|<*D2z z%Z0}`7Tg{>JNb<(xzsMF##ng>+zCV++QyGB#~m!A*J|+5uCA;P<`1}&rh-gog3Km@ zENFdwo>+=+e}b!DPWl|?Ipo}rKY=HwIdYClkuH|2%O+C33_t8M*Use%3=Jp5hG5VY zCh?2YFRMBOw_LA#zWxa^82I6bho`uk@T85agT|A9oufW|vtrcY*YENy7Y#V2^ zb;6&V$4p09{^kAm?d}CE9{Ee{R-#3el|U(jFf@b*9O>0BOT8%LJv56C{si#?^xLV2 zNeNd)3HgvCuZg*w;)gY3Fs(A|okv~-xI=yEiuI>AsCidi2P@ABF%w0eC09cWvtKu( z^{L|?ZMKk6)l5B_s5I}wZ!iEj{skP6#v3z{+-cMxoOFaRqCHQMVjWDgm60EX;5XT%Cu!{$kBn_jOJ1VOR=*kdtV6V+)%g z)s=PJ>zGZhFa5Z)wX}pw0Ws$7u8}ZgaXs!+j=Mkhub*Acz4=@I{qgqT+`6NGE0ATd zcgvefp>)5+X0iehB#v{XRX;C**6A5nk-E-Nh7CC?KTftbjqT6nkWD=8fj>`Uh;ch8J^lo7f}P-`gL%b91la zfisB*4m*9{4$IFJn5hqPp*W!o&d@fNHLX0uH?<-kTCN9Pd8|*jmX;BF!&tC=BGtEK zdgx$kQHuhuVn6h4yj}nygk>C(i*^VEVM&o_S5!_@=gLZM4(?lVPZzsw zL?oTt9E+Pm2v-a{n(-NT*Lt>qHHt3m*(uiB7;Ni1h~yr4|B=us>`KT@-#qD$fAT_O zc4A)rDl!<#bDs)?;*lOYrprT|QCP+yp{?4^%Er3Dm&cH#hHeq@n3g=cNjipyu}w7! zf7WU1@)Fmbo+BYWjM>wMf5gBg7P~y|w0a8WABLi#I+D~C0OCm~l&Yp;xo4qZfVS8J z4NpR$R5KOJJ!3)n=ei7CH8%WU^8t=TW_vk0ObkC*EIbBWJl!fh1@6NFIY**A;DiTB z>_Dd%dEn`J1TUy#3#-hN1iO#lVh<1w?F-)a?j9koS?_;Or4U}RS$wuuC?-3PlgE~? z-0JGXS9pl@oRV5>`{(tY+D}~9=k-ix+COvCz|io}+DZH5?CNYTr|@@sDs%PpmdUBO z9k;O+zGc}iLnQvQr?t1pyts^|GID+`sr2`BL9R3|6An*0aB6WapnH6i$mP%3 zi7^+2f4f^PreEkvz0eIL{(9f)pq=z@5=)l-R-v-~+=a^%IS{R7IF7LZV&;D&+2EBN zrzgL(;If2kPIiNGP!s%~Z$M03B!HoynH&UJcxg_oOFgBL0^Pq9%3IPeMJZf4mtdP9Imzuy_wii*fSgNxzEYI<1g;e>bz*ckgH zOg;MjKi^OaTWtzauBA!rVHfBUNTgVYJ2nwOkAOQ)%mNbCY%7Ypy*ZG@-n-wsEX@8& zD&{~`dT_B>Lh`$^H+2EY^qt`xUkV^%Gj-hj z?YF6J>+Y4;C=-F9u)}2gkKsNitzR{TDG942Ycl!>3vx9i0ODQ%Aplhjx+wtO|{AA5T^es-vU#gG58Xs-Gdvu5C2c?0%fuKW4*|?-4-@ zUQVKcNjPOX9}(jC-RS6@JEio7&rt-JVyB8Va0GBQp)pePkS+Yt%Ldo0zyki=T?&JV z0YL<8H0NN1x(n4lL!=8dW50=#Z`HoRg^9yzB$AoU7!aHeFGlKeD#3 zF351)1#<~S-RvMc@8t!4d<5MLnx^!`JO?pHqulghlmd+2J2U6yiH#6;X&T5*$E}lT zr2fp$TsMg>{BDv*L3AAy_=GUy;wS^d(f!M$uv+b3QM7YHZ$IZU-r|U0lsprqgI-?=tKclUvN*wXrw|+2GtPtMp603K zut`u0U@31>ER(o#NTA$cEi*I`$O8nPb{6FzA}kZ-)Brr;%YaV0KqhF++vk{ILiPS8 zz$8d5fF(6-SFkps#0H2lQ!P?twHSs-XhqbPx?E+T=g|+)kp(6E>j#~5MJTC7ldwHl zs=uBbKr3@BP!spUJ-j-)Y9$T^xI1D`HFX;VfnKBm-x-;yb){ww;7wBcx@#s-QtYJc z0b&ErVRE4Aq)>z^5#$GM$)OObL z`qoqMIq5w!KOuiB^VGLOgAmTZ*R)KJ0NN<1_+a68`q3kU@3A)DNr$v-!SXZ!l+!@~ zv_mS#5r*>b{5acZl!Z+EzItw^A-*?YXkwo2o?}p!V9LLbz)Vw;{;O@k-#gpBA zFBpZp{GA8UJEnj|1G`CV86j)|A^zRP?>WvXoy%-ya(*?3y=yf?hL>DD{GQ8xX|*m) z{Gq(}6FqZaCZRa7izC&GJXn-hIvYT_og7?Y*F>-ZEy4p(+GMGDiGvsVuU_-`Ozqb2 zO7x;JWFmv~^DqHS!BgWe76x%x)@#{DwjN>ZuIN@PnzwPuwlF;0umnA@X?PGgI2$X= zmtANRA;t`jzg%+F!?HB0DH^l(kT%ExRGtVYCkq48Y3BK|p*Jm_cTSEVqH3V_FxE2& z+SKE-YXG{idl<-f1T1ia-0AuGFI`LUp1Z_m^o+NI8-fhNi3DmAlYm z{ZPGWB{Lkk#0baYtl0sT0H>biWCUr-B?=Df&Z()|&c<2<1sPrDa+HCJGT>}n3RMGY z4ijC%#_EwPG$AO4u{*{CfQW_jUv`)Nadmei7Ntc8$5 zR5@jTvFux4+v+plwa*Vunz+=hdx>iabN_a?C6PF^(~{gLx`qV_PJB^W9p;FK0fsbQ zxw_%U?l$c$a#8Y3AQNN0Cc*^tDjl&Dyj{DycrJXFdpNjJ9#L2tye(;1%=(Z z+#UBr^YjV}U<(1F#Z`W_v9>fl72+?a1;m6JUurty>WB3WhAZMUsJwlvM>#Wk-cLI4 z-HE3D!EDE_SC~7;Er?k#D>3Fkeyr}f;T~7YFgzm^U$?G1z8EBk#uFnJ+qnpa6)NVf zBZ<-IUct=AV&wpKcLb;vJ=pb)1~Rg5>?}3R$PFxlfNyr7bK1rz*hdU>Rz$n4W@lf9 zuOt4P2w`EW>4ECt2i?YfX|6YYJmb&MXhXseu`?Cj&L(xZ4->KbK+0V|Tw=9-&VV zzhx+KH$$#6fgq~i{(*Jt!KZJbiE%{87KAvbXzQ?QX__bS^jMTt(wr(wKOvn|9a|+^ z8*3ywV6gq7#A}@%_MouHsDY%o5&*Hl5hmOzEqBDF?F3vrjRS9#cCAr-4IJgTiXQ8* zlBK@G03Bkod}w!|8(j|7l3SDK`~hTTH@N{&o7M7brfNyoO1&@f=65_DhE8t*eGpk# zgyTgQ&#T6#Z~5!dBc8Xr4wH@uw`R+$s-qZX-paugc?C)-tmvw{liYLUw*!G}xe?UN*#_3TKVOR_nO{hU?6+_H^NzX)& zLze_?^Js<}U#6LKcJcbin&KrU#3mq|BL-GkIdt(Gn>{eSgHnt5-Ux#$wf=DU=4M!) zfNADP-EWFlyP#FHOS<3;9V-BGbBO}Oe2|-A`hx5SjG~9x-Jslo3p53gKuY+e1eE#S zknYz+&kP^>-!t=5#Q!V`{V)(Sz*;qvz~LVTyqAK(^oGCFh*hLH-t;AVkWLSi>QBIg zvBbEYp4uLxoM?;o%+;4CHwvR~J}&M`-13!XfC%r+!K{zPT@N6<^~iWwbTbsd&|y#n z5!1lS(cs)b7u|*HshGB4!1#yDp;~$f!!r6|z-MND;0vPe`T0qR8hb?q8(3=e=r`XB z^@-&Bq0ex~U*GOXBbbi3h;0ZOIV5890ZK0dFvpzkrXM25Qa&hB(W|?Bb&RrO*rt~S zofn?o*m;>LecP6fH?NNao9^GwKTmp^lbMi(hv3^tYG%J)?CZUh)v*`S)I?wy%_ziF zSh4c4mAj5&@b(jyB=(e-Bq?jPjlAynq@=4zx)YdiOMhs@_7%KA9V)YhT^Qs1`{>bI zh+qT&lRNZ>ZxN~7z07q8HeBdHl;(V2a%26fEq7L`rJz4o&U3s|vmgDTFa zDco!C%KCY(NbI-p#}s@R$e+ z&st~jcNC38I#Y_zIF{r_&A5;XODy6Fa_5m}6rY-zlep4{mm-FGOn;Mqpm~=-6}6HI zkdP0^93@J)VoOL0)4e)8Jo!!Mzws(rDh`GUdC`Ct(l^D5M3I~jVJToQFC^c_jfCI6 zIEBwIA_%89{QU*|CCDs?Vy4vB%TGh+7|fe!)CX6)qa;U4cx#c3hjXD>1<48sQ+|4q z!y&vL4fa5lA)PX5CLNrsA&M9UY!xDZDMG!HLa9=(VV{@P$8j|3%>3C>LY|?!a4Y1Q z<^^S_NWecMB|`Z^W1i?rw!ctN*kj|3Xa8*?ld5?PJp^pO2LWPXP<1HD3+2K6%n5_M zE69$UymMuP;IM^H#H1iWHxe$5ErhD^z?%%Qk&&DR85uEs_L;JT{<4Pm{)q`lOvB7b z$OB#bdYd=ZmQvU%?X`=3c<$?D2s3@Xx+5D)v0DVMbq5)5bVy;G;os=l`6&(wpSJW` zDe5`u-ip}!48Ix6Q3X7@k+gf4+je$6+d*aQRAB=b$3r!BGKV&G6TD*ggKCoeXkLD9 zZ(@a);wYSK41VIg>X&PB(30Y5#Vie9Xx&YeoU&dV+B!$DlCFzU2{wKnX7ytn*O#hu z0j8Itg3mHc>BeDSL*|M>+ym>hbAg8D!3^+5>1LAUt-cV1l;Z9|Z|9PTGOJn-gloHy zy@c%>7QF#IZqejX1e>w8A;QUV8GRTiiho#SDjPHzoqk6ky{um)Xox!sCO`Ifs%)%7 zx%}?JAYjx^SwBG5cmgDyG~QTqGO}*$J70o7vH#Ab4(t(-uocqei0C z)cm%=SZ6};#>F`lTsAU;QRBrK_F^8giE7!-s{MMXH|msfwP4?t;CB2Lduqr?Tup`Y zuvqK^)7LTM6q;|Sql*R~Mu`64@hX)PT}E9iv3(ZCTn8$Ope-qpsZbHcb>q~QINpI9 ze-J*Fpvw}mjolw4eM1Rp3pRBsL`lP}&K+ucL%6tJ-RnLa+dFtT9(L9UoBw=0v99$o zf!eMsZ*{bD`icbRBZyu5tRpMsFf%5R4D_ej zq*?BAAi$Pl21Edim0}LWQ>2!OMcIm=>$n{j6%-V`A0B={j*f8g5}rds!Y}0}MMfAk zXkoHAmjc)Da49#p+pO}ANGLarIOJAUQa<<{GUW3LX{`!-7Mb;lb!aKRx>K*uzI+Dkcp?JoHR2I^br@sb@lk_n%|G?#dZ0GE#;z($b7Fds`ef%cz}_CF|v zfI&4(-a0jAG{__hpp0c~DCE&Bx0F%V8P|e#fI7_^%4wRz0P$9FdLcG3DO+Bv;ovbM zEgE(1PKZ%+M#BV2p^?uK!B@CqE#v``IR!9_TE9@jw7&7p2?_%4xWuIEGXGRuXVj6V zuf4i9k7TLbP|=Eav1Nt^5MouE7<+w>d}(STN+U3NBF07XnD%R$Ydo0|Yzaoiufc9e zj1Hm;X!*q5oe-7xAQcq$#LUbDawqG1(R4vhnaBE5&~>HqDZ7L1E>wK+1KmeuW$Ug&aXHAd;ECv zf7R9}A3sJZw*a8_1sY0(g6T705U?33Z@3_5)uyB_n91s|F!tsEk!8x9BCE)6l2m}c zh}r=eu(PBd!U7T5lqbT#P(4mSQA1j*+4}3%)o;V(p;>&BW(tJ_2PtK=4$W~>M{R8Q zF$mwrobMPS?P^=!XBGo%S*1c?UD2fraH;`x5(6tS zk}t0i%Z7||?xLN1EzRMn6`-#XIfo>8mVgs+i4xk1AW=!n7-G>SNKdK=r+ZOBkYi?N zH#@CECKs~!@fb8L$2M-LjX72FwWXlQSXCUE$4G+ozJ;kpCm3MJNK)Ccg-sr35Qw@A3x>=>yIB-350)n z!Xt&y{T8`1dc=sg)@N+*`(AV*-P}K+>2$ONVaT=P-sK-}vZ5ZaK(*(*P zsfN)#TCD@HL`qNGd5^Qgb=X|#NWvV9hS04z@_6SP_xX~BYKm>4y${`2M8s&t)W=iy z&_@zp-#|{W)^9jQKKacz-^ls2?X`M0GZRex-1JL+ze@!Y%QCBDCHL|4$ z6sVh$hT$^P?fvPoz3qqNSfNbgVsAY5GgKqYPsSD)UcQnQOyL7UP3M^#P%|PvdESP(dOl9U!HW|R?GYBiN-iuDGVuE z#<^06GuLtfdaURRDoR91NCV{aw1Iv72yvRygBPGd@P}Zq8bx+<4;yHfFSx0kNTuDT zNF{546K608Xf)}p$wzuo8@brgmwu)fv3KcFEX#fa zzx0NKM`bi%C!(4&smHImgAVH@8F|f9S~eeX3ZQvV!8MXJ13q0FS@A`1vIpxMFc%$! z7FKYdS6$Y4KvYqMAZnzHEX3l1R_q1NKe|B6>n#pH?Yjs$>5)v^@CtFuqT;b|LBCEl zq9$|>BS<{&Vcn|GPz6&#sDQ7z;)!BuRW4}8g?YrLPm6{Pm``-IfNMcoj;5Rx`F`nV zEOWVBj?$sL75)SrB;g)O5wRwl5OtK^<#bYd928TZ@=iPD%d3h)4XCK}M)ee)s-8+O zx=~pv^0#ubcakz*8|gA=GyyN#Ol1{19?G48FSJKQo9PSDXsRB*Rec6c-s`jB^mx}r zWSoRy{stpdl@>aPe+VauMv;hzPKIy}yr8PbyJ|n3oEwmN0OINx$8MAd5PB;Lot2?A z%ZFFUu7mC$@%kptq1Ga!n38Ug;UKcN|EbCdx17Y|nTJEr%DFI5(OJqc+QVmHDh8NA z#Fahe)A8#tzZwRZVSTf-+HC|n2r^#Tp+PVn2QabZB-UZTLlEMJ@3jo4q~%gfTo|Xl zIEFH`4bhhUM9(I}cWGJZ*{3xscDUOb65=FV?zkV66gW93?_(VIQqmF8&+zJu>H(F1 zK#;1%ij6W#)MGJK+H0sb#9#CVsA$E2QS?IqSq&Rv@7ky0gq5#cR!1twF@Vv`MW8Wx z971-D|AeKO)WdH)QkxVT2Ra(E(b)0)joz#5rP0HO2D&$?2R}J+tF9}aI{*Vu1X_=you1ubXBFp<0d@%L#0VwTwBTDl)l79`Vp)@z(9`{*OtUq76KGNF+YCFuXbi1 zPkfENR{jHfe=fZInlJJEP5$|lXZHNY)zcjphGGQf;RlDc8I^^XcV659@t^#JgzmXz z7&_&D71nyR67I0f)8Ud^--Sh!oSc>olFwe>g(XcC*3Vkr-CjGa?#gcYV(S;Pesryc zTL8I9DCQK_5slwlopY%R;%JFSwqy!#MUoN)kQa=%C8~!-$RONKN+DOEs;gQE9L2GG zao)v>#UR*{Bv?3E8E5Nxbc1$)u1&|k8|$;A!;N}#W)+1^gu%8yytDmne_O!>BP7mw zgVq2JP+9{dAec7Qs4I3ayN7cfO4(i-1rk^RBNOyK{taHx^d;k+I)YG`bFK`{v1S;@ z-D7G>zelVN2$)pG7Z5TmVX&)zouS*r));(n-Z%jV<1VXI44Ym-it#XQj>h=$ z$5pyvFj=)$0;d2X>W$vYaP7Ow)iB15%WNM1@!ueP;^IoG(i?k=yInmlabXqVibUyg zqCncLtiM|ajo%(spOPKG1e2?K9v=QIDq7yZNna07&ynv?o%hlWWreuE2}<81VK>bb zE1-0awsu_g^1ZAkcpPH#S$Fg)mZ_6ZuujElaL?ljeBJGC!h8vZS;qPcK#*8|WBG~*6 zFxF-N(k47feMbEyK~C5levcG{AF~x)f_R2|y-$#jP*%JoOuhwpEw)-Hh4C#p7w2%J zUgxTLq_8hNjK5w zKou%twUo*oL#0$*Ib>wyBUeg5mOHSa2$MSeUYSM4znh`WL=?hRz8(J5>&|R6nVeepXZm;nc0Uw4Fr$CmA z@ZrXjGu%vv2}dU~o@y4z%ik_#S#3I0;NIf_pMV(cj5`XAK^jZLyz!?VCAJjsFf2clL(gW zBT!P_*bP6+-u9!t?j!v~=)j}#a8MAuh%wB{3_Ov^Ck|k7Iw7tq1R@FOASw8(aza&^ zRE{Yz6#X-@g4h<5VN*IbGz5b`E;?83pwOp&J42M7fJ-pHkj@#DTne-0B@;fsj#$9T z8K7YVssF3gOpqI=VQi9x9Lw~Rw9AWT=Sc2pFYpGBG1Er*3=@nJYdM}oC~LV8uu7F> z(Kk3Tuq=lK#EX(*6oV&DH#N)4u$5WMa8|20n2x!?94U6US~QSS{O1jIbk?-CG0p3& z9!~n493(oGHE2z!SF}P-a7zvQKxMsLg=^n0N-KVO($rSz#YgRtXaRD&@w?%U&l~ z4c@2%3z&jMdO7#8BU+HRBE`g;ortED+&2YP?(1UkwFwl2yzg>7yK>rBGI5?Z>o?<0f}Nn5aWyl zcp_{?#2IBCJrdob9Ogqr`N)wmb4bMhqqs=DQ$av>~i@0wfe3+ui%{c6|Cs zIDk?LO$Gc4F-R~OfZXmA<}@M<8y@galda|k`mUshh~_-*Qr!3nPbu3x!6gk^1kmKY z(tbo5sa6rv5Gus-2AY?yvHf6dl(o+DCy1ixtpkCI#o;v#1$wavGpNAUk7QNk4+c5K z8R?gIaExMwiw@Ew_Z}v#{b`s^)Dxr2cp9o3Nkag%Gr+QPgN)2uM&;wQv~EnqKv3aI zyNYZ;XdX%jN06gVD!1na6?KQoSL7c-fg$z}_5=bYaA4jHq5y-W&wGZvS)X!wA!Y$BAdKGktIAD1m3yU06#76T z%mfhgmYc1Vqo*8?9yrnKi$rfRV`V4~6oT0p{z{XCC|$Pl!MLW=sL(Ynssjj=bk;^d zan{L3#2eHvD#gzfjnjQ%ljP&7@H;eLkQd^sGNSy`3dI-k^@@rfK}vCs z;}y>o+{_pTjrGb1lw?g?mo4RhDIJ&tVQcyEL6Aj$74N&l)bayi5?Mi5KCDB!ga|8$ zfO_S2wFsi|nz}|@;08YU=T(A_ERx~Tmm)I-YUhA+3skgBRQ>`8sqg~2R1CbzYFbYQ z6kgyw6pyxF+xQ%WfCgPs2nni0G7dr`2ASOf7Fxd%R*F~~2n^`NuHJ?l_9eq)dN+8t z;deVYKuG9)VQ{x{f{_cib~vF2H~fvd|wI@mAS)jtm|*VS9W zk+HTwPP*4?98M;xnoseJ;CSJjmZsHc4vy00j*D&<@`u=>57Y+Dg zr_?<4d=?h#+!34Lxe#d#3(08p&@09JEMh7-i^%8XU=x~vDU`Bx6K9%S2AQf$U^65O z2CNrK^SLqr3xN-d25jA~tj`BG;xf`$OWuGXXUU^9ap*}52&02>n1NOdXUX@4Q(<6H zj&fWu=qSin=BqsR9OH7#eYbzngH5jVJ5=vWd{cE|u0wwE$OtaWAStf2xnz7m0VCrZ z=@F+ot~AlNX$E?Qaf3%t!q~EwM+Yarrln^ngPmO*NAwGAiZccT3k;~iquHQ~4xa+4 zO?Z%ueL8^9FK#RqtK29GMf#d7^bpL6B%8{XdC@I;&ubzFN@k=W@TC~_7p|LSODxSi zI$oGoWqbe;-mm#riqj24IdbFQ%Y^)}4cg(q4-ewNv^nK}#z9JO`&X#deuI(c?DtWI_C5VTs@Y4E*rGApT$@rvwt_fv&(x`^mAJ5~SLZ7SXa??U#-c3rbPVD-s zxM(rtM;wZ{; znNnC4mux$yyal9vtmW_LZ!ziPpX|86% z0Uv7SigMdL$LA?~84Ng)2G1nQu3l;fIZbV16P1_)k6`^FUX3;?g*zOL^)_oyLsDDl zuTTR9GMO)6o5HNhBHVH3mKDAN5V_`&7E5>Ua#^eioR~X6^d_^&pMH$e&X%#ht9F}* ztw#4_7b^=G;H3gNaR16+OiJVTa1Y#1D?5!4pGn-qDy94Usi0~Sl~V|Y-zIO=>tu`P zAKD0VKFF4vK=>dNd*}$eJA&-cRU2FDzYInL{SP_I_Syyl@u(5%KuS(!>xjLm>7pv) zJ^j=+$Za6UY`Em?<7Bm_#owctdyHOaVTLVwL0_Co$&pCk%OJZ8Nw%*rXn18ZB8}P6 z{IWkM$|eUM2XWzlJ_EF=9)S{ZqOw}<6{)*$iHI0>xgCZ9@_SQr1at?vkk&?CUmV~9 zWW8XMp)Vc8C7V|RpqIMy{1LFABQqIsJy6`8PZB^o^%qO zpf$s*gf&(IQBAUXHc3-o0V^n7#;}tF+ruwY zyKx{apR`Z9$1R+eP)~Q5sXXF*^C|3tyP%yLmb}S}h2%Q8-Y~x>NfFiNOj!|C!Iy8U z_npImZ>W~cQ80cTI7|@U;~~xP1S0;&|676?)WyHCNhnXD9+c6TqC}_r8+g{UYvGjA z7Eq_&y!-ZD=S-%4eADYA<=51kth~Ll3g6#5B*v>sFBAnE+5=iS`W?*_TRHl@0Q~6p z1U+)$rba#wWM713g(y7-8Bjurl(wl!d6p>&$)@0o!Fdsqt(lrX+Cq&G<;FMG(v zx58;7nS&13oZ|(EZA5?fZFXlaw4g+NKcuPD3t=x#h?o$`v_JJGM9k*P(eaos$ooQ_ z$VDcpDAWDKf6_z!D*MtFDs;<;U>Y@!k{Ne2fgI7*grO#GIxK$K@LD{ey$DH_B@ zdL?Pv#KDI<#4rXVc$P)MPQ5T_><~F_j~jZ#WUN$gw%gF^;_edx5x{W8=7l4{mBU)Z z0G>fs2&4+L9y=%qGdNo$nn z*Mc)1CL7=KB5VBV;6E$QR1zj}k@EM-^^NuAm6xx#YC9_%>*Lq9@Ws8*hbKo@9XSjI z^OenVF|o3~v$VCow8QU5zn@%SZp}l;JL}2Z`xi$VMTW!Sr?hts8m1>|G~9To&=D<0 zoU5hDjncQoxf(m07&ibQNr3^Z(Bwygb{?PwdKon1NNz!ZogORzhz7|G$|?1;d7RPt zb-ImwOj#v;r(t2Lk?e!bLhX?5s{oa+h0+`ZeC01w%Bz~L^#I|M&jL7xbgz+v5rQiw9NHLyHO`7y zLWMlUi~tS+zOd9a67tbB4t5NQKSNVjK|yuKx!gvirogP0wy0AiGb7u|6|1;ni-U_X z8Bc(=8H*v$BhQ;&%O~9hyxz)d|FP22*475R%=PoD(*sG`ibLF3F3QPAO@m4=K8da@ zks_FkGlTAAN+W!Kkx@XR`dt|jI6ZJyI|Sy5PK9gQfkqJIU;B} z+0Y|)I8JI01v?^^Rp&FJiMFzAM}I1Y$cC&x6~`>A>rcfp%Usy}}cP_Ngv z{m(30(VyrC8p^erYctnkuDx7q9va7R(9WTEgD9~mjOs^;Md6guVNp0`R9F<|Sf>|- zIof4k#nkb-B%#_>b&%-A}92%Z_67ja1xiftH;`U*5o z-XdIBggz(Jr~?s-ARt64;k8xbqZrhG-sbm33T|zCli!#4{pBj<=)p3-Z@$8#VMX%g z>d*ZCiqBuINL>+nEN1xpdp=)Pn5*)AN#LyWduZJtd?wZ4S?M-TH-IZToaL+}KwC<*q!3XHM>0oY(Y+4xye^csOd66$G z<8a<|{oNE9(K4@7naUFxqVl}*)O~-J=v=8KoGZ1|R>kq9QuE~#Un(`>I|keEgUUjp zb7jH7sk^$4FBMfzirberPa3Hc+2tgkvo9Tttqj#r4tYmRTn=vuh5f(=D?qOEQjT*JO?ozRa#AUd*mJI&36<%{m#Fb-bS4 zbTn~1oprk6$v3I*Pn;fj;`G21$D=2XM^6@9UB{y*b@$xy<%y%)6F0t|xN-4hP3A!9 z`x7@7o~$SOKXGH>$p(s=&VRC*X!~R{$;K1c_b1y9&UPAiPnD8~+#I_PS`D#7srLVtA^WfKxcV90gJ@EBP>dV&-|F4~1{pM++!#57j zH*Q>f?HWLnbgPH%+uK4T4mOKf8xGBbKg^6YL%ob zYO@Zev)O7-Tp4GZ)xLV1V1DJ`fAy7n{6u#1^{eLkRdemS zxufP}wN^`GvsO!UZmlMC0F$vI(D_AVqvrTkbK|$>cvn+9)9NNWw&uoo&FQ+@g2Q1U z>HOM)!^hdHwS^=PwFOyEC~nS1sx2gaRaJI<9!{5!bwYtNFrwG^~>p^ zT3z%NK8Pns7R#qGUR!kiU37A#i(sYmqU+*Hb?k2N=DYl}&r*A^XLoQ+yrbbWC) zMs3mcMHl6UgX7m?S|8OGUB8xGUzVJHSW5c5wj{hzJ}x=jxcI~xQE0X7<(zW$6*&#J&Ki6IgeN+ZsIvm{GS9|H`@Y41DmD3fk9G-68sj1zic)B^L z_R8Vo=A+sx$H!NWcdyc1Q*(1l?Uln#=Q0QsWbBp4)A41+;pyh1nzQ|CD^4e@I2@dv zQ(JK|v*P6ce>om~@96)%)9v58@~aM?RVOp64$i96tE*4b*jaTtcGdBH^=ntg>2^9+ z)IW!$#SXVs*WXncU$Vxj(P8j(`s_P4qAEz=xD>MT7(@_%J65gpiuR49W>S(y? zY2tXgDr3Q5imrgtCH%C0tT~&!=IpMTv%6}}?y5Q4qqgScZO!RMUF+$1UvuNa*+n&H z7uB2%Q`7aJ)pdPwHh<08d$l#EL)M(Et~uT4{1P?im#8^gv9>O}({|S#@0?9lTX+0& zYtovt!)xmf=XIgK!rX8$Hyj@~oeXa}8QydBhCLFCf%}>HFp6bJNM^rlZfMqmNr(*ESs=-5Ra7 z>E!lr4$hXN;g+M}mW)}Y|CSrGTW-v5Ilj{=nLPlq=*yOq?JXzUThezc<7AtT&REyc zVaw5B%i+8&I4hiOhx4}JtU7;NaJKIb=WU1cwv(%E$5ZE{sBMd_WpErHx1}%W1p2$} z<_J2AGdhm>+~M!mi8XJx?>O9c9Bw-fpB<<7b{uVYoGk4)9CjQHcN`8oAX(6>J5GLf z+<4z{a`M{Y_S)6`!Qu0hYwKsBzsmm`$Co!wmfkp+Z(M)hI9|MQGV{jK{Eh4H8;8%E z)RzUf4qBKI8scO4!Gijq1-FHYe=cp|gJqJfxGpW-Xtii9t$@=O*)lD%Q(9zS zw8)>+YEhqLQ?$&cu=$ux;jRO1w9H;`_XFQ(k^bK@{U5{yJd*z3ifLUj&4GN#EwZ~? z3Bj3k_!jB#Ez-|hZGsQ!-YwF-TW!KG>D#R~;fwr=EeYzlecEaVzSlDS+~7cd>{f^H zV*0tY=@1M_S8sKwPx5cKxUx3{`P^Q6PKNN;bE-rnkBct8K%L%I%pphY@)tEcnC zAK;Gk?H1|SEz*r!u1_uKLAu&mi!q)qqHOb;wpqG?NnU(x9KT(!YlJlb+ckeX>RIf)?q7Ez${F zh+$W7Fg*~P9&;u=utoY_i~OZ6(*0T)(E#antxWf$@etGN3_hgGwK9VL@Ijc*kZ5BV z<{Kuomf2Ez+Y}qagcQq%XBbLH4ywcd~hohzFYPAK zb6Tdi*!_~|vn2W~33sN$7_Q0h-7jm+y7sP*F(41fJe8T+Wy8$opy)e(1V(#(%yVY9a`(dxervE6esgq0)AuC&0^Ed z+_;46M?sFnrl+|!VPD6sK*Mp1a7}tzOn&CL74}X{zU7$W?=kt7WAZJ>lsgfVpE)Mo zFK!V|N%xCm!Y}!pW77R%@*BtGH;&0y9Fwm&CSP$(zT%kl!>o=ZrfvhYrDk;^1+I_zCHpG3lIfhiHRz$e47< zn0&vn`F^p{F`pjsy&lm#`F>-HxyPnk8m`Ir8=LRf*4PXBTigqBDkfbtHs7ynKMJ@o z9aZ(8m|~hS#q46zU1QQ+W71b+^5w=9+l~7~Cy!~K9?`@S`D@X!aMm|WAe4e`C45+L>rP+ z=i8VL48UXlCZ9wQDf4dW7D5q|1?k1lVkFW z#^e``GuoRO?M>64ZSCY2jma+>4~gbUe~yPFADx43Jff3iDbNq+TnFh8nmuXA(PN;B?SX~tdC+zO3lxcj;{-8Iiy^(DJcwoFX^ z*qCgYn0&J_*)p;DU=4=kca6!eiOJU*mqh2}ca6#K8k65OCOar5J18dGCnkF*9uw~! zlTP@Q_Utz8>uuua+scdZ2lTK_xFEl7yiN0et~!#z@cDy)yXV0sil5`L$LVt&*R{ts zjwHbvV?8H&cuwm#0^d#^20olno^3+8&B-I>|JVe`NGBU7 zpV$G#l9>9BmClv-CS=PbX3JnxN}qw|6S8X(vR@L)X-UYZotVv{G@p=9J0YKT zl7#)3kS&vt{gRO1JE1(5glw6FY?&m{J&1{8{$$rAl*f`-zKX$(Y@CGr;R)F_3E4FX z*)mC+;6t`dLjLoFY?*{?nS^}i3E3|R*)Iv@ekYy4Clks8Pso-@$d*YuL5E2?K?Wrq zq93wxlCJJwqlYf>6Y{qwls}wwi6@ZnJu%Nce6kmGr$mZasFGXoZ31skD90x0E6i1gO!~x!`^1O)L1#|LUQ7D4uPNs<=@ZTLb-lK) zDQ_pC*hE6MUP3uM3B@TAvip+0(vrcdkL7uo^l811Y0hN#B^0Mf$firo=F%8MVz!lC zQ#>M}ctnyCt)>Jwic=)%w_$E6$)NOmy8lGDp(xW zNH$brHk7-seAVz+5N#9$lY;n3LHvYlpM>n4gzTM!;y4M}J_*@A3FVw56yHh6_DRh4 z!QfcSnB*PVG706JBow;VwCOvJNU_!B*_TA8D zo8l>Lij}kHt^3j#WmWLL(=|h*hg*C`IR=>q|diWXKs`4z1@0N zt*cG`@HXj$ZPEkVeW^M9owTXYWiBGnPAGXOK)h2&bo8r!G@rh;> zLpfs|vcWrKYj>z_r9(D#hj>({74()4#R@x=C)S~wln&Y59kRPS6cg-F9I!)tuS2oF z4%yBfssZVc9o@0mpTX1WLEN?C%UvrEch^C_bcnBZC??n;8@WR{V;#y9>yTaCA)B{D zHgAV)-VVj`I%NNLD1O%=`?u2}x+1>aq4-^g?A(s=WYw!XWE*zKHtdk?)*)N0L$#|N zvX44s`*a=$o2x_iONU}xoyUPMbttyg8PHxZS)lTwLv;ili*2ba>yRDPAv>r;v8oQm zsyY^jdM+}kWA)muAN=EVh7Q?E9kP`=l%v%l+0-G~)G=E|eXSj`J31tfIwX%eWM6d1 zzUWYneTQUFhjOkuq}z8WzSFVXDx+bNQ=MUmk##7h)1f#{hjQ;b6vye1jnE;v)*=1B zL$a(x@~cBSe1~LNhh$TS;vF5!Ik)+fF5M}JuNFbq>X2UDA$imxxziz8(;*qrA>Fk@ zx@(7Y*ADsTJLI45P!3XOO!WK|Q}?t)KK9PG+WSUtmPf5??2^y9OTOhU>7w2HLGS8P zy=V7+u+6*ozpuvaQvOf(LC`t755oTHJ_vSDm-2tQl&$&zTt4s2$OMcxh<*sx|u65gCKXysRbxFo`Nyc?a#&t=qbxE#u z$p_n|8pAI6MZ4q+?NZK0mt;_vd~RK;iR+TA=~^9};fU(sx>N_(rP{YH$)+yZDP77R z?vkA9lAP*Ny<3;$RF~@Ax&z&h*jPAmi1LlQR0r3!+zdBowL@L|;4|rxyz5dvMwjw2 zx|ENh2OdRo_>qhocvN=~>`guV2xk;on_v%iNmh1AK6XhacBu}oOLDMFezR^yJc?|z zF4d!T$wupvOzct}S(j|IF3Gqq*=1d-DeF=lS(ow+x>P&X&55sC?t#IIWM7x;yDs^= zx+D|3lyBU%dNK9QcF7Ocr96Z#$;~e18+6I{)g>FSOa80wi1y})co+Gjx+FKdX6qS# z$p_UfNJfx-*CoGGm;6rMQss-r(u^J0^M~`Q9ZzRhQ&@m(EJ+lB~yhmO9?99B#b?!D*LxIT-lICB9@&yTlEpoW;r2)__b3OoM>b>6;yfPNk^ikn zanc^;fA+{P*Q5ApuZ`{M^voW~*&fN+9@&yTlDR!OoUVE|@cdqza7Xn=Jvu9(NA*WN zlGil`%k?ih~Kd{#gKAaxa`}Zghvq!dPk80<8<}_*S}X_8T?d}lBfGChIe0yigFT7? z^-LzZeh5Ak1L~2C>sfxC+C)8)cRjKhd*tWrJqbEb?+LAi{G2_iS?-aavqy5UNAj*m zHNris|1~~icBRn|$-y4g(e$W}rbn``SB6-5k7QYoWLb~w&>qQ`-kA2|Q}wGDJf8;n z)qDDV*vk|X=}{b{M|Nn>^1EzZW{0|Kk~`0X-Pe0gxU;-0l}G)%fv5HF-L2-(r&^W% zy)e%{#Z&qZLJXx(wrBq#^+UBMeUgd&Z-TG2PcpIpz3Mrb?9H$GCga?7khA?3z1s@w z?UN1Ir?YhWWDoYK#-UHLrcd&vPco%XwqBp?xIXzR`((TI>5Q5_`5XI`!_%i6o<7-h zeTwh&$)@X5tfxzCfIlZNyg*=LW7JMvyI)|iBdH8+HwNU=qrx;(K zwvj;5D6KxqOkWkmB?(4+dHFC*Z3{PH~Vxh zN}uf9KE*ow<|{T_lRnTVJGW0dK%ZiuebWaFr%#C9$hX|5vrzhE7xzgY=#L=MJYGmQ z=#xIsC*N|Pbbx*lbdNrr0n(?lJNhK+`y}i8WViN9qNTC!L8BS6L;GZJ_AN)k+L(+s z_{#y%(N`d}n_vA*=konbHI+ZpS$sc}Pw!{49e$=5?ql*lKc*VV$7DY~Cj0R*`D`DP zE%}(_;A4x^DKC0V^6N3#IFBi}^Kn<#rR#l6^5rq*?>(lRy2qq5KQ@}Qu_&henEVWn z2}h5g1vxUf8+hY@{PP3L{Z?PlfOMO|18r~j&G+uE1C0$H()D)%*8}p656FHWP!9Hh z;5?uh?tpyV1G2#f+{i{7P~2@maks%x<%??%5IBA{AbvhD zey*~9Kzw^ZHrjyBwi*zB9uR*X5FZ{;F5H0PaRWP}$#7AqUg55T%{ZVq-Jl>kC;MnX z_R)ZN2G40+s#O_~T{ED%l>ybQ49LbASWSx2!}DO9=z;!`9PWP; zhx-#xcpl{Y!0Ju3O?nTa$l)cu2X^eQ@6+`IEW`DgQcNxVHuRs;8AK`NgrpQ-OQ}vI zrSnl!su@YmPpI-SB|l+Gd?qE|U`oEhl=ysVd|v4)C0>+L%q}IqloJ0>DQ1_FEJ%rW zrQ}OYiI1gJ1Co+2F(qGOO8&!?>ON9BvnZw7_LTgJDcO1{*?K9}iKJxrrDW@+6#Gl5 zP9&u`U`qC2N-@5a_;5=0U`n;>DcOT5@#mCm!<1~plx)M4>N`@h6I1eAro`J*@=vDZ zlT67cnNnOYH9Y|v1z)uwzhX+Uyp(cO^rIK}_Jy?%dUDzc`#0?<->^26(~{B|M=70U zl+t;mDb-e_SHO{ zxhd6Fq*gSHDx*3-&@vwG1iQ$SLLLq$Dd-l9j2+N}C(W$JAn` zV6?y~)hVQOhEn=iZAsEn>+nUZWxDF&KSeojiYJ~jYWA|>n(XD2^88bh>8aVswl1@g-F1*71q1^aP^;(i2j$NmH^(Q?f%-ihHJJd#X*E4hct8FOX8bKspRMZAvxf>G0biv&be* z$tF$7CQZo>P3cUhlFr`O1ZwN`NnPSWDBR11Du*&?Aiod zI3@crCA&B!-7lrMa7sB^DaD9WiV>%j8=TUanJM|zQ?jX3iUp?>3r;D&E2X^Olzi_g z+1e@9Bc#u0e?24lMZWiRJNS80(nV9!KU4Cnr)IMo4bb^iDe0Ukohy~y3%X)BfT*r`!pjRGNat%jP%Kj^vR6;1{u{9XQo4{ zzM7E^nUM~ekq((rY&s)-G9!I5BONlMI^yh6(BU((moqviGb24SBRw;tT6RJAvNO^rGs}OrwUcg{QGIbnIb#{=lNs6g8Rdy(WaDQ^;Q1NplNsrg8O6IZ z^2ubRD`pfs$jB#CA!MdQx;BA_WTZplYoHZB%-TVR%q$+Q zeuJzN@<}p^Wn>h~$mpD+jC>Rs>5v)ehnbyYuX{5i{V*f_Fe5!MBRw#q*hfaOkBrXD z%%~1GqdMG-bi#~cA{o`sW^{gLMn02_YGX6f4>Qsavp&=;XP;)|Gs#FN%t#N+=$xX= zYE;$7n33+6k-nEvoFy~ePxYM4d@puQah8nY?-|A4Gt==@hGrCV$tdQMQLH4RSV>0u zUPkAiXOw%ESzejyiW%u(8RcjM)R^V(rq&G|74`kWTekzq|apJhtDV$pHZAWBfok^ zKBA2LKN6X5?4T$Y-08+|S6Do>AUcM(3_%B-1lGMEHXIU97!n^C5+4|njWeX! z+>rMBkoNe{>=fmPLpq0cNaxTF$)*^R?J%TV&>`*XA?@oS>GMO<;fGZJJEYjw@LA9Y zhNNQ;w}Y%7Zil$=kj_3D+Sx}&KXmrda68zcL&}XA(m6;&(&2N8sCJtyC9PQKrq^!c3lQcgO2PC9%}I($w# zd`^0MPI`Mz{4F=VU2_a_^8Mzdx96m{=f)2WhNicx&XyBz%t>$0%?}JE9bd~OKABVA zPEL8Gxt;%GeUeU|Q%-44=bh%nZ*$VsbMgu21O=bV!rk&_*flm9s^a#WIoTjN#Y}VZW9Qw# z_j2=Tt8SckHBUx)T~78(PBu$UHcQ?Od^IQkc2557oNSq#&Kk0%-lrIGPT%m#?K~paM*VW`I_PFO<(1{68{}k9<#aYt zPX6|s^oP8sz5*zQGN0hv$;sx*$>z%KJR-vdokx_@c|>_X=xKRB=xKTX`%1UW`@!#* zlg~e=yy%>Co1E;soZ{wrpJ;<(0XfCZbFu+*(vfmH%P6NaY;()Cur)pg=$$^C)48=d z)lB84Uzxn17(q@pV{SI1(X-V4nR)%+d0{oIq7ma)$`_LW9Af7$SFpUQ;ZC!PG=3}Was9jPv#VB$SKy4Q>-DUoVT28Zk|8vS=%gtUkSmnfT=`5q1YP)he*C@9-FO6yDIqf@&BjjXv z=cI4vrf-`*K>BuW`nJ&$+18zxj^6hh~JIg5^kyEZ+PW9b6<&)$Tv&iXNV>x{< zBOeiOp>u9?^D`Lz(04R)vRQJoSzH_Z<9XBw=8gNlQf_DAx;7!kniqFNdy19h6d%bg zK4S2<_=xeM0^8V+MX{2catL$E8_daW$|-J=Q`{t{T7#U39@d$;sc6Tdt04k7fJyQp_bMKTJ;NuH;m6m(#aDa*Da+WDn+K z59Uupo@f44<(m49^QR#;my?~C)48}god=bZ-Iueiw@oxa`9=A2;wR5Ze|t`H++sbp zXDQZ`Q?60|ob)$37dN*YB%>ud3pXdfQ*LMBx;9F~?wa6FF{AuB9(%md8M!%~k(<-E zNS=IuziR)4V%ASc9z8L7hVppxt0zVSI)^8O(+0G-fkw;|Pj>v8uQO?qc?A8(4tt0Z?jp$t25yfss6uTLb9XBE$ z+KB9|k<|~XellwRwSx1AY@d|;ddca2ET zACV3}qVFt>NIxHuem0=|(kw&D?j7Xmukq$E=9cE;Di|PX-IvamPxtb%>TU3sZNN*XDt}-Hj{)qf_ zBhnv63s>P(gmSg7V=D@|zXpH!I9t0w_i(uFa^iZ^d%qm(zW)-c#KMV7%X*{kV-&$euZk1&P z`OpgcevrE#^n`-)Dhu+V6%_j}=p3+ucxgdrtrQg3D2T@vRJ&b}pRF)|n!%RxEeqnw z1^Lzrigy&ms|)kF8Ggy%K^c#_0Q!1=WKWZNdfd{KEWQHZJ+Q z3iD+dob7w=x_=AvYq|Ep*HMtXC`?|sHmWDMYy9K%fx_g7yH9(kL-QmbSJ5F{Q~aeM zpH)FVtAcz`1;x+{svj)KA61atDM;=Vlrve7|EDk?j@rwG#l+SAD$H+Fihfei*<}U! zX9|)>1<9R)d?p3?ObYUu6eOF9$DvNPARkCUXTlT|ODZV8u^?YWVg3iBE6QUm$p287 z|G{_#$-9E&T|xebf^r%QtK&2Jp|e&B)A4Lv@(&c`6DTO3upn7kP)xiaxmi$ryf7JR z{gd1*$gVFa$FCq+S&*zO$ObRS1}{j478LU;$ObP+wiaZA7kS8kD9G+EC@xk|9K0Y| zT#$WTP#nCV+Vg^J-hyo2g6!Oa?AC&E_6m~M1)a%RkR4i3+^rycv!K{|K{jJS_2~uK zk3~uQy(Ae?l8hi7pdcNfAiJ`lSYAPAbrz%>6jX0jkX>1jU0IM#QIP#uP|jXKar|OT zvX9PZE6DCB=vyiU*_egdmBs^~fz>+RSkjqnC4Kv&y#FAyxgT`+@&Vl^oussLL6wJ> z4+EUbZ)mJ<^;-E=N%bHl=_KX%L7yopCRmcLQj)GxQjD)8U8N-bq$Jy?Bz>bKeWN6O zqoh2#lJezBs>>)_1QUwcm6SVIT5L}Fc1blFrN!n94x~$z6q_qauP8~cC`qpd%=zp&l%#KzW;@$@DfUrX?uxq~d^jbYX;7L@0>Fc|DJD{qPEwLiQc@0H zN#_-mRDV%Y9c5`T5!D$=@;jAOUs;lVQj#rSlI~Gb45FkML`gA-l5F;pZ1$3LlG0)g z#;+{aV0g4xgX)~6#TwkT@@j)2=`bbfCne?Pm86rDX8Rl8Af2Q%oy5&SV*##zqGyW* z7%iEvz|E8BnPLGYeUq*ve?m$6Oi8|l^2x(MpHG6GP(BHILP`FIlJuXF^q-P^{w3)` zCHeeI^Z6SbEVt0;jr{*5SWPqnTk8zoWzL!^$E>}`4pd@{)Bps|I{i-DWswDlYq&kR_ za-~Z1UBjrwzP6fKcO7h;^11qQ-TmOlD9v|mu(JAD*G6IMuGJ28*GiM_8tyaCZ_P(- zG)&*%F6kTGP%B+8*Bxv^~BX#v0$dTg`J! ze(5pQ_Kr#S8$bMOX#WlMN&f2bw_)#$=^Xg+_v7#`>3Czy%ToA^NoO0A&Nimp(J|#L zjVX6@OuEpRa)icIb2=v7V@&$Sn0x|b%5@o&tRIt4U`+P%*v|d7`BQ!0m~y|zlqWeR zIWnfW`IzLwm}1{!k`ZIFXUAF4m&Oze9#brMOuTwb{CP~aQ|`^Soq1*L$tSS=^xLpriq&q@H%zxFR=Z6x z*=?%Vdv51@s9bwauzgPcmgg@5u3tP*dQiRY1^EPCke&X5`1}jXjeJ4&-3zkaUQiC$ z3(~h=(Arwe>2(LzZvO&A8y__ejlyM?Px2SznLDK|7f@7(|lXp=EjeEN% z`$rSk^k{k_m$TE!Nwl_la7Vkts5j0qklm3cccNA4R37Xd&E^w%Vy(_E&Q79L>&E8w zG0gUScY5@{FxzGGolhpe*?eW9e_6kGC%XUduEXH|_WbztWcRqfjs4*W}$O`grrk>Bam_wDuG1 zy$;UU+ZptW5>T%}`QS%4iH|n3-HK2>@jPlh8nq+o&0fS5 zFoq0_wa8M0Sm%@ToypnR>}=;~w)dMhv`I#hOcU@V3N^Zs`=`_Wt<}{ZZ|VzC38n^}ULGr7m(3UY)GytYiqcUhOo@ z(#;$?p-5S57taqMlmKGs(2T__ANzZ)`;wENfQdeLhS2J4#@O#P;o z{VK$3>j0?n%dg~YHaq8qOb^zoSy!}w?a4=u-$XXF4dVK{c|#c^R)w`-@2m>p-SO~V zeY<;fF}V%4ro2+tejp5_`t@cuKi`r+)m`DK%KD_EX!1WE!nZ%zt6M9p0`a6j+T4&4 zH&*5K4L6Ymk~C3tdNw^dkBTzEw4;?*C$G-e*VjGeobMgp2Fo*}tIt=x_TNQ4Wcq#CY- z^3h0$`fzJOMZ*)PnjPu_Y%Rj%Y<=DnPBm=_mlnTHM&|gOrece*MwooJM-Ox z$nWI(?&-zl+k-RoR>9!_aL~7Pno;CbtiP=u{2iP7Y-4M6$8hWyt{POu z;8vwGCmxl=j98QhR_uChb#99Aoz-JeYn1Z{ES67Go@fV^7L6&&i`6`(g+tasgokqg zNbd0*bx*b0-F`-s0lq}fwAOkb$|F)MK755gIAP`E)>rfC;mPjN&fd{v_vGUAD{D%v zCCWPk7?vi;502nEF>eDNe$WOYsl{q1>)9zMyZigr7J93?L^_Z9 z14I$-z_)<$?~r99J>XtEP-D*q3$NG4QojogCgY#Mu;2;Ey=AwS+*@XN@72wAUFNFV zB0C9AxY)X9L|2(;I=+}^X0N~z;oT6^efF2gSOB-KF^a^DK1@ngIzu9IjT76<;VI?+WrM5#+j))WBmj36O}faXiU95q3Y$sR+OYTgzqaULXR zi`l}Ytx%y(slMNYF5H6#xV$wdpi^iEUxD-4)z!6XAvVDN`991>QRiis%5JdD_HK6` z{Wd*1nuHmB=@dSjpZEbA^h`9XO?UREXVq{*iumm{aN#q`WxiP7*9VoKz_AHu1%I)o zZ~bc%F44{4qxkXTEio(3-$#3ICVRg{_Y`LC9skO!zg+Rgeg6jeIDS1lj@Hi(bUwe@ zGKCgou0|np&uGKJ0>3}#^IHbac?C}Jmi6;JAa*r+3^>lg7x7`3UVo5OD83~Cj@F=8 zi#WMcHE{bvH*eGBx7=N-Q)v7V=z7;x(~HSIFMUldMjcRCL&cC_xkxu((55#F^Mi57 z%lbD$bTnRVKizw)w)0?K1^;DpdbQVW-z$FxVDO$7BlfRM+HKM;o({GHZ;hsxPF_=g zN&Th3e{j`&=hoQ-CJ&s}`eKCL8hQ30n^Ndm99RJl0=wzlIknbqM_+!49phj5;}183 z+tKZS19;_Y-V@oC{9jaDfTx_jZwfwJ%&QaMy%O2Y8w`=aS}P}{I&T||DyXg0n+d`I zd=rXcjjU5(xwU8ltxG^*L5UB+qK9w9%UDAucZOJybOwi+Mkc7Qin#!q`);#%vbdGa zq7-UQG!Tr83}HIkTXk5d)}*d-a%4vpiWQ-z)XUUa`TDdn)XtK+Dg*+*-NcyJhd#Ue z&((%L-jw+O2F9rr7@n6~Bte010UmbN+>{q&qtx^Oxp8uS_C828ZL)9&j6~R_Je;5J zo?p!UFA>AcVw~R;gQ(jSen}^e&25W51P=lxb=4yB2r_|3==SaCZ_(YV_1gM9@wK_$ zFh;bsg~zzzR}R;Pi+l*fiB=-#qt*qQ-19mKoKU|{B>IC{ISP}m)icE%HiWSeRV9g4 zcTs+K>*92O_k0qa?w(Cfj6=W%^b%o9G!g-iQL!wQlzpdrAJjam(FXpjyVeeN0q33h zvnS&YJ$8pcdEcsVI~)! z1p?QNgT(4TDm%_P)=rl%thO$KttzSui?Z1AS}=DOttF+@N;?72#yE_!9rru^b`qJ3 z8KF4cw1z&NyWvIthBe%D%CV}CJA1Q}gX!VL*{(zsO(c051poT!sB*^|KYMF?H4;Wt z8PuncS4SSv0(Za!kqYcSWovDGhGVee5$W9YM&c2aTz!nN*-ube;o=5RZxE6_ZO5~V zqx~qGokwG+A+AeM9&!OhAHN!QY-q07yVxx;Cgow}FdgUy@i#wzctzSH9OGLp!8Aa> zf-en_2>eXWPQYaW(UXY=Xu+r5f&_S3nB; z0v;(=4I&ZNSXj%lr+XJ?M}W+qpL*Wi$%f?)zCH)<;-H=UpyPdF9bc?1PIUG3_Mh4- zHGD73X7v=Y`x^GaEIbEu`^4GzX7Mxth}~pcL^jBA*dZeC&#(s(AYMJTeWEJB#p&tn z?0mAnr2$_TzK|y_P>tPld;~%i_N09O6uaSvA2vzvliM{$ymC4@JBrp*Y%%DT_f~Fi z!7-*eC*wG77e%ETh$eAE*i{uH^bvlcbs185nOrEBTs_stf8t%cl814;cjpn)2}YwCJfJ2zl{R?VE)<%iT;js?nrG|e|0O`B{;(XZooSm_?xWDUk{{?7Ew4FuruN#K1PM*&$qV!^Z9`%i> zMdxpzV9Jg--QD|b_YiNMVAsCmly8hv*u7N%`6A@ND;3CQ$f|AHBXfSJCCB3m#mboXQ~~OB#@z zGj*P1ZDd>hKlHbL1XGyV2g+E^_h!mvnb;SZrJC0@-<4xwW!<&#kyop0!&$Eu>^^ zt-LuuKmB2IQ#P(k2HBXMiThAzgK|iGaW!e}JW3Mei4|}~`d2qclR4V#P3D{DdlGiv zf4y=3`?-H}ScuuSGn)%9(Y{8*VY&6C+!QBAbvsVB_TFihnzo8z!*8v|iF*m(G;dn~ z<14xR3ZV<@ZCKzF68@3>kcZmG5GQHGJ@=aZsGi|~o#Bp7MbZHLDlura;`kA4jOrJ> z3e|NQuG%OzOp5AvJ{Ti1?ti;qJF*lRMJMHCdv(+9#@pLlD~Dfy?OWk@XYi;CKv%Pi za}WSG$#Dp2qe+YwdwW$U&F39FKltuD|GY!bMXI`;ytM*t2W{lm{^Vfy;^=(GOwk>e zKDTl*b9b!SPiK?=xtN|!_IGwqPmiX1suIt)Oe*XQM?1#7wacI8l5>D(G6=MBbZ#5-#*X8MMoE0OR?>{);v?Ju8bu7nSTP<1Fs)I>G?1#XPi_ogBRf z6tsOw#8Qb^u zhkNZ0yoc}zF9+k!PbYiRgDH5d%-}lxuD@AalJ;wWxR^trKyLW(gz9KfK-KLJO9KKb zU`@(Kid>JttI#RL>Qu)H3jwve`)_wo_T0*<`FKlg6*)$0zfIoH9XG#y`;Jj5$t>5Y zrxjawpqN#OFgYr4+M$v}LxT%XQmnf2?D2dy_xb#ig`` z7|0*%`_s8y2;2MvaROtuTarfh$2wk(X`Fi(k(+&0#_P+22aVjY9DA!|STmfl+ZaAT~=4jE& zM{c-xZzfn5+CUeAiUxeo;r>%c!)wuy;Ntj`=nG^$oBiPl=cT4f!hAuchC$M?O1FE! zj%N`DcHH^Tj$M&Iqw=NQT}CFKgTB+Fi$hG0dj?thyV&4xe9Yi){PZSWLL29M5+xOM zoe6c=ATM7_*y$8{EV2&;T@`J-lMv#+53aMx>1=CL2G~5GZOShU{POkmWcO^Ud+l^K zpUR??>On1^TBGp59~>72L93Tcc(br()3XuGbwI~`9}IDKE`wZdhRyu4p276CpsE7~6hd(%8$V(A?i~FML!Ld2Lm+b?+L3qbM8h;M7qZJT%PkYpJ4o zXSLPGSK|8ZVn<4XkS!}>;L_I7Dk^MgOzG)THRt}AJU8tcC25+9-Z=>Z>)_ zEDoZu(uR742Frn54b~V-1s14QsMu(bplg&TeVjR1xsELAysQ$!;!sE2Y|;~ z{k7_@Qe1sjg4=p)MfZ}~DEbv(dbJ2qWtcqQXf>Fj7#bX-Hny?#`U|BQ##Q5r4sU<> z(vZI6SA!kyFD1x%6P?59U5$uJOGK<9lqHCN5>L!}HYcUr_7;+;F>iL?vVkCGimb-* z_XFhPLzNO|jXg1IFnYCOeZE?WCMR#FD1<^FGkOd8AlhU!okz#0M1pFx5efH(riuI@ zSsFqeZc1Xo|EH%Ueg26lIS_uasyGk;*%h22;*;3i@Kz&M^6}=E5{iM$0~W0PkM&#X zUcjsRaB~kSmJ>03Yp=oSfEI#rNo87ioK~+pTXC_4`6oiV$@!bv{(PaG+h$cew-+}- z6VlfCN6b@%`D}uZKu)Va16%~J$s@U|qF-NgkCWlEY%qM3n7_l??a$tw9L;w3eHT?5 zDJex~)o)q2sD4t2po1AebT9!3X6E6wrd<;NaigEresj0WAISK4BAf7wI=_bmt@D<~ zENiN;uw6edpuhGa4J?$A=C~m{Q=~5jC4Q$trkc>hBln=f&EX3~zUQWR05=_ogwFlQ(#Pqc=&-J9^0%x`zg`mdKy!du`tbgK zh0}Cv%O&l2J=hmAtqdXMW(O*kAf=9G@5B(V%*JC0g|HL4hJdaGvJ4z=z0w$S^zoeq-c&0F32Epg7{Md}Z~Ft`F6 zm#WVTFTsrEO>>CMKW@n#?W=Z2=Me7r4zNG1L+*|{GZz+`G5nEWW%i(KB!KpVf>%fh zme7SL7@9QZ0>YTj>K?6@DXeM_?$v0wb8xhKXv?X+E+k>WT=#-smF8$bkrGsgiJ(Nn z_v{)rI`*$?ze3VCeEVv0m_>E%>Cra3K~E-PT;Zc(#Q*x>ydfV|5p}U@gBHV6Hed~) zvIJELB@c!8jri-$xh_MV9)A2F_WDQo*JPS-TPvU@S)da|mvpN9^+a4gNGz<{RPgk%VVPHCHl;FWKSSS; zh)uG@MIqS~4&g60U?NGKq(tf(spGmae1G+Y>E!Iz%JN~ul&zUjfIwbJ#tSZB&YLXN zK61VkNkqqgsQiRQD;zVp6X$U7`&iL_b+yjBIn988dwHT=gX@|02eOVteT_W zoC43lRQ$}Zq6SBkqO%xAt3E#uG&(7R$;X=w>~!GYMy{ujeV{#!R_Kr-<_=(G9qowq zeRf{q0?HyO%@EbTV|~pH!ZiVZ`g&Q10_E_Zo5&+^ltsljO&^V(ho=hzFY9oj(dXRY z4*gE{({P%fPk&L!BDDo#y@7}*YFA+|-x~45=?M~p$q3U|uPejwrjucw2#MSTwcw*W zmiG>4v2Uvf&)^9PI6l^xfTz0K|5$k`jf4%O(Jw1M=*b4yWbz**lt6Mq1g*m!mzd?6GFmNWMWHZ6<+xFXJvA)Ij1OEJ}Y>e z{ImjSJh1B1s&fq|UMn8^DPSRv|8_dN5FvKSR6cJeVQ!y06PN35uSIKqVqUaae029M zGUCNkrzfgZsQ35``HP-9KKtM6Qkk2sBesekE}fE1!c=7CmsrHb8O$(MelF2FJmx%~ z5XtMeeP9xGOJup;K_cffR1cY`?dOAwBZ$wN*H;$;r>OMtV`RFBx4>_F&u(frJsQPy zcCuQu2$}{`&u+NVvX#HMBpHKl)w5>s28p5X9GCyRm}O=4T-b=ULR&zI+xa zD)_`aq(d+Dl}MZ(U}l_!47TnGip-Y@wa?+rpQa@FOU)e1fA3XjwBJ*-8}nJwoL`#A#rvbIWX0@OyQaw{s}l8QM_3Y2@4!^mkT+6I3X`o65wg@&JVquJ@JlLE02@0c=O4kFZ1Cc+}S@5L>( ze=!k)O2vDCTwJE|ltDofh*hKY#ifS$O$U2vekVGdNe42{>}-lW2k7eWCa)14n&w za2+bW%bf$cG;sJi&|PS&;BIv25pMr>5EmZwU$mp=!|}+|glVj3aIFp(8hy?Uo}t%K z5obd>Ql)hw`3gxJP&lP+Zfhi1i&MDFhK`2x7H_7g(;^K&F@Xu2(oDOtAu zarxxZo%vLnrTFV`mG|`8gCTQQ5@Pl56#snY$kj@NBbbNAOy!8M>daNF z)aH$KN>VU}K9qk}4*&X%{(y)OH?v$%<=W5ZlR)qV-vTu`Wi^1SKA(f#w|6R7|Fpx) zMNPFH*{h^EJ%g9t`@un}7bv3l{7kNtfL*ad6zkaz2l|e_z55nC>D-C}Sn5foF3mvk z>ph=Ks!#-cRc+Afp7SGm*M^&}7+!KqRxKpCGd++>kCPd$%xN;Iow%v#J0P_B;(3-* zAqf938HysFmsOuh$rq_Pj{UiW)i2bafFKf*^$?VKA1y{cFsf}tH&e3#z%5)n1WA;S zP?csGYN{S-a06HD(XHwwwGPZ6QN_>d=tsYZrP1Pb@5$D?gSF7E`$_I?p~$F*&sta{ zPKZ)U7Q!!mhGT@bpUX2;&xJ=2GyVs4vGZ`JjE9|0TMncRebH^6gFyWY7yb*R(!`YV z4MKwA%7Td~3xU@h*0!ACASW@&5B$;m5`P0!wE)lB7$_GN*7U)@fKa1!pwx(WmGJ&d zxtK0VXN!`amEYm^_9rgL4@c~HF8^Ipp=G6!msWuN{=ZrNb&bxcDoD4+0n$|cF*bVi z&<`jyir}4>eIV)2&|Ng`6eq^)sYmXmmbT%kR5Sci+YKy!MAgJWO^$f{?g#*u>N5aU z=m5oMa`h)`&lpX(c1UuZsH#{C3<&q+L)BEB#zJ2%R3(=%*^H0*gJA=v`mSm? zimR$&$Dw|33~b}{$T6$yqelk)1bt)CTUPD}Z<4@aYh``7@}qzOSL?`#p3JxIBTC}b z_Vx4W@nm*!zIE>|PMvWO_So`%r-ceXna7Hi%?Ou3*ZLz2Idel+m~!}E0=@q?NWG$W zP`gr>=O_@mQ0_cSQF7XH2fb?ed=&&~aMgxNUe5aPq%G()vQ~a~MJXlX6ChCNz6)f0 zhC@^F2wghb72yNlhpRZoqoduE!wVF!;L>!DK;+fpoQvfniRbD)4TgisfAAgMM_t+t z*Oxu?Pbffb8)=bixc4;pC#9FDSQlFL3d@=+)&$Xfvc6dsZ4nxw6%@D1Zy(e2BO77r zsaTDXgnbD}5y~_s7Jk2yh^B;0KVt;#j*N&}xAptY-evi9a=(5JcC~09=JHdPP8|>w z!nm*Bj=;Zxl{yZC1|PJM5)VAaJ8;1-klNnt6h&1^Y+^TojPxD-Bh2!PdWx3bSG-!P zfdWWE$3AHZ0RD9~&Ml1WZ`N{`e-%oTj3|vXBQi^HlyYy@s5OiA^#mUgIhq`ti{(%yE~*vjG4F_9Hom|q z5?`vM(OotX=cTMogr>1z*oS$z0c0kQeAHngmcK7_u1xAHW@jX{e0os@s49{!r;zQU zqHu4D^M&>+Cy!56!KsN_^Et|T$VhWaOupQx81>Za5-OEAnn9SbuxJ8@5E@G^|rd>M4#Uv z{wVHF5JukOlD+Ka=yoAYPoACz>l@~l0}q&!4*@Ncd=ojG!{EW=8uMxf87d>$SDRoC zAQ|8Pm05k-R24|yt3{|>;qgaH%&Cfxbz}OD33`?HS|W)WO{wkx;U6Vk@rGN^CwQQr zhIUk~0k2aU7}6~w67o9797igEPlr?q{NC}dPs^IH$b>Ey+&xsO$fBzEETmh16Y|wh zi(|u;NS7|F4y-o6*#UG#lY3;V%B3;hFTSkwASv8O61YE0M#Yj3301BIsHe_7V?5ZR zb$47mIue%b)G9Tu(4Xx8>Nq2{d8?ExoNKgnb=8WNf}|G0YPvp}^Aq;xC&vQIodBlH zNr537O6_q=%agnsr5{f_3tGEiR*R0@Hqjj^U{%5n97VrqgnQ;6skSQ-2_9B_#kqAa?Qt-{yy05kdhMJ4M@60&OgcyKK$yn zQ$OOu5h4!q?-OhXX?6e8XmoB1&Ql>{w$MEbRbI- zT*+UD!{zIDEZ78v$7+2CULUW%N&{5kEpFPULtspunjLLRP09xC1^?NkEG74$E8&`o6p2G;#-&8pFS(;JW3` z+6B>wdWZ=11qy#)z|D~@2k9+0sgOv^U~IG85*k|5hd5JkcV9PwRV&@7#`B5R6=BL& zm+!lHwHRMrsg7^L*|8oc{xM8GNnoqzgt{)u6z5MI;>2lxv?RUnp4DF0Iqbaw;2X7q zw#W4Gsz<6b4#7~2JfN@({Ht}q@Nz{mlKyvo_)kf$l@_|W@F^QpweA?^1@SODs(0|p z+Q!$fHgB)J{I6G=C^TJrwShivZ{Toa8_1Kh({yXEB5mQ-#(!c&>*xBT{`+g(JzG8+ zIsY24yAo^yts4SdJ%+`=Z?xif7PgV>J!#`KwF-qeW(tlBkk^Of-;^j$4;`U7BEfHI ztS{WcKGe;?g+yWnRXI4JU)_;h%(Ure!%hJ+5tlZLHX7N+x5gQc;#bQf$8HqsBhE!aO6CcD(9E~FexY-XGzW|!aU=t&H zT$h83Do5Ut34^pEc{MiuV2g*kE$BJF$~T34`-)MDaV%&y;Q2A@1!>j>nzm-P@Z>HJ zzeIke67m-wRYSAsOF`|Z>n|>%^~iR-q#wE@LdQA6dyXwy_6nrv0=zFy{yD`-x`6ft zj#7|MSDEOrE<~`e2_*~5QHBFpd~j;omv&kg#I^*70r^Ai%-&b>7YqyRoW@k^4TI@X zJRk_yzhh}Kg1uHBU~L7jMC-r51-N8`DaF|c^=Q+rE~=(sdSXt9DI>i>BuWjs*n4)i zf)esi2S-~+&}n^uiK8o6KOPgGl{LsFu74HN%h#<{eCZMks87hh<69|F=+L@UxA*!ss80>cR471m*w};@T#reGUr>PMuzd@9G)^Kut)a>YL3?$I zohwJ<+#sdHX4-xE}?QOgfesCPF-PydK zc=>eyHNt7<3vb)OzSn$N!}m0_KNVO&?o1t9PMzX)1q3X&n-&@cq>1xPcihr8;i<)6 z;0^RJ0?w3OLW!$di4um~W1PCdt^AHt61joQC%se^!$DgODH}(Lhn>TJbvm5T3vk6+dLTyl* z_EG_Q;la`LwXVv<*NXNJ>OPZW;((TAg5*Y>D8PLh@G^S8iYlT(za@t!Zut3O8WF%* zy9Zj(o@jN@F;H5Iqg3!6a5c!>gsc0KJ^BBgX`|?z^ldSV6&tG5z!8t+Oz1QYbHa8n z4i2Od7G7VUEJ~$kt>mBBb~BWtC&41mbR@@@A(Z2E@JI;{N}?3L*q);X)py*SDVbCq9CYG$UoiF4ZTbS`>?Q` z<-`SSdo}8bX)z#dc;6lctsmTs2R5tp}txlK8V&2E>6x+nvbvj&Q9lF$&rI@ zKfArVu_1)r5R5uksiyVt)OU!tiu4SPt_fcUUT2fbhj?`F&0&Ga>3spVaBgGM;&cPF zfI%eZ(nec8`H0y>{-O&{|`_YVCpfs zS>0N|smRjW;~Re4*zR$^Y}>falMn0KkKS%b`_tJK%Fm+YinM)$D6gVLdDbLBn`?cl zqhSl*?8H7&KPf$HQV7hH*HA9uQnzlR57;4a3hu-(i(a4UF+8Gx=4iJo)Q6MB_EHoz z9hq?>Hw4~$_Q_+n;Y@Q!#GLh&g-zTL<64nmb76?+VHg!k9RO+?-ZG%Loo6eLkj`oF z7-g5^u-Y{qCTRSh1j{n8rr7TrE>U}i{XfNr5dtvp;85e~@$?+n0Yv_@K=q5f8nUuY z8sLR`g#Sh9xQGXBPhhww8^=>u1xn<2z%LM>2-VSBb@oWIK+r->J2Kyv2oBA6b>=)Q z_6ujtgI;Ci%Z>Tei56MtAb}!S;3H1!NBEe4RB27c%C0|9V0$%zCsIY9NOib;TpZYc zynFs;WA9XO3VAxakh98;W{3ADazp;}H*umc&VomHLU;Ek7Ia0&zTc{2^e9Q=IBwpp z>MBTG(lJdAAgnDz$WkHo$-V7`aV33g+gc~bGS_IXV#DsqC8Ho!;kikYf^=2k{w&0+zPu#qWs_AXnK~a4^Baq zU0C)4m)6+;@&7q6JXWogQCVXrAO>{}{^sInjvBDsg~|TAo)V!uA9r6OW0n%6N9Ln+ znQzk*qhG}CaoxeWOe#D=o9jsh;irnAruTIbG)+7%>`165x_mW8WM^M}i z(1wnJbOjt2r%~Wz1QVS0?oeU<+hk<0De?$@loywJ9)dfrGDNBk^Y26YQTF)K?NSNf zQxsi+V_mUb{?}S37N*Np*`r=yKF9N9{_56%C>$cB*}ZaOl~Dl-SDEfjE(R6lyed6;zitgx5|f z*%vPe32tn{cygX;8KMpqHz7dR8p`Xc07+a(uUvFcPJFdTE~L9O-3a+Tph@kck@xA- zThQkR?N{=8K!FRX=^`r5P|mX_bu6gk4%`pd%M!~Xo7Sy+>)u!BlZt8nRrbwJ|t zkHf5x^wAG-9k`OZBwNH)XDBu;y~P{Tl6!($qc^*ADf7TdOGvWQ4`A5dB7yDT;Syv~ zp+?^vvHXuIj*P>}*RU)%qG$3shQ=8Tbe@wXXLv^7QRrq+PbtY8Q)#6I8 zq8K%Ad~S-9)TnTE6Zg4+POq+#SP$HB#`KAq#YZ5HGiLOQsQo(VlGVwA-!Nv-xE@+DZtNIWEMDN-sd z4&{p1eQ@_Ffy749=!k188D{SMorO$XORL#hQ5DJc;z>uRTLAz$Zq>)$a`!Qf&6ex{ zR65F8-<#SOKu+Q}etrJmfR-h*Xl&w&V)vytoSWE8=`w`Wa>zf`MXYBPgv>5aajbeTbGgJhXEF`9RSEq*(5EHmL>=8LR(_Uj( z&}0GG5Aw&PV56Q*?`s2O(9~CeM8%c+PKa7Guei(un$j|bzWgvX? z9fr26@slKNe^V4o9BdwXcJtPKB>Ek6mRCse#k<%+>t`xzG@srRkN;PvV6(z3Na=8{ zgrNTay7vabi0I;LY$GQKf0fb=e>?z2bv)4b?TAHqs_pe^=QOHSlnlLGYZURiY@Viq zEB*mV^}wqi^mSppxWVU|=>3YdNNdP#&BetvaT&b&(-BDE;&^xdTeNl;{|QCl!`(jn zL3+NUryNIHe~<2d_uY3NrG*aQS6hc9OC&?Nv=hl>_7>2>Q+Kt{RFhRrUh?j(QrZm% zJh|Qt^uCU|HX9zF$K5+^42$C;A=l1lY!N7z)qGafJ^(c(OZib1_R0^)gK*DDj{3Wm z)b}DyV4)MWEv5Zqbnq5=;%4nm3{h|er7XIsnD&JP=Wlk;^{aILlarBb7d*M5llros|_Y!=&&-}Tgaw_`nYH5*Iu8};H^$maxcP{5#`V%owE=gnBdm0Lg(6g zRgTtiE82Sll}{}$PcPE`X?uhiMztMqytL$~I0Hl)=r=*oWF>s1MK`~^DS}o$b-Ip! zuX2nl{oJ@4S1u_G#vR3w3D>rL*ALTl1JgK*F`%X)OgvmQ5OYn@Tk%c1_fC)cMxLbQmN$kjnp&S!BZ&9 z7Utx>e53_S_(JxIaWc=Moz7+&n}X~U{a@a9G}g~NE0JPsp|^$It7x}nRaub&%)nTk zgUFp)HFu9*dt_zaHUG`g@q%uh?p|Zr9WVVa&hQ{fT3Af4WpuIsN8TU1K=;KkXQ@HOr}a73gr{SdvBju$>a`49Uq8o2}6X3=kx z$*J;6_w701u9D9GcK7JQf4@>8pLE1x5vABpTq=t-ncJ=H&0fDIE}XN$wM6 zqQ4n%-lG7*PNC2v6tEzC*b)UA=wl=5OR|T@Cdy7E4dO=StcEo)-vf zNZkp>w6XThLe-7V7-l%Tovmk)E38zW!bj@7BZf;)UWuMc8NEX;ohm73Go1O4q&uZ7 z%)+*T!{|R6D0M?!wShor=tT(3&xJEdn{$;-Ntp7^C2{It+BNRszuFiz`N!_b{M`f& zp$gLssI9Gg6~eu1EHte8RJ9eZAAe(Or3o*5Ex^G`zFFi+9sqJAWYk`DU_|KDQ=8$| z(caqMaK2VQ`@4KyR2D9Hg)dwe0Gsl^-dpjOyW=R`(~_UQM=!sq-?DVT^_+jH#Z+zY zwQ8zvE`|offZqp<0DR3vtDbRel-E&Y3Dr8PgOTK5smnJ+d%IumxFejy?weRY$~ziN zRfgqV(5zH161j-_MX87KcLVMM|0wN*`;maQ}!)gp3S9A_jk`|77MM3Gs-mG zeCnLs;ZWfqI5I!9`F|_?2%tPe5Wwl`aIQvGoDQqbO;UkX7gG3u^K|b`G(!fmu}LI` zL0-T6#h`X4dU=G)i{Ei^{EL>%{qPT`k@{Uso19n@?^PTc4`d+Djyeskx~l^X*a!^a zUDb9u;%bc@>RjhF-051EGK2*ex@X58+<+I}cH~+eFw!8}HDE=#0!(v9i~jv$oae() z*-ntRE;OiSI4SIK4+tjR`7{1Qs=^OG=&S{!YLqtlzHASp5NWdfNFY23CHE3waOM2w zhs6zi1bTJB;;F=gMRinY3)2pl2N;;5t9&`pX|Rj<*3siUO^|> z)YME{!@o8U{9SU90p+!c0hA#sAZHBx<@T#hf5yP7R?9E--GAwQ_gJ-zcjpss`v$8m zF6MLj^bpSU0zT9@l`?7pwAaxV9Q}w7%Sc<=%1M3Mc%F>tP$q4-OovxIEAJOf9&N4e zpd$h1+Uk+8Fr2LbDC&u>fXi#Sb4xY`HjX(Djsbp6xY>QjlY=3mQ~ z66FLA)jbV$N7A)?cVJT$ELp_|xCh*a3*NrG_sho*t8ZW4{{ea#J*=O|6fEuJUHPD)Ow#t6+o%3ilZsXjFGB##shs$2_sSxs3d{u+{m$q=J5SI?SS%ub+ zQK82Y`|vU4X-YVfo;~10857#nc$%x{E0?ysHjZljFCwXW{QJh? z?DceSzOg^S7oLqNR1anT$Tkx+Y2oGk4NiXvC04&Le`6_jYkm3_b@bMnEa10#$}q=2T!LKf=0A&F?Xs~Ymt$lJesMN>gX*=r%P=g(eNEJ&h|qW99$y=q zuKgk!Mele$olQ^ROh?I)?9hw7quq_k{>3IU|N5z94TyQs4o}eZ}9h0X+f@NkRAUJqXeHHj3n+ z!*G)Yboz(&8Th+9Z}08gTR(SzWWA22TdmHyEhG{uMP0Z*K10G6M zlWXIodSekGs{3!eK0e#{?fu34&Bgk~#_rz6f1kP|E@mh2Kuk90lQYb>+GACJH3Tfo z@9L)unEAw1=Cgxyl!{MmX6xT>e0%r7y3~lThl46imkf%3HBs+)!A^5_%%2(U7}0fD zKRC|KA++khK^ERbSZEh$Ltkx(=c+p*4qa!}k5!s3kcXD3E;hP8fmHo2Qiw2K6mGtq ze6xWNo)mQ;?;(&v^=1v*VKZ8L-mSW$@!k8y`7V&e^0B=^F@Lb}otqD?b{6f3F!mz; zKdWoJ{^0%wPPkZ{vw7$OU42%+`tr_n7oFEF)-dx=QC0Cn!bVyPQsHkC#x1KEEc77yut`++9u<+SR8)tIY_o=+DFLR4PQ98&OJKn+>iF zSl=T7R@{u6o6{K*-{>a+|_-(p@igCxu!wVizHO+DHaUG7~ zd4S}y;VNgyeA8apbg2dnpoab~0c&Wm9I#q}+XSl=@A?J%2G<6ue_;`zP|HPaeY5d; za`xNgX!2f_I%!{#sDHTz+#n>Hj}5p%>GRJQfGZEyO_U$bW=MV8gU?Rol=!pfoAMl1 z@ZAP@eSen#*FPrE*7ax9_BLUwg~1-UP$#X)wV_+Ru?Sv$R8v=Sg)|)lPRpYW30x2|8Dx*bhB_qQ)AQ`)Gv8v z5N|wOfc7PWdlh{Xvla@+|J4;-w;B)KOG7EH9Ya}q^V4!gkqdw>Q$1~CNwez%ocdk_ z`aj>Ggum&K`t3p`UzwUn+Vmxx2TSI`DCk&C<`u0J8J9O(K+C^BJw1FVm^Gi%;SS81 zu#*UkpTst`tzo><7opbc*$K^!}7NO3qE&)0>xfI?_iD^F8h;XbFvRp2OgZwgDM0<jElr9O*7fydB=F z5gGn9;keLZkwsNa0^FB(aW#oo-FR@j+$%p`Nq55xqOTM90`G%Ch+F{(KPrZLpMutvG}--i12&?3)h%L zWgwsGq}Cs7eEZi1!wCa;WSpNJ&-W`-gy)0@>Bpnt&GGU1Y|#nPOVe^#p&>N#XaMUv zpWsU|*Vz~0Z9;{5VDRyz(1ux1H`yk(LaH8YWf2 zvg%_gC>NgAAz3{RfV}Sb0K!iHX@gp;{;r05)$9_mzr*>#yU?qb=$GwQ|Jk@TcvO^? zhFNdj!~;quXMo-N9i-{j*?IjvLP1l%T-s0pNenkQJg-nMT~B^*);nedveLM`m5zUT zvw+ar&ZzfwHJ0jaJ*rOU(`M%L?jGV-IN`uAOObbaczOx`6nl9$uMpU1e|-!#Uc3T@ z%Uk{_9Qv*b1}Jh^k9JnW-<0*yQQeC0m3!@ zOdPtm2!R%X#@~&TJ?K;?(>F-TeY>ekkrN~LF3xvx6x@9C|FZY34Q(Yy+W88<;#igk zF-BlJlQ#)t5i=NU5)3Thne5sQ5gpNZ%O&1pJJ^iqWiqFasYh;CKJAiCB345DvuEN;%vufeb}M0OU@s^MIe zS9Q8;8i`<~%qt~iwq0ZY9IpdA?Th{6*>j|^*5erNrC$8$<<1VG*RXw)=rkY9{`TR6 z*$2Oyd*R7rHrJ|ANy(pX4mmDfYe@Ly)qe6sBun^$@9^VQQzv<; z2d8G)C^Vwl5YbEZMo_&}%ZYizcFY%W5Dcc(g2M6w5Y{XIgyX)}@iTQ&$3KNSK};o; z!naV%j3Jy)@6A7jI)2rcRtn!jEjj9>RrEtB4~j?9RrnTa;jP;)lJAMfcnU20ju*aS zuUz_c1qa7-_>EkEN=Hao0yuaOmwex4*H&zZ{I?7N#GQV$-b!X zy`ex2rnFw=NW`0?yevSD_Aae3giS5`p0vww`tzSZU5&&Fu9_pU%E|)t=-i3yRcKs+ zRr)n?KFI`%^qru#L4bwbF6;ru9!om4u2(Z zQ>ZdxDk#=7=u4ZyP^e{94YRk~e69W-y!WELk4z|M{bP&V^OwFky;8cr-f|A^V_N6p`qxKQ8=Q zkgJtFL>vR~3JRLotsXc84;;}M@~(Y?m_R)|r+M4CZtxx&uOG9KlY0#ziK-!{#5BBW(9yu;8Y{(ZY#onQz zyAXWoht7w-G@QQDm*x_6*u;Uvc?l97kp`?V(^s(=?DqIm2%cagiO8jcXxv*%GV zz_igJDC*!k_9TC00TITChJZ&j8W7?1L!^o*=qTaiIU(xbOD@PkJf++UJYY53VloLFqip8BM z>hJJEtJ?#z{Ne0!FpcmX+8rl*qs2gGD^Qr8Be2^^631h8WQm2Ngp^}_!ZvJJ{`;!^?h=m^EJ0Qn z);CF9=o5z-v3bLwFZzR-CmNE_W=yF1BWDd1nL#`o1j6zV?$^wpbY!(#wY%LOUa2EC z*<;0OLDup=af?)xG z8ZT%hEUV_hLgZKfMgMhHxS2J`9KX^(h;~#g_uhUz$sd;99eh3cq>miPNI>4G4NfKX z;sAzW$t%UMwfw;~H~Gjs)%<2BN3h`}r@MZ4aqHQ)tyc3P7mkisM~DQDopx_mqkEp8 zAV)10UGZ4{rjl@Qz!0)cM3h^Qzgv&>$3Ehkv>uBbWQ7+b%!7HT6p{}T>Jq|KYIF|7 z43)eOc#inN!tQ#MJ4Dq-PT9deFZ$+RfxAdYpRM{24I8|#;@X$>AHKwfq69YlV;Dz- z_#6}s32(NtxVrXoYgtwyR$hJor1d?XA0wh-QJZ-}TA+x8X|M>f#GAddT|`F4VUQf; zBuXG!z%+-LwLR$UT^^Q9%ydHGDY-%pbk^+~C2MG`g@nB{N~-di@43>Jvhs$0b9 z9285C`Bdm;uzWb2KZg~DBLZ~bK#Yl+&3r3^I(jn|7>yG)CE%=r5kMc=zCq%Cd=qdvu zp5XGgISWyTm>Psq&0zY^dMD4NOM~6_=I1IG+pojH->yqK_ z`mzMZXrglsRo(!#9>kf>Nw<`Xp#65Q7$Gd)9WxwLd#_JN0SnqqJra>Sd(2F&Nvz>W zb8?2m?h(&$_@~bRryOP=#Jfm{!c+vG$ND=+nEE@$imbnz{ubQ51zGqS+2_P|BS5{S}Ow4?|( zu&HQB9LgAd;E1KmKT~-TKJ#oKLJKfRM2>_%0u^*43=*oezF=HPZ*cwaw7sqfW*X2= z9^({cLeh2Q!gel7@dC#-E1qjTvI4>3E+W9++wM=;0r6xF$M`ry#88#uJ}#ak#P_|>DJ zsq(%>-91#wHU95Vw!oOd5sFuE?S3m&?y2;`sAUJR$q6v4Oc{<|^4U&bg>6tcRk`>) z8_w^nMYTfm;k zo6`E7{i^f1B6AkRj?b5ZUjcY$d6Tj-QYQ7trWvVPcpS{WC7j3PEeQr1Z%;#vrYjM3 zRFAqz9%M^jmb;EnI#C{Bx&zQZtWFQxYo(U0NdzEwF8;ynGl`5W&$5h724ez7n`*y) z#E&G6BGoA>Us{h>7P86k(1RYFn-gL4Ojswq)CjvY_9p3_r!|V;)F!4( zh8e^d>izqzfF^YO`hhM;J?&G}q5`t1$Hi*Q=93cWs6>=K$X0kZJW-OLF#CzlkT793 zIynl!X9+q3WP^mm7vYVcumFt?#2wV+L5l%Snb_jvN85+>OZJI^OmZC=n&}D02IBJN z4tbh@6NXJt0&OgtkyKKQL}GHeO1mqop!hjQIHA0s8@su0e-vtAzgdTs6Kox(;t#3o zRm!RM{4x>H5LpF#Ih79EjY3Uf>F(gu+qV3!xrSwffpNZ zi3Bfw6HtNZC*E(uBeI$h>NUx{V!wbBuM|Dx$51o{zkC~!l3ydAPam%#k$R}neBp~t z+Ptdoy#bd$Mslg)qBe>?84YxJMqP!fpAzEow5>}l&{sytLD=z{G3RxEf(1=c6#$Z- zDwo~?M%YoJ?vg6Ysr3}RN)eC$`_{)f93kc64ihmcP+dh9$)oC}HIEwv^dvtExa0_v zh@qlG8Mf?7IGueVLOQAx&^-cr_f;2(TXxV0$coO?Uz~pEV3z?paahpS2v@c;$HKG( z-I#PY2xo^e$vLCaCMRl2(9y&Mx)#gb=qb#r32(sokP?u8l5>=;y_Y9RY+k5b>=z81?%5K+zH$?1+&fQOBu6 z7*Y-qK45&4^@1cGOqSwzD|uyj(0E&{rQO8%$;X}b`m9t>;TW0`3|H){Iy{dQhx_;6 zv|=G!Dni1Q+*ZA!U>8*$KRXpTJn5J-wJUEXHDD#4q>_cT#?Zwf8k#&{QG>5IMs0em zil@jI*Y6-`#d@3330`yt$7ct9`x;%q2@_Wxt=jd~($MCH!VKGC*2Ih;dHnc$m@52G zgrpQTOTc+uC$@IN{Sm?r6isI69M#BIoAjhSR{QU>%Zq}8EVety0@SB@nkVTMTtDGP zy9$&oKsD7y)!6_pg{&}7Eu5r)2W2JS(RZCaq;A7;{j~jod1LrG1O>$ooe7vYt~kMA z{vz~2p9_h%e{u4NYe=*Hi9X;{izNg?;_r7n`ykmfeuS^~34a{AQkLY|^ld^Vnn$cU zSAo$}s6&3dQ^)(XmDOi2w-$F+H`XctnB8m_*0aOz5uL$d0Ed#uZh4Kcx(butD`Vo^sx>!YZUfG(Fxa>ph;s!%l7hKD z1e*L3p`AH2r+s0hs$<_8KX2i^(;;*LK(Tq_@bUfcbMy0J zC1-t{K>0b0gN7cM66)t%eh)|IL82KqPsQSAF5mqregqp;C@xxm)m$6^osfb_as{u8 zQgR%E%R6w(v38((LKVMBr%FUoi=i4h71bF8_hB4*wBM4F@adoiGy#HuiugaUD(IGQ zE{H9^z!i|@>&1Aa0wEA}ns%fZlzk#*9RdM_#2^`M@{&xDO))%4oGTgrw3DztbIRu|5K@YBIU#xm<6h!ECTgT|yE+pDafsvhrDtQD-McF3UGPxfM zyUAa|RA8$i+F<}DCn1RbN-7uJhc%EHgP0Y~4ZxS*z?)N2>34O{>mSQ;Gc~F z-v^-?A*BJ-GMGZ-$H&FP2N0u9M98Fo6|E-WyRT%f9#d(i-B3V4XeJ%mJcfoOq#cQ) z8ppZEdgEMOwBW*h(9oMUkX=3=wrboKXX_WU^*XdK&yy!63SoP+CJ@+X6Z!VJev1wT5$p8u5Kmws^TT;dFS;9r z-W>zLl>n*J8JXDPd}Ti&acOPV-F~DK(bHRX-a3orNPlOtyxCWOc|H5)OG%jrd-k5F zh`0x$7CC!*w!hy-^2$9RQm1cd>#vR)_7Ur?Xi`I9Y0>=KWw$ece8v%u*#`L$<5t~F zeiOlnU;#VJtLx0C!yf67-m0C57vkER9p@*gpLL^%@i>9A@~5pQ55 zn1f!s3e;BuN|CxF%;e)1>z+(4Nb4CVL5wiyrceaTi?P4!bdQb)t=?JDL=n|6XH^#cV1M1cB+J_l&X+MdFJ@L{VzC9(qGUnAWxd%l_i z173D|`<;hVpJue`{xS6Y?txU#s(L}F380Uz1^OsdwYE~d3TUWVJMNsEe>|>DkP5Hs z{7ngg>m;0h4$lP1nh@n<+pEd1thY$29ABLE&Mx}}P9~?_KC^XeqjTJ)e}A^;jqF!8 z1HEv;*oR9vv*#5>4I1&_vhOwZH?OF_X+41J9(?@1)vpzbuzX<6Kc4Na>QyD8Lbbam zAGc#ABffn9#LCM}R-uOyPs0kD>CIvLiBl#YSevX1Pv?FgG;w@w8rg>s&gYf&S9@?c zEfCg80CQn+EvaYxI^{)6+``GPjrxNbXbq?X)ljI zk@c!}*4)82IxeWx3WlM$@R|#Fbp<19;ry(Li zjfc&Jv)=Au8IobxHHxEsi~ZD%3<0P+?uK*Idvp#Nz|Ba5%1GdX6qh zv#O-o-gu$)VjXLR_MA+f6pZ5~gPd~lG_+{}f2UC(F)(hY4^VAbHn8643Ru04p8 z;P2*w><`-_b0Qj?zd*)~mpiaF>R@QX2m|0c)z89vPdC<=h5sx!y5qKUR$!=34dfzE zmVdM9jL~e$_{v23gk_$vE4pmL=w8VtPho|<6S?LZB{W0MQ|eD(Pn2bO*urB6NxW}MF`?dIpdUEbP;eM=^n@TO$- zR@G?zy_kCdJ^W$wH*b*NP*($)NJkpE4G|+-Hg)c3n%T!-hA^m*_EG;o%?)Sg(J=MDJ#P;D;&+$M0O!V!Tz| zaTCf>qwZ`I)(5yI*%~w1HMP0Cj{MWlpivXv-C~IbSR;VU>AN<(m~qacHy8F6WW6@; zt-Cq#q#=cMAYMK$ai_|}+}6wWb#^U_ArXI$l8=Lkxp=%;+Ol?znYGO*T#~q-g9%IB=aKRT0jVJkm7D5+Vh`+S(hbe4VaVcjP)n9q_fy^+(D za)!)E5Oh442oG|4aR8-)DMwBUOG*Mxxh*W=4!B}KVU24IZCF3-+8h!u3iz?5i0fE& zoT{SB1v8S!9`HtlVpx^1$dx<%76n~OlpOzO*b8})B9JJ4-d*t81M?!U35kWtha6=Q zOGKJW^}Ms+J?v6|J3e8x5+y{sQ`Lf4#fjsz%s2pLr3Bf6nuCs!`vhdsRBp>0G^K1KuH+^|Onq7`Ofh<)^xZlexl z7L1oRSG2`NKpI=OZgUM?+YXfyDBYrP?mRu8sRPUI;KMYy+wWR(A-)78le2&@%sefd zXgwP>X%kWAv?6qY#|Y}+ehy2^jjndtr9%J(1UV;xp`t``7YKmL2Z-I-Mka^q?BHSw z`{T#U8!MBprcJi&&*bE$h2`f73hHFHk6TWNMEFTFSRP*qX#D>EeLFhQH=OXpLpuIQYHq)e4nnEQ22!xWaB8>>b zyXQ7b(+zb8>A)SrnoThd$t?+i1se2^VV~hSD44>aQ&E)?Q#shBcZ98Zax&GZ0ePNl zVFzThp65EWP3U<{>Zu(HDi3zVl z5ktqtI|LG<5`(c^bP?qs1Jxd2lJx*L=;B@`B?PbUc_{58+$>1I$+drwF9MNEYvStmE2H3QKL>Q~_*{?5s?(o9#j&aFi*1PN01`-y4!Z|r1ErnJZx<)fvjVnozC!^roPfBnj0uDSmAF_{ zUp0@>#p=OA+Nn-8m=h5obvLT)VjgXZf>xZODSUSf9(2Z&GCOZrG0A<|V+;)`T;JH) zUDRc4u#OH?I)_BOSgtU`LI@9dM^Je~ zC`}|*G}8Ry7fKK9MycMrJjKQ<7VZ5u zR#d}Z2xFKHKVU)Oqj;861Af*^mbxr!{A$yKpL9;~L-&CGtg>$KuLxuo+oc1P8$kEV zEI6gyEuN}0@9T|JQ6yJe@DUf|(mwBVu;!#&ksYBjBHPF<7$eT<^@!eC4~`)dkKy|k zYGSzU6RGH*oNQ_#s!wRt-v=AvG7J|bxUOdh!_BmgtQRgw{=qPD zAW*fY&q2Px)dUxjNq8L&LS=L%ETpupK`%pWx6_YsiPF2A^!CdNxI&ITV!RBo!T4*w2SWhkEh4nPT0g)$f@)5d(WaNLCe*!wU$tM(+h%fsmM-RF)7IcD8s)%OlQ9t0>^|5B(>tE3d|+MwF5>t9RLEx23_^}_NHBZnxYx-($U#hF7AzJp3Ml zXs|Mc(C5Q$sACr{uC+F#wP`Tg05Uu-=P(43?Aic77Kaz`_R@Z|mB@U%;Ep}nPB47S z9cLk5BBBh-T;6om9XqjY#_qf2Hye6#*&VC9FOY}JZBCR03Kj+$849k!Vx|z0$ z2X0Rp=N??GNx2bX=O2C>j=kjlhlcygoSZ=)K*)i?+>|X1L(;1#x>>Uj*B(om+V3 zqr@!TsFD3t9MX3FV=n81p*WiGf6t@^rj257Uo0G0CK(ZBV8SmSse++ zkfFagD#nebi^>*Ixhed9PUjR>OdN!dGcG#XoMb^8Ppga9z{4adDl$8GSQc=DPODb*FU9uJYnGmEV46@|r7-+gz+1Z$bOhxZu)ZxR+Vj zxPp&C>JBhALJ;sj!BOPa^W#T(eq7HcE__peom)>3Ivf0qo*+~xqLo!tzW1jm)M1jZ zSQ`Um0%ZZ891b@@+_dT@ICa72hOM})`G<3!xn<}yvk0sH|E|kPpc?Pif}&=|-qdq| z1|HPG_63a|+jU73tEf7L%Zk1GbEOVCm*_)uKf#UHKf`OKtkVAi&MTt1I#it|3~0D~2Sn5pXK0uCi zF0@LxN;f2Td;zUj*F)3P^MwO-*oYnO&`S!u>Jea?6(Be{QR$Jxt5G}*C~D?Jf7#>p z0<{wHRMF!WQLO=Zj-EO94EyC=huy@GTaMBgw|$6s9|jd%SkgJnopYRiAkYCdWT*m_ z4mwlS4mwlCY;;V*&(Tw7)Z_#`OteP!sWMOpU`ks`WeeC%)<8&~>j|wASDc4P>9XgK zj1b=|s5hRk&v!4IatD<7`fRn&anl-3q3j~L8u!bhet|@zC*A+$9S*Of^d_l&f)t0{ z!SSgm+9h8g&VTO965KOj@GtqX@Y=t5PM;1K{&+hjOE5IZF0Rb(kEb5I8STyJzi2GK zzn{?<0qnl=&p?}TCiKVm?E5ME4ueO-(0BNV)e!C$Krb$*q=R{xH8j)v{fwYm)TlKz zJ&3I6=^^)}Q=*_3WclcM&68c8HQ`PN(!M{pdXPvb==s6p<;N{vH$Ipxw*7(yC4D?4 zgcB+5>2V(#?>7_Vhkv9J4`U0idf0QIK^PYBq~io9zKQJ)*n~^B#D4}pC35vfmcdHZ z>$ehtaD5{eoT6+H9AZT^8CDy$b2`W)FF5tnS%Ia*4A(Slox>!QJwl0hazqMO!ThJ{ z-j+OtSR^`PaUgHvHX7bha*bv3jhqtW}{;X-d?Li zR^KKhZFZoAydl$4FVtJFa3!WZicBQPe^Gfg2KuqHeZmWOU;yb}Pl+qr1dTk+vM-xg z9PP$dc1a5@z*Y$MOp2W%$J>x|mrNtN0A;~g$gnN{`9aXreT`zwK!aS5Z2eN$1u56)W(I$++!ST^s3;qe0CkJF$ zZj89IBteaAq`>f>)b)+x9dG1x*~#F(E)vm%eT{x`%`@@`^;x-}Bqf!F3!E1yJaM3K zt4jm#$^}7q3K>Qfu61E5{>{AVaL4_I8{`W0r^LnU){8Dv6|V83Q}-KJ2C97*tEmjG z6At~ydeSMcb9=dUrGrLhKE5T#!zx$0@m7cX+pR!~jOlGxOjbJEi7NMKj%qD+!AHCF z~E;wraBHTjkFHs-8WaySc3Bn92aV{e!ChbB^LJ|}VkrR`Kd z{kT$%r@#bhz=gxLpMoLky3%M=uVWy+ivHbw#CKy#eh-y z;lZ^nFw(Y3sX)M)2cBtAn6w48->6X5;45yBo*OnPtWYYDmZ4*hf`gFs@}{~Ek0rYK z<>LvZ0w+5AVPW9qAKr&Z0#zLyZ7WCZ^N-I0byAG1RNy>=bBb7EEM||khs_FT6T)%@ zCZRMykS`2XQeQn#vJqV$c`$(u3W5{^LFLZsXOsKaTQ) z{LT4>fwwwdO_k4EbRckFAG$pyu0*#^a7Z^%^~m%WcY?FKr!;g1ZTIF;$7_{eDqhV$ z$qf#p%NXwlhc!G}kVn?7pTT2|Gb~$_UprMe$W`{|Tk$kql=m=?xZ>6w;tP2@42Qf)SI{l<;uU&PfchPOx` zCR0NfEQx8j#{9+I$$qjgnTzrez2sljk?c0&&~3z_+lWK{n1PNp(fO0V!4qE(Lli*# z6ZJIn!Wp0zTz76G4&6o^;;GG?T0YC+ie@s8l*2no8Z&H@ruG-qL-HR#q#=XG^lWk< zsmm3?sS8l*oFf6TLnKviH-=l&|M8eZu5Cp>B#>`%2aX(jyvM;ci#r|_2;Y0sL7)#j z$)%%*Trh|Ul70};ASqAc)wT-5?fTL;tLmdPJ309o*G$*kG6APKMXul7rJXRpX7Ujg zeT~?*?=SWd3nq_|L{5R950o+f@$5^ui@Vh=U0CFLwQ6K0@!aa7egjHP5Bx_n;a*mSENO zYZP@m@jDjpBs2+rOhrR3VI-_4sU~UOnn=RxPDI``abeIKn3C6!y3A}ZKPz7C%&feD zs@xQpEV-hHK!CM50!aZ`Q*JD5!Zo-`QhoSG1l)%Ky?gPl+lTAaL;Ut)ZrdVL4Z5Aa zzMUOzmwb6-je2LjriQeVhQ+V(eFedHJ`dVg-YN%23Oo}p5WT1f{Ravlmw*HUlDmm^ zfvX6%G4C|HoUm3yZS;Nuv4X7C5qrYV8My;TJ;NOUyjH@@yk%{@W(sJ*%$ufG5cYiB%Olm|y%uMv+ zKP29q;qoW+ZB9g+di!IGW(dF-tH^hX8D2*9JDme`DE}n>YkDdNEq_EPwz3bKk>CEo zoc$P0M6BnPWAqa>E z)I;QH+)#m$&F)GDE<3gfgs`GN%e&3+Q5-7&zTU&F(xWZM=f}9UC71-ljOE?-3x|yJ zwK02sf;p6XvqIdi$`Rw->x!B(XdJ?q{nLEgfW-9y;!uHlqFf|;Ou!!-9}cj_3J-^R z5`M*8&glg-im>J2a86)~Nq`9i{_$RIqma=H<*?v?e0Vr?@NXF%E|GvdDS*OsudST8 zFImM15B`+Hqkk-I1F$T^c<{B(JH zX=`A&r7anJt!TVNdZWQ*@%z~aU*T0mYp=bJK$JYS9bR5w zCK;*~I|~jQJRV?+uNr5id*BYgfU6c2y>@V7`7_TcwT{`c$R;cw=@`fC2+!~ZFc&rgdw zpzU7{G?f(g>=5(sUHgK;82h-y#__ON?j0d$`LV|T16Sw|$z1=OkpbBu?>%A~D{-8l zPx(vm==FKC0`*C5A-_9WK&!`S}*78#&^ZQtQ;f_JEE2sFwL5ZG91Lq*rXN$^)I zMQ19b7CG18Ey@?|OgjYsO~3@3^&69u6A1Ey8bc@g z$%!d@q(pxw+ziX7dAusXpghH9I6&XT z6htRH%042bUNt6K9x$nPf}EI=)6mDoR#$Kt9*~qfE(i|eQLDo#%Kechrt}!d*m~6% zX?egX`t4}}$P$3|KlTV^1Uh1=QaE>u2qw1Xe4A(I!N`$W4IdjPJv&;;WbYsEDt3Wu zG9JWqhZ+RLSd#cM$8=>bMN@@b20b?B= zejSZ!Yo($2e`##GOKg1bfW@;v1tC9%?tOZ^jt@ZR*FePfVr4sob+%oSQAvTwJL3-o z+U~-1i%e!{f-M{(Tx9AJVrbI68_!7*MicJx6t^=4BCf)7+9>kg0`_G4BWwC#XI~Z^DJFyoHsJgM0WsTPmCRNunEN^^jgT0=+i2U+Y z0%vn7b1JZ+mf4&r5*lY)Ek^+uV8J5U83dGaSX!2#gaJM6?Bgl{B3E_A;)Kc~;NUd0 zch>JXqzor7i;$ScvKmg*A!S#|;KVX#H{!E*iO0$68turKlI(mgKR7Mm^LmRcdGZT!4BC}3 z?OOg%=+MXxzm6P=Q#f9PbaC^AL{CURA(YocQLnEDQ&YB@NBAeiT+n>DjlwhC71Jp- z9tyx4;3bOB5YVKIkQJVsAd>WiNp{jg)04_Da@wgx5%*whKiK7QY(Ugjl6`U_`hriS ziA%3Xe9ETZNEw(xiOAk3C+^_?^tlWv4}(O(cO)kd-!oZJDsv%F`mFOXg|I*wq+}(t z3`xY{?3`rpi~$rgx95mTR4G6l+Fqw8uVnN82H820g5gqb%@~^5@^fk~KfLH4Xj%Zz zw;{#?xkT{LVHSF3YP@uxL(`&(J~e!0x`><-HkrB#64v4A5X(ctUJkW$!Im`^h*(HW zB!E!vVVW}HlFO>V`h2CqH6sYy5=mQOJ;fGZceP#8Tc}#yPsTH!)0sAuOzP?2Zs;zs z?s#3{j$v0jy0(uFh(P`7g{zzzuf~~B;{GG{SicXpGj&w$NjQAxD?C+Ym9`UK$hTd6 zvcHS*krNP+i5)KY7`x9>3NiPlB#)y$1<1xKG3RZZKgSFyMJ4HN;EkjJnKn=7{_^_C z9M+Dk&J>WxEY;TjThfG$Ae1I(Rv}W7CQWW!5GF`@J?7;G8k8dj2BVuOxA}X~7hL98 z_(cGiQYCK^X=GU%aP0$=6^;Ww#JNZ|C6>-2sJeCrAwdhSSJm8i^!LzNK>dj?k_jok zI6;$L+DaN&5;8rQAhW@(yj)+Rg>~D_Xz5ZN=-3Q)z%7H$MOwYDra-vAeuKA;J^Y}%luV!Dq1H9a zvN$F*=nl5CL?8~E{3|h$aF;^M4>Bzs!IfcB`n+sogtD>o#IeW%x28#WRdzMQrZf*Ms4|<)#i4aPCU&eNgzL0e~7nHaqs=QsBdi3 zP(EEy8%WwRMYzK1^xp2m=Jx&rNDRDvrpP2VGR52H2-pi82oSymktqfN32(f4kPzc4 zOaldV`jJQ(P9}_5YMKP;C`n1dJQ}-P65HS~dw|@LCSV*fq$BU|YPpE+2|70mTM@3j z(*O$#H6I^8Txh)d%i}lqryswb!!NS<7^O=>shj>@i5Vk8;=;0Y6Ag> zbU8Mj=>E#O4Em+Zu?%l`MdmebSeSX`Y<-HDp>)NIas=7eMQ`N z@$A(k3g{T+kqMNF+R|H#k6*hzdy%m#64@Y;$$?l-AVm?e(QrV>J4e3AsqO)`00w@( zW^oMD!dOBmaiM|RvQDp`?VuUir29#b{s^U+_c>S0RoSYZ@&MEZ$sMmkEN5f!HlM=_ z-lm!*!i29L0L?K(b|pSYp)g^GYOW4mAjx?vfllW!o9-$;gdt@FCmONm$^bL=)Jo$s zXslnwqOp|heuE?)L6Bmqisx*uV+R24+rRJfmpuxXZ4Ff}!J-0FQEf&9JQpFzbk?Yg z?F|oo#7Z`koJ@xW3hLj$IjB+1C+e4xun6Uebjg`>zTroi^CS($bqm$H6X3=&HXLOZ z(Rf2VZ0XL<5o17=>IT(_qfl?yNR$LR3~g?wej6GO=454VEn?&p?SYq4xK|aej2E)L z*<)K3(R-biBKvG2g4dtNR4~&x3-%=ZYKAx3@yq;W@ojsD>c|cSYlxb zQOo5*6D^k?Q4Z`wU|i{USM=~k@k8fBKkr#p0-2yYK11M$*uSwl0r2Rc^(Wx-3JEc? zB5>e7uSXVJ0_GrrLlLCy=EnApQBcpYuUp4vAQbY_mQ<(yB%*hd41!i<_aktZ2A&CQxy50nP# z{}7H-v5y->Zmd`>c>`r!$X-K=92Q!3eJ55ZGsUB@3F`<B-~`u7#=v@nZN{ucB`sgeEC)N! zP;iBYI}3c8KnmZb8&6UYxx$~8Nah%@=LqIWtB%1!Y4x9nk;)LSWhWoBTn%AFy6Fv{ zH(a^T<+hNV_iOzUW0@%T3CRu*VLiIsOwS<+@}W_#>Q&WnbuS+cI^tQRssT?V#CyCm zNdloSDzke7X@SyCPQCg;84a_ktM&%2&!JZe#C%-Wu)iN~4G)^DR4m$)A#gm0Ew?>< z|2Mn}j9j1{U<`J-#1)vcJyg~N<7*ee*z7+hhV6}`~8{?vg$B0LRV-HO-Eli0V;)oK&8&qN5 z&m41=DAq9vAG)Qp3PDKWO}TH8tG;;Of{S5&!3K8JBDua4L0oy6RmTPJ@!5fBwctOq zGvOy`m-Ao+BIH9((BWlopRORP9p}d%w_UlQ^IevJp zSZ};5w`(d!b8}(JuzBm`5LLyUS>>BZomH+Rw)VD;6I;TZI{fk_yM7%4DIW;Hq+9si z_b@I4`S?^W8>?s3O;%9lEcZofQW(wU+5dQbz`C&1(8945IM1dQMN7hUo0 zQb@fTx=T4q6FWDeO)~Z`Mg6Hy>`i{AE?~!9>rOr=))d@;Wm7Je$&VplUAR_pO)f>+(I_U|mZw_m@9{?+p~pKcJzV#Cdm66jQT!!H^^t zv|+gM@AMLme0Ub^M~zvuj~wTzY`BE-GfuX_q_j`glMS1ZqJ4_pvdgOks+efmj z#u3(WoDv2NVjsJ5wq*LwhFnotQi#(#h71>lseh%%T8vXA`OP4(T)^gdj!`_O5MBtc zIcwTG+#{+%o7OT?0ZCUWC2i#<0Xr))`Kpgoep$wg7%}GRdqmZ(lj@AlnCsH9aJ2Z3 zb%;`MeervsZMXvDo?N_)iEp+t2c~fFqfuNuh=fq)o2(8(N;;lwSZO=YTP&J_Y#c$n z;hrM#q?7v|%8W1tcG)AB9}%s9eixo&$W~M^((#-)l#3^txr9U+;4^AI=V2Afmd|79 zaDG~6_nX8kxZ2njOpSa^`#%J?k(`Td-FUPB?(E$I)q*H|@n6^uuG7;>>j}FPudU0_ zCi*9x&N(0Q!H+8%v68gk?66wn$$6%djfWlf0y9eyAEjV?xcQ<-pl11iBFFoaHoSID zP7sO)h6w7}`gTQ^BwyLON1C17hkMEn?&adqE1_I-XgxT0t{$wMU93Qa@`MIPB@Id5 z^7jW4iV_AK?CqU{go`O*&|GCN8q4O+F9ax7T^iSYjg%h&$=pYv?szEs25m6(Sx0(y zec*!GmHJ7r+SJd`@@RtHue2$LMQ&xrahwV>q_FBjXHnKEEBgBJ$&s-MOu|k6+%3NC zwjolzVv1k|kkq%@n*cUdv!z`rzlLr^?~$dS4lO10vQ zC0$$Jq#L$YBBGxw?UTh+#p+@kzXm35sXM7{X8asPeOxvzOU)r5 znys-gasttjvaJHo>Wy05y*PiV18($h5ja80X}kanC`cc}Hf|OWL7*M{?BLy*xiM2R z7L&5|>P}zTU&-M&y{xUOPbQ$D%Go)r%dm6*QZkO4{VFW%+>03=A#vEoyF=Yjgb&3{ z1I%biQe}ayt#0p(T4G^^`D27q+EiI#!l7Z%bj)nXr#m$NPjlUe1?PR)k|VYF5;80~ zWLP{sZ^$v`TUX} z8z=Y9UP9P$7d(NFx#qJa%638nuBM5ooa9nwvi6;ZN|*<)gG8@uLcG^C;@dkL;Jmqi zhTNFUheuDCbOfgS2z>VO6GQ=;OHjz7?lYX;5+=Uular#kLN>`uUG;lEyf{0>5go!B zb}rpnlPenNDOAkUm$SBJqf30Il!Wd^Ya^jbwHg8^lWj^|uB(5Ff`Ah}F~GWjR|FjY zNgSv+Wd*^wA_$u6e!z>pZ{}B@lEhAZ@>T4~p>w0beB!@W75ZRr%{{%qIeB=g}3|Em`nYH$NyD5#U@ENp~W>FAtFGj zpCm@Wh@P}f(oxbxx*ByDmPHmBHd$uz{#2tz?egUvSCziOY4%|Tl}i(Thc>9|C#_4> zcF2(`sW5sOC6$Jjk?VN4JOZ!#?GZH{vq0c519sR$z!?(`2#wyp19m7fYjC?2s^I zrNJ2dtQ5`thK!w-l2PBk&-z$#6xq7#B-qBAr-`IZv*~T50gaZiC%;$##A~QkE^_?P z>IyS6f#v^Q8_V7Vs`SVPKFf*Q@w4JcqifLuyN=>(v2fE zA%VqlJ?QU}aGRA}WF`8k@_X8_lHZdGqxn6lbREA(cCQ|K2@IBB>S)?Uq-Qx;QtW=K zQ4M@I$oUJkh^rm9r=Hnmsak-Q8r)TZDu+zC;m$`ydSWHSqggzGtaS&qNeJrn5<0kHXG99#AWZK)9=HtBwCex$BAcdzn2JmTr7gr zlu>}O)WIF&4F_9sv7;f~-29)!D;mVkN|tnL9*+x~otF zl>KUqlQA&)c*oBJL$$&2hEw&?F=;K(s?L1Si)N>^lo#|jAb(?R9$ox4OsWFeMJ-d_xL$m|fm6-BTmV(=`g)*$>imea zu;0m|J3Tl-+zabpmzqL2R_rE`cdp@9l@9Lg;eyLWmtS?e1f#@?V9SgW#F%cC83$g& ze4_!H74Kh`^RB_X%yxOz&*8a|8}(7}J%;1zi2KBNILEHMg_F7oOx)^;@KjH2_$WZW ziqk0~pc6USD7dWmVUdA-1e}Bt&^u^f;L!`?iWLp;%If;G?CKPxBCRv? zK(IS$7y+Lvt zfrV;{F>W0D?5)Ae!`1cB9vZ}hM_=hyL@DAO6lo$8H*chJVFi?OP9;l&^PIh`3$P5HYw+5qT6N6V{73W+2b{7(9QgsQ#xVT$et1{DLRc>s9Fe7 zJgIdze?9(K%}gL_wJV!xcZz@fn9;3cgzAvDr`5u9zG8B#eU1~oTTVq;rlAa9+86uB zp3A3STn-TR@qam`)TzJGJU%B!2%$VUJ|(20lq{!tE(s_sS%fGeA%TE4_wiv8uun(| z2wd@s?q}}MRs-OhPYI1w7wiZwK=ZGeaS!0m+las2?+_q70A`ErPE4XG_zeA(_wI0I zbj+wAfj+%a=pGh-+`$D3@=#DU7HJGnsJKEQn*14&xu?)N;PHv}#CNLNFLHk`<&m zf zAKB@k!<2uubKda(*c z-faql1_^pvj9dXXHUIRr+fpWFD*%Y_Ea$Wt%bqjM+K+KG$hLQb)qmP)*wJ_9; zhpc`iDeH!#wCgbx?!gcj+FNYAyf1zf;Y}f9*hqw&6iYFHl?S9B2gjJvcbH6%3{bo~ zhNgmZmC)Q1sG#x<0*WxqRRX(UK$?aH--iO-<%=BRNKd5;OnfjI@i`9f-UT^L$!&NK z|C4N6)Pu7w)y6^ovRp>4A!-5G9^<{};uT3~rq&?sCU87mB5bKhxw?yLrCbPyo({UW z;A?+?y;7f^afrIu0))_~#9FnHg+34RP_?15g`<_~p>j8mM;j^+@MzR`|4@0X%tJEI zlWAUPOa?M)Xj&bctU0-0fE5Ua{lGcofHR0Y{7Y^m&tNLuBAnz}$z4lzX-f8?*Q3%8 zt$>Gs!Ingk>T}np2@L&BCoG2pXk?;WRU$373YaRS^gBUC9HC~yjB^4?la9m6 z%5WkWnfNiYv{>w9q<Jm(dvYt>z?8QGQZ;Sgb5B zKmBHL=}&XpFE=+gws!DZ7y*jF%i^WCKfr;efcRc}T#29qUEn+D5PI3yB%<|Je`6Fzs5KXB|9V~yKV%1MhH zh-z7gvS2nA2f&ObVhZvC#OBB04+aCzSL6^fG_;BXp||~ZW={Z=JY7*Glq_QrY9MfP zQ{Hf6=fr+Uiva+=?RMVjQTwCj3mB$KtfDBvCCs!zZ3vaYEjR#Zz$^<=C1zSB9baWG zBnf>Ai193FSy6^jj8z=P^>C1nWq_rpde4YdiJewSv5T;@jBq-=es|D)3meDB?U45& zo5iGx01M2J6c7?N(~kqsj!=yesziK*AMk~FNc+X!2jp5L7?_9pA9o_0VIoPD1Wsft zmWXYMx)C8=bx71Rx>v3MLEF>x#k=xn=NGQSqgamM80Q`9S_ z4tj0eiZe~okIykA_I*MVS6o1gR*F(Kk)*%{6c+Uh92tH}#vw9K2R`=0Lcpb3EOo+O zxBmBrQ-zqLV#seXGHVf3V}$b!EN3Fx@z7G67|cF$)2J#f@753*82(vwUFmg@G|*jS zIl5EiB8WhRksW4u-UxX5$0Bi-tSGnXhCG=}o|Wb{-4OFA;!Upj8AjeDcfy0ij8|Yn zWw>f0T3J}sY)rrEvW0~*Q0nRxPmo^D%t=`gUqm7`+DIK5d;se<-4F=<4Ue9;>4xZK zG2#W4WkISX`}S?RA=t8q5(v2vfYV6&idL8BQ0;8B-liL(9OVOS7>a_!w^9y?Wz#%r zbSXt@CiTgX5)Uo~7lRQks=@kv@ga$Oc193loy4mK^X{|`@zo<#RaC9+N3D-Ly#LTw z661EJ4R6y8W$$$3l{{2eW0fjLYS+qT3e%@TNkNi3NEdAiD7>sAfA~u{%~GNniu|<% zeec3EQ@H_3UbQ5>-KHD5O*e!ql-qPeu+7s4@5WI0Sd+KuhV-d3wgO3*Bz`-$>4x}@ zE(`oE8^2s+-=-Ui0d0e3WDmsrBq+`l)aT)1r)3jy` z90oqq5I68PfT|prifS{i_MM+t^)}tmQIcv{X2ep&h*y@me9O=F2=Y3IekM`7O*bTu zutezGrW;ajxKYQtO*h2!rp*P9wvSh22qDWyj*Kz~YXt5TcHGtIHr)`;FG!3Y_75|m zlml7HJH#OKJ>bC&dr^dimgy^S>>SAxF?-W*8G>%p4TZVD54a1wO*drOVU!S5944IRaz=VA3u8 z?t2(TuY7!Zn{Egftsxtby>I&VHr5Ybj zKTX@W>4q3a13_X$ih)W=XwYkSGE-*I5+PzCJrM+qipXucp+erNghU*->4t984e`*y zd`K>_OFoempJRkm+TCx{4c(?2T1hj2-KHDb6E|oH`kSOfq8dO$6&~|xJW;>Bibez$ zW1B0dPW!1T)u>C{rW;~fA$a1D{K>3P@nR+(Gsy5qw<>x>d`Z+J-srdKhWMV&!mYq} zf85Mt2zGj#ZpeeJ{|xyEaS|PDV;j!m3CCv;^eq&NL5!H|vS#GJH)q_jCl>}AQ>xa% z3I)O9%9r~3Wpf>lAW0Q=!_>KX@WXH-9jZ-xx9Ns{mUKg7=JUaGqv0$&X>bgAC*-r3 zzM9w66nR#ktReEh3@$D^3{Wpj{|`$W1mCueryB_K#)y3<2rJ5XV-`cxp3pO#18l5C zjDuU?t-TT>X!QOzziOlwlL3-sN(VT~Qhl4)XMosOJo+TLYHkzzAO+HGVjo5%)aZb` zi4*7g+r&PW=7^SI=-7Ju6Eb3`>#k<&)GMRg#6A*}f+6r2kV?}W-6r;-b;>WL^2|23 ziG8MGD0G~~${AL&+)2Fmp%od|4$rL`t`0q22BA7KObth;dQ++tQ9OA2+H*vIXSX5sQ*-O2@< zBfO4o6Z?1u6isY&o7e}tMI+d%Ar7gPVuYp4i8OHixu62#S51)F-p3=Gg#36kDxxo7AVAvql5=f{p$)lln-ep=fu+ zEQTZsp5K9ILr6=6RX|kVJiQNxRh1UVa#3h2iOQe16Nk?K`)PspnA|3qQ2Rn$%g_^( z3MJ*Rs%kPO(si4SleoZ1j*s*!!ggrR~V+iY? z0O;xZB9oq2bYV-d_73^eX3+4uKNUm}Fzj!ih=%~ggcACLu38y{Si3?BCq~`9O(m32 z>^7Cq^_+N{O2{?}-)ihVmx!3#R6?3wsxrmSZ7QLK;?n)^C z635-!R6^K-L6u)Pl~9&^1>IHV>DfVWvHsk<&R)nu^q-eV2yesbZMV6#@y!kr13kwL z_=DMBe|@)*Jgm%JiTn*6s>YJW3#kS6Vr~wkD?$=Hivz?dgTmSvyPut%;|K{7LwXY|U*P(dZMwfqk z*Qk5dxu<)hCkUuu+4_L;w5Z~SXfx>y$zUUzhR^N)a8t3O3NtQ5 z&CbuSo%N3Ni`IH}!rQv}Bm4tz00P$U+vlDA^!J_4={ZoHD+c)C5FN-52i=Qe4!zz=uW)zK_N}` zs@oN;3=)2+Zvr%3-zO;)J3ic)QC_=K>@4lBt$wq+va$7IacB3zLwU|f7-_Y82l$Ns ziG~CRu10&eeQn(oIX&nm zGDK_p{)>=XUi?@GA^kOM^JRL1OE33<+7Km;5imsHw|9P;VJXx5Be+7^-SrgMTr^zO znhMS{jvaR2<1GEI(>*%Y+@C3b+~o`;JOZqgRmey~fRRp;8DWtYcE2;N*S9zV6_>s4 zfH_v-#3Kmt(AMB`?zSK!>fOh6jG8~(zn}7XsP=seMGsNod$0L@UX#d_r~?W%7hcu7 zZ(h~Ef0HdAR_34V)~klAuZ^ww;x$Ph8v=E^c@3*a8yAHxIsc8l=S>$Lq+{`V+9_A4 z3`xl0W&Agm*9yqQv?wpGe-DaWQ;z105tff;wy0e*4js`aMmR5X?co`+%3L%`vg_v) zS}wD;m;Y<`;qK1H?z-SfOgL;o=ltXlDWSM>AVB3S{}LgZNFi=g$e7zdPUR^pJ<*jn zjqOcyX9{F#P6>{afBo=yaEi?4^+WCw`s4m71>FAN0)M|l2F0^?yZ!F}cChELbL5`H zdSLVW_w|c>t_wiOXy30u_gSQ3Z_1R^i&DP*HHY3sXW93m@4hgBWOET(p@}87o=-4hzoL zWh!sSTc4#C73&n?(I^3ZX+i=>-^9WhP$yk6Mmq76;-c5q*%z5|fRxR++T?ZTsb-Q@ z^wSAyHBw9-|MtQ3AJPx=zqM}bm|*H7TkDI~L-V_Ari;gsABu&!gU;Kz-sQ=O%~<~f z5<#6d2*p@J1|!no55*nmQ>hS;Svm}10Zin?t`$zf%;c2F6rGas)v~k%LHvheVWIe4 zq?_`y{;o8{tsX%V`amRLig~zj}iA3nMUnifA`>g_PkFmpo>vJs_PrU6DUTS z;*4_>#&rkz$puIp+12Fa#5G`{2w~0}fIjnJ=Ha91qz`0ygDHlwOnJ86v4=>J6 zi+y}0?DMn!pud07J=bkZxs3V98!OK#CeHgt)_2F$|71(khZ4o(mFEkQKqjVogD#r& z2H)dv$|-A2l#t-+^t^#6{XNJQe&C<5Fz(_p4WDQ1o%6r`-!2ACQN}O#&fbSgnA;~X z@FPci3wx2`@%Q3%?k|m351PM!gRS*`>8IDT@|95Pa|tqJ-#!*z`=X%`hxShlqT6Bs zN<~!v=Ez$0N2QNMv{nE0mvtU21ZzvRKg+ui@D!#%KyrsVJww`9=t)Qa+pXrqu)+fuDt|&LlUC;n$^{(Y zoEOc%@pOQ-u5)yESbW{B5M6hPV~Nlvy9DZw5nFe$wG*r^)#A17&Z^Fv{sF0vE$r|V z+H!VeqV|tTc(QAwaB3a3&uOOT#PMCo-;4fSb8ZfYJAS*1l+ov%i+zABAaRp=#pS-9 zD7@lM(Of8ACN&6YXYOSLr2>-MWw(bwLkJwbe~c6`P>~FQT`~!

}t(SAX#n?VEs+ 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

  • 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 installs t_coffee only"; + print "\n!!!!!!! ./install all --> installs all the modes [mcoffee, expresso, psicoffee,rcoffee..]"; + print "\n!!!!!!! ./install [mcoffee|rcoffee|..] --> installs the specified mode"; + print "\n!!!!!!! ./install -h --> print usage\n\n"; + if ( $#ARGV==-1){exit ($EXIT_FAILURE);} + } + +if (($cl=~/-h/) ||($cl=~/-H/) ) + { + my $m; + print "\n\n!!!!!!! advanced mode\n"; + foreach $m ((keys (%MODE)),@smode) + { + print "!!!!!!! ./install $m\n"; + } + + print "!!!!!!! ./install [target:package|mode|] [-update|-force|-exec=dir|-dis=dir|-root|-tclinkdb=file|-] [CC=|FCC=|CXX=|CFLAGS=|CXXFLAGS=]\n"; + print "!!!!!!! ./install clean [removes all executables]\n"; + print "!!!!!!! ./install [optional:target] -update [updates package already installed]\n"; + print "!!!!!!! ./install [optional:target] -force [Forces recompilation over everything]\n"; + + print "!!!!!!! ./install [optional:target] -root [You are running as root]\n"; + print "!!!!!!! ./install [optional:target] -exec=/foo/bar/ [address for the T-Coffee executable]\n"; + print "!!!!!!! ./install [optional:target] -dis=/foo/bar/ [Address where distributions should be stored]\n"; + print "!!!!!!! ./install [optional:target] -tclinkdb=foo|update [file containing all the packages to be installed]\n"; + print "!!!!!!! ./install [optional:target] -clean [clean everything]\n"; + print "!!!!!!! ./install [optional:target] -plugins [plugins directory]\n"; + print "!!!!!!! ./install [optional:target] -tcdir=/foor/bar [base path where T-Coffee will be installed]\n"; + print "!!!!!!! ./install [optional:target] -repo=/path/to/repo [binaries repository root directory]\n"; + print "!!!!!!! mode:"; + foreach $m (keys(%MODE)){print "$m ";} + print "\n"; + print "!!!!!!! Packages:"; + foreach $m (keys (%PG)){print "$m ";} + print "\n"; + + print "\n\n"; + exit ($EXIT_FAILURE); + } + + + +# parse compiler flags +my (@argl)=($cl=~/(\S+=[^=]+)\s\w+=/g); +push (@argl, ($cl=~/(\S+=[^=]+\S)\s*$/g)); + +foreach $a (@argl) + { + if ( ($cl=~/CXX=(.*)/)){$CXX=$1;} + if ( ($cl=~/-CC=(.*)/ )){$CC=$1;} + if ( ($cl=~/-FC=(.*)/ )){$FC=$1;} + if ( ($cl=~/-CFLAGS=(.*)/)){$CFLAGS=$1;} + if ( ($cl=~/-CXXFLAGS=(.*)/)){$CXXFLAGS=$1;} + } +#parse install flags +our ($ROOT_INSTALL, $NO_QUESTION, $default_update_action,$BINARIES_ONLY,$force, $default_update_action, $INSTALL_DIR, $PLUGINS_DIR, $DISTRIBUTIONS,$tclinkdb, $proxy, $clean); +if ( ($cl=~/-root/)){$ROOT_INSTALL=1;} +if ( ($cl=~/-no_question/)){$NO_QUESTION=1;} +if ( ($cl=~/-update/)){$default_update_action="update";} +if ( ($cl=~/-binaries/)){$BINARIES_ONLY=1;} +if ( ($cl=~/-force/)){$force=1;$default_update_action="update"} +if ( ($cl=~/-exec=\s*(\S+)/)){$INSTALL_DIR=$1;} +if ( ($cl=~/-plugins=\s*(\S+)/)){$PLUGINS_DIR=$1;} +if ( ($cl=~/-dis=\s*(\S+)/)){$DISTRIBUTIONS=$1;} + +if ( ($cl=~/-tclinkdb=\s*(\S+)/)){$tclinkdb=$1;} +if ( ($cl=~/-proxy=\s*(\S+)/)){$proxy=$1;} +if ( ($cl=~/-clean/)){$clean=1;} +if ( ($cl=~/-repo=\s*(\S+)/)){ $REPO_ROOT=$1; } +if ( ($cl=~/-tcdir=\s*(\S+)/)){ $TCDIR=$1; } +#automated update +if ($tclinkdb){&update_tclinkdb ($tclinkdb);} + + +if( $REPO_ROOT ne "" ) { + if( $OSNAME eq "" ) { print "You have specified the repository folder but the required \"OSNAME\" enviroment variable is missing. \n"; exit 1; } + if( $OSARCH eq "" ) { print "You have specified the repository folder but the required \"OSARCH\" enviroment variable is missing. \n"; exit 1; } +} + +#Prepare the T-Coffee directory structure + +if(!$TCDIR) { $TCDIR="$HOME/.t_coffee"; } +&add_dir ($TCDIR); +&add_dir ($TCCACHE="$TCDIR/cache"); +&add_dir ($TCTMP="$CDIR/tmp"); +&add_dir ($TCM="$TCDIR/mcoffee"); +&add_dir ($TCMETHODS="$TCDIR/methods"); +&add_dir ($TCPLUGINS="$TCDIR/plugins/$OS"); + +#Prepare the Installation Structure + +our $BASE="$CD/bin"; +our $BIN="$BASE/binaries/$OS"; +our $DOWNLOAD_DIR="$BASE/download"; +our $DOWNLOAD_FILE="$DOWNLOAD_DIR/files"; +our $TMP="$BASE/tmp"; + +&add_dir($BASE); +&add_dir($BIN); +&add_dir($DOWNLOAD_DIR); +&add_dir($DOWNLOAD_FILE); +if (!$DISTRIBUTIONS){$DISTRIBUTIONS="$DOWNLOAD_DIR/distributions";} +&add_dir ($DISTRIBUTIONS); +&add_dir ($TMP); + + +#set the directory for the plugins +if (!$PLUGINS_DIR && !$ROOT_INSTALL){$PLUGINS_DIR=$TCPLUGINS;} +elsif (!$PLUGINS_DIR && $ROOT_INSTALL){$PLUGINS_DIR="/usr/local/bin/";} + +#set the directory for t_coffee +if (!$INSTALL_DIR && !$ROOT_INSTALL){$INSTALL_DIR="$HOME/bin/";mkpath ($INSTALL_DIR);} +elsif (!$INSTALL_DIR && $ROOT_INSTALL){$INSTALL_DIR="/usr/local/bin/";} + +#prepare mcoffee files [Only if vanilla installation] +if (-d "mcoffee"){`cp mcoffee/* $TCM`;} + + +#prepare the environement +our $ENV_FILE="$TCDIR/t_coffee_env"; +&env_file2putenv ($ENV_FILE); +&set_proxy($proxy); +my ($target, $p, $r); +$target=$p; + +foreach $p ( ((keys (%PG)),(keys(%MODE)),(@smode)) ) + { + if ($ARGV[0] eq $p && $target eq ""){$target=$p;} + } +if ($target eq ""){exit ($EXIT_FAILURE);} + + +# Check the basic requirements are met +foreach $r (@required_applications) + { + my @app_list; + my $i; + $i=0; + + @app_list=split (/_OR_/, $r); + foreach my $pg (@app_list) + { + $i+=&pg_is_installed ($pg); + } + if ($i==0) + { + print "One of the following packages must be installed to proceed: "; + foreach my $pg (@app_list) + { + print ("$pg "); + } + die; + } + } + + +# Set the mains paths and create directories +# distrib_dir/install/bin +# distrib_dir/install/Downloads +# distrib_dir/install/Downloads/Files +# distrib_dir/install/Downloads/Distributions +# distrib_dir/tmp + +#Directory structure of the installation WITHIN the distribution dir + + + +#sign the license +&sign_license_ni(); + + +#Configure the copilers and their optins +$PG{C}{compiler}=get_C_compiler($CC); +$PG{Fortran}{compiler}=get_F_compiler($FC); +$PG{CXX}{compiler}=$PG{CPP}{compiler}=$PG{GPP}{compiler}=get_CXX_compiler($CXX); +if ($CXXFLAGS){$PG{CPP}{options}=$PG{GPP}{options}=$PG{CXX}{options}=$CXXFLAGS;} +if ($CFLAGS){$PG{C}{options}=$CFLAGS;} +foreach my $c (keys(%PG)) + { + my $arguments; + if ($PG{$c}{compiler}) + { + $arguments="$PG{$c}{compiler_flag}=$PG{$c}{compiler} "; + if ($PG{$c}{options}) + { + $arguments.="$PG{$c}{options_flag}=$PG{$c}{options} "; + } + $PG{$c}{arguments}=$arguments; + } + } + +# select the list of packages to update +if ($PG{$target}){$PG{$target}{install}=1;} +else + { + foreach my $pg (keys(%PG)) + { + if ( $target eq "all" || ($PG{$pg}{mode}=~/$target/)) + { + $PG{$pg} {install}=1; + } + } + } + +foreach my $pg (keys(%PG)) + { + if (!$PG{$pg}{update_action}){$PG{$pg}{update_action}=$default_update_action;} + elsif ($PG{$pg}{update_action} eq "never"){$PG{$pg}{install}=0;} + if ( $force && $PG{$pg}{install}) + { + `rm $BIN/$pg $BIN/$pg.exe $SILENT`; + } + if ($PG{$pg}{update_action} eq "update" && $PG{$pg}{install}){$PG{$pg}{update}=1;} + } + +#Execute the target: install/remove all the selected components +if (($target=~/clean/)) + { + print "------- cleaning executables -----\n"; + `rm bin/* $SILENT`; + exit ($EXIT_SUCCESS); + } + +if ( !$PG{$target}){print "------- Installing T-Coffee Modes\n";} + +#1 - Installing various modes +foreach my $m (keys(%MODE)) + { + if ( $target eq "all" || $target eq $m) + { + print "\n------- The installer will now install the $m components $MODE{$m}{description}\n"; + foreach my $pg (keys(%PG)) + { + if ( $PG{$pg}{mode} =~/$m/ && $PG{$pg}{install}) + { + if ($PG{$pg}{touched}){print "------- $PG{$pg}{dname}: already processed\n";} + else {$PG{$pg}{success}=&install_pg($pg);$PG{$pg}{touched}=1;} + } + } + } + } + +#2 - Installing Various Packages +if ( $PG{$target}){print "------- Installing Individual Package\n";} +foreach my $pg (keys (%PG)) + { + + if ( $PG{$pg}{install} && !$PG{$pg}{touched}) + { + print "\n------- Install $pg\n"; + $PG{$pg}{success}=&install_pg($pg);$PG{$pg}{touched}=1; + } + } +print "------- Finishing The installation\n"; +my $final_report=&install ($INSTALL_DIR); + +print "\n"; +print "*********************************************************************\n"; +print "******** INSTALLATION SUMMARY *****************\n"; +print "*********************************************************************\n"; +print "------- SUMMARY package Installation:\n"; +print "------- Executable Installed in: $PLUGINS_DIR\n"; + +foreach my $pg (keys(%PG)) + { + if ( $PG{$pg}{install}) + { + my $bin_status=($PG{$pg}{from_binary} && $PG{$pg}{success})?"[from binary]":""; + if ( $PG{$pg}{new} && !$PG{$pg}{old}) {print "*------ $PG{$pg}{dname}: installed $bin_status\n"; $PG{$pg}{status}=1;} + elsif ( $PG{$pg}{new} && $PG{$pg}{old}) {print "*------ $PG{$pg}{dname}: updated $bin_status\n" ; $PG{$pg}{status}=1;} + elsif (!$PG{$pg}{new} && $PG{$pg}{old} && !$PG{$pg}{update}){print "*------ $PG{$pg}{dname}: previous\n" ; $PG{$pg}{status}=1;} + elsif (!$PG{$pg}{new} && $PG{$pg}{old} && $PG{$pg}{update}){print "*------ $PG{$pg}{dname}: failed update (previous installation available)\n";$PG{$pg}{status}=0;} + else {print "*------ $PG{$pg}{dname}: failed installation\n";$PG{$pg}{status}=0;} + } + } +my $failure; + +if ( !$PG{$target}){print "*------ SUMMARY mode Installation:\n";} +foreach my $m (keys(%MODE)) + { + + if ( $target eq "all" || $target eq $m) + { + my $succesful=1; + foreach my $pg (keys(%PG)) + { + if (($PG{$pg}{mode}=~/$m/) && $PG{$pg}{install} && $PG{$pg}{status}==0) + { + $succesful=0; + print "*!!!!!! $PG{$pg}{dname}: Missing\n"; + } + } + if ( $succesful) + { + $MODE{$m}{status}=1; + print "*------ MODE $MODE{$m}{dname} SUCCESSFULLY installed\n"; + } + else + { + $failure++; + $MODE{$m}{status}=0; + print "*!!!!!! MODE $MODE{$m}{dname} UNSUCCESSFULLY installed\n"; + } + } + } + + + +if ($clean==1 && ($BASE=~/install4tcoffee/) ){print "*------ Clean Installation Directory: $BASE\n";`rm -rf $BASE`;} +#failure if one program was not well installed +foreach my $pg (keys(%PG)){if ($PG{$pg}{install} && $PG{$pg}{status}==0){exit ($EXIT_FAILURE);}} + +if ($failure) + { + print "*********************************************************************\n"; + print "******** SOME PACKAGES FAILED TO INSTALL *****************\n"; + print "*********************************************************************\n"; + print "\nSome of the reported failures may be due to connectivity problems"; + print "\nRerun the installation and the installer will specifically try to install the missing packages"; + print "\nIf this Fails, go to the original website and install the package manually"; + } + +print "*********************************************************************\n"; +print "******** FINALIZE YOUR INSTALLATION *****************\n"; +print "*********************************************************************\n"; +print "------- Your executables are in:\n"; +print "------- $PLUGINS_DIR:\n"; +print "------- Add this directory to your path with the following command:\n"; +print "------- export PATH=$PLUGINS_DIR:\$PATH\n"; +print "------- Make this permanent by adding this line to the file:\n"; +print "------- $HOME/.bashrc\n"; +exit ($EXIT_SUCCESS); + +################################################################################# +# # +# # +# # +# GENERIC INSTALLATION # +# # +# # +# # +################################################################################# +sub get_CXX_compiler + { + my $c=@_[0]; + my (@clist)=("g++"); + + return get_compil ($c, @clist); + } +sub get_C_compiler + { + my $c=@_[0]; + my (@clist)=("gcc", "cc", "icc"); + + return get_compil ($c, @clist); + } + +sub get_F_compiler + { + my ($c)=@_[0]; + my @clist=("f77", "g77","g95", "gfortran", "ifort"); + return get_compil ($c, @clist); + } + +sub get_compil + { + my ($fav,@clist)=(@_); + + #return the first compiler found installed in the system. Check first the favorite + foreach my $c ($fav,@clist) + { + if (&pg_is_installed ($c)){return $c;} + } + return ""; + } +sub exit_if_pg_not_installed + { + my (@arg)=(@_); + + foreach my $p (@arg) + { + if ( !&pg_is_installed ($p)) + { + print "!!!!!!!! The $p utility must be installed for this installation to proceed [FATAL]\n"; + die; + } + } + return 1; + } +sub set_proxy + { + my ($proxy)=(@_); + my (@list,$p); + + @list= ("HTTP_proxy", "http_proxy", "HTTP_PROXY", "ALL_proxy", "all_proxy","HTTP_proxy_4_TCOFFEE","http_proxy_4_TCOFFEE"); + + if (!$proxy) + { + foreach my $p (@list) + { + if ( ($ENV_SET{$p}) || $ENV{$p}){$proxy=$ENV{$p};} + } + } + foreach my $p(@list){$ENV{$p}=$proxy;} + } + +sub check_internet_connection + { + my $internet; + + if ( -e "x"){unlink ("x");} + if (&pg_is_installed ("wget")){`wget www.google.com -Ox >/dev/null 2>/dev/null`;} + elsif (&pg_is_installed ("curl")){`curl www.google.com -ox >/dev/null 2>/dev/null`;} + else + { + printf stderr "\nERROR: No pg for remote file fetching [wget or curl][FATAL]\n"; + exit ($EXIT_FAILURE); + } + + if ( !-e "x" || -s "x" < 10){$internet=0;} + else {$internet=1;} + if (-e "x"){unlink "x";} + return $internet; + } +sub url2file + { + my ($cmd, $file,$wget_arg, $curl_arg)=(@_); + my ($exit,$flag, $pg, $arg); + + if ($INTERNET || check_internet_connection ()){$INTERNET=1;} + else + { + print STDERR "ERROR: No Internet Connection [FATAL:install.pl]\n"; + exit ($EXIT_FAILURE); + } + + if (&pg_is_installed ("wget")){$pg="wget"; $flag="-O";$arg="--tries=2 --connect-timeout=10 $wget_arg";} + elsif (&pg_is_installed ("curl")){$pg="curl"; $flag="-o";$arg=$curl_arg;} + else + { + printf stderr "\nERROR: No pg for remote file fetching [wget or curl][FATAL]\n"; + exit ($EXIT_FAILURE); + } + + + if (-e $file){unlink($file);} + $exit=system "$pg $cmd $flag$file $arg"; + return $exit; + } + +sub pg_is_installed + { + my ($p, $dir)=(@_); + my ($r,$m, $ret); + my ($supported, $language, $compil); + + + if ( $PG{$p}) + { + $language=$PG{$p}{language2}; + $compil=$PG{$language}{compiler}; + } + + if ( $compil eq "CPAN") + { + if ( system ("perl -M$p -e 1")==$EXIT_SUCCESS){$ret=1;} + else {$ret=0;} + } + elsif ($dir) + { + if (-e "$dir/$p" || -e "$dir/$p\.exe"){$ret=1;} + else {$ret=0;} + } + elsif (-e "$PLUGINS_DIR/$p" || -e "$PLUGINS_DIR/$p.exe"){$ret=1;} + else + { + $r=`which $p 2>/dev/null`; + if ($r eq ""){$ret=0;} + else {$ret=1;} + } + + return $ret; + } +sub install + { + my ($new_bin)=(@_); + my ($copied, $report); + + + if (!$ROOT_INSTALL) + { + + if (-e "$BIN/t_coffee"){`$CP $BIN/t_coffee $INSTALL_DIR`}; + `cp $BIN/* $PLUGINS_DIR`; + $copied=1; + } + else + { + $copied=&root_run ("You must be root to finalize the installation", "$CP $BIN/* $INSTALL_DIR $SILENT"); + } + + + if ( !$copied) + { + $report="*!!!!!! Installation unsuccesful. The executables have been left in $BASE/bin\n"; + } + elsif ( $copied && $ROOT) + { + $report="*------ Installation succesful. Your executables have been copied in $new_bin and are on your PATH\n"; + } + elsif ( $copied && !$ROOT) + { + $report= "*!!!!!! T-Coffee and associated packages have been copied in: $new_bin\n"; + $report.="*!!!!!! This address is NOT in your PATH sytem variable\n"; + $report.="*!!!!!! You can do so by adding the following line in your ~/.bashrc file:\n"; + $report.="*!!!!!! export PATH=$new_bin:\$PATH\n"; + } + return $report; +} + +sub sign_license_ni + { + my $F=new FileHandle; + open ($F, "license.txt"); + while (<$F>) + { + print "$_"; + } + close ($F); + + return; + } +################################################################################# +# # +# # +# # +# INDIVIDUAL MULTIPLE SEQUENCE ALIGNMNT PACKAGES INSTALLATION # +# # +# # +# # +################################################################################# + +sub install_pg + { + my ($pg)=(@_); + my ($report, $previous, $language, $compiler, $return); + + if (!$PG{$pg}{install}){return 1;} + + $previous=&pg_is_installed ($pg); + + if ($PG{$pg}{update_action} eq "no_update" && $previous) + { + $PG{$pg}{old}=1; + $PG{$pg}{new}=0; + $return=1; + } + else + { + $PG{$pg}{old}=$previous; + + if ($PG{$pg} {language2} eq "Perl"){&install_perl_package ($pg);} + elsif ($BINARIES_ONLY && &install_binary_package ($pg)){$PG{$pg}{from_binary}=1;} + elsif (&install_source_package ($pg)){;} + else + { + + if (!&supported_os($OS)) + { + print "!!!!!!!! $pg compilation failed, binary unsupported for $OS\n"; + } + elsif (!($PG{$pg}{from_binary}=&install_binary_package ($pg))) + { + print "!!!!!!!! $pg compilation and binary installation failed\n"; + } + } + $PG{$pg}{new}=$return=&pg_is_installed ($pg,$BIN); + } + + + return $return; + } +sub install_perl_package + { + my ($pg)=(@_); + my ($report, $language, $compiler); + + $language=$PG{$pg} {language2}; + $compiler=$PG{$language}{compiler}; + + if (!&pg_is_installed ($pg)) + { + if ( $OS eq "windows"){`perl -M$compiler -e 'install $pg'`;} + elsif ( $ROOT eq "sudo"){system ("sudo perl -M$compiler -e 'install $pg'");} + else {system ("su root -c perl -M$compiler -e 'install $pg'");} + } + return &pg_is_installed ($pg); + } + + + +sub install_source_package + { + my ($pg)=(@_); + my ($report, $download, $arguments, $language, $address, $name, $ext, $main_dir, $distrib); + my $wget_tmp="$TMP/wget.tmp"; + my (@fl); + if ( -e "$BIN/$pg" || -e "$BIN/$pg.exe"){return 1;} + + # + # check if the module exists in the repository cache + # + if( repo_load($pg) ) { + return 1; + } + + if ($pg eq "t_coffee") {return &install_t_coffee ($pg);} + elsif ($pg eq "TMalign"){return &install_TMalign ($pg);} + + chdir $DISTRIBUTIONS; + + $download=$PG{$pg}{source}; + + if (($download =~/tgz/)) + { + ($address,$name,$ext)=($download=~/(.+\/)([^\/]+)(\.tgz).*/); + } + elsif (($download=~/tar\.gz/)) + { + ($address,$name,$ext)=($download=~/(.+\/)([^\/]+)(\.tar\.gz).*/); + } + elsif (($download=~/tar/)) + { + ($address,$name,$ext)=($download=~/(.+\/)([^\/]+)(\.tar).*/); + } + else + { + ($address,$name)=($download=~/(.+\/)([^\/]+)/); + $ext=""; + } + $distrib="$name$ext"; + + if ( !-d $pg){mkdir $pg;} + chdir $pg; + + #get the distribution if available + if ( -e "$DOWNLOAD_DIR/$distrib") + { + `$CP $DOWNLOAD_DIR/$distrib .`; + } + #UNTAR and Prepare everything + if (!-e "$name.tar" && !-e "$name") + { + &check_rm ($wget_tmp); + print "\n------- Downloading/Installing $pg\n"; + + if (!-e $distrib && &url2file ("$download", "$wget_tmp")==$EXIT_SUCCESS) + { + + `mv $wget_tmp $distrib`; + `$CP $distrib $DOWNLOAD_DIR/`; + } + + if (!-e $distrib) + { + print "!!!!!!! Download of $pg distribution failed\n"; + print "!!!!!!! Check Address: $PG{$pg}{source}\n"; + return 0; + } + print "\n------- unzipping/untaring $name\n"; + if (($ext =~/z/)) + { + &flush_command ("gunzip $name$ext"); + + } + if (($ext =~/tar/) || ($ext =~/tgz/)) + { + &flush_command("tar -xvf $name.tar"); + } + } + #Guess and enter the distribution directory + @fl=ls($p); + foreach my $f (@fl) + { + if (-d $f) + { + $main_dir=$f; + } + } + if (-d $main_dir) + + { + chdir $main_dir;} + else + { + print "Error: $main_dir does not exist"; + } + print "\n------- Compiling/Installing $pg\n"; + `make clean $SILENT`; + + + # + # SAP module + # + if ($pg eq "sap") + { + if (-e "./configure") + { + #new sap distribution + if ($OS eq "macosx") + { + &replace_line_in_file ("./src/galloc.h", "malloc.h", ""); + &replace_line_in_file ("./src/pdbprot.h", "malloc.h", ""); + &replace_line_in_file ("./src/pdbprot.c", "malloc.h", ""); + } + + &flush_command ("./configure"); + &flush_command ("make clean"); + &flush_command ("make"); + &check_cp ("./src/$pg", "$BIN"); + repo_store("./src/$pg"); + } + else + { + #old style distribution + `rm *.o sap sap.exe ./util/aa/*.o ./util/wt/.o $SILENT`; + &flush_command ("make $arguments sap"); + &check_cp ($pg, "$BIN"); + repo_store($pg); + } + } + + # + # CLUSTALW2 module + # + elsif ($pg eq "clustalw2") + { + &flush_command("./configure"); + &flush_command("make $arguments"); + &check_cp ("./src/$pg", "$BIN"); + repo_store("./src/$pg"); + } + + # + # FSA module + # + elsif ($pg eq "fsa") + { + &flush_command("./configure --prefix=$BIN"); + &flush_command("make $arguments"); + &flush_command ("make install"); + + repo_store("fsa", "$BIN/bin"); + `mv $BIN/bin/* $BIN`; + `rmdir $BIN/bin`; + } + + # + # CLUSTALW module + # + elsif ($pg eq "clustalw") + { + &flush_command("make $arguments clustalw"); + `$CP $pg $BIN $SILENT`; + repo_store($pg); + } + + # + # MAFFT module + # + elsif ($pg eq "mafft") + { + my $base=cwd(); + my $c; + + #compile core + mkpath ("./mafft/bin"); + mkpath ("./mafft/lib"); + chdir "$base/core"; + `make clean $SILENT`; + &flush_command ("make $arguments"); + &flush_command ("make install LIBDIR=../mafft/lib BINDIR=../mafft/bin"); + + #compile extension + chdir "$base/extensions"; + `make clean $SILENT`; + &flush_command ("make $arguments"); + &flush_command ("make install LIBDIR=../mafft/lib BINDIR=../mafft/bin"); + + #put everything in mafft and copy the compiled stuff in bin + chdir "$base"; + if ($ROOT_INSTALL) + { + &root_run ("You Must be Root to Install MAFFT\n", "mkdir /usr/local/mafft/;$CP mafft/lib/* /usr/local/mafft;$CP mafft/lib/mafft* /usr/local/bin ;$CP mafft/bin/mafft /usr/local/bin/; "); + } + else + { + `$CP mafft/lib/* $BIN`; + `$CP mafft/bin/mafft $BIN`; + } + `tar -cvf mafft.tar mafft`; + `gzip mafft.tar`; + `mv mafft.tar.gz $BIN`; + + repo_store("mafft/bin/mafft", "mafft/lib/", "$BIN/mafft.tar.gz"); + } + + # + # DIALIGN-TX module + # + elsif ( $pg eq "dialign-tx" ) + { + my $f; + my $base=cwd(); + + chdir "./source"; + if ($OS eq "macosx"){&flush_command ("cp makefile.MAC_OS makefile");} + + &flush_command (" make CPPFLAGS='-O3 -funroll-loops' all"); + + chdir ".."; + &check_cp ("./source/$pg", "$BIN"); + repo_store("./source/$pg"); + } + + # + # DIALIGN-T module + # (is the same as dialign-tx, but it is mantained for backward name compatibility with tcoffee) + # + elsif ( $pg eq "dialign-t" ) + { + my $f; + my $base=cwd(); + + chdir "./source"; + if ($OS eq "macosx"){&flush_command ("cp makefile.MAC_OS makefile");} + + &flush_command (" make CPPFLAGS='-O3 -funroll-loops' all"); + + chdir ".."; + &check_cp ("./source/dialign-tx", "$BIN/dialign-t"); + repo_store("$BIN/dialign-t"); + } + + # + # POA module + # + elsif ($pg eq "poa") + { + &flush_command ("make $arguments poa"); + &check_cp ("$pg", "$BIN"); + repo_store("$pg"); + } + + + # + # PROBCONS module + # + elsif ( $pg eq "probcons") + { + &add_C_libraries("./ProbabilisticModel.h", "list", "cstring"); + + `rm *.exe $SILENT`; + &flush_command ("make $arguments probcons"); + &check_cp("$pg", "$BIN/$pg"); + repo_store("$pg"); + } + + # + # PROBCONS RNA module + # + elsif ( $pg eq "probconsRNA") + { + &add_C_libraries("./ProbabilisticModel.h", "list", "cstring"); + &add_C_libraries("./Main.cc", "iomanip", "cstring","climits"); + `rm *.exe $SILENT`; + &flush_command ("make $arguments probcons"); + &check_cp("probcons", "$BIN/$pg"); + repo_store("$BIN/$pg"); + } + + # + # MUSCLE module + # + elsif ( $pg eq "muscle") + { + `rm *.o muscle muscle.exe $SILENT`; + if ($OS eq "macosx" || $OS eq "linux") + { + &replace_line_in_file ("./Makefile", "LDLIBS = -lm -static", "LDLIBS = -lm"); + } + elsif ($OS eq "windows") + { + &replace_line_in_file ("./intmath.cpp", "double log2e", "double cedric_log"); + &replace_line_in_file ("./intmath.cpp", "double log2", "double log_notuse"); + &replace_line_in_file ("./intmath.cpp", "double cedric_log", "double log2e"); + } + &flush_command ("make $arguments all"); + &check_cp("$pg", "$BIN"); + repo_store("$pg"); + } + + # + # MUS4 module + # + elsif ( $pg eq "mus4") + { + `rm *.o muscle muscle.exe $SILENT`; + &flush_command ("./mk"); + &check_cp("$pg", "$BIN"); + repo_store("$pg"); + } + + # + # PCMA module + # + elsif ( $pg eq "pcma") + { + if ($OS eq "macosx") + { + &replace_line_in_file ("./alcomp2.c", "malloc.h", ""); + } + &flush_command ("make $arguments pcma"); + &check_cp("$pg", "$BIN"); + repo_store("$pg"); + } + + # + # KALIGN module + # + elsif ($pg eq "kalign") + { + &flush_command ("./configure"); + &flush_command("make $arguments"); + &check_cp ("$pg",$BIN); + repo_store("$pg"); + } + + # + # AMAP module + # + elsif ( $pg eq "amap") + { + &add_C_libraries("./Amap.cc", "iomanip", "cstring","climits"); + `make clean $SILENT`; + &flush_command ("make $arguments all"); + &check_cp ("$pg", $BIN); + repo_store("$pg"); + } + + # + # PRODA module + # + elsif ( $pg eq "proda") + { + &add_C_libraries("AlignedFragment.h", "vector", "iostream", "cstring","cstdlib"); + &add_C_libraries("Main.cc", "vector", "climits"); + &add_C_libraries("Sequence.cc", "stdlib.h", "cstdio"); + &flush_command ("make $arguments all"); + &check_cp ("$pg", $BIN); + repo_store("$pg"); + } + + # + # PRANK module + # + elsif ( $pg eq "prank") + { + &flush_command ("make $arguments all"); + &check_cp ("$pg", $BIN); + repo_store("$pg"); + } + + # + # !!!! MUSTANG module + # + elsif ( $pg eq "mustang") + { + &flush_command ("rm ./bin/*"); + &flush_command ("make $arguments all"); + + if ( $OS=~/windows/){&flush_command("cp ./bin/* $BIN/mustang.exe");} + else {&flush_command("cp ./bin/* $BIN/mustang");} + + repo_store("$BIN/mustang"); + } + + # + # RNAplfold module + # + elsif ( $pg eq "RNAplfold") + { + &flush_command("./configure"); + &flush_command ("make $arguments all"); + &check_cp("./Progs/RNAplfold", "$BIN"); + &check_cp("./Progs/RNAalifold", "$BIN"); + &check_cp("./Progs/RNAfold", "$BIN"); + + repo_store("./Progs/RNAplfold", "./Progs/RNAalifold", "./Progs/RNAfold"); + } + + # + # !!! RETREE module + # + elsif ( $pg eq "retree") + { + chdir "src"; + &flush_command ("make $arguments all"); + &flush_command ("make put"); + system "cp ../exe/* $BIN"; + + repo_store("retree", "../exe"); + } + + chdir $CDIR; + return &pg_is_installed ($pg, $BIN); + } + +sub install_t_coffee + { + my ($pg)=(@_); + my ($report,$cflags, $arguments, $language, $compiler) ; + #1-Install T-Coffee + chdir "t_coffee_source"; + &flush_command ("make clean"); + print "\n------- Compiling T-Coffee\n"; + $language=$PG{$pg} {language2}; + $arguments=$PG{$language}{arguments}; + if (!($arguments =~/CFLAGS/)){$arguments .= " CFLAGS=-O2 ";} + + if ( $CC ne ""){&flush_command ("make -i $arguments t_coffee");} + &check_cp ($pg, $BIN); + + chdir $CDIR; + return &pg_is_installed ($pg, $BIN); + } +sub install_TMalign + { + my ($pg)=(@_); + my $report; + chdir "t_coffee_source"; + print "\n------- Compiling TMalign\n"; + `rm TMalign TMalign.exe $SILENT`; + if ( $FC ne ""){&flush_command ("make -i $PG{Fortran}{arguments} TMalign");} + &check_cp ($pg, $BIN); + repo_store($pg); + + if ( !-e "$BIN/$pg" && pg_has_binary_distrib ($pg)) + { + print "!!!!!!! Compilation of $pg impossible. Will try to install from binary\n"; + return &install_binary_package ($pg); + } + chdir $CDIR; + return &pg_is_installed ($pg, $BIN); + } + +sub pg_has_binary_distrib + { + my ($pg)=(@_); + if ($PG{$pg}{windows}){return 1;} + elsif ($PG{$pg}{osx}){return 1;} + elsif ($PG{$pg}{linux}){return 1;} + return 0; + } +sub install_binary_package + { + my ($pg)=(@_); + my ($base,$report,$name, $download, $arguments, $language, $dir); + my $isdir; + &input_os(); + + if (!&supported_os($OS)){return 0;} + if ( $PG{$pg}{binary}){$name=$PG{$pg}{binary};} + else + { + $name=$pg; + if ( $OS eq "windows"){$name.=".exe";} + } + + $download="$WEB_BASE/Packages/Binaries/$OS/$name"; + + $base=cwd(); + chdir $TMP; + + if (!-e $name) + { + `rm x $SILENT`; + if ( url2file("$download","x")==$EXIT_SUCCESS) + { + `mv x $name`; + } + } + + if (!-e $name) + { + print "!!!!!!! $PG{$pg}{dname}: Download of $pg binary failed\n"; + print "!!!!!!! $PG{$pg}{dname}: Check Address: $download\n"; + return 0; + } + print "\n------- Installing $pg\n"; + + if ($name =~/tar\.gz/) + { + `gunzip $name`; + `tar -xvf $pg.tar`; + chdir $pg; + if ( $pg eq "mafft") + { + if ($ROOT_INSTALL) + { + &root_run ("You Must be Roor to Install MAFFT\n", "$CP mafft/bin/* /usr/local/mafft;mkdir /usr/local/mafft/; $CP mafft/lib/* /usr/local/bin/"); + } + else + { + `$CP $TMP/$pg/bin/* $BIN $SILENT`; + `$CP $TMP/$pg/lib/* $BIN $SILENT`; + } + } + else + { + if (-e "$TMP/$pg/data"){`$CP $TMP/$pg/data/* $TCM $SILENT`;} + if (!($pg=~/\*/)){`rm -rf $pg`;} + } + } + else + { + &check_cp ("$pg", "$BIN"); + `chmod u+x $BIN/$pg`; + unlink ($pg); + } + chdir $base; + $PG{$pg}{from_binary}=1; + return &pg_is_installed ($pg, $BIN); + } + +################################################################################ +# # +# # +# # +# Simple Utilities # +# # +# # +# # +################################################################################# +sub add_dir + { + my $dir=@_[0]; + + if (!-e $dir && !-d $dir) + { + my @l; + umask (0000); + @l=mkpath ($dir,{mode => 0777}); + + } + else + { + return 0; + } + } +sub check_rm + { + my ($file)=(@_); + + if ( -e $file) + { + return unlink($file); + } + return 0; + } +sub check_cp + { + my ($from, $to)=(@_); + if ( !-e $from && -e "$from\.exe"){$from="$from\.exe";} + if ( !-e $from){return 0;} + + `$CP $from $to`; + return 1; + } + +# +# Cache the specified package +# +# - path (mandatory): the source path to be cached +# - pg (optional): the package name +# +sub repo_store +{ + # check that all required data are available + if( $REPO_ROOT eq "" ) { return; } + + + # extract the package name from the specified path + my $pg =`basename $_[0]`; + chomp($pg); + + my $VER = $PG{$pg}{version}; + my $CACHE = "$REPO_ROOT/$pg/$VER/$OSNAME-$OSARCH"; + + print "-------- Storing package: \"$pg\" to path: $CACHE\n"; + + # clean the cache path if exists and create it again + `rm -rf $CACHE`; + `mkdir -p $CACHE`; + + for my $path (@_) { + + # check if it is a single file + if( -f $path ) { + `cp $path $CACHE`; + } + # .. or a directory, in this case copy all the content + elsif( -d $path ) { + opendir(IMD, $path); + my @thefiles= readdir(IMD); + closedir(IMD); + + for my $_file (@thefiles) { + if( $_file ne "." && $_file ne "..") { + `cp $path/$_file $CACHE`; + } + } + } + } + + +} + +# +# Retrieve a target object from the build binary repository +# - pg (mandatory): a know target package name, it will be used to access to the $PG packages map +# +sub repo_load +{ + my ($pg)=(@_); + + # check that all required data are available + if( $REPO_ROOT eq "" ) { return 0; } + + my $VER = $PG{$pg}{version}; + my $CACHE = "$REPO_ROOT/$pg/$VER/$OSNAME-$OSARCH"; + if( !-e "$CACHE/$pg" ) { + print "-------- Module \"$pg\" NOT found on repository cache.\n"; + return 0; + } + + print "-------- Module \"$pg\" found on repository cache. Using copy on path: $CACHE\n"; + `cp $CACHE/* $BIN`; + return 1; +} + +sub check_file_list_exists + { + my ($base, @flist)=(@_); + my $f; + + foreach $f (@flist) + { + if ( !-e "$base/$f"){return 0;} + } + return 1; + } +sub ls + { + my $f=@_[0]; + my @fl; + chomp(@fl=`ls -1 $f`); + return @fl; + } +sub flush_command + { + my $command=@_[0]; + my $F=new FileHandle; + open ($F, "$command|"); + while (<$F>){print " --- $_";} + close ($F); + } + +sub input_installation_directory + { + my $dir=@_[0]; + my $new; + + print "------- The current installation directory is: [$dir]\n"; + print "??????? Return to keep the default or new value:"; + + if ($NO_QUESTION==0) + { + chomp ($new=); + while ( $new ne "" && !input_yes ("You have entered $new. Is this correct? ([y]/n):")) + { + print "???????New installation directory:"; + chomp ($new=); + } + $dir=($new eq "")?$dir:$new; + $dir=~s/\/$//; + } + + if ( -d $dir){return $dir;} + elsif (&root_run ("You must be root to create $dir","mkdir $dir")==$EXIT_SUCCESS){return $dir;} + else + { + print "!!!!!!! $dir could not be created\n"; + if ( $NO_QUESTION) + { + return ""; + } + elsif ( &input_yes ("??????? Do you want to provide a new directory([y]/n)?:")) + { + return input_installation_directory ($dir); + } + else + { + return ""; + } + } + + } +sub input_yes + { + my $question =@_[0]; + my $answer; + + if ($NO_QUESTION==1){return 1;} + + if ($question eq ""){$question="??????? Do you wish to proceed ([y]/n)?:";} + print $question; + chomp($answer=lc()); + if (($answer=~/^y/) || $answer eq ""){return 1;} + elsif ( ($answer=~/^n/)){return 0;} + else + { + return input_yes($question); + } + } +sub root_run + { + my ($txt, $cmd)=(@_); + + if ( system ($cmd)==$EXIT_SUCCESS){return $EXIT_SUCCESS;} + else + { + print "------- $txt\n"; + if ( $ROOT eq "sudo"){return system ("sudo $cmd");} + else {return system ("su root -c \"$cmd\"");} + } + } +#analyze environement +sub get_root + { + if (&pg_is_installed ("sudo")){return "sudo";} + else {return "su";} + } + +sub get_os + { + my $raw_os=`uname`; + my $os; + + $raw_os=lc ($raw_os); + + if ($raw_os =~/cygwin/){$os="windows";} + elsif ($raw_os =~/linux/){$os="linux";} + elsif ($raw_os =~/osx/){$os="macosx";} + elsif ($raw_os =~/darwin/){$os="macosx";} + else + { + $os=$raw_os; + } + return $os; + } +sub input_os + { + my $answer; + if ($OS) {return $OS;} + + print "??????? which os do you use: [w]indows, [l]inux, [m]acosx:?"; + $answer=lc(); + + if (($answer=~/^m/)){$OS="macosx";} + elsif ( ($answer=~/^w/)){$OS="windows";} + elsif ( ($answer=~/^linux/)){$OS="linux";} + + else + { + return &input_os(); + } + return $OS; + } + +sub supported_os + { + my ($os)=(@_[0]); + return $SUPPORTED_OS{$os}; + } + + +################################################################################ +# # +# # +# # +# update/initialize links # +# # +# # +# # +################################################################################# + + +sub update_tclinkdb + { + my $file =@_[0]; + my $name; + my $F=new FileHandle; + my ($download, $address, $name, $l, $db); + + if ( $file eq "update"){$file=$TCLINKDB_ADDRESS;} + + if ( $file =~/http:\/\// || $file =~/ftp:\/\//) + { + ($address, $name)=($download=~/(.*)\/([^\/]+)$/); + `rm x $SILENT`; + if (&url2file ($file,"x")==$EXIT_SUCCESS) + { + print "------- Susscessful upload of $name"; + `mv x $name`; + $file=$name; + } + } + open ($F, "$file"); + while (<$F>) + { + my $l=$_; + if (($l =~/^\/\//) || ($db=~/^#/)){;} + elsif ( !($l =~/\w/)){;} + else + { + my @v=split (/\s+/, $l); + if ( $l=~/^MODE/) + { + $MODE{$v[1]}{$v[2]}=$v[3]; + } + elsif ($l=~/^PG/) + { + $PG{$v[1]}{$v[2]}=$v[3]; + } + } + } + close ($F); + &post_process_PG(); + return; + } + + + +sub initialize_PG + { +#TclinkdbStart End tag for the list updating + +$PG{"t_coffee"}{"4_TCOFFEE"}="TCOFFEE"; +$PG{"t_coffee"}{"type"}="sequence_multiple_aligner"; +$PG{"t_coffee"}{"ADDRESS"}="http://www.tcoffee.org"; +$PG{"t_coffee"}{"language"}="C"; +$PG{"t_coffee"}{"language2"}="C"; +$PG{"t_coffee"}{"source"}="http://www.tcoffee.org/Packages/T-COFFEE_distribution.tar.gz"; +$PG{"t_coffee"}{"update_action"}="always"; +$PG{"t_coffee"}{"mode"}="tcoffee,mcoffee,rcoffee,expresso,3dcoffee"; +$PG{"clustalw2"}{"4_TCOFFEE"}="CLUSTALW2"; +$PG{"clustalw2"}{"type"}="sequence_multiple_aligner"; +$PG{"clustalw2"}{"ADDRESS"}="http://www.clustal.org"; +$PG{"clustalw2"}{"language"}="C++"; +$PG{"clustalw2"}{"language2"}="CXX"; +$PG{"clustalw2"}{"source"}="http://www.clustal.org/download/2.0.10/clustalw-2.0.10-src.tar.gz"; +$PG{"clustalw2"}{"mode"}="mcoffee,rcoffee"; +$PG{"clustalw2"}{"version"}="2.0.10"; +$PG{"clustalw"}{"4_TCOFFEE"}="CLUSTALW"; +$PG{"clustalw"}{"type"}="sequence_multiple_aligner"; +$PG{"clustalw"}{"ADDRESS"}="http://www.clustal.org"; +$PG{"clustalw"}{"language"}="C"; +$PG{"clustalw"}{"language2"}="C"; +$PG{"clustalw"}{"source"}="http://www.clustal.org/download/1.X/ftp-igbmc.u-strasbg.fr/pub/ClustalW/clustalw1.82.UNIX.tar.gz"; +$PG{"clustalw"}{"mode"}="mcoffee,rcoffee"; +$PG{"clustalw"}{"version"}="1.82"; +$PG{"dialign-t"}{"4_TCOFFEE"}="DIALIGNT"; +$PG{"dialign-t"}{"type"}="sequence_multiple_aligner"; +$PG{"dialign-t"}{"ADDRESS"}="http://dialign-tx.gobics.de/"; +$PG{"dialign-t"}{"DIR"}="/usr/share/dialign-tx/"; +$PG{"dialign-t"}{"language"}="C"; +$PG{"dialign-t"}{"language2"}="C"; +$PG{"dialign-t"}{"source"}="http://dialign-tx.gobics.de/DIALIGN-TX_1.0.2.tar.gz"; +$PG{"dialign-t"}{"mode"}="mcoffee"; +$PG{"dialign-t"}{"binary"}="dialign-t"; +$PG{"dialign-t"}{"version"}="1.0.2"; +$PG{"dialign-tx"}{"4_TCOFFEE"}="DIALIGNTX"; +$PG{"dialign-tx"}{"type"}="sequence_multiple_aligner"; +$PG{"dialign-tx"}{"ADDRESS"}="http://dialign-tx.gobics.de/"; +$PG{"dialign-tx"}{"DIR"}="/usr/share/dialign-tx/"; +$PG{"dialign-tx"}{"language"}="C"; +$PG{"dialign-tx"}{"language2"}="C"; +$PG{"dialign-tx"}{"source"}="http://dialign-tx.gobics.de/DIALIGN-TX_1.0.2.tar.gz"; +$PG{"dialign-tx"}{"mode"}="mcoffee"; +$PG{"dialign-tx"}{"binary"}="dialign-tx"; +$PG{"dialign-tx"}{"version"}="1.0.2"; +$PG{"poa"}{"4_TCOFFEE"}="POA"; +$PG{"poa"}{"type"}="sequence_multiple_aligner"; +$PG{"poa"}{"ADDRESS"}="http://www.bioinformatics.ucla.edu/poa/"; +$PG{"poa"}{"language"}="C"; +$PG{"poa"}{"language2"}="C"; +$PG{"poa"}{"source"}="http://downloads.sourceforge.net/poamsa/poaV2.tar.gz"; +$PG{"poa"}{"DIR"}="/usr/share/"; +$PG{"poa"}{"FILE1"}="blosum80.mat"; +$PG{"poa"}{"mode"}="mcoffee"; +$PG{"poa"}{"binary"}="poa"; +$PG{"poa"}{"version"}="2.0"; +$PG{"probcons"}{"4_TCOFFEE"}="PROBCONS"; +$PG{"probcons"}{"type"}="sequence_multiple_aligner"; +$PG{"probcons"}{"ADDRESS"}="http://probcons.stanford.edu/"; +$PG{"probcons"}{"language2"}="CXX"; +$PG{"probcons"}{"language"}="C++"; +$PG{"probcons"}{"source"}="http://probcons.stanford.edu/probcons_v1_12.tar.gz"; +$PG{"probcons"}{"mode"}="mcoffee"; +$PG{"probcons"}{"binary"}="probcons"; +$PG{"probcons"}{"version"}="1.12"; +$PG{"mafft"}{"4_TCOFFEE"}="MAFFT"; +$PG{"mafft"}{"type"}="sequence_multiple_aligner"; +$PG{"mafft"}{"ADDRESS"}="http://align.bmr.kyushu-u.ac.jp/mafft/online/server/"; +$PG{"mafft"}{"language"}="C"; +$PG{"mafft"}{"language"}="C"; +$PG{"mafft"}{"source"}="http://align.bmr.kyushu-u.ac.jp/mafft/software/mafft-6.603-with-extensions-src.tgz"; +$PG{"mafft"}{"windows"}="http://align.bmr.kyushu-u.ac.jp/mafft/software/mafft-6.603-mingw.tar"; +$PG{"mafft"}{"mode"}="mcoffee,rcoffee"; +$PG{"mafft"}{"binary"}="mafft.tar.gz"; +$PG{"mafft"}{"version"}="6.603"; +$PG{"muscle"}{"4_TCOFFEE"}="MUSCLE"; +$PG{"muscle"}{"type"}="sequence_multiple_aligner"; +$PG{"muscle"}{"ADDRESS"}="http://www.drive5.com/muscle/"; +$PG{"muscle"}{"language"}="C++"; +$PG{"muscle"}{"language2"}="GPP"; +$PG{"muscle"}{"source"}="http://www.drive5.com/muscle/downloads3.7/muscle3.7_src.tar.gz"; +$PG{"muscle"}{"windows"}="http://www.drive5.com/muscle/downloads3.7/muscle3.7_win32.zip"; +$PG{"muscle"}{"linux"}="http://www.drive5.com/muscle/downloads3.7/muscle3.7_linux_ia32.tar.gz"; +$PG{"muscle"}{"mode"}="mcoffee,rcoffee"; +$PG{"muscle"}{"version"}="3.7"; +$PG{"mus4"}{"4_TCOFFEE"}="MUS4"; +$PG{"mus4"}{"type"}="sequence_multiple_aligner"; +$PG{"mus4"}{"ADDRESS"}="http://www.drive5.com/muscle/"; +$PG{"mus4"}{"language"}="C++"; +$PG{"mus4"}{"language2"}="GPP"; +$PG{"mus4"}{"source"}="http://www.drive5.com/muscle/muscle4.0_src.tar.gz"; +$PG{"mus4"}{"mode"}="mcoffee,rcoffee"; +$PG{"mus4"}{"version"}="4.0"; +$PG{"pcma"}{"4_TCOFFEE"}="PCMA"; +$PG{"pcma"}{"type"}="sequence_multiple_aligner"; +$PG{"pcma"}{"ADDRESS"}="ftp://iole.swmed.edu/pub/PCMA/"; +$PG{"pcma"}{"language"}="C"; +$PG{"pcma"}{"language2"}="C"; +$PG{"pcma"}{"source"}="ftp://iole.swmed.edu/pub/PCMA/pcma.tar.gz"; +$PG{"pcma"}{"mode"}="mcoffee"; +$PG{"pcma"}{"version"}="1.0"; +$PG{"kalign"}{"4_TCOFFEE"}="KALIGN"; +$PG{"kalign"}{"type"}="sequence_multiple_aligner"; +$PG{"kalign"}{"ADDRESS"}="http://msa.cgb.ki.se"; +$PG{"kalign"}{"language"}="C"; +$PG{"kalign"}{"language2"}="C"; +$PG{"kalign"}{"source"}="http://msa.cgb.ki.se/downloads/kalign/current.tar.gz"; +$PG{"kalign"}{"mode"}="mcoffee"; +$PG{"kalign"}{"version"}="1.0"; +$PG{"amap"}{"4_TCOFFEE"}="AMAP"; +$PG{"amap"}{"type"}="sequence_multiple_aligner"; +$PG{"amap"}{"ADDRESS"}="http://bio.math.berkeley.edu/amap/"; +$PG{"amap"}{"language"}="C++"; +$PG{"amap"}{"language2"}="CXX"; +$PG{"amap"}{"source"}="http://amap-align.googlecode.com/files/amap.2.0.tar.gz"; +$PG{"amap"}{"mode"}="mcoffee"; +$PG{"amap"}{"version"}="2.0"; +$PG{"proda"}{"4_TCOFFEE"}="PRODA"; +$PG{"proda"}{"type"}="sequence_multiple_aligner"; +$PG{"proda"}{"ADDRESS"}="http://proda.stanford.edu"; +$PG{"proda"}{"language"}="C++"; +$PG{"proda"}{"language2"}="CXX"; +$PG{"proda"}{"source"}="http://proda.stanford.edu/proda_1_0.tar.gz"; +$PG{"proda"}{"mode"}="mcoffee"; +$PG{"proda"}{"version"}="1.0"; +$PG{"fsa"}{"4_TCOFFEE"}="FSA"; +$PG{"fsa"}{"type"}="sequence_multiple_aligner"; +$PG{"fsa"}{"ADDRESS"}="http://fsa.sourceforge.net/"; +$PG{"fsa"}{"language"}="C++"; +$PG{"fsa"}{"language2"}="CXX"; +$PG{"fsa"}{"source"}="http://sourceforge.net/projects/fsa/files/fsa-1.15.3.tar.gz/download/"; +$PG{"fsa"}{"mode"}="mcoffee"; +$PG{"fsa"}{"version"}="1.15.3"; +$PG{"prank"}{"4_TCOFFEE"}="PRANK"; +$PG{"prank"}{"type"}="sequence_multiple_aligner"; +$PG{"prank"}{"ADDRESS"}="http://www.ebi.ac.uk/goldman-srv/prank/"; +$PG{"prank"}{"language"}="C++"; +$PG{"prank"}{"language2"}="CXX"; +$PG{"prank"}{"source"}="http://www.ebi.ac.uk/goldman-srv/prank/src/prank/prank.src.100303.tgz"; +$PG{"prank"}{"mode"}="mcoffee"; +$PG{"prank"}{"version"}="100303"; +$PG{"sap"}{"4_TCOFFEE"}="SAP"; +$PG{"sap"}{"type"}="structure_pairwise_aligner"; +$PG{"sap"}{"ADDRESS"}="http://mathbio.nimr.mrc.ac.uk/wiki/Software"; +$PG{"sap"}{"language"}="C"; +$PG{"sap"}{"language2"}="C"; +$PG{"sap"}{"source"}="http://mathbio.nimr.mrc.ac.uk/download/sap-1.1.1.tar.gz"; +$PG{"sap"}{"mode"}="expresso,3dcoffee"; +$PG{"sap"}{"version"}="1.1.1"; +$PG{"TMalign"}{"4_TCOFFEE"}="TMALIGN"; +$PG{"TMalign"}{"type"}="structure_pairwise_aligner"; +$PG{"TMalign"}{"ADDRESS"}="http://zhang.bioinformatics.ku.edu/TM-align/TMalign.f"; +$PG{"TMalign"}{"language"}="Fortran"; +$PG{"TMalign"}{"language2"}="Fortran"; +$PG{"TMalign"}{"source"}="http://zhang.bioinformatics.ku.edu/TM-align/TMalign.f"; +$PG{"TMalign"}{"linux"}="http://zhang.bioinformatics.ku.edu/TM-align/TMalign_32.gz"; +$PG{"TMalign"}{"mode"}="expresso,3dcoffee"; +$PG{"TMalign"}{"version"}="1.0"; +$PG{"mustang"}{"4_TCOFFEE"}="MUSTANG"; +$PG{"mustang"}{"type"}="structure_pairwise_aligner"; +$PG{"mustang"}{"ADDRESS"}="http://www.cs.mu.oz.au/~arun/mustang"; +$PG{"mustang"}{"language"}="C++"; +$PG{"mustang"}{"language2"}="CXX"; +$PG{"mustang"}{"source"}="http://ww2.cs.mu.oz.au/~arun/mustang/mustang_v3.2.1.tgz"; +$PG{"mustang"}{"mode"}="expresso,3dcoffee"; +$PG{"mustang"}{"version"}="3.2.1"; +$PG{"lsqman"}{"4_TCOFFEE"}="LSQMAN"; +$PG{"lsqman"}{"type"}="structure_pairwise_aligner"; +$PG{"lsqman"}{"ADDRESS"}="empty"; +$PG{"lsqman"}{"language"}="empty"; +$PG{"lsqman"}{"language2"}="empty"; +$PG{"lsqman"}{"source"}="empty"; +$PG{"lsqman"}{"update_action"}="never"; +$PG{"lsqman"}{"mode"}="expresso,3dcoffee"; +$PG{"align_pdb"}{"4_TCOFFEE"}="ALIGN_PDB"; +$PG{"align_pdb"}{"type"}="structure_pairwise_aligner"; +$PG{"align_pdb"}{"ADDRESS"}="empty"; +$PG{"align_pdb"}{"language"}="empty"; +$PG{"align_pdb"}{"language2"}="empty"; +$PG{"align_pdb"}{"source"}="empty"; +$PG{"align_pdb"}{"update_action"}="never"; +$PG{"align_pdb"}{"mode"}="expresso,3dcoffee"; +$PG{"fugueali"}{"4_TCOFFEE"}="FUGUE"; +$PG{"fugueali"}{"type"}="structure_pairwise_aligner"; +$PG{"fugueali"}{"ADDRESS"}="http://www-cryst.bioc.cam.ac.uk/fugue/download.html"; +$PG{"fugueali"}{"language"}="empty"; +$PG{"fugueali"}{"language2"}="empty"; +$PG{"fugueali"}{"source"}="empty"; +$PG{"fugueali"}{"update_action"}="never"; +$PG{"fugueali"}{"mode"}="expresso,3dcoffee"; +$PG{"dalilite.pl"}{"4_TCOFFEE"}="DALILITEc"; +$PG{"dalilite.pl"}{"type"}="structure_pairwise_aligner"; +$PG{"dalilite.pl"}{"ADDRESS"}="built_in"; +$PG{"dalilite.pl"}{"ADDRESS2"}="http://www.ebi.ac.uk/Tools/webservices/services/dalilite"; +$PG{"dalilite.pl"}{"language"}="Perl"; +$PG{"dalilite.pl"}{"language2"}="Perl"; +$PG{"dalilite.pl"}{"source"}="empty"; +$PG{"dalilite.pl"}{"update_action"}="never"; +$PG{"dalilite.pl"}{"mode"}="expresso,3dcoffee"; +$PG{"probconsRNA"}{"4_TCOFFEE"}="PROBCONSRNA"; +$PG{"probconsRNA"}{"type"}="RNA_multiple_aligner"; +$PG{"probconsRNA"}{"ADDRESS"}="http://probcons.stanford.edu/"; +$PG{"probconsRNA"}{"language"}="C++"; +$PG{"probconsRNA"}{"language2"}="CXX"; +$PG{"probconsRNA"}{"source"}="http://probcons.stanford.edu/probconsRNA.tar.gz"; +$PG{"probconsRNA"}{"mode"}="mcoffee,rcoffee"; +$PG{"probconsRNA"}{"version"}="1.0"; +$PG{"sfold"}{"4_TCOFFEE"}="CONSAN"; +$PG{"sfold"}{"type"}="RNA_pairwise_aligner"; +$PG{"sfold"}{"ADDRESS"}="http://selab.janelia.org/software/consan/"; +$PG{"sfold"}{"language"}="empty"; +$PG{"sfold"}{"language2"}="empty"; +$PG{"sfold"}{"source"}="empty"; +$PG{"sfold"}{"update_action"}="never"; +$PG{"sfold"}{"mode"}="rcoffee"; +$PG{"RNAplfold"}{"4_TCOFFEE"}="RNAPLFOLD"; +$PG{"RNAplfold"}{"type"}="RNA_secondarystructure_predictor"; +$PG{"RNAplfold"}{"ADDRESS"}="http://www.tbi.univie.ac.at/~ivo/RNA/"; +$PG{"RNAplfold"}{"language"}="C"; +$PG{"RNAplfold"}{"language2"}="C"; +$PG{"RNAplfold"}{"source"}="http://www.tbi.univie.ac.at/~ivo/RNA/ViennaRNA-1.7.2.tar.gz"; +$PG{"RNAplfold"}{"mode"}="rcoffee,"; +$PG{"RNAplfold"}{"version"}="1.7.2"; +$PG{"retree"}{"4_TCOFFEE"}="PHYLIP"; +$PG{"retree"}{"type"}="RNA_secondarystructure_predictor"; +$PG{"retree"}{"ADDRESS"}="http://evolution.gs.washington.edu/phylip/"; +$PG{"retree"}{"language"}="C"; +$PG{"retree"}{"language2"}="C"; +$PG{"retree"}{"source"}="http://evolution.gs.washington.edu/phylip/download/phylip-3.69.tar.gz"; +$PG{"retree"}{"mode"}="trmsd,"; +$PG{"retree"}{"version"}="3.69"; +$PG{"hmmtop"}{"4_TCOFFEE"}="HMMTOP"; +$PG{"hmmtop"}{"type"}="protein_secondarystructure_predictor"; +$PG{"hmmtop"}{"ADDRESS"}="www.enzim.hu/hmmtop/"; +$PG{"hmmtop"}{"language"}="C"; +$PG{"hmmtop"}{"language2"}="C"; +$PG{"hmmtop"}{"source"}="empty"; +$PG{"hmmtop"}{"update_action"}="never"; +$PG{"hmmtop"}{"mode"}="tcoffee"; +$PG{"gorIV"}{"4_TCOFFEE"}="GOR4"; +$PG{"gorIV"}{"type"}="protein_secondarystructure_predictor"; +$PG{"gorIV"}{"ADDRESS"}="http://mig.jouy.inra.fr/logiciels/gorIV/"; +$PG{"gorIV"}{"language"}="C"; +$PG{"gorIV"}{"language2"}="C"; +$PG{"gorIV"}{"source"}="http://mig.jouy.inra.fr/logiciels/gorIV/GOR_IV.tar.gz"; +$PG{"gorIV"}{"update_action"}="never"; +$PG{"gorIV"}{"mode"}="tcoffee"; +$PG{"wublast.pl"}{"4_TCOFFEE"}="EBIWUBLASTc"; +$PG{"wublast.pl"}{"type"}="protein_homology_predictor"; +$PG{"wublast.pl"}{"ADDRESS"}="built_in"; +$PG{"wublast.pl"}{"ADDRESS2"}="http://www.ebi.ac.uk/Tools/webservices/services/wublast"; +$PG{"wublast.pl"}{"language"}="Perl"; +$PG{"wublast.pl"}{"language2"}="Perl"; +$PG{"wublast.pl"}{"source"}="empty"; +$PG{"wublast.pl"}{"update_action"}="never"; +$PG{"wublast.pl"}{"mode"}="psicoffee,expresso,accurate"; +$PG{"blastpgp.pl"}{"4_TCOFFEE"}="EBIBLASTPGPc"; +$PG{"blastpgp.pl"}{"type"}="protein_homology_predictor"; +$PG{"blastpgp.pl"}{"ADDRESS"}="built_in"; +$PG{"blastpgp.pl"}{"ADDRESS2"}="http://www.ebi.ac.uk/Tools/webservices/services/blastpgp"; +$PG{"blastpgp.pl"}{"language"}="Perl"; +$PG{"blastpgp.pl"}{"language2"}="Perl"; +$PG{"blastpgp.pl"}{"source"}="empty"; +$PG{"blastpgp.pl"}{"update_action"}="never"; +$PG{"blastpgp.pl"}{"mode"}="psicoffee,expresso,accurate"; +$PG{"blastcl3"}{"4_TCOFFEE"}="NCBIWEBBLAST"; +$PG{"blastcl3"}{"type"}="protein_homology_predictor"; +$PG{"blastcl3"}{"ADDRESS"}="ftp://ftp.ncbi.nih.gov/blast/executables/LATEST"; +$PG{"blastcl3"}{"language"}="C"; +$PG{"blastcl3"}{"language2"}="C"; +$PG{"blastcl3"}{"source"}="empty"; +$PG{"blastcl3"}{"update_action"}="never"; +$PG{"blastcl3"}{"mode"}="psicoffee,expresso,3dcoffee"; +$PG{"blastall"}{"4_TCOFFEE"}="blastall"; +$PG{"blastall"}{"type"}="protein_homology_predictor"; +$PG{"blastall"}{"ADDRESS"}="ftp://ftp.ncbi.nih.gov/blast/executables/LATEST"; +$PG{"blastall"}{"language"}="C"; +$PG{"blastall"}{"language2"}="C"; +$PG{"blastall"}{"source"}="empty"; +$PG{"blastall"}{"update_action"}="never"; +$PG{"blastall"}{"mode"}="psicoffee,expresso,3dcoffee"; +$PG{"legacy_blast.pl"}{"4_TCOFFEE"}="NCBIBLAST"; +$PG{"legacy_blast.pl"}{"type"}="protein_homology_predictor"; +$PG{"legacy_blast.pl"}{"ADDRESS"}="ftp://ftp.ncbi.nih.gov/blast/executables/LATEST"; +$PG{"legacy_blast.pl"}{"language"}="C"; +$PG{"legacy_blast.pl"}{"language2"}="C"; +$PG{"legacy_blast.pl"}{"source"}="empty"; +$PG{"legacy_blast.pl"}{"update_action"}="never"; +$PG{"legacy_blast.pl"}{"mode"}="psicoffee,expresso,3dcoffee"; +$PG{"SOAP::Lite"}{"4_TCOFFEE"}="SOAPLITE"; +$PG{"SOAP::Lite"}{"type"}="library"; +$PG{"SOAP::Lite"}{"ADDRESS"}="http://cpansearch.perl.org/src/MKUTTER/SOAP-Lite-0.710.08/Makefile.PL"; +$PG{"SOAP::Lite"}{"language"}="Perl"; +$PG{"SOAP::Lite"}{"language2"}="Perl"; +$PG{"SOAP::Lite"}{"source"}="empty"; +$PG{"blastpgp"}{"update_action"}="never"; +$PG{"SOAP::Lite"}{"mode"}="none"; +$PG{"XML::Simple"}{"4_TCOFFEE"}="XMLSIMPLE"; +$PG{"XML::Simple"}{"type"}="library"; +$PG{"XML::Simple"}{"ADDRESS"}="http://search.cpan.org/~grantm/XML-Simple-2.18/lib/XML/Simple.pm"; +$PG{"XML::Simple"}{"language"}="Perl"; +$PG{"XML::Simple"}{"language2"}="Perl"; +$PG{"XML::Simple"}{"source"}="empty"; +$PG{"XML::Simple"}{"mode"}="psicoffee,expresso,accurate"; +$MODE{"tcoffee"}{"name"}="tcoffee"; +$MODE{"rcoffee"}{"name"}="rcoffee"; +$MODE{"3dcoffee"}{"name"}="3dcoffee"; +$MODE{"mcoffee"}{"name"}="mcoffee"; +$MODE{"expresso"}{"name"}="expresso"; +$MODE{"trmsd"}{"name"}="trmsd"; +$MODE{"accurate"}{"name"}="accurate"; +$MODE{"seq_reformat"}{"name"}="seq_reformat"; +#TclinkdbEnd End tag for the list updating + +########### Compilers ############################## +# +# + +$PG{C}{compiler}="gcc"; +$PG{C}{compiler_flag}="CC"; +$PG{C}{options}=""; +$PG{C}{options_flag}="CFLAGS"; +$PG{C}{type}="compiler"; + +$PG{"CXX"}{compiler}="g++"; +$PG{"CXX"}{compiler_flag}="CXX"; +$PG{"CXX"}{options}=""; +$PG{"CXX"}{options_flag}="CXXFLAGS"; +$PG{CXX}{type}="compiler"; + +$PG{"CPP"}{compiler}="g++"; +$PG{"CPP"}{compiler_flag}="CPP"; +$PG{"CPP"}{options}=""; +$PG{"CPP"}{options_flag}="CPPFLAGS"; +$PG{CPP}{type}="compiler"; + +$PG{"GPP"}{compiler}="g++"; +$PG{"GPP"}{compiler_flag}="GPP"; +$PG{"GPP"}{options}=""; +$PG{"GPP"}{options_flag}="CFLAGS"; +$PG{GPP}{type}="compiler"; + +$PG{Fortran}{compiler}="g77"; +$PG{Fortran}{compiler_flag}="FCC"; +$PG{Fortran}{type}="compiler"; + +$PG{Perl}{compiler}="CPAN"; +$PG{Perl}{type}="compiler"; + +$SUPPORTED_OS{macox}="Macintosh"; +$SUPPORTED_OS{linux}="Linux"; +$SUPPORTED_OS{windows}="Cygwin"; + + + +$MODE{t_coffee}{description}=" for regular multiple sequence alignments"; +$MODE{rcoffee} {description}=" for RNA multiple sequence alignments"; + +$MODE{psicoffee} {description}=" for Homology Extended multiple sequence alignments"; +$MODE{expresso}{description}=" for very accurate structure based multiple sequence alignments"; +$MODE{"3dcoffee"}{description}=" for multiple structure alignments"; +$MODE{mcoffee} {description}=" for combining alternative multiple sequence alignment packages\n------- into a unique meta-package. The installer will upload several MSA packages and compile them\n +"; + + +&post_process_PG(); +return; +} + +sub post_process_PG + { + my $p; + + %PG=&name2dname (%PG); + %MODE=&name2dname(%MODE); + foreach $p (keys(%PG)){if ( $PG{$p}{type} eq "compiler"){$PG{$p}{update_action}="never";}} + + } + +sub name2dname + { + my (%L)=(@_); + my ($l, $ml); + + foreach my $pg (keys(%L)) + { + $l=length ($pg); + if ( $l>$ml){$ml=$l;} + } + $ml+=1; + foreach my $pg (keys(%L)) + { + my $name; + $l=$ml-length ($pg); + $name=$pg; + for ( $b=0; $b<$l; $b++) + { + $name .=" "; + } + $L{$pg}{dname}=$name; + } + return %L; + } + +sub env_file2putenv + { + my $f=@_[0]; + my $F=new FileHandle; + my $n; + + open ($F, "$f"); + while (<$F>) + { + my $line=$_; + my($var, $value)=($_=~/(\S+)\=(\S*)/); + $ENV{$var}=$value; + $ENV_SET{$var}=1; + $n++; + } + close ($F); + return $n; + } + +sub replace_line_in_file + { + my ($file, $wordin, $wordout)=@_; + my $O=new FileHandle; + my $I=new FileHandle; + my $l; + if (!-e $file){return;} + + system ("mv $file $file.old"); + open ($O, ">$file"); + open ($I, "$file.old"); + while (<$I>) + { + $l=$_; + if (!($l=~/$wordin/)){print $O "$l";} + elsif ( $wordout ne ""){$l=~s/$wordin/$wordout/g;print $O "$l";} + } + close ($O); + close ($I); + return; + } + +sub add_C_libraries + { + my ($file,$first,@list)=@_; + + my $O=new FileHandle; + my $I=new FileHandle; + my ($l,$anchor); + if (!-e $file){return;} + + $anchor="#include <$first>"; + + system ("mv $file $file.old"); + open ($O, ">$file"); + open ($I, "$file.old"); + while (<$I>) + { + $l=$_; + print $O "$l"; + if (!($l=~/$anchor/)) + { + + foreach my $lib (@list) + { + print $O "#include <$lib>\n"; + } + } + } + close ($O); + close ($I); + return; + } diff --git a/binaries/src/tcoffee/license.txt b/binaries/src/tcoffee/license.txt new file mode 100644 index 0000000..3321dbf --- /dev/null +++ b/binaries/src/tcoffee/license.txt @@ -0,0 +1,348 @@ +-------------------------------COPYRIGHT NOTICE------------------------------/ + ACADEMIC LICENCE AGREEMENT + + © Centro de Regulacio Genomica and Cedric Notredame ( Fri Feb 18 08:27:45 CET 2011 - Revision 596). + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + + + +-------------------------------COPYRIGHT NOTICE------------------------------/ diff --git a/binaries/src/tcoffee/t_coffee_source/CUSTOM_evaluate_for_struc.c b/binaries/src/tcoffee/t_coffee_source/CUSTOM_evaluate_for_struc.c new file mode 100644 index 0000000..fac03a8 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/CUSTOM_evaluate_for_struc.c @@ -0,0 +1,460 @@ +#include +#include +#include +#include + + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" + +#include "dp_lib_header.h" + + +/* + 23/06/00, Cedric Notredame + + + 1-Content of the data structures. + 2-Implementing your own function in pdb_align. + 3-Using that function with T-Coffee (multiple Sequence Alignment). + 4-Syntax rules as defined by Philipp Bucher (19/06/00). + 5-Current Shortcomings + 6-Enquiries. + + 1-Content of the data structures + + This file only contains a dummy function to help you create + your own matching potential function (Step 2 in the Notations RULES + + int evaluate_match_score ( Constraint_list *CL, int A, int i, int B, int j) + + returns a score, expected to be between -100 and 100, that corresponds to the matching of + A_i with B_j. + + Most needed parameters are included in the data structure CL, + This Data Structure is declared in util_constraint_list.h + The following, non exhaustive list explains the most common parameters + + The neighborhood is computed using: + ((CL->T[A])->pdb_param)->maximum_distance as a radius for the Bubble + ((CL->T[A])->pdb_param)->n_excluded_nb are excluded around the central residue + i.e i-1 and i+1 for n_excluded_nb=1. + + + ((CL->T[A])->Bubble)->nb[i][0] --> Number of residues in the bubble around A_i + ((CL->T[A])->Bubble)->nb[i][k]=j --> Index of the kth residue in the bubble + Residues are sorted according to the Ca chain + ((CL->T[A])->Bubble)->d_nb[i][k]=d --> Distance between A_i and A_j equals d; + + ((CL->T[A])->ca[i]->x -----------> Coordinates of the Ca A_i + ((CL->T[A])->ca[i]->y + ((CL->T[A])->ca[i]->z + + + + ((CL->T[A])->len -----------> Length of Chain A. + ((CL->T[A])->n_atom -----------> n atoms in A. + + + Unspecified parameters can be passed from the command line: + + align_pdb -extra_parameters=10, 10.3, 11, 12.4, my_file + + The values of these parameters can be accessed in: + + ((CL->T[A])->pdb_param)->n_extra_param=4 + ((CL->T[A])->pdb_param)->extra_param[0]="10" + ((CL->T[A])->pdb_param)->extra_param[1]="10.3" + ((CL->T[A])->pdb_param)->extra_param[2]="11.6" + ((CL->T[A])->pdb_param)->extra_param[3]="my_file" + + These parameters contain strings! To get the real values, in C, use atoi and atof: + atoi ( ((CL->T[A])->pdb_param)->extra_param[0])=10; + atof ( ((CL->T[A])->pdb_param)->extra_param[1])=10.3; + + The maximum number of parameters is currently 1000... + + + + 2-Implementing your own function + + all you need to do is to edit this file and recompile align_pdb. + There is no need to prototype any function. + + 10 functions holders exist, that correspond to the 10 dummy functions + declared in this file: + custom_pair_score_function1 + custom_pair_score_function2 + custom_pair_score_function3 + custom_pair_score_function4 + ..... + custom_pair_score_function10 + + Let us imagine, you want to use custom_pair_function1. + + 1-In CUSTOM_evaluate_for_struc.c, modify custom_pair_function1, + so that it computes the score you need. + + 2-If you need extra parameters, get them from ((CL->T[A])->pdb_param)->extra_param. + 3-Recompile pdb_align: + -put it in your bin + -rehash or whatever + + 4-run the program as follows: + + align_pdb -in -hasch_mode=custom_pair_score_function1 + -extra_param=10, 12, 0.4, matrix... + + 5-My advice for a first time: make a very simple dummy function that spits + out the content of extra_param. + + 6-Remember it is your responsability to control the number of extra parameters + and their proper order, and type. Do not forget to apply atoi and atof to the parameters + + 7-Remember that the modifications you made to CUSTOM_evaluate_for_sytructure + must be preserved by you!!! They may disappear if you update align_pdb, save them + appart as your own patch. + + + + +3-Using that function with T-Coffee (multiple Sequence Alignment). + + 1- setenv ALIGN_PDB_4_TCOFFEE + + 2- run t_coffee + To do so, you will NOT NEED to recompile T-Coffee, simply type: + t_coffee -in ... custom1_align_pdb_pair + + + +4-Syntax rules as defined by Philipp Bucher (19/06/00). + + Proposed ascii text notation for align_pdb + + First, let us summarize the align pdb algorithm in plain + english: + + Given are two protein structures A and B. + + Step 1: For each residue in each structure extract + the local structural neighbourhood. A neighbourhood + is simply a subset of (usually non-consecutive) + residues from one of the structures. + + Step 2: For all possible pairs of residues between structures + A and B, compute the optimal neighbourhood alignment + score. This score, which is also referred to as + local neighbourhood similarity (LNS) score indicates + whether two residues have similar local stuctural + environemnts. + + Step 3: Generate one (or multiple) optimal structural alignment(s) + for A and B based on LNS scores plus some gap penalty + function. + + Now, some rules for ascii/email notation: + + - Whenever possible use a style which fits on one line (because it + is painful to modify formulas that span over several lines). Example: + + Use: ( a**2 + b**2 )**0.5 + ________ + | 2 2 + instead of: \| a + b + + Introduce local variables/functions to split long expressions over + several lines, e.g. + + Score = Sum(0 Step 1: For each residue in each structure, extract + > the local structural neighbourhood. A neighbourhood + > is simply a subset of (usually non-consecutive) + > residues from the same structure. + + The result is something like: + + P(i) = P_1(i) .. P_k(i) .. P_K_i(i) + Q(i) = Q_1(j) .. Q_l(j) .. Q_L_j(j) + + These are all ordered integer arrays. The P's and Q's indicate + residue positions in sequence space. For the C-alpha coordinates, + we use: + + C(i) = C_1(i) .. C_k(i) .. C_K_i(i) + D(i) = D_1(j) .. D_l(j) .. D_L_i(j) + + > Step 2: For all possible pairs of residues between structures + > A and B, compute the optimal neighbourhood alignment + > score. This score, which is also referred to as + > local neighbourhood similarity (NSL) score indicates + > whether two residues have similar local stuctural + > environemnts. + + We have to define a similarity score: + + S(i,j) = function[A,B,P(i),Q(j)] + + More specifically, S(i,j) is the score of an opimal alignment between + two subsets of C-alpha coordinates from A and B, defined by P(i) and Q(j). + We use the following notation for an alignment between two neighbourhoods. + + R = (k_1,l_1) .. (k_m,l_m) .. (k_M, l_M) + + This is pretty abstract and requires some explanation. + + The alignment consists of M pairs of residues from two neighbourhoods. + The paired residues are numbered 1,2...K and 1,2...L, respectively. + Obviously M <= K,L. For K=9 and L=7, a possible alignment would + look as follows: + + R = (1,2) , (2,3) , (5,4) , (6,5) , (9,7) + + This alignment consists of five paired residues, the first + residue of neighbourhood P(i) is aligned with with the second residue + of Q(j), etc. + + The score of an alignment Z(R) is a function that can be + defined in many different ways. But independently of its + definition: + + S(i,j) = Z(R*,A,B,P(i),Q(j)) + R* = argmax Z(R,A,B,P(i),Q(j)) + + This is just a complicated way of saying that the LNS score + S(i,j) is an optimal alignment score. A simple alignment + scoring function would be: + + Z = Sum(m=1..M) [ 2 - |C_(k_m) - D_l_m)| ] + + A more complex function could be the sum of the sums of "pair-weights", + "pair-connection-weights", and unpaired-residue-weights": + + Z = Sum(m=1 .. M) [ PW (i,P_k_m,Q_l_m,C_k_m, D_l_m) ] + + Sum(m=2 .. M ) [ PCW(j,P_k_m,P_l_m,Q_k_m-1,Q_l_m-1,C_k_m,D_l_m,C_k_m-1,D_j_m-1 ] + + Sum(over k for all C_i(k) unpaired) UPRW [P_k, C_k ] + + Sum(over l for all C_i(l) unpaired) UPRW [Q_l, D_l)) ] + + Here, the terms P_k_m ... denote sequence positions, the terms C_k_m ... + denote coordinates. i and j, the sequence position of the center residues + of the neighbourhoods under consideration) are included in the argument + lists of the functions because they are necessary to decide whether + a residue A_k_m occurs before or after the residue A_i in sequence space. + We don not want to align a residue A_k_m that occurs before A_i with + a residue B_j_l that occurs after B_j and vice-versa. + + The LNS score could also be defined by a recursive equation system + defining a dynamic programming algorithm. However, I find the + above formulation more helpful for designing appropriate alignment + scoring functions. + + > Step 3: Generate one (or multiple) optimal structural alignment(s)r + > for A and B based on NLS scores plus some gap penalty + > function. + + This is now pretty simple. We use essentially the same notation as + for the neighbourhood alignments. + + R = (i_1,j_1) .. (i_n,j_n) .. (i_N, j_N) + + X* = X(R*,A,B) + R* = argmax X(R,A,B) + + The alignment scoring functing X is the sum of the LNS scores + of the pairs minus some gap penalties. + + +5-Current Shortcomings + + At present, it is impossible to use the extra_param flag with T-Coffee. This means that + the actual values of your parameters must be HARD-CODED within the custom_pair_score_function + you are using. + + On request, I will implement a solution to solve that problem. + +6-Contact + For any enquiry, please send a mail to: + cedric.notredame@europe.com + */ + + + + + + + + +int custom_pair_score_function1 (Constraint_list *CL, int s1, int r1, int s2, int r2) + { + int score=0; + int a; + FILE *fp; + + fp=vfopen ( "test_file", "w"); + for ( a=0; a< ((CL->T[0])->pdb_param)->n_extra_param; a++) + fprintf (fp, "\n\t%s", ((CL->T[0])->pdb_param)->extra_param[a]); + + fprintf ( fp, "\nTEST OK"); + vfclose ( fp); + exit (1); + + return score; + + } +int custom_pair_score_function2 (Constraint_list *CL, int s1, int r1, int s2, int r2) + { + int score=0; + + return score; + + } +int custom_pair_score_function3 (Constraint_list *CL, int s1, int r1, int s2, int r2) + { + int score=0; + + return score; + + } +int custom_pair_score_function4 (Constraint_list *CL, int s1, int r1, int s2, int r2) + { + int score=0; + + return score; + + } +int custom_pair_score_function5 (Constraint_list *CL, int s1, int r1, int s2, int r2) + { + int score=0; + + return score; + + } +int custom_pair_score_function6 (Constraint_list *CL, int s1, int r1, int s2, int r2) + { + int score=0; + + return score; + + } +int custom_pair_score_function7 (Constraint_list *CL, int s1, int r1, int s2, int r2) + { + int score=0; + + return score; + + } +int custom_pair_score_function8 (Constraint_list *CL, int s1, int r1, int s2, int r2) + { + int score=0; + + return score; + + } + +int custom_pair_score_function9 (Constraint_list *CL, int s1, int r1, int s2, int r2) + { + int score=0; + + return score; + + } +int custom_pair_score_function10 (Constraint_list *CL, int s1, int r1, int s2, int r2) + { + int score=0; + + return score; + + } +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/TMalign.f b/binaries/src/tcoffee/t_coffee_source/TMalign.f new file mode 100644 index 0000000..5920db1 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/TMalign.f @@ -0,0 +1,2554 @@ +************************************************************************* +* This program is to identify the best alignment of two protein +* structures to give the best TM-score. By default, TM-score is +* normalized by the second protein. The program can be freely +* copied or modified or redistributed. +* (For comments, please email to: yzhang@ku.edu) +* +* Reference: +* Yang Zhang, Jeffrey Skolnick, Nucl. Acid Res. 2005 33: 2303-9 +* +************************ updating history ******************************* +* 2005/06/01: A small bug of two-point superposition was fixed. +* 2005/10/19: the program was reformed so that the alignment +* results are not dependent on the specific compilers. +* 2006/06/20: select 'A' if there is altLoc when reading PDB file. +* 2007/02/27: rotation matrix from Chain-1 to Chain-2 is added. +* 2007/04/18: add options with TM-score normalized by average +* length, shorter length, or longer length of two +* structures. +* 2007/05/23: add additional output file 'TM.sup_all' for showing +* all atoms while 'TM.sup' is only for aligned atoms +* 2007/09/19: add a new feature alignment to deal with the problem +* of aligning fractional structures (e.g. protein +* interfaces). +************************************************************************* + + program compares + PARAMETER(nmax=5000) + PARAMETER(nmax2=10000) + + COMMON/BACKBONE/XA(3,nmax,0:1) + common/dpc/score(nmax,nmax),gap_open,invmap(nmax) + common/alignrst/invmap0(nmax) + common/length/nseq1,nseq2 + common/d0/d0,anseq + common/d0min/d0_min + common/d00/d00,d002 + + character*100 fnam,pdb(100),outname + character*3 aa(-1:20),aanam,ss1(nmax),ss2(nmax) + character*100 s,du + character*200 outnameall_tmp,outnameall + character seq1(0:nmax),seq2(0:nmax) + character aseq1(nmax2),aseq2(nmax2),aseq3(nmax2) + + dimension xx(nmax),yy(nmax),zz(nmax) + dimension m1(nmax),m2(nmax) + dimension xtm1(nmax),ytm1(nmax),ztm1(nmax) + dimension xtm2(nmax),ytm2(nmax),ztm2(nmax) + common/init/invmap_i(nmax) + + common/TM/TM,TMmax + common/n1n2/n1(nmax),n2(nmax) + common/d8/d8 + common/initial4/mm1(nmax),mm2(nmax) + +ccc RMSD: + double precision r_1(3,nmax),r_2(3,nmax),r_3(3,nmax),w(nmax) + double precision u(3,3),t(3),rms,drms !armsd is real + data w /nmax*1.0/ +ccc + + data aa/ 'BCK','GLY','ALA','SER','CYS','VAL','THR','ILE', + & 'PRO','MET','ASP','ASN','LEU', + & 'LYS','GLU','GLN','ARG', + & 'HIS','PHE','TYR','TRP','CYX'/ + character*1 slc(-1:20) + data slc/'X','G','A','S','C','V','T','I', + & 'P','M','D','N','L','K','E','Q','R', + & 'H','F','Y','W','C'/ + + call getarg(1,fnam) + if(fnam.eq.' '.or.fnam.eq.'?'.or.fnam.eq.'-h')then + write(*,*) + write(*,*)'Brief instruction for running TM-align program:' + write(*,*)'(For detail: Zhang & Skolnick, Nucl. Acid Res.', + & '2005 33, 2303)' + write(*,*) + write(*,*)'1. Align ''structure.pdb'' to ''target.pdb''' + write(*,*)' (By default, TM-score is normalized by the ', + & 'length of ''target.pdb'')' + write(*,*)' >TMalign structure.pdb target.pdb' + write(*,*) + write(*,*)'2. Run TM-align and output the superposition ', + & 'to ''TM.sup'' and ''TM.sup_all'':' + write(*,*)' >TMalign structure.pdb target.pdb -o TM.sup' + write(*,*)' To view the superimposed structures of the', + & ' aligned regions by rasmol:' + write(*,*)' >rasmol -script TM.sup)' + write(*,*)' To view the superimposed structures of all', + & ' regions by rasmol:' + write(*,*)' >rasmol -script TM.sup_all)' + write(*,*) + write(*,*)'3. If you want TM-score normalized by ', + & 'an assigned length, e.g. 100 aa:' + write(*,*)' >TMalign structure.pdb target.pdb -L 100' + write(*,*)' If you want TM-score normalized by the ', + & 'average length of two structures:' + write(*,*)' >TMalign structure.pdb target.pdb -a' + write(*,*)' If you want TM-score normalized by the ', + & 'shorter length of two structures:' + write(*,*)' >TMalign structure.pdb target.pdb -b' + write(*,*)' If you want TM-score normalized by the ', + & 'longer length of two structures:' + write(*,*)' >TMalign structure.pdb target.pdb -c' + write(*,*) +c write(*,*)'5. If you want to set a minimum cutoff for d0, ', +c & 'e.g. d0>3.0' +c write(*,*)' (By default d0>0.5, this option need ', +c & 'be considered only when L<35 aa)' +c write(*,*)' >TMalign structure.pdb target.pdb -dmin 3.0' +c write(*,*) + write(*,*)'(All above options does not change the ', + & 'final structure alignment result)' + write(*,*) + goto 9999 + endif + +******* options -----------> + m_out=-1 !decided output + m_fix=-1 !fixed length-scale only for output + m_ave=-1 !using average length + m_d0_min=-1 !diminum d0 for search + m_d0=-1 !given d0 for both search and output + narg=iargc() + i=0 + j=0 + 115 continue + i=i+1 + call getarg(i,fnam) + if(fnam.eq.'-o')then + m_out=1 + i=i+1 + call getarg(i,outname) + elseif(fnam.eq.'-L')then !change both L_all and d0 + m_fix=1 + i=i+1 + call getarg(i,fnam) + read(fnam,*)L_fix + elseif(fnam.eq.'-dmin')then + m_d0_min=1 + i=i+1 + call getarg(i,fnam) + read(fnam,*)d0_min_input + elseif(fnam.eq.'-d0')then + m_d0=1 + i=i+1 + call getarg(i,fnam) + read(fnam,*)d0_fix + elseif(fnam.eq.'-a')then ! this will change the superposed output but not the alignment + m_ave=1 + i=i+1 + elseif(fnam.eq.'-b')then + m_ave=2 + i=i+1 + elseif(fnam.eq.'-c')then + m_ave=3 + i=i+1 + else + j=j+1 + pdb(j)=fnam + endif + if(i.lt.narg)goto 115 + +ccccccccc read data from first CA file: + open(unit=10,file=pdb(1),status='old') + i=0 + do while (.true.) + read(10,9001,end=1010) s + if(i.gt.0.and.s(1:3).eq.'TER')goto 1010 + if(s(1:3).eq.'ATO')then + if(s(13:16).eq.'CA '.or.s(13:16).eq.' CA '.or + & .s(13:16).eq.' CA')then + if(s(17:17).eq.' '.or.s(17:17).eq.'A')then + i=i+1 + read(s,9000)du,aanam,du,mm1(i),du, + $ xa(1,i,0),xa(2,i,0),xa(3,i,0) + do j=-1,20 + if(aanam.eq.aa(j))seq1(i)=slc(j) + enddo + ss1(i)=aanam + if(i.ge.nmax)goto 1010 + endif + endif + endif + enddo + 1010 continue + 9000 format(A17,A3,A2,i4,A4,3F8.3) + 9001 format(A100) + close(10) + nseq1=i +c^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +ccccccccc read data from the second CA file: + open(unit=10,file=pdb(2),status='old') + i=0 + do while (.true.) + read(10,9001,end=1011) s + if(i.gt.0.and.s(1:3).eq.'TER')goto 1011 + if(s(1:3).eq.'ATO')then + if(s(13:16).eq.'CA '.or.s(13:16).eq.' CA '.or. + & s(13:16).eq.' CA')then + if(s(17:17).eq.' '.or.s(17:17).eq.'A')then + i=i+1 + read(s,9000)du,aanam,du,mm2(i),du, + $ xa(1,i,1),xa(2,i,1),xa(3,i,1) + do j=-1,20 + if(aanam.eq.aa(j))seq2(i)=slc(j) + enddo + ss2(i)=aanam + if(i.ge.nmax)goto 1011 + endif + endif + endif + enddo + 1011 continue + close(10) + nseq2=i +c^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +*!!! Scale of TM-score in search is based on the smaller protein ---------> + d0_min=0.5 + if(m_d0_min.eq.1)then + d0_min=d0_min_input !for search + endif + anseq_min=min(nseq1,nseq2) + anseq=anseq_min !length for defining TMscore in search + d8=1.5*anseq_min**0.3+3.5 !remove pairs with dis>d8 during search & final + if(anseq.gt.15)then + d0=1.24*(anseq-15)**(1.0/3.0)-1.8 !scale for defining TM-score + else + d0=d0_min + endif + if(d0.lt.d0_min)d0=d0_min + if(m_d0.eq.1)d0=d0_fix + d00=d0 !for quickly calculate TM-score in searching + if(d00.gt.8)d00=8 + if(d00.lt.4.5)d00=4.5 + d002=d00**2 + nseq=max(nseq1,nseq2) + do i=1,nseq + n1(i)=i + n2(i)=i + enddo + +***** do alignment ************************** + CALL super_align !to find invmap(j) + +************************************************************ +*** resuperpose to find residues of dis + n_al=0 + do j=1,nseq2 + if(invmap0(j).gt.0)then + i=invmap0(j) + n_al=n_al+1 + xtm1(n_al)=xa(1,i,0) + ytm1(n_al)=xa(2,i,0) + ztm1(n_al)=xa(3,i,0) + xtm2(n_al)=xa(1,j,1) + ytm2(n_al)=xa(2,j,1) + ztm2(n_al)=xa(3,j,1) + m1(n_al)=i !for recording residue order + m2(n_al)=j + endif + enddo + d0_input=d0 + call TMscore8(d0_input,n_al,xtm1,ytm1,ztm1,n1,n_al, + & xtm2,ytm2,ztm2,n2,TM,Rcomm,Lcomm) !TM-score with dis + d0_min=0.5 !for output + anseq=nseq2 !length for defining final TMscore + if(m_ave.eq.1)anseq=(nseq1+nseq2)/2.0 ! + if(m_ave.eq.2)anseq=min(nseq1,nseq2) + if(m_ave.eq.3)anseq=max(nseq1,nseq2) + if(anseq.lt.anseq_min)anseq=anseq_min + if(m_fix.eq.1)anseq=L_fix !input length + if(anseq.gt.15)then + d0=1.24*(anseq-15)**(1.0/3.0)-1.8 !scale for defining TM-score + else + d0=d0_min + endif + if(d0.lt.d0_min)d0=d0_min + if(m_d0.eq.1)d0=d0_fix + +*** remove dis>d8 in normal TM-score calculation for final report-----> + j=0 + n_eq=0 + do i=1,n_al + dis2=sqrt((xtm1(i)-xtm2(i))**2+(ytm1(i)-ytm2(i))**2+ + & (ztm1(i)-ztm2(i))**2) + if(dis2.le.d8)then + j=j+1 + xtm1(j)=xtm1(i) + ytm1(j)=ytm1(i) + ztm1(j)=ztm1(i) + xtm2(j)=xtm2(i) + ytm2(j)=ytm2(i) + ztm2(j)=ztm2(i) + m1(j)=m1(i) + m2(j)=m2(i) + if(ss1(m1(i)).eq.ss2(m2(i)))then + n_eq=n_eq+1 + endif + endif + enddo + seq_id=float(n_eq)/(n_al+0.00000001) + n8_al=j + d0_input=d0 + call TMscore(d0_input,n8_al,xtm1,ytm1,ztm1,n1,n8_al, + & xtm2,ytm2,ztm2,n2,TM8,Rcomm,Lcomm) !normal TMscore + rmsd8_al=Rcomm + TM8=TM8*n8_al/anseq !TM-score after cutoff + +********* for output summary ****************************** + write(*,*) + write(*,*)'*****************************************************', + & '*********************' + write(*,*)'* TM-align ', + & ' *' + write(*,*)'* A protein structural alignment algorithm based on T', + & 'M-score *' + write(*,*)'* Reference: Y. Zhang and J. Skolnick, Nucl. Acids Re', + & 's. 2005 33, 2302-9 *' + write(*,*)'* Comments on the program, please email to: yzhang@ku', + & '.edu *' + write(*,*)'*****************************************************', + & '*********************' + write(*,*) + write(*,101)pdb(1),nseq1 + 101 format('Chain 1:',A10,' Size=',I4) + write(*,102)pdb(2),nseq2,int(anseq) + 102 format('Chain 2:',A10,' Size=',I4, + & ' (TM-score is normalized by ',I4,')') + write(*,*) + write(*,103)n8_al,rmsd8_al,TM8,seq_id + 103 format('Aligned length=',I4,', RMSD=',f6.2, + & ', TM-score=',f7.5,', ID=',f5.3) + write(*,*) + +********* extract rotation matrix ------------> + L=0 + do i=1,n8_al + k=m1(i) + L=L+1 + r_1(1,L)=xa(1,k,0) + r_1(2,L)=xa(2,k,0) + r_1(3,L)=xa(3,k,0) + r_2(1,L)=xtm1(i) + r_2(2,L)=ytm1(i) + r_2(3,L)=ztm1(i) + enddo + if(L.gt.3)then + call u3b(w,r_1,r_2,L,1,rms,u,t,ier) !u rotate r_1 to r_2 + armsd=dsqrt(rms/L) + write(*,*)'-------- rotation matrix to rotate Chain-1 to ', + & 'Chain-2 ------' + write(*,*)'i t(i) u(i,1) u(i,2) ', + & ' u(i,3)' + do i=1,3 + write(*,204)i,t(i),u(i,1),u(i,2),u(i,3) + enddo +c do i=1,nseq1 +c ax=t(1)+u(1,1)*xa(1,i,0)+u(1,2)*xa(2,i,0)+u(1,3)*xa(3,i,0) +c ay=t(2)+u(2,1)*xa(1,i,0)+u(2,2)*xa(2,i,0)+u(2,3)*xa(3,i,0) +c az=t(3)+u(3,1)*xa(1,i,0)+u(3,2)*xa(2,i,0)+u(3,3)*xa(3,i,0) +c enddo + write(*,*) + endif + 204 format(I2,f18.10,f15.10,f15.10,f15.10) + +********* for output superposition ****************************** + if(m_out.eq.1)then + 1237 format('ATOM ',i5,' CA ',A3,I6,4X,3F8.3) + 1238 format('TER') + 1239 format('CONECT',I5,I5) + 900 format(A) + 901 format('select atomno=',I4) + 104 format('REMARK Chain 1:',A10,' Size=',I4) + 105 format('REMARK Chain 2:',A10,' Size=',I4, + & ' (TM-score is normalized by ',I4,')') + 106 format('REMARK Aligned length=',I4,', RMSD=',f6.2, + & ', TM-score=',f7.5,', ID=',f5.3) + OPEN(unit=7,file=outname,status='unknown') !pdb1.aln + pdb2.aln +*** script: + write(7,900)'load inline' + write(7,900)'select atomno<2000' + write(7,900)'wireframe .45' + write(7,900)'select none' + write(7,900)'select atomno>2000' + write(7,900)'wireframe .20' + write(7,900)'color white' + do i=1,n8_al + dis2=sqrt((xtm1(i)-xtm2(i))**2+ + & (ytm1(i)-ytm2(i))**2+(ztm1(i)-ztm2(i))**2) + if(dis2.le.5)then + write(7,901)m1(i) + write(7,900)'color red' + write(7,901)2000+m2(i) + write(7,900)'color red' + endif + enddo + write(7,900)'select all' + write(7,900)'exit' + write(7,104)pdb(1),nseq1 + write(7,105)pdb(2),nseq2,int(anseq) + write(7,106)n8_al,rmsd8_al,TM8,seq_id +*** chain1: + do i=1,n8_al + write(7,1237)m1(i),ss1(m1(i)),mm1(m1(i)), + & xtm1(i),ytm1(i),ztm1(i) + enddo + write(7,1238) !TER + do i=2,n8_al + write(7,1239)m1(i-1),m1(i) !connect atoms + enddo +*** chain2: + do i=1,n8_al + write(7,1237)2000+m2(i),ss2(m2(i)),mm2(m2(i)), + $ xtm2(i),ytm2(i),ztm2(i) + enddo + write(7,1238) + do i=2,n8_al + write(7,1239)2000+m2(i-1),2000+m2(i) + enddo + close(7) +ccc + k=0 + outnameall_tmp=outname//'_all' + outnameall='' + do i=1,200 + if(outnameall_tmp(i:i).ne.' ')then + k=k+1 + outnameall(k:k)=outnameall_tmp(i:i) + endif + enddo + OPEN(unit=8,file=outnameall,status='unknown') !pdb1.aln + pdb2.aln +*** script: + write(8,900)'load inline' + write(8,900)'select atomno<2000' + write(8,900)'wireframe .45' + write(8,900)'select none' + write(8,900)'select atomno>2000' + write(8,900)'wireframe .20' + write(8,900)'color white' + do i=1,n8_al + dis2=sqrt((xtm1(i)-xtm2(i))**2+ + & (ytm1(i)-ytm2(i))**2+(ztm1(i)-ztm2(i))**2) + if(dis2.le.5)then + write(8,901)m1(i) + write(8,900)'color red' + write(8,901)2000+m2(i) + write(8,900)'color red' + endif + enddo + write(8,900)'select all' + write(8,900)'exit' + write(8,104)pdb(1),nseq1 + write(8,105)pdb(2),nseq2,int(anseq) + write(8,106)n8_al,rmsd8_al,TM8,seq_id +*** chain1: + do i=1,nseq1 + ax=t(1)+u(1,1)*xa(1,i,0)+u(1,2)*xa(2,i,0)+u(1,3)*xa(3,i,0) + ay=t(2)+u(2,1)*xa(1,i,0)+u(2,2)*xa(2,i,0)+u(2,3)*xa(3,i,0) + az=t(3)+u(3,1)*xa(1,i,0)+u(3,2)*xa(2,i,0)+u(3,3)*xa(3,i,0) + write(8,1237)i,ss1(i),mm1(i),ax,ay,az + enddo + write(8,1238) !TER + do i=2,nseq1 + write(8,1239)i-1,i + enddo +*** chain2: + do i=1,nseq2 + write(8,1237)2000+i,ss2(i),mm2(i), + $ xa(1,i,1),xa(2,i,1),xa(3,i,1) + enddo + write(8,1238) + do i=2,nseq2 + write(8,1239)2000+i-1,2000+i + enddo + close(8) + endif +*^^^^^^^^^^^^^^^^^^ output finished ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +************ output aligned sequences ************************** + ii=0 + i1_old=1 + i2_old=1 + do i=1,n8_al + do j=i1_old,m1(i)-1 + ii=ii+1 + aseq1(ii)=seq1(j) + aseq2(ii)='-' + aseq3(ii)=' ' + enddo + do j=i2_old,m2(i)-1 + ii=ii+1 + aseq1(ii)='-' + aseq2(ii)=seq2(j) + aseq3(ii)=' ' + enddo + ii=ii+1 + aseq1(ii)=seq1(m1(i)) + aseq2(ii)=seq2(m2(i)) + dis2=sqrt((xtm1(i)-xtm2(i))**2+ + & (ytm1(i)-ytm2(i))**2+(ztm1(i)-ztm2(i))**2) + if(dis2.le.5)then + aseq3(ii)=':' + else + aseq3(ii)='.' + endif + i1_old=m1(i)+1 + i2_old=m2(i)+1 + enddo + do i=i1_old,nseq1 + ii=ii+1 + aseq1(ii)=seq1(i) + aseq2(ii)='-' + aseq3(ii)=' ' + enddo + do i=i2_old,nseq2 + ii=ii+1 + aseq1(ii)='-' + aseq2(ii)=seq2(i) + aseq3(ii)=' ' + enddo + write(*,50) + 50 format('(":" denotes the residue pairs of distance < 5.0 ', + & 'Angstrom)') + write(*,10)(aseq1(i),i=1,ii) + write(*,10)(aseq3(i),i=1,ii) + write(*,10)(aseq2(i),i=1,ii) + 10 format(10000A1) + write(*,*) + +c^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 9999 END + +*********************************************************************** +*********************************************************************** +* Structure superposition +*********************************************************************** +*********************************************************************** +*********************************************************************** + SUBROUTINE super_align + PARAMETER(nmax=5000) + COMMON/BACKBONE/XA(3,nmax,0:1) + common/length/nseq1,nseq2 + common/dpc/score(nmax,nmax),gap_open,invmap(nmax) + common/alignrst/invmap0(nmax) + common/zscore/zrms,n_al,rmsd_al + common/TM/TM,TMmax + common/init/invmap_i(nmax) + dimension gapp(100) + + TMmax=0 + n_gapp=2 + gapp(1)=-0.6 + gapp(2)=0 + +c n_gapp=11 +c do i=1,n_gapp +c gapp(i)=-(n_gapp-i) +c enddo + +*11111111111111111111111111111111111111111111111111111111 +* get initial alignment from gapless threading +********************************************************** + call get_initial !gapless threading + do i=1,nseq2 + invmap(i)=invmap_i(i) !with highest zcore + enddo + call get_score !TM, matrix score(i,j) + if(TM.gt.TMmax)then + TMmax=TM + do j=1,nseq2 + invmap0(j)=invmap(j) + enddo + endif + +***************************************************************** +* initerative alignment, for different gap_open: +***************************************************************** + DO 111 i_gapp=1,n_gapp !different gap panalties + GAP_OPEN=gapp(i_gapp) !gap panalty + do 222 id=1,30 !maximum interation is 200 + call DP(NSEQ1,NSEQ2) !produce alignment invmap(j) +* Input: score(i,j), and gap_open +* Output: invmap(j) + + call get_score !calculate TM-score, score(i,j) +c record the best alignment in whole search ----------> + if(TM.gt.TMmax)then + TMmax=TM + do j=1,nseq2 + invmap0(j)=invmap(j) + enddo + endif + if(id.gt.1)then + diff=abs(TM-TM_old) + if(diff.lt.0.000001)goto 33 + endif + TM_old=TM + 222 continue + 33 continue + 111 continue + +*222222222222222222222222222222222222222222222222222222222 +* get initial alignment from secondary structure alignment +********************************************************** + call get_initial2 !DP for secondary structure + do i=1,nseq2 + invmap(i)=invmap_i(i) !with highest zcore + enddo + call get_score !TM, score(i,j) + if(TM.gt.TMmax)then + TMmax=TM + do j=1,nseq2 + invmap0(j)=invmap(j) + enddo + endif + +***************************************************************** +* initerative alignment, for different gap_open: +***************************************************************** + DO 1111 i_gapp=1,n_gapp !different gap panalties + GAP_OPEN=gapp(i_gapp) !gap panalty + do 2222 id=1,30 !maximum interation is 200 + call DP(NSEQ1,NSEQ2) !produce alignment invmap(j) +* Input: score(i,j), and gap_open +* Output: invmap(j) + + call get_score !calculate TM-score, score(i,j) +c write(*,21)gap_open,rmsd_al,n_al,TM +c record the best alignment in whole search ----------> + if(TM.gt.TMmax)then + TMmax=TM + do j=1,nseq2 + invmap0(j)=invmap(j) + enddo + endif + if(id.gt.1)then + diff=abs(TM-TM_old) + if(diff.lt.0.000001)goto 333 + endif + TM_old=TM + 2222 continue + 333 continue + 1111 continue + +*333333333333333333333333333333333333333333333333333333333333 +* get initial alignment from invmap0+SS +************************************************************* + call get_initial3 !invmap0+SS + do i=1,nseq2 + invmap(i)=invmap_i(i) !with highest zcore + enddo + call get_score !TM, score(i,j) + if(TM.gt.TMmax)then + TMmax=TM + do j=1,nseq2 + invmap0(j)=invmap(j) + enddo + endif + +***************************************************************** +* initerative alignment, for different gap_open: +***************************************************************** + DO 1110 i_gapp=1,n_gapp !different gap panalties + GAP_OPEN=gapp(i_gapp) !gap panalty + do 2220 id=1,30 !maximum interation is 200 + call DP(NSEQ1,NSEQ2) !produce alignment invmap(j) +* Input: score(i,j), and gap_open +* Output: invmap(j) + + call get_score !calculate TM-score, score(i,j) +c write(*,21)gap_open,rmsd_al,n_al,TM +c record the best alignment in whole search ----------> + if(TM.gt.TMmax)then + TMmax=TM + do j=1,nseq2 + invmap0(j)=invmap(j) + enddo + endif + if(id.gt.1)then + diff=abs(TM-TM_old) + if(diff.lt.0.000001)goto 330 + endif + TM_old=TM + 2220 continue + 330 continue + 1110 continue + +*444444444444444444444444444444444444444444444444444444444 +* get initial alignment of pieces from gapless threading +********************************************************** + call get_initial4 !gapless threading + do i=1,nseq2 + invmap(i)=invmap_i(i) !with highest zcore + enddo + call get_score !TM, matrix score(i,j) + if(TM.gt.TMmax)then + TMmax=TM + do j=1,nseq2 + invmap0(j)=invmap(j) + enddo + endif + +***************************************************************** +* initerative alignment, for different gap_open: +***************************************************************** + DO 44 i_gapp=2,n_gapp !different gap panalties + GAP_OPEN=gapp(i_gapp) !gap panalty + do 444 id=1,2 !maximum interation is 200 + call DP(NSEQ1,NSEQ2) !produce alignment invmap(j) +* Input: score(i,j), and gap_open +* Output: invmap(j) + + call get_score !calculate TM-score, score(i,j) +c record the best alignment in whole search ----------> + if(TM.gt.TMmax)then + TMmax=TM + do j=1,nseq2 + invmap0(j)=invmap(j) + enddo + endif + 444 continue + 44 continue + +c^^^^^^^^^^^^^^^ best alignment invmap0(j) found ^^^^^^^^^^^^^^^^^^ + RETURN + END + +************************************************************** +* get initial alignment invmap0(i) from gapless threading +************************************************************** + subroutine get_initial + PARAMETER(nmax=5000) + COMMON/BACKBONE/XA(3,nmax,0:1) + common/length/nseq1,nseq2 + common/dpc/score(nmax,nmax),gap_open,invmap(nmax) + common/alignrst/invmap0(nmax) + common/zscore/zrms,n_al,rmsd_al + common/TM/TM,TMmax + common/init/invmap_i(nmax) + + aL=min(nseq1,nseq2) + idel=aL/2.5 !minimum size of considered fragment + if(idel.le.5)idel=5 + n1=-nseq2+idel + n2=nseq1-idel + GL_max=0 + do ishift=n1,n2 + L=0 + do j=1,nseq2 + i=j+ishift + if(i.ge.1.and.i.le.nseq1)then + L=L+1 + invmap(j)=i + else + invmap(j)=-1 + endif + enddo + if(L.ge.idel)then + call get_GL(GL) + if(GL.gt.GL_max)then + GL_max=GL + do i=1,nseq2 + invmap_i(i)=invmap(i) + enddo + endif + endif + enddo + + return + end + +************************************************************** +* get initial alignment invmap0(i) from secondary structure +************************************************************** + subroutine get_initial2 + PARAMETER(nmax=5000) + COMMON/BACKBONE/XA(3,nmax,0:1) + common/length/nseq1,nseq2 + common/dpc/score(nmax,nmax),gap_open,invmap(nmax) + common/alignrst/invmap0(nmax) + common/zscore/zrms,n_al,rmsd_al + common/TM/TM,TMmax + common/sec/isec(nmax),jsec(nmax) + common/init/invmap_i(nmax) + +********** assign secondary structures *************** +c 1->coil, 2->helix, 3->turn, 4->strand + do i=1,nseq1 + isec(i)=1 + j1=i-2 + j2=i-1 + j3=i + j4=i+1 + j5=i+2 + if(j1.ge.1.and.j5.le.nseq1)then + dis13=diszy(0,j1,j3) + dis14=diszy(0,j1,j4) + dis15=diszy(0,j1,j5) + dis24=diszy(0,j2,j4) + dis25=diszy(0,j2,j5) + dis35=diszy(0,j3,j5) + isec(i)=make_sec(dis13,dis14,dis15,dis24,dis25,dis35) + endif + enddo + do i=1,nseq2 + jsec(i)=1 + j1=i-2 + j2=i-1 + j3=i + j4=i+1 + j5=i+2 + if(j1.ge.1.and.j5.le.nseq2)then + dis13=diszy(1,j1,j3) + dis14=diszy(1,j1,j4) + dis15=diszy(1,j1,j5) + dis24=diszy(1,j2,j4) + dis25=diszy(1,j2,j5) + dis35=diszy(1,j3,j5) + jsec(i)=make_sec(dis13,dis14,dis15,dis24,dis25,dis35) + endif + enddo + call smooth !smooth the assignment + +********** score matrix ************************** + do i=1,nseq1 + do j=1,nseq2 + if(isec(i).eq.jsec(j))then + score(i,j)=1 + else + score(i,j)=0 + endif + enddo + enddo + +********** find initial alignment: invmap(j) ************ + gap_open=-1.0 !should be -1 + call DP(NSEQ1,NSEQ2) !produce alignment invmap(j) + do i=1,nseq2 + invmap_i(i)=invmap(i) + enddo + +*^^^^^^^^^^^^ initial alignment done ^^^^^^^^^^^^^^^^^^^^^^ + return + end + +************************************************************** +* get initial alignment invmap0(i) from secondary structure +* and previous alignments +************************************************************** + subroutine get_initial3 + PARAMETER(nmax=5000) + COMMON/BACKBONE/XA(3,nmax,0:1) + common/length/nseq1,nseq2 + common/dpc/score(nmax,nmax),gap_open,invmap(nmax) + common/alignrst/invmap0(nmax) + common/zscore/zrms,n_al,rmsd_al + common/TM/TM,TMmax + common/sec/isec(nmax),jsec(nmax) + common/init/invmap_i(nmax) + +********** score matrix ************************** + do i=1,nseq2 + invmap(i)=invmap0(i) + enddo + call get_score1 !get score(i,j) using RMSD martix + do i=1,nseq1 + do j=1,nseq2 + if(isec(i).eq.jsec(j))then + score(i,j)=0.5+score(i,j) + else + score(i,j)=score(i,j) + endif + enddo + enddo + +********** find initial alignment: invmap(j) ************ + gap_open=-1.0 !should be -1 + call DP(NSEQ1,NSEQ2) !produce alignment invmap(j) + do i=1,nseq2 + invmap_i(i)=invmap(i) + enddo + +*^^^^^^^^^^^^ initial alignment done ^^^^^^^^^^^^^^^^^^^^^^ + return + end + +************************************************************** +* get initial alignment invmap0(i) from fragment gapless threading +************************************************************** + subroutine get_initial4 + PARAMETER(nmax=5000) + COMMON/BACKBONE/XA(3,nmax,0:1) + common/length/nseq1,nseq2 + common/dpc/score(nmax,nmax),gap_open,invmap(nmax) + common/alignrst/invmap0(nmax) + common/zscore/zrms,n_al,rmsd_al + common/TM/TM,TMmax + common/init/invmap_i(nmax) + common/initial4/mm1(nmax),mm2(nmax) + logical contin + + dimension ifr2(2,nmax,nmax),Lfr2(2,nmax),Lfr_max2(2),i_fr2(2) + dimension ifr(nmax) + dimension mm(2,nmax) + + fra_min=4 !>=4,minimum fragment for search + fra_min1=fra_min-1 !cutoff for shift, save time + dcu0=3.85 + dcu_min=3.65 + +ccc Find the smallest continuous fragments --------> + do i=1,nseq1 + mm(1,i)=mm1(i) + enddo + do i=1,nseq2 + mm(2,i)=mm2(i) + enddo + do k=1,2 + dcu=dcu0 + if(k.eq.1)then + nseq0=nseq1 + r_min=nseq1/3.0 !minimum fragment, in case too small protein + else + nseq0=nseq2 + r_min=nseq2/3.0 !minimum fragment, in case too small protein + endif + if(r_min.gt.fra_min)r_min=fra_min + 20 nfr=1 !number of fragments + j=1 !number of residue at nf-fragment + ifr2(k,nfr,j)=1 !what residue + Lfr2(k,nfr)=j !length of the fragment + do i=2,nseq0 + dis=diszy(k-1,i-1,i) + contin=.false. + if(dcu.gt.dcu0)then + if(dis.lt.dcu)then + if(dis.gt.dcu_min)then + contin=.true. + endif + endif + elseif(mm(k,i).eq.(mm(k,i-1)+1))then + if(dis.lt.dcu)then + if(dis.gt.dcu_min)then + contin=.true. + endif + endif + endif + if(contin)then + j=j+1 + ifr2(k,nfr,j)=i + Lfr2(k,nfr)=j + else + nfr=nfr+1 + j=1 + ifr2(k,nfr,j)=i + Lfr2(k,nfr)=j + endif + enddo + Lfr_max=0 + i_fr2(k)=1 !ID of the maximum piece + do i=1,nfr + if(Lfr_max.lt.Lfr2(k,i))then + Lfr_max=Lfr2(k,i) + i_fr2(k)=i + endif + enddo + if(Lfr_max.lt.r_min)then + dcu=1.1*dcu + goto 20 + endif + enddo +c^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +ccc select what piece will be used (this may araise ansysmetry, but +ccc only when L1=L2 and Lfr1=Lfr2 and L1 ne Lfr1 +ccc if L1=Lfr1 and L2=Lfr2 (normal proteins), it will be the same as initial1 + mark=1 + if(Lfr2(1,i_fr2(1)).lt.Lfr2(2,i_fr2(2)))then + mark=1 + elseif(Lfr2(1,i_fr2(1)).gt.Lfr2(2,i_fr2(2)))then + mark=2 + else !Lfr1=Lfr2 + if(nseq1.le.nseq2)then + mark=1 + else + mark=2 + endif + endif +ccc + L_fr=Lfr2(mark,i_fr2(mark)) + do i=1,L_fr + ifr(i)=ifr2(mark,i_fr2(mark),i) + enddo +ccc + if(mark.eq.1)then !non-redundant to get_initial1 + nseq0=nseq1 + else + nseq0=nseq2 + endif + if(L_fr.eq.nseq0)then + n1=int(nseq0*0.1) !0 + n2=int(nseq0*0.89) !2 + j=0 + do i=n1,n2 + j=j+1 + ifr(j)=ifr(n1+j) + enddo + L_fr=j + endif + +ccc get initial -------------> + if(mark.eq.1)then !nseq1 as the smallest one + nseq1_=L_fr + aL=min(nseq1_,nseq2) + idel=aL/2.5 !minimum size of considered fragment + if(idel.le.fra_min1)idel=fra_min1 + n1=-nseq2+idel !shift1 + n2=nseq1_-idel !shift2 + GL_max=0 + do ishift=n1,n2 + L=0 + do j=1,nseq2 + i=j+ishift + if(i.ge.1.and.i.le.nseq1_)then + L=L+1 + invmap(j)=ifr(i) + else + invmap(j)=-1 + endif + enddo + if(L.ge.idel)then + call get_GL(GL) + if(GL.gt.GL_max)then + GL_max=GL + do i=1,nseq2 + invmap_i(i)=invmap(i) + enddo + endif + endif + enddo + else !@@@@@@@@@@@@@@@@@@@@ + nseq2_=L_fr + aL=min(nseq1,nseq2_) + idel=aL/2.5 !minimum size of considered fragment + if(idel.le.fra_min1)idel=fra_min1 + n1=-nseq2_+idel + n2=nseq1-idel + GL_max=0 + do ishift=n1,n2 + L=0 + do j=1,nseq2 + invmap(j)=-1 + enddo + do j=1,nseq2_ + i=j+ishift + if(i.ge.1.and.i.le.nseq1)then + L=L+1 + invmap(ifr(j))=i + endif + enddo + if(L.ge.idel)then + call get_GL(GL) + if(GL.gt.GL_max)then + GL_max=GL + do i=1,nseq2 + invmap_i(i)=invmap(i) + enddo + endif + endif + enddo + endif + + return + end + +************************************************************** +* smooth the secondary structure assignment +************************************************************** + subroutine smooth + PARAMETER(nmax=5000) + common/sec/isec(nmax),jsec(nmax) + common/length/nseq1,nseq2 + +*** smooth single --------------> +*** --x-- => ----- + do i=1,nseq1 + if(isec(i).eq.2.or.isec(i).eq.4)then + j=isec(i) + if(isec(i-2).ne.j)then + if(isec(i-1).ne.j)then + if(isec(i+1).ne.j)then + if(isec(i+1).ne.j)then + isec(i)=1 + endif + endif + endif + endif + endif + enddo + do i=1,nseq2 + if(jsec(i).eq.2.or.jsec(i).eq.4)then + j=jsec(i) + if(jsec(i-2).ne.j)then + if(jsec(i-1).ne.j)then + if(jsec(i+1).ne.j)then + if(jsec(i+1).ne.j)then + jsec(i)=1 + endif + endif + endif + endif + endif + enddo + +*** smooth double --------------> +*** --xx-- => ------ + do i=1,nseq1 + if(isec(i).ne.2)then + if(isec(i+1).ne.2)then + if(isec(i+2).eq.2)then + if(isec(i+3).eq.2)then + if(isec(i+4).ne.2)then + if(isec(i+5).ne.2)then + isec(i+2)=1 + isec(i+3)=1 + endif + endif + endif + endif + endif + endif + + if(isec(i).ne.4)then + if(isec(i+1).ne.4)then + if(isec(i+2).eq.4)then + if(isec(i+3).eq.4)then + if(isec(i+4).ne.4)then + if(isec(i+5).ne.4)then + isec(i+2)=1 + isec(i+3)=1 + endif + endif + endif + endif + endif + endif + enddo + do i=1,nseq2 + if(jsec(i).ne.2)then + if(jsec(i+1).ne.2)then + if(jsec(i+2).eq.2)then + if(jsec(i+3).eq.2)then + if(jsec(i+4).ne.2)then + if(jsec(i+5).ne.2)then + jsec(i+2)=1 + jsec(i+3)=1 + endif + endif + endif + endif + endif + endif + + if(jsec(i).ne.4)then + if(jsec(i+1).ne.4)then + if(jsec(i+2).eq.4)then + if(jsec(i+3).eq.4)then + if(jsec(i+4).ne.4)then + if(jsec(i+5).ne.4)then + jsec(i+2)=1 + jsec(i+3)=1 + endif + endif + endif + endif + endif + endif + enddo + +*** connect --------------> +*** x-x => xxx + do i=1,nseq1 + if(isec(i).eq.2)then + if(isec(i+1).ne.2)then + if(isec(i+2).eq.2)then + isec(i+1)=2 + endif + endif + endif + + if(isec(i).eq.4)then + if(isec(i+1).ne.4)then + if(isec(i+2).eq.4)then + isec(i+1)=4 + endif + endif + endif + enddo + do i=1,nseq2 + if(jsec(i).eq.2)then + if(jsec(i+1).ne.2)then + if(jsec(i+2).eq.2)then + jsec(i+1)=2 + endif + endif + endif + + if(jsec(i).eq.4)then + if(jsec(i+1).ne.4)then + if(jsec(i+2).eq.4)then + jsec(i+1)=4 + endif + endif + endif + enddo + + return + end + +************************************************************* +* assign secondary structure: +************************************************************* + function diszy(i,i1,i2) + PARAMETER(nmax=5000) + COMMON/BACKBONE/XA(3,nmax,0:1) + diszy=sqrt((xa(1,i1,i)-xa(1,i2,i))**2 + & +(xa(2,i1,i)-xa(2,i2,i))**2 + & +(xa(3,i1,i)-xa(3,i2,i))**2) + return + end + +************************************************************* +* assign secondary structure: +************************************************************* + function make_sec(dis13,dis14,dis15,dis24,dis25,dis35) + make_sec=1 + delta=2.1 + if(abs(dis15-6.37).lt.delta)then + if(abs(dis14-5.18).lt.delta)then + if(abs(dis25-5.18).lt.delta)then + if(abs(dis13-5.45).lt.delta)then + if(abs(dis24-5.45).lt.delta)then + if(abs(dis35-5.45).lt.delta)then + make_sec=2 !helix + return + endif + endif + endif + endif + endif + endif + delta=1.42 + if(abs(dis15-13).lt.delta)then + if(abs(dis14-10.4).lt.delta)then + if(abs(dis25-10.4).lt.delta)then + if(abs(dis13-6.1).lt.delta)then + if(abs(dis24-6.1).lt.delta)then + if(abs(dis35-6.1).lt.delta)then + make_sec=4 !strand + return + endif + endif + endif + endif + endif + endif + if(dis15.lt.8)then + make_sec=3 + endif + + return + end + +**************************************************************** +* quickly calculate TM-score with given invmap(i) in 3 iterations +**************************************************************** + subroutine get_GL(GL) + PARAMETER(nmax=5000) + common/length/nseq1,nseq2 + COMMON/BACKBONE/XA(3,nmax,0:1) + common/dpc/score(nmax,nmax),gap_open,invmap(nmax) + common/zscore/zrms,n_al,rmsd_al + common/d0/d0,anseq + dimension xtm1(nmax),ytm1(nmax),ztm1(nmax) + dimension xtm2(nmax),ytm2(nmax),ztm2(nmax) + common/TM/TM,TMmax + common/n1n2/n1(nmax),n2(nmax) + common/d00/d00,d002 + + dimension xo1(nmax),yo1(nmax),zo1(nmax) + dimension xo2(nmax),yo2(nmax),zo2(nmax) + dimension dis2(nmax) + +ccc RMSD: + double precision r_1(3,nmax),r_2(3,nmax),r_3(3,nmax),w(nmax) + double precision u(3,3),t(3),rms,drms !armsd is real + data w /nmax*1.0/ +ccc + +c calculate RMSD between aligned structures and rotate the structures --> + n_al=0 + do j=1,NSEQ2 + i=invmap(j) !j aligned to i + if(i.gt.0)then + n_al=n_al+1 + r_1(1,n_al)=xa(1,i,0) + r_1(2,n_al)=xa(2,i,0) + r_1(3,n_al)=xa(3,i,0) + r_2(1,n_al)=xa(1,j,1) + r_2(2,n_al)=xa(2,j,1) + r_2(3,n_al)=xa(3,j,1) + xo1(n_al)=xa(1,i,0) + yo1(n_al)=xa(2,i,0) + zo1(n_al)=xa(3,i,0) + xo2(n_al)=xa(1,j,1) + yo2(n_al)=xa(2,j,1) + zo2(n_al)=xa(3,j,1) + endif + enddo + call u3b(w,r_1,r_2,n_al,1,rms,u,t,ier) !u rotate r_1 to r_2 + GL=0 + do i=1,n_al + xx=t(1)+u(1,1)*xo1(i)+u(1,2)*yo1(i)+u(1,3)*zo1(i) + yy=t(2)+u(2,1)*xo1(i)+u(2,2)*yo1(i)+u(2,3)*zo1(i) + zz=t(3)+u(3,1)*xo1(i)+u(3,2)*yo1(i)+u(3,3)*zo1(i) + dis2(i)=(xx-xo2(i))**2+(yy-yo2(i))**2+(zz-zo2(i))**2 + GL=GL+1/(1+dis2(i)/(d0**2)) + enddo +ccc for next iteration-------------> + d002t=d002 + 21 j=0 + do i=1,n_al + if(dis2(i).le.d002t)then + j=j+1 + r_1(1,j)=xo1(i) + r_1(2,j)=yo1(i) + r_1(3,j)=zo1(i) + r_2(1,j)=xo2(i) + r_2(2,j)=yo2(i) + r_2(3,j)=zo2(i) + endif + enddo + if(j.lt.3.and.n_al.gt.3)then + d002t=d002t+.5 + goto 21 + endif + L=j + call u3b(w,r_1,r_2,L,1,rms,u,t,ier) !u rotate r_1 to r_2 + G2=0 + do i=1,n_al + xx=t(1)+u(1,1)*xo1(i)+u(1,2)*yo1(i)+u(1,3)*zo1(i) + yy=t(2)+u(2,1)*xo1(i)+u(2,2)*yo1(i)+u(2,3)*zo1(i) + zz=t(3)+u(3,1)*xo1(i)+u(3,2)*yo1(i)+u(3,3)*zo1(i) + dis2(i)=(xx-xo2(i))**2+(yy-yo2(i))**2+(zz-zo2(i))**2 + G2=G2+1/(1+dis2(i)/(d0**2)) + enddo +ccc for next iteration-------------> + d002t=d002+1 + 22 j=0 + do i=1,n_al + if(dis2(i).le.d002t)then + j=j+1 + r_1(1,j)=xo1(i) + r_1(2,j)=yo1(i) + r_1(3,j)=zo1(i) + r_2(1,j)=xo2(i) + r_2(2,j)=yo2(i) + r_2(3,j)=zo2(i) + endif + enddo + if(j.lt.3.and.n_al.gt.3)then + d002t=d002t+.5 + goto 22 + endif + L=j + call u3b(w,r_1,r_2,L,1,rms,u,t,ier) !u rotate r_1 to r_2 + G3=0 + do i=1,n_al + xx=t(1)+u(1,1)*xo1(i)+u(1,2)*yo1(i)+u(1,3)*zo1(i) + yy=t(2)+u(2,1)*xo1(i)+u(2,2)*yo1(i)+u(2,3)*zo1(i) + zz=t(3)+u(3,1)*xo1(i)+u(3,2)*yo1(i)+u(3,3)*zo1(i) + dis2(i)=(xx-xo2(i))**2+(yy-yo2(i))**2+(zz-zo2(i))**2 + G3=G3+1/(1+dis2(i)/(d0**2)) + enddo + if(G2.gt.GL)GL=G2 + if(G3.gt.GL)GL=G3 + +c^^^^^^^^^^^^^^^^ GL done ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + return + end + +**************************************************************** +* with invmap(i) calculate TM-score and martix score(i,j) for rotation +**************************************************************** + subroutine get_score + PARAMETER(nmax=5000) + common/length/nseq1,nseq2 + COMMON/BACKBONE/XA(3,nmax,0:1) + common/dpc/score(nmax,nmax),gap_open,invmap(nmax) + common/zscore/zrms,n_al,rmsd_al + common/d0/d0,anseq + dimension xtm1(nmax),ytm1(nmax),ztm1(nmax) + dimension xtm2(nmax),ytm2(nmax),ztm2(nmax) + common/TM/TM,TMmax + common/n1n2/n1(nmax),n2(nmax) + +ccc RMSD: + double precision r_1(3,nmax),r_2(3,nmax),r_3(3,nmax),w(nmax) + double precision u(3,3),t(3),rms,drms !armsd is real + data w /nmax*1.0/ +ccc + +c calculate RMSD between aligned structures and rotate the structures --> + n_al=0 + do j=1,NSEQ2 + i=invmap(j) !j aligned to i + if(i.gt.0)then + n_al=n_al+1 +ccc for TM-score: + xtm1(n_al)=xa(1,i,0) !for TM-score + ytm1(n_al)=xa(2,i,0) + ztm1(n_al)=xa(3,i,0) + xtm2(n_al)=xa(1,j,1) + ytm2(n_al)=xa(2,j,1) + ztm2(n_al)=xa(3,j,1) +ccc for rotation matrix: + r_1(1,n_al)=xa(1,i,0) + r_1(2,n_al)=xa(2,i,0) + r_1(3,n_al)=xa(3,i,0) + endif + enddo +*** calculate TM-score for the given alignment-----------> + d0_input=d0 + call TMscore8_search(d0_input,n_al,xtm1,ytm1,ztm1,n1, + & n_al,xtm2,ytm2,ztm2,n2,TM,Rcomm,Lcomm) !simplified search engine + TM=TM*n_al/anseq !TM-score +*** calculate score matrix score(i,j)------------------> + do i=1,n_al + r_2(1,i)=xtm1(i) + r_2(2,i)=ytm1(i) + r_2(3,i)=ztm1(i) + enddo + call u3b(w,r_1,r_2,n_al,1,rms,u,t,ier) !u rotate r_1 to r_2 + do i=1,nseq1 + xx=t(1)+u(1,1)*xa(1,i,0)+u(1,2)*xa(2,i,0)+u(1,3)*xa(3,i,0) + yy=t(2)+u(2,1)*xa(1,i,0)+u(2,2)*xa(2,i,0)+u(2,3)*xa(3,i,0) + zz=t(3)+u(3,1)*xa(1,i,0)+u(3,2)*xa(2,i,0)+u(3,3)*xa(3,i,0) + do j=1,nseq2 + dd=(xx-xa(1,j,1))**2+(yy-xa(2,j,1))**2+(zz-xa(3,j,1))**2 + score(i,j)=1/(1+dd/d0**2) + enddo + enddo + +c^^^^^^^^^^^^^^^^ score(i,j) done ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + return + end + +**************************************************************** +* with invmap(i) calculate score(i,j) using RMSD rotation +**************************************************************** + subroutine get_score1 + PARAMETER(nmax=5000) + common/length/nseq1,nseq2 + COMMON/BACKBONE/XA(3,nmax,0:1) + common/dpc/score(nmax,nmax),gap_open,invmap(nmax) + common/zscore/zrms,n_al,rmsd_al + common/d0/d0,anseq + common/d0min/d0_min + dimension xtm1(nmax),ytm1(nmax),ztm1(nmax) + dimension xtm2(nmax),ytm2(nmax),ztm2(nmax) + common/TM/TM,TMmax + common/n1n2/n1(nmax),n2(nmax) + +ccc RMSD: + double precision r_1(3,nmax),r_2(3,nmax),r_3(3,nmax),w(nmax) + double precision u(3,3),t(3),rms,drms !armsd is real + data w /nmax*1.0/ +ccc + +c calculate RMSD between aligned structures and rotate the structures --> + n_al=0 + do j=1,NSEQ2 + i=invmap(j) !j aligned to i + if(i.gt.0)then + n_al=n_al+1 +ccc for rotation matrix: + r_1(1,n_al)=xa(1,i,0) + r_1(2,n_al)=xa(2,i,0) + r_1(3,n_al)=xa(3,i,0) + r_2(1,n_al)=xa(1,j,1) + r_2(2,n_al)=xa(2,j,1) + r_2(3,n_al)=xa(3,j,1) + endif + enddo +*** calculate score matrix score(i,j)------------------> + call u3b(w,r_1,r_2,n_al,1,rms,u,t,ier) !u rotate r_1 to r_2 + d01=d0+1.5 + if(d01.lt.d0_min)d01=d0_min + d02=d01*d01 + do i=1,nseq1 + xx=t(1)+u(1,1)*xa(1,i,0)+u(1,2)*xa(2,i,0)+u(1,3)*xa(3,i,0) + yy=t(2)+u(2,1)*xa(1,i,0)+u(2,2)*xa(2,i,0)+u(2,3)*xa(3,i,0) + zz=t(3)+u(3,1)*xa(1,i,0)+u(3,2)*xa(2,i,0)+u(3,3)*xa(3,i,0) + do j=1,nseq2 + dd=(xx-xa(1,j,1))**2+(yy-xa(2,j,1))**2+(zz-xa(3,j,1))**2 + score(i,j)=1/(1+dd/d02) + enddo + enddo + +c^^^^^^^^^^^^^^^^ score(i,j) done ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + return + end + + +************************************************************************* +************************************************************************* +* This is a subroutine to compare two structures and find the +* superposition that has the maximum TM-score. +* +* L1--Length of the first structure +* (x1(i),y1(i),z1(i))--coordinates of i'th residue at the first structure +* n1(i)--Residue sequence number of i'th residue at the first structure +* L2--Length of the second structure +* (x2(i),y2(i),z2(i))--coordinates of i'th residue at the second structure +* n2(i)--Residue sequence number of i'th residue at the second structure +* TM--TM-score of the comparison +* Rcomm--RMSD of two structures in the common aligned residues +* Lcomm--Length of the common aligned regions +* +* Note: +* 1, Always put native as the second structure, by which TM-score +* is normalized. +* 2, The returned (x1(i),y1(i),z1(i)) are the rotated structure after +* TM-score superposition. +************************************************************************* +************************************************************************* +*** dis<8, simplified search engine + subroutine TMscore8_search(dx,L1,x1,y1,z1,n1,L2,x2,y2,z2,n2, + & TM,Rcomm,Lcomm) + PARAMETER(nmax=5000) + common/stru/xt(nmax),yt(nmax),zt(nmax),xb(nmax),yb(nmax),zb(nmax) + common/nres/nresA(nmax),nresB(nmax),nseqA,nseqB + common/para/d,d0 + common/d0min/d0_min + common/align/n_ali,iA(nmax),iB(nmax) + common/nscore/i_ali(nmax),n_cut ![1,n_ali],align residues for the score + dimension k_ali(nmax),k_ali0(nmax) + dimension L_ini(100),iq(nmax) + common/scores/score + double precision score,score_max + dimension xa(nmax),ya(nmax),za(nmax) + dimension iL0(nmax) + + dimension x1(nmax),y1(nmax),z1(nmax),n1(nmax) + dimension x2(nmax),y2(nmax),z2(nmax),n2(nmax) + +ccc RMSD: + double precision r_1(3,nmax),r_2(3,nmax),r_3(3,nmax),w(nmax) + double precision u(3,3),t(3),rms,drms !armsd is real + data w /nmax*1.0/ +ccc + +********* convert input data *************************** +* because L1=L2 in this special case----------> + nseqA=L1 + nseqB=L2 + do i=1,nseqA + xa(i)=x1(i) + ya(i)=y1(i) + za(i)=z1(i) + nresA(i)=n1(i) + xb(i)=x2(i) + yb(i)=y2(i) + zb(i)=z2(i) + nresB(i)=n2(i) + iA(i)=i + iB(i)=i + enddo + n_ali=L1 !number of aligned residues + Lcomm=L1 + +************///// +* parameters: +***************** +*** d0-------------> + d0=dx + if(d0.lt.d0_min)d0=d0_min +*** d0_search -----> + d0_search=d0 + if(d0_search.gt.8)d0_search=8 + if(d0_search.lt.4.5)d0_search=4.5 +*** iterative parameters -----> + n_it=20 !maximum number of iterations + d_output=5 !for output alignment + n_init_max=6 !maximum number of L_init + n_init=0 + L_ini_min=4 + if(n_ali.lt.4)L_ini_min=n_ali + do i=1,n_init_max-1 + n_init=n_init+1 + L_ini(n_init)=n_ali/2**(n_init-1) + if(L_ini(n_init).le.L_ini_min)then + L_ini(n_init)=L_ini_min + goto 402 + endif + enddo + n_init=n_init+1 + L_ini(n_init)=L_ini_min + 402 continue + +****************************************************************** +* find the maximum score starting from local structures superposition +****************************************************************** + score_max=-1 !TM-score + do 333 i_init=1,n_init + L_init=L_ini(i_init) + iL_max=n_ali-L_init+1 + k=0 + do i=1,iL_max,40 !this is the simplification! + k=k+1 + iL0(k)=i + enddo + if(iL0(k).lt.iL_max)then + k=k+1 + iL0(k)=iL_max + endif + n_shift=k + do 300 i_shift=1,n_shift + iL=iL0(i_shift) + LL=0 + ka=0 + do i=1,L_init + k=iL+i-1 ![1,n_ali] common aligned + r_1(1,i)=xa(iA(k)) + r_1(2,i)=ya(iA(k)) + r_1(3,i)=za(iA(k)) + r_2(1,i)=xb(iB(k)) + r_2(2,i)=yb(iB(k)) + r_2(3,i)=zb(iB(k)) + LL=LL+1 + ka=ka+1 + k_ali(ka)=k + enddo + call u3b(w,r_1,r_2,LL,1,rms,u,t,ier) !u rotate r_1 to r_2 + if(i_init.eq.1)then !global superposition + armsd=dsqrt(rms/LL) + Rcomm=armsd + endif + do j=1,nseqA + xt(j)=t(1)+u(1,1)*xa(j)+u(1,2)*ya(j)+u(1,3)*za(j) + yt(j)=t(2)+u(2,1)*xa(j)+u(2,2)*ya(j)+u(2,3)*za(j) + zt(j)=t(3)+u(3,1)*xa(j)+u(3,2)*ya(j)+u(3,3)*za(j) + enddo + d=d0_search-1 + call score_fun8 !init, get scores, n_cut+i_ali(i) for iteration + if(score_max.lt.score)then + score_max=score + ka0=ka + do i=1,ka0 + k_ali0(i)=k_ali(i) + enddo + endif +*** iteration for extending ----------------------------------> + d=d0_search+1 + do 301 it=1,n_it + LL=0 + ka=0 + do i=1,n_cut + m=i_ali(i) ![1,n_ali] + r_1(1,i)=xa(iA(m)) + r_1(2,i)=ya(iA(m)) + r_1(3,i)=za(iA(m)) + r_2(1,i)=xb(iB(m)) + r_2(2,i)=yb(iB(m)) + r_2(3,i)=zb(iB(m)) + ka=ka+1 + k_ali(ka)=m + LL=LL+1 + enddo + call u3b(w,r_1,r_2,LL,1,rms,u,t,ier) !u rotate r_1 to r_2 + do j=1,nseqA + xt(j)=t(1)+u(1,1)*xa(j)+u(1,2)*ya(j)+u(1,3)*za(j) + yt(j)=t(2)+u(2,1)*xa(j)+u(2,2)*ya(j)+u(2,3)*za(j) + zt(j)=t(3)+u(3,1)*xa(j)+u(3,2)*ya(j)+u(3,3)*za(j) + enddo + call score_fun8 !get scores, n_cut+i_ali(i) for iteration + if(score_max.lt.score)then + score_max=score + ka0=ka + do i=1,ka + k_ali0(i)=k_ali(i) + enddo + endif + if(it.eq.n_it)goto 302 + if(n_cut.eq.ka)then + neq=0 + do i=1,n_cut + if(i_ali(i).eq.k_ali(i))neq=neq+1 + enddo + if(n_cut.eq.neq)goto 302 + endif + 301 continue !for iteration + 302 continue + 300 continue !for shift + 333 continue !for initial length, L_ali/M + +******** return the final rotation **************** + LL=0 + do i=1,ka0 + m=k_ali0(i) !record of the best alignment + r_1(1,i)=xa(iA(m)) + r_1(2,i)=ya(iA(m)) + r_1(3,i)=za(iA(m)) + r_2(1,i)=xb(iB(m)) + r_2(2,i)=yb(iB(m)) + r_2(3,i)=zb(iB(m)) + LL=LL+1 + enddo + call u3b(w,r_1,r_2,LL,1,rms,u,t,ier) !u rotate r_1 to r_2 + do j=1,nseqA + x1(j)=t(1)+u(1,1)*xa(j)+u(1,2)*ya(j)+u(1,3)*za(j) + y1(j)=t(2)+u(2,1)*xa(j)+u(2,2)*ya(j)+u(2,3)*za(j) + z1(j)=t(3)+u(3,1)*xa(j)+u(3,2)*ya(j)+u(3,3)*za(j) + enddo + TM=score_max + +c^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + return + END + +************************************************************************* +************************************************************************* +* This is a subroutine to compare two structures and find the +* superposition that has the maximum TM-score. +* +* L1--Length of the first structure +* (x1(i),y1(i),z1(i))--coordinates of i'th residue at the first structure +* n1(i)--Residue sequence number of i'th residue at the first structure +* L2--Length of the second structure +* (x2(i),y2(i),z2(i))--coordinates of i'th residue at the second structure +* n2(i)--Residue sequence number of i'th residue at the second structure +* TM--TM-score of the comparison +* Rcomm--RMSD of two structures in the common aligned residues +* Lcomm--Length of the common aligned regions +* +* Note: +* 1, Always put native as the second structure, by which TM-score +* is normalized. +* 2, The returned (x1(i),y1(i),z1(i)) are the rotated structure after +* TM-score superposition. +************************************************************************* +************************************************************************* +*** dis<8, but same search engine + subroutine TMscore8(dx,L1,x1,y1,z1,n1,L2,x2,y2,z2,n2, + & TM,Rcomm,Lcomm) + PARAMETER(nmax=5000) + common/stru/xt(nmax),yt(nmax),zt(nmax),xb(nmax),yb(nmax),zb(nmax) + common/nres/nresA(nmax),nresB(nmax),nseqA,nseqB + common/para/d,d0 + common/d0min/d0_min + common/align/n_ali,iA(nmax),iB(nmax) + common/nscore/i_ali(nmax),n_cut ![1,n_ali],align residues for the score + dimension k_ali(nmax),k_ali0(nmax) + dimension L_ini(100),iq(nmax) + common/scores/score + double precision score,score_max + dimension xa(nmax),ya(nmax),za(nmax) + + dimension x1(nmax),y1(nmax),z1(nmax),n1(nmax) + dimension x2(nmax),y2(nmax),z2(nmax),n2(nmax) + +ccc RMSD: + double precision r_1(3,nmax),r_2(3,nmax),r_3(3,nmax),w(nmax) + double precision u(3,3),t(3),rms,drms !armsd is real + data w /nmax*1.0/ +ccc + +********* convert input data *************************** +* because L1=L2 in this special case----------> + nseqA=L1 + nseqB=L2 + do i=1,nseqA + xa(i)=x1(i) + ya(i)=y1(i) + za(i)=z1(i) + nresA(i)=n1(i) + xb(i)=x2(i) + yb(i)=y2(i) + zb(i)=z2(i) + nresB(i)=n2(i) + iA(i)=i + iB(i)=i + enddo + n_ali=L1 !number of aligned residues + Lcomm=L1 + +************///// +* parameters: +***************** +*** d0-------------> + d0=dx + if(d0.lt.d0_min)d0=d0_min +*** d0_search -----> + d0_search=d0 + if(d0_search.gt.8)d0_search=8 + if(d0_search.lt.4.5)d0_search=4.5 +*** iterative parameters -----> + n_it=20 !maximum number of iterations + d_output=5 !for output alignment + n_init_max=6 !maximum number of L_init + n_init=0 + L_ini_min=4 + if(n_ali.lt.4)L_ini_min=n_ali + do i=1,n_init_max-1 + n_init=n_init+1 + L_ini(n_init)=n_ali/2**(n_init-1) + if(L_ini(n_init).le.L_ini_min)then + L_ini(n_init)=L_ini_min + goto 402 + endif + enddo + n_init=n_init+1 + L_ini(n_init)=L_ini_min + 402 continue + +****************************************************************** +* find the maximum score starting from local structures superposition +****************************************************************** + score_max=-1 !TM-score + do 333 i_init=1,n_init + L_init=L_ini(i_init) + iL_max=n_ali-L_init+1 + do 300 iL=1,iL_max !on aligned residues, [1,nseqA] + LL=0 + ka=0 + do i=1,L_init + k=iL+i-1 ![1,n_ali] common aligned + r_1(1,i)=xa(iA(k)) + r_1(2,i)=ya(iA(k)) + r_1(3,i)=za(iA(k)) + r_2(1,i)=xb(iB(k)) + r_2(2,i)=yb(iB(k)) + r_2(3,i)=zb(iB(k)) + LL=LL+1 + ka=ka+1 + k_ali(ka)=k + enddo + call u3b(w,r_1,r_2,LL,1,rms,u,t,ier) !u rotate r_1 to r_2 + if(i_init.eq.1)then !global superposition + armsd=dsqrt(rms/LL) + Rcomm=armsd + endif + do j=1,nseqA + xt(j)=t(1)+u(1,1)*xa(j)+u(1,2)*ya(j)+u(1,3)*za(j) + yt(j)=t(2)+u(2,1)*xa(j)+u(2,2)*ya(j)+u(2,3)*za(j) + zt(j)=t(3)+u(3,1)*xa(j)+u(3,2)*ya(j)+u(3,3)*za(j) + enddo + d=d0_search-1 + call score_fun8 !init, get scores, n_cut+i_ali(i) for iteration + if(score_max.lt.score)then + score_max=score + ka0=ka + do i=1,ka0 + k_ali0(i)=k_ali(i) + enddo + endif +*** iteration for extending ----------------------------------> + d=d0_search+1 + do 301 it=1,n_it + LL=0 + ka=0 + do i=1,n_cut + m=i_ali(i) ![1,n_ali] + r_1(1,i)=xa(iA(m)) + r_1(2,i)=ya(iA(m)) + r_1(3,i)=za(iA(m)) + r_2(1,i)=xb(iB(m)) + r_2(2,i)=yb(iB(m)) + r_2(3,i)=zb(iB(m)) + ka=ka+1 + k_ali(ka)=m + LL=LL+1 + enddo + call u3b(w,r_1,r_2,LL,1,rms,u,t,ier) !u rotate r_1 to r_2 + do j=1,nseqA + xt(j)=t(1)+u(1,1)*xa(j)+u(1,2)*ya(j)+u(1,3)*za(j) + yt(j)=t(2)+u(2,1)*xa(j)+u(2,2)*ya(j)+u(2,3)*za(j) + zt(j)=t(3)+u(3,1)*xa(j)+u(3,2)*ya(j)+u(3,3)*za(j) + enddo + call score_fun8 !get scores, n_cut+i_ali(i) for iteration + if(score_max.lt.score)then + score_max=score + ka0=ka + do i=1,ka + k_ali0(i)=k_ali(i) + enddo + endif + if(it.eq.n_it)goto 302 + if(n_cut.eq.ka)then + neq=0 + do i=1,n_cut + if(i_ali(i).eq.k_ali(i))neq=neq+1 + enddo + if(n_cut.eq.neq)goto 302 + endif + 301 continue !for iteration + 302 continue + 300 continue !for shift + 333 continue !for initial length, L_ali/M + +******** return the final rotation **************** + LL=0 + do i=1,ka0 + m=k_ali0(i) !record of the best alignment + r_1(1,i)=xa(iA(m)) + r_1(2,i)=ya(iA(m)) + r_1(3,i)=za(iA(m)) + r_2(1,i)=xb(iB(m)) + r_2(2,i)=yb(iB(m)) + r_2(3,i)=zb(iB(m)) + LL=LL+1 + enddo + call u3b(w,r_1,r_2,LL,1,rms,u,t,ier) !u rotate r_1 to r_2 + do j=1,nseqA + x1(j)=t(1)+u(1,1)*xa(j)+u(1,2)*ya(j)+u(1,3)*za(j) + y1(j)=t(2)+u(2,1)*xa(j)+u(2,2)*ya(j)+u(2,3)*za(j) + z1(j)=t(3)+u(3,1)*xa(j)+u(3,2)*ya(j)+u(3,3)*za(j) + enddo + TM=score_max + +c^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + return + END + +ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc +c 1, collect those residues with dis + nseqA=L1 + nseqB=L2 + do i=1,nseqA + xa(i)=x1(i) + ya(i)=y1(i) + za(i)=z1(i) + nresA(i)=n1(i) + xb(i)=x2(i) + yb(i)=y2(i) + zb(i)=z2(i) + nresB(i)=n2(i) + iA(i)=i + iB(i)=i + enddo + n_ali=L1 !number of aligned residues + Lcomm=L1 + +************///// +* parameters: +***************** +*** d0-------------> +c d0=1.24*(nseqB-15)**(1.0/3.0)-1.8 + d0=dx + if(d0.lt.d0_min)d0=d0_min +*** d0_search -----> + d0_search=d0 + if(d0_search.gt.8)d0_search=8 + if(d0_search.lt.4.5)d0_search=4.5 +*** iterative parameters -----> + n_it=20 !maximum number of iterations + d_output=5 !for output alignment + n_init_max=6 !maximum number of L_init + n_init=0 + L_ini_min=4 + if(n_ali.lt.4)L_ini_min=n_ali + do i=1,n_init_max-1 + n_init=n_init+1 + L_ini(n_init)=n_ali/2**(n_init-1) + if(L_ini(n_init).le.L_ini_min)then + L_ini(n_init)=L_ini_min + goto 402 + endif + enddo + n_init=n_init+1 + L_ini(n_init)=L_ini_min + 402 continue + +****************************************************************** +* find the maximum score starting from local structures superposition +****************************************************************** + score_max=-1 !TM-score + do 333 i_init=1,n_init + L_init=L_ini(i_init) + iL_max=n_ali-L_init+1 + do 300 iL=1,iL_max !on aligned residues, [1,nseqA] + LL=0 + ka=0 + do i=1,L_init + k=iL+i-1 ![1,n_ali] common aligned + r_1(1,i)=xa(iA(k)) + r_1(2,i)=ya(iA(k)) + r_1(3,i)=za(iA(k)) + r_2(1,i)=xb(iB(k)) + r_2(2,i)=yb(iB(k)) + r_2(3,i)=zb(iB(k)) + LL=LL+1 + ka=ka+1 + k_ali(ka)=k + enddo + call u3b(w,r_1,r_2,LL,1,rms,u,t,ier) !u rotate r_1 to r_2 + if(i_init.eq.1)then !global superposition + armsd=dsqrt(rms/LL) + Rcomm=armsd + endif + do j=1,nseqA + xt(j)=t(1)+u(1,1)*xa(j)+u(1,2)*ya(j)+u(1,3)*za(j) + yt(j)=t(2)+u(2,1)*xa(j)+u(2,2)*ya(j)+u(2,3)*za(j) + zt(j)=t(3)+u(3,1)*xa(j)+u(3,2)*ya(j)+u(3,3)*za(j) + enddo + d=d0_search-1 + call score_fun !init, get scores, n_cut+i_ali(i) for iteration + if(score_max.lt.score)then + score_max=score + ka0=ka + do i=1,ka0 + k_ali0(i)=k_ali(i) + enddo + endif +*** iteration for extending ----------------------------------> + d=d0_search+1 + do 301 it=1,n_it + LL=0 + ka=0 + do i=1,n_cut + m=i_ali(i) ![1,n_ali] + r_1(1,i)=xa(iA(m)) + r_1(2,i)=ya(iA(m)) + r_1(3,i)=za(iA(m)) + r_2(1,i)=xb(iB(m)) + r_2(2,i)=yb(iB(m)) + r_2(3,i)=zb(iB(m)) + ka=ka+1 + k_ali(ka)=m + LL=LL+1 + enddo + call u3b(w,r_1,r_2,LL,1,rms,u,t,ier) !u rotate r_1 to r_2 + do j=1,nseqA + xt(j)=t(1)+u(1,1)*xa(j)+u(1,2)*ya(j)+u(1,3)*za(j) + yt(j)=t(2)+u(2,1)*xa(j)+u(2,2)*ya(j)+u(2,3)*za(j) + zt(j)=t(3)+u(3,1)*xa(j)+u(3,2)*ya(j)+u(3,3)*za(j) + enddo + call score_fun !get scores, n_cut+i_ali(i) for iteration + if(score_max.lt.score)then + score_max=score + ka0=ka + do i=1,ka + k_ali0(i)=k_ali(i) + enddo + endif + if(it.eq.n_it)goto 302 + if(n_cut.eq.ka)then + neq=0 + do i=1,n_cut + if(i_ali(i).eq.k_ali(i))neq=neq+1 + enddo + if(n_cut.eq.neq)goto 302 + endif + 301 continue !for iteration + 302 continue + 300 continue !for shift + 333 continue !for initial length, L_ali/M + +******** return the final rotation **************** + LL=0 + do i=1,ka0 + m=k_ali0(i) !record of the best alignment + r_1(1,i)=xa(iA(m)) + r_1(2,i)=ya(iA(m)) + r_1(3,i)=za(iA(m)) + r_2(1,i)=xb(iB(m)) + r_2(2,i)=yb(iB(m)) + r_2(3,i)=zb(iB(m)) + LL=LL+1 + enddo + call u3b(w,r_1,r_2,LL,1,rms,u,t,ier) !u rotate r_1 to r_2 + do j=1,nseqA + x1(j)=t(1)+u(1,1)*xa(j)+u(1,2)*ya(j)+u(1,3)*za(j) + y1(j)=t(2)+u(2,1)*xa(j)+u(2,2)*ya(j)+u(2,3)*za(j) + z1(j)=t(3)+u(3,1)*xa(j)+u(3,2)*ya(j)+u(3,3)*za(j) + enddo + TM=score_max + +c^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + return + END + +ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc +c 1, collect those residues with dis +#include +#include +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "dp_lib_header.h" +#include "define_header.h" + + +int aln_compare ( int argc, char *argv[]) + { + int a, b, c,f; + + int ik =0; + Alignment *A, *B; + Sequence *SA, *SB, *TOT_SEQ=NULL; + Sequence *defined_residueA; + Sequence *defined_residueB; + char **seq_list; + int n_seq_file; + + + Sequence *S=NULL; + Structure *ST=NULL; + Result *R=NULL; + char *buf1; + char *buf2; + +/*PARAMETERS*/ + char ***grep_list; + int n_greps; + char compare_mode[STRING]; + char sim_aln[STRING]; + char *alignment1_file; + char *alignment2_file; + + char *pep1_file; + char *pep2_file; + + char io_format[STRING]; + + int n_structure; + char **struct_file; + char **struct_format; + int *n_symbol; + char ***symbol_list; + int pep_compare; + int aln_compare; + int count; + int output_aln; + int output_aln_threshold; + char output_aln_file[LONG_STRING]; + char output_aln_format[LONG_STRING]; + char output_aln_modif[LONG_STRING]; +/*LIST VARIABLES*/ + Constraint_list *CL_A; + Constraint_list *CL_B; + + int pos_in_clist; + Sequence *CLS; + + +/*Column Comparison Variables*/ + int **posA; + int **posB; + int **seq_cache; + int is_same; + int *correct_column; +/*RESULTS_VARIABLES*/ + int **tot_count; + int **pos_count; + int ***pw_tot_count; + int ***pw_pos_count; + int *glob; + int **pw_glob; + int s1, r1, s2, r2; +/*IO VARIABLES*/ + int n_categories; + char ***category; + char *category_list; + int *n_sub_categories; + char sep_l; + char sep_r; + char io_file[STRING]; + FILE *fp; + int **aln_output_count; + int **aln_output_tot; + +/*Sims VARIABLES*/ + float **sim; + float **sim_param; + char sim_matrix[STRING]; + + int sim_n_categories; + char ***sim_category; + char *sim_category_list; + int *sim_n_sub_categories; + + + if ( argc==1|| strm6 ( argv[1], "h", "-h", "help", "-help", "-man", "?")) + { + output_informations(); + } + + argv=standard_initialisation (argv, &argc); +/*Declarations and Initializations*/ + alignment1_file=vcalloc ( LONG_STRING, sizeof (char)); + alignment2_file=vcalloc ( LONG_STRING, sizeof (char)); + + pep1_file=vcalloc ( LONG_STRING, sizeof (char)); + pep2_file=vcalloc ( LONG_STRING, sizeof (char)); + + + sprintf (compare_mode, "sp"); + count=0; + pep_compare=0; + aln_compare=1; + + + grep_list=vcalloc ( STRING, sizeof (char**)); + for ( a=0; a< STRING; a++)grep_list[a]=declare_char (3, STRING); + n_greps=0; + + n_structure=0; + struct_file=declare_char ( MAX_N_STRUC, LONG_STRING); + struct_format=declare_char (MAX_N_STRUC, STRING); + + n_symbol=vcalloc ( MAX_N_STRUC, sizeof (int)); + symbol_list=vcalloc (MAX_N_STRUC, sizeof (char**)); + for ( a=0; a< MAX_N_STRUC; a++)symbol_list[a]=declare_char ( 100, 100); + + + + + n_categories=1; + category=vcalloc ( MAX_N_CATEGORIES, sizeof (char**)); + for ( a=0; a< MAX_N_CATEGORIES; a++)category[a]=declare_char(100, STRING); + n_sub_categories=vcalloc ( 100, sizeof (int)); + category_list=vcalloc ( LONG_STRING, sizeof (char)); + sprintf ( category_list, "[*][*]=[ALL]"); + + + sim_n_categories=1; + sim_category=vcalloc ( MAX_N_CATEGORIES, sizeof (char**)); + for ( a=0; a< MAX_N_CATEGORIES; a++)sim_category[a]=declare_char(100, STRING); + sim_n_sub_categories=vcalloc ( 100, sizeof (int)); + sim_category_list=vcalloc ( LONG_STRING, sizeof (char)); + sprintf ( sim_category_list, "[*][*]=[ALL]"); + sprintf ( sim_aln, "al1"); + sim_matrix[0]='\0'; + sprintf ( sim_category_list, "[*][*]=[ALL]"); + + sprintf ( io_format, "ht"); + sprintf ( io_file, "stdout"); + sep_l='['; + sep_r=']'; + + output_aln=0; + output_aln_threshold=100; + sprintf ( output_aln_file, "stdout"); + sprintf ( output_aln_format, "clustalw"); + sprintf ( output_aln_modif, "lower"); +/*END OF INITIALIZATION*/ + + + + +/*PARAMETERS INPUT*/ + + for ( a=1; a< argc; a++) + { + if (strcmp ( argv[a], "-f")==0) + { + sprintf (io_file,"%s", argv[++a]); + } + else if ( strcmp ( argv[a], "-sim_aln")==0) + { + sprintf (sim_aln,"%s", argv[++a]); + } + else if ( strcmp ( argv[a], "-sim_matrix")==0) + { + sprintf (sim_matrix,"%s", argv[++a]); + } + else if ( strm ( argv[a], "-compare_mode")) + { + sprintf ( compare_mode, "%s", argv[++a]); + } + else if ( strcmp ( argv[a], "-sim_cat")==0) + { + if ( argv[++a][0]!='[') + { + if ( strcmp ( argv[a], "3d_ali")==0)sprintf ( sim_category_list, "[b][b]+[h][h]=[struc]"); + else + { + fprintf ( stderr, "\n%s: Unknown category for distance measure", argv[a]); + } + + } + else + { + sprintf ( sim_category_list, "%s", argv[a]); + } + } + else if ( strcmp ( argv[a], "-grep_value")==0) + { + sprintf ( grep_list[n_greps][0], "%s", argv[++a]); + sprintf ( grep_list[n_greps][1], "%s", argv[++a]); + n_greps++; + + } + else if ( strcmp ( argv[a], "-al1")==0) + { + + sprintf ( alignment1_file, "%s", argv[++a]); + + } + else if ( strcmp ( argv[a], "-al2")==0) + { + + sprintf ( alignment2_file, "%s", argv[++a]); + + } + else if ( strcmp ( argv[a], "-pep1")==0) + { + pep_compare=1; + sprintf ( pep1_file, "%s", argv[++a]); + } + else if ( strcmp ( argv[a], "-pep2")==0) + { + pep_compare=1; + sprintf ( pep2_file, "%s", argv[++a]); + } + else if ( strcmp ( argv[a], "-pep")==0) + { + pep_compare=1; + } + else if ( strcmp ( argv[a], "-count")==0) + { + count=1; + } + else if ( strcmp ( argv[a], "-output_aln")==0) + { + output_aln=1; + } + else if ( strcmp ( argv[a], "-output_aln_threshold")==0) + { + output_aln_threshold=atoi(argv[++a]); + } + else if ( strcmp ( argv[a], "-output_aln_file")==0) + { + sprintf (output_aln_file,"%s",argv[++a]); + } + else if ( strcmp ( argv[a], "-output_aln_format")==0) + { + sprintf (output_aln_format,"%s",argv[++a]); + } + else if ( strcmp ( argv[a], "-output_aln_modif")==0) + { + sprintf (output_aln_modif,"%s",argv[++a]); + } + else if ( strcmp ( argv[a], "-st")==0) + { + sprintf ( struct_file [n_structure], "%s", argv[++a]); + if (!NEXT_ARG_IS_FLAG && is_a_struc_format (argv[a+1])) + sprintf ( struct_format[n_structure], "%s", argv[++a]); + else + sprintf ( struct_format[n_structure], "%s", "pep"); + + if ( !NEXT_ARG_IS_FLAG && strcmp ( argv[a+1], "conv")==0) + { + a++; + while(!NEXT_ARG_IS_FLAG) + { + sprintf ( symbol_list[n_structure][n_symbol[n_structure]], "%s", argv[++a]); + n_symbol[n_structure]++; + } + } + else if (!NEXT_ARG_IS_FLAG) + { + symbol_list[n_structure]=make_symbols ( argv[++a], &n_symbol[n_structure]); + } + + else + { + symbol_list[n_structure]=make_symbols ( "any", &n_symbol[n_structure]); + } + + n_structure++; + + } + else if ( strcmp (argv[a], "-sep")==0) + { + if ( !NEXT_ARG_IS_FLAG) + get_separating_char ( argv[++a][0], &sep_l, &sep_r); + else + sep_l=sep_r=' '; + } + else if ( strncmp ( argv[a], "-io_format",5)==0) + { + sprintf ( io_format, "%s", argv[++a]); + } + else if ( strcmp ( argv[a], "-io_cat")==0) + { + if ( argv[++a][0]!='[') + { + if ( strcmp ( argv[a], "3d_ali")==0)sprintf ( category_list, "[b][b]+[h][h]=[struc];[*][*]=[tot]"); + } + else + { + sprintf ( category_list, "%s", argv[a]); + } + } + else + { + fprintf ( stdout, "\nOPTION %s UNKNOWN[FATAL]\n", argv[a]); + myexit (EXIT_FAILURE); + } + } + +/*PARAMETER PROCESSING*/ + +if ( pep_compare==1 || count==1)aln_compare=0; +if ( aln_compare==1)pep_compare=0; + +/*READ THE TOTAL SEQUENCES*/ + seq_list=declare_char ( 100,STRING); + n_seq_file=0; + + if ( alignment1_file[0] && !check_file_exists ( alignment1_file)) + { + fprintf (stderr, "\nERROR: %s DOES NOT EXIST[FATAL:%s]\n", alignment1_file, PROGRAM); + myexit(EXIT_FAILURE); + } + if ( alignment2_file[0] && !check_file_exists ( alignment2_file)) + { + fprintf (stderr, "\nERROR: %s DOES NOT EXIST[FATAL:%s]\n", alignment2_file, PROGRAM); + myexit(EXIT_FAILURE); + } + if ( pep1_file[0] && !check_file_exists ( pep1_file)) + { + fprintf (stderr, "\nERROR: %s DOES NOT EXIST[FATAL:%s]\n", pep1_file, PROGRAM); + myexit(EXIT_FAILURE); + } + if ( pep2_file[0] && !check_file_exists ( pep2_file)) + { + fprintf (stderr, "\nERROR: %s DOES NOT EXIST[FATAL:%s]\n", pep2_file, PROGRAM); + myexit(EXIT_FAILURE); + } + + if ( alignment1_file[0])sprintf ( seq_list[n_seq_file++], "A%s", alignment1_file); + if ( alignment2_file[0])sprintf ( seq_list[n_seq_file++], "A%s", alignment2_file); + if ( pep1_file[0])sprintf ( seq_list[n_seq_file++], "S%s", pep1_file); + if ( pep2_file[0])sprintf ( seq_list[n_seq_file++], "S%s", pep2_file); + + + + TOT_SEQ=read_seq_in_n_list ( seq_list, n_seq_file, NULL, NULL); + + A=declare_aln (TOT_SEQ); + B=declare_aln (TOT_SEQ); + + +/*1 COMPARISON OF THE SEQUENCES*/ + if ( pep_compare==1 || count==1) + { + f=0; + + if ( pep1_file[0]!='\0')SA=main_read_seq (pep1_file); + else if (alignment1_file[0]!='\0') + { + main_read_aln ( alignment1_file, A); + SA=aln2seq ( A); + } + else + { + main_read_aln ("stdin", A); + sprintf ( alignment1_file, "stdin"); + SA=aln2seq ( A); + } + if ( pep2_file[0]!='\0')SB=main_read_seq (pep2_file); + else if (alignment2_file[0]!='\0') + { + main_read_aln ( alignment2_file, B); + + SB=aln2seq (B); + } + else + { + SB=SA; + sprintf ( alignment2_file, "%s", alignment1_file ); + } + buf1=(pep1_file[0]!='\0')?pep1_file: alignment1_file; + buf2=(pep2_file[0]!='\0')?pep2_file: alignment2_file; + /*Output of the Results*/ + + fp=vfopen ( io_file, "w"); + + + if ( count==1) + { + fprintf (fp, "Number of seq: %d %d\n", SA->nseq,SA->nseq); + for ( a=0; a< SA->nseq; a++) fprintf (fp, "%-15s %d %d\n", SA->name[a], (int)strlen (SA->seq[a]), (int)strlen (SA->seq[a])); + } + + if (SA->nseq!=SB->nseq) + { + + fprintf ( fp, "DIFFERENCE TYPE 1: Different number of sequences %3d/%3d",SA->nseq,SB->nseq); + f=1; + } + + trim_seq ( SA, SB); + for ( a=0; a< SA->nseq; a++) + { + lower_string (SA->seq[a]); + lower_string (SB->seq[a]); + ungap ( SA->seq[a]); + ungap ( SB->seq[a]); + + if ( strcmp ( SA->seq[a], SB->seq[a])!=0) + { + fprintf ( fp, "DIFFERENCE TYPE 2: %s is different in the 2 files\n", SA->name[a]); + f=1; + } + } + for ( a=0; a< SA->nseq; a++) + { + lower_string (SA->seq[a]); + lower_string (SB->seq[a]); + ungap ( SA->seq[a]); + ungap ( SB->seq[a]); + + if ( strlen ( SA->seq[a])!= strlen (SB->seq[a])) + { + fprintf ( fp, "DIFFERENCE TYPE 3: %s has != length in the 2 files (%d-%d)\n", SA->name[a],(int)strlen ( SA->seq[a]), (int)strlen (SB->seq[a])); + f=1; + } + } + if ( f==1) + { + fprintf ( fp, "\nDIFFERENCES found between:\n\t%s\n\t%s\n**********\n\n",buf1, buf2); + } + fclose (fp); + } + +/*2 COMPARISON OF THE ALIGNMENTS*/ + else if ( aln_compare==1) + { + + n_categories=parse_category_list ( category_list, category, n_sub_categories); + sim_n_categories=parse_category_list ( sim_category_list, sim_category, sim_n_sub_categories); + + main_read_aln ( alignment1_file, A); + main_read_aln ( alignment2_file, B); + CLS=trim_aln_seq ( A, B); + + + defined_residueA=get_defined_residues (A); + defined_residueB=get_defined_residues (B); + + + A=thread_defined_residues_on_aln(A, defined_residueA); + A=thread_defined_residues_on_aln(A, defined_residueB); + B=thread_defined_residues_on_aln(B, defined_residueA); + B=thread_defined_residues_on_aln(B, defined_residueB); + + + CL_A=declare_constraint_list ( CLS, NULL, NULL, 0, NULL, NULL); + CL_B=declare_constraint_list ( CLS, NULL, NULL, 0, NULL, NULL); + + + CL_A=aln2constraint_list (A,CL_A, "sim"); + CL_B=aln2constraint_list (B,CL_B, "sim"); + + + + glob=vcalloc ( A->nseq+1, sizeof (int)); + pw_glob=declare_int ( A->nseq+1, A->nseq+1); + + + if ( strm( compare_mode, "sp")) + { + int *entry; + while (entry=extract_entry (CL_A)) + { + s1=entry[SEQ1]; + s2=entry[SEQ2]; + glob[0]++; + glob[s1+1]++; + glob[s2+1]++; + pw_glob[s1][s2]++; + pw_glob[s2][s1]++; + entry[MISC]=1; + + if ((main_search_in_list_constraint (entry,&pos_in_clist,4,CL_B))!=NULL) + add_entry2list (entry,CL_A); + + } + } + else if ( strm( compare_mode, "column") ) + { + int *entry; + posA=aln2pos_simple_2(A); + posB=aln2pos_simple_2(B); + seq_cache=declare_int ( A->nseq, A->len_aln+1); + for ( a=0; a< A->len_aln; a++) + for ( b=0; blen_aln; b++) + { + is_same=compare_pos_column(posA, a, posB, b, A->nseq); + if(is_same) + { + for (c=0; c< A->nseq;c++) + { + if(posA[c][a]>0) + { + seq_cache[c][posA[c][a]]=1; + } + } + } + } + + while (entry=extract_entry (CL_A)) + { + s1=entry[SEQ1]; + s2=entry[SEQ2]; + r1=entry[R1]; + entry[MISC]=0; + glob[0]++; + glob[s1+1]++; + glob[s2+1]++; + pw_glob[s1][s2]++; + pw_glob[s2][s1]++; + + if (seq_cache[s1][r1]) + { + entry[MISC]=1; + add_entry2list (entry, CL_A); + } + } + free_int (posA, -1); + free_int (posB, -1); + free_int (seq_cache, -1); + } + else if ( strm( compare_mode, "tc") ) + { + correct_column = vcalloc(A->len_aln+1, sizeof (int)); + posA=aln2pos_simple_2(A); + posB=aln2pos_simple_2(B); + for ( a=0; a< A->len_aln; a++) + for ( b=0; blen_aln; b++) + { + is_same = compare_pos_column(posA, a, posB, b, A->nseq); + if(is_same) + correct_column[a] = is_same; + } + free_int (posB, -1); + } + + for ( a=0; a< n_structure; a++) + { + ST=read_structure (struct_file[a],struct_format[a], A,B,ST,n_symbol[a], symbol_list[a]); + } + + /*RESULT ARRAY DECLARATION*/ + + tot_count=declare_int (n_categories+1, A->nseq+1); + pos_count=declare_int (n_categories+1, A->nseq+1); + pw_tot_count=vcalloc ( A->nseq, sizeof (int**)); + for ( a=0; a< A->nseq; a++)pw_tot_count[a]=declare_int ( A->nseq, n_categories); + + + pw_pos_count=vcalloc ( A->nseq, sizeof (int**)); + for ( a=0; a< A->nseq; a++)pw_pos_count[a]=declare_int ( A->nseq, n_categories); + + /*COMPARISON MODULE*/ + if (strm( compare_mode, "tc") ) + { + int column_is_structure; + int pair_is_structure; + + for ( a=0; a< n_categories; a++) + { + for(b = 0; b < A->len_aln; b++) + { + column_is_structure = 1; + pair_is_structure = 0; + for (s1=0; s1< A->nseq-1; s1++) + { + for(s2=s1+1; s2 < A->nseq; s2++) + { + if ((posA[s1][b]>0) && (posA[s2][b]>0)) + { + pair_is_structure=is_in_struct_category(s1,s2,posA[s1][b],posA[s2][b],ST,category[a], n_sub_categories[a]); + column_is_structure = (column_is_structure && pair_is_structure); + if(pair_is_structure) + { + tot_count[a][s1+1]++; + tot_count[a][s2+1]++; + pw_tot_count[s1][s2][a]++; + pw_tot_count[s2][s1][a]++; + if (correct_column[b]) + { + pw_pos_count[s1][s2][a]++; + pw_pos_count[s2][s1][a]++; + pos_count[a][s1+1]++; + pos_count[a][s2+1]++; + } + } + } + } + } + if(column_is_structure && pair_is_structure) + { + tot_count[a][0]++; + if(correct_column[b]) + { + pos_count[a][0]++; + } + } + } + } + free_int (posA, -1); + } + else + { + /*COMPARISON MODULE*/ + int *entry; + for ( a=0; a< n_categories; a++) + { + while (entry=extract_entry (CL_A)) + { + s1=entry[SEQ1]; + s2=entry[SEQ2]; + r1=entry[R1]; + r2=entry[R2]; + c= entry[MISC]; + if ( is_in_struct_category ( s1, s2, r1, r2, ST, category[a], n_sub_categories[a])) + { + tot_count[a][0]++; + tot_count[a][s1+1]++; + tot_count[a][s2+1]++; + pw_tot_count[s1][s2][a]++; + pw_tot_count[s2][s1][a]++; + if ( c==1) + { + pw_pos_count[s1][s2][a]++; + pw_pos_count[s2][s1][a]++; + pos_count[a][0]++; + pos_count[a][s1+1]++; + pos_count[a][s2+1]++; + } + } + } + } + } +// printf("pos=%d,tot=%d\n", pos_count[0][0], tot_count[0][0]); + /*Measure of Aligned Sequences Similarity*/ + + sim=get_aln_compare_sim ((strcmp (sim_aln, "al1")==0)?A:B, ST,sim_category[0], sim_n_sub_categories[0], sim_matrix); + sim_param=analyse_sim ((strcmp (sim_aln, "al1")==0)?A:B, sim); + + /*Fill the Result_structure*/ + R=vcalloc ( 1, sizeof (Result)); + + R->grep_list=grep_list; + R->n_greps=n_greps; + R->A=A; + R->B=B; + + R->S=S; + R->ST=ST; + R->sim_aln=sim_aln; + R->alignment1_file=alignment1_file; + R->alignment2_file=alignment2_file; + R->io_format=io_format; + R->n_structure=n_structure; + R->struct_file=struct_file; + R->struct_format=struct_format; + R->n_symbol=n_symbol; + R->symbol_list=symbol_list; + + + R->tot_count=tot_count; + R->pos_count=pos_count; + R->pw_tot_count=pw_tot_count; + R->pw_pos_count=pw_pos_count; + R->glob=glob; + R->pw_glob=pw_glob; + R->n_categories=n_categories; + R->category=category; + R->category_list=category_list; + R->n_sub_categories=n_sub_categories; + R->sim=sim; + R->sim_param=sim_param; + R->sim_matrix=sim_matrix; + R->sim_n_categories=sim_n_categories; + R->sim_category=sim_category; + R->sim_category_list=sim_category_list; + R->sim_n_sub_categories=sim_n_sub_categories; + R->sep_r=sep_r; + R->sep_l=sep_l; + + /*Output of the Results*/ + + fp=vfopen ( io_file, "w"); + fp=output_format (io_format, fp, R); + vfclose ( fp); + + + /*Rewriting of Alignment A*/ + if ( output_aln) + { + int *entry; + A->residue_case=2; + aln_output_tot =declare_int ( A->nseq, A->len_aln+1); + aln_output_count=declare_int ( A->nseq, A->len_aln+1); + + while (entry=extract_entry (CL_A)) + { + aln_output_tot[entry[SEQ1]][entry[R1]]++; + aln_output_tot[entry[SEQ2]][entry[R2]]++; + + aln_output_count[entry[SEQ1]][entry[R1]]+=entry[MISC]; + aln_output_count[entry[SEQ2]][entry[R2]]+=entry[MISC]; + } + + for ( a=0; a< A->nseq; a++) + { + + for (c=0, b=0; b< A->len_aln; b++) + { + if ( !is_gap(A->seq_al[a][b])) + { + c++; + if ( aln_output_tot[a][c] && ((aln_output_count[a][c]*100)/aln_output_tot[a][c])seq_al[a][b]=tolower(A->seq_al[a][b]); + else + A->seq_al[a][b]=output_aln_modif[0]; + } + else A->seq_al[a][b]=toupper(A->seq_al[a][b]); + } + + } + } + A->score_aln=(int)(R->tot_count[0][0]==0)?0:((R->pos_count[0][0]*100)/(float)R->tot_count[0][0]); + + output_format_aln (output_aln_format,A,NULL,output_aln_file); + + free_int ( aln_output_tot, -1); + free_int ( aln_output_count, -1 ); + } + } + return EXIT_SUCCESS; + } +/************************************************************************************/ +/* */ +/* OUTPUT */ +/* */ +/* */ +/************************************************************************************/ +FILE *output_format (char *iof,FILE *fp, Result *R) + { + int a; + int l; + + /* + H: files Header + h: basic header; + s: sequence results + t: total results (global); + p: pairwise_results; + */ + l=strlen ( iof); + + for ( a=0; a< l; a++) + { + if ( iof[a]=='H')fp=output_large_header (fp,R); + else if ( iof[a]=='h')fp=output_header (fp,R); + else if ( iof[a]=='t')fp=output_total_results (fp, R); + else if ( iof[a]=='s')fp=output_sequence_results (fp,R); + else if ( iof[a]=='p')fp=output_pair_wise_sequence_results(fp,R); + } + return fp; + } + +FILE *output_pair_wise_sequence_results (FILE *fp, Result *R) + { + int a,c,d; + + + for ( c=0; c<(R->A)->nseq-1; c++) + { + for ( d=c+1; d< (R->A)->nseq; d++) + { + fprintf (fp, "%-10s %-10s%s",(R->A)->name[c],(R->A)->name[d],SSPACE); + fprintf (fp, "%5.1f%s", R->sim[c][d], SSPACE); + + for (a=0; a< R->n_categories; a++) + { + fprintf ( fp, "%5.1f ",(R->pw_tot_count[c][d][a]==0)?0:((float)(R->pw_pos_count[c][d][a]*100)/(float)R->pw_tot_count[c][d][a])); + fprintf ( fp, "%c%5.1f%c%s",(R->sep_l),(R->pw_glob[c][d]==0)?0:((float)(R->pw_tot_count[c][d][a]*100)/(float)R->pw_glob[c][d]),(R->sep_r),SSPACE); + } + fprintf ( fp, "%c%5d%c\n",(R->sep_l), R->pw_glob[c][d],(R->sep_r)); + } + } + + return fp; + } +FILE *output_sequence_results (FILE *fp, Result *R) + { + int a,c; + + for ( c=1; c<=R->A->nseq; c++) + { + fprintf (fp, "%-10s %-10s%s",(R->A)->name[c-1], "..",SSPACE); + fprintf (fp, "%5.1f%s", R->sim_param[c-1][0],SSPACE); + for (a=0; a< R->n_categories; a++) + { + fprintf ( fp, "%5.1f ",(R->tot_count[a][c]==0)?0:((float)(R->pos_count[a][c]*100)/(float)R->tot_count[a][c])); + fprintf ( fp, "%c%5.1f%c%s",(R->sep_l),(R->glob[c]==0)?0:((float)(R->tot_count[a][c]*100)/(float)R->glob[c]),(R->sep_r), SSPACE); + } + fprintf ( fp, "%c%5d%c\n",(R->sep_l), R->glob[c],(R->sep_r)); + } + return fp; + } + + +FILE *output_total_results (FILE *fp, Result *R) + { + int a; + + + fprintf ( fp, "%-13s %-7d%s",extract_suffixe (R->alignment1_file),(R->A)->nseq, SSPACE); + fprintf (fp, "%5.1f%s", R->sim_param[(R->A)->nseq][0], SSPACE); + for (a=0; a< R->n_categories; a++) + { + fprintf ( fp, "%5.1f ",(R->tot_count[a][0]==0)?0:((float)(R->pos_count[a][0]*100)/(float)R->tot_count[a][0])); + fprintf ( fp, "%c%5.1f%c%s",(R->sep_l),(R->glob[0]==0)?0:((float)(R->tot_count[a][0]*100)/(float)R->glob[0]),(R->sep_r), SSPACE); + } + fprintf ( fp, "%c%5d%c\n",(R->sep_l), R->glob[0],(R->sep_r)); + return fp; + } +FILE *output_header (FILE *fp, Result *R) + { + int a; + + + fprintf ( fp, "%s\n",generate_string ( R->n_categories*(13+strlen(SSPACE))+31+2*strlen(SSPACE),'*')); + + fprintf ( fp, "%-10s %-10s %s%-3s%s", "seq1", "seq2",SSPACE,"Sim",SSPACE); + + for ( a=0; a< R->n_categories; a++) + fprintf ( fp, "%-12s%s ",R->category[a][0], SSPACE); + fprintf (fp, "%-5s", "Tot"); + fprintf (fp, "\n"); + return fp; + } +FILE *output_large_header ( FILE *fp, Result *R) + { + int a, b; + + fprintf ( fp, "AL1: %s\n", R->alignment1_file); + fprintf ( fp, "AL2: %s\n", R->alignment2_file); + for ( a=0; a< R->n_structure; a++) + { + fprintf (fp, "ST %d: %s [%s]/[", a, R->struct_file[a], R->struct_format[a]); + for ( b=0; b< R->n_symbol[a]; b++)fprintf (fp, "%s ", R->symbol_list[a][b]); + fprintf ( fp, "]\n"); + } + return (fp); + } + +void get_separating_char ( char s, char *l, char *r) + { + if ( s=='{' || s=='}') + { + l[0]='{'; + r[0]='}'; + return; + } + else if ( s==']' || s=='[') + { + l[0]='['; + r[0]=']'; + return; + } + else if ( s==')' || s=='(') + { + l[0]='('; + r[0]=')'; + return; + } + else + { + l[0]=s; + r[0]=s; + return; + } + } + +/************************************************************************************/ +/* */ +/* SIM MEASURE */ +/* */ +/* */ +/************************************************************************************/ +float **get_aln_compare_sim ( Alignment *A, Structure *ST, char **cat, int n_cat, char *matrix) + { + int a, b, c; + + float **sim; + char cr1, cr2; + int r1, r2; + int p1, p2; + float pos,tot; + + sim=declare_float ( A->nseq, A->nseq); + + for ( a=0; anseq-1; a++) + { + for (b=a+1; b< A->nseq; b++) + { + for ( r1=0, r2=0,tot=0, pos=0,c=0; c< A->len_aln; c++) + { + p1=is_gap(A->seq_al[a][c]); + p2=is_gap(A->seq_al[b][c]); + + r1+=1-p1; + r2+=1-p2; + cr1=A->seq_al[a][c]; + cr2=A->seq_al[b][c]; + if (!p1 && !p2) + { + if (is_in_struct_category (a, b, r1, r2, ST, cat, n_cat)) + { + tot++; + pos+=is_in_same_group_aa ( cr1, cr2, 0, NULL, matrix); + } + } + } + sim[a][b]=sim[b][a]=(tot==0)?0:((pos*100)/tot); + } + } + return sim; + } +float **analyse_sim ( Alignment *A, float **sim) + { + int a,b,c; + + float **an, d; + + + an=declare_float ( A->nseq+1,2); + + for (d=0, a=0; a< A->nseq;a++) + { + for ( b=0; b< A->nseq; b++) + { + if ( b!=a) + { + an[a][0]+=sim[a][b]; + an[A->nseq][0]+=sim[a][b]; + d++; + } + } + an[a][0]=((float)an[a][0]/(float)(A->nseq-1)); + } + + + an[A->nseq][0]=an[A->nseq][0]/d; + + for ( d=0,a=0; a< A->nseq; a++) + { + for ( b=0; b< A->nseq; b++) + { + if ( b!=a) + { + c=an[a][0]-sim[a][b]; + an[a][1]+=(c>0)?c:-c; + an[A->nseq][1]+=(c>0)?c:-c; + d++; + } + } + an[a][1]=((float)an[a][1]/(float)(A->nseq-1)); + } + + an[A->nseq][1]=an[A->nseq][1]/d; + + return an; + } + + + + + + + + +/************************************************************************************/ +/* */ +/* STRUC ANALYSE */ +/* */ +/* */ +/************************************************************************************/ +int is_in_struct_category ( int s1, int s2, int r1, int r2, Structure *ST, char **cat, int n_cat) + { + int a; + static char *struc_r1; + static char *struc_r2; + char first[STRING]; + char second[STRING]; + static int **r; + + + + + if ( ST==NULL)return 1; + if ( struc_r1!=NULL) + { + vfree ( struc_r1); + vfree ( struc_r2); + } + + if ( r==NULL)r=declare_int (2, 2); + else r[0][0]=r[1][1]=r[1][0]=r[0][1]=0; + + + struc_r1=get_structure_residue ( s1, r1, ST); + struc_r2=get_structure_residue ( s2, r2, ST); + + + for ( a=1; a< n_cat; a+=2) + { + sprintf ( first, "%s", cat[a]); + sprintf ( second,"%s", cat[a+1]); + r[0][0]=struc_matches_pattern ( struc_r1, first); + r[0][1]=struc_matches_pattern ( struc_r2, first); + r[1][0]=struc_matches_pattern ( struc_r1, second); + r[1][1]=struc_matches_pattern ( struc_r2, second); + + if ( (r[0][0]&&r[1][1])||(r[1][0]&&r[0][1]))return 1; + } + return 0; + } + +char * get_structure_residue (int seq, int res, Structure *ST) + { + int a; + char *s; + + s=vcalloc ( ST->n_fields+1, sizeof (char)); + for (a=0; a< ST->n_fields; a++) + s[a]=ST->struc[seq][res][a]; + s[a]='\0'; + return s; + } + +int struc_matches_pattern ( char *struc, char *pattern) + { + char p[STRING]; + char *y; + + int b,l; + + + sprintf ( p, "%s", pattern); + + if ( strcmp (p, "*")==0)return 1; + else + { + l=strlen ( struc); + y=strtok ( p, "."); + + for ( b=0; bnseq, A->seq_al); + else + ST=extend_structure ( ST); + + StrucAln=declare_Alignment(NULL); + if (strm ( format, "pep")) + { + SEQ=main_read_seq ( fname); + StrucAln=seq2aln(SEQ,StrucAln,0); + } + + else if ( strcmp ( format, "aln")==0) + { + StrucAln=main_read_aln (fname, StrucAln); + } + + reorder_aln(StrucAln, A->name, A->nseq); + + SA=aln2seq(StrucAln); + string_array_convert (SA->seq, SA->nseq, n_symbols, symbol_table); + seq2struc (SA, ST); + + free_aln(StrucAln); + if (SEQ)free_sequence (SEQ, SEQ->nseq); + + return ST; + } + +int parse_category_list ( char *category_list_in, char ***category, int*n_sub_categories) + { + int n,a; + char *category_list; + char *y,*z; + category_list=vcalloc ( strlen(category_list_in)+1, sizeof (char)); + sprintf (category_list, "%s", category_list_in); + + n=0; + z=category_list; + while ((y=strtok(z, ";"))!=NULL) + { + sprintf ( category[n++][2], "%s", y); + z=NULL; + } + + + for ( a=0; a< n; a++) + { + sprintf (category_list,"%s",strtok(category[a][2], "=")); + sprintf (category[a][0],"%s",strtok (NULL, "=")); + sprintf ( category[a][++n_sub_categories[a]],"%s", strtok(category_list, "[]+")); + while ( ((y=strtok(NULL, "[]+"))!=NULL)) + { + if ( strcmp (y, "#")==0)y=category[a][n_sub_categories[a]]; + sprintf ( category[a][++n_sub_categories[a]],"%s",y); + } + } + return n; + } + + +int is_a_struc_format (char *format) + { + if ( strcmp ( format, "pep")==0)return 1; + if ( strcmp ( format, "aln")==0)return 1; + return 0; + } +/************************************************************************************/ +/* */ +/* Informations */ +/* */ +/* */ +/************************************************************************************/ +void output_informations () +{ +fprintf ( stderr, "\nPROGRAM: %s (%s)\n",PROGRAM,VERSION); +fprintf ( stderr, "******INPUT***************************"); +fprintf ( stderr, "\n-al1 al1_file"); +fprintf ( stderr, "\n-al2 al2_file"); +fprintf ( stderr, "\n-compare_mode [sp] or column"); +fprintf ( stderr, "\n-pep (compare only the sequences"); +fprintf ( stderr, "\n-count"); +fprintf ( stderr, "\n-pep1 pep1_file"); +fprintf ( stderr, "\n-pep1 pep2_file"); +fprintf ( stderr, "\n-st str_file st_format conversion"); +fprintf ( stderr, "\n **st_format: aln, pep"); +fprintf ( stderr, "\n **conversion: 3d_ali, conv abcZ #X"); +fprintf ( stderr, "\nNOTE: Several structures in a row are possible"); + +fprintf ( stderr, "\n\n****DISTANCE MEASURE*****************"); +fprintf ( stderr, "\n-sim_cat category_format or category_name"); +fprintf ( stderr, "\n **category_format: [*][*]=[tot]"); +fprintf ( stderr, "\n **category_name : 3d_ali (<=>[h][h]+[e][e]=[Struc]"); +fprintf ( stderr, "\n-sim_matrix matrix_name"); +fprintf ( stderr, "\n **matrix_name: idmat,pam250mt.."); +fprintf ( stderr, "\n-sim_aln al1 or al2"); +fprintf ( stderr, "\n\n****COMPARISON***********************"); +fprintf ( stderr, "\n-io_cat category_format or category_name"); +fprintf ( stderr, "\n **category_format: [*][*]=[tot]"); +fprintf ( stderr, "\n **category_name : 3d_ali(<=>[h][h]+[e][e]=[Struc];[*][*]=[Tot]"); +fprintf ( stderr, "\n\nNOTE: if two structures:"); +fprintf ( stderr, "\n[he.123][#]=[he123VShe123];[beh.*][he.2345]=[other]"); +fprintf ( stderr, "\n\n****OUTPUT****************************"); +fprintf ( stderr, "\n-f stdout"); +fprintf ( stderr, "\n stderr"); +fprintf ( stderr, "\n file_name"); +fprintf ( stderr, "\n-io_format hts"); +fprintf ( stderr, "\n H ->large Header"); +fprintf ( stderr, "\n h ->small Header"); +fprintf ( stderr, "\n t->global (average)results"); +fprintf ( stderr, "\n s ->average results for each sequence"); +fprintf ( stderr, "\n p ->results for each pair of sequences"); +fprintf ( stderr, "\n-output_aln Outputs al1 with conserved bits in Upper"); +fprintf ( stderr, "\n-output_aln_threshold [100]"); +fprintf ( stderr, "\n-output_aln_file [stdout]"); +fprintf ( stderr, "\n-output_aln_format [clustalw]"); +fprintf ( stderr, "\n-output_aln_modif [lower]"); +fprintf ( stderr, "\n"); +myexit (EXIT_SUCCESS); +} + +/*********************************COPYRIGHT NOTICE**********************************/ +/*� Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Tue Jul 1 10:00:54 WEST 2008. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/*********************************COPYRIGHT NOTICE**********************************/ +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/aln_convertion_util.c b/binaries/src/tcoffee/t_coffee_source/aln_convertion_util.c new file mode 100644 index 0000000..6afa479 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/aln_convertion_util.c @@ -0,0 +1,18008 @@ +#include +#include +#include +#include +#include +#include +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "dp_lib_header.h" +#include "define_header.h" + +int aln_has_stockholm_structure (Alignment *A) +{ + return name_is_in_list ("#=GC SS_cons", A->name, A->nseq, 100); +} + +int get_aln_stockholm_structure (Alignment *A) +{ + int i; + if ((i=aln_has_stockholm_structure(A))==-1) + A=add_alifold2aln (A, NULL); + return aln_has_stockholm_structure(A); +} +int ** update_RNAfold_list (Alignment *A, int **pos, int s, int **l) +{ + int a=0; + while (l[a]) + { + if (!is_gap(A->seq_al[s][l[a][0]]) && !is_gap (A->seq_al[s][l[a][1]])) + { + l[a][2]=pos[s][l[a][0]]; + l[a][3]=pos[s][l[a][1]]; + } + else + { + l[a][2]=l[a][3]=-1; + } + a++; + } + return l; +} + +Alignment *compare_RNA_fold ( Alignment *A, Alignment *B) +{ + int i1, i2, i; + int **l1, **l2; + int **pos1, **pos2; + int a, b; + int tot_ol=0, tot_l=0; + + i1=get_aln_stockholm_structure (A); + i2=get_aln_stockholm_structure (B); + + l1=vienna2list (A->seq_al[i1]); + l2=vienna2list (B->seq_al[i2]); + + pos1=aln2pos_simple(A, A->nseq); + pos2=aln2pos_simple(B, B->nseq); + + + + for (a=0; a< A->nseq; a++) + { + char **lu; + int ol=0, ll1=0, ll2=0; + if ( A->name[a][0]=='#')continue; + i=name_is_in_list (A->name[a], B->name, B->nseq, 100); + if (i!=-1) + { + l1=update_RNAfold_list (A,pos1,a, l1); + l2=update_RNAfold_list (B,pos2,i, l2); + lu=declare_char (A->len_aln, B->len_aln); + + b=0; + while (l2[b]) + { + + if (l2[b][2]==-1 || l2[b][3]==-1); + else + { + ll2++; + lu[l2[b][2]][l2[b][3]]=1; + + } + b++; + } + b=0; + + while (l1[b]) + { + + if (l1[b][2]==-1 || l1[b][3]==-1); + else + { + ll1++; + if (lu[l1[b][2]][l1[b][3]]==1) + { + A->seq_al[a][l1[b][0]]='6'; + A->seq_al[a][l1[b][1]]='6'; + ol++; + } + else + { + A->seq_al[a][l1[b][0]]='0'; + A->seq_al[a][l1[b][1]]='0'; + } + } + b++; + } + + free_char (lu, -1); + } + tot_ol+=ol; + tot_l+=ll1; + tot_l+=ll2; + fprintf ( stdout, "@@ Seq: %s Overalp: %.2f Al1: %.2f Al2: %.2f \n", A->name[a], (float)(ol*200)/(ll1+ll2), (float)(ol*100)/ll1,(float)(ol*100)/ll2); + } + + fprintf ( stdout, "@@ Seq: Tot Overalp: %.2f \n", (float)(tot_ol*200)/(tot_l)); + + return A; +} +int is_neutral(char c1, char c2); +int is_watson (char c1, char c2); +int is_watson2 (char c1, char c2); +int is_watson (char c1, char c2) +{ + c1=tolower (c1); + c2=tolower (c2); + if ( is_watson2 (c1, c2)) return 1; + else return is_watson2 (c2, c1); +} +int is_watson2 (char c1, char c2) +{ + + if ( c1=='g' && c2=='c')return 1; + else if (c1=='a' && (c2=='t' || c2=='u'))return 1; + return 0; +} +int is_neutral (char c1, char c2) +{ + + c1=tolower (c1); + c2=tolower (c2); + if (is_watson (c1, c2)) return 1; + else if (c1=='g' && (c2=='t' || c2=='u'))return 1; + else if ((c1=='t' || c1=='u') && c2=='g')return 1; + return 0; +} + +int ** vienna2list ( char *seq) +{ + int a, b, i, i2,l; + int **list; + l=strlen (seq); + list=declare_int (l+1, 8); + for (i=0,a=0; a=0; b++) + { + if (seq[b]=='(')i2++; + else if (seq[b]==')')i2--; + } + list[i][1]=b-1; + i++; + } + } + + list[i]=NULL; + return list; +} +Alignment *aln2alifold(Alignment *A) +{ + char *tmp1; + char *tmp2; + + print_aln (A); + tmp1=vtmpnam (NULL); + tmp2=vtmpnam (NULL); + output_clustal_aln (tmp1,A); + printf_system ("RNAalifold %s >%s 2>/dev/null", tmp1, tmp2); + return alifold2aln (tmp2); +} + +Alignment *add_alifold2aln (Alignment *A, Alignment *ST) +{ + int a,b,c,d,p1,p2; + int r1, rr1, r2, rr2; + int watson, comp,tot; + int **compmat; + int max, p,k; + int minseq=3; + int **list; + int ncomp=0, nwatson=0; + int cons_l, fold_l; + int i,l; + + if (!ST) + { + char *tmp1, *tmp2; + int f; + Alignment *T; + T=copy_aln (A, NULL); + tmp1=vtmpnam (NULL); + tmp2=vtmpnam (NULL); + cons_l=A->len_aln; + for (a=0; alen_aln; a++) + { + for (f=0,b=0; bnseq && f==0; b++) + { + if (is_gap (A->seq_al[b][a]))f=1; + + } + if (f) + { + cons_l--; + for (b=0; bnseq; b++)T->seq_al[b][a]='-'; + } + } + ST=aln2alifold (T); + } + //add or Replace the structure + l=strlen (ST->seq_al[1]); + for (a=0; a< l; a++)if (ST->seq_al[1][a]==STOCKHOLM_CHAR)ST->seq_al[1][a]='.'; + if ((i=name_is_in_list ("#=GC SS_cons", A->name, A->nseq, 100))!=-1) + { + sprintf (A->seq_al[i], "%s", ST->seq_al[1]); + } + else + { + A=realloc_aln2 ( A, A->nseq+1, A->len_aln+1); + sprintf (A->name[A->nseq], "#=GC SS_cons"); + sprintf (A->seq_al[A->nseq], "%s", ST->seq_al[1]); + A->nseq++; + } + return A; +} +Alignment * alifold2analyze (Alignment *A, Alignment *ST, char *mode) +{ + int s; + int **list; + int usegap; + + s=name_is_in_list ("#=GC SS_cons", A->name,A->nseq, 100); + + if (s==-1) + { + A=add_alifold2aln (A,ST); + s=name_is_in_list ("#=GC SS_cons", A->name,A->nseq, 100); + } + + list=vienna2list (A->seq_al[s]); + list=alifold_list2cov_list (A, list); + + usegap=0; //do not use gaped positions by default + if (mode && strstr (mode, "usegap"))usegap=1;//count positions with gaps + + if (!mode) + { + A=alifold2cov_stat (A, list,usegap); + } + else + { + if ( strstr (mode, "stat")) A=alifold2cov_stat (A, list, usegap); + if ( strstr (mode, "list")) A=alifold2cov_list (A, list, usegap); + if ( strstr (mode, "aln")) A=alifold2cov_aln (A, list, usegap); + if ( strstr (mode, "color") ) + { + Alignment *C; + C=copy_aln (A, NULL); + C=alifold2cov_cache (C, list, usegap); + A=alifold2cov_aln (A, list, usegap); + if ( strstr ( mode, "ps")) + output_color_ps (A, C, "stdout"); + else + output_color_html (A, C, "stdout"); + myexit (EXIT_SUCCESS); + } + } + return A; +} + + +int ** alifold_list2cov_list (Alignment *A, int **list) +{ + int a,b,c,d,p1,p2,s; + int r1, rr1, r2, rr2; + int neutral,watson, comp,tot, occupancy; + int **compmat; + int max, p,k; + int minseq=3; + + int ncomp=0, nwatson=0, nneutral=0, ncomp_wc=0; + int cons_l, fold_l; + int nseq; + + + for (nseq=0,a=0; a< A->nseq; a++)if ( A->name[a][0]!='#')nseq++; + max=((nseq*(nseq-1))/2); + a=0; + while (list[a]) + { + p1=list[a][0]; + p2=list[a][1]; + watson=0; + comp=0; + neutral=0; + tot=0; + occupancy=0; + for (c=0; cnseq-1; c++) + { + if (A->name[c][0]=='#')continue; + r1=tolower(A->seq_al[c][p1]); + r2=tolower(A->seq_al[c][p2]); + if (is_gap(r1) || is_gap(r2))continue; + for (d=c+1; dnseq; d++) + { + if (A->name[d][0]=='#')continue; + rr1=tolower(A->seq_al[d][p1]); + rr2=tolower(A->seq_al[d][p2]); + if (is_gap(rr1) || is_gap(rr2))continue; + if (is_watson (r1, r2))watson++; + if (is_watson (rr1, rr2))watson++; + if (is_neutral (r1, r2))neutral++; + if (is_neutral (rr1, rr2))neutral++; + if (r1!=rr1 && r2!=rr2)comp++; + occupancy++; + } + } + if (occupancy==0) + { + a++; + continue; + } + watson=(watson*100)/(occupancy*2); + comp=(comp*100)/occupancy; + neutral=(neutral*100)/(occupancy*2); + occupancy=(occupancy*100)/max; + list[a][3]=neutral; + list[a][4]=watson; + list[a][5]=comp; + list[a][6]=occupancy; + + if (list[a][3]<100)list[a][7]='I';//incompatible pair + else + { + list[a][7]='N';//Neutral pair + if (list[a][4]==100) + { + list[a][7]='W';//Watson and Crick + if ( list[a][5]>0)list[a][7]='C'; //Watson and crick compensated + } + else if ( list[a][5]>0) + { + list[a][7]='c';//compensated + } + } + a++; + } + + return list; +} +Alignment *alifold2cov_aln (Alignment *inA,int **list, int ug) +{ + int a=0; + a=0; + Alignment *A; + + A=copy_aln (inA, NULL); + A=realloc_aln2 ( A, A->nseq+1, A->len_aln+1); + sprintf (A->name[A->nseq], "#=GC SS_analyze"); + sprintf (A->seq_al[A->nseq], "%s", A->seq_al[A->nseq-1]); + A->nseq++; + while (list[a]) + { + char s; + if (list[a][6]<100 && !ug); + else + { + s=list[a][7]; + A->seq_al[A->nseq-1][list[a][0]]=s; + A->seq_al[A->nseq-1][list[a][1]]=s; + } + a++; + } + return A; +} +Alignment *alifold2cov_stat (Alignment *A,int **list, int ug) +{ + int fold=0,watson=0, comp=0, compwc=0, incomp=0, neutral=0; + int a; + + a=0; + while (list[a]) + { + int s; + fold++; + if (list[a][6]<100 && !ug); + else + { + s=list[a][7]; + watson +=(s=='W')?1:0; + compwc +=(s=='C')?1:0; + comp +=(s=='c')?1:0; + neutral+=(s=='N')?1:0; + incomp +=(s=='I')?1:0; + } + a++; + } + fprintf ( stdout, "@@ TOT Nseq:%d tot_len: %d fold: %d neutral: %d watson: %d CorWC: %d cor: %d Incompatible: %d\n",A->nseq-1, A->len_aln,fold, neutral,watson, compwc,comp,incomp); + return A; +} +Alignment *alifold2cov_cache (Alignment *inA, int **list, int ug) +{ + int a,b, c; + Alignment *A; + + A=copy_aln (inA, NULL); + a=0; + while (list[a]) + { + int v, s; + if (list[a][6]<100 && !ug); + else + { + s=list[a][7]; + if (s=='C')v=9; //red + else if ( s=='c')v=7; //orange + else if ( s=='W')v=5; //Yellow + else if ( s=='N')v=2; //green + else if ( s=='I')v=0; //blue; + for (b=0;bnseq; b++) + { + if (A->name[b][0]=='#'); + else + { + for (c=0; c<2; c++) + { + A->seq_al[b][list[a][c]]='0'+v; + } + } + } + } + a++; + } + return A; +} + +Alignment *alifold2cov_list (Alignment *A,int **list, int ug) +{ + int a,b, s; + + a=0; + while (list[a]) + { + s=list[a][7]; + if (list[a][6]<100 && !ug); + else if (s=='C') + { + fprintf ( stdout, "@@ WC Compensated pair: %4d %4d =>", list[a][0]+1, list [a][1]+1); + for (b=0; bnseq; b++)if (A->name[b][0]!='#')fprintf ( stdout, "[%c%c]", toupper (A->seq_al[b][list[a][0]]), toupper(A->seq_al[b][list[a][1]])); + fprintf (stdout,"\n"); + } + else if (s=='c') + { + fprintf ( stdout, "@@ Neural Compensated pair: %4d %4d =>", list[a][0]+1, list [a][1]+1); + for (b=0; bnseq; b++)if (A->name[b][0]!='#')fprintf ( stdout, "[%c%c]", toupper (A->seq_al[b][list[a][0]]), toupper(A->seq_al[b][list[a][1]])); + fprintf (stdout,"\n"); + } + else if (s=='W') + { + fprintf ( stdout, "@@ WC pair: %4d %4d =>", list[a][0]+1, list [a][1]+1); + for (b=0; bnseq; b++)if (A->name[b][0]!='#')fprintf ( stdout, "[%c%c]", toupper (A->seq_al[b][list[a][0]]), toupper(A->seq_al[b][list[a][1]])); + fprintf (stdout,"\n"); + } + else if (s=='N') + { + fprintf ( stdout, "@@ Neutral pair: %4d %4d =>", list[a][0]+1, list [a][1]+1); + for (b=0; bnseq; b++)if (A->name[b][0]!='#')fprintf ( stdout, "[%c%c]", toupper (A->seq_al[b][list[a][0]]), toupper(A->seq_al[b][list[a][1]])); + fprintf (stdout,"\n"); + } + else if (s=='I') + { + fprintf ( stdout, "@@ incompatible pair: %4d %4d =>", list[a][0]+1, list [a][1]+1); + for (b=0; bnseq; b++)if (A->name[b][0]!='#')fprintf ( stdout, "[%c%c]", toupper (A->seq_al[b][list[a][0]]), toupper(A->seq_al[b][list[a][1]])); + fprintf (stdout,"\n"); + } + a++; + } + + return A; +} + + +Alignment *aln2sample (Alignment *A, int n) +{ + Alignment *B; + int a, b, p; + int **pos; + + B=copy_aln (A, NULL); + + vsrand(0); + + pos=declare_int (A->len_aln, 2); + for (a=0; alen_aln; a++){pos[a][0]=a;pos[a][1]=rand()%(1000*A->len_aln);} + + sort_int (pos, 2, 1, 0, A->len_aln-1); + + n=(n==0)?A->len_aln:(MIN (n, (A->len_aln))); + for (a=0; anseq; b++) + A->seq_al[b][a]=B->seq_al[b][pos[a][0]]; + for (b=0; bnseq; b++) + A->seq_al[b][n]='\0'; + A->len_aln=n; + + free_aln (B); + free_int (pos, -1); + return A; +} +Alignment *aln2bootstrap (Alignment *A, int n) +{ + Alignment *B; + int a, b, p; + + if (n==0)n=A->len_aln; + else A=realloc_aln (A, n+1); + vsrand(0); + B=copy_aln (A, NULL); + for (a=0; alen_aln; + for (b=0; bnseq; b++) + A->seq_al[b][a]=B->seq_al[b][p]; + } + for ( b=0; bnseq; b++)A->seq_al[b][n]='\0'; + A->len_aln=n; + + free_aln (B); + return A; + +} + + +Alignment * aln2random_aln (Alignment *A, char *smode) + +{ + int a, b, n, **res; + int max; + + + + if ( smode==NULL) + { + smode=vcalloc (4, sizeof (char)); + sprintf ( smode, "SCR");//Sequences, Column Residues + } + else if ( strm (smode, "NO"))return A; + + vsrand(0); + max=A->nseq*1000; + + if ( strstr ( smode, "S")) + { + A=aln2scramble_seq (A); + } + if ( strstr ( smode, "C")) + { + + res=declare_int (A->nseq, 2); + for (a=0; a< A->len_aln; a++) + { + for (n=0,b=0;bnseq; b++) + { + if ( !is_gap(A->seq_al[b][a])) + { + res[n][0]=A->seq_al[b][a]; + res[n][1]=rand()%max; + n++; + } + sort_int (res, 2, 1, 0, n-1); + } + for (n=0,b=0;bnseq; b++) + { + if ( !is_gap(A->seq_al[b][a]))A->seq_al[b][a]=res[n++][0]; + } + } + free_int (res, -a); + } + + + //Redistributes the residues randomly without changing the gap pattern + if ( strstr ( smode, "R")) + { + max=A->len_aln*A->nseq; + res=declare_int (max, 2); + + for (n=0,a=0; a< A->len_aln; a++) + { + for (b=0;bnseq; b++) + { + if ( !is_gap(A->seq_al[b][a])) + { + res[n][0]=A->seq_al[b][a]; + res[n][1]=rand()%max; + n++; + } + + } + } + sort_int (res, 2, 1, 0, n-1); + for (n=0,a=0; a< A->len_aln; a++) + { + for (b=0;bnseq; b++) + { + if ( !is_gap(A->seq_al[b][a])) + { + A->seq_al[b][a]=res[n++][0]; + } + + } + } + + free_int (res, -1); + } + + return A; +} +Alignment *score_aln2score_ascii_aln (Alignment *A, Alignment *C) +{ + //Convert the output of T-Coffee evaluate into a printable score_ascii alignment*/ + //A and C must be sorted + //sets to 0 lone residues + int a, b; + + for (a=0; anseq; a++) + for (b=0; blen_aln; b++) + { + + int rC=C->seq_al[a][b]; + int rA=A->seq_al[a][b]; + if ( !strm (A->name[a], C->name[a])){HERE ("Unsorted aln in score_aln2score_ascii"); myexit (EXIT_FAILURE);} + + if ( rA=='x' || rA=='X')C->seq_al[a][b]='9'; + else if ( rC >='0' && rC<='9'); + else if ( rC<10)C->seq_al[a][b]='0'+rC; + else if ( rC==NO_COLOR_RESIDUE && !is_gap(rA)) C->seq_al[a][b]='0'; + else if ( rC==NO_COLOR_RESIDUE && is_gap(rA))C->seq_al[a][b]='-'; + } + return C; +} +Alignment*aln2gap_cache (Alignment *A, int val) +{ + Alignment *B; + int a, b, c, nr; + + B=copy_aln (A, NULL); + for (b=0; blen_aln; b++) + { + for (nr=0,a=0; anseq; a++)nr+=!is_gap (A->seq_al[a][b]); + for (a=0; anseq; a++)if (!is_gap(A->seq_al[a][b]))B->seq_al[a][b]=(nr==1)?'0'+val:'1'; + } + return B; +} + +Alignment* aln2case_aln (Alignment *B, char *upper, char *lower) +{ + int a, b, c, up, lo; + Alignment *A; + + A=copy_aln (B, NULL); + + up=(upper)?upper[0]:'u'; + lo=(lower)?lower[0]:'l'; + + for (a=0; anseq; a++) + for (b=0; blen_aln; b++) + { + c=A->seq_al[a][b]; + + if ( is_gap(c)); + else A->seq_al[a][b]=(isupper (c))?up:lo; + } + return A; +} +Alignment *aln2scale (Alignment *A, char *coffset) +{ + int a, b, t, v, n; + char *s1, *s2; + char s[1000]; + int offset; + + if (coffset)offset=atoi(coffset); + else offset=0; + + sprintf (s, "%d", A->len_aln+offset); + n=strlen (s); + + A=realloc_aln2 (A, A->nseq+n, A->len_aln+1); + s1=vcalloc ( n+1, sizeof (char)); + s2=vcalloc ( n+1, sizeof (char)); + + for (a=0; aname[A->nseq+a], "%s", s2); + } + + for (a=0; alen_aln; a++) + { + sprintf (s1, "%d", a+1+offset); + s2=invert_string (s1); + t=strlen (s2); + + for (b=0; b<=n; b++) + { + if (b>=t) v='0'; + else v=s2[b]; + + A->seq_al[A->nseq+b][a]=v; + } + } + + A->nseq+=n; + return A; +} + + + + +int * pos2list (int * pos, int len, int *nl) +{ + int *list; + int a; + nl[0]=0; + list=vcalloc (len, sizeof (int)); + for (a=0; anseq+((B)?B->nseq:0), sizeof (int)); + pos=aln2pos_simple_2 (A); + if (B) + { + n=B->nseq; + for ( a=0; anseq; a++) + { + list[a]=name_is_in_list(B->name[a], A->name, A->nseq, 100); + } + } + else + { + for ( a=0; anseq; a++) + list[a]=a; + n=A->nseq; + } + + + fprintf ( fp, "#"); + for ( b=0; bname[s]); + } + fprintf (fp, "\n"); + + for ( a=0; alen_aln; a++) + { + for ( b=0; bx, where x is the position of residue z of seq1/S1 in S2->seq[index[Seq1/S1]] + */ + int a; + int **index; + char *seq1=NULL, *seq2=NULL; + Alignment *Profile; + + index=vcalloc ( S1->nseq, sizeof (int*)); + + for (a=0; a< S1->nseq; a++) + { + int len1, len2, b, c; + + seq1=S1->seq[a]; + + if (name_index[a][0]==-1) + seq2=NULL; + else if (name_index[a][1]==-1) + { + seq2=S2->seq[name_index[a][0]]; + } + else if ((Profile=seq2R_template_profile (S2, name_index[a][0])) !=NULL) + { + seq2=Profile->seq_al[name_index[a][1]]; + } + + len1=(seq1)?strlen (seq1):0; + len2=(seq2)?strlen (seq2):0; + index[a]=vcalloc (len2, sizeof(int)); + + + for (c=0,b=0; bx if seq1 is the xth sequence of S2 + ->-1 if seq1 is nowhere to be found + index[seq1 of S1][1]->z if seq1 is the zth sequence within the xth profile of S2 + */ + int **index; + int a, b, x, z; + Alignment *Profile; + index=declare_int (S1->nseq, 2); + + + for ( a=0; anseq; a++) + { + index[a][0]=index[a][1]=-1; + x=name_is_in_list (S1->name[a],S2->name,S2->nseq,100); + if ( x!=-1){index[a][0]=x;index[a][1]=-1;} + for ( b=0; bnseq; b++) + { + if ((Profile=seq2R_template_profile (S2,b))) + { + z=name_is_in_list (S1->name[a],Profile->name,Profile->nseq,100); + if ( z!=-1){index[a][0]=b;index[a][1]=z;b=S2->nseq;} + } + } + } + return index; +} + + + + +int *get_name_index (char **l1, int n1, char **l2, int n2) +{ + int *r; + int a; + /*return Array[Index_L1]=Index_L2 */ + r=vcalloc ( n1, sizeof (int)); + for ( a=0; a< n1; a++) + r[a]=name_is_in_list (l1[a],l2,n2,100); + return r; +} + +int* get_res_index (char *seq0, char *seq1) +{ + int *coor, a; + + if ( !seq0 || !seq1) return NULL; + + + coor=vcalloc ( strlen (seq0)+1, sizeof (int)); + if (!strm (seq0, seq1)) + { + int r0, r1 , isr0, isr1; + int l0=0, l1=0; + Alignment *A; + A=align_two_sequences (seq0,seq1,"pam250mt",-5,-1, "myers_miller_pair_wise"); + + for ( a=0; a< A->len_aln; a++) + { + r0=A->seq_al[0][a];r1=A->seq_al[1][a]; + isr0=!is_gap(r0); + isr1=!is_gap(r1); + l0+= isr0; + l1+= isr1; + if (isr0 && isr1)coor[l0-1]=l1-1; + else if (isr0) coor[l0-1]=-1; + } + free_aln (A); + } + else + { + int l0; + + l0=strlen (seq0); + for ( a=0;a< l0; a++) + coor[a]=a; + } + + return coor; +} + +int change_residue_coordinate ( char *in_seq1, char *in_seq2, int v) +{ + /*Expresses the coordinate of a residue in seq1, in the coordinate system of seq2*/ + + + static char *seq1, *seq2; + static int *coor; + + + if ( seq1 !=in_seq1 || seq2 !=in_seq2) + { + int r0, r1 , isr0, isr1; + int l0=0, l1=0; + Alignment *A; + int a; + + vfree (coor); + seq1=in_seq1, seq2=in_seq2; + A=align_two_sequences (seq1,seq2,"pam250mt", -14, -2, "myers_miller_pair_wise"); + + coor=vcalloc ( A->len_aln, sizeof (int)); + for ( a=0; a< A->len_aln; a++) + { + r0=A->seq_al[0][a];r1=A->seq_al[1][a]; + + isr0=!is_gap(r0); + isr1=!is_gap(r1); + l0+= isr0; + l1+= isr1; + + if (isr0 && isr1)coor[l0-1]=l1-1; + else if (isr0) coor[l0-1]=-1; + } + free_aln (A); + } + return coor[v]; +} + + +int ** minimise_repeat_coor (int **coor, int nseq, Sequence *S) + { + int **new_coor; + int a, min; + new_coor=declare_int ( nseq, 3); + min=return_min_int (coor, nseq, 2); + for ( a=0; a< nseq; a++) + { + new_coor[a][0]=coor[a][0]; + new_coor[a][1]=coor[a][1]; + new_coor[a][2]=min; + } + return new_coor; + } +int ** get_nol_seq ( Constraint_list *CL, int **coor, int nseq, Sequence *S) + { + int a, s, p, l, nl; + int **buf; + int **new_coor; + + new_coor=declare_int ( nseq+1, 3); + + + buf=get_undefined_list ( CL); + + + + for ( a=0; a< nseq; a++)buf[coor[a][0]][coor[a][1]]=1; + + + for ( a=0; a< nseq; a++) + { + s=coor[a][0]; + p=coor[a][1]+1; + l=strlen(S->seq[s]); + nl=0; + while ( p<=l && !buf[s][p++])nl++; + new_coor[a][0]=s; + new_coor[a][1]=coor[a][1]; + new_coor[a][2]=nl; + } + free_int ( buf, -1); + return new_coor; + } + + + +int compare_pos_column( int **pos1,int p1, int **pos2,int p2, int nseq) + { + int a,v1, v2; + int identical=0; + + for ( a=0; a< nseq; a++) + { + + v1=pos1[a][p1]; + v2=pos2[a][p2]; + + if (v1>0 || v2>0) + { + if ( v1!=v2)return 0; + else identical=1; + } + } + + return identical; + } + +char *seq2alphabet (Sequence *S) +{ + return array2alphabet (S->seq, S->nseq, ""); +} + +char *aln2alphabet (Alignment *A) +{ + return array2alphabet (A->seq_al, A->nseq, ""); +} + +char *array2alphabet (char **array, int n, char *forbiden) +{ + int a, b, l; + int *hasch; + char *alphabet; + + hasch=vcalloc (256, sizeof (int)); + alphabet=vcalloc ( 257, sizeof (char)); + + + for ( a=0; anseq; a++) + { + char s; + s=Pred->seq_al[a][pos]; + if (!is_gap(s)) + { + score[tolower(s)]++; + tot++; + } + } + + if ( score['h']>score['i'] && score['h']>score['o'])cons='h'; + + else if ( score['i']>score['o'])cons='i'; + else cons='o'; + if (tot==0) return ""; + + + if (mode==VERBOSE)sprintf (result, " H: %3d I: %3d O: %3d P: %c", (score['h']*100)/tot, (score['i']*100)/tot, (score['o']*100)/tot, cons); + else if (mode == SHORT)sprintf ( result, "%c", cons); + score['h']=score['o']=score['i']=0; + return result; +} + + +Alignment * aln2hmmtop_pred (Alignment *A) + { + int a, b, c; + char *buf, *pred; + Alignment *PA; + + PA=copy_aln (A, NULL); + buf=vcalloc ( A->len_aln+1, sizeof (char)); + + for ( a=0; a< A->nseq; a++) + { + sprintf (buf, "%s", A->seq_al[a]); + pred=seq2tmstruc (buf); + for (c=0,b=0; blen_aln; b++) + { + if (!is_gap (PA->seq_al[a][b]))PA->seq_al[a][b]=pred[c++]; + } + vfree (pred); + } + vfree (buf); + return PA; + } + +char * seq2tmstruc ( char *seq) + { + static Sequence *S; + char *seqfile, *predfile, *buf; + FILE *fp; + + seqfile=vtmpnam (NULL); + predfile=vtmpnam (NULL); + + fp=vfopen (seqfile, "w"); + fprintf ( fp, ">seq1\n%s", seq); + vfclose (fp); + + + printf_system ( "fasta_seq2hmmtop_fasta.pl -in=%s -out=%s -arch=%s/%s -psv=%s/%s", seqfile, predfile, get_mcoffee_4_tcoffee(), "hmmtop.arch", get_mcoffee_4_tcoffee(), "hmmtop.psv"); + S=get_fasta_sequence (predfile, NULL); + buf=vcalloc ( strlen (S->seq[0])+1, sizeof (char)); + sprintf ( buf, "%s", S->seq[0]); + + free_sequence (S, S->nseq); + + return buf; + } + +char * set_blast_default_values() +{ + set_string_variable ("blast_server", (getenv ("blast_server_4_TCOFFEE"))?getenv ("blast_server_4_TCOFFEE"):"EBI"); + set_string_variable ("pdb_db", (getenv ("pdb_db_4_TCOFFEE"))?getenv ("pdb_db_4_TCOFFEE"):"pdb"); + set_string_variable ("prot_db", (getenv ("prot_db_4_TCOFFEE"))?getenv ("prot_db_4_TCOFFEE"):"uniprot"); + set_int_variable ("prot_min_sim", 0); + set_int_variable ("prot_max_sim", 100); + + set_int_variable ("prot_min_cov", 0); + set_int_variable ("prot_max_cov", 100); + + set_int_variable ("pdb_min_sim", 0); + set_int_variable ("pdb_max_sim", 100); + set_int_variable ("pdb_min_cov", 0); + set_int_variable ("pdb_max_cov", 100); + + return; +} + +char * seq2pdb (Sequence *S) +{ + set_blast_default_values(); + S->nseq=1; + S=seq2template_seq (S, "PDB", NULL); + return seq2P_pdb_id(S,0); +} + +Alignment * seq2blast ( Sequence *S) +{ + Alignment *A; + set_blast_default_values(); + + if (S->nseq==1) + { + S=seq2template_seq (S, "BLAST", NULL); + A=seq2R_template_profile(S,0); + sprintf ( A->name[0], "%s", S->name[0]); + } + else + { + int a; + for (a=0; a< S->nseq; a++) + { + Sequence *NS; + char name[1000]; + NS=fill_sequence_struc(1, &(S->seq[a]), &(S->name[a])); + NS=seq2template_seq (NS, "BLAST", NULL); + A=seq2R_template_profile(NS,0); + sprintf ( name, "%s.prf", S->name[a]); + + output_fasta_aln (name,A); + fprintf (stdout, "\nOUTPUT %s\n", name); + } + myexit (EXIT_SUCCESS); + } + return A; +} + + + + +Sequence * seq2unique_name_seq ( Sequence *S) +{ + int a; + if ((a=name_list2unique_name_list (S->nseq, S->name))) + { + add_warning ( stderr, "\nWarning: Sequence %s is duplicated in file %s. The sequence will be renamed", S->name[a-1], S->file[a-1]); + } + return S; +} +Alignment * aln2unique_name_aln ( Alignment *S) +{ + int a; + if ((a=name_list2unique_name_list (S->nseq, S->name))) + { + add_warning ( stderr, "\nWarning: Sequence %s is duplicated in file %s. The sequence will be renamed", S->name[a-1], S->file[a-1]); + } + return S; +} + + +int name_list2unique_name_list (int n, char **name) +{ + int duplicate=0; + int a, b; + + for (a=0; a%s\naggggg\n", name[a]); + vfclose (fp); + printf_system ("fasta_aln2fasta_aln_unique_name.pl %s > %s", tmp1, tmp2); + S=get_fasta_sequence (tmp2, NULL); + for (a=0; aname[a])+1)); + sprintf ( name[a], "%s", S->name [a]); + } + free_sequence(S, -1); + } + return duplicate; +} +char**gene2exons (char **seq, int nseq) +{ + + int a, b, c,r; + for (a=0; anseq; a++) + { + l=strlen (S->seq[a]); + for (d=0,b=0; bseq[a][b]; + if ( alp==NULL && !strchr (AA_ALPHABET, c) && !strchr (DNA_ALPHABET, c)); + else if (alp && strchr (alp, c)); + else S->seq[a][d++]=c; + } + S->seq[a][d]='\0'; + S->len[a]=strlen (S->seq[a]); + } + return S; +} +int ** seq2aln_pos (Alignment *A, int *ns, int **l_s) + { + int **code; + int a, b,c, d,l, p , g; + + + l=MAX(strlen (A->seq_al[l_s[0][0]]), strlen (A->seq_al[l_s[1][0]])); + code=declare_int ((A->S)->nseq,l+1); + + for (c=0; c<2; c++) + { + l=strlen (A->seq_al[l_s[c][0]]); + for (d=0; dorder[l_s[c][d]][0]; + for (p=0, b=0; bseq_al[l_s[c][d]][b]); + if (!g){p++; code[a][p]=b+1;} + } + } + } + return code; + } + +Alignment *local_maln2global_maln (char *seq, Alignment *A) + { + /*inputs a BLAST alignmnent where the master sequence may be partila + outputs the same alignment, while amkeing sure the profile is perfectly in sink with its master sequence + */ + + int a, b, c; + int start, end, rend; + char qname[100], *p; + Alignment *B=NULL; + + sprintf ( qname, "%s", A->name[0]); + p=strtok (qname, "_"); + if ( !strm (p, "QUERY")) + { + fprintf ( stderr, "\nUnappropriate format for the alignment [%s:FATAL]", PROGRAM); + myexit (EXIT_FAILURE); + } + + start=atoi(strtok (NULL, "_")); + end=atoi(strtok (NULL, "_")); + rend=strlen (seq); + + B=copy_aln (A,NULL); + if ( start>1 || endseq_al[0][a]=seq[a]; + for ( b=1; b< A->nseq; b++)A->seq_al[b][a]='-'; + } + + for (c=0,a=start-1; a< end; a++, c++) + { + A->seq_al[0][a]=seq[a]; + for ( b=1; b< A->nseq; b++) + { + A->seq_al[b][a]=B->seq_al[b][c]; + } + } + for ( a=end; aseq_al[0][a]=seq[a]; + for ( b=1; b< A->nseq; b++)A->seq_al[b][a]='-'; + } + for ( a=0; a< A->nseq; a++) A->seq_al[a][rend]='\0'; + free_aln (B); + + A->len_aln=rend; + return A; + } + +int ** aln2inv_pos ( Alignment *A) +{ + int **pos,a; + pos=vcalloc (A->nseq, sizeof (char*)); + for (a=0; a< A->nseq; a++)pos[a]=seq2inv_pos (A->seq_al[a]); + return pos; +} +int * seq2inv_pos ( char *seq) +{ + /*returns a list where each value gives the index of the corresponding residue in seq*/ + /*Numbering: 1 to L : Analogy to the aln2pos*/ + + int a,l1, l2; + int *pos; + + l1=strlen ( seq); + for ( l2=a=0; a< l1; a++)l2+=1-is_gap(seq[a]); + pos=vcalloc (l2+1, sizeof (int)); + for ( l2=a=0; a< l1; a++)if (!is_gap(seq[a]))pos[++l2]=a+1; + return pos; +} + + +int ** aln2pos_simple_2 (Alignment *A) + { + int **pos1; + int **pos2; + pos1=aln2pos_simple (A, A->nseq); + pos2=duplicate_int (pos1, A->nseq,read_size_int (pos1[0],sizeof (int))); + pos1=aln2pos_simple (NULL, 0); + return pos2; + } +int ** aln2pos_simple (Alignment *A, int n_nseq, ...) + { + /* + function documentation: start + int ** aln2pos_simple (Alignment *A, int n_nseq, ...) + +####with two parameter only: Alignment *A, int n_nseq + + this function turns A into pos, a matrix where each residue is replace by its index according to the complete sequence. + the indices in pos are computed using A->order[x][1] that contains the indice of the first residue of seq x of A + + n_nseq MUST not be null + +####with more than two param: + int ** aln2pos_simple (Alignment *A, int n_nseq, int *ns, int **ls) + n_nseq must be set to 0 for the param 3 and four to be read + + ns[x]=number seq in group + ls[x]=list of the sequences in group x ( size=ns[x]) + + The computation of the indices is only carried out on the scpecified residues + +####IMPORTANT + in pos, the numbering of the residues goes from 1 to L: + pos[0][0]=3, means that the first position of the first sequence + in the alignmnet contains residue #3 from sequence A->order[0][0]; + + function documentation: end + */ + + int a, b,c, p, g,l; + int **T; + + int max_nseq; + int n_len=0; + + int *list=NULL; + int *ns=NULL; + int **ls=NULL; + + + + va_list ap; + + + if ( A==NULL) + { + return NULL; + } + else + { + if ( n_nseq>0) + { + list=vcalloc(n_nseq, sizeof (int)); + for ( a=0; a< n_nseq; a++)list[a]=a; + } + else + { + va_start (ap, n_nseq); + ns=va_arg(ap, int * ); + ls=va_arg(ap, int **); + va_end(ap); + list=vcalloc ( ns[0]+ns[1], sizeof (int)); + n_nseq=0; + for ( a=0; a< ns[0]; a++)list[n_nseq++]=ls[0][a]; + for ( a=0; a< ns[1]; a++)list[n_nseq++]=ls[1][a]; + + } + max_nseq=MAX(read_size_int(A->order,sizeof (int*)),return_max_int (A->order, read_size_int(A->order,sizeof (int*)),0))+1; + n_len=get_longest_string ( A->seq_al,A->max_n_seq, NULL, NULL)+1; + + + T=declare_int (max_nseq, n_len); + for ( c=0; c< n_nseq; c++) + { + a=list[c]; + l=strlen ( A->seq_al[a]); + + for ( p=A->order[a][1],b=0; bseq_al[a][b]); + p+=g; + T[a][b]=(g==1)?p:-(1+p); + if ( A->seq_al[a][b]==UNDEFINED_RESIDUE)T[a][b]=0; + if ( A->seq_cache && T[a][b]>0)T[a][b]=A->seq_cache[A->order[a][0]][T[a][b]]; + } + } + vfree (list); + } + + return T; + } +Alignment ** split_seq_in_aln_list ( Alignment **aln, Sequence *S, int n_seq, char **seq_list) + { + int a, b, c; + char * long_seq=NULL; + int len,l; + int **translation; + int **table; + + + + + if ( aln==NULL)return NULL; + translation=declare_int ( S->nseq,2); + + for (len=0,a=0; a< S->nseq; a++) + { + if((b=name_is_in_list (S->name[a],seq_list, n_seq, 100))!=-1) + { + l=strlen(S->seq[a])+1; + long_seq=vrealloc(long_seq,(len+l+1)*sizeof(char)); + long_seq=strcat(long_seq, S->seq[a]); + long_seq=strcat(long_seq, "*"); + + translation[a][0]=b; + translation[a][1]=len; + len+=l; + } + else translation[a][0]=-1; + } + + long_seq[len-1]='\0'; + len--; + + table=declare_int ( len+1, 2); + + for ( b=0,a=0; a< S->nseq; a++) + { + if ( translation[a][0]!=-1) + { + c=1; + while (long_seq[b]!='\0' && long_seq[b]!='*') + { + table[b+1][1]=c++; + table[b+1][0]=translation[a][0]; + b++; + } + table[b][1]=c++; + table[b][0]=translation[a][0]; + b++; + } + } + + for ( a=0; a< (aln[-1])->nseq; a++) + { + for ( b=0; b< (aln[a])->nseq; b++) + { + + (aln[a])->order[b][0]=table[(aln[a])->order[b][1]][0]; + (aln[a])->order[b][1]=table[(aln[a])->order[b][1]][1]; + sprintf ( (aln[a])->name[b],"%s_%d_%d", S->name[(aln[a])->order[b][0]],a+1,b+1); + } + } + free_int (translation, -1); + free_int (table, -1); + return aln; + } + + + +Sequence * fill_sequence_struc ( int nseq, char **sequences, char **seq_name) + { + int a; + Sequence *S; + int shortest, longuest; + + if (!sequences) + { + shortest=longuest=0; + } + else if ( nseq>1) + { + shortest=get_shortest_string( sequences, nseq, NULL, NULL); + longuest=get_longest_string (sequences, nseq, NULL, NULL); + } + else if ( nseq==1) + { + shortest=longuest=strlen (sequences[0]); + } + else + { + return NULL; + } + + + S=declare_sequence (shortest, longuest,nseq); + S->nseq=nseq; + + if (sequences)S->seq=copy_char ( sequences, S->seq, nseq, -1); + else S->seq=declare_char (S->nseq, 1); + + S->name=copy_char ( seq_name, S->name,nseq, -1); + + ungap_array (S->seq,nseq); + for ( a=0; a< S->nseq; a++)S->len[a]=strlen(S->seq[a]); + return S; + } + + +Alignment * thread_profile_files2aln (Alignment *A, char *template_file, Fname *F) +{ + + Alignment *P; + int a; + + if (!A->S)A->S=aln2seq (A); + if (template_file)A->S=seq2template_seq (A->S, template_file,F); + for ( a=0; a< A->nseq; a++) + { + P=seq2R_template_profile (A->S, a); + if ( P) + { + P->expand=1; + sprintf ( P->name[0], "%s", A->name[a]); + } + } + + return expand_aln (A); +} + + + + +Alignment * expand_aln (Alignment *A) + { + /*This function expands the profiles within an alignment*/ + + + int a, b, d, e; + Alignment *MAIN=NULL, *SUB=NULL; + int n_sub_seq=0; + int new_nseq=0; + int *list; + Alignment *Profile; + + if ( !A)return A; + + + + list=vcalloc (A->nseq, sizeof (int)); + for ( a=0; a< A->nseq; a++) + { + Profile=seq2R_template_profile (A->S, A->order[a][0]); + if (Profile && Profile->expand) + { + new_nseq+=Profile->nseq; + } + else + { + new_nseq++; + list[n_sub_seq++]=a; + } + } + + if ( n_sub_seq==A->nseq){vfree(list);return A;} + else if (n_sub_seq==0){MAIN=copy_aln (A, MAIN);MAIN->nseq=0;} + else + { + MAIN=extract_sub_aln (A, n_sub_seq, list); + } + vfree(list); + + + for ( a=0; a< A->nseq; a++) + { + Profile=seq2R_template_profile (A->S, A->order[a][0]); + if ( Profile && Profile->expand) + { + + SUB=copy_aln (Profile,SUB); + + SUB=realloc_aln2(SUB, SUB->nseq, A->len_aln+1); + + for ( e=0,b=0; b< A->len_aln; b++) + { + if ( is_gap(A->seq_al[a][b])) + {for (d=0; d< SUB->nseq; d++)SUB->seq_al[d][b]='-';} + else + { + for(d=0; dnseq; d++)SUB->seq_al[d][b]=Profile->seq_al[d][e]; + e++; + } + + } + MAIN=stack_aln(MAIN, SUB); + } + } + free_aln (A); + free_aln (SUB); + return MAIN; + } +Alignment * expand_number_aln (Alignment *A,Alignment *EA) + { + /*This function expands the profiles within an alignment*/ + + + int a, b, d, e; + Alignment *MAIN=NULL, *SUB=NULL, *C=NULL; + int n_sub_seq=0; + int new_nseq=0; + int *list; + Alignment *Profile; + + if ( !EA || !A)return EA; + + if ( EA->nseqnseq) + { + fprintf (stderr, "\n[ERROR:expand_number_aln] Using as a master an expanded aln (%d %d) [FATAL:%s]", EA->nseq, A->nseq,PROGRAM); + EA->A=A->A=NULL; + print_aln (EA); + print_aln (A); + myexit (EXIT_FAILURE); + } + + + list=vcalloc (EA->nseq, sizeof (int)); + for ( a=0; a< EA->nseq; a++) + { + Profile=seq2R_template_profile (EA->S, EA->order[a][0]); + if (Profile && Profile->expand)new_nseq+=Profile->nseq; + else + { + new_nseq++; + list[n_sub_seq++]=a; + } + } + + if ( n_sub_seq==EA->nseq){vfree(list);return EA;} + else if (n_sub_seq==0){MAIN=copy_aln (EA, MAIN);MAIN->nseq=0;} + else + { + MAIN=extract_sub_aln (EA, n_sub_seq, list); + } + + + list[0]=EA->nseq; + C=extract_sub_aln (EA,1, list); + vfree(list); + + + + for ( a=0; a< EA->nseq; a++) + { + Profile=seq2R_template_profile (EA->S, EA->order[a][0]); + if ( Profile && Profile->expand) + { + SUB=copy_aln (Profile,SUB); + SUB=realloc_aln2(SUB, SUB->nseq, EA->len_aln+1); + + for ( e=0,b=0; b<= EA->len_aln; b++) + { + if (is_gap(A->seq_al[a][b])) + { + for ( d=0; dnseq; d++) + SUB->seq_al[d][b]=NO_COLOR_RESIDUE; + } + else + { + for ( d=0; dnseq; d++) + { + + if ( is_gap (Profile->seq_al[d][e])) + { + SUB->seq_al[d][b]=NO_COLOR_RESIDUE; + } + else SUB->seq_al[d][b]=EA->seq_al[a][b]; + } + e++; + } + } + for (d=0; d< SUB->nseq; d++)SUB->score_seq[d]=EA->score_seq[a]; + + MAIN=stack_aln(MAIN, SUB); + } + } + + MAIN=stack_aln(MAIN, C); + MAIN->nseq--; + MAIN->score=MAIN->score_aln=EA->score_aln; + + free_aln (SUB); + free_aln (EA); + + free_aln (C); + + return MAIN; + } + +Alignment * probabilistic_rm_aa ( Alignment *A, int pos, int len) +{ + int random_len=0; + int a, b; + int left, right; + + if ( len<0) + { + random_len=1; + len=-len; + } + + vsrand(0); + + if (pos==0)pos= (rand()%(A->len_aln-(2*len+len))) +len; + + + for ( a=0; a< A->nseq; a++) + { + if (random_len)left =rand()%len; + else left=len; + if (random_len)right=rand()%len; + else right=len; + if ( (pos-right)<0 || (pos+left)>A->len_aln) + { + add_warning ( stderr, "\nWarning: probabilistic_rm_aa, pos out of range [%s]\n", PROGRAM); + } + else + for ( b=pos-right; bseq_al[a][b]=(b==pos)?'~':'*'; + } + + ungap_aln (A); + free_sequence ( A->S, A->nseq); + A->S=aln2seq (A); + return A; + +} + +Alignment * remove_gap_column ( Alignment *A, char *mode) + { + int a, b; + char *p; + int *seq_list; + int nseq=0; + int keep_col, cl; + + + seq_list =vcalloc ( A->nseq, sizeof (int)); + while ( (p=strtok(mode, ":"))) + { + mode=NULL; + if (p[0]=='#') + { + seq_list[nseq++]=atoi(p+1)-1; + } + else if ( (a=name_is_in_list (p, A->name, A->nseq, 100))!=-1) + { + seq_list[nseq++]=a; + } + } + + if ( nseq==0) + { + for ( a=0; a< A->nseq; a++)seq_list[a]=a; + nseq=A->nseq; + } + + for ( cl=0,a=0; a<=A->len_aln; a++) + { + for (keep_col=1, b=0; b< nseq && keep_col; b++) + { + keep_col=(is_gap(A->seq_al[seq_list[b]][a]))?0:keep_col; + } + + if ( keep_col) + { + for ( b=0; b< A->nseq; b++) + { + A->seq_al[b][cl]=A->seq_al[b][a]; + } + cl++; + } + else + { + for ( b=0; b< A->nseq; b++) + { + A->seq_al[b][cl]='-'; + } + cl++; + } + } + A->len_aln=cl; + vfree (seq_list); + + return A; + } + + +Alignment * ungap_sub_aln (Alignment *A, int ns, int *ls) + { + + int a, b, c,t; + int len; + + len=strlen ( A->seq_al[ls[0]]); + + for ( c=0,a=0; aseq_al[ls[b]][a]); + if (t==ns); + else + { + for ( b=0; bseq_al[ls[b]][c]=A->seq_al[ls[b]][a]; + c++; + } + } + for ( b=0; bseq_al[ls[b]][c]='\0'; + return A; + } + +Sequence * ungap_seq ( Sequence *S) + { + int a; + + if ( !S)return NULL; + ungap(S->seq[0]); + S->max_len=S->min_len=strlen (S->seq[0]); + for ( a=0; a< S->nseq; a++) + { + ungap(S->seq[a]); + S->len[a]=strlen (S->seq[a]); + S->max_len=MAX(S->max_len,S->len[a]); + S->min_len=MAX(S->min_len,S->len[a]); + } + return S; + + } +Alignment* shift_column (Alignment *A, int from, int to); +int max_shift (Alignment *A, int p); +int column_is_lower (Alignment *A, int p); + +Alignment * unalign_aln_2 (Alignment *A, Alignment *C, int t) +{ + int a, b, pos, len; + Sequence *S; + int n, insert; + if (C) + { + for (a=0; anseq; a++) + for (b=0; blen_aln; b++) + { + int res=C->seq_al[a][b]; + A->seq_al[a][b]=toupper(A->seq_al[a][b]); + if ((isdigit (res) && (res-'0')<=t)) + A->seq_al[a][b]=tolower(A->seq_al[a][b]); + } + } + + n=0; + while ( A->seq_al[0][n]) + { + insert=0; + for (b=0; bnseq; b++)if (islower (A->seq_al[b][n]))insert=1; + if (insert) + { + insert_gap_col (A,n,1); + for (b=0; bnseq; b++) + { + if ( islower (A->seq_al[b][n+1])) + { + A->seq_al[b][n]=A->seq_al[b][n+1]; + A->seq_al[b][n+1]='-'; + } + } + } + n++; + } + for (a=A->len_aln-1; a>=0; a--) + { + if (column_is_lower (A,a)) + { + int s; + s=max_shift (A,a); + shift_column (A,a, a+s); + } + } + return A; +} +Alignment* shift_column (Alignment *A, int from, int to) +{ + char *buf; + int a; + + buf=vcalloc (A->nseq, sizeof (char)); + for (a=0; anseq; a++) + { + buf[a]=A->seq_al[a][from]; + A->seq_al[a][from]='-'; + } + to++; + insert_gap_col (A, to, 1); + for ( a=0; anseq; a++)A->seq_al[a][to]=buf[a]; + vfree (buf); + ungap_aln (A); + return A; +} +int max_shift (Alignment *A, int p) +{ + int shift, max_shift, a; + for (max_shift=A->len_aln,a=0; a< A->nseq; a++) + { + shift=0; + + if (!islower (A->seq_al[a][p]) || A->seq_al[a][p]=='-')continue; + while (A->seq_al[a][p+shift+1]=='-')shift++; + max_shift=MIN(shift,max_shift); + } + return max_shift; +} +int column_is_lower (Alignment *A, int p) +{ + int a; + + for ( a=0; anseq; a++) + if ( !is_gap (A->seq_al[a][p]) && !islower(A->seq_al[a][p]))return 0; + return 1; +} + +Alignment * unalign_aln (Alignment *A, Alignment *C, int t) +{ + int a, b, pos, len; + Sequence *S; + + for (a=0; anseq; a++) + for (b=0; blen_aln; b++) + { + int res=C->seq_al[a][b]; + A->seq_al[a][b]=toupper(A->seq_al[a][b]); + if ((isdigit (res) && (res-'0')<=t)) + A->seq_al[a][b]=tolower(A->seq_al[a][b]); + } + + + for (pos=-1, a=0; anseq; a++) + { + b=0; + while ( C->seq_al[a][b]) + { + int res=C->seq_al[a][b]; + if ((isdigit (res) && (res-'0')<=t)) + { + if (pos==-1){pos=b;len=1;} + else len++; + } + else if (pos!=-1) + { + + C=unalign_aln_pos(C,a,pos, len); + pos=-1; + } + b++; + } + if ( pos!=-1){C=unalign_aln_pos(C,a,pos, len);pos=-1;} + } + S=aln2seq (A); + thread_seq_struc2aln (C, S); + A=realloc_aln2 (A, A->nseq, C->len_aln+1); + A->len_aln=C->len_aln; + for (a=0; anseq; a++)sprintf ( A->seq_al[a], "%s", C->seq_al[a]); + ungap_aln (A); + + free_sequence (S, -1); + return A; +} +Alignment * unalign_aln_pos (Alignment *A, int s, int p, int l) +{ + int a; + char *buf; + int unalign=0; + + + buf=vcalloc (l+1, sizeof (char)); + for (a=0; aseq_al[s][p+a]; + A->seq_al[s][p+a]='-'; + } + + + A=insert_gap_col (A,p, l); + for (a=0; aseq_al[s][p+a]=buf[a]; + } + vfree (buf); + return A; +} +Alignment * insert_gap_col (Alignment *A, int p, int l) +{ + int a, c; + char *buf; + char *gap; + + gap=generate_null(l); + if ( !A || p>=A->len_aln || p<0)return A; + + buf=vcalloc (A->len_aln+l+1, sizeof (char)); + A=realloc_aln2(A,A->nseq, A->len_aln+l+1); + for (a=0; anseq; a++) + { + c=A->seq_al[a][p]; + A->seq_al[a][p]='\0'; + sprintf ( buf, "%s%s%c%s", A->seq_al[a],gap,c,A->seq_al[a]+p+1); + sprintf (A->seq_al[a], "%s", buf); + } + vfree (buf); + A->len_aln+=l; + return A; +} +Alignment * unalign_residues (Alignment *A, int si1, int si2) +{ + char *s1, *s2, *ns1, *ns2; + int l, a, b,r1, r2; + + s1=A->seq_al[si1];s2=A->seq_al[si2]; + l=strlen (s1); + + ns1=vcalloc (2*l+1, sizeof (char)); + ns2=vcalloc (2*l+1, sizeof (char)); + + for (b=a=0; a< l; a++) + { + r1=s1[a]; r2=s2[a]; + if (is_gap(r1) || is_gap(r2) || isupper (r1) || isupper(r2)) + { + ns1[b]=(r1=='.')?'-':r1; + ns2[b]=(r2=='.')?'-':r2; + b++; + } + else + { + ns1[b]=r1; + ns2[b]='-'; + b++; + ns2[b]=r2; + ns1[b]='-'; + b++; + } + } + ns1[b]='\0'; + ns2[b]='\0'; + A->seq_al[si1]=ns1; + A->seq_al[si2]=ns2; + + + A->len_aln=strlen (ns1); + return A; +} +Alignment *degap_aln (Alignment *A) +{ + //Reomove all the gaps + int a; + for ( a=0; a< A->nseq; a++)ungap (A->seq_al[a]); + return A; +} + +Alignment *ungap_aln_n ( Alignment *A, int p) + { +/*remove all the columns of gap-only within an alignment*/ + int a, b, c; + int t; + int gp; + + if ( A->nseq==0)return A; + + for ( c=0,a=0; a< A->len_aln; a++) + { + for ( t=0,b=0; bnseq; b++) + t+=is_gap(A->seq_al[b][a]); + gp=(t*100)/A->nseq; + if (p>0 && (gp>=p || (t==A->nseq && p==100) || (t && p==1)));//Remove columns containing more than p% gaps + else if (p<0 && (gp<=p || (t==0 && p==-100) ||(t && p==-1)));//remove columns containing less than p% gaps + else + { + for ( b=0; bnseq; b++) + A->seq_al[b][c]=A->seq_al[b][a]; + c++; + } + } + for ( b=0; bnseq; b++)A->seq_al[b][c]='\0'; + A->len_aln=c; + return A; + } + +Alignment *ungap_aln ( Alignment *A) +{ + return ungap_aln_n (A, 100); +} +/* +Alignment *ungap_aln ( Alignment *A) + { + int a, b, c,t; + + for ( c=0,a=0; a< A->len_aln; a++) + { + for ( t=0,b=0; bnseq; b++) + t+=is_gap(A->seq_al[b][a]); + if (t==A->nseq); + else + { + for ( b=0; bnseq; b++) + A->seq_al[b][c]=A->seq_al[b][a]; + c++; + } + } + for ( b=0; bnseq; b++)A->seq_al[b][c]='\0'; + A->len_aln=c; + return A; + + } +*/ + + +Alignment *remove_end (Alignment *A) + { + int a, b, d; + int left, right; + + for (a=0; a< A->len_aln; a++) + { + for ( b=0, d=0; b< A->nseq; b++) + if ( !is_gap(A->seq_al[b][a]))d++; + if ( d>1)break; + } + left=a; + for (a=A->len_aln-1; a>0; a--) + { + for ( b=0, d=0; b< A->nseq; b++) + if ( !is_gap(A->seq_al[b][a]))d++; + if ( d>1)break; + } + right=a; + + return extract_aln(A, left, right+1); + } + +Alignment* condense_aln (Alignment *A) +{ + /* condense complementarz columns: + X- X + -X ....>X + X- X + + */ + int a, b, plen, n,m, r1, r2; + + plen=0; + while ( A->len_aln !=plen) + { + plen=A->len_aln; + for ( a=0; a< A->len_aln-1; a++) + { + for ( n=m=b=0; b< A->nseq; b++) + { + r1=is_gap(A->seq_al[b][a]); + r2=is_gap(A->seq_al[b][a+1]); + n+=(r1 || r2); + m+=r1; + } + + if ( n==A->nseq && m!=A->nseq) + { + for (b=0; b< A->nseq; b++) + { + if (!is_gap(A->seq_al[b][a+1])) + { + A->seq_al[b][a]=A->seq_al[b][a+1]; + A->seq_al[b][a+1]='-'; + } + } + a++; + } + } + } + A=ungap_aln(A); + return A; +} + + + + +void compress_aln ( Alignment *A) + { + + /*remove all the columns of gap-only within an alignment*/ + int a, b, c, d; + + + + for (c=0, a=0; a< A->len_aln; a++) + { + for ( b=0, d=0; b< A->nseq; b++) + if ( A->seq_al[b][a]!='-'){d=1; break;} + if ( d==0); + else + { + for (b=0; b< A->nseq; b++) + A->seq_al[b][c]=A->seq_al[b][a]; + c++; + } + } + A->len_aln=c; + + for ( a=0; a< A->nseq; a++) + A->seq_al[a][c]='\0'; + } + +Alignment *seq_coor2aln ( Sequence *S, Alignment *A, int **coor, int nseq) + { + int a; + char *buf; + + A=realloc_alignment2(A, nseq, return_maxlen ( S->seq, S->nseq)+1); + for ( a=0; a< S->nseq; a++)sprintf ( A->file[a], "%s", S->file[a]); + for ( a=0; a< nseq; a++) + { + sprintf (A->name[a], "Repeat_%d_%d", a, coor[a][0]); + buf=extract_char ( S->seq[coor[a][0]], coor[a][1]-1, coor[a][2]); + sprintf ( A->seq_al[a],"%s", buf); + vfree(buf); + A->order[a][0]=0; + A->order[a][1]=coor[a][1]-1; + } + A->nseq=nseq; + return A; + } + +Alignment *strings2aln (int nseq,...) + { + /*strings2aln(nseq, , , , ....)*/ + va_list ap; + char **list, **list2; + char **name, **name2; + Sequence *S; + Alignment *A; + int a, max; + + va_start(ap, nseq); + list=vcalloc (nseq, sizeof (char*)); + name=vcalloc (nseq, sizeof (char*)); + for ( a=0; a< nseq; a++) + { + name[a]=va_arg(ap,char*); + list[a]=va_arg(ap,char*); + + } + va_end(ap); + + for ( max=0,a=0; a< nseq; a++) + { + max=(strlen (list[a])>max)?strlen(list[a]):max; + } + list2=declare_char (nseq, max+1); + name2=declare_char (nseq, MAXNAMES+1); + + for ( a=0; a< nseq; a++) + { + sprintf ( list2[a], "%s", list[a]); + sprintf ( name2[a], "%s", name[a]); + } + + + S=fill_sequence_struc(nseq,list2,name2); + + free_char (list2, -1); + free_char (name2, -1); + vfree (list); + vfree(name); + A=seq2aln(S,NULL, 1); + return A; + } +Alignment *seq2aln ( Sequence *S, Alignment *A,int rm_gap) + { + int a; + + A=realloc_alignment2(A, S->nseq, S->max_len+1); + for ( a=0; a< S->nseq; a++)sprintf ( A->file[a], "%s", S->file[a]); + A->nseq=S->nseq; + A->max_len=S->max_len; + A->min_len=S->min_len; + + for ( a=0; a< S->nseq; a++) + { + A->order[a][0]=a; + A->order[a][1]=0; + + sprintf ( A->seq_comment[a], "%s", S->seq_comment[a]); + sprintf ( A->aln_comment[a], "%s", S->aln_comment[a]); + + sprintf ( A->name[a], "%s", S->name[a]); + sprintf ( A->seq_al[a], "%s", S->seq[a]); + + ungap ( A->seq_al[a]); + A->len[a]=strlen ( A->seq_al[a]); + + if ( rm_gap==0 || rm_gap==NO_PAD)sprintf ( A->seq_al[a], "%s", S->seq[a]); + + } + if (rm_gap!=NO_PAD)padd_aln (A); + A->S=S; + return A; + } + +Alignment *padd_aln ( Alignment *A) +{ + A->seq_al=padd_string (A->seq_al, A->nseq, '-'); + A->len_aln=strlen (A->seq_al[0]); + return A; +} + +char **padd_string ( char **string, int n,char pad) +{ + /*Pads a the strings so that they all have the same length*/ + + int max_len, a; + char *buf; + + max_len=get_longest_string (string,n, NULL, NULL); + for (a=0; anseq; a++) sprintf (A->name[a], "tmpname_%d", seqindex++); + + R=copy_aln (A, NULL); + for (c=0, a=0; a< A->len_aln; a++) + { + if ( is_gap (A->seq_al[0][a])); + else + { + for ( b=0; bnseq; b++) + R->seq_al[b][c]=A->seq_al[b][a]; + c++; + } + } + for ( a=0; a< A->nseq; a++)R->seq_al[a][c]='\0'; + R->len_aln=c; + R->S=aln2seq (R); + + free_aln (S); + free_aln (P); + free_aln (A); + + return R; +} + +Alignment * add_align_seq2aln ( Alignment *A, char *seq, char *seq_name) + { + if ( !A) + { + A=declare_aln (NULL); + A=realloc_aln2 ( A, 1, strlen (seq)+1); + A->nseq=0; + sprintf ( A->name[A->nseq], "%s", seq_name); + sprintf ( A->seq_al[A->nseq], "%s", seq); + A->nseq++; + + } + else if ( strlen (seq)!=A->len_aln) + { + fprintf ( stderr, "\nError: Attempt to stack incompatible aln and aligned sequence[FATAL]\n"); + myexit (EXIT_FAILURE); + A=NULL; + } + else + { + + A=realloc_aln2 ( A, A->nseq+1, A->len_aln+1); + sprintf ( A->name[A->nseq], "%s", seq_name); + sprintf ( A->seq_al[A->nseq], "%s", seq); + A->nseq++; + } + return A; + } + + +Alignment *aln2number (Alignment *A) + { + A->seq_al=char_array2number(A->seq_al, A->nseq); + return A; + } +Sequence *seq2number (Sequence *A) + { + A->seq=char_array2number(A->seq, A->nseq); + return A; + } + +Sequence * aln2seq (Alignment *A) +{ + return aln2seq_main(A, RM_GAP); +} +Sequence * aln2seq_main (Alignment *A, int mode) + { + Sequence *LS; + int a; + int maxlen; + + if ( !A) return NULL; + else if ( A->nseq==0)return NULL; + for (maxlen=0,a=0; anseq; a++)maxlen=MAX(maxlen, strlen (A->seq_al[a])); + + + LS=declare_sequence ( maxlen+1, maxlen+1, A->nseq); + LS->nseq=A->nseq; + for ( a=0; a< LS->nseq; a++) + { + sprintf (LS->file[a],"%s", A->file[a]); + + sprintf ( LS->seq[a], "%s", A->seq_al[a]); + + if (mode==RM_GAP)ungap ( LS->seq[a]); + + LS->len[a]=strlen ( LS->seq[a]); + + sprintf ( LS->seq_comment[a], "%s",A->seq_comment[a]); + sprintf ( LS->aln_comment[a], "%s",A->aln_comment[a]); + sprintf ( LS->name[a], "%s", A->name[a]); + } + return LS; + } + +Sequence *keep_residues_in_seq ( Sequence *S, char *list, char replacement) +{ + Alignment *A=NULL; + int a; + + A=seq2aln (S, A,1); + A=keep_residues_in_aln ( A, list, replacement); + for ( a=0; a< A->nseq; a++) + { + ungap (A->seq_al[a]); + sprintf ( S->seq[a], "%s", A->seq_al[a]); + } + free_aln (A); + return S; +} + + +Alignment *aln2short_aln ( Alignment *A, char *list, char *new, int spacer) +{ + int a, b, r, cl, l; + char *buf; + + for ( a=0; a< A->nseq; a++) + { + buf=vcalloc ( strlen (A->seq_al[a])+1, sizeof (char)); + + for (l=0,cl=0, b=0; b< A->len_aln; b++) + { + r=A->seq_al[a][b]; + if ( is_gap(r)); + else if ( is_in_set (r, list)) + { + if (cl){cl=0; buf[l++]=new[0];} + buf[l++]=r; + } + else + { + if ( cl==spacer){buf[l++]=new[0];cl=0;} + cl++; + } + + } + + buf[l]='\0'; + sprintf (A->seq_al[a], "%s", buf); + vfree (buf); + } + return A; +} + +Alignment *keep_residues_in_aln ( Alignment *A, char *list, char replacement) +{ + return filter_keep_residues_in_aln (A,NULL, 0, -1, list, replacement); +} +Alignment *filter_keep_residues_in_aln ( Alignment *A,Alignment *ST, int use_cons, int value, char *list, char replacement) +{ + char **sl; + int n, a; + + n=strlen (list); + sl=declare_char (n+1, 256); + for (a=0; a< n; a++) + sprintf ( sl[a], "%c%c", list[a], list[a]); + sprintf ( sl[a],"#%c", replacement); + A=filter_aln_convert (A, ST,use_cons,value, n+1, sl); + free_char (sl, -1); + return A; +} + + +Alignment *filter_convert_aln ( Alignment *A,Alignment *ST, int use_cons, int value, int n, ...) +{ + va_list ap; + char **sl; + int a; + va_start (ap, n); + sl=vcalloc ( n,sizeof(char*)); + for ( a=0; a< n; a++) + { + sl[a]=va_arg(ap, char * ); + } + va_end(ap); + A=filter_aln_convert (A,ST,use_cons,value, n,sl); + vfree(sl); + return A; +} + +Alignment * filter_aln ( Alignment *A, Alignment *ST, int value) + { + return filter_aln_convert (A, ST,0,value,DELETE, NULL); + } +Alignment * filter_aln_switchcase ( Alignment *A, Alignment *ST,int use_cons, int value) + { + return filter_aln_convert (A, ST,0,value,SWITCHCASE, NULL); + } +Alignment * filter_aln_upper_lower ( Alignment *A, Alignment *ST,int use_cons, int value) + { + return filter_aln_convert (A, ST,use_cons,value, LOWER, NULL); + } +Alignment * filter_aln_lower_upper ( Alignment *A, Alignment *ST,int use_cons, int value) + { + + return filter_aln_convert (A, ST,use_cons,value, UPPER, NULL); + } +Alignment * STseq2STaln ( Alignment *A, Alignment *ST) + { + int a, i=0; + + if (ST && ST->len_aln !=A->len_aln) + { + Sequence *S_T, *S_A; + + S_T=aln2seq (ST); + S_A=aln2seq (A); + + for (a=0; a< A->nseq; a++) + { + i=name_is_in_list (A->name[a], S_T->name,S_T->nseq, 100); + if (i!=-1) + { + char *s1, *s2; + s1=(S_T)->seq[i];ungap(s1); + s2=(S_A)->seq[a];ungap(s2); + + if ( strlen (s1)!=strlen(s2)) + { + fprintf ( stderr, "%s\n%s\n", s1, s2); + printf_exit (EXIT_FAILURE, stderr, "ERROR: Sequence %s has different length in the alignment and in the structure Alignment [FATAL:%s]\n", A->name[a], PROGRAM); + } + } + } + ST=copy_aln (A, ST); + thread_seq_struc2aln (ST,S_T); + } + + return ST; + } +Alignment * merge_annotation ( Alignment *A, Alignment *ST, char *seq) +{ + int s, a, b; + + ST=STseq2STaln (A, ST); + if ( seq==NULL)s=0; + else + s=name_is_in_list ( seq, A->name, A->nseq, 100); + + if (s==-1) + { + add_warning ( stderr, "\nERROR: %s is not in your MSA [FATAL: %s]", PROGRAM); + myexit (EXIT_FAILURE); + } + + for (a=0; alen_aln; a++) + { + int t, r; + + t=A->seq_al[s][a]; + if (is_gap (t))continue; + for (b=0; bnseq; b++) + { + t=A->seq_al[s][a]; + r=ST->seq_al[b][a]; + if ( isdigit (r)) + { + if (!isdigit(t) || (isdigit (t) && tseq_al[s][a]=r; + } + } + } + return A; +} + + + +Alignment * filter_aln_convert ( Alignment *A, Alignment *ST,int use_cons, int value, int n_symbol,char **symbol_list) + { + int a, b, c; + int st; + int cons=0; + + + ST=STseq2STaln (A, ST); + if ( ST && use_cons) + { + cons=name_is_in_list ("con", ST->name,ST->nseq+1, 100); + if ( cons==-1)cons=name_is_in_list ("cons", ST->name,ST->nseq+1, 100); + if ( cons==-1)cons=name_is_in_list ("Cons", ST->name,ST->nseq+1, 100); + if ( cons==-1) + { + use_cons=0; + fprintf (stderr, "WARNING: Could Not Use the Consensus Sequence [WARNING:%s]\n", PROGRAM); + } + } + + A->residue_case=KEEP_CASE; + for ( a=0; a< A->nseq; a++) + { + if(value!=10 && ST && !use_cons) + { + c=name_is_in_list (A->name[a], ST->name, ST->nseq,100); + if (c==-1)st=11; + } + + for ( b=0; b< A->len_aln; b++) + { + if ( value==10 || !ST)st=11; + else if ( ST && use_cons) + { + st=(isdigit(ST->seq_al[cons][b]))?ST->seq_al[cons][b]-'0':ST->seq_al[cons][b]; + } + else st=(isdigit(ST->seq_al[c][b]))?ST->seq_al[c][b]-'0':ST->seq_al[c][b]; + + + if ( st==value || value==-1 || st==NO_COLOR_RESIDUE) + { + if ( n_symbol==UPPER && !symbol_list)A->seq_al[a][b]=toupper (A->seq_al[a][b]); + else if ( n_symbol==LOWER && !symbol_list)A->seq_al[a][b]=tolower (A->seq_al[a][b]); + else if ( n_symbol==SWITCHCASE && !symbol_list) + { + if ( !isalpha(A->seq_al[a][b])); + else if (isupper (A->seq_al[a][b]))A->seq_al[a][b]=tolower (A->seq_al[a][b]); + else if (islower (A->seq_al[a][b]))A->seq_al[a][b]=toupper (A->seq_al[a][b]); + } + else if ( n_symbol==DELETE && !symbol_list)A->seq_al[a][b]='-'; + else + { + A->seq_al[a][b]=convert(A->seq_al[a][b],n_symbol,symbol_list); + } + } + + } + } + return A; + } + + +char ** sar_aln2motif (Alignment *A, Alignment *B, int *pos, int c); +char ** sar_aln2motif (Alignment *A, Alignment *B, int *pos, int c) +{ + static Alignment *I; + static Alignment *O; + int a, b, o, i; + + float tp,tn,fp,fn,best, sp, sn, sen2; + float best_pred=-1; + int best_motif=0; + + + int n1; + static char ***alp; + static int *alp_size; + + char ***motif_list; + int n; + + + if (!I) + { + I=copy_aln(A, NULL); + O=copy_aln(A, NULL); + } + + + + I->nseq=O->nseq=I->len_aln=O->len_aln=0; + for (a=0; alen_aln; a++) + { + if (pos[a]) + { + for (i=o=0,b=0; bnseq; b++) + { + + if ( is_gap(A->seq_al[b][a]))return 0; + if (B->seq_al[b][c]=='I')I->seq_al[i++][I->len_aln]=A->seq_al[b][a]; + else O->seq_al[o++][O->len_aln]=A->seq_al[b][a]; + } + I->len_aln++; + O->len_aln++; + } + } + + if (O->len_aln==0 || I->len_aln==0) return 0; + O->nseq=o; + I->nseq=i; + for (a=0; aseq_al[a][O->len_aln]='\0'; + for (a=0; aseq_al[a][I->len_aln]='\0'; + + alp=vcalloc ( sizeof (char**), I->len_aln); + alp_size= vcalloc ( I->len_aln, sizeof (int)); + for (a=0; alen_aln; a++) + { + char *col; + alp[a]=string2alphabet ( (col=aln_column2string (I,a)),2, &alp_size[a]); + vfree (col); + } + + + + motif_list=generate_array_string_list (I->len_aln, alp, alp_size, &n, NULL, OVERLAP); + best_pred=best_motif=0; + for (a=0; anseq; b++) + { + if (match_motif (I->seq_al[b], motif_list[a]))tp++; + else fn++; + } + for (b=0; bnseq; b++) + { + if (match_motif (O->seq_al[b], motif_list[a]))fp++; + else tn++; + } + rates2sensitivity (tp, tn, fp, fn, &sp, &sn, &sen2, &best); + + if (best> best_pred) + { + best_pred=best; + best_motif=a; + } + } + + output_Alignment_without_header ( I, stdout); + fprintf ( stdout, "\n"); + output_Alignment_without_header ( O, stdout); + + + fprintf ( stdout, "\nMotifCompound %d pred: %.2f motif: ", c, best_pred); + for (n1=0, a=0; alen_aln; a++) + { + char *m; + int l; + m=motif_list[best_motif][a]; + fprintf ( stdout, "[%s]-", m); + l=strlen (m); + n1+=(l==1 && !strm ("*",m) )?1:0; + } + fprintf (stdout, "SCORE: %d", n1); + + for (a=0; alen_aln) + { + fprintf ( stdout, "\n W:"); + for (a=0; alen_aln; a++)fprintf ( stdout, "%d", array[a]); + fprintf ( stdout, " %.4f",(float)sar_aln2r(A,B,array,0)); + return; + } + else + { + for ( a=0; alen_aln=w; + for ( a=0; alen_aln-w;a++) + { + for (b=0; bnseq; b++) + { + for (c=0; cseq_al[b][c]=B->seq_al[b][a+c]; + } + S->seq_al[b][c]='\0'; + } + + s=search_best_combo (A, S); + fprintf ( stdout,"\nP: XXXX \nP: XXXXX A=%d / %d", a, B->len_aln); + + } + +} + +float search_best_combo(Alignment *A, Alignment *B) +{ + int a, b, c, d, best_pos,nl, max; + float best_score, score; + int *list, *pos; + + int w; + int combo_mode=1; //1: greedy 2: consider all thw w combinations; + FILE *fp2; + static int **M; + max=2; + int delta=0; + w=1; + + pos=vcalloc ( A->len_aln, sizeof (int)); + list=vcalloc (A->len_aln, sizeof (int)); + nl=0; + + if ( combo_mode==1) + { + for (a=0; a< max; a++) + { + for (best_score=-9999,best_pos=0,b=0; b< A->len_aln-w; b++) + { + for (c=0; cbest_score) + { + best_score=score; + best_pos=b; + } + for (c=0; clen_aln-1, 1,NULL, tmpf); + printf_system ( "cp %s testfile", tmpf); + buf=vcalloc ( 1000, sizeof (char)); + fp=vfopen (tmpf, "r"); + best_score=-99999; + + n_preset=0; + preset=vcalloc (A->len_aln, sizeof (int)); + preset[n_preset++]=353; + preset[n_preset++]=361; + //preset[n_preset++]=365; + //preset[n_preset++]=187; + //preset[n_preset++]=397; + //preset[n_preset++]=492; + + + while ( (buf=vfgets ( buf, fp))!=NULL) + { + + array=string2num_list (buf); + + for (a=1; a<=max; a++) + { + pos[array[a]]=1; + } + for ( a=0; abest_score) + { + best_score=score; + fprintf ( stdout, "\n"); + for (a=0; alen_aln; c++) + { + sar_aln2motif (A,B,pos, c); + + } + myexit (EXIT_FAILURE); + HERE ("***************"); + fp2=vfopen ("aln.aln", "w"); + for (a=0; anseq; a++) + { + fprintf (fp2, ">%s\n", A->name[a]); + for ( b=0; bseq_al[a][list[b]]); + fprintf ( fp2, "\n"); + } + vfclose (fp2); + HERE ("Output aln.aln"); + if (1) + { + float tp=0, tn=0, fp=0, fn=0, pp2=0,pp=0, sn,sn2, sp; + int **result,**result2,**compound_score, *ref_score,n2,n, s, p, c; + Alignment *AI, *AO; + int simI, simO; + + compound_score=declare_int (B->len_aln, 2); + ref_score=vcalloc (nl, sizeof (int)); + + result=declare_int (B->len_aln*A->nseq*A->nseq, 2); + result2=declare_int (B->len_aln*A->nseq*A->nseq, 2); + + for (n2=c=0; c< B->len_aln; c++) + { + + int sar1, sar2; + pp=tp=tn=fp=fn=0; + if (!M)M=read_matrice ("blosum62mt"); + for (n=0,a=0; anseq-1; a++) + { + for (b=a+1; bnseq;b++) + { + for (s=0,p=0; pseq_al[a][list[p]]; + r2=A->seq_al[b][list[p]]; + if ( !is_gap (r1) && !is_gap(r2))s+=M[r1-'A'][r2-'A']; + } + result2[n2][0]=result[n][0]=s; + + sar1=B->seq_al[a][c];sar2=B->seq_al[b][c]; + + if (sar1=='I' && sar1==sar2) + { + result2[n2][1]=result[n][1]=1; + pp++;pp2++; + n++;n2++; + } + else if ( sar1==sar2 && sar1=='O') + { + ; + } + else + { + result2[n2][1]=result[n][1]=0; + n++;n2++; + } + //else if ( s1==s2=='O')result[n][1]=-1; + } + } + + if (pp==0)continue; + sort_int_inv (result, 2, 0, 0, n-1); + + + for (tp=0,a=0; alen_aln-1); + + fp2=vfopen ("compound.fasta", "w"); + for (d=0; dnseq; a++) + for (b=0; bnseq; b++) + { + r1= A->seq_al[b][list[d]]; + r2= A->seq_al[b][list[d]]; + if (is_gap(r1) || is_gap(r2))continue; + else + { + ref_score[d]+=M[r1-'A'][r2-'A']; + n++; + } + } + ref_score[d]/=n; + } + AO=copy_aln (A, NULL); + AI=copy_aln (A,NULL); + AO->len_aln=AI->len_aln=nl; + for (a=0; anseq; a++)AO->seq_al[a][nl]=AI->seq_al[a][nl]='\0'; + + for (a=0; alen_aln; a++) + { + fprintf (stdout, "\n>%4d %4d ", compound_score[a][0], compound_score[a][1]); + for (b=0; bnseq; b++) fprintf (stdout, "%c", B->seq_al[b][compound_score[a][0]]); + fprintf ( stdout, "\n"); + + for (AI->nseq=0,b=0; bnseq; b++) + { + if (B->seq_al[b][compound_score[a][0]]=='O')continue; + fprintf ( stdout, "\n\t"); + for (c=0; cseq_al[b][list[c]]); + AI->seq_al[AI->nseq][c]=A->seq_al[b][list[c]]; + } + AI->nseq++; + } + fprintf ( stdout, "\n\t"); + for (d=0; dnseq; b++) + { + if (B->seq_al[b][compound_score[a][0]]=='O')continue; + for (c=0; cnseq; c++) + { + if (B->seq_al[c][compound_score[a][0]]=='O')continue; + { + int r1, r2; + + r1= A->seq_al[b][list[d]]; + r2= A->seq_al[b][list[d]]; + if (is_gap(r1) || is_gap(r2))continue; + else score+=M[r1-'A'][r2-'A']; + n++; + } + } + } + score/=n; + if ((float)score/(float)ref_score[d]>1.2)fprintf ( stdout, "*"); + else fprintf ( stdout, " "); + } + for (AO->nseq=0,b=0; bnseq; b++) + { + if (B->seq_al[b][compound_score[a][0]]=='I')continue; + fprintf ( stdout, "\n\t"); + for (c=0; cseq_al[AO->nseq][c]=A->seq_al[b][list[c]]; + fprintf ( stdout, "%c", A->seq_al[b][list[c]]); + } + AO->nseq++; + } + simI=aln2sim (AI, "blosum62mt"); simO=aln2sim (AO, "blosum62mt"); + fprintf ( stdout, "\nDELTA: I: %d O: %d %d",simI,simO, simI-simO); + delta+=simI-simO; + } + + for ( a=0; anseq; a++) + { + + fprintf ( fp2, ">%s\n", B->name[a]); + for (b=0; blen_aln/2; b++) + fprintf ( fp2, "%c", B->seq_al[a][compound_score[b][0]]); + fprintf (fp2, "\n"); + } + vfclose (fp2); + HERE ("OUTPUT compound.fasta"); + result=result2; + n=n2; + pp=pp2; + + sort_int_inv (result, 2, 0, 0, n-1); + + + for (tp=0,a=0; anseq; b++) + C->seq_al[b][a]=A->seq_al[b][list[a]]; + C->len_aln=nl; + array=vcalloc (C->len_aln, sizeof (int)); + explore_weight_matrix (C, B, 6,0, array); + */ + + return best_score; +} + + +void count_misc (Alignment *A, Alignment *B) +{ + int **done, a, b, c, d, e,f, g, *list, n, score; + double **slist, *r; + int *pos; + int w=1; + + search_best_combo (A,B); + myexit (EXIT_FAILURE); + pos=vcalloc (A->len_aln+1, sizeof (int)); + /* + pos[354]=1; + pos[362]=1; + pos[366]=1; + pos[398]=1; + pos[476]=1; + + + fprintf ( stdout, "\nR: %3f " ,(float)sar_aln2r(A,B,pos,1));myexit (EXIT_FAILURE); + */ + for (a=0; a< A->len_aln-w; a++) + { + for (c=0; clen_aln-1; a++) + { + pos[a-w]=0; + pos[a]=1; + fprintf ( stdout, "\nP: %3d W:2 R: %3f ",a, (float)sar_aln2r(A,B,pos,0)); + } + + myexit (EXIT_FAILURE); + pos[2]=1; + pos[3]=1; + + + + explore_weight_matrix (A, B,3, 0,pos); + myexit (EXIT_FAILURE); + + for (a=0; alen_aln; a++) + for ( b=0; blen_aln; b++) + for (c=0; clen_aln; c++) + for (d=0; dlen_aln; d++) + for (f=0; flen_aln; f++) + for (g=0; glen_aln; g++) + { + e=0; + pos[e++]=a; + pos[e++]=b; + pos[e++]=c; + pos[e++]=d; + pos[e++]=f; + pos[e++]=g; + pos[e++]=-1; + fprintf ( stdout, "\n%d %d %d %d %d %d %.3f", a, b,c,d,f, g, sar_aln2r(A,B, pos,0)); + + } + + myexit (EXIT_FAILURE); + + + slist=declare_double (A->nseq*A->nseq*10, 2); + done=declare_int (256, 256); + list=vcalloc ( A->nseq, sizeof (int)); + + for (a=0; alen_aln-1; a++) + { + for (b =0; b<256; b++)for (c=0; c<256; c++)done[b][c]=0; + + for (b=0; bnseq-1; b++) + { + int r1, r2; + r1=A->seq_al[b][a]; + r2=A->seq_al[b][a+1]; + if (done[r1][r2])continue; + n=0; + done[r1][r2]=1; + list[n++]=b; + fprintf ( stdout, "\n%3d %c%c: %s ",a+1, r1, r2, A->name[b]); + for ( c=b+1; cnseq; c++) + { + if (r1==A->seq_al[c][a] && r2==A->seq_al[c][a+1]) + { + fprintf ( stdout, "%s ", A->name[c]); + list[n++]=c; + } + + } + if (B && n>1) + { + for (e=0,score=0,c=0; cseq_al[list[c]], B->seq_al[list[d]]); + fprintf ( stdout, " Score=%d", score/e); + } + } + } + for (score=0,e=0,a=0; anseq-1; a++) + for (b=a+1; bnseq; b++,e++) + { + score+=get_sar_sim2(B->seq_al[a], B->seq_al[b]); + } + fprintf (stdout,"AVG=%d", score/e); + for (n=0,a=0; a< A->nseq-1; a++) + { + static int **M; + int sim; + if (!M)M=read_matrice ("blosum62mt"); + + + for (b=a+1; bnseq; b++) + { + int n11, n01, n10, n00, n1; + + for (sim=d=0;dlen_aln; d++) + { + int r1, r2; + r1=A->seq_al[a][d]; + r2=A->seq_al[b][d]; + sim+=(r1==r2)?1:0; + //sim +=(M[r1-'A'][r2-'A']>0)?1:0; + } + + sim=(100*sim)/(A->len_aln);//+rand()%10; + for (n1=n00=n11=n10=n01=score=0, d=0; dlen_aln; d++) + { + int r1, r2; + r1=B->seq_al[a][d]; + r2=B->seq_al[b][d]; + n11+=(r1=='I' && r2=='I'); + n00+=(r1=='O' && r2=='O'); + n10+=(r1=='I' && r2=='0'); + n01+=(r1=='O' && r2=='I'); + n1+=(r1=='I' || r2=='I'); + } + score =((n11+n00)*100)/B->len_aln; + + //score=get_sar_sim2(B->seq_al[a], B->seq_al[b]); + + fprintf ( stdout, "\nSIM: %d SC: %d", sim, score); + slist[n][0]=(double)sim; + slist[n][1]=(double)score; + n++; + } + } + r=return_r(slist, n); + fprintf ( stdout, "\nR= %.4f", (float)r[0]); + myexit (EXIT_FAILURE); +} + +int aln2ngap ( Alignment *A) +{ + int ngap=0, a, b; + for (a=0; a< A->len_aln; a++) + for (b=0; bnseq; b++) ngap+=is_gap (A->seq_al[b][a]); + return ngap; +} +int * count_in_aln ( Alignment *A, Alignment *ST, int value, int n_symbol,char **symbol_list, int *table) + { + int a, b, c=0, d; + int st; + + if (!table)table=vcalloc (n_symbol, sizeof (int)); + + A->residue_case=KEEP_CASE; + for ( a=0; a< A->nseq; a++) + { + if(value!=10 && ST)for ( c=0; c< ST->nseq; c++)if ( strm(ST->name[c], A->name[a]))break; + for ( b=0; b< A->len_aln; b++) + { + if ( value==10 || !ST)st=11; + else st=(isdigit(ST->seq_al[c][b]))?ST->seq_al[c][b]-'0':ST->seq_al[c][b]; + if ( st==value || value==-1) + { + for ( d=0; dseq_al[a][b], symbol_list[d]); + } + } + } + return table; + } + +char *dna_aln2cons_seq ( Alignment *A) + { + int a, b, best; + static int **column_count; + static int **old_tot_count; + static int **new_tot_count; + static char *string1, *string2; + int **count_buf; + char r1, r2,*seq; + int NA=0, NG=1, NC=2, NT=3, IGAP=4; + static int MAX_EST_SIZE=10000; + static int size_increment=1000; + static int first; + int overlap=0, best_overlap=0; + + + seq=vcalloc ( A->len_aln+1, sizeof (char)); + + if (!column_count ) + { + column_count=vcalloc(MAX_EST_SIZE, sizeof (int*)); + for ( a=0; a< MAX_EST_SIZE; a++) + column_count[a]=vcalloc (5, sizeof (int)); + + old_tot_count=vcalloc(MAX_EST_SIZE, sizeof (int*)); + new_tot_count=vcalloc(MAX_EST_SIZE, sizeof (int*)); + A->P=declare_profile( "agct-",MAX_EST_SIZE); + string1=vcalloc (MAX_EST_SIZE, sizeof (char)); + string2=vcalloc (MAX_EST_SIZE, sizeof (char)); + } + else if (A->len_aln>MAX_EST_SIZE) + { + if ( column_count) + { + for ( a=0; a< MAX_EST_SIZE; a++) + vfree(column_count[a]); + vfree(column_count); + vfree(old_tot_count); + vfree(new_tot_count); + vfree(string1); + vfree(string2); + } + + column_count=vcalloc(MAX_EST_SIZE+ size_increment, sizeof (int*)); + for ( a=0; a< MAX_EST_SIZE+ size_increment; a++) + column_count[a]=vcalloc (5, sizeof (int)); + + old_tot_count=vcalloc(MAX_EST_SIZE+ size_increment, sizeof (int*)); + new_tot_count=vcalloc(MAX_EST_SIZE+ size_increment, sizeof (int*)); + + for (a=0; a< MAX_EST_SIZE; a++) + { + old_tot_count[a]=*(column_count++); + for ( b=0; b<5; b++)old_tot_count[a][b]=(A->P)->count[b][a]; + } + free_int ( (A->P)->count, -1); + + (A->P)->count=declare_int (5, MAX_EST_SIZE+ size_increment); + (A->P)->max_len=MAX_EST_SIZE+ size_increment; + MAX_EST_SIZE+= size_increment; + string1=vcalloc (MAX_EST_SIZE, sizeof (char)); + string2=vcalloc (MAX_EST_SIZE, sizeof (char)); + } + + + sprintf ( string1, "%s",A->seq_al[0]); + sprintf ( string2, "%s",A->seq_al[1]); + + + string1=mark_internal_gaps(string1,'.'); + string2=mark_internal_gaps(string2,'.'); + + + + for (b=0,a=0; a< A->len_aln; a++) + { + r1=string1[a]; + r2=string2[a]; + + if ( r1==r2) + { + overlap++; + } + else + { + best_overlap=MAX(overlap, best_overlap); + overlap=0; + } + + + if (!is_gap(r1) && first==1)new_tot_count[a]=old_tot_count[b++]; + else if (is_gap(r1) || first==0){new_tot_count[a]=*column_count;column_count++;}; + + if ( first==0) + { + if(r1=='a') new_tot_count[a][NA]++; + else if ( r1=='g')new_tot_count[a][NG]++; + else if ( r1=='c')new_tot_count[a][NC]++; + else if ( r1=='t')new_tot_count[a][NT]++; + else if (is_gap(r1)); + else + { + new_tot_count[a][NA]++; + new_tot_count[a][NG]++; + new_tot_count[a][NC]++; + new_tot_count[a][NT]++; + } + } + if ( a> 0 && alen_aln-1 && r1=='.') + { + new_tot_count[a][IGAP]+=((new_tot_count[a-1][NA]+new_tot_count[a-1][NG]+new_tot_count[a-1][NC]+new_tot_count[a-1][NT])); + } + + + if(r2=='a') new_tot_count[a][NA]++; + else if ( r2=='g')new_tot_count[a][NG]++; + else if ( r2=='c')new_tot_count[a][NC]++; + else if ( r2=='t')new_tot_count[a][NT]++; + else if ( r2=='.')new_tot_count[a][IGAP]++; + else if ( r2=='-'); + else + { + new_tot_count[a][NA]++; + new_tot_count[a][NG]++; + new_tot_count[a][NC]++; + new_tot_count[a][NT]++; + } + (A->P)->count[0][a]=new_tot_count[a][NA]; + (A->P)->count[1][a]=new_tot_count[a][NG]; + (A->P)->count[2][a]=new_tot_count[a][NC]; + (A->P)->count[3][a]=new_tot_count[a][NT]; + (A->P)->count[4][a]=new_tot_count[a][IGAP]; + + best_int(4,1, &best,new_tot_count[a][NA], new_tot_count[a][NG],new_tot_count[a][NC],new_tot_count[a][NT]); + if( best==0) seq[a]='a'; + else if ( best==1)seq[a]='g'; + else if ( best==2)seq[a]='c'; + else if ( best==3)seq[a]='t'; + } + + first=1; + + seq[a]='\0'; + fprintf ( stderr, "[Best Overlap: %d Residues]", best_overlap); + count_buf=old_tot_count; + old_tot_count=new_tot_count; + new_tot_count=count_buf; + + return seq; + + } + +char *aln2cons_maj ( Alignment *A, int ns, int *ls, int n_groups, char **group_list) + { + char *seq; + int a, b; + int len; + int clean_ls=0; + static int *aa; + + if ( !aa) aa=vcalloc (1000, sizeof (int)); + + len=strlen (A->seq_al[ls[0]]); + seq=vcalloc (len+1, sizeof (char)); + + if ( ns==0) + { + ns=A->nseq; + ls=vcalloc ( A->nseq, sizeof (int)); + for ( a=0; a< A->nseq; a++)ls[a]=a; + clean_ls=1; + } + + for ( a=0; aseq_al[ls[b]][a]); + aa[r]++; + if (!is_gap(r) && aa[r]>best_s) + { + best_s=aa[r]; + best_aa=r; + } + seq[a]=best_aa; + } + for (best_s=0, best_aa=0,b=0; b< ns; b++) + { + aa[tolower(A->seq_al[ls[b]][a])]=0; + } + } + if ( clean_ls)vfree(ls); + seq[a]='\0'; + + return seq; + } + +char *aln2cons_seq ( Alignment *A, int ns, int *ls, int n_groups, char **group_list) + { + char *seq; + int a, b, c; + int best_group=0; + int aa_group=0; + int *group; + int len; + int clean_ls=0; + + len=strlen (A->seq_al[ls[0]]); + seq=vcalloc (len+1, sizeof (char)); + + if ( ns==0) + { + ns=A->nseq; + ls=vcalloc ( A->nseq, sizeof (int)); + for ( a=0; a< A->nseq; a++)ls[a]=a; + clean_ls=1; + } + + + if ( !group_list) + { + group_list=declare_char ( 26, 2); + for ( a=0; a<26; a++)group_list[a][0]=a+'a'; + n_groups=26; + aa_group=1; + } + + + for ( a=0; aseq_al[ls[b]][a])) + { + for (c=0; c< n_groups; c++) + if ( is_in_set (tolower(A->seq_al[ls[b]][a]), group_list[c])) + {group[c]++; + best_group=(group[c]>group[best_group])?c:best_group; + } + } + seq[a]=group_list[best_group][0]; + } + vfree (group); + } + seq[a]='\0'; + if ( aa_group) free_char (group_list, -1); + + if ( clean_ls)vfree(ls); + + return seq; + } + +Alignment *aln2conservation ( Alignment *A, int threshold,char *seq) +{ + int a, b, c, d, i, c1, c2; + int *pos; + float *eval; + float tot=0; + float tn=0; + int **sim; + int w=0; + + pos =vcalloc (A->len_aln, sizeof (int)); + eval=vcalloc (A->len_aln, sizeof (int)); + sim=aln2sim_mat (A, "idmat"); + if (seq)i=name_is_in_list (seq, A->name, A->nseq, 100); + else i=0; + + if ( i==-1) {HERE ("%s is an unknown:sequence [FATAL]"); myexit (EXIT_FAILURE);} + + for (a=0; alen_aln; a++) + { + double s; + int e; + for (c=0,e=a-w; e<=a+w; e++) + { + if (e<0 || e==A->len_aln)continue; + c1=toupper (A->seq_al[i][e]); + for (b=0; bnseq; b++) + { + c2=toupper (A->seq_al[b][a]); + if (c1==c2) + { + c++; + s=(double)((double)sim[i][b]/(double)(100)); + + } + else + { + s=(double)(((double)100-(double)sim[i][b])/(double)(100)); + } + eval[a]+=(s==0)?0:log(s); + } + } + pos[a]=(c*100)/A->nseq; + if (!is_gap(c1)){tot+=pos[a]; tn++;} + + if (pos[a]>=threshold)A->seq_al[i][a]=toupper (A->seq_al[i][a]); + else A->seq_al[i][a]=tolower (A->seq_al[i][a]); + } + fprintf (stdout, ">%s %s [i=%d]\n%s\n", A->name[i],A->aln_comment[i],i, A->seq_al[i]); + tot=(tn>0)?(float)tot/(float)tn:0; + + for (d=0,a=0; alen_aln; a++) + { + fprintf (stdout, "# %c %4d", A->seq_al[i][a],pos[a]); + + + if ( !is_gap (A->seq_al[i][a])) + { + fprintf (stdout, " LogOdd: %6.2f ", (tot==0 || pos[a]==0)?0:(float)log((float)pos[a]/tot)); + fprintf ( stdout, " Pos: %5d E-Val: %9.2f", ++d, eval[a]/(A->nseq)); + } + fprintf ( stdout, "\n"); + } + fprintf ( stdout, "#average conservation: %.2f", tot); + myexit (EXIT_SUCCESS); +} +char *aln2cons_seq_mat ( Alignment *A, char *mat_name) +{ + return sub_aln2cons_seq_mat (A, A->nseq, NULL, mat_name); +} +char *sub_aln2cons_seq_mat2 ( Alignment *A,int ns, char **ls, char *mat_name) +{ + char *cons; + int *list; + list=name_array2index_array(ls, ns, A->name, A->nseq); + cons=sub_aln2cons_seq_mat ( A,ns, list, mat_name); + vfree (list); + return cons; +} + +char *sub_aln2cons_seq_mat ( Alignment *A,int ns, int *ls, char *mat_name) +{ + int a, b, c, s; + char *seq, r1, r2; + int **mat; + int score=0, best_score=0, best_r=0; + int len; + int naa; + + mat=read_matrice (mat_name); + len=strlen ( A->seq_al[(ls==NULL)?0:ls[0]]); + seq=vcalloc (len+1, sizeof (char)); + for ( a=0; aseq_al[s][a]))continue; + else + { + naa++; + r2=A->seq_al[s][a]; + score+=mat[r1-'A'][r2-'A']; + } + } + if (naa==0)best_r='-'; + if ( b==0 || score>best_score){best_score=score; best_r=r1;} + } + seq[a]=best_r; + } + free_int (mat, -1); + return seq; +} + +int seq_list2in_file ( TC_method *M, Sequence *S, char *list, char *file) +{ + X_template *T=NULL; + + if ( !S)return 0; + else + { + int t; + t=tolower(M->seq_type[0]); + + if ( t=='s') + { + return seq_list2fasta_file ( S, list, file, M->out_mode); + + } + else + { + FILE *fp, *fp2; + int a, n, s, c; + int *slist; + + + + fp=vfopen ( file, "w"); + slist=string2num_list (list); + n=slist[0]; + + if (strlen (M->seq_type) >1) + { + add_warning( stderr, "\nERROR: Mixed seq_type not supported for external methods\n[FATAL:%s]", PROGRAM); + } + + for ( a=2; aT[s])->P; + else if (t=='r')T=(S->T[s])->R; + else if (t=='g')T=(S->T[s])->G; + + if (!T && t=='r') + { + fprintf ( fp, ">%s\n%s%s", S->name[s], S->seq[s], LINE_SEPARATOR); + } + else if ( T && T->template_file && T->template_file[0]) + { + fp2=vfopen (T->template_file, "r"); + while ( (c=fgetc (fp2))!=EOF) + { + fprintf ( fp, "%c", c); + } + fprintf (fp, "%s", LINE_SEPARATOR); + vfclose (fp2); + } + } + + fprintf (fp, "TARGET_SEQ_NAME: "); + for (a=2; aname[slist[a]])); + fprintf ( fp, "%s", LINE_SEPARATOR); + + vfclose (fp); vfree (slist); + + } + + return 1; + } +} + +int seq_list2fasta_file( Sequence *S, char *list, char *file, char *outmode) + { + FILE *fp; + int n, a, s; + static char *buf; + static int blen; + int l; + //out_mode: names can only be re-converted when out mode is aln + + /*Buf is used because cmalloced functions cannot go through strtok*/ + if ( !S)return 0; + else + { + fp=vfopen ( file, "w"); + if ( !list) + { + for ( a=0; anseq; a++) + { + if (outmode && strm (outmode, "aln"))fprintf ( fp, ">%s %s\n%s\n", decode_name (S->name[a], CODE),S->name[a], S->seq[a]); + else fprintf ( fp, ">%s %s\n%s\n", S->name[a],S->name[a], S->seq[a]); + } + } + else + { + int **list2; + int max; + + l=strlen (list); + if ( l>blen) + { + if (buf)vfree(buf); + buf=vcalloc ( strlen (list)+1, sizeof (char)); + sprintf ( buf, "%s", list); + blen=l; + } + n=atoi(strtok (list,SEPARATORS)); + + list2=declare_int (n, 2); + max=n*1000; + for ( a=0; a%s %s\n%s\n", decode_name (S->name[i], CODE), S->name[a],S->seq[i]); + else fprintf ( fp, ">%s %s\n%s\n", S->name[a], S->name[a],S->seq[i]); + } + } + vfclose (fp); + } + return 1; + } +Structure * seq2struc ( Sequence *S, Structure *ST) + { + int a, b; + + for ( a=0; a< S->nseq; a++) + for ( b=0; b< S->len[a]; b++) + ST->struc[a][b+1][ST->n_fields-1]=S->seq[a][b]; + return ST; + } + +void aln2struc (Alignment *A, Structure *ST) + { + int a, b, c; + + for ( a=0; a< A->nseq; a++) + for (c=0, b=0; b< A->len_aln; b++) + { + if ( !is_gap (A->seq_al[a][b])) + { + ST->struc[a][c][ST->n_fields-1]=A->seq_al[a][b]; + c++; + } + } + } +Alignment *stack_aln (Alignment *A, Alignment *B) + { + int a,b; + int max_len=0, max_nseq=0; + if ( B==NULL)return A; + if ( A==NULL)return B; + + max_nseq=A->nseq+B->nseq; + for (a=0; a< A->nseq; a++)max_len=MAX(strlen(A->seq_al[a]),max_len); + for (a=0; a< B->nseq; a++)max_len=MAX(strlen(B->seq_al[a]),max_len); + + A=realloc_aln2 ( A,max_nseq,max_len+1); + + for (a=A->nseq,b=0; b< B->nseq; b++, a++) + { + sprintf ( A->seq_comment[a] , "%s", B->seq_comment[b]); + sprintf ( A->aln_comment[a] , "%s", B->aln_comment[b]); + + sprintf ( A->seq_al [a] , "%s", B->seq_al [b]); + sprintf ( A->name [a] , "%s", B->name[b]); + sprintf ( A->file [a], "%s" , B->file[b]); + A->order[a][0]=B->order[b][0]; + A->order[a][1]=B->order[b][1]; + A->score_seq[a]=B->score_seq[b]; + A->len[a]=B->len[b]; + } + + A->len_aln=MAX(A->len_aln, B->len_aln); + A->nseq=A->nseq+B->nseq; + A->score_aln=A->score_aln+B->score_aln; + + A->finished=A->finished+B->finished; + return A; + } + +Alignment *chseqIaln(char *name, int seq_n, int start,int len,Sequence *S, int seqIaln, Alignment *A) + { + char *seq; + + seq=extract_char ( S->seq[seq_n], start, len); + A=realloc_aln2 (A, (A==NULL)?(seqIaln+1):MAX(A->nseq,seqIaln+1), ((A==NULL)?(strlen (seq)):MAX(strlen (seq),A->len_aln))+1); + + + sprintf ( A->seq_al[seqIaln], "%s",seq); + + + A->order[seqIaln][0]=seq_n; + A->order[seqIaln][1]=start; + sprintf ( A->name[seqIaln], "%s", name); + A->nseq=MAX(A->nseq, seqIaln+1); + A->len_aln=return_maxlen(A->seq_al, A->nseq); + A->S=S; + vfree (seq); + return A; + } + +Alignment * aln_gap2random_aa(Alignment *A) + { + int a, b,l; + char alp[200]; + + if (strm ( (A->S)->type, "PROTEIN")) + sprintf ( alp, "acefghiklmnpqrstuvwy"); + else if ( strm ( (A->S)->type, "DNA") ||strm ( (A->S)->type, "RNA") ) + sprintf ( alp, "agct"); + l=strlen (alp); + + + for (a=0; anseq; a++) + for ( b=0; blen_aln; b++) + if ( is_gap (A->seq_al[a][b]))A->seq_al[a][b]=alp[(int)rand()%(l)]; + return A; + } + +Alignment * make_random_aln(Alignment *A,int nseq, int len, char *alphabet) + { + int a; + + + A=realloc_aln2(A, nseq, len+1); + + A->nseq=0; + A->len_aln=len; + for ( a=0; a< A->nseq; a++)sprintf ( A->file[a], "random alignment"); + for ( a=0; a< nseq; a++) + A=add_random_sequence2aln(A,alphabet); + return A; + } +Alignment * add_random_sequence2aln( Alignment *A, char *alphabet) + { + int a, n; + + vsrand(0); + + n=strlen(alphabet); + A=realloc_alignment2 (A, A->nseq+1, A->len_aln+1); + + for ( a=0; a< A->len_aln; a++)A->seq_al[A->nseq][a]=alphabet[rand()%n]; + if (! A->name[A->nseq][0]) + { + for ( a=0; a<10; a++)A->name[A->nseq][a]=alphabet[rand()%n]; + A->name[A->nseq][a]='\0'; + } + + A->nseq++; + return A; + } + +Sequence *get_defined_residues( Alignment *A) + { + char *buf; + Sequence *S; + int a, b, s, l, r; + if ( !A || !A->S) return NULL; + + S=duplicate_sequence (A->S); + for ( a=0; a< S->nseq; a++) + for ( b=0; b< S->len[a]; b++)S->seq[a][b]=UNDEFINED_RESIDUE; + buf=vcalloc(A->len_aln+1,sizeof (char)); + for ( a=0; a< A->nseq; a++) + { + sprintf ( buf, "%s",A->seq_al[a]); + ungap(buf); + l=strlen (buf); + s=A->order[a][0]; + + for ( b=1; b<= l; b++) + { + r=A->seq_cache[s][b]; + + if ( r>=0)S->seq[s][r-1]=(A->S)->seq[s][r-1]; + } + } + vfree(buf); + return S; + } +Alignment *thread_defined_residues_on_aln ( Alignment *A, Sequence *S1) + { + int a, b; + int gap, r,s, r2; + for ( a=0; a< A->nseq; a++) + { + s=A->order[a][0]; + r=A->order[a][1]; + for (b=0;b< A->len_aln; b++) + { + gap=is_gap(A->seq_al[a][b]); + + if (!gap) + { + r+=!gap; + r2=A->seq_cache[s][r]-1; + + if (r2>=0 && S1->seq[s][r2]==UNDEFINED_RESIDUE) + A->seq_al[a][b]=UNDEFINED_RESIDUE; + } + } + } + return A; + } + +int ** trim_aln_borders (char **seq1, char **seq2, int nseq) + { + int a, b, c,l1,l2; + char *buf1; + char *buf2; + int max; + + + + + max=MAX(get_longest_string (seq1,-1, NULL, NULL),get_longest_string (seq2,-1, NULL, NULL))+1; + buf1=vcalloc ( max, sizeof(char)); + buf2=vcalloc ( max, sizeof(char)); + + for ( a=0; a< nseq; a++) + { + sprintf ( buf1, "%s", seq1[a]); + sprintf ( buf2, "%s", seq2[a]); + + + + ungap (buf1); + ungap (buf2); + + if (str_overlap ( buf1, buf2,'*')!=0) + { + l1=strlen ( seq1[a]); + l2=strlen ( seq2[a]); + for ( b=0,c=0; c< l1; c++) + if ( !is_gap(seq1[a][c]))seq1[a][c]=buf1[b++]; + seq1[a][c]='\0'; + for ( b=0,c=0; c< l2; c++) + if ( !is_gap(seq2[a][c]))seq2[a][c]=buf2[b++]; + seq2[a][c]='\0'; + } + } + vfree (buf1); + vfree (buf2); + return NULL; + + } +Sequence * merge_seq ( Sequence *IN, Sequence *OUT) + { + int a; + + if ( OUT==NULL)return duplicate_sequence (IN); + else + { + if ( IN && check_list_for_dup( IN->name, IN->nseq)) + { + fprintf ( stderr, "\nERROR: %s is duplicated in file %s[FATAL]\n", check_list_for_dup( IN->name, IN->nseq), IN->file[0]); + myexit (EXIT_FAILURE); + } + for ( a=0; a< IN->nseq; a++) + if ((OUT=add_sequence ( IN, OUT, a))==NULL)return NULL; + return OUT; + } + } + +Alignment *seq_name2removed_seq_name(Sequence *S, Alignment *NA, float **diff) +{ + int a, b, rb, s; + float min_diff; + for (a=0; a< S->nseq; a++) + { + if (name_is_in_list( S->name[a], NA->name, NA->nseq, 100)!=-1) continue; + for ( min_diff=100, s=0, b=0; b< NA->nseq; b++) + { + rb=name_is_in_list ( NA->name[b], S->name, S->nseq, 100); + if ( diff[a][rb]seq_comment[s], " "); + strcat ( NA->seq_comment[s], S->name[a]); + } + return NA; +} + + + + +int seq_name2index (char *name, Sequence *S) +{ + if ( !S) return -1; + else return name_is_in_list ( name, S->name, S->nseq, MAXNAMES+1); +} +char * seq_name2coor ( char *s, int *start, int *end, char sep) +{ + /*name|start|end */ + char n1[100], n2[100]; + int a=0, b=0, c=0; + + n1[0]=n2[0]='\0'; + start[0]=end[0]=0; + + while ( s[a]!=sep && s[a]!='\0')a++; + if ( s[a]=='\0')return s; + else + s[a++]='\0'; + + + + while ( s[a]!=sep && s[a]!='\0')n1[b++]=s[a++]; + + if ( s[a]=='\0'){n1[b]='\0';if ( n1[0])start[0]=atoi(n1);return s;} + else s[a++]=n1[b]='\0'; + + + while ( s[a]!=sep && s[a]!='\0')n2[c++]=s[a++]; + n2[c]='\0'; + + + if ( n1[0])start[0]=atoi(n1); + if ( n2[0])end[0]=atoi(n2); + + + return s; +} + +Sequence *extract_one_seq(char *n,int start, int end, Alignment *S, int keep_name) + { + + int seq, a; + FILE*fp; + char *name; + Sequence *OUT_S; + + + if ( n[0]=='#')seq=S->nseq; + else if ( (seq=name_is_in_list (n, S->name, S->nseq, 100)+1)!=0); + else if (is_number (n) && (seq=atoi(n))!=0) seq=atoi(n); + else + { + fprintf ( stderr, "\nCould not find Sequence %s [FATAL]", n); + myexit (EXIT_FAILURE); + } + seq--; + + name=vtmpnam ( NULL); + fp=vfopen ( name, "w"); + if ( start && end &&!keep_name)fprintf (fp, ">%s_%d_%d\n",S->name[seq],start, end); + else if ( start && end==0 && !keep_name)fprintf (fp, ">%s_%d_%d\n",S->name[seq],start,(int)strlen ( S->seq_al[seq])); + else fprintf (fp, ">%s\n", S->name[seq]); + + if ( start==0 && end==0){fprintf (fp, "%s\n", S->seq_al[seq]);} + else if (end==0){fprintf (fp, "%s\n", S->seq_al[seq]+start-1);} + else + { + for ( a=start-1; aseq_al[seq][a]);} + fprintf ( fp, "\n"); + } + + + vfclose (fp); + OUT_S=get_fasta_sequence_num (name, NULL); + + return OUT_S; + } + + + +Sequence * extract_sub_seq( Sequence *COOR, Sequence *S) + { + int a, b, c,s; + int start, end; + + for ( a=0; a< S->nseq; a++) + { + if ( (s=name_is_in_list ( S->name[a], COOR->name, COOR->nseq, 100))!=-1) + { + + sscanf ( COOR->seq_comment[s], "%d %d", &start, &end); + for (c=0,b=start-1; b< end; b++, c++)S->seq[a][c]=S->seq[a][b]; + S->seq[a][c]='\0'; + sprintf ( S->seq_comment[a], "%s",COOR->seq_comment[s]); + + } + } + S=reorder_seq ( S, COOR->name, COOR->nseq); + return S; + } + + + +char * aln_column2string (Alignment *A, int p) + { + char *s; + int a; + if (p>=A->len_aln) + { + HERE ("ERROR: index (p=%d) loger than aln (l=%d) [FATAL]", p, A->len_aln); + myexit (EXIT_FAILURE); + } + else + { + s=vcalloc (A->nseq+1, sizeof (char)); + for (a=0; a< A->nseq; a++)s[a]=A->seq_al[a][p]; + } + return s; + } + + +int **fix_seq_aln (Sequence *S, Alignment*A, int **cache) +{ + int s, b,i,nr; + + if (!cache)cache=vcalloc (S->nseq, sizeof (int*)); + + for (s=0; snseq; s++) + { + if ((i=name_is_in_list (A->name[s], S->name, S->nseq, 100)==-1))continue; + for (nr=0,b=0; blen_aln; b++) + { + if (!is_gap(A->seq_al[s][b])) + cache[i][++nr]=b+1; + } + } + return cache; +} + +int **fix_seq_seq (Sequence *S0, Sequence *Sx) +{ + //Expresses seq1 in terms of s2 + //sequences 0-N + //residues 1-N+1 + int s0, r0,i; + int **index; + + index=vcalloc ( S0->nseq, sizeof (int*)); + for (s0=0; s0nseq; s0++) + { + int l=S0->len[s0]; + index[s0]=vcalloc (l+1, sizeof (int)); + i=index[s0][0]=name_is_in_list (S0->name[s0], Sx->name, Sx->nseq, 100); + if (i==-1); + else if (strm (S0->seq[s0], Sx->seq[i])) + { + for (r0=1; r0<=l; r0++) + { + index [s0][r0]=r0; + } + } + else + { + int c; + int nr0=0; + int nr1=0; + + Alignment *B=align_two_sequences (S0->seq[s0],Sx->seq[i],(strm(S0->type, "PROTEIN"))?"blosum62mt":"idmat",-4,-1, "myers_miller_pair_wise"); + for (c=0; clen_aln; c++) + { + + int g0=is_gap(B->seq_al[0][c]); + int g1=is_gap(B->seq_al[1][c]); + nr0+=1-g0; + nr1+=1-g1; + if (!g0 && !g1)index[s0][nr0]=nr1; + } + if (aln2sim(B, "idmat")<20) add_warning (stderr,"Unreliable reconciliation for sequence %s. If it a PDB, check source file", S0->name[s0]); + free_aln (B);B=NULL; + } + } + return index; +} +int **fix_aln_seq_new (Alignment *A, Sequence *Sx) +{ + Sequence *S; + int **f; + + S=aln2seq (A); + f=fix_seq_seq(S, Sx); + free_sequence (S, S->nseq); + return f; +} +Alignment * fix_aln_seq ( Alignment *A, Sequence *S) + { + int a, b, c; + char *buf1, *buf2; + int g0, g1, nr0, nr1; + int id, tot; + Alignment *B; + + + /*This function establishes the correspondance between every (1..N+1) residue of each aligned sequence + and its correspondance in S: + A->seq_cache[a][b]=x means that residue b of aligned sequence a corresponds to residue x of the sequence with tye same index in S + A->seq_cache[a][b]=0 means there is no correspondance. + a is the index of the sequence + Applying this function is needed for turning an alignment into a constraint list + */ + + + if ( S==NULL)return A; + reorder_aln (A, S->name,S->nseq); + if (A->seq_cache)free_int (A->seq_cache, -1); + A->seq_cache=declare_int ( S->nseq, MAX((A->len_aln+1), S->max_len+1)); + + for (a=0; a< S->nseq; a++) + for ( b=0; b< A->len_aln; b++)A->seq_cache[a][b]=-1; + + buf1=buf2=NULL; + for ( a=0; a< S->nseq; a++) + { + for (b=0; b< A->nseq; b++) + { + if (strm ( S->name[a], A->name[b])) + { + A->order[b][0]=a; + + vfree (buf1); + buf1=vcalloc ( A->len_aln+1, sizeof (char)); + sprintf (buf1, "%s", A->seq_al[b]); + ungap (buf1); + upper_string (buf1); + + vfree(buf2); + buf2=vcalloc (strlen(S->seq[a])+1, sizeof (char)); + sprintf (buf2, "%s",S->seq[a]); + ungap (buf2); + upper_string (buf2); + + + + if ( strm (buf1,buf2)) + { + + for ( c=0; clen[a]; c++)A->seq_cache[a][c+1]=c+1; + } + else + { + + B=align_two_sequences (buf2,buf1,"blosum62mt",-4,-1, "myers_miller_pair_wise"); + if ( getenv ("DEBUG_RECONCILIATION")) + { + fprintf (stderr, "\n[DEBUG_RECONCILIATION:fix_aln_seq]\nReconciliation of %s\nA=Ref_sequence\nB=New_seq", S->name[a]); + print_aln (B); + } + + for (id=0, tot=0,nr0=0,nr1=0,c=0; clen_aln; c++) + { + g0=is_gap(B->seq_al[0][c]); + g1=is_gap(B->seq_al[1][c]); + nr0+=1-g0; + nr1+=1-g1; + if ( !g0 && !g1) + { + tot++; + id+=(B->seq_al[0][c]==B->seq_al[1][c])?1:0; + A->seq_cache[a][nr1]=nr0; + } + else if (g0 && !g1) + { + A->seq_cache[a][nr1]=0; + } + } + if ( ((id*100)/tot)<20) + { + print_aln (B); + fprintf ( stderr, "\nTwo different sequences have the same name: %s", S->name[a]); + fprintf ( stderr, "\nIf %s is a PDBID, Make sure it identifies the right chain (A, B, 1, 2...)", S->name[a]); + fprintf ( stderr, "\nChain number or index must be added to the PDB id (i.e. 1gowA)"); + fprintf ( stderr, "\nIf You want to use %s anyway, rename it with a non-PDB identifier such as seq_%s\n",S->name[a],S->name[a]); + myexit (EXIT_FAILURE); + } + + free_sequence ( B->S, -1); + free_aln (B); + } + + } + } + } + vfree(buf1);vfree(buf2); + return A; + } + +Sequence * add_prf2seq ( char *file, Sequence *S) + { + char **new_seq; + Sequence *NS; + + if ( !is_aln (file)&& !is_seq (file))return S; + else + { + X_template *R; + Alignment *A; + + + R=fill_R_template(file,file, S); + + A=(R->VR)->A; + ((R->VR)->A)->expand=1; + new_seq=declare_char (1,A->len_aln+1); + sprintf ( new_seq[0], "%s",aln2cons_seq_mat(A, "blosum62mt")); + + NS=fill_sequence_struc(1, new_seq,A->file); + S=add_sequence (NS, S, 0); + (S->T[S->nseq-1])->R=R; + + free_sequence (NS, NS->nseq); + free_char( new_seq, -1); + + return S; + } + } +int prf_in_seq ( Sequence *S) +{ + int a; + + if ( !S) return 0; + else + { + for ( a=0; a< S->nseq; a++) + if (seq2R_template_profile(S, a)) return 1; + } + return 0; +} +Sequence * add_sequence ( Sequence *IN, Sequence *OUT, int i) + { + int s, a; + + char *buf; + if (OUT==NULL) + { + + OUT=duplicate_sequence (IN); + return OUT; + } + for (a=0; anseq; a++) + { + Alignment *P; + P=seq2R_template_profile (OUT, a); + if (!P) continue; + else if (name_is_in_list (IN->name[i], P->name, P->nseq, 100)!=-1) return OUT; + } + + /*Adds sequence i of IN at the end of OUT*/ + + if ((s=name_is_in_list ( IN->name[i], OUT->name, OUT->nseq,STRING))==-1 ) + { + OUT=realloc_sequence (OUT, OUT->nseq+1, IN->len[i]); + sprintf ( OUT->name[OUT->nseq],"%s",IN->name[i]); + sprintf ( OUT->file[OUT->nseq],"%s",IN->file[i]); + sprintf ( OUT->seq_comment[OUT->nseq],"%s",IN->seq_comment[i]); + sprintf ( OUT->aln_comment[OUT->nseq],"%s",IN->aln_comment[i]); + + sprintf ( OUT->seq[OUT->nseq],"%s",IN->seq[i]); + OUT->len[OUT->nseq]=IN->len[i]; + OUT->T[OUT->nseq][0]=IN->T[i][0]; + OUT->nseq++; + return OUT; + } + else if ( s!=-1 && !case_insensitive_strcmp ( IN->seq[i], OUT->seq[s])) + { + + if ( getenv4debug("DEBUG_RECONCILIATION"))fprintf ( stderr,"[DEBUG_RECONCILIATION:add_sequence]\n%s\n%s\n", IN->seq[i], OUT->seq[s]); + + add_warning (stderr, "DISCREPANCY:%s in [%s] and [%s]\n", IN->name[i], IN->file[i], OUT->file[s]); + + + if (((buf=build_consensus(IN->seq[i], OUT->seq[s],"cfasta_pair_wise" ))!=NULL)||((buf=build_consensus(IN->seq[i], OUT->seq[s],"myers_miller_pair_wise" ))!=NULL)) + { + + OUT->max_len=MAX(OUT->max_len, strlen(buf)); + OUT->min_len=MIN(OUT->min_len, strlen(buf)); + OUT->seq =realloc_char ( OUT->seq, -1, -1,OUT->nseq,OUT->max_len+1); + + sprintf ( OUT->seq[s],"%s",buf); + OUT->len[s]=strlen (buf); + vfree (buf); + return OUT; + } + else + { + fprintf ( stderr, "IMPOSSIBLE TO RECONCILIATE SOME SEQUENCES[FATAL:%s]\n", PROGRAM); + print_aln ( align_two_sequences (IN->seq[i], OUT->seq[s], "idmat", 0, 0, "fasta_pair_wise")); + myexit (EXIT_FAILURE); + return NULL; + } + + } + else + { + return OUT; + } + } + + +Sequence * trim_seq ( Sequence *A, Sequence *B) + { + int a; + Sequence *R; + + if (A->nseq>B->nseq) + { + Sequence *I; + I=A;A=B;B=I; + } + + R=declare_sequence (MIN(A->min_len,B->min_len), MAX(A->max_len, B->max_len), MIN(A->nseq, B->nseq)); + R->nseq=0; + + for (a=0; a< A->nseq; a++) + { + if ( name_is_in_list ( A->name[a], B->name, B->nseq,STRING+1)!=-1) + { + sprintf ( R->name[R->nseq], "%s", A->name[a]); + sprintf ( R->seq[R->nseq], "%s", A->seq[a]); + sprintf ( R->file[R->nseq], "%s", A->file[a]); + sprintf ( R->aln_comment[R->nseq], "%s", A->aln_comment[a]); + sprintf ( R->seq_comment[R->nseq], "%s", A->seq_comment[a]); + + R->len[R->nseq]=A->len[a]; + R->nseq++; + } + } + return R; + } + +Sequence * trim_aln_seq ( Alignment *A, Alignment *B) + { + int a; + static char **name_list; + int n=0; + Sequence *SA, *SB; + int **cache_A=NULL; + int **cache_B=NULL; + int * p; + + /*This function inputs two alignments A and B + It removes sequences that are not common to both of them + It rearange the sequences so that they are in the same order + A decides on the order + The Sequences (A->S) and (B->S) are treated the same way + Sequences are also merged in order to detects discrepencies. + A pointer to S is returned + */ + if (name_list)free_char (name_list, -1); + name_list=declare_char (MAX(A->nseq, B->nseq), STRING+1); + + for ( a=0; a< A->nseq; a++) + { + if ( name_is_in_list ( A->name[a], B->name, B->nseq,STRING)!=-1) + { + sprintf ( name_list[n++], "%s", A->name[a]); + } + } + + + + reorder_aln ( A, name_list, n); + if (A->seq_cache)cache_A=duplicate_int (A->seq_cache, -1, -1); + if (B->seq_cache)cache_B=duplicate_int (B->seq_cache, -1, -1); + reorder_aln ( B, name_list, n); + for ( a=0; a< n; a++) + { + if ( cache_A) + { + p=A->seq_cache[A->order[a][0]]; + A->seq_cache[A->order[a][0]]=cache_A[a]; + cache_A[a]=p; + } + if ( cache_B) + { + p=B->seq_cache[B->order[a][0]]; + B->seq_cache[B->order[a][0]]=cache_B[a]; + cache_B[a]=p; + } + A->order[a][0]=B->order[a][0]=a; + } + free_int(A->seq_cache, -1); + free_int(B->seq_cache, -1); + + A->seq_cache=cache_A; + B->seq_cache=cache_B; + + + + SA=aln2seq(A); + SB=aln2seq(B); + + A->S=B->S=merge_seq (SA, SB); + return A->S; + } +Sequence * trim_aln_seq_name ( Alignment *A, Alignment *B) + { + int a; + Sequence *S; + + /*This function inputs two alignments A and B + It removes sequences that are not common to both of them + It rearange the sequences so that they are in the same order + A decides on the order + */ + S=declare_sequence ( 1, 1, A->nseq+B->nseq); + S->nseq=0; + for ( a=0; a< A->nseq; a++) + { + if ( name_is_in_list ( A->name[a], B->name, B->nseq,STRING)!=-1) + { + sprintf ( S->name[S->nseq++], "%s", A->name[a]); + } + } + return S; + } + + + +char ** rm_name_tag (char **name, int nseq, char *tag) +{ + int a , b, ntag; + char **tag_list; + char *s; + char **template_list; + if ( !name )return NULL; + + tag_list=declare_char (10, 4); + + if ( tag) + { + ntag=1; sprintf ( tag_list[0], "%s", tag); + } + else + { + ntag=0; + sprintf ( tag_list[ntag++], "_S_"); + sprintf ( tag_list[ntag++], "_G_"); + } + template_list=declare_char (nseq, 100); + for ( a=0; a%s _%s_ %s", name[a], s+1, s+3); + break; + } + } + } + + free_char (tag_list, -1); + return template_list; +} +Sequence * swap_header ( Sequence *S, Sequence *H) +{ + int a, b, n; + + for ( a=0; a< S->nseq; a++) + { + if ( (n=name_is_in_list (S->name[a],H->name, H->nseq, 1000))!=-1) + { + char **list; + + + list=string2list (H->seq_comment[n]); + if ( list==NULL || atoi(list[0])==1)continue; + S->seq_comment[a]='\0'; + sprintf (S->name[a], "%s%s%s",H->name[n], list[1], list[2]); + vfree ( S->seq_comment[a]);S->seq_comment[a]=vcalloc ( strlen (H->seq_comment[n])+1, sizeof (char)); + for (b=3; b< atoi(list[0]); b++)S->seq_comment[a]=strcat (S->seq_comment[a], list[b]); + free_char (list, -1); + } + } + return S; +} + + +Sequence * profile_seq2template_seq ( Sequence *S, char *template_file, Fname *F) +{ + /*This function fetches potential templates associated with sequences within a profile*/ + int i; + Alignment *A; + + for ( i=0; i< S->nseq; i++) + { + + if ( (A=seq2R_template_profile (S, i))) + { + + A->S=aln2seq (A); + A->S=seq2template_seq (A->S, template_file, F); + if (!A->S)return NULL; + } + } + + return S; +} + +Sequence * seq2template_type(Sequence *Seq) +{ + //add template + int a, e; + int s; + struct X_template *S=NULL; + struct X_template *P=NULL; + struct X_template *R=NULL; + struct X_template *G=NULL; + struct X_template *F=NULL; + struct X_template *T=NULL; + struct X_template *E=NULL; + struct X_template *U=NULL; + Alignment *A; + + + e=' '; + for (a=0; a< Seq->nseq; a++) + { + if (!Seq->T[a])continue; + //HERE ADD a Template + P=seq_has_template (Seq, a, "_P_"); + S=seq_has_template (Seq, a, "_S_"); + R=seq_has_template (Seq, a, "_R_"); + G=seq_has_template (Seq, a, "_G_"); + F=seq_has_template (Seq, a, "_F_"); + T=seq_has_template (Seq, a, "_T_"); + E=seq_has_template (Seq, a, "_E_"); + U=seq_has_template (Seq, a, "_U_"); + + s=(!P)?1:0; + sprintf ( (Seq->T[a])->seq_type, "%c%c%c%c%c%c%c%c", (P)?'P':e, (S)?'S':e, (S &&!P)?'s':e,(R)?'R':e, (G)?'G':e,(T)?'T':e,(E)?'E':e,(U)?'U':e); + + if (R && (A=seq2R_template_profile (Seq,a)) && A->S) + { + + A->S=seq2template_type ( A->S); + } + } + return Seq; +} + +char * string_contains_template_tag (char *string_in) +{ + char string[100]; + + if ( strstr (string, "_P_"))return "_P_"; + if ( strstr (string, "_S_"))return "_S_"; + if ( strstr (string, "_R_"))return "_R_"; + if ( strstr (string, "_G_"))return "_G_"; + if ( strstr (string, "_F_"))return "_F_"; + if ( strstr (string, "_T_"))return "_T_"; + if ( strstr (string, "_E_"))return "_E_"; + if ( strstr (string, "_U_"))return "_U_"; + + return NULL; +} +static int check_blast_is_installed (char *server); + + + +static int check_blast_is_installed (char *server) +{ + if (strm (server, "EBI")); + else if ( strm (server, "NCBI")) + return check_program_is_installed (NCBIWEBBLAST_4_TCOFFEE,NULL, NULL,NCBIWEBBLAST_ADDRESS, INSTALL_OR_DIE); + else if ( strm (server, "LOCAL")) + return check_program_is_installed (NCBIBLAST_4_TCOFFEE,NULL, NULL,NCBIBLAST_ADDRESS, INSTALL_OR_DIE); + return 1; +} + + +Sequence * vremove_seq_template_files(Sequence *S) +{ + return handle_seq_template_file (S, "remove"); +} +Sequence * display_seq_template_files(Sequence *S) +{ + return handle_seq_template_file (S, "display"); +} +Sequence * handle_seq_template_file (Sequence *S, char *mode) +{ + int a; + Template *T; + + for (a=0; a< S->nseq; a++) + { + T=S->T[a]; + if (T) + { + handle_X_template_files (T->P, mode); + handle_X_template_files (T->F, mode); + handle_X_template_files (T->R, mode); + handle_X_template_files (T->T, mode); + handle_X_template_files (T->E, mode); + } + } + + return S; +} +int handle_X_template_files ( X_template *T, char *mode) + { + if (!T)return 0; + + if ( strm (mode, "remove")) + { + vremove (T->template_file); + vremove (T->template_name); + } + else if (strm (mode, "display")) + { + char buf[100]; + sprintf ( buf, "Template %s", template_type2type_name (T->template_type)); + if (check_file_exists (T->template_name))display_output_filename ( stdout,buf,T->template_format,T->template_name, STORE); + } + else + { + printf_exit (EXIT_FAILURE, stderr, "\nUnkonwn mode %s for template handling [FATAL:%s]", mode, PROGRAM); + } + return 1; + } +Sequence * seq2template_seq ( Sequence *S, char *template_list, Fname *F) +{ + /*Expected format for the template file: + >seq_name _X_ Target_template + X: S for Structures + G for genomes (Exoset) + When alternative templates are given for a sequence, the first one superseeds all the others + */ + + /*Fill the sequences*/ + /*1: No template*/ + char buf[1000]; + + int PmC,PmI,PMI; + int BmC,BmI,BMI; + char *server; + char *pdb_db,*prot_db; + char pdb_type[100]; + char *p; + int remove_template_file=0; + + + remove_template_file=get_int_variable ("remove_template_file"); + server=get_string_variable ("blast_server"); + pdb_db=get_string_variable ("pdb_db"); + prot_db=get_string_variable ("prot_db"); + + PmI=get_int_variable ("pdb_min_sim"); + PMI=get_int_variable ("pdb_max_sim"); + PmC=get_int_variable ("pdb_min_cov"); + + BmI=get_int_variable ("prot_min_sim"); + BMI=get_int_variable ("prot_max_sim"); + BmC=get_int_variable ("prot_min_cov"); + + //Set the type of the PDB structure + if ((p=get_string_variable ("pdb_type"))) + { + sprintf ( pdb_type, "%s",p); + } + else + { + sprintf (pdb_type, "dmn"); + } + + if ( (template_list && template_list[0]=='\0') || strm ( template_list, "no_template")) + { + return S; + } + else if ( strstr (template_list, "MODE_"))//pre_set mode + { + return seq2template_seq ( S,template_list+strlen ("MODE_"),F); + } + else if ( strm ( template_list, "SSP")|| strm ( template_list, "GOR")) + { + + /*use GOR to Predict the secondary structure*/ + check_program_is_installed (GOR4_4_TCOFFEE,NULL, NULL,GOR4_ADDRESS, INSTALL_OR_DIE); + sprintf ( buf, "SCRIPT_tc_generic_method.pl@mode#ssp_template@seq#%s/%s@obs#%s/%s@cache#%s@type#_E_",get_mcoffee_4_tcoffee(), "New_KS.267.seq", get_mcoffee_4_tcoffee(), "New_KS.267.obs", get_cache_dir()); + S=seq2template_seq (S,buf, F); + return S; + } + else if ( strm ( template_list, "PSISSP") || strm (template_list, "PSIGOR")) + { + + /*Computes a GOR consensus on a psi-blast output*/ + check_program_is_installed (GOR4_4_TCOFFEE,NULL, NULL,GOR4_ADDRESS, INSTALL_OR_DIE); + check_blast_is_installed(server); + + sprintf ( buf, "SCRIPT_tc_generic_method.pl@mode#psissp_template@seq#%s/%s@obs#%s/%s@cache#%s@minid#%d@maxid#%d@mincov#%d@server#%s@type#_E_",get_mcoffee_4_tcoffee(), "New_KS.267.seq", get_mcoffee_4_tcoffee(), "New_KS.267.obs", get_cache_dir(), BmI,BMI,BmC,server); + S=seq2template_seq (S,buf, F); + return S; + } + else if ( strm ( template_list, "TM")) + { + + /*predict transmembrane structure*/ + check_program_is_installed (HMMTOP_4_TCOFFEE,NULL, NULL,HMMTOP_ADDRESS, INSTALL_OR_DIE); + sprintf ( buf, "SCRIPT_tc_generic_method.pl@mode#tm_template@arch#%s/%s@psv#%s/%s@type#_T_",get_mcoffee_4_tcoffee(), "hmmtop.arch", get_mcoffee_4_tcoffee(), "hmmtop.psv"); + S=seq2template_seq (S,buf, F); + return S; + } + else if ( strm ( template_list, "PSITM")) + { + + /*predict transmembrane structure*/ + check_program_is_installed (HMMTOP_4_TCOFFEE,NULL, NULL,HMMTOP_ADDRESS, INSTALL_OR_DIE); + check_blast_is_installed(server); + + sprintf ( buf, "SCRIPT_tc_generic_method.pl@mode#psitm_template@database#%s@arch#%s/%s@psv#%s/%s@cache#%s@minid#%d@maxid#%d@mincov#%d@server#%s@type#_T_", prot_db, get_mcoffee_4_tcoffee(), "hmmtop.arch", get_mcoffee_4_tcoffee(), "hmmtop.psv",get_cache_dir(), BmI,BMI,BmC,server); + S=seq2template_seq (S,buf, F); + return S; + } + + else if (strm ( template_list, "PSIBLAST")) + { + + check_blast_is_installed(server); + sprintf ( buf, "SCRIPT_tc_generic_method.pl@mode#psiprofile_template@database#%s@method#psiblast@cache#%s@minid#%d@maxid#%d@mincov#%d@server#%s@type#_R_", prot_db,get_cache_dir(),BmI,BMI,BmC,server); + S=seq2template_seq (S,buf, F); + + return S; + } + else if (strm ( template_list, "BLAST") ) + { + check_blast_is_installed(server); + sprintf ( buf, "SCRIPT_tc_generic_method.pl@mode#profile_template@database#%s@method#blastp@cache#%s@minid#%d@maxid#%d@mincov#%d@server#%s@type#_R_", prot_db,get_cache_dir(),BmI,BMI,BmC,server); + S=seq2template_seq (S,buf, F); + + return S; + } + else if ( strm ( template_list, "EXPRESSO") || strm (template_list, "PDB")) + { + check_blast_is_installed(server); + + int isRNA = 0; + int i; + for (i= 0; i < S->len[0]; ++i) + { + isRNA = (isRNA || is_rna(S->seq[0][i])); + } + + if (isRNA) + { + sprintf ( buf, "SCRIPT_tc_generic_method.pl@mode#pdb_template@database#%s@method#blastn@cache#%s@minid#%d@maxid#%d@mincov#%d@server#%s@type#_P_@pdb_type#%s",pdb_db, get_cache_dir(),PmI,PMI,PmC, server,pdb_type); + } + else + { + sprintf ( buf, "SCRIPT_tc_generic_method.pl@mode#pdb_template@database#%s@method#blastp@cache#%s@minid#%d@maxid#%d@mincov#%d@server#%s@type#_P_@pdb_type#%s",pdb_db, get_cache_dir(),PmI,PMI,PmC, server,pdb_type); + } + return seq2template_seq (S,buf, F); + } + + else if ( strm (template_list, "RCOFFEE") || strm (template_list, "RNA")) + { + char *file_struc_clac = vtmpnam (NULL); + FILE* struc_calc_f =vfopen(file_struc_clac,"w"); + int i; + int j=0; + for (i = 0; i< S->nseq; ++i) + { + if (S->T[i]->P) + { + ++j; + fprintf(struc_calc_f,"%s %s\n",S->name[i],S->T[i]->P->template_file); + } + } + vfclose(struc_calc_f); + if (j == S->nseq) + { +// S = seq2template_seq (S,buf,F); + sprintf ( buf, "SCRIPT_tc_generic_method.pl@mode#calc_rna_template@pdbfile#%s@cache#%s@type#_F_", file_struc_clac,get_cache_dir()); + } + else + { + check_program_is_installed (RNAPLFOLD_4_TCOFFEE,NULL, NULL,RNAPLFOLD_ADDRESS, IS_FATAL); + sprintf ( buf, "SCRIPT_tc_generic_method.pl@mode#RNA_template@type#_F_"); + if (j > 0) + { + S = seq2template_seq (S,buf,F); + sprintf ( buf, "SCRIPT_tc_generic_method.pl@mode#calc_rna_template@pdbfile#%s@cache#%s@type#_F_", file_struc_clac,get_cache_dir()); + } + } +// printf("IN T_\n"); + return seq2template_seq (S,buf,F); + } + + + /*2: Templates from seqnames (SELF) or named like the sequences (SEQFILE)*/ + else if ( strstr (template_list, "SELF_") ||strstr (template_list, "SEQFILE_") ) + { + int a; + char *p; + + //add template + for (a=0; a< S->nseq; a++) + { + + if ( (p=strstr (template_list,"SELF_")))p=S->name[a]; + else if ( strstr (template_list, "SEQFILE_"))p=template_list; + else + { + fprintf ( stderr, "\nUnkown mode for Template [FATAL:%s]\n", PROGRAM); + myexit (EXIT_FAILURE); + } + + if ( strstr (template_list, "_P_") && !(S->T[a])->P)(S->T[a])->P =fill_P_template ( S->name[a], p,S);//PDB + else if ( strstr (template_list, "_S_") && !(S->T[a])->S)(S->T[a])->S =fill_S_template ( S->name[a], p,S);//Sequence + else if ( strstr (template_list, "_R_" )&& !(S->T[a])->R)(S->T[a])->R =fill_R_template ( S->name[a], p,S);//pRofile + else if ( strstr (template_list, "_G_" )&& !(S->T[a])->G)(S->T[a])->G =fill_G_template ( S->name[a], p,S);//Genomic + else if ( strstr (template_list, "_F_" )&& !(S->T[a])->F)(S->T[a])->F =fill_F_template ( S->name[a], p,S);//Fold + else if ( strstr (template_list, "_T_" )&& !(S->T[a])->T)(S->T[a])->T =fill_T_template ( S->name[a], p,S);//Trans Membrane + else if ( strstr (template_list, "_E_" )&& !(S->T[a])->E)(S->T[a])->E =fill_E_template ( S->name[a], p,S);//Secondary Structure + else if ( strstr (template_list, "_U_" )&& !(S->T[a])->U)(S->T[a])->U =fill_U_template ( S->name[a], p,S);//unicode, list template + + } + return S; + } + + /*2: Templates comes in a template_file*/ + else if ( template_list==NULL || format_is_fasta (template_list)) + { + Sequence *T; + int a, i; + int ntemp=0; + T=(template_list!=NULL)?get_fasta_sequence (template_list, NULL):S; + for (a=0; a< T->nseq; a++) + { + + char *p; + if ((i=name_is_in_list(T->name[a], S->name, S->nseq, MAXNAMES))!=-1) + { + + if ( (p=strstr (T->seq_comment[a], " _P_ ")) && !(S->T[i])->P &&( (S->T[i])->P=fill_P_template (S->name[i],p,S)))ntemp++; + else if ( (p=strstr (T->seq_comment[a], " _F_ ")) && !(S->T[i])->F &&( (S->T[i])->F=fill_F_template (S->name[i],p,S)))ntemp++; + else if ( (p=strstr (T->seq_comment[a], " _S_ ")) && !(S->T[i])->S &&( (S->T[i])->S=fill_S_template (S->name[i],p,S)))ntemp++; + + else if ( (p=strstr (T->seq_comment[a], " _R_ ")) && !(S->T[i])->R &&( (S->T[i])->R=fill_R_template (S->name[i],p,S)))ntemp++; + else if ( (p=strstr (T->seq_comment[a], " _G_ ")) && !(S->T[i])->G &&( (S->T[i])->G=fill_G_template (S->name[i],p,S)))ntemp++; + else if ( (p=strstr (T->seq_comment[a], " _T_ ")) && !(S->T[i])->T &&( (S->T[i])->T=fill_T_template (S->name[i],p,S)))ntemp++; + else if ( (p=strstr (T->seq_comment[a], " _E_ ")) && !(S->T[i])->E &&( (S->T[i])->E=fill_E_template (S->name[i],p,S)))ntemp++; + else if ( (p=strstr (T->seq_comment[a], " _U_ ")) && !(S->T[i])->U &&( (S->T[i])->E=fill_U_template (S->name[i],p,S)))ntemp++; + + if (T!=S)strcat (S->seq_comment[i], T->seq_comment[a]); + + } + } + + if (T!=S)free_sequence (T, -1); + + if ( remove_template_file==2) + { + vremove (template_list); + } + else + if (template_list)display_output_filename ( stdout, "Template_List","fasta_seq", template_list, STORE); + return S; + } + + /*3 Templates are generated with a script*/ + else if (strstr (template_list, "SCRIPT_") && get_string_variable ("multi_core") && strstr (get_string_variable ("multi_core"), "templates") && get_nproc()>1) + { + char *tmp1,*command; + Alignment *A; + char **temp_file,**seq_file; + int * pid_list, pid, npid, submited; + int nproc, max_nproc; + int num=0; + + char outfile[1000]; + static char *script; + static int ntemp; + char *p; + int z, i; + int freeF=0; + + if (!script)script=vcalloc ( 1000, sizeof(char)); + + ntemp++; + + command=vcalloc ( 1000, sizeof (char)); + tmp1=vtmpnam (NULL); + + A=seq2aln (S,NULL, 0); + string_array_upper(A->seq_al, A->nseq); + output_fasta_seq (tmp1, A); + sprintf ( script, "%s", after_strstr (template_list, "SCRIPT_")); + + if ((p=strstr (template_list, "@type#"))) + p+=strlen ("@type#"); + + if (!F){F=parse_fname (S->file[0]);freeF=1;} + sprintf (outfile, "%s%s_%s%d.template_list", F->path,F->name,template_type2short_type_name(p),ntemp); + while ( check_file_exists (outfile)) + { + sprintf (outfile, "%s%s_%s%d.%d.template_list",F->path, F->name,template_type2short_type_name(p),ntemp, ++num); + } + if (freeF)free_fname(F); + + nproc=get_nproc(); + //max_nproc=2*nproc; + max_nproc=20; //EBI recommended maximum + script=substitute(script, "@", " -"); + script=substitute(script, "#", "="); + + temp_file=vcalloc ( A->nseq, sizeof (char*)); + seq_file =vcalloc (A->nseq, sizeof (char*)); + pid_list =vcalloc (MAX_N_PID, sizeof (int *)); + + fprintf ( stderr, "\n\t------ Fetch Templates [Multi Core Mode %d CPUs]\n",get_nproc()); + for (npid=0, submited=0,i=0; inseq; i++) + { + FILE *fp2; + seq_file[i]=vtmpnam (NULL); + temp_file[i]=vtmpnam (NULL); + fp2=vfopen (seq_file[i], "w"); + fprintf ( fp2, ">%s\n%s\n", S->name[i], S->seq[i]); + vfclose (fp2); + + pid=vvfork(NULL); + if (pid==0) + { + initiate_vtmpnam (NULL); + if ( strstr (script, "tc_generic_method")) + { + //sprintf ( command, "%s -other_pg %s -infile=%s -outfile=%s -tmpdir=%s",get_string_variable ("t_coffee"),script,seq_file[i],temp_file[i],get_tmp_4_tcoffee()); + sprintf ( command, "%s -infile=%s -outfile=%s -tmpdir=%s",script,seq_file[i],temp_file[i],get_tmp_4_tcoffee()); + } + else + //sprintf ( command, "%s -other_pg %s -infile=%s -outfile=%s",get_string_variable("t_coffee"),script,seq_file[i],temp_file[i]); + sprintf ( command, "%s -infile=%s -outfile=%s",script,seq_file[i],temp_file[i]); + command=substitute(command, "@", " "); + //my_system ( command); + myexit (my_system(command)); + } + else + { + pid_list[pid]=npid; + //set_pid(pid); + npid++; + submited++; + submited=vwait_npid(submited,max_nproc,nproc); + } + } + + submited=vwait_npid(submited,0,0); + //Concatenate all the files + vremove (outfile); + for (i=0; iseq_al, A->nseq); + output_fasta_seq (tmp1, A); + sprintf ( script, "%s", after_strstr (template_list, "SCRIPT_")); + fprintf ( stderr, "\n"); + if ((p=strstr (template_list, "@type#"))) + p+=strlen ("@type#"); + if (F) + { + sprintf (outfile, "%s%s_%s%d.template_list", F->path,F->name,template_type2short_type_name(p),ntemp); + } + else + { + F=parse_fname (S->file[0]); + sprintf (outfile, "%s%s_%s%d.template_list",F->path, F->name,template_type2short_type_name(p),ntemp); + free_fname (F); + } + + script=substitute(script, "@", " -"); + script=substitute(script, "#", "="); + + if ( strstr (script, "tc_generic_method")) + { + sprintf ( command, "%s -other_pg %s -infile=%s -outfile=%s -tmpdir=%s",get_string_variable ("t_coffee"),script, tmp1,outfile,get_tmp_4_tcoffee()); + } + else sprintf ( command, "%s -other_pg %s -infile=%s -outfile=%s",get_string_variable("t_coffee"),script, tmp1, outfile); + + vremove (outfile); + command=substitute(command, "@", " "); + + my_system ( command); + + free_aln (A); + + if ( check_file_exists (outfile) && format_is_fasta(outfile)) + { + S=seq2template_seq (S, outfile, F); + } + else if (strstr (command, "webblast.pl"))return S; + else + { + + add_warning (stderr, "Could not Run %s to find templates[%s](unforked mode)\n",command, PROGRAM); + return NULL; + } + + vfree (command); + return S; + } + + return S; +} + +char* seq2template_file (Sequence *S, char *file) +{ + Alignment *A; + int i; + if (!S)return file; + if (file==NULL)file=vtmpnam (NULL); + + seq2template_file2 (S, file, "w"); + + for (i=0; inseq; i++) + { + if ( (A=seq2R_template_profile (S, i))) + { + Sequence *S; + S=A->S; + if (S)seq2template_file2 (A->S, file, "a"); + } + } + return file; +} + +int seq2template_file2 (Sequence *S, char *file, char *mode) +{ + FILE *fp; + int i; + char buf1[10000]; + char buf2[10000]; + struct X_template *X; + + fp=vfopen ( file, mode); + for ( i=0; i< S-> nseq; i++) + { + buf1[0]=0; + if ( S->T) + { + if (S->T[i]) + { + if ( (X=(S->T[i])->P)){sprintf (buf2, " %s %s ", X->template_type, X->template_file);strcat (buf1, buf2);} + /*if ( (X=(S->T[i])->S)){sprintf (buf2, " %s %s ", X->template_type, X->template_file);strcat (buf1, buf2);}*/ + if ( (X=(S->T[i])->R)){sprintf (buf2, " %s %s ", X->template_type, X->template_file);strcat (buf1, buf2);} + if ( (X=(S->T[i])->G)){sprintf (buf2, " %s %s ", X->template_type, X->template_file);strcat (buf1, buf2);} + if (buf1[0])fprintf ( fp, ">%s %s\n", S->name[i], buf1); + } + } + } + vfclose (fp); + return EXIT_SUCCESS; +} + + + + +int seq2n_X_template ( Sequence *S, char *type) +{ + int a, n; + + for (n=0,a=0; a< S->nseq; a++) + { + if ( strm2 (type, "_P_","_*_") && (S->T[a])->P)n++; + if ( strm2 (type, "_F_","_*_") && (S->T[a])->F)n++; + if ( strm2 (type, "_S_","_*_") && (S->T[a])->S)n++; + if ( strm2 (type, "_R_","_*_") && (S->T[a])->R)n++; + if ( strm2 (type, "_G_","_*_") && (S->T[a])->G)n++; + } + return n; +} +struct X_template *fill_X_template ( char *name, char *p, char *token) +{ + struct X_template *X; + + + + + char *k; + + X=vcalloc (1, sizeof (X_template)); + sprintf ( X->seq_name, "%s", name); + if ( (k=strstr (p, token)))sscanf (k+strlen(token), "%s",X->template_name); + else sprintf (X->template_name, "%s", p); + + + /*Add a Structure HERE*/ + sprintf ( X->template_type, "%s", token); + if ( strm (token, "_P_"))X->VP=vcalloc (1, sizeof (P_template)); + if ( strm (token, "_F_"))X->VF=vcalloc (1, sizeof (F_template)); + + if ( strm (token, "_S_"))X->VS=vcalloc (1, sizeof (S_template)); + if ( strm (token, "_R_"))X->VR=vcalloc (1, sizeof (R_template)); + if ( strm (token, "_G_"))X->VG=vcalloc (1, sizeof (G_template)); + if ( strm (token, "_T_"))X->VT=vcalloc (1, sizeof (T_template)); + if ( strm (token, "_E_"))X->VE=vcalloc (1, sizeof (E_template)); + if ( strm (token, "_U_"))X->VU=vcalloc (1, sizeof (U_template)); + + return X; +} + +struct X_template* free_X_template ( struct X_template *X) +{ + if (X->VP) + { + vfree (X->VP); + } + if (X->VF) + { + vfree (X->VF); + } + if ( X->VS) + { + free_sequence ((X->VS)->S, -1); + vfree (X->VS); + } + if ( X->VR) + { + free_aln ((X->VR)->A); + vfree (X->VR); + } + if ( X->VG) + { + free_sequence ((X->VG)->S, -1); + vfree (X->VG); + } + + vfree (X); + return NULL; +} + +FILE * display_sequence_templates (Sequence *S,int i, FILE *io) +{ + + + io=display_X_template ( (S->T[i])->P, io); + + io=display_X_template ( (S->T[i])->F, io); + + io=display_X_template ( (S->T[i])->S, io); + + io=display_X_template ( (S->T[i])->R, io); + io=display_X_template ( (S->T[i])->G, io); + io=display_X_template ( (S->T[i])->T, io); + io=display_X_template ( (S->T[i])->E, io); + + return io; +} + +FILE * display_X_template (struct X_template *X, FILE *io) +{ + + if ( !X) return io; + if ( !strm (X->template_type, "_S_"))fprintf (io, "\n\t%s: Template=%s, File=%s",template_type2type_name (X->template_type), X->template_name,X->template_file); + return io; +} +char *template_type2short_type_name (char *type) +{ + //add_template + if (!type)return ""; + else if ( strstr (type, "_P_")) return "pdb"; + else if ( strstr (type, "_F_")) return "rfold"; + else if ( strstr (type, "_S_")) return "seq"; + else if ( strstr (type, "_R_")) return "prf"; + else if ( strstr (type, "_G_")) return "genome"; + else if ( strstr (type, "_E_")) return "ssp"; + else if ( strstr (type, "_T_")) return "tmp"; + else if ( strstr (type, "_U_")) return "unicode"; + else return type; +} +char *template_type2type_name (char *type) +{ + //add_template + if ( strstr (type, "_P_")) return "PDB struc"; + else if ( strstr (type, "_F_")) return "RNA Fold"; + else if ( strstr (type, "_S_")) return "Sequeence"; + else if ( strstr (type, "_R_")) return "Profile"; + else if ( strstr (type, "_G_")) return "Genomic"; + else if ( strstr (type, "_E_")) return "Protein Secondary Structure"; + else if ( strstr (type, "_T_")) return "Protein Trans Membrane Structure "; + else if ( strstr (type, "_U_")) return "Unicode and strings"; + + else return type; +} +struct X_template *fill_F_template ( char *name,char *p, Sequence *S) +{ + /*Profile template*/ + struct X_template *F; + + F=fill_X_template ( name, p, "_F_"); + sprintf (F->template_format , "TCOFFEE_LIBRARY"); + if (!F || !check_file_exists (F->template_name)) + { + fprintf ( stderr, "Could Not Fill _F_ (Fold) template for sequence |%s|", name); + free_X_template (F); + return NULL; + } + else if ( check_file_exists (F->template_name)) + { + sprintf ( F->template_file, "%s", F->template_name); + } + + return F; + +} + + +struct X_template *fill_P_template ( char *name,char *p, Sequence *S) +{ + struct X_template *P; + Sequence *PS; + Alignment *A; + int sim, cov, i; + char *buf; + + + P=fill_X_template ( name, p, "_P_"); + sprintf (P->template_format , "pdb"); + + if (!P ||(check_file_exists (P->template_name) && !is_pdb_file (P->template_name) )) + { + //fprintf ( stderr, "Could Not Fill _P_ template for sequence |%s|", name); + free_X_template (P); + return NULL; + } + else if ( check_file_exists (P->template_name)) + { + sprintf ( P->template_file, "%s", P->template_name); + buf=path2filename (P->template_name); + if (P->template_name!=buf) + { + sprintf ( P->template_name, "%s",buf ); + vfree (buf); + } + } + else + { + char *st; + + st=is_pdb_struc (P->template_name); + if (st) + { + if (st!=P->template_file)sprintf ( P->template_file, "%s", st); + } + } + + /*Make a first run to fix relaxed PDB files*/ + buf=fix_pdb_file (P->template_file); + + if ( buf!=P->template_file) + { + + sprintf ( P->template_file, "%s",buf); + vfree (buf); + } + + /*Check the PDB FILE EXISTS*/ + + if (!is_pdb_file (P->template_file)) + { + + if (p)add_warning(stderr, "_P_ Template | %s | Could Not Be Found\n",p); + else if (name)add_warning(stderr, "_P_ Template | %s | Could Not Be Found\n",name); + free_X_template (P); + return NULL; + } + else + { + buf= get_pdb_id (P->template_file); + if (buf!=(P->VP)->pdb_id) + { + sprintf ((P->VP)->pdb_id, "%s", buf); + vfree (buf); + } + } + + /*Check the target sequence is similar enough*/ + + PS=get_pdb_sequence (P->template_file); + + + + if ( PS==NULL) + { + add_warning( stderr, "_P_ Template |%s| Could Not be Used for Sequence |%s|: Structure Not Found", P->template_name, name); + free_X_template (P);P=NULL; + } + else + { + int minsim=get_int_variable ("pdb_min_sim"); + int mincov=get_int_variable ("pdb_min_cov"); + + + i=name_is_in_list (name, S->name, S->nseq, 100); + + A=align_two_sequences (S->seq[i], PS->seq[0],"idmat",-3,0, "fasta_pair_wise"); + + sprintf ( A->name[0], "seq"); + sprintf ( A->name[1], "pdb"); + cov=aln2coverage (A, 0); + sim=aln2sim (A, "idmat"); + + if (sim<=minsim) + { + add_information( stderr, "_P_ Template %s Could Not be Used for Sequence %s: Similarity too low [%d, Min=%d]",P->template_name,name,sim,minsim); + add_information( stderr, "If you want to include %s in anycase,add -pdb_min_sim=%d to the command line",name,sim); + print_aln (A); + free_X_template (P); + P=NULL; + } + else if ( cov<=mincov) + { + add_information(stderr, "_P_ Template |%s| Could Not be Used for Sequence |%s|: Coverage too low [%d, Min=%d]",P->template_name,name, cov, mincov); + add_information( stderr, "If you want to include this sequence in anycase add -pdb_min_cov=%d to the command line", cov); + print_aln (A); + free_X_template (P);P=NULL; + } + free_aln(A); + free_sequence (PS, -1); + } + + return P; +} + +struct X_template *fill_S_template ( char *name,char *p, Sequence *Seq) +{ + struct X_template *S; + S=fill_X_template ( name, p, "_S_"); + if ( strm (name, p))sprintf ( S->template_file, "%s",output_fasta_seqX (NULL,"w",Seq,NULL, seq_name2index (name, Seq))); + (S->VS)->S=get_fasta_sequence (S->template_file, NULL); + return S; +} +struct X_template *fill_R_template ( char *name,char *p, Sequence *S) +{ + /*Profile template*/ + struct X_template *R; + + + R=fill_X_template ( name, p, "_R_"); + sprintf (R->template_format , "fasta_aln"); + + + if (!is_aln(R->template_name) && !is_seq (R->template_name)) + { + + add_information ( stderr, "_R_ Template %s Could Not Be Found\n",R->template_name); + free_X_template (R); + return NULL; + } + else + { + int s; + Sequence *S1; + Alignment *A1; + + (R->VR)->A=main_read_aln (R->template_name, NULL); + + if ( !S) + sprintf ( R->template_file, "%s", R->template_name); + else + { + s=name_is_in_list(name, S->name, S->nseq, 100); + if ( s!=-1) + { + S1=fill_sequence_struc (1, &S->seq[s], &S->name[s]); + A1=seq2aln (S1,NULL, RM_GAP); + + (R->VR)->A=trim_aln_with_seq (A1, (R->VR)->A); + + sprintf ( R->template_file, "%s", vtmpnam (NULL)); + output_clustal_aln (R->template_file, (R->VR)->A); + } + else + sprintf ( R->template_file, "%s", R->template_name); + } + (R->VR)->A=aln2profile ((R->VR)->A); + + //free_data_in_aln ((R->VR)->A); + + } + return R; +} + +struct X_template *fill_T_template ( char *name,char *p, Sequence *S) +{ + /*Profile template*/ + struct X_template *T; + + T=fill_X_template ( name, p, "_T_"); + sprintf (T->template_format , "fasta_seq"); + + if (!is_aln(T->template_name) && !is_seq (T->template_name)) + { + + add_information ( stderr, "_T_ Template %s Could Not Be Found\n",T->template_name); + free_X_template (T); + return NULL; + } + else + { + + (T->VT)->S=main_read_seq(T->template_name); + sprintf ( T->template_file, "%s", T->template_name); + } + return T; +} +//add template +struct X_template *fill_U_template ( char *name,char *p, Sequence *S) +{ + /*Profile template*/ + struct X_template *U; + + U=fill_X_template ( name, p, "_U_"); + sprintf (U->template_format , "string list"); + + if (!check_file_exists(U->template_name)) + { + add_information ( stderr, "_U_ Template %s Could Not Be Found\n",U->template_name); + free_X_template (U); + return NULL; + } + else + { + //(U->VU)->list=file2string(U->template_name); + sprintf ( U->template_file, "%s", U->template_name); + } + return U; +} +struct X_template *fill_E_template ( char *name,char *p, Sequence *S) +{ + /*Profile template*/ + struct X_template *E; + + + E=fill_X_template ( name, p, "_E_"); + sprintf (E->template_format , "fasta_seq"); + + if (!is_aln(E->template_name) && !is_seq (E->template_name)) + { + + add_information ( stderr, "_E_ Template %s Could Not Be Found\n",E->template_name); + free_X_template (E); + return NULL; + } + else + { + (E->VE)->S=main_read_seq (E->template_name); + sprintf ( E->template_file, "%s", E->template_name); + } + return E; +} +struct X_template *fill_G_template ( char *name,char *p, Sequence *S) +{ + struct X_template *G; + G=fill_X_template ( name, p, "_G_"); + sprintf (G->template_format , "fasta_seq"); + + /*1: Get the sequence from another file if needed*/ + if ( strm (name, p))sprintf ( G->template_file, "%s",output_fasta_seqX (NULL,"w",S,NULL, seq_name2index (name, S))); + else if ( strstr (p, "SEQFILE_")) + { + Sequence *ST; + int i2; + + + ST=main_read_seq (after_strstr ( p,"SEQFILE_G_")); + + i2=seq_name2index (name, ST); + if ( i2!=-1) + { + sprintf ( G->template_file, "%s",output_fasta_seqX (NULL,"w",ST,NULL, i2)); + sprintf ( G->template_name, "%s", name); + } + free_sequence (ST, -1); + } + else sprintf (G->template_file, "%s", G->template_name); + + + /*2: Put the template in VG->S*/ + if (!is_seq (G->template_file)) + { + add_information ( stderr, "_G_ Template %s Could Not Be Found \n",p); + + free_X_template (G); + return NULL; + } + else + { + (G->VG)->S=get_fasta_sequence (G->template_file, NULL); + } + return G; +} + + +char *seq2T_value ( Sequence *S, int n, char *value, char *type) +{ + static char *rv_buf; + X_template *X; + + if ( !rv_buf)rv_buf=vcalloc (100, sizeof(char)); + if (!(X=seq_has_template (S, n, type)))return NULL; + else + { + if (strm (value, "template_file"))return X->template_file; + else if ( strm (value, "template_name"))return X->template_name; + else if ( strm (value, "seq_name"))return X->seq_name; + else if (strm (type, "_P_")) + { + if ( strm (value, "pdb_id"))return (X->VP)->pdb_id; + } + else if ( strm (type, "_R_")) + { + if ( strm (value, "A")) + { + if ((X->VR)->A) + {sprintf ( rv_buf, "%ld", (long)(X->VR)->A);return rv_buf;} + else return NULL; + } + } + + } + return NULL; +} +char *seq2P_pdb_id (Sequence *S, int n) +{ + if (!S->T || !S->T[n] || !(S->T[n])->P ) return NULL; + else return ((S->T[n])->P)->template_name; +} + + +char *seq2P_template_file(Sequence *S, int n) +{ + + return seq2T_value (S, n, "template_file", "_P_"); +} + +char *profile2P_template_file (Sequence *S, int n) +{ + Alignment *A; + int a; + char *p; + + if ( !(A=seq2R_template_profile (S, n)))return NULL; + for (a=0; anseq; a++) + { + if ((p=seq2P_template_file (A->S, a))!=NULL)return p; + } + return NULL; +} +Alignment * seq2R_template_profile (Sequence *S, int n) +{ + X_template *X; + + return (Alignment *)atop(seq2T_value (S, n, "A", "_R_")); + + if (!(X=seq_has_template (S, n, "_R_")))return NULL; + else + { + if (!(X->VR))return NULL; + else return (X->VR)->A; + } + return NULL; + + + +} +char * seq2E_template_string (Sequence *S, int n) +{ + struct X_template *T; + + if ( (T=seq_has_template (S, n, "_E_"))!=NULL) + return ((T->VE)->S)->seq[0]; + else + return NULL; +} +//add template +int* seq2U_template (Sequence *S, int n) +{ + struct X_template *T; + + if ( (T=seq_has_template (S, n, "_U_"))!=NULL) + return (T->VU)->list; + else + return NULL; +} +char * seq2T_template_string (Sequence *S, int n) +{ + struct X_template *T; + + if ( (T=seq_has_template (S, n, "_T_"))!=NULL) + return ((T->VT)->S)->seq[0]; + else + return NULL; +} + +struct X_template* seq_has_template ( Sequence *S, int n, char *mode) +{ + Template *T; + + if ( !S || !mode) return NULL; + else if ( n<0 || n>=S->nseq)return NULL; + else if ( !(S->T)) return NULL; + else if ( !(S->T[n]))return NULL; + + T=S->T[n]; + //ADD STRUCTURE + //add template + if ( strm (mode, "_P_"))return T->P; + else if ( strm (mode, "_F_"))return T->F; + else if ( strm (mode, "_S_"))return T->S; + else if ( strm (mode, "_R_"))return T->R; + else if ( strm (mode, "_T_"))return T->T; + else if ( strm (mode, "_E_"))return T->E; + else if ( strm (mode, "_U_"))return T->U; + else if ( strm (mode, "_G_"))return T->G; + else return NULL; +} + +char ** name2random_subset (char **in_name, int n_in, int n_out) +{ + char **out_name; + + int **list; + int a,max; + + + vsrand (0); + max=n_in*10000; + out_name=declare_char (n_out,MAXNAMES+1 ); + list=declare_int (n_in, 2); + + for (a=0; aname, A->nseq, A->nseq); + A=reorder_aln (A, name_list, A->nseq); + free_char (name_list, -1); + return A; +} +Alignment *aln2jacknife (Alignment *A, int nseq, int len) +{ + int a, b; + + if (nseq!=0 && nseqnseq) + { + char **name; + + name=name2random_subset (A->name, A->nseq, nseq); + A=reorder_aln (A, name, nseq); + free_char (name, -1); + } + + if (len!=0 && lenlen_aln) + { + int **l; + Alignment *B; + + l=declare_int (A->len_aln, 2); + for (a=0; a< A->len_aln; a++) + { + l[a][0]=a; + l[a][1]=rand()%(A->len_aln*1000); + } + sort_int ( l,2, 1, 0, A->len_aln-1); + B=copy_aln (A, NULL); + for ( a=0; a< len; a++) + { + for ( b=0; bnseq; b++) + { + A->seq_al[b][a]=B->seq_al[b][l[a][0]]; + } + } + for (b=0; bnseq; b++)A->seq_al[b][len]='\0'; + free_aln (B); + free_int (l, -1); + } + return A; +} +Alignment * aln2scramble_seq (Alignment *A) +{ + int **list; + char **name_list; + int a,max; + + max=100*A->nseq; + vsrand (0); + + list=declare_int (A->nseq, 2); + name_list=vcalloc (A->nseq, sizeof (char*)); + + + for (a=0; anseq; a++) + { + list[a][0]=a; + list[a][1]=rand ()%max; + } + sort_int ( list,2, 1, 0, A->nseq-1); + + for ( a=0; a< A->nseq; a++) + name_list[a]=A->seq_al[a]; + for (a=0; anseq; a++) + { + A->seq_al[a]=name_list[list[a][0]]; + } + vfree (name_list); + free_int (list, -1); + return aln2random_order (A); +} + + + +Alignment * reorder_aln ( Alignment *A, char **name, int nseq) + { + int a,sn; + Alignment *BUF; + int n=0; + int *tpp_int; + + if ( name==NULL)return aln2random_order(A); + + + BUF=copy_aln ( A,NULL); + for ( a=0; aname, A->nseq,STRING); + if ( sn==-1) + { + ; + } + else + { + + + SWAPP(A->order[n], BUF->order[sn], tpp_int); + sprintf ( A->name[n], "%s", BUF->name[sn]); + sprintf ( A->seq_al[n], "%s",BUF->seq_al[sn]); + sprintf ( A->seq_comment[n], "%s", BUF->seq_comment[sn]); + + n++; + + } + } + + for ( a=n; a< A->nseq; a++)A->name[a][0]=A->seq_al[a][0]='\0'; + A->nseq=n; + + if ( A->A)A->A=reorder_aln(A->A, name, nseq); + free_aln (BUF); + return A; + } +Sequence * reorder_seq_2 ( Sequence *A, int **order,int field, int nseq) + { + char **name; + int a; + + if (!A || !order) return A; + name=declare_char (A->nseq, 100); + for (a=0; aname[order[a][field]]); + A=reorder_seq (A, name,nseq); + free_char (name, -1); + return A; + } +Sequence * reorder_seq ( Sequence *A, char **name, int nseq) + { + int a,sn; + Sequence *nA; + + + nA=duplicate_sequence (A); + + + for ( a=0; a< nseq; a++) + { + sn=name_is_in_list (name[a] ,nA->name, nA->nseq, 100); + if (sn==-1)continue; + + if ( nA->file) sprintf ( A->file[a], "%s", nA->file[sn]); + + if ( nA->seq_comment)sprintf ( A->seq_comment[a], "%s", nA->seq_comment[sn]); + if ( nA->aln_comment)sprintf ( A->aln_comment[a], "%s", nA->aln_comment[sn]); + sprintf ( A->seq[a], "%s", nA->seq[sn]); + A->len[a]=nA->len[sn]; + sprintf ( A->name[a], "%s", nA->name[sn]); + A->T[a][0]=nA->T[sn][0]; + } + A->nseq=nseq; + free_sequence (nA, nA->nseq); + + return A; +} + +char * concatenate_seq ( Sequence *S, char *conc, int *order) + { + int a; + + vfree (conc); + conc=vcalloc ( S->nseq*S->max_len, sizeof (char)); + + for ( a=0; a< S->nseq; a++) + { + conc=strcat ( conc, S->seq[order[a]]); + } + return conc; + + } + + + + +Alignment * rotate_aln ( Alignment *A, char *name) +{ + Alignment *B; + int a, b; + + B=declare_aln2 (A->len_aln, A->nseq+1); + for ( a=0; a< A->nseq; a++) + for ( b=0; b< A->len_aln; b++) + { + B->seq_al[b][a]=A->seq_al[a][b]; + } + for (a=0; a< A->len_aln; a++) + if (name && name[0])sprintf ( B->name[a], "%s_%s%d", name, (a<9)?"0":"",a+1); + else + sprintf ( B->name[a], "%d", a+1); + + + for (a=0; a< A->len_aln; a++)B->seq_al[a][A->nseq]='\0'; + B->len_aln=A->nseq; + B->nseq=A->len_aln; + /*free_aln (A);*/ + return B; +} + +Alignment * invert_aln ( Alignment *A) +{ + char *buf; + int l, a, b, c; + + for ( a=0; a< A->nseq; a++) + { + l=strlen ( A->seq_al[a]); + buf=vcalloc ( l+1,sizeof (char) ); + + for ( c=l-1,b=0; b< l; b++, c--) + { + buf[c]=A->seq_al[a][b]; + } + buf[l]='\0'; + sprintf ( A->seq_al[a], "%s", buf); + } + vfree(buf); + return A; +} +char * complement_string (char *s) +{ + char *buf; + int l, a, b, c; + + l=strlen (s); + for ( b=0; b< l; b++) + { + char r; + r=s[b]; + if ( r=='a')r='t'; + else if (r=='A')r='T'; + else if (r=='t')r='a'; + else if (r=='T')r='A'; + else if (r=='g')r='c'; + else if (r=='G')r='C'; + else if (r=='c')r='g'; + else if (r=='C')r='G'; + s[b]=r; + } + + return invert_string (s); +} +Alignment * complement_aln ( Alignment *A) +{ + char *buf; + int l, a, b, c; + + for ( a=0; a< A->nseq; a++) + { + A->seq_al[a]=complement_string (A->seq_al[a]); + } + + return A; +} + +Alignment * extract_nol_local_aln(Alignment *A, int start, int max_end) + { + A=extract_aln ( A, start, max_end); + A=trunkate_local_aln (A); + return A; + } + +Alignment * alnpos_list2block (Alignment *A, int n, char **in_list) +{ + int *pos; + int a; + char **list; + int list_declared=0; + Alignment *B; + + if (check_file_exists (in_list[0])) + { + int mn; + char ***tmp_list; + + mn=count_n_line_in_file (in_list[0]); + list=declare_char (mn, 100); + list_declared=1; + tmp_list=file2list (in_list[0], " "); + a=0; + n=0; + while (tmp_list[a]) + { + if (tmp_list[a][1][0]!='!') + { + sprintf (list[n++], "%s", tmp_list[a][1]); + } + a++; + } + free_arrayN ((void **)tmp_list, 3); + } + else + { + list=in_list; + } + + + pos=vcalloc (A->len_aln, sizeof (int)); + for (a=0; a=end || end>A->len_aln+1) + { + add_warning ( stderr, "Illegal coordinates in extract_pos_list [%s]", list[a]); + return A; + } + start--; end--; + for (a=start; aA->len_aln) + { + add_warning ( stderr, "Illegal coordinates in extract_pos_list [%s]", list[a]); + } + p--; + pos[p]=1; + } + } + B=alnpos2block(A, pos, NULL); + vfree (pos); + if ( list_declared)free_char (list, -1); + + return B; +} +Alignment * aln2block (Alignment *A, int start, int end, Alignment *B) +{ + if ( !A || start<=0 || start>=end || end>A->len_aln+1) + { + add_warning ( stderr, "Illegal coordinates in extract_block start=%d end=%d len=%d [Note : [start-end[, with [1...n] ** Block Ingored", start, end, A->len_aln); + return A; + } + else + { + int *pos, p; + start--; + end--; + pos=vcalloc (A->len_aln, sizeof (int)); + for (p=start;plen_aln=0; + for (a=0; a<=A->len_aln; a++) + { + if ( pos[a]!=0 || a==A->len_aln) + { + for ( b=0; bnseq; b++) + B->seq_al[b][B->len_aln]=A->seq_al[b][a]; + if ( a!=A->len_aln)B->len_aln++; + } + } + + return B; +} +Alignment * extract_aln ( Alignment *A, int start, int end) +{ + return extract_aln2 ( A, start, end, "cons"); +} + +Alignment * extract_aln2 ( Alignment *A, int in_start, int in_end, char *seq) + { + char *tmp; + FILE *fp; + + + tmp=vtmpnam (NULL); + fp=vfopen (tmp, "w"); + fprintf ( fp, "%s %d %d\n", seq, in_start, in_end); + vfclose (fp); + return extract_aln3 (A,tmp); + } +Alignment * extract_aln3 ( Alignment *B, char *file) + { + int a, b, c; + int start, end; + int n, i, s, nline=0; + FILE *fp; + Alignment *A=NULL; + int *col; + char name[MAXNAMES]; + char line[VERY_LONG_STRING]; + int *offset; + + /*Reads in a file + #comment + ! seq_name offset + seqname pos + OR + seqname start end[ + modifies the incoming alignment + */ + + offset=vcalloc ( B->nseq+1, sizeof (int)); + fp=vfopen (file,"r"); + while ( (c=fgetc(fp))!=EOF) + { + s=-1; + fgets ( line, VERY_LONG_STRING,fp); + if ( c=='!') + { + sscanf (line, "%s %d", name, &start); + s=name_is_in_list (name,B->name,B->nseq,MAXNAMES); + } + if (s!=-1) + offset[s]=start; + } + + vfclose (fp); + + A=copy_aln (B, A); + col=vcalloc ( A->len_aln, sizeof (int)); + + fp=vfopen ( file, "r"); + while ( (c=fgetc(fp))!=EOF) + { + nline++; + if ( c=='#' || c=='!')fgets ( line, VERY_LONG_STRING,fp); + else + { + ungetc(c, fp); + fgets ( line, VERY_LONG_STRING,fp); + + if (sscanf (line, "%s %d %d", name, &start, &end)==3); + else if (sscanf (line, "%s %d", name, &start)==2) + { + end=start+1; + } + else + { + add_warning ( stderr, "Wrong format in coordinate file (line=%d) ** Line Ignored", nline); + continue; + } + if ( end==0)end=A->len_aln+1; + + s=name_is_in_list (name,A->name,A->nseq,MAXNAMES); + + + if ( s==-1 && !strm (name, "cons")) + { + add_warning ( stderr, "Seq %s does not belong to the alignment (line %d) ** Line ignored", name,nline); + continue; + } + else if ( start>end) + { + add_warning ( stderr, "Illegal coordinates [%s %d %d] (line %d) ** Line ignored", name,start, end,nline); + continue; + } + else + { + int done=0; + if ( s!=-1) + { + start-=offset[s]-1; + end-=offset[s]-1; + } + for (n=0, a=0; done!=1 && a< A->len_aln; a++) + { + i=(strm (name, "cons"))?1:!is_gap(A->seq_al[s][a]); + + n+=i; + if (n>=start && n=end)done=1; + //if (n>=start && n=end)a=A->len_aln; + } + if ( done==0) + { + HERE ("Warning Missing positions in File %s",file ); + } + } + } + } + vfclose ( fp); + + + + /*Extract [start-end[*/ + for ( b=0,a=0; a< A->len_aln; a++) + { + if ( col[a]) + { + for (c=0; c< A->nseq; c++)A->seq_al[c][b]=A->seq_al[c][a]; + b++; + } + } + A->len_aln=b; + + for (c=0; c< A->nseq; c++)A->seq_al[c][A->len_aln]='\0'; + vfree (col); + + return A; + + } +Alignment * trunkate_local_aln ( Alignment *A) + { + int a, b; + int **pos; + int **cache; + int seq; + + + cache=declare_int (return_max_int (A->order,read_size_int ( A->order,sizeof (int*)),0)+1,return_max_int (A->order,read_size_int ( A->order,sizeof (int*)),1)+A->len_aln+1); + pos=aln2pos_simple(A,A->nseq); + + for ( b=0; blen_aln; b++) + for ( a=0; a< A->nseq; a++) + { + seq=A->order[a][0]; + if ( pos[a][b]<=0); + else if ( pos[a][b]>0) + { + + if (cache[seq][pos[a][b]]==0)cache[seq][pos[a][b]]++; + else if ( cache[seq][pos[a][b]]>=1) + { + cache[seq][pos[a][b]]++; + A->seq_al[a][b]='\0'; + } + } + } + + A->len_aln=get_shortest_string ( A->seq_al, A->nseq, NULL, NULL); + pad_string_array ( A->seq_al, A->nseq, A->len_aln, '-'); + + free_int (pos, -1); + free_int ( cache,-1); + + + return A; + } + +int get_nol_aln_border ( Alignment *A, int start, int direction) + { + int a, b; + int **pos; + int **cache; + int seq,end; + + /*This Function Returns the limit position for a non overlaping alignment*/ + + cache=declare_int (return_max_int (A->order,read_size_int ( A->order,sizeof (int*)),0)+1,return_max_int (A->order,read_size_int ( A->order,sizeof (int)),1)+A->len_aln+1); + pos=aln2pos_simple(A,A->nseq); + end=(direction==GO_RIGHT)?A->len_aln:-1; + + + for ( b=start; b!=end;b+=direction) + for ( a=0; a< A->nseq; a++) + { + seq=A->order[a][0]; + if ( pos[a][b]<=0); + else if ( pos[a][b]>0) + { + + if (cache[seq][pos[a][b]]==0)cache[seq][pos[a][b]]++; + else if ( cache[seq][pos[a][b]]>=1) + { + cache[seq][pos[a][b]]++; + free_int(cache, -1); + return b-direction; + } + } + } + + free_int ( cache,-1); + free_int (pos, -1); + return end-direction; + } + + + + + +char * extract_defined_seq ( char *in, int in_of, int in_start, int *aa_def, int dir, int *out_start, char *out) + { + int start=0, end,l; + int b, c, d; + + + + if ( dir==GO_LEFT){start=in_start-1;} + else if ( dir==GO_RIGHT){start=in_start+1;} + + end=start; + while (aa_def[end]!=UNDEFINED) + { + end+=dir; + } + end-=dir; + + if (end=start && c<=end) + { + if ( out_start[0]==-1)out_start[0]=c-!is_gap(in[b]); + out[d++]=in[b]; + } + } + out[d]='\0'; + + + return out; + } + +Alignment * aln2N_replicate (Alignment *A,char *nn, char *name) +{ + int a, n; + char *fname; + + fname=vcalloc (100, sizeof (char)); + if (nn)n=atoi(nn); + else n=100; + if (!name){name=vcalloc (100, sizeof (char)); sprintf (name, "replicate");} + + + for (a=0; a< n;a++) + { + FILE *fp; + sprintf (fname, "%s.%d.rep",name, a+1); + fp=vfopen (fname, "w"); + + vfclose(aln2replicate (A, fp)); + fprintf ( stdout, ">%s Alignment Replicate #%d\n",fname, a+1); + } + myexit (EXIT_SUCCESS); +} +FILE *aln2replicate (Alignment *A, FILE *fp) +{ + int a, b; + int *p; + float tot=0; + float corr; + if (A->col_weight)for (a=0; alen_aln; a++)tot+=A->col_weight[a]; + else tot=A->len_aln; + + p=vcalloc (A->len_aln, sizeof (int)); + corr=(float)A->len_aln/tot; + + for (a=0; alen_aln; a++) + { + int x; + x=rand()%(int)tot; + + p[a]=(int)(x*corr); + } + + for (a=0; anseq; a++) + { + fprintf ( fp, ">%s\n", A->name[a]); + //for (b=0;blen_aln; b++)fprintf ( stdout, "%d ", (int)p[b]); + for (b=0;blen_aln; b++)fprintf ( fp, "%c", A->seq_al[a][p[b]]); + fprintf ( fp, "\n"); + } + + vfree (p); + return fp; +} + +Alignment * orthologous_concatenate_aln (Alignment *A, Sequence *S, char *mode) +{ + Alignment *C; + char **name, *cname; + int nname=0; + int a, b,c, i; + + if (mode && strm (mode, "voronoi"))seq_weight2species_weight (A, S); + + + cname=vcalloc ( 100, sizeof (char)); + name=declare_char (A->nseq, 100); + for (a=0; anseq; a++) + { + char *p=strstr (A->name[a], "_"); + if (!p) + { + fprintf ( stderr, "\nWARNING: Seq %s could not be included.", A->name[a]); + } + p+=1; + if ( name_is_in_list (p, name,nname, 100)==-1) + { + sprintf ( name[nname++], "%s", p); + } + } + + C=declare_aln2 (nname, (A->len_aln*S->nseq)+1); + free_char (C->name,-1); C->name=name; + C->nseq=nname; + C->col_weight=vcalloc ( A->len_aln*S->nseq, sizeof(float)); + + C->len_aln=0; + for (a=0; anseq; a++) + { + for (b=0; bnseq; b++) + { + sprintf (cname, "%s_%s", S->name[a],C->name[b]); + if ((i=name_is_in_list (cname, A->name, A->nseq, 100))==-1) + { + char *s=generate_null (A->len_aln); + strcat (C->seq_al[b], s); + vfree (s); + } + else + strcat (C->seq_al[b], A->seq_al[i]); + } + for (c=C->len_aln, b=0;blen_aln;b++, c++) + { + C->col_weight[c]=(S->W)->SEQ_W[a]; + } + C->len_aln+=A->len_aln; + } + return C; +} + + +Alignment * concatenate_aln ( Alignment *A1, Alignment *A2, char *spacer) +{ + Alignment *A; + int a, i; + + A=declare_aln2( A1->nseq+A2->nseq , A1->len_aln+A2->len_aln+1); + for ( a=0; a< A1->nseq; a++) + { + if ((i=name_is_in_list ( A1->name[a], A2->name, A2->nseq, 100))!=-1) + { + sprintf ( A->name[A->nseq], "%s", A1->name[a]); + sprintf (A->seq_al[A->nseq], "%s%s%s", A1->seq_al[a],(spacer)?spacer:"", A2->seq_al[i]); + A->nseq++; + } + else + { + char *buf; + buf=generate_string (A2->len_aln, '-'); + sprintf ( A->name[A->nseq], "%s", A1->name[a]); + sprintf (A->seq_al[A->nseq], "%s%s", A1->seq_al[a], buf); + A->nseq++; + vfree (buf); + } + } + for ( a=0; a< A2->nseq; a++) + { + if ((i=name_is_in_list ( A2->name[a], A1->name, A1->nseq, 100))==-1) + { + char *buf; + buf=generate_string (A1->len_aln, '-'); + sprintf ( A->name[A->nseq], "%s", A2->name[a]); + sprintf (A->seq_al[A->nseq], "%s%s", buf, A2->seq_al[a]); + A->nseq++; + vfree (buf); + } + } + A->len_aln=A1->len_aln+A2->len_aln; + return A; +} +Alignment * aln_cat ( Alignment *A, Alignment *B) + { + int a; + + if ( A->nseq!=B->nseq) + { + fprintf ( stderr, "\nERROR IN ALN CAT: DIFFERENT NSEQ\n"); + myexit(EXIT_FAILURE); + } + + A=realloc_alignment2(A, A->nseq,A->len_aln+B->len_aln+1); + + for ( a=0;a< A->nseq; a++) + { + strcat ( A->seq_al[a], B->seq_al[a]); + } + A->len_aln+=B->len_aln; + return A; + } +int verify_aln ( Alignment *A, Sequence *S, char *message) + { + int a, b, c,s,r; + + + for ( a=0;a< A->nseq; a++) + { + s=A->order[a][0]; + r=A->order[a][1]; + for ( b=0, c=0; b< A->len_aln; b++) + { + if ( !is_gap(A->seq_al[a][b])) + { + if (tolower(A->seq_al[a][b])!=tolower(S->seq[s][c+r])) + { + fprintf ( stderr, "\n%s\nResidue [%c %d, %c %d] line %d seq %d",message,A->seq_al[a][b], b,S->seq[s][c+r], c+r,a,s); + output_Alignment_with_res_number(A, stderr); + myexit(EXIT_FAILURE); + return 0; + } + c++; + } + } + } + return 1; + } + +Alignment *adjust_est_aln ( Alignment *PW, Alignment *M, int s) +{ + /*This function reajusts M, threading M onto PW + two seqences in PW + s+1 seq in M + + seq 0 PW ----> 0->s-1 in M + seq 1 PW ----> 1->s in M; + + */ + int a, b; + static char **array; + + + int top_M=0; + int bottom_M=0; + + + if ( array==NULL) + { + array=declare_char (500, 100000); + } + + for ( a=0; a< PW->len_aln; a++) + { + if ( is_gap(PW->seq_al[0][a])) + { + for ( b=0; b< s; b++) + array[b][a]='-'; + } + else + { + for ( b=0; b< s; b++) + array[b][a]=M->seq_al[b][top_M]; + top_M++; + } + + if ( is_gap(PW->seq_al[1][a])) + { + array[s][a]='-'; + } + else + { + + array[s][a]=M->seq_al[s][bottom_M]; + bottom_M++; + } + } + + M->len_aln=PW->len_aln; + for (a=0; alen_aln; b++) + M->seq_al[a][b]=array[a][b]; + M->seq_al[a][b]='\0'; + } + + + M->nseq=s+1; + + return M; +} + + +Alignment * rename_seq_in_aln (Alignment *A, char ***list) +{ + int n, i; + if ( !A)return A; + + + + n=0; + while ( list[n][0][0]) + { + if ( (i=name_is_in_list (list[n][0], A->name, A->nseq, 100))!=-1) + { + sprintf ( A->name[i], "%s", list[n][1]); + } + n++; + } + + A->S=rename_seq_in_seq (A->S, list); + return A; +} +Sequence * rename_seq_in_seq (Sequence *A, char ***list) +{ + int n, i; + if ( !A || !list)return A; + + n=0; + while ( list[n][0][0]) + { + if ( (i=name_is_in_list (list[n][0], A->name, A->nseq, 100))!=-1) + { + sprintf ( A->name[i], "%s", list[n][1]); + } + n++; + } + return A; +} +/********************************************************************/ +/* */ +/* FLOAT SIMILARITIES */ +/* */ +/* */ +/* */ +/********************************************************************/ +float get_seq_fsim ( char *string1, char *string2, char *ignore, char *similarity_set,int **matrix, int MODE ) + { + int len, a, r1, r2, nr1=0, nr2=0; + float pos=0, sim=0; + + + len=MIN((strlen (string1)),(strlen (string2))); + if ( len==0)return 0; + + for ( a=0; a< len; a++) + { + + r1=string1[a]; + r2=string2[a]; + nr1+=!is_gap(r1); + nr2+=!is_gap(r2); + + if ( !is_in_set (r1, ignore) && !is_in_set (r2, ignore)) + { + pos++; + if ( matrix)sim+=matrix[r1-'A'][r2-'A']; + else if (is_in_same_group_aa(r1,r2,0, NULL,similarity_set)) + { + sim++; + } + } + } + if ( MODE==UNGAPED_POSITIONS)return ( sim*100)/pos; + else if ( MODE==ALIGNED_POSITIONS)return (sim*100)/len; + else if ( MODE==AVERAGE_POSITIONS)return (sim*200)/(nr1+nr2); + else + { + return 0; + } + + } +float get_seq_fsim2 ( char *string1, char *string2, char *ignore, char *in_mode) + { + int len1; + int a; + int p1, p2; + int r1=0,r2=0; + char *p; + char mode[1000]; + float r=0, pos1, pos2, pos0, gap, sim; + + + sprintf ( mode, "%s", in_mode); + + /*mode: __ + mat: idscore to get the alignment done + any legal cw matrix + sim_mode: sim1->identities/matches + sim2->identities/min len + */ + + + if ( (p=strstr (mode, "_"))!=NULL) + { + p[0]='\0'; + p++; + } + + + if (strstr (mode, "idscore")) + { + static int **mat; + if (!mat) mat=read_matrice ("blosum62mt"); + return idscore_pairseq (string1, string2, -12, -1, mat,mode); + + } + + len1=strlen (string1); + for ( sim=pos1=pos2=pos0=gap=0,a=0; a< len1; a++) + { + r1=string1[a]; + r2=string2[a]; + p1=1-is_in_set (r1, ignore); + p2=1-is_in_set (r2, ignore); + pos1+=p1; pos2+=p2; + if (p1 && p2) + { + pos0++; + if (is_in_same_group_aa(r1,r2,0, NULL, mode)) + { + sim++; + } + } + else if (p1+p2==1) + { + gap++; + } + } + + if ( p==NULL || strm (p, "sim1") || strm (p, "sim")) + { + r=(pos0==0)?0:(sim*MAXID)/pos0; + } + else if ( strm (p, "sim2")) + { + r=(pos1==0 || pos2==0)?0:(sim*MAXID)/MIN(pos1,pos2); + } + else if ( strm (p, "sim3")) + { + r=(pos1==0 || pos2==0)?0:(sim*MAXID)/MAX(pos1,pos2); + } + else if ( strm (p, "gap1")) + { + r=(len1==0)?MAXID:(gap*MAXID)/len1; + r=MAXID-r; + } + else if ( strm (p, "logid")) + { + r=logid_score (pos0, sim); + } + + return r; + + } + +/********************************************************************/ +/* */ +/* ALIGNMENT ANALYSES */ +/* */ +/* */ +/* */ +/********************************************************************/ +int **dist_array2sim_array ( int **p, int max) +{ + int s1, s2, a, b; + s1=read_array_size ((void *)p, sizeof (void *)); + s2=read_array_size ((void*)p[0],sizeof (int)); + /* s2=read_array_size ((void*)p[0],sizeof (void *)); OLD before 64 BITS*/ + for ( a=0; a< s1; a++) + for ( b=0; b< s2; b++) + { + p[a][b]=max-p[a][b]; + } + return p; +} + +int **sim_array2dist_array ( int **p, int max) +{ + int s1, s2, a, b; + s1=read_array_size ((void *)p, sizeof (void *)); + s2=read_array_size ((void*)p[0],sizeof (int)); + + /*s2=read_array_size ((void*)p[0],sizeof (void *)); OLD before 64 Bits stuff*/ + for ( a=0; a< s1; a++) + for ( b=0; b< s2; b++) + { + p[a][b]=max-(int)p[a][b]; + } + return p; +} + +int **normalize_array (int **p, int max, int norm) +{ +int s1, s2, a, b; + s1=read_array_size ((void *)p, sizeof (void *)); + s2=read_array_size ((void*)p[0],sizeof (int)); + + /*s2=read_array_size ((void*)p[0],sizeof (void *)); OLD before 64 Bits stuff*/ + for ( a=0; a< s1; a++) + for ( b=0; b< s2; b++) + { + p[a][b]=(p[a][b]*norm)/max; + } + return p; +} + +int aln2most_similar_sequence ( Alignment *A, char *mode) +{ + int **w; + int a, b; + int avg, best_avg=0, best_seq=0; + char *buf; + int coverage; + + + if ( !A) return -1; + else if ( A->nseq==1)return 0; + else + { + buf=vcalloc ( A->len_aln+1, sizeof (char)); + w=get_sim_aln_array ( A, mode); + + for ( a=0; a< A->nseq; a++) + { + sprintf ( buf, "%s", A->seq_al[a]); + ungap(buf); + coverage=(strlen(buf)*MAXID)/A->len_aln; + + for ( avg=0,b=0; b< A->nseq; b++)avg+=w[a][b]*coverage; + if ( avg>best_avg){best_avg=avg; best_seq=a;} + } + free_int (w, -1); + vfree (buf); + return best_seq; + } + +} + +int aln2coverage ( Alignment *A, int ref_seq) +{ + int a,b; + int cov_pos=0, npos=0; + + + for ( a=0; a< A->len_aln; a++) + { + if ( !is_gap ( A->seq_al[ref_seq][a])) + { + npos++; + for ( b=0; b< A->nseq; b++) + { + if ( b!=ref_seq && !is_gap ( A->seq_al[b][a])){cov_pos++;break;} + } + } + } + + return (int) (npos==0)?0:(( MAXID*cov_pos)/npos); +} + + +int sub_aln2sim ( Alignment *A, int *ns, int **ls, char *mode) +{ + int a, b, n; + float avg; + + n=0; avg=0; + if (!A || (ns==NULL && A->nseq<2))return -1; + else if (ns==NULL) + { + for (a=0; a< A->nseq-1; a++) + for ( b=a+1; b< A->nseq;b++, n++) + avg+=generic_get_seq_sim (A->seq_al[a], A->seq_al[b], NULL, mode); + } + else + { + for (a=0; aseq_al[ls[0][a]], A->seq_al[ls[1][b]], NULL, mode); + } + } + return (int)(n==0)?0:((float)avg/(float)n); +} +int sub_aln2max_sim ( Alignment *A, int *ns, int **ls, char *mode) +{ + int a, b, n; + float avg; + + n=0; avg=0; + if (!A || (ns==NULL && A->nseq<2))return -1; + else if (ns==NULL) + { + for (a=0; a< A->nseq-1; a++) + for ( b=a+1; b< A->nseq;b++, n++) + avg=MAX(avg,generic_get_seq_sim (A->seq_al[a], A->seq_al[b], NULL, mode)); + } + else + { + for (a=0; aseq_al[ls[0][a]], A->seq_al[ls[1][b]], NULL, mode)); + } + } + return avg; +} + + +double aln2entropy (Alignment *A, int *in_ls, int in_ns, float gap_threshold) +{ + int ns, a, s, col, r,ncol; + int *ls; + double *count; + double entropy=0; + float ng; + + ls=vcalloc ( A->nseq, sizeof (int)); + count=vcalloc ( 26, sizeof (double)); + + + if ( in_ls) + { + ns=in_ns; + for ( a=0; a< ns; a++)ls[a]=in_ls[a]; + } + else + { + ns=A->nseq; + for ( a=0; a< ns; a++)ls[a]=a; + } + + if ( ns==0) + { + vfree(ls);vfree(count);return 0; + } + for (ncol=0,col=0; collen_aln; col++) + { + for (ng=0,a=0; a< ns; a++) + { + s=ls[a]; + ng+=is_gap(A->seq_al[s][col]); + } + ng/=ns; + if ( ng>gap_threshold)continue; + + ncol++; + + for ( a=0; aseq_al[s][col]); + if (!is_gap(r))count[r-'a']++; + } + for (a=0; a<26; a++) + { + if ( count[a]==0); + else + { + count[a]/=(double)ns; + + entropy+=count[a]*log(count[a]); + count[a]=0; + } + } + } + entropy/=-ncol; + vfree (ls); vfree(count); + + return entropy; +} +int aln2sim ( Alignment *A, char *mode) +{ + return sub_aln2sim ( A, NULL, NULL, mode); + /* + if ( !A || A->nseq<2) return -1; + w=get_sim_aln_array ( A, mode); + + for (c=0, a=0; a< A->nseq-1; a++) + for ( b=a+1; b< A->nseq; b++, c++) + { + avg+=(float)w[a][b]; + } + free_int (w, -1); + return (int)((float)avg/(float)c); + */ +} + +int aln_is_aligned ( Alignment *A) +{ + int a, b; + + if ( !A)return 0; + for (a=0; a< A->nseq; a++) + for ( b=A->len_aln-1; b>0; b--) + { + if (!is_gap(A->seq_al[a][b]) && is_gap(A->seq_al[a][b-1]))return 1; + } + return 0; +} + + +int seq2aln2sim_old ( char *seq1, char *seq2, char *mode_aln, char *mode_id) +{ + Alignment *A; + int sim; + + A=align_two_sequences (seq1, seq2, "pam250mt", -10, -1, mode_aln); + sim=aln2sim (A, mode_id); + free_aln (A); + return sim; +} +int seq2aln2sim ( char *seq1, char *seq2, char *mode_aln, char *mode_id) +{ + Alignment *A; + int sim; + static int gop; + + if (!gop) + { + int **m; + m=read_matrice ("blosum62mt"); + gop=get_avg_matrix_mm(m, AA_ALPHABET)*10; + free_int (m, -1); + } + + A=align_two_sequences (seq1, seq2, "blosum62mt",gop,-1, mode_aln); + sim=aln2sim (A, mode_id); + free_aln (A); + return sim; +} +int* get_cdna_seq_winsim ( int *cache, char *string1, char *string2, char *ignore, char *mode,int *w ) + { + int len1, len2; + int a, x; + + + len1=strlen (string1); + len2=strlen (string2); + + if ( len1!=len2) + { + fatal_exit( stderr,EXIT_FAILURE, "\nTHE TWO cDNAs DO NOT HAVE THE SAME LENGTH [FATAL:get_cdna_seq_sim:%s", PROGRAM); + } + + x=get_cdna_seq_sim(cache, string1, string2, ignore, ""); + for ( a=0; a< len1; a++) + w[a]=x; + + add_warning (stderr, "\nWARNING: winsim not implemented for cDNA"); + return w; + } + +int get_cdna_seq_sim ( int *cache, char *string1, char *string2, char *ignore, char *mode) + { + int len1; + int len2; + int a; + int pos=0; + int sim=0; + char r1=0, r2=0; + + len1=strlen (string1); + len2=strlen (string2); + + + + if ( len1!=len2) + { + fprintf ( stderr, "\nTHE TWO cDNAs DO NOT HAVE THE SAME LENGTH [FATAL:get_cdna_seq_sim:%s", PROGRAM); + crash(""); + } + + for ( a=0; a< len1;) + { + + if ( cache[a]==0){a++;continue;} + else if ( cache[a]==1) + { + + r1=translate_dna_codon (string1+a, 'x'); + r2=translate_dna_codon (string2+a, 'x'); + a+=3; + } + + if ( !is_in_set (r1, ignore) && !is_in_set (r2, ignore)) + { + pos++; + if (is_in_same_group_aa(r1,r2,0, NULL,mode+4)) + { + sim++; + } + } + } + + + + if (pos==0) + return 0; + else + return (int) (sim*MAXID)/pos; + + } + +int* get_seq_winsim ( char *string1, char *string2, char *ignore, char *mode, int*w) + { + int len1, len2, len; + int left, right; + int a,b; + int sim=0; + int window; + int r1, r2; + + len1=strlen (string1); + len2=strlen (string2); + window=atoi(mode); + len=2*window+1; + + if ( len1!=len2)return 0; + if (window==0 || (window*2+1)>=len1) + { + sim=get_seq_sim (string1, string2, ignore, ""); + for (a=0; a__ + mat: idscore to get the alignment done + any legal cw matrix + sim_mode: sim1->identities/matches + sim2->identities/min len + */ + + + if ( (p=strstr (mode, "_"))!=NULL) + { + p[0]='\0'; + p++; + } + + + if (strstr (mode, "idscore")) + { + static int **mat; + if (!mat) mat=read_matrice ("blosum62mt"); + return idscore_pairseq (string1, string2, -12, -1, mat,mode); + + } + len1=strlen (string1); + for ( sim=pos1=pos2=pos0=0,a=0; a< len1; a++) + { + r1=string1[a]; + r2=string2[a]; + p1=1-is_in_set (r1, ignore); + p2=1-is_in_set (r2, ignore); + + pos1+=p1; pos2+=p2; + if (p1 && p2) + { + pos0++; + if (is_in_same_group_aa(r1,r2,0, NULL, mode)) + { + sim++; + } + } + else if (p1+p2==1) + { + gap++; + } + } + + if ( strstr (mode, "cov")) + { + r=(pos0+gap==0)?0:(pos0*MAXID)/(pos0+gap); + } + else if ( p==NULL || strm (p, "sim1") || strm (p, "sim")) + { + r=(pos0==0)?0:(sim*MAXID)/pos0; + } + else if ( strm (p, "sim2")) + { + r=(pos1==0 || pos2==0)?0:(sim*MAXID)/MIN(pos1,pos2); + } + else if ( strm (p, "sim3")) + { + r=(pos1==0 || pos2==0)?0:(sim*MAXID)/MAX(pos1,pos2); + } + else if ( strm (p, "gap1")) + { + r=(len1==0)?MAXID:(gap*MAXID)/len1; + r=MAXID-r; + } + else if ( strm (p, "logid")) + { + r=logid_score (pos0, sim); + } + else if ( strstr (mode, "sim")) + { + r=(pos0==0)?0:(sim*MAXID)/pos0; + } + + + return r; + + } +int get_seq_sim_2 ( char *string1, char *string2, char *ignore, char **gr, int ng) + { + int len1; + int len2; + int a; + int pos=0; + int sim=0; + char r1, r2; + + + len1=strlen (string1); + len2=strlen (string2); + + if ( len1!=len2)return 0; + + for ( a=0; a< len1; a++) + { + r1=string1[a]; + r2=string2[a]; + if ( !is_in_set (r1, ignore) && !is_in_set (r2, ignore)) + { + pos++; + if (is_in_same_group_aa(r1,r2,ng, gr, NULL)) + { + sim++; + } + } + } + + if (pos==0) + return 0; + else + return (int) (sim*MAXID)/pos; + + } + +int get_seq_sim_3 ( char *string1, char *string2, char *ignore, int **mat) + { + int len1; + int len2; + int a; + + int sim=0; + char r1, r2; + + + len1=strlen (string1); + len2=strlen (string2); + + if ( len1!=len2)return 0; + + for ( a=0; a< len1; a++) + { + r1=string1[a]; + r2=string2[a]; + if ( !is_in_set (r1, ignore) && !is_in_set (r2, ignore)) + { + sim+=mat[r1-'A'][r2-'A']; + } + } + return sim; + + } +int * get_aln_col_weight ( Alignment *A, char *mode) + { + int a, b; + char *col; + int *weight; + + col=vcalloc ( A->nseq, sizeof (int)); + weight=vcalloc (A->len_aln, sizeof (int)); + + for (a=0; a< A->len_aln; a++) + { + for ( b=0; b< A->nseq; b++) + col[b]=A->seq_al[b][a]; + weight[a]=(find_group_aa_distribution (col, A->nseq,0,NULL,NULL, mode )*MAXID)/A->nseq; + } + vfree (col); + return weight; + + } + +int analyse_aln_column ( Alignment *B, int col) + { + + char r=' '; + int a, b, c=0; + static char *mat; + static int ng_cw_star; + static char **cw_star; + int *cw_star_count; + + static int ng_cw_col; + static char **cw_col; + int *cw_col_count; + + static int ng_cw_dot; + static char **cw_dot; + int *cw_dot_count; + + + + + + + if ( !B->S || !(B->S)->type)B= get_aln_type (B); + + if ( !mat)mat=vcalloc ( STRING, sizeof (char)); + + if ( !ng_cw_star) + { + cw_star=make_group_aa ( &ng_cw_star, strcpy ( mat,"idmat")); + cw_col=make_group_aa ( &ng_cw_col, strcpy (mat,"clustalw_col")); + cw_dot=make_group_aa ( &ng_cw_dot, strcpy (mat, "clustalw_dot")); + } + + cw_star_count=vcalloc (ng_cw_star, sizeof (int)); + cw_col_count=vcalloc ( ng_cw_col, sizeof (int)); + cw_dot_count=vcalloc (ng_cw_dot, sizeof (int)); + + for ( a=0; a< B->nseq; a++) + { + c=tolower (B->seq_al[a][col]); + if (is_gap(c)){r=' ';break;} + + for ( b=0; b< ng_cw_star; b++) + cw_star_count[b]+=is_in_set (c, cw_star[b]); + for ( b=0; b< ng_cw_col; b++) + cw_col_count[b]+=is_in_set (c, cw_col[b]); + for ( b=0; b< ng_cw_dot; b++) + cw_dot_count[b]+=is_in_set (c, cw_dot[b]); + } + + + + + + if ( !is_gap(c) && r==' ') + for ( b=0; b< ng_cw_star; b++)if ( cw_star_count[b]==B->nseq){r='*'; break;} + if ( !is_gap(c) && r==' ' && !(strm((B->S)->type, "DNA")||strm ((B->S)->type,"RNA"))) + for ( b=0; b< ng_cw_col ; b++)if ( cw_col_count [b]==B->nseq){r=':'; break;} + if ( !is_gap(c) && r==' ' && !(strm((B->S)->type, "DNA")||strm ((B->S)->type,"RNA"))) + for ( b=0; b< ng_cw_dot ; b++)if ( cw_dot_count [b]==B->nseq){r='.'; break;} + + + + vfree(cw_star_count); + vfree(cw_col_count); + vfree(cw_dot_count); + + return r; + } + + +int ** get_cov_aln_array ( Alignment *A, char *mode) +{ + int **w; + int a, b, c, t; + + w=declare_int ( A->nseq, A->nseq); + + + for ( a=0; a< A->nseq-1; a++) + { + w[a][a]=100; + for ( t=0,b=a+1; b< A->nseq; b++) + { + for ( c=0; c< A->len_aln; c++) + { + t+=(!is_gap(A->seq_al[a][c]) &&!is_gap(A->seq_al[b][c])); + } + w[a][b]=w[b][a]=(t*100)/A->len_aln; + } + } + return w; +} + +int ** get_cov_master_aln_array ( Alignment *A,int n, char *mode) +{ + int **w; + int b, c, t; + + w=declare_int ( A->nseq, A->nseq); + + + for (b=0; b< A->nseq; b++) + { + + for (t=0, c=0; c< A->len_aln; c++) + { + t+=(!is_gap(A->seq_al[n][c]) &&!is_gap(A->seq_al[n][c])); + } + w[n][b]=w[b][n]=(t*100)/A->len_aln; + } + + return w; +} +int ** get_sim_master_aln_array ( Alignment *A,int n, char *mode) + { + int **w; + int a; + + w=declare_int ( A->nseq, A->nseq); + + + for ( a=0; a< A->nseq; a++) + { + if ( strm (mode, "cdna")) + w[n][a]=w[a][n]=get_cdna_seq_sim ( A->cdna_cache[0], A->seq_al[a], A->seq_al[n],GAP_LIST, mode); + else + w[n][a]=w[a][n]=get_seq_sim ( A->seq_al[n], A->seq_al[a],GAP_LIST, mode); + } + return w; + } +int ** get_dist_aln_array ( Alignment *A, char *mode) +{ + + int **w; + + w=get_sim_aln_array ( A, mode); + return sim_array2dist_array(w,MAXID); +} +Sequence * seq2filter (Sequence *Sin, int min, int max) +{ + int *keep; + char *tmpfile; + Sequence *S, *Sout; + int a, b, sim; + int **M; + FILE *fp; + int n; + + S=duplicate_sequence (Sin); + for (a=0; anseq; a++)ungap(S->seq[a]); + keep=vcalloc (S->nseq, sizeof (int)); + M=read_matrice ("blossum62mt"); + for (a=0; anseq; a++) + { + output_completion ( stderr, a, S->nseq, 100, "Distance Matrix Computation: "); + for ( b=a+1; bnseq; b++) + { + + sim=idscore_pairseq(S->seq[a], S->seq[b],-10, -2,M, "sim"); + if ( sim>min && simnseq; a++) + if ( keep[a]) + { + fprintf ( fp, ">%s %s\n%s", S->name[a], S->seq_comment[a], S->seq[a]); + n++; + } + vfclose (fp); + if (n==0) return NULL; + Sout=main_read_seq(tmpfile); + free_int (M, -1); vfree (keep); free_sequence (S, -1); + return Sout; +} + +Alignment * grep_seq (Alignment *S,char *field, char *mode, char *string) +{ + int a; + FILE *fp; + char *tmp; + int n=0; + + tmp=vtmpnam (NULL); + fp=vfopen (tmp, "w"); + + if ( !strm(mode, "KEEP") && ! strm (mode, "REMOVE")) + { + add_warning ( stderr, "\nERROR: +grep [FATAL: %s]", PROGRAM); + myexit (EXIT_FAILURE); + } + else if ( !strm(field, "SEQ") && ! strm (field, "COMMENT") && ! strm(field, "NAME")) + { + add_warning ( stderr, "\nERROR: +grep [FATAL: %s]", PROGRAM); + myexit (EXIT_FAILURE); + } + + + for (n=0, a=0; a< S->nseq; a++) + { + int found=0; + + if (strm(field, "NAME") && perl_strstr (S->name[a], string))found=1; + else if (strm(field, "COMMENT") && S->seq_comment[a][0] && perl_strstr (S->seq_comment[a], string) )found=1; + else if (strm(field, "SEQ") && perl_strstr (S->seq_al[a], string))found=1; + + if ( (strm (mode, "KEEP") && found) || (strm (mode, "REMOVE") && !found)) + { + n++; + fprintf (fp, ">%s", S->name[a]); + if (S->seq_comment[a][0])fprintf (fp, " %s", S->seq_comment[a]); + fprintf (fp, "\n%s\n", S->seq_al[a]); + } + } + + vfclose (fp); + + free_aln (S); + if ( n==0) return NULL; + else + return main_read_aln (tmp, NULL); +} + +Alignment * modify_seq (Alignment *S, char *field, char *string1, char *string2) +{ + int a; + FILE *fp; + char *tmp; + + tmp=vtmpnam (NULL); + fp=vfopen (tmp, "w"); + for ( a=0; a< S->nseq; a++) + { + if (strm(field, "NAME"))S->name[a]=substitute ( S->name[a], string1, string2); + else if (strm(field, "COMMENT"))S->seq_comment[a]=substitute ( S->seq_comment[a], string1, string2); + else if (strm(field, "SEQ"))S->seq_al[a]=substitute ( S->seq_al[a], string1, string2); + fprintf (fp, ">%s", S->name[a]); + if (S->aln_comment[a][0])fprintf (fp, " %s", S->aln_comment[a]); + fprintf (fp, "\n%s\n", S->seq_al[a]); + } + vfclose (fp); + free_aln (S); + S=main_read_aln (tmp, NULL); + return S; +} + +int ** seq2sim_mat (Sequence *S, char *mode) +{ + return seq2comp_mat ( S,mode, "sim"); +} +int ** seq2cov_mat (Sequence *S, char *mode) +{ + return seq2comp_mat ( S,mode, "cov"); +} + +int ** seq2comp_mat (Sequence *S, char *mode, char *comp_mode) +{ + int a, b; + int **sim; + char file[1000]; + Alignment *A; + char *name; + + + /*Use pre_computed value if available in the current dir*/ + + name=path2filename(S->file[0]); + sprintf ( file, "%s%s.%s.%s_file", get_cache_dir(),name, mode, comp_mode); + A=seq2aln(S,NULL, RM_GAP); + if ( check_file_exists (file) && is_distance_matrix_file (file) && (sim=input_similarities(file, A, NULL))!=NULL) + { + display_input_filename (stderr, "SIMILARITY_MATRIX", "SIMILARITY_MATRIX_FORMAT_01", file, CHECK); + fprintf ( stderr, "\n"); + } + else + { + char mode2[1000]; + int **M; + + M=read_matrice (mode); + sim=declare_int ( S->nseq, S->nseq); + for ( a=0; a< S->nseq; a++) + { + ungap (S->seq[a]); + sim[a][a]=100; + } + + for ( a=0; anseq-1; a++) + { + + output_completion4halfmat ( stderr, a, S->nseq, 100, "Similarity Matrix Computation: "); + for ( b=a+1; b< S->nseq; b++) + { + sim[a][b]=sim[b][a]=idscore_pairseq(S->seq[a], S->seq[b],-12, -1,M, comp_mode); + } + } + free_int (M,-1); + sprintf ( mode2, "_memory_%ld", (long int)sim); + output_similarities( file, A, mode2); + display_output_filename (stderr, "SIMILARITY_MATRIX", "SIMILARITY_MATRIX_FORMAT_01", file, CHECK); + fprintf ( stderr, "\n"); + } + free_aln (A); + return sim; +} + +int ** fast_aln2sim_list (Alignment *A, char *mode, int *ns, int **ls) +{ + int **simm; + int p1, p2, p3, r1, r2; + int gap,pos0,pos1,pos2,len,sim; + int a, b, c, m, s=0,s1, s2, n; + int free_ns=0; + + if (ns==NULL) + { + free_ns=1; + ns=vcalloc (2, sizeof (int)); + ns[0]=ns[1]=A->nseq; + ls=declare_int (2, A->nseq); + for ( a=0; a< 2; a++) + for (b=0; bnseq; b++) + ls[a][b]=b; + } + + + simm=declare_int (ns[0]*ns[1]+1, 3); + + if (strstr (mode, "sim1"))m=0; + else if (strstr (mode, "sim2"))m=1; + else if (strstr (mode, "sim3"))m=2; + else if (strstr (mode, "gap1"))m=3; + else if (strstr (mode, "cov1"))m=4; + else if (strstr (mode, "logid"))m=5; + else m=0; + + + + for (n=0,a=0; alen_aln; c++) + { + r1=tolower (A->seq_al[s1][c]); + r2=tolower (A->seq_al[s2][c]); + p1=(r1!='-')?1:0; + p2=(r2!='-')?1:0; + p3=p1+p2; + if ( p3==0)continue; + if ( p3==1)gap++; + if ( r1==r2)sim++; + pos1+=p1; + pos2+=p2; + pos0+=(p3==2)?1:0; + len++; + } + + if (m==0)s=(pos0==0)?0:(sim*MAXID)/pos0; //sim1 + else if (m==1) s=(MIN(pos1,pos2)==0)?0:(sim*MAXID)/MIN(pos1,pos2);//sim2 + else if (m==2) s=(MAX(pos1,pos2)==0)?0:(sim*MAXID)/MAX(pos1,pos2);//sim3 + else if (m==3) s=(len==0) ?0:((len-gap)*MAXID)/len;//gap1 + else if (m==4) s=(len==0) ?0:((pos0)*MAXID)/len; //cov + else if (m==5) + { + s=logid_score ( sim, len); + } + simm[n][0]=s1; + simm[n][1]=s2; + simm[n][2]=s; + } + } + + if ( free_ns) {vfree(ns); free_int (ls, -1);} + simm[n][0]=-1; + return simm; +} + +int ** fast_aln2sim_mat (Alignment *A, char *mode) +{ + int **simm; + int p1, p2, p3, r1, r2; + int gap,pos0,pos1,pos2,len,sim; + int a, b, c, m; + + simm=declare_int (A->nseq, A->nseq); + + + + if (strstr (mode, "sim1"))m=0; + else if (strstr (mode, "sim2"))m=1; + else if (strstr (mode, "sim3"))m=2; + else if (strstr (mode, "gap1"))m=3; + else if (strstr (mode, "cov1"))m=4; + else if (strstr (mode, "logid"))m=5; + else m=0; + + + + for ( a=0; a< A->nseq-1; a++) + { + simm[a][a]=MAXID; + for ( b=a+1; b< A->nseq; b++) + { + gap=pos0=pos1=pos2=len=sim=0; + + for ( c=0; c< A->len_aln; c++) + { + r1=tolower (A->seq_al[a][c]); + r2=tolower (A->seq_al[b][c]); + p1=(r1!='-')?1:0; + p2=(r2!='-')?1:0; + p3=p1+p2; + if ( p3==0)continue; + if ( p3==1)gap++; + if ( r1==r2)sim++; + pos1+=p1; + pos2+=p2; + pos0+=(p3==2)?1:0; + len++; + } + + if (m==0)simm[a][b]=simm[b][a]=(pos0==0)?0:(sim*MAXID)/pos0; //sim1 + else if (m==1) simm[a][b]=simm[b][a]=(MIN(pos1,pos2)==0)?0:(sim*MAXID)/MIN(pos1,pos2);//sim2 + else if (m==2) simm[a][b]=simm[b][a]=(MAX(pos1,pos2)==0)?0:(sim*MAXID)/MAX(pos1,pos2);//sim3 + else if (m==3) simm[a][b]=simm[b][a]=(len==0) ?0:((len-gap)*MAXID)/len;//gap1 + else if (m==4) simm[a][b]=simm[b][a]=(len==0) ?0:((pos0)*MAXID)/len; //cov + else if (m==5) + { + + //Inspired from Muscle +mafft 5 + simm[a][b]=simm[b][a]=logid_score ( sim, len); + } + } + } + return simm; +} +int logid_score ( int sim, int len) +{ + float score; + + if ( len==0)return (int)(0.33*(float)MAXID); + + score=(float)sim/(float)len; + if (score>0.9) score=1.0; + else score=-log10 (1.0-score); + + score=(score*MAXID); + return score; +} +int ** aln2sim_mat (Alignment *A, char*mode) +{ + + + if ( strstr (mode, "idmat"))return fast_aln2sim_mat(A, mode); + return get_sim_aln_array(A, mode); +} +int ** aln2cov (Alignment *A) +{ + int a, b, c; + int r1, r2, gr1, gr2, pos0, gap; + int **cov; + cov=declare_int (A->nseq, A->nseq); + + for (a=0; a< A->nseq-1; a++) + { + cov[a][a]=100; + for ( b=a+1; bnseq; b++) + { + for (gap=0,pos0=0,c=0;clen_aln; c++) + { + r1=A->seq_al[a][c]; + r2=A->seq_al[b][c]; + gr1=is_gap(r1); gr2=is_gap(r2); + if ( gr1+gr2==0)pos0++; + else if ( gr1+gr2<2)gap++; + } + cov[a][b]=cov[b][a]=((gap+pos0)==0)?0:((pos0*100)/(gap+pos0)); + } + } + return cov; +} +int ** get_raw_sim_aln_array (Alignment *A, char *mode) +{ + int **w; + int **M; + int a, b, c, r1, r2, set, max, min; + + w=declare_int (A->nseq, A->nseq); + if (strstr(mode, "sar"))M=NULL; + else M=read_matrice (mode); + + HERE ("RAW STUFF"); + + for ( set=0,a=0; a< A->nseq; a++) + for (b=a; bnseq; b++) + { + if (M) + { + for (c=0; clen_aln; c++) + { + r1=A->seq_al[a][c]; + r2=A->seq_al[b][c]; + + if ( !is_gap(r1) && !is_gap(r2)) + w[a][b]+=M[r1-'A'][r2-'A']; + } + } + else if ( strm (mode, "sarmat2")) + { + w[a][b]=get_sar_sim2 (A->seq_al[a], A->seq_al[b]); + } + else + { + HERE ("ERROR: %s is an unknown mode of raw_sim\n", mode); myexit (EXIT_FAILURE); + } + + w[b][a]=w[a][b]; + if (!set){min=max=w[a][b];set=1;} + min=MIN(min,w[a][b]); + max=MAX(max,w[a][b]); + } + for (a=0; anseq; a++) + for (b=a; bnseq; b++) + { + w[b][a]=((max-min)==0)?0:((w[b][a]-min)*100)/(max-min); + w[a][b]=w[b][a]; + } + free_int (M, -1); + return w; +} +int ** get_sim_aln_array ( Alignment *A, char *mode) + { + int **w; + int a, b; + + + w=declare_int ( A->nseq, A->nseq); + + for ( a=0; a< A->nseq-1; a++) + { + for ( b=a+1; b< A->nseq; b++) + { + + w[a][b]=w[b][a]=generic_get_seq_sim ( A->seq_al[a], A->seq_al[b], (A->cdna_cache)?A->cdna_cache[0]:NULL, mode); + } + } + return w; + } +int generic_get_seq_sim ( char *seq1, char *seq2, int*cache, char *mode) +{ + + + if ( strm (mode, "cdna")) + return get_cdna_seq_sim ( cache, seq1, seq2,GAP_LIST, mode); + else if ( strnm (mode, "ktup",4)) + return ktup_comparison (seq1, seq2,atoi(mode+4)); + else if ( strstr (mode, "sarmat2")) + { + + return get_sar_sim2 (seq1, seq2); + } + else if ( strstr (mode, "sarmat")) + return (int) get_sar_sim (seq1,seq2); + else + { + return get_seq_sim ( seq1,seq2,GAP_LIST, mode); + } +} +int *** get_winsim_aln_array ( Alignment *A,char *mode, int ***w) + { + int a, b; + for ( a=0; a< A->nseq; a++) + for ( b=0; b< A->nseq; b++) + { + if ( strm (mode, "cdna")) + w[a][b]=get_cdna_seq_winsim ( A->cdna_cache[0], A->seq_al[a], A->seq_al[b],GAP_LIST, mode, w[a][b]); + else + w[a][b]=get_seq_winsim ( A->seq_al[a], A->seq_al[b],GAP_LIST, mode, w[a][b]); + } + return w; + } + +Alignment * seq2profile (Sequence *S, int i) +{ + Alignment *A; + + if ((A=seq2R_template_profile (S, i))) + { + return A; + } + else + { + char *tmp; + FILE *fp; + tmp=vtmpnam (NULL); + fp=vfopen ( tmp, "w"); + fprintf (fp, ">%s\n%s\n", S->name[i], S->seq[i]); + vfclose (fp); + + (S->T[i])->R=fill_R_template (S->name[i], tmp, S); + + return seq2R_template_profile (S, i); + } +} +Alignment* remove_seq_from_aln (Alignment *A, char *seq) +{ + int a, n; + for (n=0,a=0; anseq; a++) + { + if ( strm (seq, A->name[a]))continue; + else if ( n==a); + else + { + sprintf (A->name[n], "%s",A->name[a]); + sprintf (A->seq_al[n], "%s",A->seq_al[a]); + if (A->seq_comment[a])sprintf (A->seq_comment[n], "%s", A->seq_comment[a]); + if (A->aln_comment[a])sprintf (A->aln_comment[n], "%s", A->aln_comment[a]); + A->order[n][0]=A->order[a][0]; + A->order[n][1]=A->order[a][1]; + } + n++; + } + A->nseq=n; + return A; +} + + +Alignment* aln2sub_aln_file (Alignment *A, int n, char **string) +{ + char ***list; + int a; + + list=vcalloc (A->nseq, sizeof (char***)); + if ( n==0)return A; + else if (n>1) + { + int l; + char *buf; + + for (l=0,a=0; a< n; a++)l+=strlen (string[a]); + buf=vcalloc ( 2*n+l+1, sizeof (char)); + for (a=0; a< n; a++){buf=strcat (buf,string[a]), buf=strcat ( buf, " ");} + list[0]=string2list (buf); + vfree (buf); + } + else if ( file_exists (NULL,string[0])) + { + list=read_group (string[0]); + + } + else + { + fprintf (stderr, "\nERROR: file <%s> does not exist [FATAL:%s]\n",string[0], PROGRAM); + myexit (EXIT_FAILURE); + } + + + a=0; + while (list[a]) + { + int i, b; + FILE *fp; + n=atoi (list[a][0]); + fp=vfopen (list[a][1], "w"); + for (b=2; bname, A->nseq, MAXNAMES); + if (n==3)ungap (A->seq_al[i]); + fprintf (fp, ">%s\n%s\n", A->name[i], A->seq_al[i]); + } + vfclose (fp); + free_char (list[a], -1); + a++; + } + vfree(list); + return A; +} +Sequence *remove_empty_sequence (Sequence *S) +{ + int a, b; + char *c; + Sequence *NS; + + c=vcalloc ( S->max_len+1, sizeof (char)); + + for (a=0, b=0; a< S->nseq; a++) + { + sprintf ( c, "%s",S->seq[a]); + ungap (c); + if ( strlen (c)==0) + { + //vfree (S->seq[a]); + S->seq[a]=NULL; + add_warning ( stderr, "WARNING: Sequence %s does not contain any residue: automatically removed from the set [WARNING:%s]",S->name[a], PROGRAM); + } + } + NS=duplicate_sequence (S); + free_sequence (S, S->nseq); + vfree (c); + return NS; +} +Alignment* aln2sub_seq (Alignment *A, int n, char **string) +{ + char ***list; + int a; + Sequence *S=NULL; + + list=vcalloc (A->nseq, sizeof (char***)); + if ( n==0)return A; + else if (n>1) + { + int l; + char *buf; + + for (l=0,a=0; a< n; a++)l+=strlen (string[a]); + buf=vcalloc ( 2*n+l+1, sizeof (char)); + for (a=0; a< n; a++){buf=strcat (buf,string[a]), buf=strcat ( buf, " ");} + list[0]=string2list (buf); + vfree (buf); + } + else if ( file_exists (NULL,string[0])) + { + list=read_group (string[0]); + + } + else + { + fprintf (stderr, "\nERROR: file <%s> does not exist [FATAL:%s]\n",string[0], PROGRAM); + myexit (EXIT_FAILURE); + } + + + + a=0; + while (list[a]) + { + int t; + Alignment *B; + Sequence *subS; + + + B=main_read_aln (list[a][1], NULL); + t=aln2most_similar_sequence(B, "idmat"); + subS=extract_one_seq(B->name[t],0,0,B,KEEP_NAME); + S=add_sequence (subS,S,0); + free_aln (B);free_sequence (subS, -1); + vremove (list[a][1]); + a++; + } + vfree(list); + return seq2aln (S, NULL, RM_GAP); +} + +Alignment * aln2collapsed_aln (Alignment * A, int n, char **string) +{ + Alignment *B; + char ***list; + char **list2; + char *buf=NULL; + FILE *fp; + int a, b,c, ns, m, l; + int *collapsed; + + list=vcalloc (A->nseq, sizeof (char***)); + ns=0; + if ( n==0)return A; + else if (n>1) + { + for (l=0,a=0; a< n; a++)l+=strlen (string[a]); + buf=vcalloc ( 2*n+l+1, sizeof (char)); + for (a=0; a< n; a++){buf=strcat (buf,string[a]), buf=strcat ( buf, " ");} + + list[0]=string2list (buf);ns=1; + + } + else if ( file_exists (NULL,string[0])) + { + /*Format: Fasta like, the name fo the group followed with the name of the sequences + > .... + Groups must NOT be overlaping + */ + l=measure_longest_line_in_file (string[0])+1; + buf=vcalloc (l, sizeof (char)); + ns=0; + fp=vfopen (string[0], "r"); + while ((c=fgetc(fp))!=EOF) + { + buf=fgets (buf,l-1, fp); + if ( c=='>')list[ns++]=string2list (buf); + } + vfclose (fp); + } + else + { + fprintf (stderr, "\nERROR: file <%s> does not exist [FATAL:%s]\n",string[0], PROGRAM); + myexit (EXIT_FAILURE); + } + + vfree (buf); buf=NULL; + + /*Identify lost sequences*/ + collapsed=vcalloc (A->nseq, sizeof (int)); + for ( a=0; a< ns; a++) + { + m=atoi (list[a][0]); + for (b=2; bname, A->nseq, MAXNAMES); + if ( c>=0)collapsed[c]=1; + } + } + for ( a=0; a< A->nseq; a++) + { + if ( collapsed[a]==0) + { + list[ns]=declare_char (3, MAXNAMES); + sprintf ( list[ns][0], "3"); + sprintf ( list[ns][1], "%s", A->name[a]); + sprintf ( list[ns][2], "%s", A->name[a]); + ns++; + } + } + vfree (collapsed); + + + + + + list2=declare_char (A->nseq, 100); + /*1 Collapse the alignment*/ + for ( a=0; a< ns; a++) + { + sprintf ( list2[a], "%s", list[a][2]); + } + B=extract_sub_aln2 ( A, ns, list2); + /*2 Rename the sequences*/ + for ( a=0; a< ns; a++) + { + sprintf ( B->name[a], "%s", list[a][1]); + } + /*replace sequence with consensus*/ + + for ( a=0; a< ns; a++) + { + m=atoi (list[a][0]); + for (c=0, b=2; bseq_al[a], "%s", buf); + } + vfree (buf); + + free_aln (A); + B->S=aln2seq(B); + return B; +} +Alignment * aln2profile (Alignment * A) + { + Alignment *B=NULL; + char *cons; + + if (!A->P) + { + A->P=declare_profile (AA_ALPHABET,A->len_aln+1); + } + B=copy_aln (A, B); + free_int ((A->P)->count, -1); + free_int ((A->P)->count2, -1); + free_int ((A->P)->count3, -1); + (A->P)->count=aln2count_mat (A); + (A->P)->count2=aln2count_mat2 (A); + + cons=aln2cons_seq_mat (A, "blosum62mt"); + + sprintf (B->seq_al[0], "%s", cons); + B->nseq=1; + (A->P)->count3=aln2count_mat2 (B); + vfree (cons); + free_aln (B); + + + + return A; + + } + +int** aln2count_mat2 ( Alignment *A) +{ + return sub_aln2count_mat2 (A, 0, NULL); +} + +int sub_aln2nseq_prf ( Alignment *A, int ns, int *ls) +{ + + + int a, c, s; + Alignment *R; + int n; + int free_ls=0; + + + if ( ns==0) + { + n=ns=A->nseq; + ls=vcalloc (n, sizeof (int)); + for ( a=0; anseq; a++)ls[a]=a; + free_ls=1; + } + else + { + n=ns; + } + + for (c=0,a=0; aS && (R=seq2R_template_profile (A->S, A->order[s][0]))!=NULL) + { + n+=R->nseq; + } + else + { + ; + } + } + + if ( free_ls) vfree (ls); + return n; +} + +int** sub_aln2count_mat2 ( Alignment *A, int ns, int *ls) +{ + char **p; + int **count; + int a, b, c, s; + Alignment *R; + int n; + int free_ls=0; + + if ( ns==0) + { + n=ns=A->nseq; + p=vcalloc ( n, sizeof (char*)); + ls=vcalloc (n, sizeof (int)); + for ( a=0; anseq; a++)ls[a]=a; + free_ls=1; + } + else + { + n=ns; + p=vcalloc (n, sizeof (char*)); + } + + for (c=0,a=0; aS && (R=seq2R_template_profile (A->S, A->order[s][0]))!=NULL) + { + n+=R->nseq; + p=vrealloc (p, n*sizeof (char*)); + for (b=0; bnseq; b++) + { + p[c++]=R->seq_al[b]; + } + } + else + { + int w; + w=A->order[s][4]+1; + + for (b=0; bseq_al[s]; + } + } + count=sub_aln2count_mat3 (p,c); + vfree (p); + if ( free_ls) vfree (ls); + return count; +} +int** sub_aln2count_mat3 (char **al, int ns) +{ + int **count; + int used[1000]; + int a, b; + int r; + + int len; + int us; + + + /*count[x][0]=n symbols in column + count[x][1]=total_size of line + count[x][2]=Gap frequency + + count[x][n]=symbol n + count[x][n+1]=N occurence symbol n; + count[x][n+2]=N frequence symbol n*100; + + special multi-channeling + count[x][count[x][1]]=Nseq + count[x][count[x][1]+s]=residue col x, sequence s + */ + + + for (a=0; a< 1000; a++)used[a]=0; + len=strlen (al[0]); + + count=declare_int (len+2,100+ns+2); + count[len][0]=END_ARRAY; + count[len][1]=ns; + count[len][2]=len; + + + + for (a=0; anseq-us)*100/A->nseq;*/ + count[a][2]=ns-us; + + for (b=3; bnseq; + for (b=1; b<=A->nseq; b++) + count [a][count[a][1]+b]=(is_gap(A->seq_al[b-1][a]))?0:A->seq_al[b-1][a]; + */ + } +#ifdef XXXXXX + HERE ("Display "); + for (a=0; a< 5; a++) + { + fprintf ( stderr, "\n"); + for ( b=3; b< count[a][1]; b+=3) + { + fprintf ( stderr, "[%c %d]", count[a][b], count[a][b+1]); + } + fprintf ( stderr, "\n"); + for ( b=0; blen_aln); + + + for ( a=0; alen_aln; a++) + { + for ( b=0; b< A->nseq; b++) + { + if ( is_gap ( A->seq_al[b][a]))freq_mat[alp_size][a]++; + else + { + x=tolower(A->seq_al[b][a]); + freq_mat[x-'a'][a]++; + freq_mat[alp_size+1][a]++; + + } + } + } + + return freq_mat; + } +char *aln2random_seq (Alignment *A, int pn1, int pn2, int pn3, int gn) + { + + /* + + + Given the frequencies in A ( read as total counts of each Residue in + freq[A->nseq][A->len_aln], and pn1, pn2 and pn3: + + 1-Generate a new amino-acid at each position + 2-Insert Gaps, using a HMM. + + + pn3=Weight of the noise induced with sub mat. + + pn1=% noise type 1 ( Varies with entropi) + n1=Ratio noise type 1 + + T =Nseq + t1=Noise 1 expressed in Nseq + al=alphabet size; + ncat=number of non 0 cat for a given position + ICi initial count for residue i + + Ci=freq[seq][AA] + t1=T*n1*(1-1/ncat); + t2=T*n2; + + Ci= ICi*(T-(t1+t2))/T +(t1)/al+(t2)/al + + */ + + int **freq; + int **count; + float T, tot_t1, tot_t2,tot_t3, n1, n2, n3; + float ncat; + + double gf; + double *init_freq; + double *blur_freq; + double *t1, *t2,*t3; + int a, b, c, x; + char *seq; + int tot; + /*Viterbi Parameters */ + + int p; + int AL=0; /*Allowed Transition*/ + int F=-100000; /*Forbiden Transition*/ + + int GAP_TRANSITION; + int IGAP=0, IAA=1; + + int state,best_state=0, score, best_score=0; + int p_state; + int e=0; + int **score_tab; + int **state_tab; + int nstate=2; + int **transitions; + + int max; + + seq=vcalloc ( A->len_aln+1, sizeof (char)); + count=aln2count_mat(A); + freq=aln2count_mat(A); + + T=100; + + n1=(float)pn1/100; + n2=(float)pn2/100; + n3=(float)pn3/100; + + for ( a=0; a< A->len_aln; a++) + { + for ( b=0; b<26; b++) + freq[b][a]=freq[b][a]*((T)/(A->nseq-freq[26][a])); + freq[26][a]= (freq[26][a]*T)/A->nseq; + } + + + init_freq=vcalloc ( 26, sizeof (double)); + blur_freq=vcalloc ( 26, sizeof (double)); + + tot_t1=tot_t2=tot_t3=0; + + t1=vcalloc ( 27, sizeof (double)); + t2=vcalloc ( 27, sizeof (double)); + t3=vcalloc ( 27, sizeof (double)); + for (a=0; a< A->len_aln; a++) + { + + /*Compute Frequencies*/ + for (tot=0, b=0; b<26; b++) + { + if ( is_aa(b+'A')) + { + init_freq[b]=freq[b][a]; + tot+=freq[b][a]; + } + } + /*Count the number of different amino acids*/ + for ( ncat=0, b=0; b<=26; b++) + { + ncat+=(freq[b][a]!=0)?1:0; + } + /*Blurr the distribution using */ + blur_freq=compute_matrix_p (init_freq,tot); + + + /*compute noise 1: biased with blurred content * enthropy--> keeps prosite motifs*/ + tot_t1=T*n1*(1-1/ncat); + for ( b=0; b< 26; b++)if ( is_aa(b+'A')){t1[b]=blur_freq[b]*(1-1/ncat)*n1;} + + /*Compute noise 2: completely random*/ + tot_t2=T*n2; + for ( b=0; b< 26; b++)if ( is_aa(b+'A')){t2[b]=tot_t2/21;} + + /*compute noise 3: biased with the sole content(pam250mt)*/ + tot_t3=T*n3; + for ( b=0; b<26; b++)if ( is_aa(b+'A')){t3[b]=blur_freq[b]*n3;} + + for ( b=0; b<26; b++) + { + if ( is_aa('A'+b)) + freq[b][a]=freq[b][a]*(T-(tot_t1+tot_t2+(tot_t3)))/T+t1[b]+t2[b]+t3[b]; + } + + /*end of the loop that mutates position a*/ + } + + vfree (blur_freq); + vfree (init_freq); + vfree ( t3); + + /*1-Generate the amino acids of the new sequence new*/ + + + vsrand (0); + + for ( a=0; a< A->len_aln; a++) + { + + for (T=0,b=0; b<26; b++)T+=freq[b][a]; + x=rand ()%((int)T); + for (c=0,b=0; b<26; b++) + { + c+=freq[b][a]; + if ( c>=x) + { + seq[a]='A'+b; + c=-1; + break; + } + } + if ( c!=-1)seq[a]='-'; + } + seq[a]='\0'; + + + /*2 Generate the gaps in the new sequence*/ + + + + if ( gn<0); + else + { + + transitions=declare_int ( nstate, nstate); + score_tab=declare_int ( A->len_aln+2, nstate ); + state_tab=declare_int ( A->len_aln+2, nstate ); + + + + for (a=0; alen_aln; p++){for (state=0; state< nstate; state++){score_tab[p][state]=F;state_tab[p][state]=-1;} } + + for (p=1; p<= A->len_aln; p++) + { + for (max=0,a=0; a<26; a++)max=MAX(max, freq[a][p-1]); + max=(max*(A->nseq-count[26][p-1]))/A->nseq; + + for (state=0; state< nstate; state++) + { + + + gf=freq[26][p-1]; + if ( state==IGAP) e=gf-50; + else if ( state==IAA ) e=max-50; + for (p_state=0; p_statebest_score){ best_score=score;best_state=p_state;} + } + score_tab[p][state]=best_score; + state_tab[p][state]=best_state; + } + } + + for (state=0; statebest_score){best_score=score_tab[p-1][state]; best_state=state;} + } + + for (p=A->len_aln; p>0;) + { + if ( best_state==IGAP) + { + seq[p-1]='-'; + } + else if ( best_state==IAA) + { + seq[p-1]=seq[p-1]; + } + best_state=state_tab[p][best_state]; + p--; + } + } + + free_int (freq, -1); + return seq; + } + +/********************************************************************/ +/* */ +/* Weighting functions */ +/* */ +/* */ +/* */ +/********************************************************************/ +Alignment * master_trimseq( Alignment *A, Sequence *S,char *mode) + { + Alignment *NA; + char *p; + int a, b; + int use_aln=0, upper_sim=0, min_nseq=0, lower_sim=0; + float f_upper_sim, f_lower_sim; + char weight_mode[1000]; + char method[1000]; + int statistics=0; + int trim_direction=TOP; + float **sim_weight; + int *seq_list; + int table=0; + + + + + /* + mode: + (trim)__%_n_w + */ + + + + seq_list=vcalloc ( S->nseq, sizeof (int)); + for ( a=0; a< A->nseq; a++) + { + seq_list[a]=1; + } + + + use_aln=aln_is_aligned(A); + + if ( mode[0]=='\0') + { + + upper_sim=50; + lower_sim=0; + min_nseq=0; + sprintf (weight_mode, "pwsim"); + sprintf ( method, "clustering2"); + } + else + { + + upper_sim=lower_sim=min_nseq; + sprintf (weight_mode, "pwsim"); + sprintf ( method, "clustering2"); + } + + /* + U or % (deprecated) Upper bound for pairwise similarity + L or m (depercated) Lower bound for pairwise similarity + n max number of sequences + N max number of sequences as a fraction of thet total + S print Statistics + T print Table of distances + */ + + + + while ( (p=strtok(mode, "_"))) + { + mode=NULL; + if (strm (p, "seq"))use_aln=0; + else if ( strm(p,"aln"))use_aln=1; + else if (p[0]=='s')statistics=1; + else if (p[0]=='t')table=1; + else if (p[0]=='U')upper_sim=atoi(p+1); + else if (p[0]=='L')lower_sim=atoi(p+1); + else if (p[0]=='n')min_nseq=atoi(p+1); + else if (p[0]=='N')min_nseq=atoi(p+1)*-1; + else if (p[0]=='B')trim_direction=BOTTOM; + else if (p[0]=='T')trim_direction=TOP; + else if (p[0]=='W')sprintf (weight_mode, "%s", p+1); + else if (p[0]=='M')sprintf (method, "%s", p+1); + else if (p[0]=='K') + { + + while ((p=strtok(NULL, ":"))) + { + + if ( p[0]=='#') + { + seq_list[atoi(p+1)-1]=2; + } + else if ( (a=name_is_in_list (p, A->name, A->nseq, 100))!=-1) + + { + seq_list[a]=2; + } + } + } + } + + if ( !upper_sim && !min_nseq && !lower_sim)upper_sim=50; + + + + if (!S) + { + fprintf ( stderr, "\ntrimseq requires a set of sequences[FATAL:%s]\n", PROGRAM); + crash(""); + } + + else if ( min_nseq> S->nseq) + { + min_nseq=S->nseq; + } + else if ( min_nseq<0) + { + if ( min_nseq<-100) + { + add_warning ( stderr, "\nWARNING: trimseq: Nseq(N) max_val=100%% [Automatic reset]\n"); + min_nseq=-100; + } + + min_nseq=(int)((float)S->nseq*((float)min_nseq/100)*-1); + } + + + NA=seq2subseq3 (A, S,use_aln,lower_sim,upper_sim,min_nseq,trim_direction, weight_mode,&sim_weight, seq_list ); + + if ( table) + { + fprintf ( stderr, "\nSIMILARITY MATRIX\n"); + for ( a=0; a< A->nseq-1; a++) + for ( b=a+1; b< A->nseq; b++) + { + fprintf ( stderr, "%15s Vs %15s : %3.2f %% id\n", A->name[a], A->name[b], 100-sim_weight[a][b]); + } + } + if ( statistics) + { + f_upper_sim=(upper_sim>100)?((float)upper_sim/(float)100):upper_sim; + f_lower_sim=(upper_sim>100)?((float)lower_sim/(float)100):lower_sim; + + fprintf ( stderr, "\nTRIM Informations:\n"); + fprintf ( stderr, "\tUse...........: %s\n",(use_aln)?"multiple_aln":"pairwise_aln"); + fprintf ( stderr, "\tcluster_mode..: %s\n" ,method); + fprintf ( stderr, "\tsim_mode......: %s\n" ,weight_mode); + fprintf ( stderr, "\tlower_id_bound: %.2f%%\n" ,(f_lower_sim==0)?-1:f_lower_sim); + fprintf ( stderr, "\tupper_id_bound: %.2f%%\n",(f_upper_sim==0)?-1:f_upper_sim); + fprintf ( stderr, "\tnseq_kept.....: %d (out of %d)\n" ,NA->nseq, S->nseq); + fprintf ( stderr, "\treduction.....: %d%% of original set\n" ,(NA->nseq*100)/S->nseq); + fprintf ( stderr, "\tTrim_direction: From %s \n" ,(trim_direction==BOTTOM)?"Bottom":"Top"); + } + + return NA; + } + +Alignment *sim_filter (Alignment *A, char *in_mode, char *seq) +{ + int **sim, **cov; + int *list; + int *keep; + int maxnseq, nseq_ratio, nc; + int new_nseq; + int a, s, n, k; + Alignment *R; + char *mode; + int outlayers; + int direction=1;//remove the higher than + int coverage=0; //remove based on coverage + static char *field; + int maxsim, minsim, maxcov, mincov; + + if ( !field) field=vcalloc (1000, sizeof (char)); + + mode=vcalloc ( strlen (in_mode)+10, sizeof (char)); + sprintf ( mode, "_%s_", in_mode); + + strget_param ( mode, "_I", "100", "%d", &maxsim); + strget_param ( mode, "_i", "0", "%d", &minsim); + strget_param ( mode, "_C", "100", "%d", &maxcov); + strget_param ( mode, "_c", "0", "%d", &mincov); + + + + + + keep=vcalloc ( A->nseq, sizeof (int)); + list=vcalloc ( A->nseq, sizeof (int)); + + + + + + + if (!seq)s=0; + else s=name_is_in_list (seq, A->name, A->nseq, 100); + if (s==-1) + { + + if ( s==-1)printf_exit (EXIT_FAILURE, stderr, "ERROR: %s is not a valid sequence", seq); + } + else + keep[s]=1; + + //get the distances + if ( strstr (mode, "_seq_")) + { + char **seq; + int **M; + + M=read_matrice ("blosum62mt"); + seq=declare_char (A->nseq, A->len_aln+1); + for (a=0; anseq; a++) + { + sprintf ( seq[a], "%s", A->seq_al[a]); + ungap (seq[a]); + } + + sim=declare_int (A->nseq, A->nseq); + cov=declare_int (A->nseq, A->nseq); + + for (a=0; anseq; a++) + { + if ( s!=a) + { + sim[s][a]=sim[a][s]=idscore_pairseq(seq[s], seq[a],-12, -1,M,"sim"); + cov[s][a]=cov[a][s]=idscore_pairseq(seq[s], seq[a],-12, -1,M,"cov"); + + } + } + free_char (seq, -1); + free_int (M,-1); + } + else + { + sim=aln2sim_mat (A, "idmat"); + cov=aln2cov (A); + } + + for (a=0; a< A->nseq; a++) + { + if (a==s)continue; + else + { + if ( sim[s][a]>maxsim || sim[s][a]maxcov)keep[a]=-1; + else keep[a]=1; + } + } + + for ( n=0, a=0; a< A->nseq; a++) + { + if ( keep[a]!=-1) + { + list[n++]=a; + } + } + + R=extract_sub_aln (A, n, list); + free_int (sim, -1); free_int (cov, -1);vfree (list); + + return R; +} + + +static int find_worst_seq ( int **sim, int n, int *keep, int max, int direction); +Alignment *simple_trimseq (Alignment *A, Alignment *K, char *in_mode, char *seq_list, int **sim) +{ + int *list; + int *keep; + int maxnseq, maxsim, nseq_ratio, nc; + int new_nseq; + int a,b, s, n, k; + Alignment *R; + char *mode; + int outlayers; + int direction=1;//remove the higher than + int coverage=0; //remove based on coverage + static char *field; + int *tot_avg; + int KeepN=0; + int Print=0; + + if ( !field) field=vcalloc (1000, sizeof (char)); + + mode=vcalloc ( strlen (in_mode)+10, sizeof (char)); + sprintf ( mode, "_%s_", in_mode); + + strget_param ( mode, "_%%", "0", "%d", &maxsim); + strget_param ( mode, "_n", "0", "%d", &maxnseq); + strget_param ( mode, "_N", "0", "%d", &nseq_ratio); + strget_param ( mode, "_F", "0", "%d", &nc); + strget_param ( mode, "_O", "0", "%d", &outlayers); + strget_param ( mode, "_K", "0", "%d", &KeepN); + + strget_param ( mode, "_f", "NAME", "%s", field); + + if ( strstr (mode, "_P_"))Print=1; + + if ( strstr (mode, "_min"))direction=-1; + else direction=1; + + if ( strstr (mode, "_cov"))coverage=1; + else coverage=0; + + + if ( nseq_ratio) + { + maxnseq=(A->nseq*nseq_ratio)/100; + maxsim=0; + } + else if ( maxnseq) + { + maxsim=0; + } + else if ( !maxsim) + { + maxsim=100; + } + + + keep=vcalloc ( A->nseq, sizeof (int)); + list=vcalloc ( A->nseq, sizeof (int)); + + + + + /*Remove Sequences that do not have at least one residue in the first and last nc columns*/ + if ( nc) + { + int left, right, full_n,x, y; + int *full_list; + + Alignment *F; + + full_list=vcalloc ( A->nseq, sizeof (int)); + full_n=0; + for (x=0; x< A->nseq; x++) + { + for ( left=0,y=0; ylen_aln,nc); y++) + if (!is_gap(A->seq_al[x][y]))left=1; + + for ( right=0,y=MAX(0,(A->len_aln-nc)); ylen_aln; y++) + if (!is_gap(A->seq_al[x][y]))right=1; + + if ( left && right)full_list[full_n++]=x; + } + F=extract_sub_aln (A, full_n, full_list); + free_aln (A); + vfree (full_list); + A=F; + } + + /*Reorder the sequences according to the tree order: hopefully better phylogenetic coverage after trim*/ + if (strstr (mode, "_T")) + { + NT_node **T; + Sequence *O; + + if (!sim)sim=sim_array2dist_array ( NULL, MAXID); + T=int_dist2nj_tree (sim, A->name, A->nseq, NULL); + O=tree2seq (T[3][0], NULL); + A=reorder_aln (A, O->name, O->nseq); + + free_int (sim, -1); + free_sequence (O, -1); + } + + if ( coverage==0) + { + if ( strstr (mode, "seq_") && !sim)sim=seq2comp_mat (aln2seq(A), "blosum62mt", "sim"); + else sim=aln2sim_mat (A, "idmat"); + } + else + { + int b; + if ( strstr (mode, "seq_") && !sim)sim=seq2comp_mat (aln2seq(A), "blosum62mt", "cov"); + else sim=aln2cov (A); + + } + + + if ( K && K->nseq>0) + { + for ( a=0; a< K->nseq; a++) + if ( (k=name_is_in_list (K->name[a], A->name, A->nseq, MAXNAMES+1))!=-1) + { + + keep[k]=1; + } + } + if ( seq_list) + { + for ( a=0; a< A->nseq; a++) + { + if (strstr (field, "NAME") && perl_strstr (A->name[a], seq_list)){keep[a]=1;} + else if (strstr (field, "COMMENT") && A->seq_comment && perl_strstr(A->seq_comment[a], seq_list)){keep[a]=1;} + else if (strstr (field, "SEQ") && perl_strstr((A->S)->seq[a], seq_list)){keep[a]=1;} + } + + } + for (a=0; anseq; a++) + if ( keep[a]) fprintf ( stderr, "\nFORCED KEEP %s", A->name[a]); + } + + new_nseq=A->nseq; + + + while ( (s=find_worst_seq (sim, A->nseq, keep, maxsim, direction))!=-1 && new_nseq>maxnseq) + { + for ( a=0; a< A->nseq; a++)sim[a][s]=sim[s][a]=-1; + keep[s]=-1; + new_nseq--; + } + + /*Trim Outlayers*/ + if (outlayers!=0) + { + int nn, b; + tot_avg=vcalloc ( A->nseq, sizeof (int)); + + for (a=0; anseq; a++) + { + if ( keep[a]==-1)tot_avg[a]=-1; + else + { + for (nn=0, b=0; b< A->nseq; b++) + { + if (a==b || keep[b]==-1)continue; + else + { + tot_avg[a]+=sim[a][b]; + nn++; + } + } + tot_avg[a]=(nn==0)?-1:(tot_avg[a])/nn; + } + } + for ( a=0; anseq; a++) + { + if (tot_avg[a]!=-1 && tot_avg[a]name[a]); + keep[a]=-1; + } + } + vfree ( tot_avg); + } + + for ( n=0, a=0; a< A->nseq; a++) + { + if ( keep[a]!=-1) + { + list[n++]=a; + } + } + + R=extract_sub_aln (A, n, list); + free_int (sim, -1); vfree (list); + + return R; +} + +int find_worst_seq ( int **sim, int n, int *keep,int max,int direction) +{ + int **sc; + int a, b, r=0; + int si; + + sc=declare_int (n, 2); + if (direction==-1)max=100-max; + + for ( a=0; a< n; a++) sc[a][0]=a; + for ( a=0; a< n-1; a++) + { + for ( b=a+1; b=0)si=(direction==-1)?100-sim[a][b]:sim[a][b]; + else si=sim[a][b]; + if ( si>max) + { + if ( keep[a]!=1)sc[a][1]+=si; + if ( keep[b]!=1)sc[b][1]+=si; + } + } + } + + sort_int_inv ( sc, 2, 1, 0, n-1); + if ( sc[0][1]>0)r=sc[0][0]; + else r=-1; + + free_int (sc, -1); + if (r!=-1 && keep && keep[r])return -1; + else return r; +} + +int find_worst_seq_old ( int **sim, int n, int *keep,int max,int direction) +{ + int **sc; + int a, b, r=0; + + sc=declare_int (n, 2); + + for ( a=0; a< n; a++) sc[a][0]=a; + for ( a=0; a< n-1; a++) + { + for ( b=a+1; bmax) + { + if ( keep[a]!=1)sc[a][1]+=sim[a][b]; + if ( keep[b]!=1)sc[b][1]+=sim[a][b]; + } + } + else if ( direction == -1) + { + if ( sim[a][b]=0) + { + if ( keep[a]!=1)sc[a][1]+=sim[a][b]; + if ( keep[b]!=1)sc[b][1]+=sim[a][b]; + } + } + } + } + + if ( direction ==1) //remove max + { + sort_int_inv ( sc, 2, 1, 0, n-1); + if ( sc[0][1]>0)r=sc[0][0]; + else r=-1; + + } + else if ( direction ==-1)//remove min + { + sort_int_inv ( sc, 2, 1, 0, n-1); + if ( sc[0][1]>=0)r=sc[0][0]; + else r=-1; + HERE ("** %d %d\n", r,sc[0][1]); + } + free_int (sc, -1); + if (r!=-1 && keep && keep[r])return -1; + else return r; +} + + +Alignment * trimseq( Alignment *A, Sequence *S,char *mode) + { + Alignment *NA; + char *p; + int a, b; + int use_aln=0, upper_sim=0, min_nseq=0, lower_sim=0; + char weight_mode[1000]; + char method[1000]; + int statistics=0; + int trim_direction=TOP; + float **sim_weight; + int *seq_list; + int table=0; + int print_name=0; + float f_lower_sim, f_upper_sim; + + + + /* + mode: + (trim)__%_n_w + */ + + + + seq_list=vcalloc ( S->nseq, sizeof (int)); + for ( a=0; a< A->nseq; a++) + { + seq_list[a]=1; + } + + + use_aln=aln_is_aligned(A); + + + if ( mode[0]=='\0') + { + + upper_sim=50; + lower_sim=0; + min_nseq=0; + sprintf (weight_mode, "pwsim_fragment"); + sprintf ( method, "clustering2"); + } + else + { + + upper_sim=lower_sim=min_nseq; + sprintf (weight_mode, "pwsim_fragment"); + sprintf ( method, "clustering2"); + } + + /* + U or % (deprecated) Upper bound for pairwise similarity + L or m (depercated) Lower bound for pairwise similarity + n max number of sequences + N max number of sequences as a fraction of thet total + S print Statistics + T print Table of distances + */ + + + + while ( (p=strtok(mode, "_"))) + { + mode=NULL; + if (strm (p, "seq"))use_aln=0; + else if ( strm(p,"aln"))use_aln=1; + else if (p[0]=='s')statistics=1; + else if (p[0]=='t')table=1; + else if (p[0]=='p')print_name=1; + else if (p[0]=='U')upper_sim=atoi(p+1); + else if (p[0]=='L')lower_sim=atoi(p+1); + else if (p[0]=='n')min_nseq=atoi(p+1); + else if (p[0]=='N')min_nseq=atoi(p+1)*-1; + else if (p[0]=='B')trim_direction=BOTTOM; + else if (p[0]=='T')trim_direction=TOP; + else if (p[0]=='W')sprintf (weight_mode, "%s", p+1); + else if (p[0]=='M')sprintf (method, "%s", p+1); + else if (p[0]=='K') + { + + while ((p=strtok(NULL, ":"))) + { + + if ( (a=name_is_in_list (p, A->name, A->nseq, 100))!=-1) + { + seq_list[a]=2; + } + } + } + } + + if ( !upper_sim && !min_nseq && !lower_sim)upper_sim=50; + + + + if (!S) + { + fprintf ( stderr, "\ntrimseq requires a set of sequences[FATAL:%s]\n", PROGRAM); + crash(""); + } + + else if ( min_nseq> S->nseq) + { + min_nseq=S->nseq; + } + else if ( min_nseq<0) + { + if ( min_nseq<-100) + { + add_warning ( stderr, "\nWARNING: trimseq: Nseq(N) max_val=100%% [Automatic reset]\n"); + min_nseq=-100; + } + + min_nseq=(int)((float)S->nseq*((float)min_nseq/100)*-1); + } + + + NA=seq2subseq2 (A, S,use_aln,lower_sim,upper_sim,min_nseq,trim_direction, weight_mode,&sim_weight, seq_list ); + + if ( table) + { + fprintf ( stderr, "\nSIMILARITY MATRIX\n"); + for ( a=0; a< A->nseq-1; a++) + for ( b=a+1; b< A->nseq; b++) + { + fprintf ( stderr, "%15s Vs %15s : %3.2f %% id\n", A->name[a], A->name[b], 100-sim_weight[a][b]); + } + } + + NA=seq_name2removed_seq_name(S, NA,sim_weight); + + if ( print_name) + { + fprintf ( stderr, "\nList of sequences with their closest removed neighbors\n"); + for ( a=0; a< NA->nseq; a++)fprintf ( stderr, "\n%s: %s\n", NA->name[a], NA->seq_comment[a]); + } + + if ( statistics) + { + f_lower_sim=(lower_sim>100)?(float)lower_sim/100:lower_sim; + f_upper_sim=(upper_sim>100)?(float)upper_sim/100:upper_sim; + + fprintf ( stderr, "\nTRIM seq Informations:\n"); + fprintf ( stderr, "\tUse...........: %s\n",(use_aln)?"multiple_aln":"pairwise_aln"); + fprintf ( stderr, "\tcluster_mode..: %s\n" ,method); + fprintf ( stderr, "\tsim_mode......: %s\n" ,weight_mode); + fprintf ( stderr, "\tlower_id_bound: %.2f%%\n" ,(f_lower_sim==0)?-1:f_lower_sim); + fprintf ( stderr, "\tupper_id_bound: %.2f%%\n",(f_upper_sim==0)?-1:f_upper_sim); + fprintf ( stderr, "\tnseq_kept.....: %d (out of %d)\n" ,NA->nseq, S->nseq); + fprintf ( stderr, "\treduction.....: %d%% of original set\n" ,(NA->nseq*100)/S->nseq); + fprintf ( stderr, "\tTrim_direction: From %s \n" ,(trim_direction==BOTTOM)?"Bottom":"Top"); + } + + return NA; + } + +Alignment * tc_trimseq( Alignment *A, Sequence *S,char *mode) + { + Alignment *NA; + Sequence *TS; + char *trimfile, *alnfile; + int *seq_list; + int a, nseq=0, sim=0; + char *p; + char command[100000]; + char keep_list[10000]; + + int top, bottom, middle, pmiddle; + + keep_list[0]='\0'; + + seq_list=vcalloc ( S->nseq, sizeof (int)); + for ( a=0; a< A->nseq; a++) + { + seq_list[a]=1; + } + + trimfile=vtmpnam (NULL); + alnfile=vtmpnam (NULL); + if ( !aln_is_aligned (A)) + { + fprintf ( stderr, "\ntrimTC: computation of an Approximate MSA ["); + A=compute_tcoffee_aln_quick ( A, NULL); + fprintf ( stderr, "DONE]\n"); + } + output_clustal_aln (alnfile, A); + + + while ( (p=strtok(mode, "#"))) + { + mode=NULL; + + + if (p[0]=='%' || p[0]=='S')sim=(p[1]=='%')?atoi(p+2):atoi(p+1); + else if (p[0]=='n' || p[0]=='N')nseq=atoi(p+1); + else if (p[0]=='K') + { + if ( (a=name_is_in_list (p+1, A->name, A->nseq, 100))!=-1) + { + seq_list[a]=2; + } + + } + } + if ( nseq ==0 && sim ==0) + { + fprintf ( stderr, "\nERROR: trimTC\nIndicate the maximum number of sequences Nnseq\nOR the maximum average similarity of the chosen sequencesSx\nEX: +trimTC S20 OR +trimTC N5"); + fprintf ( stderr, "\n[FATAL:%s]", PROGRAM); + myexit (EXIT_FAILURE); + } + + for ( a=0; anseq; a++)if (seq_list[a]==2){strcat ( keep_list, A->name[a]);strcat ( keep_list," ");} + + if ( sim) + { + sprintf ( command , "%s -infile %s -trim -trimfile=%s -split_score_thres %d -convert -iterate 0 ",get_string_variable("t_coffee"), alnfile, trimfile,sim); + if ( keep_list[0]){strcat ( command, " -seq_to_keep ");strcat ( command, keep_list);} + my_system ( command); + TS=read_sequences (trimfile); + } + else if ( nseq && A->nseq>nseq) + { + + top=100;bottom=0; + pmiddle=0;middle=50; + + sprintf ( command , "%s -infile %s -trim -trimfile=%s -split_score_thres %d -convert -iterate 0",get_string_variable("t_coffee"), alnfile, trimfile,middle); + if ( keep_list[0]){strcat ( command, " -seq_to_keep ");strcat ( command, keep_list);} + my_system ( command); + + TS=read_sequences (trimfile); + fprintf ( stderr, "\n\tTrimTC: Sim %d Nseq %d\t",middle, TS->nseq); + + if ( TS->nseq>nseq)top=middle; + else if ( TS->nseqnseq!=nseq && pmiddle!=middle) + { + + sprintf ( command , "%s -infile %s -trim -trimfile=%s -split_score_thres %d -convert -iterate 0 ",get_string_variable("t_coffee"), alnfile, trimfile,middle); + if ( keep_list[0]){strcat ( command, " -seq_to_keep ");strcat ( command, keep_list);} + my_system ( command); + free_sequence (TS, -1); + TS=read_sequences (trimfile); + fprintf ( stderr, "\n\tTrimTC: Sim %d Nseq %d\t", middle, TS->nseq); + + if ( TS->nseq>nseq)top=middle; + else if ( TS->nseq100)?(float)int_lower_sim/100:int_lower_sim; + upper_sim=(int_upper_sim>100)?(float)int_upper_sim/100:int_upper_sim; + + sim_weight[0]=get_weight ((use_aln)?A:NULL, S, weight_mode); + + name=declare_char (S->nseq, (MAXNAMES+1)); + seq= declare_char (S->nseq, S->max_len+1); + + /* + Remove every sequence that is more than upper_sim and less than lower_sim similar to the master sequences + the master sequence(s) are those for which seq_list[x]==2 + */ + + + + + new_nseq=A->nseq; + + + for (a=0; a< A->nseq; a++) + { + if ( seq_list[a]==2) + { + + for ( b=0; b< A->nseq;b++) + { + sim=100-sim_weight[0][a][b]; + if (seq_list[b]==1 && (sim>upper_sim || simnseq; a++) + { + if ( seq_list[a]) + { + sprintf ( name[b], "%s", S->name[a]); + sprintf ( seq[b] , "%s",(use_aln)?A->seq_al[a]: S->seq[a] ); + b++; + } + } + + + NS=fill_sequence_struc (new_nseq,seq,name); + NA=seq2aln(NS,NULL,1); + + if ( use_aln && A) + { + NA=realloc_aln2 ( NA,A->max_n_seq,A->len_aln+1); + + for (b=0, a=0; anseq; a++) + { + if ( seq_list[a]) + { + sprintf ( NA->seq_al[b] , "%s",A->seq_al[a]); + b++; + } + } + + NA->len_aln=A->len_aln; + ungap_aln(NA); + } + + + return NA; +} +Alignment* seq2subseq2( Alignment *A, Sequence *S,int use_aln, int int_lower_sim,int int_upper_sim, int min_nseq, int trim_direction, char *weight_mode, float ***sim_weight, int *seq_list) +{ + int a, b; + int new_nseq; + int seq_index=0; + /*OUTPUT*/ + char **seq, **name; + Sequence *NS; + Alignment *NA; + float lower_sim, upper_sim; + + lower_sim=(int_lower_sim>100)?(float)int_lower_sim/100:int_lower_sim; + upper_sim=(int_upper_sim>100)?(float)int_upper_sim/100:int_upper_sim; + + + sim_weight[0]=get_weight ((use_aln)?A:NULL, S, weight_mode); + + name=declare_char (S->nseq, (MAXNAMES+1)); + seq= declare_char (S->nseq, S->max_len+1); + + /* + 1 REMOVE OUTLAYERS + 2 REMOVE CLOSELY RELATED SEQUENCES + 3 IF STILL TOO MANY SEQUENCES: + REMOVE THE MOST CLOSELY RELATED ONES + */ + + + /*1 Remove outlayers*/ + + new_nseq=A->nseq; + + + /*1 Remove outlayers*/ + while ( lower_sim && (extreme_seq(BOTTOM,A,sim_weight[0],seq_list, &seq_index) min_nseq) && seq_index!=-1) + { + + if ( seq_list[seq_index]==1) + { + seq_list[seq_index]=0; + new_nseq--; + } + } + /*2 Remove close relative*/ + + + while ( upper_sim && (extreme_seq(TOP, A,sim_weight[0],seq_list, &seq_index)>upper_sim) && ((new_nseq)>min_nseq)&& seq_index!=-1) + { + + if ( seq_list[seq_index]==1) + { + seq_list[seq_index]=0; + new_nseq--; + } + } + + + /*Remove extra sequences*/ + + while ( min_nseq>0 && new_nseq>min_nseq && seq_index!=-1) + { + + extreme_seq(trim_direction, A,sim_weight[0],seq_list, &seq_index); + + if ( seq_index==-1)break; + if ( seq_list[seq_index]==1) + { + seq_list[seq_index]=0; + new_nseq--; + } + } + + + /*Prepare the new sequence List*/ + + for (b=0, a=0; anseq; a++) + { + if ( seq_list[a]) + { + sprintf ( name[b], "%s", S->name[a]); + sprintf ( seq[b] , "%s",(use_aln)?A->seq_al[a]: S->seq[a] ); + b++; + } + } + + + NS=fill_sequence_struc (new_nseq,seq,name); + NA=seq2aln(NS,NULL,1); + + if ( use_aln && A) + { + NA=realloc_aln2 ( NA,A->max_n_seq,A->len_aln+1); + + for (b=0, a=0; anseq; a++) + { + if ( seq_list[a]) + { + sprintf ( NA->seq_al[b],"%s",A->seq_al[a]); + b++; + } + } + + NA->len_aln=A->len_aln; + ungap_aln(NA); + } + + + return NA; +} + +float extreme_seq (int direction, Alignment *A,float **sim_weight,int *seq_list, int *seq_index) +{ + + /*find the closest relative of each sequence + Return: + Direction= BOTTOM: the sequence whose closest relative is the most distant + Direction= TOP: the sequence whose closest relative is the closest + weight: different sequences=100 + similar sequences =0 + */ + int a, b; + + float top_sim,bottom_sim, best_sim, sim; + int top_seq, bottom_seq; + + bottom_seq=top_seq=seq_index[0]=-1; + top_sim=-1; + bottom_sim=101; + + for (a=0; a< A->nseq; a++) + { + if (seq_list[a]!=1)continue; + + for ( best_sim=0, b=0; b< A->nseq; b++) + { + if ( a==b || !seq_list[b])continue; + + sim=100-sim_weight[a][b]; + if (sim>best_sim) + { + best_sim=sim; + } + } + + if ( best_sim>top_sim) + { + top_seq=a; + top_sim=best_sim; + } + + if ( best_sim_%_n_w + */ + + sim_weight=get_weight ((use_aln)?A:NULL, S, weight_mode); + pw_weight=declare_float (S->nseq, S->nseq); + seq_weight=declare_float ( S->nseq, 2); + + + for (best_score=0,a=0; anseq; a++) + { + for ( b=0; bnseq; b++) + { + if ( a==b)continue; + seq_weight[a][0]+=sim_weight[a][b]; + } + seq_weight[a][0]=seq_weight[a][0]/(S->nseq-1); + score=seq_weight[a][0]=100-seq_weight[a][0]; + + if ( score>best_score) + { + best_seq=a; + best_score=score; + } + + } + for (a=0; anseq; a++) + { + for ( b=0; bnseq; b++) + { + if ( a==b)continue; + pw_weight[a][b]=sim_weight[a][b]*seq_weight[a][0]*seq_weight[b][0]/(100*100); + + } + } + + + seq_list=vcalloc ( S->nseq, sizeof (int)); + used_seq_list=vcalloc ( S->nseq, sizeof (int)); + + + + name=declare_char (S->nseq, (MAXNAMES+1)); + seq= declare_char (S->nseq, S->max_len+1); + + /*compute the normalization factor*/ + for (sum=0,d=0; d< S->nseq; d++) + { + for (score=0,c=0; cnseq; c++) + { + if ( c!=d) + score=MAX(score, 100-sim_weight[c][d]); + } + sum+=score; + } + sum=sum/S->nseq; + /*chose the first sequence */ + for ( best_score=0,a=0; a< S->nseq; a++) + { + for (score=0, b=0; b< S->nseq; b++) + { + score+=100-sim_weight[a][b]; + } + if ( score>best_score) + { + best_seq=a; + best_score=score; + } + + } + + + last_chosen=chosen=((best_score/S->nseq)*100)/sum; + nchosen=last_nchosen=1; + seq_list[0]=best_seq; + used_seq_list[best_seq]=1; + + sprintf ( name[0],"%s", S->name[seq_list[0]]); + sprintf ( seq[0],"%s", S->seq[seq_list[0]]); + nchosen=last_nchosen=1; + + + fprintf ( stderr, "\nTRIM:\n"); + fprintf ( stderr, "\n1-Chosen Sequences\n"); + /*Assemble the list of sequences*/ + for (a=1; a< S->nseq; a++) + { + for (best_score=0,b=0; b< S->nseq; b++) + { + if (used_seq_list[b]); + else + { + score=pw_weight[seq_list[0]][b]+1; + for (c=0; c=best_score) + { + best_seq=b; + best_score=score; + } + + } + } + seq_list[a]=best_seq; + used_seq_list[best_seq]=1; + + + + for ( chosen=0,d=0; d< S->nseq; d++) + { + for (score=0, c=0; c<=a; c++) + { + if ( seq_list[c]!=d) + score=MAX(score, 100-sim_weight[seq_list[c]][d]); + } + chosen+=score; + + } + + chosen=((chosen/S->nseq)*100)/sum; + nchosen=a+1; + + condition1= (int)chosen<=(int)percent || !percent; + condition2=(nchosen)<=max_nseq || !max_nseq; + + if (condition1 && condition2) + { + fprintf ( stderr, "\tADD %s (set score: %.2f %%)\n", S->name[seq_list[a]], chosen); + sprintf ( name[a],"%s", S->name[seq_list[a]]); + sprintf ( seq[a],"%s", S->seq[seq_list[a]]); + + } + else + { + break; + } + last_chosen=chosen; + last_nchosen=nchosen; + } + + NS=fill_sequence_struc (last_nchosen,seq,name); + NA=seq2aln(NS,NULL,1); + fprintf ( stderr, "\n2-Informations:\n"); + fprintf ( stderr, "\tUse...........: %s\n",(use_aln)?"multiple_aln":"pairwise_aln"); + fprintf ( stderr, "\tweight_mode...: %s\n" ,weight_mode); + fprintf ( stderr, "\tpercent_weight: %.2f%% (max=%d%%)\n",last_chosen,percent); + fprintf ( stderr, "\tn_seq.........: %d\n" ,NS->nseq); + fprintf ( stderr, "\treduction.....: %d%% of original set\n" ,(NS->nseq*100)/S->nseq); + + return NA; + } +Sequence * seq_weight2species_weight (Alignment *A, Sequence *S) +{ + float *wsp; + float *wseq; + int a,b; + + S->W=declare_weights(S->nseq); + if (!A->S || !(A->S)->W)aln2voronoi_weights (A); + + wseq=((A->S)->W)->SEQ_W; + wsp=(S->W)->SEQ_W; + for ( a=0; a< S->nseq; a++) + { + for (b=0; bnseq; b++) + if ( strstr (A->name[b], S->name[a]))wsp[a]+=wseq[b]; + } + for (a=0; anseq; a++) + fprintf ( stderr, "\nVoronoi Weights: Species %s ---> %.2f\n", S->name[a], wsp[a]); + return S; +} +Alignment * aln2voronoi_weights (Alignment *A) +{ + int a, b, c; + float t=0; + int **tab; + float *w; + + tab=declare_int (256, A->nseq+1); + if (A->S)free_sequence (A->S, (A->S)->nseq); + A->S=aln2seq(A); + (A->S)->W=declare_weights (A->nseq); + w=((A->S)->W)->SEQ_W; + + for (a=0; alen_aln; a++) + { + for ( b=0; bnseq; b++) + { + c= A->seq_al[b][a]; + if (!is_gap(c)) + { + c=tolower(c); + tab[c][++tab[c][0]]=b; + } + } + for (c=0; c<256; c++) + { + if (tab[c][0]) + { + for (b=1; b<=tab[c][0]; b++) + { + w[tab[c][b]]+=(float)1/(float)tab[c][0]; + t+=(float)1/(float)tab[c][0]; + } + } + tab[c][0]=0; + } + } + for (a=0; anseq; a++) + { + w[a]=(w[a]/t)*A->nseq; + } + + return A; +} + +float ** get_weight ( Alignment *A, Sequence *S, char *mode) +{ + char *aln_name; + char *weight_name; + char *seq_name; + char command[LONG_STRING]; + char program[LONG_STRING]; + float **weight; + FILE *fp; + int c; + + if ( !mode || !mode[0] || strm (mode, "msa")) + { + if ( getenv ( "SEQ2MSA_WEIGHT")==NULL)sprintf (program, "%s",SEQ2MSA_WEIGHT); + else sprintf ( program, "%s", (getenv ( "SEQ2MSA_WEIGHT"))); + } + else if ( strm(mode, "pwsim") ||strm(mode, "pwsim_fragment") ) + { + return seq2pwsim (A, S, mode); + } + else + { + if (getenv (mode))sprintf ( program, "%s", (getenv (mode))); + else fprintf ( stderr, "\nERROR: %s is not a valid mode for weight computation [FATAL:%s]", mode, PROGRAM); + } + + /*MSA weights*/ + seq_name=vtmpnam(NULL); + aln_name=vtmpnam(NULL); + weight_name=vtmpnam(NULL); + weight=declare_float (S->nseq+1, 2); + + + + if (A) + { + output_clustal_aln (seq_name,A); + output_fasta_seq (aln_name,A); + sprintf ( command, "%s %s -i %s -w %s", program, seq_name, aln_name, weight_name); + } + else + { + A=seq2aln(S,A,1); + output_fasta_seq (seq_name,A); + sprintf ( command, "%s %s -w %s", program, seq_name, weight_name); + } + + + my_system ( command); + + fp=vfopen( weight_name, "r"); + while ( (c=fgetc(fp))!='$'); + c=fgetc(fp); + c=0; + while ( (fscanf (fp, "%*s %f\n",&(weight[c][1])))==1) + {weight[c][0]=c;c++;} + vfclose (fp); + + + return weight; +} + +float **seq2pwsim ( Alignment *A, Sequence *S, char *mode) +{ + int a, b, c; + float d,t; + float **W; + Alignment *B; + W=declare_float (S->nseq, S->nseq); + + + + for (a=0; a< S->nseq; a++) + for ( b=a; bnseq; b++) + { + if ( a==b){d=1;} + else if (!A) + { + + B=align_two_sequences ((S)->seq[a], (S)->seq[b],"pam250mt", -10, -1, "fasta_pair_wise"); + for (t=0,d=0,c=0; clen_aln; c++) + { + d+=(B->seq_al[0][c]==B->seq_al[1][c] && !is_gap(B->seq_al[0][c])); + t+=(!is_gap(B->seq_al[0][c]) && !is_gap(B->seq_al[1][c])); + } + t=(strm ( mode, "pwsim_fragment"))?B->len_aln:t; + + d=d/((t==0)?1:t); + free_aln(B); + } + else + { + for (t=0,d=0,c=0; clen_aln; c++) + { + d+=(A->seq_al[a][c]==A->seq_al[b][c] && !is_gap(A->seq_al[a][c])); + t+=(!is_gap(A->seq_al[a][c]) && !is_gap(A->seq_al[b][c])); + } + d=d/((t==0)?1:t); + } + + + W[a][b]=W[b][a]=(1-d)*100; + } + + + return W; + +} + +float **seq2pwsim_fragment ( Alignment *A, Sequence *S, char *mode) +{ + + + int a, b, c; + float d,t; + float **W; + Alignment *B; + W=declare_float (S->nseq, S->nseq); + + + + + for (a=0; a< S->nseq; a++) + for ( b=a; bnseq; b++) + { + if ( a==b){d=1;} + else if (!A) + { + + B=align_two_sequences ((S)->seq[a], (S)->seq[b],"pam250mt", -10, -1, "fasta_pair_wise"); + for (t=0,d=0,c=0; clen_aln; c++) + { + d+=(B->seq_al[0][c]==B->seq_al[1][c] && !is_gap(B->seq_al[0][c])); + t+=(!is_gap(B->seq_al[0][c]) && !is_gap(B->seq_al[1][c])); + } + + d=d/((t==0)?1:t); + free_aln(B); + } + else + { + for (t=0,d=0,c=0; clen_aln; c++) + { + d+=(A->seq_al[a][c]==A->seq_al[b][c] && !is_gap(A->seq_al[a][c])); + t+=(!is_gap(A->seq_al[a][c]) && !is_gap(A->seq_al[b][c])); + } + d=d/((t==0)?1:t); + } + + + W[a][b]=W[b][a]=(1-d)*100; + } + + + return W; + +} + +/********************************************************************/ +/* */ +/* AMINO ACID FUNCTIONS */ +/* */ +/* */ +/* */ +/********************************************************************/ +//Builds an extended alphabet from a string +char** string2alphabet (char *string, int depth, int *falp_size) +{ + int max_s; + int a, b,c, l, n; + char buf[1000]; + char **alp; + int alp_size; + + char ***alp2; + int *alp2_size; + + int *array; + char **falp; + + + l=strlen (string); + array=vcalloc ( 256, sizeof (int)); + + + max_s=l+1; + falp_size[0]=0; + falp=declare_char (l+1, 2); + + alp=declare_char(l,2); + alp_size=0; + + array=vcalloc ( 256, sizeof (int)); + for (a=0;a0) + { + for ( c=0,b=0;b< 26; b++) + { + + if ( matrix[a][b]>0 && matrix[b][b]>0) + { + buf[c++]=b+'A'; + buf[c++]=b+'a'; + } + } + buf[c]='\0'; + for ( is_in=0,b=0; b< ngroup[0]; b++)if ( strcmp (buf, group_list[b])==0)is_in=1; + if (is_in==0)sprintf ( group_list[ngroup[0]++], "%s", buf); + + } + } + free_int (matrix, -1); + vfree (matrix_name); + + return group_list; + } +char** make_group_aa_upgma (char*matrix, int max_n) + { + char **group_list; + int **mat; + int *used; + int a, b, ba, bb, best, set, l, n; + l=26; + + group_list=declare_char (l+1, l+1); + for (a=0; amax_n) + { + for (set=0,a=0; abest) + { + best=mat[a][b]; + ba=a; + bb=b; + set=1; + } + } + + for (a=0; ac)?d[a]:c; + return c; + } + + + +int is_in_same_group_aa ( char r1, char r2, int n_group, char **gl, char *mode) + { + int a; + static char **lgl; + static int ln_group; + + char **gl2; + int n_group2; + + /*use mode=idmat for similarity based on id*/ + + r1=toupper(r1); + r2=toupper(r2); + if (mode==NULL)return (r1==r2)?1:0; + + if ( strm (mode, "clean")) + { + free_char (lgl, -1); + lgl=NULL; + ln_group=0; + return 0; + } + else if ( strstr (mode, "cov")) + { + return 1; + } + + if ( lgl==NULL) + { + lgl=make_group_aa ( &ln_group, mode); + } + + if ( gl==NULL) + { + gl2=lgl; + n_group2=ln_group; + } + else + { + gl2=gl; + n_group2=n_group; + } + + for ( a=0; a< n_group2; a++) + if ( is_in_set ( r1, gl2[a]) && is_in_set ( r2, gl2[a]))return 1; + return 0; + } + + +Alignment * gene2prot (Alignment *A){return A; } +char * test_gene2prot (Constraint_list *CL, int s1) + { + int a, b,q, nal; + int F=-10000000; /*FORBIDEN STATE*/ + int AL=0; /*ALLOWED STATE*/ + int SPLICE_PENALTY=1000; + int FRAME_PENALTY=1000; + + + int START, ORF1, ORF2, ORF3, s5NC; + int s3NC,ORF3_G1, ORF3_T2, ORF3_NC, ORF3_A3, ORF3_T4; + int U1_G1, U1_T2, U1_NC, U1_A3, U1_T4; + int U2_G1, U2_T2, U2_NC, U2_A3, U2_T4; + int U1, U2, U3, U4, U5, END; + + int nstate=0; + int **transitions; + int **v_tab; + int **v_tab_p; + int **last_coding; + int **last_t4; + int *potential; + int v; + + int orf1, orf2, orf3, ncp, p, state, pstate, e, best_state_p=0, best_state_v=0, best_pstate_p=0, best_pstate_v; + char *seq, *seq2, *seq3; + int l; + int *is_coding; + int *is_t4; + char *codon; + int s, r, s2, r2, w2; + + static int *entry; + int tot=0; + + seq=vcalloc ( strlen ((CL->S)->seq[s1])+1, sizeof (char)); + seq2=vcalloc ( strlen ((CL->S)->seq[s1])+1, sizeof (char)); + seq3=vcalloc ( strlen ((CL->S)->seq[s1])+1, sizeof (char)); + sprintf ( seq, "%s", (CL->S)->seq[s1]); + ungap (seq); + + l=strlen (seq); + for ( a=0; a< l; a++) seq[a]=tolower ( seq[a]); + for ( a=0; a< l; a++) seq[a]=(seq[a]=='t')?'u': seq[a]; + + + potential=vcalloc (l+1, sizeof (int)); + + for (nal=0, s=0; s<(CL->S)->nseq; s++) + { + for ( r=1; r<=(CL->S)->len[s]; r++) + { + for ( b=1; bresidue_index[s1][r][0]; b++) + { + + s2=CL->residue_index[s][r][b+SEQ2]; + r2=CL->residue_index[s][r][b+R2]; + w2=CL->residue_index[s][r][b+WE]; + if (s==s1)potential[r-1]+=w2; + else if ( s2==s1)potential[r2-1]+=w2; + tot+=w2; + nal++; + } + } + } + + + SPLICE_PENALTY=10000; + FRAME_PENALTY=1000; + + + nstate=0; + START=nstate++; ORF1=nstate++; ORF2=nstate++; ORF3=nstate++; s5NC=nstate++; + s3NC=nstate++; + ORF3_G1=nstate++;U1_G1=nstate++;U2_G1=nstate++; + ORF3_T2=nstate++;U1_T2=nstate++;U2_T2=nstate++; + ORF3_NC=nstate++;U1_NC=nstate++;U2_NC=nstate++; + ORF3_A3=nstate++;U1_A3=nstate++;U2_A3=nstate++; + ORF3_T4=nstate++;U1_T4=nstate++;U2_T4=nstate++; + + + U1=nstate++; U2=nstate++; U3=nstate++; U4=nstate++; U5=nstate++; + END=nstate++; + + is_coding=vcalloc ( nstate, sizeof (int)); + is_coding[ORF1]=is_coding[ORF2]=is_coding[ORF3]=is_coding[U1]=is_coding[U2]=1; + is_coding[U3]=is_coding[U4]=is_coding[U5]=1; + + is_t4=vcalloc ( nstate, sizeof (int)); + is_t4[ORF3_T4]=is_t4[U1_T4]=is_t4[U2_T4]=1; + transitions=declare_int ( nstate, nstate); + for (a=0; a< nstate; a++) + for ( b=0; b< nstate; b++)transitions[a][b]=F; + + transitions[START][ORF1]=AL; + transitions[START][s5NC]=AL-FRAME_PENALTY; + transitions[s5NC][s5NC]=AL; + + transitions[s5NC][ORF1]=AL-FRAME_PENALTY; + + transitions[ORF1][ORF2]=AL; + transitions[ORF2][ORF3]=AL; + transitions[ORF3][U1]=AL; + transitions[ORF3][ORF1]=AL; + transitions[ORF3][ORF3_G1]=AL-SPLICE_PENALTY; + + + transitions[ORF3_G1][ORF3_T2]=AL; + transitions[ORF3_T2][ORF3_NC]=AL; + transitions[ORF3_NC][ORF3_NC]=AL; + transitions[ORF3_NC][ORF3_A3]=AL; + transitions[ORF3_A3][ORF3_T4]=AL; + transitions[ORF3_T4][ORF1]=AL-SPLICE_PENALTY; + + transitions[U1][U2]=AL; + transitions[U1][U1_G1]=AL-SPLICE_PENALTY; + transitions[U1_G1][U1_T2]=AL; + transitions[U1_T2][U1_NC]=AL; + transitions[U1_NC][U1_NC]=AL; + transitions[U1_NC][U1_A3]=AL; + transitions[U1_A3][U1_T4]=AL; + transitions[U1_T4][U3]=AL-SPLICE_PENALTY; + transitions[U3][U4]=AL; + transitions[U4][ORF1]=AL; + + transitions[U2][U2_G1]=AL-SPLICE_PENALTY; + transitions[U2_G1][U2_T2]=AL; + transitions[U2_T2][U2_NC]=AL; + transitions[U2_NC][U2_NC]=AL; + transitions[U2_NC][U2_A3]=AL; + transitions[U2_A3][U2_T4]=AL; + transitions[U2_T4][U5]=AL-SPLICE_PENALTY; + transitions[U5][ORF1]=AL; + + transitions[ORF3][s3NC]=AL-FRAME_PENALTY; + transitions[ORF3][END]=AL; + transitions[s3NC][END]=AL; + + + v_tab=declare_int ( l+1,nstate); + v_tab_p=declare_int ( l+1,nstate); + last_coding=declare_int ( l+1,nstate); + last_t4=declare_int ( l+1,nstate); + + for (a=0; a< l; a++) potential[a]-=200; + + codon=vcalloc ( 4, sizeof (char)); + best_pstate_p=START; + best_pstate_v=0; + nal=0; + for ( p=1; p<=l; p++) + { + if (translate_dna_codon (seq+(p-1), 'x')=='x' || p>(l-2))orf1=F; + else orf1=potential[p-1]; + + if (p<2 || translate_dna_codon (seq+(p-2), 'x')=='x' || p>(l-1))orf2=F; + else orf2=potential[p-1]; + + + if (p<3 || translate_dna_codon (seq+(p-3), 'x')=='x' || p>l)orf3=F; + else orf3=potential[p-1]; + + if ( best_int (3, 1, &a, orf1, orf2, orf3)!=F)ncp=-best_int (3, 1, &a, orf1, orf2, orf3); + else ncp=1000; + + for ( state=0; state< nstate; state++) + { + + if ( state==ORF1)e=orf1; + else if ( state==ORF2)e=orf2; + else if ( state==ORF3)e=orf3; + else if ( state>=U1 && state<=U3) + { + e=0; + } + else if ( state==U4) + { + codon[2]=seq[p-1]; + codon[1]=seq[last_coding[p-1][U3]-1]; + codon[0]=seq[last_coding[p-2][U1_T4]-1]; + if ( translate_dna_codon (codon, 'x')=='x')e=F; + else e=0; + } + else if ( state==U5) + { + codon[2]=seq[p-1]; + codon[1]=seq[last_coding[p-1][U2_T4]-1]; + q=seq[last_coding[p-1][U2_T4]]; + codon[0]=seq[last_coding[q-1][U1]-1]; + if ( translate_dna_codon (codon, 'x')=='x')e=F; + else e=0; + } + + else if (state>=ORF3_G1 && state<=U2_G1)e=(p=ORF3_T2 && state<=U2_T2) + { + e=(p>1 && seq[p-2]=='g' && seq[p-1]=='u')?ncp:F; + } + else if ( state>=ORF3_A3 && state<=U2_A3)e=(seq[p-1]=='a')?ncp:F; + else if ( state>=ORF3_T4 && state<=U2_T4)e=(seq[p-1]=='u')?ncp:F; + else e=ncp; + + for ( pstate=0; pstatebest_pstate_v) + {best_pstate_v=v;best_pstate_p=pstate;} + } + v_tab[p][state]=best_pstate_v; + v_tab_p[p][state]=best_pstate_p; + + if (!is_coding[state])last_coding[p][state]=last_coding[p-1][best_pstate_p]; + else if (is_coding[state])last_coding[p][state]=p; + + if (!is_t4[state]) + { + if (is_coding[state] && last_t4[p-1][best_pstate_p]==0)last_t4[p][state]=p; + else last_t4[p][state]=last_t4[p-1][best_pstate_p]; + } + else if (is_t4[state])last_t4[p][state]=p; + + if (state==0 ||best_pstate_v>best_state_v ){best_state_p=state; best_state_v=best_pstate_v;} + } + } + tot=0; + for ( p=l; p>0; p--) + { + if ( best_state_p>=ORF1 && best_state_p<=ORF3){seq2[tot++]=tolower (seq[p-1]);} + else if ( best_state_p>=U1 && best_state_p<=U5){seq2[tot++]=tolower (seq[p-1]);} + if (best_state_p==ORF1)seq[p-1]=toupper (seq[p-1]); + else if (best_state_p==ORF2 || best_state_p==ORF3)seq[p-1]=tolower (seq[p-1]); + else if ( best_state_p==ORF3_NC || best_state_p==U1_NC || best_state_p==U2_NC) seq[p-1]='.'; + else if ( best_state_p==U1 || best_state_p==U2 || best_state_p==U3 || best_state_p==U4 || best_state_p==U5) seq[p-1]=best_state_p-U1+'1'; + else seq[p-1]=toupper (seq[p-1]); + best_state_p=v_tab_p[p][best_state_p]; + } + + for ( a=0, b=tot-1; b>=0; b--, a++) + seq3[a]=seq2[b]; + + fprintf ( stderr, "\n%s\n", seq); + fprintf ( stderr, "\nN coding=%d\n", tot); + for ( a=0; a< tot; a+=3) + { + b=translate_dna_codon (seq3+a, 'x'); + fprintf ( stderr, "%c",b); + if ( b=='x'){fprintf ( stderr, "\n");myexit (EXIT_SUCCESS);} + } + + fprintf ( stderr, "\n"); + myexit (EXIT_SUCCESS); + return 0; + + + + } +Alignment * dna_aln2_3frame_cdna_aln(Alignment *A,int *ns,int **l_s) +{ + Alignment *B; + int a; + B=realloc_aln2 (NULL,6,strlen(A->seq_al[l_s[0][0]])+strlen(A->seq_al[l_s[1][0]])); + for ( a=0; a< 3; a++) + { + B->seq_al[a]=translate_dna_seq (A->seq_al[l_s[0][0]]+a, 0, 'o',B->seq_al[a]); + B->seq_al[a+3]=translate_dna_seq (A->seq_al[l_s[1][0]]+a, 0, 'o',B->seq_al[a+3]); + } + for ( a=1; a<3; a++) + { + if ( strlen(B->seq_al[a])seq_al[0])) B->seq_al[a]=strcat ( B->seq_al[a], "x"); + if ( strlen(B->seq_al[a+3])seq_al[3])) B->seq_al[a+3]=strcat ( B->seq_al[a+3], "x"); + } + + B->nseq=6; + B->len_aln=strlen (B->seq_al[0]); + return B; +} + +//JM_ADD +//For normal distribution scan +#ifndef PI +#define PI 3.141592653589793238462643 +#endif + +double normal(double x, double mean, double std) +{ + return (1/(std*sqrt(2.0*PI)))*exp((-0.5*(x-mean)*(x-mean))/(std*std)); +} + +int ** get_sim_aln_array_normal_distribution ( Alignment *A, char *mode, int *STD, int *CENTER) + { + int **w; + int a, b; + + + w=declare_int ( A->nseq, A->nseq); + + for ( a=0; a< A->nseq-1; a++) + { + for ( b=a+1; b< A->nseq; b++) + { + + w[a][b]=w[b][a]=generic_get_seq_sim_normal_distribution ( A->seq_al[a], A->seq_al[b], (A->cdna_cache)?A->cdna_cache[0]:NULL, mode, STD, CENTER); + } + } + return w; + } +int generic_get_seq_sim_normal_distribution ( char *seq1, char *seq2, int*cache, char *mode, int *STD, int *CENTER) +{ + return get_seq_sim_distribution ( seq1,seq2,GAP_LIST, mode, STD, CENTER); +} + +int get_seq_sim_distribution ( char *string1, char *string2, char *ignore, char *in_mode, int *STD, int *CENTER) + { + int len1; + int a; + int pos0, gap=0; + int p1, p2; + int r=0,r1=0,r2=0; + char *p; + char mode[1000]; + + double sim; + + + sprintf ( mode, "%s", in_mode); + + /*mode: __ + mat: idscore to get the alignment done + any legal cw matrix + sim_mode: sim1->identities/matches + sim2->identities/min len + */ + + + if ( (p=strstr (mode, "_"))!=NULL) + { + p[0]='\0'; + p++; + } + + + if (strstr (mode, "idscore")) + { + static int **mat; + if (!mat) mat=read_matrice ("blosum62mt"); + return idscore_pairseq (string1, string2, -12, -1, mat,mode); + } + + len1=strlen (string1); + for ( sim=pos0=0,a=0; a< len1; a++) + { + r1=string1[a]; + r2=string2[a]; + p1=1-is_in_set (r1, ignore); + p2=1-is_in_set (r2, ignore); + if (p1 && p2) + { + pos0++; + if (is_in_same_group_aa(r1,r2,0, NULL, mode)) + { + sim += normal(a, *CENTER, *STD); + } + } + else if (p1+p2==1) + { + gap++; + } + } + + if ( p==NULL || strm (p, "sim1") || strm (p, "sim")) + { + r=(pos0==0)?0:(sim*MAXID); + } +/* else if ( strm (p, "sim2")) + { + r=(pos1==0 || pos2==0)?0:(sim*MAXID)/MIN(pos1,pos2); + } + else if ( strm (p, "sim3")) + { + r=(pos1==0 || pos2==0)?0:(sim*MAXID)/MAX(pos1,pos2); + } + else if ( strm (p, "gap1")) + { + r=(len1==0)?MAXID:(gap*MAXID)/len1; + r=MAXID-r; + } + else if ( strm (p, "logid")) + { + r=logid_score (pos0, sim); + }*/ + return r; + + } + + + +Alignment *aln2clean_pw_aln (Alignment *A, OveralnP *F)// char *mode, int t, int f, int p1,int p2, int p3, char *fsa_mode) +{ + int **C, **T; + int a, b, c; + Alignment *B; + + + if (F->t==0)F->t=2; + + C=declare_int ( A->nseq, A->len_aln); + T=declare_int ( A->nseq, A->len_aln); + B=copy_aln (A, NULL); + + for (a=0; a< A->nseq;a++) + { + for (b=0; bnseq; b++) + { + int *w; + w=pw_aln2clean_aln_weight (A->seq_al[a], A->seq_al[b], 1,F);//f,p1, p2, p3, fsa_mode); + for (c=0; clen_aln; c++) + { + if (A->seq_al[a][c]=='-')continue; + C[a][c]+=w[c]; + T[a][c]++; + } + vfree (w); + } + } + + + + for (a=0; anseq; a++) + { + for (b=0; blen_aln; b++) + { + int c; + c=A->seq_al[a][b]; + if ( c=='-'); + else if (T[a][b]==0); + else + { + int r; + r=(C[a][b]*10)/T[a][b]; + r=(r==10)?9:r; + if (!F->mode || strm (F->mode, "number")) + B->seq_al[a][b]='0'+r; + else if ( F->mode && (strm (F->mode, "unalign") ||strm (F->mode, "unalign2"))) + B->seq_al[a][b]='0'+r; + else if ( F->mode && strm (F->mode, "lower") ) + { + if (r<=F->t)B->seq_al[a][b]=tolower (B->seq_al[a][b]); + else B->seq_al[a][b]=toupper (B->seq_al[a][b]); + } + } + } + } + + if (F->mode && strm (F->mode, "unalign")) + { + A=unalign_aln (A, B, F->t); + free_aln (B); + B=copy_aln (A, NULL); + } + else if (F->mode && strm (F->mode, "unalign2")) + { + A=unalign_aln_2 (A, B, F->t); + free_aln (B); + B=copy_aln (A, NULL); + } + + + + free_int (C, -1); + free_int (T, -1); + + return B; +} + +char **pw_aln2clean_pw_aln_fsa1 (char ** aln, OveralnP *F); +char **pw_aln2clean_pw_aln_fsa2 (char ** aln, OveralnP *F); + +int * pw_aln2clean_aln_weight ( char *seq1, char *seq2, int w, OveralnP *F) +{ + char **aln; + int *weight; + int l, a; + + if ( (l=strlen (seq1)) !=strlen (seq2)) + { + HERE ("\n%s\n%s\n", seq1, seq2); + printf_exit ( EXIT_FAILURE, stderr, "\nERROR: Comparing unaligned sequences [FATAL:%s]", PROGRAM); + + } + + aln=declare_char (2, l+1); + sprintf ( aln[0], "%s", seq1); + sprintf ( aln[1], "%s", seq2); + + + aln=pw_aln2clean_pw_aln (aln, F); + + weight=vcalloc (l+1, sizeof (int)); + for (a=0; amodel, "fsa2"))return pw_aln2clean_pw_aln_fsa2 (aln,F); + else if ( strm (F->model, "fsa1"))return pw_aln2clean_pw_aln_fsa1 (aln,F); + else return pw_aln2clean_pw_aln_fsa1 (aln,F); +} + +char **pw_aln2clean_pw_aln_fsa2 (char ** aln, OveralnP *FO) +{ + int a, b, c, d, l, id; + int c1, c2, e0, e1,tb, obs; + int T0, T1,T2; + int **mat, **tran, **p, **t, *s, *ids; + int ns, ps, cs; + int S, M1, M2, m1, m2,B1, B2,G1,G2, K; + int F=-9999999; + int MID_EXON_FACTOR=50; + int best; + static int **smat; + int model_type=1; + int *translate; + + if ( getenv ("MID_EXON_FACTOR"))MID_EXON_FACTOR=atoi (getenv ("MID_EXON_FACTOR")); + + + + if (!smat)smat=read_matrice ( "blosum62mt"); + + l=strlen (aln[0]); + + if ( l!=strlen (aln[1])) + { + printf_exit ( EXIT_FAILURE, stderr, "\nERROR: unaligned strings"); + } + + + + s=vcalloc (l, sizeof (int)); + ids=vcalloc (l, sizeof (int)); + + //record the id level of each posotion + for (b=0; b=2){id++; s[a]=1;} + else {s[a]=0;} + b++; + } + } + + if (b==0) + { + vfree(s);vfree (ids); + return aln; + } + + + + FO->p1=(FO->p1==0)?5:FO->p1; + FO->p2=(FO->p2==0)?15:FO->p2; + FO->p3=(FO->p3==0)?0:FO->p3; + FO->p4=(FO->p4==0)?100:FO->p4; + + + T1=100*(float)id/(float)b; + T2=(FO->f==0)?30:T1*(float)((float)FO->f/(float)100); + T2=MAX(T2,20); + + //0: unaligned + //1: aligned + //2: gap + //3: exon boundary + + ns=0; + S=ns++; + M1=ns++;//1 matched aligned + m1=ns++;//2 mmatched aligned + M2=ns++;//3 matched unaligned + m2=ns++;//4 mmatched unaligned + B1=ns++;//5 transition aligned + B2=ns++;//6 transition unaligned + + mat=declare_int (ns, 4); + tran=declare_int (ns, ns); + p=declare_int (l+1, ns); + t=declare_int (l+1, ns); + + //emission Values + mat[M1][0]=F; //non id + mat[M1][1]=T1;//id + mat[M1][2]=0; //gap + mat[M1][3]=F; //transition + + mat[M2][0]=F; + mat[M2][1]=T2; + mat[M2][2]=0; + mat[M2][3]=F; + + mat[m1][0]=100-T1; + mat[m1][1]=F; + mat[m1][2]=0; + mat[m1][3]=F; + + mat[m2][0]=100-T2; + mat[m2][1]=F; + mat[m2][2]=0; + mat[m1][3]=F; + + mat[B1][0]=F; + mat[B1][1]=F; + mat[B1][2]=F; + mat[B1][3]=0; + + mat[B2][0]=F; + mat[B2][1]=F; + mat[B2][2]=F; + mat[B2][3]=0; + + //transition values + tran[S][m1]=0; + tran[S][m2]=0; + tran[S][M1]=0; + tran[S][M2]=0; + tran[S][B1]=0; + tran[S][B2]=0; + + + tran[M1][m1]= 0; + tran[M1][m2]=-FO->p4; + tran[M1][M1]=+FO->p2; + tran[M1][M2]= F; + tran[M1][S ]= F; + tran[M1][B1]= 0; + tran[M1][B2]=-FO->p1; + + tran[M2][m1]= F; + tran[M2][m2]=+FO->p3; + tran[M2][M1]= F; + tran[M2][M2]= 0; + tran[M2][S] = F; + tran[M2][B1]= F; + tran[M2][B2]= 0; + + + tran[m1][m1]= 0; + tran[m1][m2]= F; + tran[m1][M1]= 0; + tran[m1][M2]= F; + tran[m1][S] = F; + tran[m1][B1]= 0; + tran[m1][B2]=-FO->p1; + + tran[m2][m1]= F; + tran[m2][m2]= 0; + tran[m2][M1]= -FO->p4; + tran[m2][M2]= +FO->p3; + tran[m2][S] = F; + tran[m2][B1]= F; + tran[m2][B2]= 0; + + tran[B1][m1]= 0; + tran[B1][m2]= F; + tran[B1][M1]= 0; + tran[B1][M2]= F; + tran[B1][S]= F; + tran[B1][B1]= F; + tran[B1][B2]= F; + + tran[B2][m1]= -FO->p1; + tran[B2][m2]= 0; + tran[B2][M1]= -FO->p1; + tran[B2][M2]= 0; + tran[B2][S]= F; + tran[B2][B1]= F; + tran[B2][B2]= F; + + translate=vcalloc (ns, sizeof (int)); + translate[M1]=1; + translate[m1]=1; + translate[M2]=0; + translate[m2]=0; + translate[B1]=1; + translate[B2]=0; + + for (a=1;a<=l; a++) + { + obs=s[a-1]; + + for (cs=0; cs=best){t[a][cs]=ps;best=p[a][cs]=c;} + } + + } + } + + + for (a=0; a=best){tb=a;best=p[l][a];} + } + + for (a=l; a>0; a--) + { + int v; + int p2; + + p2=a-1; + aln[0][p2]=aln[1][p2]=translate[tb]; + tb=t[a][tb]; + + } + + free_int (p, -1); + vfree(s); + free_int (t, -1); + free_int (mat, -1); + free_int (tran, -1); + vfree (translate); + return aln; +} +char **pw_aln2clean_pw_aln_fsa1 (char ** aln, OveralnP *FO) +{ + int a, b, c, d, l, id; + int c1, c2, e0, e1,tb, obs; + int T0, T1,T2; + int **mat, **tran, **p, **t, **s; + int ns, ps, cs; + int S, M1, M2, m1, m2, K; + int F=-9999999; + int best; + static int **smat; + int *translate; + + + if (!smat)smat=read_matrice ( "blosum62mt"); + + l=strlen (aln[0]); + + if ( l!=strlen (aln[1])) + { + printf_exit ( EXIT_FAILURE, stderr, "\nERROR: unaligned strings"); + } + + + s=declare_int (l+1, 2); + for (id=0,b=0,a=0;a=2){id++; s[b][0]=1;} + else {s[b][0]=0;} + s[b][1]=a; + b++; + + } + } + if (b==0) + { + free_int (s, -1); + return aln; + } + FO->f=(FO->f==0)?30:FO->f; + FO->p1=(FO->p1==0)?90:FO->p1; + FO->p2=(FO->p2==0)?15:FO->p2; + FO->p3=(FO->p3==0)?0:FO->p3; + + l=b;//length of the ungapped aln + T1=100*(float)id/(float)b; + T2=FO->f;//T1*f; + + + + //0: unaligned + //1: aligned + + + ns=0; + S=ns++; + M1=ns++;//1 matched aligned + m1=ns++;//2 mmatched aligned + M2=ns++;//3 matched unaligned + m2=ns++;//4 mmatched unaligned + + mat=declare_int (ns, 2); + tran=declare_int (ns, ns); + p=declare_int (l+1, ns); + t=declare_int (l+1, ns); + + + mat[M1][0]=F; + mat[M1][1]=T1; + + mat[M2][0]=F; + mat[M2][1]=T2; + + mat[m1][0]=100-T1; + mat[m1][1]=F; + + mat[m2][0]=100-T2; + mat[m2][1]=F; + + + tran[S][m1]=0; + tran[S][m2]=0; + tran[S][M1]=0; + tran[S][M2]=0; + + + tran[M1][m1]= 0; + tran[M1][m2]=-FO->p1;// -P; + tran[M1][M1]=+FO->p2; + tran[M1][M2]= F; + tran[M1][S] = F; + + tran[M2][m1]= F; + tran[M2][m2]=+FO->p3; + tran[M2][M1]= F; + tran[M2][M2]= 0; + tran[M2][S]= F; + + tran[m1][m1]= 0; + tran[m1][m2]= F; + tran[m1][M1]= 0; + tran[m1][M2]= F; + tran[m1][S]= F; + + tran[m2][m1]= F; + tran[m2][m2]= 0; + tran[m2][M1]=-FO->p1; + tran[m2][M2]=+FO->p3; + tran[m2][S]= F; + + translate=vcalloc (ns, sizeof (int)); + translate[M1]=1; + translate[m1]=1; + translate[M2]=0; + translate[m2]=0; + translate[S]=1; + + + for (a=1;a<=l; a++) + { + obs=s[a-1][0]; + + for (cs=0; cs=best){t[a][cs]=ps;best=p[a][cs]=c;} + } + + } + } + + + for (a=0; a=best){tb=a;best=p[l][a];} + } + for (a=l; a>0; a--) + { + int p2=s[a-1][1]; + aln[0][p2]=aln[1][p2]=translate[tb]; + + tb=t[a][tb]; + } + + + free_int (p, -1); + free_int (s, -1); + free_int (t, -1); + free_int (mat, -1); + free_int (tran, -1); + vfree (translate); + return aln; +} +float* analyze_overaln ( Alignment *iA, Alignment *iB, char *mode, int filter, int f, int p1,int p2, int p3) +{ + Alignment *C, *D; + Alignment *A, *B; + OveralnP *F; + + F=vcalloc (1, sizeof (OveralnP)); + F->p1=p1; + F->p2=p2; + F->p3=p3; + F->f=f; + F->t=filter; + sprintf (F->mode, "%s", mode); + + + float *r; + A=copy_aln (iA, NULL); + B=copy_aln (iB, NULL); + + C=aln2gap_cache (A,0); + A=filter_aln_upper_lower (A, C, 0, 0); + D=aln2clean_pw_aln (B, F); + r=aln2pred (A,D,mode); + free_aln (C); + free_aln (D); + free_aln (A); + free_aln (B); + return r; +} +float* aln2pred ( Alignment *A, Alignment*B, char *mode) +{ + int a, b, c, d, i, l, salp, s, n; + static char **list, *buf1, *buf2, *alp, *alp_lu; + static int ***r; + int T, N; + int fp, fn, tn, tp; + int tfp, tfn, ttn, ttp; + float sp, sn, sen2, best, result; + int print=1; + float *fresult; + + fresult=vcalloc ( 3, sizeof (float)); + + if ( mode && strstr (mode, "case")) + { + A=aln2case_aln (A,"u","l"); + B=aln2case_aln (B,"u","l"); + } + + if (mode && strstr (mode, "printaln")) + { + Sequence *S; + Alignment *C; + S=aln2seq (A); + C=copy_aln (B, NULL); + for (a=0; anseq; a++) + { + i=name_is_in_list (C->name[a], S->name, S->nseq, 100); + if ( i==-1) + for (b=0; blen_aln; b++) C->seq_al[a][b]='-'; + else + for (d=0,b=0; blen_aln; b++) + { + if ( !is_gap (C->seq_al[a][b])) + { + if (C->seq_al[a][b]==S->seq[i][d])C->seq_al[a][b]=toupper(C->seq_al[a][b]); + d++; + } + } + } + print_aln (C); + } + + vfree (alp);vfree (alp_lu); + alp=vcalloc ( 256, sizeof (char)); + alp_lu=vcalloc ( 256, sizeof (char)); + + for (c=0; c<2; c++) + { + Alignment *AL; + AL=(c==0)?A:B; + for (salp=0,a=0; anseq; a++) + { + for (b=0; blen_aln; b++) + { + c=AL->seq_al[a][b]; + if (!is_gap(c) && !alp[c]) + { + salp++; + alp_lu[salp]=c; + alp[c]=salp; + } + } + } + } + + vfree (buf1); vfree(buf2); + buf1=vcalloc ( A->len_aln+1, sizeof (char)); + buf2=vcalloc ( B->len_aln+1, sizeof (char)); + + free_arrayN ((void **)r, 3); + r=declare_arrayN(3, sizeof (int),A->nseq,salp+1,salp+1); + free_char ( list, -1); + list=declare_char ( A->nseq, 100); + for (n=0,a=0; a< A->nseq; a++) + { + for ( b=0; bnseq; b++) + { + if ( strm (A->name[a], B->name[b])) + { + sprintf ( buf1, "%s", A->seq_al[a]); + sprintf ( buf2, "%s", B->seq_al[b]); + ungap (buf1); ungap (buf2); + if ((l=strlen (buf1))!=strlen (buf2))continue; + else + { + sprintf ( list[n], "%s", A->name[a]); + for (c=0; c%s S=%c sp=%6.2f sn=%6.2f sen2=%6.2f best=%6.2f\n", list[a],alp_lu[s],sp, sn, sen2, best); + } + + rates2sensitivity (ttp, ttn, tfp, tfn, &sp, &sn, &sen2, &best); + if (mode && strstr (mode, "printstat"))fprintf ( stdout, ">TOT S=%c sp=%6.2f sn=%6.2f re=%6.2f best=%6.2f\n", alp_lu[s],sp, sn, sen2, best); + + if ( mode && strstr (mode, type)) + { + fresult[0]=sn; + fresult[1]=sp; + fresult[2]=sen2; + } + } + return fresult; +} + +Alignment * mark_exon_boundaries (Alignment *A, Alignment *E) +{ + char *buf, *buf2; + int a, b, c, i, l; + + buf2=vcalloc ( E->len_aln+1, sizeof (char)); + buf =vcalloc ( E->len_aln+1, sizeof (char)); + + for (a=0; a< A->nseq; a++) + { + i=name_is_in_list (A->name[a], E->name, E->nseq, 100); + if ( i==-1) continue; + sprintf (buf, "%s", E->seq_al[i]); + ungap (buf); + l=strlen (buf); + //clean buf2 + for (c=0, b=0; b=1)buf2[c-1]=tolower(buf2[c-1]); + else if (buf[b]=='j' &&clen_aln; b++) + { + if (!is_gap(A->seq_al[a][b])) + { + A->seq_al[a][b]=buf2[c++]; + } + } + } + vfree (buf); + vfree (buf2); + return A; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/define_header.h b/binaries/src/tcoffee/t_coffee_source/define_header.h new file mode 100644 index 0000000..0f5bfe1 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/define_header.h @@ -0,0 +1,785 @@ +/*DEBUGGING*/ +/*#include "mshell.h"*/ +/*MEMORY MANAGEMENT*/ +#include +#define MY_EPS 1000*DBL_EPSILON +//Maximum number of tries for interactibve things +#define MAX_N_TRIES 3 + +//Maximum CACHE and Temporary file size and age (Mb and days, 0: unlimited) +#define TMP_MAX_SIZE 0 +#define TMP_MAX_KEEP 10 +#define CACHE_MAX_SIZE 2000 +#define CACHE_MAX_KEEP 180 +#define MAX_N_PID 260000 +//Importnat Values Affecting the Program Behavior +#define O2A_BYTE 50 +#define SCORE_K 10 +#define NORM_F 1000 +#define PAVIE_MAT_FACTOR 1000 +#define MAXID 100 +#define CLEAN_FUNCTION NULL +#define MINSIM_4_TCOFFEE 25 //The minimum similarity between a sequence and its PDB template +#define MINCOV_4_TCOFFEE 25 //The minimum similarity between a sequence and its PDB template + + +#define TRACE_TYPE int +#define MAX_LEN_FOR_DP 600 + + +#define GIVE_MEMORY_BACK 0 +#define MEMSET0 1 +#define NO_MEMSET0 0 +/*OUTPUT DEFINITIONS*/ +#define NO_COLOR_RESIDUE 127 +#define NO_COLOR_GAP 126 +#define CLOSE_HTML_SPAN -1 +/*SPECIAL_CODES*/ +#define GAP_CODE 60 +/*TYPE DEFINITIONS*/ + +//Formats +#define BLAST_XML 100 +#define BLAST_TXT 101 + +/*SWITCHES*/ + + +#define USED 1 +#define UNUSED 2 + + +#define TEMPLATES 1 +#define NOTEMPLATES 0 + +#define EXTEND 1 +#define RESIZE 2 + +#define SEN 0 +#define SPE 1 +#define REC 2 +#define SEN2 2 + +#define ALL 1 +#define SEGMENTS 2 +#define DIAGONALS 3 + +#define START_STATE 0 +#define END_STATE 1 + +#define KEEP_CASE 2 /*Hard set in several places*/ +#define LOWER_CASE 0 +#define UPPER_CASE 1 +#define CHANGE_CASE 3 +#define KEEP_GAP 0 +#define RM_GAP 1 + +#define KEEP_NAME 1 + +#define CHECK 0 +#define NO_CHECK 1 +#define FORCE 2 +#define STORE 3 +#define FLUSH 4 +#define DUMP 5 + + +#define ON 8 +#define OFF 9 +#define LOCKED_ON 10 +#define LOCKED_OFF 11 + +#define YES 12 +#define NO 13 +#define MAYBE 14 + +#define NEVER 15 +#define ALWAYS 16 +#define SOMETIMES 17 + +#define UPPER 18 +#define LOWER 19 +#define DELETE 20 +#define SWITCHCASE 21 + +#define VECTOR 22 +#define NON_VECTOR 23 +#define NON_PROFILE 24 +#define BOOTSTRAP 25 + +#define HEADER 26 +#define NO_HEADER 27 + +#define VERY_VERBOSE 28 +#define VERBOSE 29 +#define SHORT 30 +#define VERY_SHORT 31 + +#define OVERLAP 32 +#define NO_OVERLAP 33 + +#define PRINT 34 +#define NO_PRINT 35 + +#define FREE_ALN 36 +#define DECLARE_ALN 37 +#define EXTRACT_ALN 38 +#define CLEAN 39 +#define INTERACTIVE 40 +#define NON_INTERACTIVE 41 +#define PAD 42 +#define NO_PAD 43 + +#define SET 44 +#define UNSET 45 +#define RESET 48 +#define ISSET 49 +#define GET 50 + +#define ENV 52 +#define LLOCK 53 +#define LERROR 54 +#define LWARNING 55 +#define LSET 56 +#define LRESET 57 +#define LCHECK 58 +#define LREAD 59 +#define LRELEASE 60 + +#define RETURN_ON_FAILURE 61 +#define EXIT_ON_FAILURE 62 +#define IGNORE_FAILURE 63 + +#define _START 64 +#define _TERM 65 + +#define GOP 0 +#define GCP 1 +#define GEP 2 + +#define BOTTOM 0 +#define TOP 1 + +#define FORWARD -1 +#define BACKWARD 1 + +#define GO_LEFT -1 +#define GO_RIGHT 1 + +#define LOCAL 1 +#define GLOBAL 2 +#define LALIGN 3 +#define MOCCA 4 + +#define TRUE 1 +#define FALSE 0 + +#define NEW 1 +#define OLD 0 + +#define RANDOM 0 +#define DETERMINISTIC 1 + +#define GREEDY 1 +#define NON_GREEDY 0 + +#define IS_FATAL 1 +#define IS_NOT_FATAL 0 +#define NO_REPORT 2 +#define INSTALL 3 +#define INSTALL_OR_DIE 4 + +#define OPTIONAL 1 +#define NON_OPTIONAL 0 + +#define GV_MAXIMISE 1 +#define GV_MINIMISE 0 + +#define MAXIMISE 1 +#define MINIMISE 0 + +#define ALLOWED 0 +#define FORBIDEN -99999999 +#define END_ARRAY -99999990 +#define SOFT_COPY 1 +#define HARD_COPY 2 + +#define VERY_SLOW 0 +#define SLOW 1 +#define FAST 2 +#define VERY_FAST 3 +#define SUPER_FAST 4 +#define ULTRA_FAST 5 + +#define CODE 1 +#define DECODE 2 +#define CODELIST 3 + +/*Identity measure*/ +#define UNGAPED_POSITIONS 1 +#define ALIGNED_POSITIONS 2 +#define AVERAGE_POSITIONS 3 +#define NOMATRIX NULL +#define NOGROUP NULL +#define NOALN NULL + +/*SIZE DEFINITIONS*/ +#define SIZE_OF_INT 10 +#define UNDEFINED FORBIDEN +#define UNDEFINED_INT UNDEFINED +#define UNDEFINED_FLOAT UNDEFINED +#define UNDEFINED_DOUBLE UNDEFINED +#define UNDEFINED_CHAR 125 +#define UNDEFINED_SHORT -125 +#define UNDEFINED_2 0 +#define UNDEFINED_RESIDUE '>' + + + +#define FACTOR 1 +#define MAX_N_SEQ 1 +#define MAX_N_ALN 1 +#define MAX_LEN_ALN 1 +#define MAX_N_LIST 100 + +#define COMMENT_SIZE 1000 +#define MAXNAMES 100 +#define FILENAMELEN 500 /* Max. file name length */ +#define MAX_N_PARAM 2000 +#define MAX_PARAM_LEN 200 +#define MAX_LINE_LENGTH 10000 +#define ALN_LINE_LENGTH 50 +#define SHORT_STRING 10 +#define STRING 300 +#define LONG_STRING 1000 +#define VERY_LONG_STRING 10000 + +#define AA_ALPHABET "acdefghiklmnpqrstvwy-ACDEFGHIKLMNPQRSTVWY" +#define DNA_ALPHABET "AGCTUNRYMKSWHBVD-agctunrymkswhbvd" +#define RNAONLY_ALPHABET "Uu" +#define BLAST_AA_ALPHABET "arndcqeghilkmfpstwyvbzx*" +#define NAMES_ALPHABET "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_|�-!%@&#-+=." + +#define SIZEOF_AA_MAT 60 +#define GAP_LIST "-.#*~" +#define SSPACE " " + +#define MATCH 1 +#define UNALIGNED 2 +#define GAP 3 + +#define MNE 3 +#define CODE4PROTEINS 10 +#define CODE4DNA 20 + +#define STOCKHOLM_CHAR 'z' +#define STOCKHOLM_STRING "z" + + +/*CODE SHORT CUTS*/ + +/*1-COMMAND LINE PROCESSING*/ +#define GET_COMMAND_LINE_INFO ((strncmp ( argv[1], "-h",2)==0)||(strncmp ( argv[1], "-man",4)==0)||(strncmp ( argv[1], "-",1)!=0)) +#define NEXT_ARG_IS_FLAG ((argc<=(a+1)) ||(( argv[a+1][0]=='-') && !(is_number(argv[a+1])))) + + +/*UTIL MACROS*/ +#define BORDER(p1,l1,p2,l2) ((p1==0 || p2==0 || p1==l1 || p2==l2)?1:0) +#define GET_CASE(f,c) ((f==UPPER_CASE)?toupper(c):((f==LOWER_CASE)?tolower(c):c)) + +#define SWAP(x,y) {x=x+y;y=x+y; x=y-x; y=y-2*x;} +#define SWAPP(x,y,tp) {tp=y;y=x;x=tp;} + +#define MAX(x, y) (((x) >(y)) ? (x):(y)) +#define MAX2(x, y) (((x) >(y)) ? (x):(y)) +#define MAX3(x,y,z) (MAX(MAX(x,y),z)) +#define MAX4(a,b,c,d) (MAX(MAX(a,b),MAX(c,d))) +#define MAX5(a,b,c,d,e) (MAX2((MAX3(a,b,c)),(MAX2(d,e)))) +#define MAX6(a,b,c,d,e,f) (MAX2((MAX3(a,b,c)),(MAX3(c,d,e)))) + +#define MIN(x, y) (((x) <(y)) ? (x):(y)) +#define FABS(x) ((x<0)?(-x):(x)) +#define is_defined(x) ((x==UNDEFINED)?0:1) +#define a_better_than_b(x,y,m) ((m==1)?(((x)>(y))?1:0):(((x)<(y))?1:0)) +#define is_in_range(x,min,max) ((x>=min && x<=max)?1:0) +/*#define bod_a_b(x,y,m) ((m==1)?(MAX((x),(y))):(MIN((x),(y)))) +#define bo_a_b(x,y,m) ((x==UNEFINED)?y:((y==UNDEFINED)?x:bod_a_b(y,y,m))) +#define best_of_a_b(x,y,m) ((x==UNDEFINED && y==UNDEFINED)?(UNDEFINED):(bo_a_b(x,y,m))) +*/ + + +#define DIE(x) HERE(x);exit(0); +#define best_of_a_b(x,y,m) ((m==1)?(MAX((x),(y))):(MIN((x),(y)))) + +#define strm(x,y) ((vstrcmp((x),(y))==0)?1:0) +#define strnm(x,y,n) ((vstrncmp((x),(y),(n))==0)?1:0) +#define strm2(a,b,c) (strm(a,b) || strm(a,c)) +#define strm3(a,b,c,d) (strm2(a,b,c) || strm(a,d)) +#define strm4(a,b,c,d,e) (strm2(a,b,c) || strm2(a,d,e)) +#define strm5(a,b,c,d,e,f) (strm2(a,b,c) || strm3(a,d,e,f)) +#define strm6(a,b,c,d,e,f,g) (strm3(a,b,c,d) || strm3(a,e,f,g)) +#define declare_name(x) (x=vcalloc (MAX(FILENAMELEN,L_tmpnam)+1, sizeof (char))) +#define is_parameter(x) (x[0]=='-' && !isdigit(x[1])) + +/*Freing functions*/ +#define free_2(a, b) free(a);free(b) +#define free_1(a) free(a) +#define free_3(a, b, c) free_2(a,b);free_1(c) +#define free_4(a, b, c,d) free_2(a,b);free_2(c,d) +#define free_5(a, b, c,d,e) free_3(a,b,e);free_2(c,d) +#define free_6(a, b, c,d,e,f) free_3(a,b,e);free_3(c,d,f) +#define free_7(a, b, c,d,e,f,g) free_3(a,b,e);free_4(c,d,f,g) +/*2-FILE PARSING*/ +#define SEPARATORS "\n \t,;" +#define LINE_SEPARATOR "\n#TC_LINE_SEPARATOR\n" +#define TC_REC_SEPARATOR "#### TC REC SEPARATOR ###" + +/*END 1-*/ + + +/*WIDOWS/UNIX DISTINCTIONS +#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) || defined(__MSDOS__) || defined(__DOS__) || defined(__NT__) || defined(__WIN32__) +#define WIN32 +#define TO_NULL_DEVICE " >nul" +#define NULL_DEVICE "nul" +#define CWF "/" +#else +#define TO_NULL_DEVICE " >/dev/null 2>&1" +#define NULL_DEVICE "/dev/null" +*/ + +#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) || defined(__MSDOS__) || defined(__DOS__) || defined(__NT__) || defined(__WIN32__) +#define WIN32 +#define TO_NULL_DEVICE " >>t_coffee.log" +#define NULL_DEVICE "t_coffee.log" +#define CWF "/" /*ClustalW Flag*/ +#else +#define TO_NULL_DEVICE " >>/dev/null 2>&1" +#define NULL_DEVICE "/dev/null" + + +#define CWF "-" /*ClustaW Flag*/ +#endif + +/*Generic Data*/ +#define EMAIL "cedric.notredame@europe.com" +#define URL "http://www.tcoffee.org" + +#define PERL_HEADER "#!/usr/bin/env perl" + +//Optimize the Score Computation in DP +#define TC_SCORE_2(x,y) (SCORE_K*CL->M[Aln->seq_al[l_s[0][0]][x]-'A'][Aln->seq_al[l_s[1][0]][y]-'A']-SCORE_K*CL->nomatch) +#define TC_SCORE_N(x,y) ((CL->get_dp_cost)(Aln, pos, ns[0], l_s[0], x, pos, ns[1], l_s[1], y, CL)) +#define TC_SCORE(x,y) ((CL->get_dp_cost==slow_get_dp_cost && CL->evaluate_residue_pair==evaluate_matrix_score && ns[0]+ns[1]==2 && x>=0 && j>=0)? (TC_SCORE_2(x,y)):(TC_SCORE_N(x,y))) + +#define NULL_2 NULL,NULL +#define NULL_3 NULL_2,NULL +#define NULL_4 NULL_2,NULL_2 +#define NULL_5 NULL_3,NULL_2 +#define NULL_6 NULL_4,NULL_2 +#define NULL_7 NULL_5,NULL_2 +/* PROGRAM PATH */ + + +//ERROR MESSAGES + + +#define ADDRESS_BUILT_IN "built_in" +#define PROGRAM_BUILT_IN "t_coffee" +#define TEST_WWWSITE_4_TCOFFEE "www.google.com" + + +//TclinkdbStart + +#define TCOFFEE_4_TCOFFEE "t_coffee" +#define TCOFFEE_type "sequence_multiple_aligner" +#define TCOFFEE_ADDRESS "http://www.tcoffee.org" +#define TCOFFEE_language "C" +#define TCOFFEE_language2 "C" +#define TCOFFEE_source "http://www.tcoffee.org/Packages/T-COFFEE_distribution.tar.gz" +#define TCOFFEE_update_action "always" +#define TCOFFEE_mode "tcoffee,mcoffee,rcoffee,expresso,3dcoffee" +#define CLUSTALW2_4_TCOFFEE "clustalw2" +#define CLUSTALW2_type "sequence_multiple_aligner" +#define CLUSTALW2_ADDRESS "http://www.clustal.org" +#define CLUSTALW2_language "C++" +#define CLUSTALW2_language2 "CXX" +#define CLUSTALW2_source "http://www.clustal.org/download/2.0.10/clustalw-2.0.10-src.tar.gz" +#define CLUSTALW2_mode "mcoffee,rcoffee" +#define CLUSTALW2_version "2.0.10" +#define CLUSTALW_4_TCOFFEE "clustalw" +#define CLUSTALW_type "sequence_multiple_aligner" +#define CLUSTALW_ADDRESS "http://www.clustal.org" +#define CLUSTALW_language "C" +#define CLUSTALW_language2 "C" +#define CLUSTALW_source "http://www.clustal.org/download/1.X/ftp-igbmc.u-strasbg.fr/pub/ClustalW/clustalw1.82.UNIX.tar.gz" +#define CLUSTALW_mode "mcoffee,rcoffee" +#define CLUSTALW_version "1.82" +#define DIALIGNT_4_TCOFFEE "dialign-t" +#define DIALIGNT_type "sequence_multiple_aligner" +#define DIALIGNT_ADDRESS "http://dialign-tx.gobics.de/" +#define DIALIGNT_DIR "/usr/share/dialign-tx/" +#define DIALIGNT_language "C" +#define DIALIGNT_language2 "C" +#define DIALIGNT_source "http://dialign-tx.gobics.de/DIALIGN-TX_1.0.2.tar.gz" +#define DIALIGNT_mode "mcoffee" +#define DIALIGNT_binary "dialign-t" +#define DIALIGNT_version "1.0.2" +#define DIALIGNTX_4_TCOFFEE "dialign-tx" +#define DIALIGNTX_type "sequence_multiple_aligner" +#define DIALIGNTX_ADDRESS "http://dialign-tx.gobics.de/" +#define DIALIGNTX_DIR "/usr/share/dialign-tx/" +#define DIALIGNTX_language "C" +#define DIALIGNTX_language2 "C" +#define DIALIGNTX_source "http://dialign-tx.gobics.de/DIALIGN-TX_1.0.2.tar.gz" +#define DIALIGNTX_mode "mcoffee" +#define DIALIGNTX_binary "dialign-tx" +#define DIALIGNTX_version "1.0.2" +#define POA_4_TCOFFEE "poa" +#define POA_type "sequence_multiple_aligner" +#define POA_ADDRESS "http://www.bioinformatics.ucla.edu/poa/" +#define POA_language "C" +#define POA_language2 "C" +#define POA_source "http://downloads.sourceforge.net/poamsa/poaV2.tar.gz" +#define POA_DIR "/usr/share/" +#define POA_FILE1 "blosum80.mat" +#define POA_mode "mcoffee" +#define POA_binary "poa" +#define POA_version "2.0" +#define PROBCONS_4_TCOFFEE "probcons" +#define PROBCONS_type "sequence_multiple_aligner" +#define PROBCONS_ADDRESS "http://probcons.stanford.edu/" +#define PROBCONS_language2 "CXX" +#define PROBCONS_language "C++" +#define PROBCONS_source "http://probcons.stanford.edu/probcons_v1_12.tar.gz" +#define PROBCONS_mode "mcoffee" +#define PROBCONS_binary "probcons" +#define PROBCONS_version "1.12" +#define MAFFT_4_TCOFFEE "mafft" +#define MAFFT_type "sequence_multiple_aligner" +#define MAFFT_ADDRESS "http://align.bmr.kyushu-u.ac.jp/mafft/online/server/" +#define MAFFT_language "C" +#define MAFFT_language "C" +#define MAFFT_source "http://align.bmr.kyushu-u.ac.jp/mafft/software/mafft-6.603-with-extensions-src.tgz" +#define MAFFT_windows "http://align.bmr.kyushu-u.ac.jp/mafft/software/mafft-6.603-mingw.tar" +#define MAFFT_mode "mcoffee,rcoffee" +#define MAFFT_binary "mafft.tar.gz" +#define MAFFT_version "6.603" +#define MUSCLE_4_TCOFFEE "muscle" +#define MUSCLE_type "sequence_multiple_aligner" +#define MUSCLE_ADDRESS "http://www.drive5.com/muscle/" +#define MUSCLE_language "C++" +#define MUSCLE_language2 "GPP" +#define MUSCLE_source "http://www.drive5.com/muscle/downloads3.7/muscle3.7_src.tar.gz" +#define MUSCLE_windows "http://www.drive5.com/muscle/downloads3.7/muscle3.7_win32.zip" +#define MUSCLE_linux "http://www.drive5.com/muscle/downloads3.7/muscle3.7_linux_ia32.tar.gz" +#define MUSCLE_mode "mcoffee,rcoffee" +#define MUSCLE_version "3.7" +#define MUS4_4_TCOFFEE "mus4" +#define MUS4_type "sequence_multiple_aligner" +#define MUS4_ADDRESS "http://www.drive5.com/muscle/" +#define MUS4_language "C++" +#define MUS4_language2 "GPP" +#define MUS4_source "http://www.drive5.com/muscle/muscle4.0_src.tar.gz" +#define MUS4_mode "mcoffee,rcoffee" +#define MUS4_version "4.0" +#define PCMA_4_TCOFFEE "pcma" +#define PCMA_type "sequence_multiple_aligner" +#define PCMA_ADDRESS "ftp://iole.swmed.edu/pub/PCMA/" +#define PCMA_language "C" +#define PCMA_language2 "C" +#define PCMA_source "ftp://iole.swmed.edu/pub/PCMA/pcma.tar.gz" +#define PCMA_mode "mcoffee" +#define PCMA_version "1.0" +#define KALIGN_4_TCOFFEE "kalign" +#define KALIGN_type "sequence_multiple_aligner" +#define KALIGN_ADDRESS "http://msa.cgb.ki.se" +#define KALIGN_language "C" +#define KALIGN_language2 "C" +#define KALIGN_source "http://msa.cgb.ki.se/downloads/kalign/current.tar.gz" +#define KALIGN_mode "mcoffee" +#define KALIGN_version "1.0" +#define AMAP_4_TCOFFEE "amap" +#define AMAP_type "sequence_multiple_aligner" +#define AMAP_ADDRESS "http://bio.math.berkeley.edu/amap/" +#define AMAP_language "C++" +#define AMAP_language2 "CXX" +#define AMAP_source "http://amap-align.googlecode.com/files/amap.2.0.tar.gz" +#define AMAP_mode "mcoffee" +#define AMAP_version "2.0" +#define PRODA_4_TCOFFEE "proda" +#define PRODA_type "sequence_multiple_aligner" +#define PRODA_ADDRESS "http://proda.stanford.edu" +#define PRODA_language "C++" +#define PRODA_language2 "CXX" +#define PRODA_source "http://proda.stanford.edu/proda_1_0.tar.gz" +#define PRODA_mode "mcoffee" +#define PRODA_version "1.0" +#define FSA_4_TCOFFEE "fsa" +#define FSA_type "sequence_multiple_aligner" +#define FSA_ADDRESS "http://fsa.sourceforge.net/" +#define FSA_language "C++" +#define FSA_language2 "CXX" +#define FSA_source "http://sourceforge.net/projects/fsa/files/fsa-1.15.3.tar.gz/download/" +#define FSA_mode "mcoffee" +#define FSA_version "1.15.3" +#define PRANK_4_TCOFFEE "prank" +#define PRANK_type "sequence_multiple_aligner" +#define PRANK_ADDRESS "http://www.ebi.ac.uk/goldman-srv/prank/" +#define PRANK_language "C++" +#define PRANK_language2 "CXX" +#define PRANK_source "http://www.ebi.ac.uk/goldman-srv/prank/src/prank/prank.src.100303.tgz" +#define PRANK_mode "mcoffee" +#define PRANK_version "100303" +#define SAP_4_TCOFFEE "sap" +#define SAP_type "structure_pairwise_aligner" +#define SAP_ADDRESS "http://mathbio.nimr.mrc.ac.uk/wiki/Software" +#define SAP_language "C" +#define SAP_language2 "C" +#define SAP_source "http://mathbio.nimr.mrc.ac.uk/download/sap-1.1.1.tar.gz" +#define SAP_mode "expresso,3dcoffee" +#define SAP_version "1.1.1" +#define TMALIGN_4_TCOFFEE "TMalign" +#define TMALIGN_type "structure_pairwise_aligner" +#define TMALIGN_ADDRESS "http://zhang.bioinformatics.ku.edu/TM-align/TMalign.f" +#define TMALIGN_language "Fortran" +#define TMALIGN_language2 "Fortran" +#define TMALIGN_source "http://zhang.bioinformatics.ku.edu/TM-align/TMalign.f" +#define TMALIGN_linux "http://zhang.bioinformatics.ku.edu/TM-align/TMalign_32.gz" +#define TMALIGN_mode "expresso,3dcoffee" +#define TMALIGN_version "1.0" +#define MUSTANG_4_TCOFFEE "mustang" +#define MUSTANG_type "structure_pairwise_aligner" +#define MUSTANG_ADDRESS "http://www.cs.mu.oz.au/~arun/mustang" +#define MUSTANG_language "C++" +#define MUSTANG_language2 "CXX" +#define MUSTANG_source "http://ww2.cs.mu.oz.au/~arun/mustang/mustang_v3.2.1.tgz" +#define MUSTANG_mode "expresso,3dcoffee" +#define MUSTANG_version "3.2.1" +#define LSQMAN_4_TCOFFEE "lsqman" +#define LSQMAN_type "structure_pairwise_aligner" +#define LSQMAN_ADDRESS "empty" +#define LSQMAN_language "empty" +#define LSQMAN_language2 "empty" +#define LSQMAN_source "empty" +#define LSQMAN_update_action "never" +#define LSQMAN_mode "expresso,3dcoffee" +#define ALIGN_PDB_4_TCOFFEE "align_pdb" +#define ALIGN_PDB_type "structure_pairwise_aligner" +#define ALIGN_PDB_ADDRESS "empty" +#define ALIGN_PDB_language "empty" +#define ALIGN_PDB_language2 "empty" +#define ALIGN_PDB_source "empty" +#define ALIGN_PDB_update_action "never" +#define ALIGN_PDB_mode "expresso,3dcoffee" +#define FUGUE_4_TCOFFEE "fugueali" +#define FUGUE_type "structure_pairwise_aligner" +#define FUGUE_ADDRESS "http://www-cryst.bioc.cam.ac.uk/fugue/download.html" +#define FUGUE_language "empty" +#define FUGUE_language2 "empty" +#define FUGUE_source "empty" +#define FUGUE_update_action "never" +#define FUGUE_mode "expresso,3dcoffee" +#define DALILITEc_4_TCOFFEE "dalilite.pl" +#define DALILITEc_type "structure_pairwise_aligner" +#define DALILITEc_ADDRESS "built_in" +#define DALILITEc_ADDRESS2 "http://www.ebi.ac.uk/Tools/webservices/services/dalilite" +#define DALILITEc_language "Perl" +#define DALILITEc_language2 "Perl" +#define DALILITEc_source "empty" +#define DALILITEc_update_action "never" +#define DALILITEc_mode "expresso,3dcoffee" +#define PROBCONSRNA_4_TCOFFEE "probconsRNA" +#define PROBCONSRNA_type "RNA_multiple_aligner" +#define PROBCONSRNA_ADDRESS "http://probcons.stanford.edu/" +#define PROBCONSRNA_language "C++" +#define PROBCONSRNA_language2 "CXX" +#define PROBCONSRNA_source "http://probcons.stanford.edu/probconsRNA.tar.gz" +#define PROBCONSRNA_mode "mcoffee,rcoffee" +#define PROBCONSRNA_version "1.0" +#define CONSAN_4_TCOFFEE "sfold" +#define CONSAN_type "RNA_pairwise_aligner" +#define CONSAN_ADDRESS "http://selab.janelia.org/software/consan/" +#define CONSAN_language "empty" +#define CONSAN_language2 "empty" +#define CONSAN_source "empty" +#define CONSAN_update_action "never" +#define CONSAN_mode "rcoffee" +#define RNAPLFOLD_4_TCOFFEE "RNAplfold" +#define RNAPLFOLD_type "RNA_secondarystructure_predictor" +#define RNAPLFOLD_ADDRESS "http://www.tbi.univie.ac.at/~ivo/RNA/" +#define RNAPLFOLD_language "C" +#define RNAPLFOLD_language2 "C" +#define RNAPLFOLD_source "http://www.tbi.univie.ac.at/~ivo/RNA/ViennaRNA-1.7.2.tar.gz" +#define RNAPLFOLD_mode "rcoffee," +#define RNAPLFOLD_version "1.7.2" +#define PHYLIP_4_TCOFFEE "retree" +#define PHYLIP_type "RNA_secondarystructure_predictor" +#define PHYLIP_ADDRESS "http://evolution.gs.washington.edu/phylip/" +#define PHYLIP_language "C" +#define PHYLIP_language2 "C" +#define PHYLIP_source "http://evolution.gs.washington.edu/phylip/download/phylip-3.69.tar.gz" +#define PHYLIP_mode "trmsd," +#define PHYLIP_version "3.69" +#define HMMTOP_4_TCOFFEE "hmmtop" +#define HMMTOP_type "protein_secondarystructure_predictor" +#define HMMTOP_ADDRESS "www.enzim.hu/hmmtop/" +#define HMMTOP_language "C" +#define HMMTOP_language2 "C" +#define HMMTOP_source "empty" +#define HMMTOP_update_action "never" +#define HMMTOP_mode "tcoffee" +#define GOR4_4_TCOFFEE "gorIV" +#define GOR4_type "protein_secondarystructure_predictor" +#define GOR4_ADDRESS "http://mig.jouy.inra.fr/logiciels/gorIV/" +#define GOR4_language "C" +#define GOR4_language2 "C" +#define GOR4_source "http://mig.jouy.inra.fr/logiciels/gorIV/GOR_IV.tar.gz" +#define GOR4_update_action "never" +#define GOR4_mode "tcoffee" +#define EBIWUBLASTc_4_TCOFFEE "wublast.pl" +#define EBIWUBLASTc_type "protein_homology_predictor" +#define EBIWUBLASTc_ADDRESS "built_in" +#define EBIWUBLASTc_ADDRESS2 "http://www.ebi.ac.uk/Tools/webservices/services/wublast" +#define EBIWUBLASTc_language "Perl" +#define EBIWUBLASTc_language2 "Perl" +#define EBIWUBLASTc_source "empty" +#define EBIWUBLASTc_update_action "never" +#define EBIWUBLASTc_mode "psicoffee,expresso,accurate" +#define EBIBLASTPGPc_4_TCOFFEE "blastpgp.pl" +#define EBIBLASTPGPc_type "protein_homology_predictor" +#define EBIBLASTPGPc_ADDRESS "built_in" +#define EBIBLASTPGPc_ADDRESS2 "http://www.ebi.ac.uk/Tools/webservices/services/blastpgp" +#define EBIBLASTPGPc_language "Perl" +#define EBIBLASTPGPc_language2 "Perl" +#define EBIBLASTPGPc_source "empty" +#define EBIBLASTPGPc_update_action "never" +#define EBIBLASTPGPc_mode "psicoffee,expresso,accurate" +#define NCBIWEBBLAST_4_TCOFFEE "blastcl3" +#define NCBIWEBBLAST_type "protein_homology_predictor" +#define NCBIWEBBLAST_ADDRESS "ftp://ftp.ncbi.nih.gov/blast/executables/LATEST" +#define NCBIWEBBLAST_language "C" +#define NCBIWEBBLAST_language2 "C" +#define NCBIWEBBLAST_source "empty" +#define NCBIWEBBLAST_update_action "never" +#define NCBIWEBBLAST_mode "psicoffee,expresso,3dcoffee" +#define blastall_4_TCOFFEE "blastall" +#define blastall_type "protein_homology_predictor" +#define blastall_ADDRESS "ftp://ftp.ncbi.nih.gov/blast/executables/LATEST" +#define blastall_language "C" +#define blastall_language2 "C" +#define blastall_source "empty" +#define blastall_update_action "never" +#define blastall_mode "psicoffee,expresso,3dcoffee" +#define NCBIBLAST_4_TCOFFEE "legacy_blast.pl" +#define NCBIBLAST_type "protein_homology_predictor" +#define NCBIBLAST_ADDRESS "ftp://ftp.ncbi.nih.gov/blast/executables/LATEST" +#define NCBIBLAST_language "C" +#define NCBIBLAST_language2 "C" +#define NCBIBLAST_source "empty" +#define NCBIBLAST_update_action "never" +#define NCBIBLAST_mode "psicoffee,expresso,3dcoffee" +#define SOAPLITE_4_TCOFFEE "SOAP::Lite" +#define SOAPLITE_type "library" +#define SOAPLITE_ADDRESS "http://cpansearch.perl.org/src/MKUTTER/SOAP-Lite-0.710.08/Makefile.PL" +#define SOAPLITE_language "Perl" +#define SOAPLITE_language2 "Perl" +#define SOAPLITE_source "empty" +#define _update_action "never" +#define SOAPLITE_mode "none" +#define XMLSIMPLE_4_TCOFFEE "XML::Simple" +#define XMLSIMPLE_type "library" +#define XMLSIMPLE_ADDRESS "http://search.cpan.org/~grantm/XML-Simple-2.18/lib/XML/Simple.pm" +#define XMLSIMPLE_language "Perl" +#define XMLSIMPLE_language2 "Perl" +#define XMLSIMPLE_source "empty" +#define XMLSIMPLE_mode "psicoffee,expresso,accurate" +//TclinkdbEnd +/*New Methods*/ +/********************************************/ +/* Various Methoids */ +/********************************************/ +#define METHODS_4_TCOFFEE "~/.t_coffee/methods/" +#define METHOD_4_MSA_WEIGHTS "petra_weight" +/********************************************/ +/* SEQAN LIBRARY */ +/********************************************/ +#define SEQAN_TCOFFEE_4_TCOFFEE "seqan_tcoffee" +/********************************************/ +/* REFORMATING AND UTILITIES */ +/********************************************/ +#define WGET_4_TCOFFEE "wget" +#define WGET_ADDRESS "http://www.gnu.org/software/wget/" + +#define CURL_4_TCOFFEE "curl" +#define CURL_ADDRESS "http://curl.haxx.se/" + +#define SEQ_REFORMAT_4_TCOFFEE "seq_reformat" +#define PS2PDF "ps2pdf" +#define EXTRACT_FROM_PDB_4_TCOFFEE "extract_from_pdb" +#define BLAST_ALN2FASTA_ALN "blast_aln2fasta_aln.pl" +#define FASTA_ALN2FASTA_ALN_UNIQUE_NAME "fasta_aln2fasta_aln_unique_name.pl" +#define MSF_ALN2FASTA_ALN "msf_aln2fasta_aln.pl" +#define SEQ2MSA_WEIGHT "seq2msa_weight" +/********************************************/ +/* DEPRECATED DEF */ +/********************************************/ +//Deprecated definitions +#define SIB_BLAST_4_TCOFFEE "blastall.remote" +#define LOCAL_BLAST_4_TCOFFEE "blastall" +#define BLAST_DB_4_TCOFFEE "nr" +#define NCBI_BLAST_4_TCOFFEE "" +/********************************************/ +/* PARAMETER_FILE */ +/********************************************/ + + + + +/* PARAMETER FILES */ +#define COLOR_FILE "seq_reformat.color" +/*This file specifies the 10 colors available to seq_reformat. +If the file is not on the system, hard coded defaults will be used. +The format is as follow: + +------------------------------------------------------------------------------------------- + +* + +------------------------------------------------------------------------------------------- +the RGB values are used for the post-script generation, the html code is used in html documents. +*/ +#define DATE "Fri Feb 18 08:27:45 CET 2011 - Revision 596" +#define PROGRAM "T-COFFEE" +#define VERSION "Version_8.99" +#define AUTHOR "Cedric Notredame " +#define DISTRIBUTION_ADDRESS "www.tcoffee.org/Packages/" +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/dev1.c b/binaries/src/tcoffee/t_coffee_source/dev1.c new file mode 100644 index 0000000..1e8f4c6 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/dev1.c @@ -0,0 +1,133 @@ +#include +#include +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" +#include "dp_lib_header.h" +#include "dev1_lib_header.h" + +//Insert functions here +void aln2hitMat_help() +{ + fprintf ( stdout, "\n+aln2hitMat| _MODE_ : how to compare the two positions of the alignment (default:id)"); + fprintf ( stdout, "\n.................id : the sequence identity of those two positions"); + fprintf ( stdout, "\n.............pairscore : the pairwise score of the residues of those two positions"); + fprintf ( stdout, "\n+aln2hitMat| _MATRIX_ : matrix used for the comparison (idmat, blosum62mt, pam250mt.. default:blosum62mt)\n"); + exit (EXIT_SUCCESS); +} + +void aln2hitMat (Alignment *A, char *phitmat) +{ + float **ffpHitScoreMatrix; + int i, j, k, l, s; + int nl = A->len_aln; + int inseq = A->nseq; + int itmpScore; + char matrix[100]; + char mode[100]; + int isim_count, itotal_count, r1, r2; + +//Initialization for files + char *pcFileName = A->file[0]; + char prefix[200] ={0}; + char *hit_matrix_file = vcalloc(200, sizeof (char)); + char *hit_html_file = vcalloc(200, sizeof (char)); + int len = (strrchr(pcFileName,'.')?strrchr(pcFileName,'.')-pcFileName:strlen(pcFileName)); + + strncpy(prefix, pcFileName, len); + sprintf(hit_matrix_file, "%s%s", prefix, "_aln.hit_matrix"); + sprintf(hit_html_file, "%s%s", prefix, ".alnhit_html"); + + if ( phitmat && strstr ( phitmat, "help")) + aln2hitMat_help(); + + if(phitmat == NULL) phitmat = vcalloc(1, sizeof(char)); //such that program could get default value + + strget_param (phitmat, "_MODE_", "id", "%s", mode); + strget_param (phitmat, "_MATRIX_", "blosum62mt", "%s", matrix); + + fprintf ( stdout, "[START] aln to hit matrix\n"); + fprintf ( stdout, " Mode:%s\n", mode); + fprintf ( stdout, " Matrix:%s\n", matrix); + + int **mat = read_matrice(matrix); + + ffpHitScoreMatrix=vcalloc (nl, sizeof (float*)); + for(i = 0; i < nl; i++) + ffpHitScoreMatrix[i]=vcalloc (nl-i, sizeof (float)); + + fprintf (stdout, "Process positions\n", i); + for(i = 0; i < nl; i++) + { + fprintf (stdout, "%d, ", i); + for(j = i; j < nl; j++) + { + if(strm (mode, "id")) + ffpHitScoreMatrix[i][j-i]=generic_get_seq_sim (aln_column2string(A, i), aln_column2string(A, j), (A->cdna_cache)?A->cdna_cache[0]:NULL, matrix); + else if(strm (mode, "pairscore")) + { + isim_count = itotal_count = 0; + for (k=0; k< inseq; k++) + { + r1=tolower(A->seq_al[k][i]); + if (is_gap(r1))continue; + for (l=0; l< inseq; l++) + { + r2=tolower(A->seq_al[l][j]); + if (is_gap (r2))continue; + s=mat[r2-'A'][r1-'A']; + s=(s<=0)?0:1; + isim_count += s; + itotal_count++; + } + } + r1=(isim_count*100)/itotal_count; + ffpHitScoreMatrix[i][j-i] = r1; + } + else + aln2hitMat_help(); + } + } + fprintf (stdout, "\n"); + output_hit_matrix(hit_matrix_file, ffpHitScoreMatrix, nl); + +//Output Hit Score into color html + output_hit_color_html (A, ffpHitScoreMatrix, nl, hit_html_file); + vfree(ffpHitScoreMatrix); + vfree(hit_matrix_file); + vfree(hit_html_file); + fprintf ( stdout, "[END] aln to hit matrix\n"); +} +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/dev1_lib_header.h b/binaries/src/tcoffee/t_coffee_source/dev1_lib_header.h new file mode 100644 index 0000000..a3a402f --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/dev1_lib_header.h @@ -0,0 +1,31 @@ +//Insert function prototypes here +void aln2hitMat (Alignment *S, char *arg_list); +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/dev2.c b/binaries/src/tcoffee/t_coffee_source/dev2.c new file mode 100644 index 0000000..1d55d84 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/dev2.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" +#include "dp_lib_header.h" +#include "dev2_lib_header.h" + + +//Insert functions here +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/dev2_lib_header.h b/binaries/src/tcoffee/t_coffee_source/dev2_lib_header.h new file mode 100644 index 0000000..29eea09 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/dev2_lib_header.h @@ -0,0 +1,30 @@ +//Insert function prototypes here +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/dev3.c b/binaries/src/tcoffee/t_coffee_source/dev3.c new file mode 100644 index 0000000..0560af6 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/dev3.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include +#include +#include +#include "dev3_lib_header.h" +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/dev3_lib_header.h b/binaries/src/tcoffee/t_coffee_source/dev3_lib_header.h new file mode 100644 index 0000000..e345822 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/dev3_lib_header.h @@ -0,0 +1,31 @@ +//Insert function prototypes here +int syctl2nproc() ; +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/dev4.c b/binaries/src/tcoffee/t_coffee_source/dev4.c new file mode 100644 index 0000000..5e27315 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/dev4.c @@ -0,0 +1,42 @@ +#include +#include +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" +#include "dp_lib_header.h" +#include "dev4_lib_header.h" + +//Insert functions here +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/dev4_lib_header.h b/binaries/src/tcoffee/t_coffee_source/dev4_lib_header.h new file mode 100644 index 0000000..29eea09 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/dev4_lib_header.h @@ -0,0 +1,30 @@ +//Insert function prototypes here +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/diagonal.c b/binaries/src/tcoffee/t_coffee_source/diagonal.c new file mode 100644 index 0000000..d76831c --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/diagonal.c @@ -0,0 +1,475 @@ +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "fastal_lib_header.h" + + + +/*! + * \file diagonal.c + * \brief Source code for the calculation and preparation of diagonals + */ + + + + + + + +int +diagonal_compare (const void * a, const void * b) +{ + + int tmp = ((((Diagonal*)a)->y - ((Diagonal*)a)->x) - (((Diagonal*)b)->y - ((Diagonal*)b)->x)); + if (tmp != 0) + return tmp; + return (((Diagonal*)a)->y - ((Diagonal*)b)->y); +} + +int +max(int a, int b) +{ + if (a < b) + return b; + else + return a; +} + + + +Segment* +extend_diagonals(Diagonal *diagonals, int *num_diagonal, int l1, int l2) +{ +// sort diagonal by diagonal number + int i; +// printf("INPUT_PRE\n"); +// for (i = 0; i < num_diagonals; ++i) +// { +// printf("%i %i %i\n",diagonals[i].x, diagonals[i].y, diagonals[i].length); +// } + int num_diagonals = *num_diagonal; + qsort (diagonals, num_diagonals, sizeof(Diagonal), diagonal_compare); + + +// find nearest diagonal and expand +// make shure that overlapping segments on the same diagonal are merged + + int diff; +// printf("INPUT\n"); + for (i = 0; i < num_diagonals; ++i) + { + printf("%i %i %i\n",diagonals[i].x, diagonals[i].y, diagonals[i].length); + } + for (i = 0; i < num_diagonals; ++i) + { + diagonals[i].end_exp = 0; + diagonals[i].front_exp = 0; + } + int first = 0; + int next = 1; + while (next < num_diagonals) + { + + if (!((diagonals[next].y >= diagonals[first].y) && diagonals[next].x <= diagonals[first].x)) + { + printf("%i %i %i %i %i %i\n",diagonals[first].x, diagonals[first].y, diagonals[next].x, diagonals[next].y, diagonals[first].y - diagonals[first].x, diagonals[next].y - diagonals[next].x); + diff = diagonals[next].y - (diagonals[first].y + diagonals[first].length); + if (diff > 0) + { + if ((diagonals[first].y - diagonals[first].x) != ((diagonals[next].y - diagonals[next].x))) + { + diagonals[first].end_exp = max(diagonals[first].end_exp, diff); + diagonals[next].front_exp = max(diagonals[next].front_exp, diff); + // if (diagonals[next].x - diagonals[next].front_exp < 0) + + while (diagonals[++first].x == -1); + } + else + { + printf("ICH TUWAS\n"); + diagonals[first].length = diagonals[next].y + diagonals[next].length - diagonals[first].y; + diagonals[first].end_exp = diagonals[next].end_exp; + diagonals[next].x = -1; + } + } + diff = diagonals[first].x - (diagonals[next].x + diagonals[next].length); + if (diff > 0) + { + // diff = diagonals[next].x + diagonals[next].length - diagonals[first].x; + + diagonals[first].front_exp = max(diagonals[first].front_exp, diff); + diagonals[next].end_exp = max(diagonals[next].end_exp, diff); + // ++num_segments; + // if (diagonals[first].x - diagonals[first].front_exp < 0) + + while (diagonals[++first].x == -1); + } + } else + ++ first; + ++next; + + } + + int num_segments =0; + Segment *seg = vcalloc(num_diagonals, sizeof(Segment)); + int pos = 0; +// int diag_num1, diag_num2; + int *tmp1; + Diagonal *tmp2; + for (i = 0; i < num_diagonals; ++i) + { + if (diagonals[i].x != -1) + { + ++num_segments; + tmp2 = &diagonals[i]; + seg[pos].segments = vcalloc(6, sizeof(int)); + seg[pos].current_pos = seg[pos].segments; + tmp1 = seg[pos].segments; + tmp1[0] = tmp2->x - tmp2->front_exp; + tmp1[1] = tmp2->y - tmp2->front_exp; + tmp1[2] = tmp2->front_exp + tmp2->length + tmp2->end_exp; + tmp1[5] = 1; + tmp1[4] = l2; + tmp1[3] = tmp1[0] + (l2 - tmp1[1]); + ++pos; + } + } + + for ( i = 0; i < num_segments; ++i ) + { + printf("%i %i %i || %i %i %i\n", seg[i].current_pos[0], seg[i].current_pos[1], seg[i].current_pos[2], seg[i].current_pos[3], seg[i].current_pos[4], seg[i].current_pos[5]); + } +// exit(1); + vrealloc(seg,num_segments*sizeof(Segment)); + + *num_diagonal = num_segments; + +// vfree(diagonals); + return seg; +} + + +int ** +segments2int(Segment *diagonals, + int num_diagonals, + char *seq1, + char *seq2, + Fastal_profile *profile1, + Fastal_profile *profile2, + int *num_points, + Fastal_param *param_set) +{ +// printf("NUM: %i\n", num_diagonals); + int l1 = strlen(seq1); + int l2 = strlen(seq2); + int gep = param_set->gep; + + int dig_length; + if (seq1 > seq2) + dig_length = l1; + else + dig_length = l2; + + int current_size = num_diagonals*dig_length + l1 +l2; + + int **list = vcalloc(current_size, sizeof(int*)); +// int *diags = vcalloc(num_diagonals, sizeof(int)); + int i; +// for (i = 0; i < num_diagonals; ++i) +// { +// diags[i] = l1 - diagonals[i*3] + diagonals[i*3+1]; +// } + +// qsort (diags, num_diagonals, sizeof(int), fastal_compare); + + +// int *diagx = vcalloc(num_diagonals, sizeof(int)); +// int *diagy = vcalloc(num_diagonals, sizeof(int)); + + + //+1 because diagonals start here at position 1, like in "real" dynamic programming + int a = -1, b = -1; + for (i = 0; i < num_diagonals; ++i) + { + if (diagonals[i].current_pos[1] - diagonals[i].current_pos[0] < 0) + { +// diagx[i] = l1 - diags[i]; +// diagy[i] = 0; + a= i; + } + else + break; + } + ++a; + b=a-1; + for (; i < num_diagonals; ++i) + { +// diagx[i] = 0; +// diagy[i] = diags[i]-l1; + diagonals[i].prev_position = diagonals[i].current_pos[1] - diagonals[i].current_pos[0]; + b = i; + } + +// vfree(diags); + int tmpy_pos; + int tmpy_value; + int **M = param_set->M; + int *last_y = vcalloc(l2+1, sizeof(int)); + int *last_x = vcalloc(l1+1, sizeof(int)); + last_y[0] = 0; + + last_x[0] = 0; + list[0] = vcalloc(6, sizeof(int)); + + int list_pos = 1; + int dig_num = l1; + int tmp_l2 = l2 + 1; + + //left border + for (; list_pos < tmp_l2; ++list_pos) + { + list[list_pos] = vcalloc(6, sizeof(int)); + list[list_pos][0] = 0; + list[list_pos][1] = list_pos; + last_y[list_pos] = list_pos; + list[list_pos][2] = list_pos*gep; + list[list_pos][4] = list_pos-1; + } + + int pos_x = 0; + int y; + int tmp_l1 = l1-1; + int tmpx, tmpy; + while (pos_x < tmp_l1) + { + if (list_pos + num_diagonals+2 > current_size) + { + current_size += num_diagonals*1000; + list = vrealloc(list, current_size * sizeof(int*)); + } + //upper border + list[list_pos] = vcalloc(6, sizeof(int)); + list[list_pos][0] = ++pos_x; + list[list_pos][1] = 0; + list[list_pos][2] = pos_x * gep; + list[list_pos][3] = last_y[0]; +// tmpy_value = list_pos; +// tmpy_pos = 0; + last_x[pos_x] = list_pos; + ++list_pos; + + //diagonals + for (i = a; i <= b; ++i) + { + + if (pos_x == diagonals[i].current_pos[0]) + { + if (diagonals[i].current_pos[2] == 0) + { + diagonals[i].current_pos+=3; + } + list[list_pos] = vcalloc(6, sizeof(int)); + tmpx = diagonals[i].current_pos[0]; + tmpy = diagonals[i].current_pos[1]; + list[list_pos][0] = tmpx; + list[list_pos][1] = tmpy; + list[list_pos][3] = last_y[tmpy]; + list[list_pos][4] = list_pos-1; + list[list_pos][5] = diagonals[i].prev_position;//last_y[tmpy-1]; + diagonals[i].prev_position = list_pos; +// printf("A: %i %i\n",tmpx-1, tmpy-1); + list[list_pos][2] = M[toupper(seq1[tmpx-1])-'A'][toupper(seq2[tmpy-1])-'A']; + last_y[tmpy] = list_pos; +// tmpy_value = list_pos; +// tmpy_pos = tmpy; + --diagonals[i].current_pos[2]; + ++diagonals[i].current_pos[0]; + ++diagonals[i].current_pos[1]; + ++list_pos; + } + } +// last_y[tmpy_pos] = tmpy_value; + + + //lower border + if (list[list_pos-1][1] != l2) + { + list[list_pos] = vcalloc(6, sizeof(int)); + list[list_pos][0] = pos_x; + list[list_pos][1] = l2; + list[list_pos][3] = last_y[l2]; + + list[list_pos][2] = -1000; + list[list_pos][4] = list_pos-1; + if (pos_x > l2) + list[list_pos][5] = last_x[pos_x-l2]; + else + list[list_pos][5] = l2-pos_x; + last_y[l2] = list_pos; + ++list_pos; + + } + + + if ((b >= 0) && (diagonals[b].current_pos[1] > l2)) + --b; + + if ((a >0) && (diagonals[a-1].current_pos[0] - diagonals[a-1].current_pos[1] == pos_x)) + { + --a; + diagonals[a].prev_position = last_x[pos_x-1]; + } + } + + + dig_num = -1; + if (list_pos + l2+2 > current_size) + { + current_size += list_pos + l2 + 2; + list = vrealloc(list, current_size * sizeof(int*)); + } + + +// right border + list[list_pos] = vcalloc(6, sizeof(int)); + list[list_pos][0] = l1; + list[list_pos][1] = 0; + list[list_pos][3] = last_x[l1-1]; + list[list_pos][2] = -1000; + ++list_pos; + + + + for (i = 1; i <= l2; ++i) + { + list[list_pos] = vcalloc(6, sizeof(int)); + list[list_pos][0] = l1; + list[list_pos][1] = i; + list[list_pos][3] = last_y[i]; + list[list_pos][4] = list_pos-1; + y = last_y[i-1]; + if ((list[y][0] == l1-1) && (list[y][1] == i-1)) + { + list[list_pos][5] = y; + list[list_pos][2] = M[toupper(seq1[l1-1])-'A'][toupper(seq2[i-1])-'A']; + } + else + { + if (i <= l1) + { + list[list_pos][5] = last_x[l1-i]; + } + else + { + list[list_pos][5] = i-l1; + } + list[list_pos][2] = -1000; + } + ++list_pos; + } + + list[list_pos - l2][2] = -1000; + + *num_points = list_pos; +// vfree(diagx); +// vfree(diagy); + + + return list; +} + + + + +int +seq_pair2blast_diagonal2(char *seq_file_name1, + char *seq_file_name2, + Diagonal **diagonals, + int *dig_length, + int l1, + int l2, + int is_dna) +{ + char *out_file = vtmpnam(NULL); + char blast_command[200]; + char blast_command2[200]; + + if (is_dna) + { + sprintf(blast_command, "bl2seq -p blastn -i %s -j %s -D 1 -g F -o %s -S 1 -F F", seq_file_name1, seq_file_name2, out_file); + } + else + { + sprintf(blast_command, "bl2seq -p blastp -i %s -j %s -D 1 -g F -o %s -F F -S 1", seq_file_name1, seq_file_name2, out_file); + } + system(blast_command); + + Diagonal *diags = diagonals[0]; + FILE *diag_f = fopen(out_file,"r"); + char line[300]; + fgets(line, 300, diag_f); + fgets(line, 300, diag_f); + fgets(line, 300, diag_f); + + + char delims[] = "\t"; + int length, pos_q, pos_d; + int current_pos = 0; + while (fgets(line, 300, diag_f) != NULL) + { + strtok(line, delims); + strtok(NULL, delims); + strtok(NULL, delims); + length = atoi(strtok(NULL, delims)); + strtok(NULL, delims); + strtok(NULL, delims); + pos_q = atoi(strtok(NULL, delims)); + strtok(NULL, delims); + pos_d = atoi(strtok(NULL, delims)); + + if (current_pos >= *dig_length) + { + (*dig_length) += 40; + diags = vrealloc(diags, sizeof(Diagonal)*(*dig_length)); + } + diags[current_pos].x = pos_q; + diags[current_pos].y = pos_d; + diags[current_pos++].length = length; + } + fclose(diag_f); + diagonals[0] = diags; + return current_pos; +} + +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/dp_lib_header.h b/binaries/src/tcoffee/t_coffee_source/dp_lib_header.h new file mode 100644 index 0000000..2c5fd16 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/dp_lib_header.h @@ -0,0 +1,842 @@ +struct CL_node + { + + int copy_mode; + struct CL_node *c; + struct CL_node *p; + struct CL_node *l; + struct CL_node *r; + int seq; + int res; + int free; +}; + +typedef struct CL_node CL_node; +Alignment * add_constraint2aln ( Alignment *A, int s1, int r1, int s2, int r2); +Alignment * graph_aln (Alignment *A, Constraint_list *CL, Sequence *S); +Alignment* graph2aln (Alignment *A, CL_node *G, Sequence *S); +CL_node ***add_constraint2graph_aln (CL_node ***G, int s1, int r1, int s2, int r2); +CL_node * shift_segment ( CL_node *S, int segL, int shiftL); + +int is_graph_gap_column(CL_node *S); +CL_node * remove_graph_gap_column (CL_node *S); +CL_node * swap_gap_in_graph ( CL_node*S, CL_node *E); + +CL_node * declare_cl_nodes ( int len, int seq); +CL_node * insert_gap_columns (CL_node *S, int d); +int get_node_distance ( CL_node *S, CL_node *E); +CL_node ***aln2graph (Alignment *A); +CL_node *vfree_graph (CL_node *S); +CL_node *vfree_cl_node ( CL_node *N); + +int gotoh_pair_wise_lalign ( Alignment *A, int*ns, int **l_s,Constraint_list *CL); +Constraint_list * undefine_sw_aln ( Alignment *A, Constraint_list *CL); +Constraint_list * undefine_sw_pair ( Constraint_list *CL, int s1, int r1, int s2, int r2); +int sw_pair_is_defined ( Constraint_list *CL, int s1, int r1, int s2, int r2); + + +int gotoh_pair_wise_sw (Alignment *A,int*ns, int **l_s,Constraint_list *CL); + +Alignment * get_best_local_aln ( Alignment *IN,Constraint_list *CL,int gop, int gep, int sw_t, int sw_l, int sw_z, int greedy); +Alignment * get_best_nol_local_aln ( Alignment *IN, Constraint_list *CL, int gop, int gep,int sw_t,int sw_l, int sw_z, int mode); +double compute_penalty (Constraint_list *CL, char *mode, int len); +double compute_scale ( Constraint_list *CL,char *mode, int len); +int evaluate_penalty (Alignment *A, Constraint_list *CL, int *scale,char *scale_mode, int *penalty, char *penalty_mode, int len_seq); +Alignment ** t_coffee_lalign (Constraint_list *CL, int scale, int penalty,int maximise,Sequence *S, int sw_t, int sw_l, int sw_z,int *sw_n, int sw_io); +Alignment * add_seq2aln (Constraint_list *CL, Alignment *IN,Sequence *S); + + + + + + + +struct Dp_Model +{ + int *diag; + + int TG_MODE; + int F_TG_MODE; + int gop; + int gep; + int f_gop; + int f_gep; + int nstate; + int START; + int END; + + char**model_comments; + int **model; + int **model_properties; + int **bounded_model; + int (***model_emission_function)(Alignment*, int **, int, int*, int, int **, int, int*, int, struct Constraint_list *); + + int LEN_I; + int LEN_J; + int DELTA_I; + int DELTA_J; + int EMISSION; + int START_EMISSION; + int TERM_EMISSION; + + int ALN_TYPE; + Constraint_list *CL; + /*Associated Functions*/ + + /*To Deprecate*/ + int UM; + + int TYPE; + int F0; + int F1; + + + int NON_CODING; + int INSERTION; + int DELETION; + int CODING0; + int CODING1; + int CODING2; + + +}; +typedef struct Dp_Model Dp_Model; + +struct Dp_Result +{ + int *traceback; + int len; + int score; + Dp_Model *Dp_model; +}; +typedef struct Dp_Result Dp_Result; + +Dp_Result * make_fast_generic_dp_pair_wise (Alignment *A, int*ns, int **l_s,Dp_Model *M); + +Constraint_list* free_dp_model (Dp_Model *D); +Dp_Result * free_dp_result (Dp_Result *D ); + +typedef struct hseq* SeqHasch; + +typedef struct hseq +{ + SeqHasch hl[256]; + int n; + int *l; +} hseq; + +int ** ktup_dist_mat ( char **seq, int nseq, int ktup, char *type); +int ** evaluate_diagonals_for_two_sequences ( char *seq1, char *seq2,int maximise,Constraint_list *CL,int ktup); +int ** evaluate_diagonals ( Alignment *A, int *ns, int **l_s, Constraint_list *CL,int maximise,int n_groups, char **group_list,int ktup); +int ** evaluate_segments_with_ktup ( Alignment *A, int *ns, int **l_s, Constraint_list *CL,int maximise,int n_groups, char **group_list,int ktup); +int ** evaluate_diagonals_with_ktup ( Alignment *A, int *ns, int **l_s, Constraint_list *CL,int maximise,int n_groups, char **group_list,int ktup); + +int ** evaluate_diagonals_with_clist ( Alignment *A, int *ns, int **l_s, Constraint_list *CL,int maximise,int n_groups, char **group_list,int ktup); + +int * flag_diagonals (int l1, int l2, int **sorted_diag,float T, int window); +int * extract_N_diag (int l1, int l2, int **sorted_diag, int n_chosen_diag, int window); + +int hasch_seq(char *seq1, int **hs, int **lu,int ktup, char *alph); +int fasta_gotoh_pair_wise (Alignment *A,int*ns, int **l_s,Constraint_list *CL); +int cfasta_gotoh_pair_wise (Alignment *A,int*ns, int **l_s,Constraint_list *CL); +int very_fast_gotoh_pair_wise (Alignment *A,int*ns, int **l_s,Constraint_list *CL); + +int make_fasta_gotoh_pair_wise (Alignment *A,int*ns, int **l_s,Constraint_list *CL, int *diag); +/*********************************************************************/ +/* */ +/* KTUP_DP */ +/* */ +/* */ +/*********************************************************************/ + +int precomputed_pair_wise (Alignment *A,int*ns, int **l_s,Constraint_list *CL); +int ktup_pair_wise (Alignment *A,int*ns, int **l_s,Constraint_list *CL); +int ktup_comparison ( char *seq1, char *seq2, int ktup); +HaschT* hasch_sequence ( char *seq1, int ktup); + +SeqHasch * seq2hasch (int i,char *seq, int ktup, SeqHasch *H); +Constraint_list * hasch2constraint_list (Sequence*S, Constraint_list *CL); +SeqHasch *cleanhasch (SeqHasch *H); +int hasch2sim (SeqHasch *H, int nseq); +int cfasta_gotoh_pair_wise_sw (Alignment *A,int*ns, int **l_s,Constraint_list *CL); +int fasta_gotoh_pair_wise_sw (Alignment *A,int*ns, int **l_s,Constraint_list *CL); +int make_fasta_gotoh_pair_wise_sw (Alignment *A,int*ns, int **l_s,Constraint_list *CL, int *diag); + +/*pair wise aln implementations*/ + +int idscore_pairseq (char *s1, char *s2, int gop, int gep, int **m, char *mode); +int idscore_pair_wise (Alignment *A,int*ns, int **l_s,Constraint_list *CL); +int gotoh_pair_wise (Alignment *A,int*ns, int **l_s,Constraint_list *CL); +int glocal_pair_wise ( Alignment *A, int *ns, int **l_s, Constraint_list *CL); +int gotoh_pair_wise_lgp ( Alignment *A, int *ns, int **l_s, Constraint_list *CL); +int test_pair_wise (Alignment *A, int *ns, int **l_s, Constraint_list *CL); + +int glocal2_pair_wise (Alignment *A,int*ns, int **ls,Constraint_list *CL); +int linked_pair_wise ( Alignment *A, int *ns, int **l_s, Constraint_list *CL); +int linked_pair_wise_collapse ( Alignment *A, int *ns, int **l_s, Constraint_list *CL); +int cl2pair_list_ecl_ext_pc ( Alignment *A, int *ns, int **ls, Constraint_list *CL, int ***list_in, int *n_in); +void free_proba_pair_wise(); + +int subop1_pair_wise ( Alignment *A, int *ns, int **ls, Constraint_list *CL); +int subop2_pair_wise ( Alignment *A, int *ns, int **ls, Constraint_list *CL); +int proba_pair_wise ( Alignment *A, int *ns, int **ls, Constraint_list *CL); +int viterbi_pair_wise ( Alignment *A, int *ns, int **ls, Constraint_list *CL); +int biphasic_pair_wise ( Alignment *A, int *ns, int **l_s, Constraint_list *CL); + + + + + + + + +int cfasta_cdna_pair_wise (Alignment *A,int*ns, int **l_s,Constraint_list *CL); +int fasta_cdna_pair_wise (Alignment *A,int*ns, int **l_s,Constraint_list *CL); +Dp_Model* initialize_dna_dp_model (Constraint_list *CL); +Dp_Result * make_fast_dp_pair_wise (Alignment *A,int*ns, int **l_s, Constraint_list *CL,Dp_Model *M); +int make_fasta_cdna_pair_wise (Alignment *B,Alignment *A,int*ns, int **l_s,Constraint_list *CL, int *diag); + + + +int ** evaluate_diagonals_cdna ( Alignment *A, int *ns, int **l_s, Constraint_list *CL,int maximise,int n_groups, char **group_list, int ktup); +int cfasta_cdna_pair_wise (Alignment *A,int*ns, int **l_s,Constraint_list *CL); +Alignment *clean_maln ( Alignment *A, Alignment *I, int T, int n_it); +Alignment *realign_segment (int seq, int start, int len,Alignment *A, Alignment *C); +Dp_Model * initialize_seg2prf_model(int left_tg_mode, int right_tg_mode, Constraint_list *CL); + +int get_gep_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); +int get_start_gep_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); +int get_term_gep_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); + +Dp_Model * initialize_sseq_model(int left_tg_mode, int right_tg_mode, Constraint_list *CL); +int ssec_pwaln_maln (Alignment *A, int *ns, int **ls, Constraint_list *CL); + + +int get_turn_gep_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); +int get_turn_start_gep_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); +int get_turn_term_gep_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); + +int get_alpha_gep_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); +int get_alpha_start_gep_cost(Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); +int get_alpha_term_gep_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); + +int get_beta_gep_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); +int get_beta_start_gep_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); +int get_beta_term_gep_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); + +int get_alpha_sub_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); +int get_beta_sub_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); +int get_turn_sub_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); + +int get_ssec_no_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); +int sim_pair_wise_lalign (Alignment *in_A, int *in_ns, int **in_l_s, Constraint_list *in_CL); + +/*pair wise aln implementations*/ +int myers_miller_pair_wise (Alignment *A, int *ns, int **l_s,Constraint_list *CL); +int diff (Alignment *A, int *ns, int **ls, int s1, int M,int s2, int N , int tb, int te, Constraint_list *CL, int **pos); +int evaluate_est_order (Sequence *S, char *concat, Constraint_list *CL, int ktuple); + +Constraint_list *prepare_cl_for_moca ( Constraint_list *CL); +Alignment ** moca_aln ( Constraint_list *CL); +Alignment * extract_domain ( Constraint_list *CL); +Alignment * interactive_domain_extraction ( Constraint_list *CL); +int print_moca_interactive_choices (); + +Alignment * approximate_domain ( int min_start, int max_start, int step_start,int min_len, int max_len, int step_len, int *best_start, int *best_len, int *best_score, Constraint_list *CL); + +int measure_domain_length ( Constraint_list *CL,Alignment *IN, int start, int min_size, int max_size, int step); +Alignment *extract_domain_with_coordinates ( Alignment *RESULT,int start, int len, Constraint_list *CL); +int get_starting_point ( Constraint_list *CL); + +Alignment * find_domain_coordinates (Constraint_list *CL, int *start, int *len); +Alignment * extend_domain ( Constraint_list *CL, int *start, int *len, int dstart, int dlen); +Alignment * modify_domain ( Constraint_list *CL, Alignment *IN, int *start, int *len, int dstart, int dlen); + +int * analyse_sequence ( Constraint_list *CL); + +/****************************************************************************/ +/* */ +/* */ +/* Alignment Methods */ +/* */ +/* */ +/****************************************************************************/ +Alignment * sorted_aln (Alignment *A, Constraint_list *CL); +Alignment * sorted_aln_seq (int seq, Alignment *A, Constraint_list *CL); +Alignment * full_sorted_aln (Alignment *A, Constraint_list *CL); + +/******************************************************************/ +/* MAIN DRIVER */ +/* */ +/* */ +/******************************************************************/ + +Constraint_list *profile2list ( Job_TC *job,int nprf); +Constraint_list *seq2list (Job_TC *Job); +Constraint_list *method2pw_cl (TC_method *M, Constraint_list *CL); +int method_uses_structure(TC_method *M); +int method_uses_profile(TC_method *M); + +/******************************************************************/ +/* MULTIPLE ALIGNMENTS */ +/* */ +/* */ +/******************************************************************/ +Alignment * compute_prrp_aln (Alignment *A, Constraint_list *CL); +Alignment * compute_clustalw_aln (Alignment *A, Constraint_list *CL); +Alignment * compute_tcoffee_aln_quick (Alignment *A, Constraint_list *CL); +Alignment * seq2clustalw_aln (Sequence *S); +Alignment * aln2clustalw_aln (Alignment *A, Constraint_list *CL); +Alignment * realign_block ( Alignment *A, int col1, int col2, char *pg); +/******************************************************************/ +/* DNA */ +/* */ +/* */ +/******************************************************************/ +Constraint_list * align_coding_nucleotides (char *seq, char *method, char *weight, char *mem_mode, Constraint_list *CL); +/******************************************************************/ +/* STRUCTURES */ +/* */ +/* */ +/******************************************************************/ +Constraint_list * seq_msa (TC_method *M , char *in_seq, Constraint_list *CL); + +Constraint_list *align_pdb_pair (char *seq_in, char *dp_mode,char *evaluate_mode, char *file, Constraint_list *CL, Job_TC *job); +Constraint_list * align_pdb_pair_2 (char *seq, Constraint_list *CL); + +Constraint_list * pdb_pair ( TC_method*M,char *seq, Constraint_list *CL); +Constraint_list * pdbid_pair ( TC_method*M,char *seq, Constraint_list *CL); +Constraint_list * profile_pair ( TC_method*M,char *seq, Constraint_list *CL); +Constraint_list * thread_pair ( TC_method*M,char *seq, Constraint_list *CL); +Constraint_list * thread_pair2 ( TC_method *M,int s1, int s2, Constraint_list *CL); +Constraint_list * sap_pair (char *seq, char *weight, Constraint_list *CL); +Constraint_list * lsqman_pair (char *seq, Constraint_list *CL); +Constraint_list * rna_pair (TC_method *M , char *in_seq, Constraint_list *CL); + +/******************************************************************/ +/* GENERIC PAIRWISE METHODS */ +/* */ +/* */ +/******************************************************************/ +Constraint_list *best_pair4prot (Job_TC *job); +Constraint_list *best_pair4rna (Job_TC *job); +Alignment * fast_pair (Job_TC *job); + +void toggle_case_in_align_two_sequences(int value); +Alignment * align_two_sequences ( char *seq1, char *seq2, char *matrix, int gop, int gep, char *align_mode); +Alignment * align_two_aln ( Alignment *A1, Alignment *A2, char *in_matrix, int gop, int gep, char *in_align_mode); +NT_node make_root_tree ( Alignment *A,Constraint_list *CL,int gop, int gep,Sequence *S, char *tree_file,int maximise); +NT_node ** make_tree ( Alignment *A,Constraint_list *CL,int gop, int gep,Sequence *S, char *tree_file, int maximise); +int ** get_pw_distances ( Alignment *A,Constraint_list *CL,int gop, int gep, char **out_seq, char **out_seq_name, int out_nseq, char *tree_file, char *tree_mode, int maximise); +Alignment *stack_progressive_nol_aln_with_seq_coor(Constraint_list *CL,int gop, int gep,Sequence *S, int **seq_coor, int nseq); +Alignment *stack_progressive_aln_with_seq_coor (Constraint_list*CL,int gop, int gep, Sequence *S, int **coor, int nseq); +Alignment *stack_progressive_aln(Alignment *A, Constraint_list *CL, int gop, int gep); +Alignment *est_progressive_aln(Alignment *A, Constraint_list *CL, int gop, int gep); +void analyse_seq ( Alignment *A, int s); + +char ** list_file2dpa_list_file (char **list_file, int *len,int maxnseq, Sequence *S); +Alignment * seq2aln_group (Alignment *A, int T, Constraint_list *CL); + +Alignment *profile_aln (Alignment *A, Constraint_list *CL); +Alignment * iterative_tree_aln (Alignment *A,int n, Constraint_list *CL); +Alignment * iterative_aln ( Alignment*A, int nseq, Constraint_list *CL); +Alignment * seq_aln ( Alignment*A, int nseq, Constraint_list *CL); +Alignment *tsp_aln (Alignment *A, Constraint_list *iCL, Sequence *S); +Alignment *iterate_aln ( Alignment*A, int nit, Constraint_list *CL); +Alignment *realign_aln ( Alignment*A, Constraint_list *CL); +Alignment *very_fast_aln (Alignment*A, int nseq, Constraint_list *CL); +Alignment *simple_progressive_aln (Sequence *S, NT_node **T, Constraint_list *CL, char *mat); +Alignment *frame_aln (Alignment *A, int n,Constraint_list *CL); +Alignment *dpa_aln (Alignment *A, Constraint_list *CL); +Alignment *new_dpa_aln (Alignment *A, Constraint_list *CL); +Alignment * make_delayed_tree_aln (Alignment *A,int n, Constraint_list *CL); + +NT_node* delayed_tree_aln ( NT_node LT, NT_node RT, Alignment*A, int nseq, Constraint_list *CL); +int node2seq_list (NT_node P, int *ns, int *ls); +Alignment* delayed_tree_aln1 ( NT_node P,Alignment*A,Constraint_list *CL, int threshold); +Alignment* delayed_tree_aln2 ( NT_node P,Alignment*A,Constraint_list *CL, int threshold); + +NT_node* tree2ao (NT_node LT, NT_node RT,Alignment *A, int nseq,Constraint_list *CL);//tree2align_order +NT_node* tree_aln ( NT_node LT, NT_node RT, Alignment*A, int nseq, Constraint_list *CL); +NT_node* local_tree_aln ( NT_node LT, NT_node RT, Alignment*A, int nseq, Constraint_list *CL); +NT_node* seqan_tree_aln ( NT_node LT, NT_node RT, Alignment*A, int nseq, Constraint_list *CL); + + +NT_node* tree_realn ( NT_node LT, NT_node RT, Alignment*A, int nseq, Constraint_list *CL); + +int split_condition (int nseq, int score, Constraint_list *CL); + +int profile_pair_wise (Alignment *A, int n1, int *l1, int n2, int *l2, Constraint_list *CL); +int pair_wise (Alignment *A, int*ns, int **l_s,Constraint_list *CL ); + +int empty_pair_wise ( Alignment *A, int *ns, int **l_s, Constraint_list *CL, int glocal); + + +Pwfunc get_pair_wise_function (Pwfunc func, char *dp_mode, int *glocal); + + + +char *build_consensus ( char *seq1, char *seq2, char *dp_mode); +int fastal (int argv, char **arg); + +int domain_pair_wise (Alignment *A,int*ns, int **l_s,Constraint_list *CL ); +Alignment *domain_match_list2aln ( Alignment *A,int *ns,int **l_s,int **ml, int nseq, int len); +Alignment * domain_seq2domain (Constraint_list *CL,int scale,int gop,int gep,Alignment *SEQ_DOMAIN, Alignment *TARGET); + + +int custom_pair_score_function1 (Constraint_list *CL, int s1, int r1, int s2, int r2); +int custom_pair_score_function2 (Constraint_list *CL, int s1, int r1, int s2, int r2); +int custom_pair_score_function3 (Constraint_list *CL, int s1, int r1, int s2, int r2); +int custom_pair_score_function4 (Constraint_list *CL, int s1, int r1, int s2, int r2); +int custom_pair_score_function5 (Constraint_list *CL, int s1, int r1, int s2, int r2); +int custom_pair_score_function6 (Constraint_list *CL, int s1, int r1, int s2, int r2); +int custom_pair_score_function7 (Constraint_list *CL, int s1, int r1, int s2, int r2); +int custom_pair_score_function8 (Constraint_list *CL, int s1, int r1, int s2, int r2); +int custom_pair_score_function9 (Constraint_list *CL, int s1, int r1, int s2, int r2); +int custom_pair_score_function10 (Constraint_list *CL, int s1, int r1, int s2, int r2); +int apdb (int argc, char *argv[]); + +Constraint_list * set_constraint_list4align_pdb (Constraint_list *inCL,int seq, char *dp_mode, char *hasch_mode, char *param_file); +int evaluate_ca_trace_sap2_bubble (Constraint_list *CL, int s1, int r1, int s2, int r2); +int evaluate_ca_trace_nb (Constraint_list *CL, int s1, int s2, int r1, int r2); +int evaluate_ca_trace_bubble (Constraint_list *CL, int s1, int s2, int r1, int r2); +int evaluate_ca_trace_sap1_bubble (Constraint_list *CL, int s1, int s2, int r1, int r2); +int evaluate_ca_trace_3D_bubble (Constraint_list *CL, int s1, int s2, int r1, int r2); +int evaluate_ca_trace_transversal (Constraint_list *CL, int s1, int s2, int r1, int r2); +int evaluate_ca_trace_bubble_2 (Constraint_list *CL, int s1, int s2, int r1, int r2); +int evaluate_ca_trace_bubble_3 (Constraint_list *CL, int s1, int s2, int r1, int r2); + + +/*********************************************************************************************/ +/* */ +/* FUNCTIONS FOR COMPARING TWO NEIGHBORHOODS:START */ +/* */ +/*********************************************************************************************/ +float matrix_match (Constraint_list *CL, int s1, int s2, int r1, int r2, Struct_nb *nbs1, Struct_nb *nbs2); +float transversal_match (Constraint_list *CL, int s1, int s2, int r1, int r2, Struct_nb *nbs1, Struct_nb *nbs2); +float neighborhood_match (Constraint_list *CL, int s1, int s2, int r1, int r2,Struct_nb *nbs1, Struct_nb *nbs2); +float sap1_neighborhood_match (Constraint_list *CL, int s1, int s2, int r1, int r2, Struct_nb *nbs1, Struct_nb *nbs2); +float sap2_neighborhood_match (Constraint_list *CL, int s1, int s2, int r1, int r2, Struct_nb *nbs1, Struct_nb *nbs2); + + +/*********************************************************************************************/ +/* */ +/* FUNCTIONS FOR COMPARING TWO NEIGHBORHOODS:END */ +/* */ +/*********************************************************************************************/ +Alignment * analyse_pdb ( Alignment *A, Alignment *ST, char *filename); +Alignment * msa2struc_dist ( Alignment *A, Alignment *ST, char *filename, int gapped, int min_ncol); +float **** analyse_pdb_residues ( Alignment *A, Constraint_list *CL, Pdb_param *pdb_param); + +float square_atom ( Atom *X); +Atom* reframe_atom ( Atom *X, Atom*Y, Atom *Z, Atom *IN, Atom *R); +Atom* add_atom ( Atom *A, Atom*B, Atom *R); +Atom* diff_atom ( Atom *A, Atom*B, Atom *R); +Atom * copy_atom ( Atom *A, Atom*R); +/************************************************************************/ +/* */ +/* NUSSINOV */ +/* */ +/************************************************************************/ +char *nussinov (char *S, int min_dist); +char * rna_struc2rna_lib ( char *seq_name, char *seq, char *name); +int display_rna_ss ( int pos, char *seq, char *struc, FILE *fp); +int evaluate_aln_gibbs ( Alignment *A, Constraint_list *CL); +int evaluate_moca_domain ( Alignment *A, Constraint_list *CL); +int moca_residue_pair_extended_list ( Constraint_list *CL, int s1, int r1, int s2, int r2); +int moca_evaluate_matrix_score ( Constraint_list *CL, int s1, int r1, int s2, int r2); +int moca_slow_get_dp_cost ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); + +int **cache_cl_with_moca_domain (Alignment *A, Constraint_list *CL); +Alignment *make_moca_nol_aln ( Alignment *A, Constraint_list *CL); +/*********************************************************************************************/ +/* */ +/* DOMAIN Z SCORE EVALUATION */ +/* */ +/*********************************************************************************************/ + +int evaluate_domain_aln_z_score (Alignment *A, int start, int end,Constraint_list *CL, char *alphabet); +int evaluate_domain_aln ( Alignment *A, int start, int end,Constraint_list *CL); + + + +int unpack_seq_residues ( int *s1, int *r1, int *s2, int *r2, int **packed_seq_lu); +Alignment * unpack_seq_aln ( Alignment *A,Constraint_list *C); +typedef struct +{ + int N_COMPONENT; + double *double_logB_alpha; + double *exponant_list; + double **ALPHA; + double *DM_Q; + double *alpha_tot; + int n_aa; + int tot_n; +} +Mixture; + +double int_logB (int *i, int n); +double float_logB (float *i, int n); +double double_logB (double *x, int n); +double *** make_lup_table ( Mixture *D); +double double_logB2(int j, double *n,Mixture *D); +double compute_exponant ( double *n, int j, Mixture *D); + +double *compute_matrix_p ( double *n,int Nseq); +double* compute_dirichlet_p ( double *n,int Nseq); +void precompute_log_B ( double *table,Mixture *D); +double compute_X (double *n,int i,Mixture *D); +Mixture *read_dirichlet ( char *name); +int dirichlet_code( char aa); + +double lgamma2 ( double x); +double lgamma_r(double x, int *signgamp); +/*********************************************************************************************/ +/* */ +/* FUNCTIONS FOR EVALUATING THE CONSISTENCY BETWEEN ALN AND CL */ +/* */ +/*********************************************************************************************/ +Alignment * overlay_alignment_evaluation ( Alignment *I, Alignment *O); +Alignment * main_coffee_evaluate_output ( Alignment *IN,Constraint_list *CL, const char *mode ); +int aln2ecl_raw_score (Alignment *A, Constraint_list *C); +int sub_aln2ecl_raw_score (Alignment *A, Constraint_list *CL, int ns, int *ls); +int sub_aln2sub_aln_raw_score ( Alignment *IN,Constraint_list *CL, const char *mode, int *ns, int **ls); +int node2sub_aln_score(Alignment *A,Constraint_list *CL, char *mode, NT_node T); +int sub_aln2sub_aln_score ( Alignment *IN,Constraint_list *CL, const char *mode, int *ns, int **ls); +Alignment * main_coffee_evaluate_output_sub_aln ( Alignment *IN,Constraint_list *CL, const char *mode, int *ns, int **ls); + +Alignment * categories_evaluate_output ( Alignment *IN,Constraint_list *CL); +Alignment * matrix_evaluate_output ( Alignment *IN,Constraint_list *CL); +Alignment * sar_evaluate_output ( Alignment *IN,Constraint_list *CL); +Alignment * boxshade_evaluate_output ( Alignment *IN,Constraint_list *CL, int T); +Alignment * triplet_coffee_evaluate_output ( Alignment *IN,Constraint_list *CL); +Alignment * fast_coffee_evaluate_output ( Alignment *IN,Constraint_list *CL); + +int slow_coffee_evaluate_sub_aln ( Alignment *IN,int *ns, int **ls, Constraint_list *CL); +Alignment * slow_coffee_evaluate_output ( Alignment *IN,Constraint_list *CL); +Alignment * non_extended_t_coffee_evaluate_output( Alignment *IN,Constraint_list *CL); +Alignment * heuristic_coffee_evaluate_output ( Alignment *IN,Constraint_list *CL); +Alignment *coffee_seq_evaluate_output ( Alignment *IN, Constraint_list *CL); +/*Old Function: To deprecate*/ +Alignment * coffee_evaluate_output ( Alignment *IN,Constraint_list *CL); + +/*********************************************************************************************/ +/* */ +/* PROFILE/PRofile Functions */ +/* */ +/*********************************************************************************************/ +Profile_cost_func get_profile_mode_function (char *name, Profile_cost_func func); +int generic_evaluate_profile_score (Constraint_list *CL,Alignment *Prf1, int s1, int r1, Alignment *Prf2, int s2, int r2, Profile_cost_func prf_prf); +int cw_profile_profile (int *prf1, int *prf2, Constraint_list *CL); +int muscle_profile_profile (int *prf1, int *prf2, Constraint_list *CL); + +/*********************************************************************************************/ +/* */ +/* FUNCTIONS FOR GETING THE COST : (Sequences) ->evaluate_residue_pair */ +/* */ +/*********************************************************************************************/ +int initialize_scoring_scheme (Constraint_list *CL); +int evaluate_blast_profile_score (Constraint_list *CL, int s1, int r1, int s2, int r2); +int evaluate_aln_profile_score (Constraint_list *CL, int s1, int r1, int s2, int r2); + +int evaluate_profile_score ( Constraint_list *CL,Alignment *Prf1, int s1, int r1, Alignment *Prf2, int s2, int r2); +int evaluate_cdna_matrix_score ( Constraint_list *CL, int s1, int r1, int s2, int r2); +int evaluate_diaa_matrix_score ( Constraint_list *CL, int s1, int r1, int s2, int r2); +int evaluate_monoaa_matrix_score ( Constraint_list *CL, int s1, int r1, int s2, int r2); +int evaluate_matrix_score ( Constraint_list *CL, int s1, int r1, int s2, int r2); +int evaluate_tm_matrix_score ( Constraint_list *CL, int s1, int r1, int s2, int r2); +int evaluate_ssp_matrix_score ( Constraint_list *CL, int s1, int r1, int s2, int r2); +int evaluate_curvature_score ( Constraint_list *CL, int s1, int r1, int s2, int r2); + +int evaluate_combined_matrix_score ( Constraint_list *CL, int s1, int r1, int s2, int r2); +int evaluate_physico_score ( Constraint_list *CL, int s1, int r1, int s2, int r2); +int residue_pair_non_extended_list ( Constraint_list *CL, int s1, int r1, int s2, int r2); + +int residue_pair_extended_list4rna1 ( Constraint_list *CL, int s1, int r1, int s2, int r2); +int residue_pair_extended_list4rna2 ( Constraint_list *CL, int s1, int r1, int s2, int r2); +int residue_pair_extended_list4rna3 ( Constraint_list *CL, int s1, int r1, int s2, int r2); +int residue_pair_extended_list4rna4 ( Constraint_list *CL, int s1, int r1, int s2, int r2); +int residue_pair_extended_list4rna ( Constraint_list *CL, Constraint_list *R, int s1, int r1, int s2, int r2); + +int residue_pair_extended_list_raw ( Constraint_list *CL, int s1, int r1, int s2, int r2); +int residue_pair_extended_list_pc ( Constraint_list *CL, int s1, int r1, int s2, int r2); +int residue_pair_extended_list_4gp ( Constraint_list *CL, int s1, int r1, int s2, int r2); +int residue_pair_extended_list ( Constraint_list *CL, int s1, int r1, int s2, int r2); + + + + +int residue_pair_extended_list_g_coffee_quadruplet ( Constraint_list *CL, int s1, int r1, int s2, int r2); +int residue_pair_extended_list_g_coffee ( Constraint_list *CL, int s1, int r1, int s2, int r2); +int residue_pair_extended_list_quadruplet ( Constraint_list *CL, int s1, int r1, int s2, int r2); +int residue_pair_extended_list_mixt ( Constraint_list *CL, int s1, int r1, int s2, int r2); +int residue_pair_test_function ( Constraint_list *CL, int s1, int r1, int s2, int r2); +int extend_residue_pair ( Constraint_list *CL, int s1, int r1, int s2, int r2); + +int residue_pair_relative_extended_list ( Constraint_list *CL, int s1, int r1, int s2, int r2 ); +/*********************************************************************************************/ +/* */ +/* FUNCTIONS FOR GETTING THE PW COST : CL->get_dp_cost */ +/* */ +/*********************************************************************************************/ +int get_dp_cost_blosum_matrix (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); +int get_dp_cost_pam_matrix (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); +int get_dp_cost_pw_matrix (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); + +int get_cdna_best_frame_dp_cost ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); +int get_dp_cost ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); +int get_dp_cost_quadruplet ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); + + +int very_fast_get_dp_cost ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); + +int cw_profile_get_dp_cost ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); +int cw_profile_get_dp_cost_window ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); + +int consensus_get_dp_cost ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); + +int fast_get_dp_cost ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); +int fast_get_dp_cost_2 ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); +int fast_get_dp_cost_3 ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); + +int fast_get_dp_cost_quadruplet ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); + +int check_fast_profile_mode (Alignment *A, int ns1,int *list1,int ns2, int *list2, Constraint_list *CL); +int check_fast_mode (Alignment *A, int ns1,int *list1,int ns2, int *list2, Constraint_list *CL); + + +int slow_get_dp_cost ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); +int slow_get_dp_cost_pc ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); +int slow_get_dp_cost_test ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); + +int sw_get_dp_cost ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL); +int get_domain_dp_cost ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2,Constraint_list *CL , int scale , int gop, int gep); + +/*********************************************************************************************/ +/* */ +/* FUNCTIONS FOR ANALYSING AL OR MATRIX */ +/* */ +/*********************************************************************************************/ +float ** initialise_aa_physico_chemical_property_table (int *n); +int aln2n_res ( Alignment *A, int start, int end); +float get_gop_scaling_factor ( int **matrix,float id, int l1, int l2); +float get_avg_matrix_mm ( int **matrix, char *alphabet); +float get_avg_matrix_match ( int **matrix, char *alphabet); +float get_avg_matrix_diff ( int **matrix1,int **matrix2, char *alphabet); +float measure_matrix_enthropy (int **matrix,char *alphabet); +float measure_matrix_pos_avg (int **matrix,char *alphabet); +float evaluate_random_match (char *matrix, int n, int len,char *alp); +float compare_two_mat (char *mat1,char*mat2, int n, int len,char *alp); +float compare_two_mat_array (int **matrix1,int **matrix2, int n, int len,char *alp); +int ** rescale_two_mat (char *mat1,char*mat2, int n, int len,char *alp); +int ** rescale_matrix ( int **mat, float lambda, char *alp); +int **mat2inverted_mat (int **matrix, char *alp); +void output_matrix_header ( char *name, int **matrix, char *alp); +float evaluate_random_match2 (int **matrix, int n, int len,char *alp); +float measure_lambda2(char *mat1,char*mat2, int n, int len,char *alp); +float measure_lambda(char *mat1,char*mat2, int n, int len,char *alp); +Constraint_list * choose_extension_mode ( char *extend_mode, Constraint_list *CL); +int ** combine_two_matrices ( int **mat1, int **mat2); +/*********************************************************************************************/ +/* */ +/* OFF THE SHELVES EVALUATION */ +/* */ +/*********************************************************************************************/ +float sum_pair ( Alignment*A,char *mat_name, int gap_op, int gap_ext); +int lat_sum_pair (Alignment *A, char *mat); +int ** show_pair(int istart, int iend, int jstart, int jend, int *seqlen_array, char **seq_array, int dna_ktup, int dna_window, int dna_wind_gap, int dna_signif,int prot_ktup, int prot_window,int prot_wind_gap,int prot_signif, int nseqs,int dnaflag, int max_aa, int max_aln_length ); +/*By convention, 0: START, 1: END*/ + +struct Hmm +{ + + double freeT; /*Free transition*/ + double forbiden; /*Forbiden transition*/ + int start; /*start, by convention: 0*/ + int end; /*end, by convention: 1*/ + + int nS; /*Number of states*/ + int order; + struct HmmState **S; /*State List*/ + + /*Bounded HMM*/ + double **T; /*Transition matrix*/ + int **fromM; /*For any sate s, fromM[0]->number of states leading to s*/ + int **toM; /*For any sate s, toM[0]->number of s can go to*/ + /*End and Start are NOT included in toM and FromM*/ + + +}; +typedef struct Hmm Hmm; + +struct HmmAln +{ + Hmm *H; + int *state_list; +}; +typedef struct HmmAln HmmAln; + +typedef double (*Generic_em_func)(struct Hmm*, struct HmmState*, int); + +struct HmmState +{ +char name[100]; +int state; +int DJ; +int DI; + + /*Pair HMM*/ +double em; +Col_cost_func em_func; + + /*Linear HMM*/ +double *em2; +Generic_em_func em_func2; +int nT; +struct StateTrans **T; +}; +typedef struct HmmState HmmState; + +struct StateTrans +{ + char name[101]; + double tr; +}; +typedef struct StateTrans StateTrans; + +struct MatState +{ + int i; + int j; + int st; + int pst; + double sc; + struct MatState *n; + struct MatState *p; + struct MatState *m; /*memory*/ + struct MatState *s; /*memory of the start point*/ + /*Heap Mamagement: Never copy*/ + struct MatState *Hn;/*Heap Next*/ + struct MatState *Hp;/*Heap Previous*/ + + struct MatState *Mn;/*Marked Heap section*/ + struct MatState *Mp;/*Marked Heap Section*/ + int free; +}; +typedef struct MatState MatState; + + +/*********************************************************************************/ +/* */ +/* */ +/* simple HMM: Viterbi */ +/* */ +/* */ +/*********************************************************************************/ +int seq_viterbi_pair_wise (Alignment *A,int*ns, int **ls,Constraint_list *CL); + +/*********************************************************************************/ +/* */ +/* */ +/* HMM: Viterbi */ +/* */ +/* */ +/*********************************************************************************/ + +int viterbi_pair_wise_OLD (Alignment *A,int*ns, int **ls,Constraint_list *CL); +Alignment * viterbipath2aln (Alignment *A, int *ns,int **ls,int *tb, Hmm *H); +double*** viterbi_hmm (Alignment *A,int *ns, int **ls, Hmm *H, Constraint_list *CL); +int * viterbi2path (int l1,int l2, Hmm *H, double ***M); +/*********************************************************************************/ +/* */ +/* */ +/* HMM modeling */ +/* */ +/* */ +/*********************************************************************************/ +int viterbiL_pair_wise (Alignment *A,int*ns, int **ls,Constraint_list *CL); +MatState* RviterbiL_hmm (Alignment *A,int *ns, int **ls, Hmm *H, Constraint_list *CL,MatState *S, MatState *E); +MatState* viterbiL_hmm (Alignment *A,int *ns, int **ls, Hmm *H, Constraint_list *CL, MatState *S, MatState *E); + +int viterbiD_pair_wise (Alignment *A,int*ns, int **ls,Constraint_list *CL); +double lu_RviterbiD_hmm (Alignment *A,int *ns, int **ls, Hmm *H, Constraint_list *CL,MatState *S, MatState *E, int **seg_list); +MatState* RviterbiD_hmm (Alignment *A,int *ns, int **ls, Hmm *H, Constraint_list *CL,MatState *S, MatState *E, int **seg_list); +MatState* viterbiD_hmm (Alignment *A,int *ns, int **ls, Hmm *H, Constraint_list *CL, MatState *S, MatState *E, int **seg_list); +int **seglist2table ( int **seglist,int l1, int l2); +int *seglist2line ( int **seglist, int line, int start, int end); +int * traceback (Alignment *A,int *ns, int **ls, Hmm *H, Constraint_list *CL,MatState *S, MatState *E, int **seg_list); + +int viterbiDGL_pair_wise (Alignment *A,int*ns, int **ls,Constraint_list *CL); +double lu_RviterbiDGL_hmm (Alignment *A,int *ns, int **ls, Hmm *H, Constraint_list *CL,MatState *S, MatState *E, int **seg_list); +MatState* RviterbiDGL_hmm (Alignment *A,int *ns, int **ls, Hmm *H, Constraint_list *CL,MatState *S, MatState *E, int **seg_list); +MatState* viterbiDGL_hmm (Alignment *A,int *ns, int **ls, Hmm *H, Constraint_list *CL,MatState *S, MatState *E, int **seg_list); + + +/*********************************************************************************/ +/* */ +/* */ +/* HMM modeling */ +/* */ +/* */ +/*********************************************************************************/ +int MatStateAreIdentical (MatState*I, MatState*O); +int MaxDeltaMatState (MatState*I, MatState*O); +int MinDeltaMatState (MatState*I, MatState*O); + +MatState * ManageMatState(int Mode, MatState *C); +MatState* CopyMatState ( MatState*I, MatState*O); + +Hmm* read_hmm(char *file); +Hmm* declare_hmm(int n); +Hmm* free_Hmm(Hmm*H); +void DisplayHmm ( Hmm *H); + +/*********************************************************************************/ +/* */ +/* */ +/* HMM Models */ +/* */ +/* */ +/*********************************************************************************/ +Hmm* define_two_mat_model(Constraint_list *CL); +Hmm* define_probcons_model(Constraint_list *CL); +Hmm* define_simple_model(Constraint_list *CL); + +Hmm * bound_hmm ( Hmm *H); +Sequence *pavie_seq2random_seq (Sequence *S, char *subst); +double **pavie_seq2pavie_aln(Sequence *S,char *mat, char *mode); +Alignment *pavie_seq2pavie_sort ( Sequence *S, char *mat, char *mode); +Alignment* pavie_seq2pavie_msa ( Sequence *S, char *mat, char *mode); +NT_node pavie_seq2pavie_tree ( Sequence *S, char *mat, char *mode); +int **pavie_seq2trained_pavie_mat(Sequence *S, char *param); +int pavie_pair_wise (Alignment *A,int *ns, int **l_s,Constraint_list *CL ); +Sequence *pavie_seq2noisy_seq (Sequence *S, int val,char *subst); +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/evaluate.c b/binaries/src/tcoffee/t_coffee_source/evaluate.c new file mode 100644 index 0000000..bf0f67e --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/evaluate.c @@ -0,0 +1,5477 @@ +#include +#include +#include +#include +#include +#include +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" + +#include "dp_lib_header.h" +float compute_lambda (int **matrix,char *alphabet); +/*********************************************************************************************/ +/* */ +/* FUNCTIONS FOR EVALUATING THE CONSISTENCY BETWEEN ALN AND CL */ +/* */ +/*********************************************************************************************/ + +/*Fast: score= extended_res/max_extended_residue_for the whole aln + slow: score= extended_res/sum all extended score for that residue + non_extended score= non_ext /sum all non extended score for that residue + heuristic score= extended /sum of extended score of all pairs in the library + (i.e. Not ALL the possible pairs) +*/ +Alignment * main_coffee_evaluate_output2 ( Alignment *IN,Constraint_list *CL, const char *mode ); +int sub_aln2ecl_raw_score (Alignment *A, Constraint_list *CL, int ns, int *ls) +{ + int **pos; + int p1,r1, r2, s1, s2; + int score=0; + + if ( !A) return 0; + A=reorder_aln (A, (CL->S)->name,(CL->S)->nseq); + pos=aln2pos_simple ( A,A->nseq); + + + + for (p1=0; p1len_aln; p1++) + { + for (s1=0; s10 && r2>0) + { + score+= residue_pair_extended_list_pc (CL,ls[s1], r1, ls[s2], r2)*SCORE_K; + } + } + } + } + free_int (pos, -1); + return score; + return (score/(((ns*ns)-ns)/2))/A->len_aln; +} +int aln2ecl_raw_score (Alignment *A, Constraint_list *CL) +{ + int **pos; + int p1,r1, r2, s1, s2; + int score=0; + if ( !A) return 0; + A=reorder_aln (A, (CL->S)->name,(CL->S)->nseq); + pos=aln2pos_simple ( A,A->nseq); + + + + for (p1=0; p1len_aln; p1++) + { + for (s1=0; s1nseq-1; s1++) + { + for (s2=s1+1; s2nseq; s2++) + { + + r1=pos[s1][p1]; + r2=pos[s2][p1]; + if (r1>0 && r2>0)score+= residue_pair_extended_list_pc (CL,s1, r1, s2, r2); + } + } + } + free_int (pos, -1); + return score; + return (score/(((A->nseq*A->nseq)-A->nseq)/2))/A->len_aln; +} +int node2sub_aln_score (Alignment *A,Constraint_list *CL, char *mode, NT_node T) +{ + if ( !T || !T->right ||!T->left)return 0; + else + { + int *ns; + int **ls; + ns=vcalloc (2, sizeof (int)); + ls=vcalloc (2, sizeof (int*)); + ns[0]= (T->left)->nseq; + ns[1]=(T->right)->nseq; + ls[0]= (T->left)->lseq; + ls[1]=(T->right)->lseq; + + return sub_aln2sub_aln_score (A, CL, mode, ns, ls); + } + return -1; +} +int sub_aln2sub_aln_score ( Alignment *A,Constraint_list *CL, const char *mode, int *ns, int **ls) +{ + /*Warning: Does Not Take Gaps into account*/ + + int **pos; + int a; + float score=0; + + /*Make sure evaluation functions update their cache if needed*/ + A=update_aln_random_tag (A); + pos=aln2pos_simple ( A, -1, ns, ls); + for (a=0; a< A->len_aln; a++) + score+=CL->get_dp_cost (A, pos, ns[0], ls[0], a, pos, ns[1],ls[1], a, CL); + free_int (pos, -1); + + score=(int)(((float)score)/(A->len_aln*SCORE_K)); + score=(int)(CL->residue_index && CL->normalise)?((score*MAXID)/(CL->normalise)):(score); + return (int)score; +} +int sub_aln2sub_aln_raw_score ( Alignment *A,Constraint_list *CL, const char *mode, int *ns, int **ls) +{ + /*Warning: Does Not Take Gaps into account*/ + + int **pos; + int a; + float score=0; + + /*Make sure evaluation functions update their cache if needed*/ + A=update_aln_random_tag (A); + pos=aln2pos_simple ( A, -1, ns, ls); + for (a=0; a< A->len_aln; a++) + score+=CL->get_dp_cost (A, pos, ns[0], ls[0], a, pos, ns[1],ls[1], a, CL); + free_int (pos, -1); + return (int) score; +} + +Alignment* main_coffee_evaluate_output_sub_aln ( Alignment *A,Constraint_list *CL, const char *mode, int *n_s, int **l_s) +{ + Alignment *SUB1, *SUB2, *SUB3; + int a, b, c,*list_seq; + + + if (strm ( CL->evaluate_mode, "no"))return NULL; + else + { + list_seq=vcalloc (n_s[0]+n_s[1], sizeof (int)); + for (b=0, a=0; a< 2; a++){for (c=0;c< n_s[a]; c++)list_seq[b++]=l_s[a][c];} + + + SUB1=copy_aln (A, NULL); + SUB2=extract_sub_aln (SUB1,n_s[0]+n_s[1],list_seq); + SUB3=main_coffee_evaluate_output (SUB2,CL,CL->evaluate_mode); + free_aln (SUB1); + free_aln (SUB2); + vfree (list_seq); + + return SUB3; + } +} +Alignment * overlay_alignment_evaluation ( Alignment *I, Alignment *O) +{ + int a, b, c, r, i; + int *buf; + + if ( !I || !O) return O; + if ( I->len_aln!=O->len_aln)printf_exit (EXIT_FAILURE, stderr, "ERROR: Incompatible alignments in overlay_alignment_evaluation"); + + buf=vcalloc ( MAX(I->len_aln, O->len_aln), sizeof (int)); + + for (a=0; anseq; a++) + { + if (!strm (I->name[a], O->name[a]))printf_exit (EXIT_FAILURE, stderr, "ERROR: Incompatible alignments in overlay_alignment_evaluation"); + for (b=0; blen_aln; b++) + { + r=I->seq_al[a][b]; + if ( islower(r))O->seq_al[a][b]=0; + else if (r<=9 || (r>='0' && r<='9'))O->seq_al[a][b]=I->seq_al[a][b]; + } + } + return O; +} + +Alignment * main_coffee_evaluate_output ( Alignment *IN,Constraint_list *CL, const char *mode ) +{ + + Alignment *TopS=NULL, *LastS=NULL, *CurrentS=NULL; + + + if ( IN->A)IN=IN->A; + while (IN) + { + + CurrentS= main_coffee_evaluate_output2(IN, CL, mode); + if (!TopS)LastS=TopS=CurrentS; + else + { + LastS->A=CurrentS; + LastS=CurrentS; + } + IN=IN->A; + } + return TopS; +} + +Alignment * main_coffee_evaluate_output2 ( Alignment *IN,Constraint_list *CL, const char *mode ) +{ + + /*Make sure evaluation functions update their cache if needed*/ + IN=update_aln_random_tag (IN); + + if ( CL->evaluate_residue_pair==evaluate_matrix_score || CL->ne==0 ||strm ( mode , "categories") || strm ( mode , "matrix")|| strm(mode, "sar")|| strstr (mode, "boxshade") ) + { + + if ( strm ( mode , "categories")) return categories_evaluate_output (IN, CL); + else if ( strm ( mode , "matrix"))return matrix_evaluate_output (IN, CL); + else if ( strm ( mode, "sar"))return sar_evaluate_output (IN, CL); + else if ( strstr ( mode, "boxshade"))return boxshade_evaluate_output (IN, CL, atoi (strstr(mode, "_")+1)); + + else if ( CL->evaluate_residue_pair==evaluate_matrix_score) return matrix_evaluate_output (IN, CL); + else if ( CL->ne==0) return matrix_evaluate_output (IN, CL); + } + else if ( strm (mode, "no"))return NULL; + else if ( strstr( mode, "triplet")) + { + return triplet_coffee_evaluate_output ( IN,CL); + } + else if ( strstr ( mode, "fast")) + { + return fast_coffee_evaluate_output ( IN,CL); + } + else if ( strstr ( mode, "slow")) + { + return slow_coffee_evaluate_output ( IN,CL); + } + + else if ( strstr ( mode, "non_extended")) + { + return non_extended_t_coffee_evaluate_output ( IN,CL); + } + + else if ( strm (mode, "sequences")) + { + return coffee_seq_evaluate_output ( IN,CL); + } + else + { + fprintf ( stderr, "\nUNKNOWN MODE FOR ALIGNMENT EVALUATION: *%s* [FATAL:%s]",mode, PROGRAM); + crash (""); + return NULL; + } + return IN; +} + + + +Alignment * coffee_evaluate_output ( Alignment *IN,Constraint_list *CL) + { + fprintf ( stderr, "\n[WARNING:%s]THE FUNCTION coffee_evaluate_output IS NOT ANYMORE SUPPORTED\n", PROGRAM); + fprintf ( stderr, "\n[WARNING]fast_coffee_evaluate_output WILL BE USED INSTEAD\n"); + + return fast_coffee_evaluate_output (IN,CL); + } +Alignment * matrix_evaluate_output ( Alignment *IN,Constraint_list *CL) + { + int a,b, c,r, s, r1, r2; + Alignment *OUT=NULL; + + double **tot_res; + double **max_res; + + double **tot_seq; + double **max_seq; + + double **tot_col; + double **max_col; + + double max_aln=0; + double tot_aln=0; + + + /* + Residue x: sum of observed extended X.. /sum of possible X.. + */ + + + if ( !CL->M)CL->M=read_matrice ("blosum62mt"); + + OUT=copy_aln (IN, OUT); + + + tot_res=declare_double ( IN->nseq, IN->len_aln); + max_res=declare_double ( IN->nseq, IN->len_aln); + + tot_seq=declare_double ( IN->nseq, 1); + max_seq=declare_double ( IN->nseq, 1); + tot_col=declare_double ( IN->len_aln,1); + max_col=declare_double ( IN->len_aln,1); + + max_aln=tot_aln=0; + + for (a=0; a< IN->len_aln; a++) + { + for ( b=0; b< IN->nseq; b++) + { + r1=tolower(IN->seq_al[b][a]); + if ( is_gap(r1))continue; + r= CL->M[r1-'A'][r1-'A']; + r= 1; + for ( c=0; cnseq; c++) + { + r2=tolower(IN->seq_al[c][a]); + if (b==c || is_gap (r2))continue; + + s=CL->M[r2-'A'][r1-'A']; + s=(s<=0)?0:1; + + tot_res[b][a]+=s; + max_res[b][a]+=r; + + tot_col[a][0]+=s; + max_col[a][0]+=r; + + tot_seq[b][0]+=s; + max_seq[b][0]+=r; + + tot_aln+=s; + max_aln+=r; + } + } + } + + + for ( a=0; a< IN->nseq; a++) + { + if ( !max_seq[a][0])continue; + + OUT->score_seq[a]=(tot_seq[a][0]*100)/max_seq[a][0]; + for (b=0; b< IN->len_aln; b++) + { + r1=IN->seq_al[a][b]; + if ( is_gap(r1) || !max_res[a][b])continue; + + r1=(tot_res[a][b]*10)/max_res[a][b]; + r1=(r1>=10)?9:r1; + r1=r1<0?0:r1; + (OUT)->seq_al[a][b]=r1+'0'; + } + } + + for ( a=0; a< IN->len_aln; a++) + { + r1=(max_col[a][0]==0)?0:((tot_col[a][0]*10)/max_col[a][0]); + r1=(r1>=10)?9:r1; + (OUT)->seq_al[OUT->nseq][a]=r1+'0'; + } + sprintf ( OUT->name[IN->nseq], "cons"); + if (max_aln)OUT->score_seq[OUT->nseq]=OUT->score_aln=(100*tot_aln)/max_aln; + + + free_double (tot_res,-1); + free_double (max_res,-1); + + free_double (tot_seq,-1); + free_double (max_seq,-1); + + return OUT; + } + +Alignment * sar_evaluate_output ( Alignment *IN,Constraint_list *CL) + { + int a,b, c,r, s, r1, r2; + Alignment *OUT=NULL; + + double **tot_res; + double **max_res; + + double **tot_seq; + double **max_seq; + + double **tot_col; + double **max_col; + + double max_aln=0; + double tot_aln=0; + + + /* + Residue x: sum of observed extended X.. /sum of possible X.. + */ + + + if ( !CL->M)CL->M=read_matrice ("blosum62mt"); + + OUT=copy_aln (IN, OUT); + + + tot_res=declare_double ( IN->nseq, IN->len_aln); + max_res=declare_double ( IN->nseq, IN->len_aln); + + tot_seq=declare_double ( IN->nseq, 1); + max_seq=declare_double ( IN->nseq, 1); + tot_col=declare_double ( IN->len_aln,1); + max_col=declare_double ( IN->len_aln,1); + + max_aln=tot_aln=0; + + for (a=0; a< IN->len_aln; a++) + { + for (b=0; b< IN->nseq; b++) + { + r1=tolower(IN->seq_al[b][a]); + for (c=0; cnseq; c++) + { + r2=tolower(IN->seq_al[c][a]); + if (b==c)continue; + + if ( is_gap(r1) && is_gap(r2))s=0; + else s=(r1==r2)?1:0; + + r=1; + + + tot_res[b][a]+=s; + max_res[b][a]+=r; + + tot_col[a][0]+=s; + max_col[a][0]+=r; + + tot_seq[b][0]+=s; + max_seq[b][0]+=r; + + tot_aln+=s; + max_aln+=r; + } + } + } + + for ( a=0; a< IN->nseq; a++) + { + if ( !max_seq[a][0])continue; + OUT->score_seq[a]=(max_seq[a][0]*100)/max_seq[a][0]; + for (b=0; b< IN->len_aln; b++) + { + r1=IN->seq_al[a][b]; + if ( is_gap(r1) || !max_res[a][b])continue; + r1=(tot_res[a][b]*10)/max_res[a][b]; + r1=(r1>=10)?9:r1; + r1=r1<0?0:r1; + (OUT)->seq_al[a][b]=r1+'0'; + } + } + + for ( a=0; a< IN->len_aln; a++) + { + r1=(max_col[a][0]==0)?0:((tot_col[a][0]*10)/max_col[a][0]); + r1=(r1>=10)?9:r1; + (OUT)->seq_al[OUT->nseq][a]=r1+'0'; + } + sprintf ( OUT->name[IN->nseq], "cons"); + if (max_aln)OUT->score_aln=(100*tot_aln)/max_aln; + + + free_double (tot_res,-1); + free_double (max_res,-1); + + free_double (tot_seq,-1); + free_double (max_seq,-1); + + return OUT; + } +Alignment * boxshade_evaluate_output ( Alignment *IN,Constraint_list *CL, int T) + { + Alignment *OUT=NULL; + int **aa; + int r,br, bs, a, b; + float f; + + + /* + Residue x: sum of observed extended X.. /sum of possible X.. + */ + + + OUT=copy_aln (IN, OUT); + aa=declare_int (26, 2); + + for ( a=0; a< OUT->len_aln; a++) + { + for ( b=0; b< 26; b++){aa[b][1]=0;aa[b][0]='a'+b;} + for ( b=0; b< OUT->nseq; b++) + { + r=tolower(OUT->seq_al[b][a]); + if ( !is_gap(r))aa[r-'a'][1]++; + } + sort_int ( aa, 2, 1, 0,25); + f=(aa[25][1]*100)/OUT->nseq; + + if (fnseq; b++) + { + r=tolower(OUT->seq_al[b][a]); + if (r==br && bs>'1')OUT->seq_al[b][a]=bs; + } + OUT->seq_al[b][a]=bs; + } + } + sprintf ( OUT->name[IN->nseq], "cons"); + + return OUT; + } + +Alignment * categories_evaluate_output ( Alignment *IN,Constraint_list *CL) + { + + Alignment *OUT=NULL; + int a, b, r; + int *aa; + float score, nseq2, tot_aln; + float n; + /* + Residue x: sum of observed extended X.. /sum of possible X.. + */ + OUT=copy_aln (IN, OUT); + aa=vcalloc ( 26, sizeof (int)); + nseq2=IN->nseq*IN->nseq; + + for (tot_aln=0, a=0; a< IN->len_aln; a++) + { + for (n=0,b=0; b< IN->nseq; b++) + { + r=IN->seq_al[b][a]; + + if ( is_gap(r))n++; + else + { + aa[tolower(r)-'a']++; + n++; + } + } + n=n*n; + for ( score=0,b=0; b< 26; b++){score+=aa[b]*aa[b];aa[b]=0;} + /*score/=nseq2;*/ + score=(n==0)?0:score/n; + tot_aln+=score; + r=score*10; + r=(r>=10)?9:r; + (OUT)->seq_al[OUT->nseq][a]='0'+r; + } + OUT->score_aln=(tot_aln/OUT->len_aln)*100; + sprintf ( OUT->name[IN->nseq], "cons"); + vfree(aa); + return OUT; + } + +Alignment * categories_evaluate_output_old ( Alignment *IN,Constraint_list *CL) + { + + Alignment *OUT=NULL; + int nc,a, b, r; + int *aa, ng; + float score, nseq2, tot_aln, min=0; + + /* + Residue x: sum of observed extended X.. /sum of possible X.. + */ + OUT=copy_aln (IN, OUT); + aa=vcalloc ( 26, sizeof (int)); + nseq2=IN->nseq*IN->nseq; + + for (tot_aln=0, a=0; a< IN->len_aln; a++) + { + for (ng=0,b=0; b< IN->nseq; b++) + { + r=IN->seq_al[b][a]; + + if ( is_gap(r))ng++; + else + { + aa[tolower(r)-'a']++; + } + } + for (nc=0, b=0; b<26; b++) + { + if ( aa[b])nc++; + aa[b]=0; + } + if (nc>9)score=0; + else score=9-nc; + + score=(2*min)/IN->nseq; + + tot_aln+=score; + r=score*10; + r=(r>=10)?9:r; + (OUT)->seq_al[OUT->nseq][a]='0'+r; + } + + OUT->score_aln=(tot_aln/OUT->len_aln)*100; + sprintf ( OUT->name[IN->nseq], "cons"); + vfree(aa); + return OUT; + } +Alignment * fork_triplet_coffee_evaluate_output ( Alignment *IN,Constraint_list *CL); +Alignment * nfork_triplet_coffee_evaluate_output ( Alignment *IN,Constraint_list *CL); +Alignment * triplet_coffee_evaluate_output ( Alignment *IN,Constraint_list *CL) +{ + + if (!IN || !CL || !CL->residue_index) return IN; + + + if ( get_nproc()==1)return nfork_triplet_coffee_evaluate_output (IN,CL); + else if (strstr ( CL->multi_thread, "evaluate"))return fork_triplet_coffee_evaluate_output (IN,CL); + else return nfork_triplet_coffee_evaluate_output (IN,CL); +} +Alignment * fork_triplet_coffee_evaluate_output ( Alignment *IN,Constraint_list *CL) + { + Alignment *OUT=NULL; + int **pos; + + double score_col=0, score_aln=0, score_res=0, score=0; + double max_col=0, max_aln=0, max_res=0; + double *max_seq, *score_seq; + + int a,b, x, y,res; + int s1,r1,s2,r2,w2,s3,r3,w3; + int **lu; + + //multi-threading + FILE *fp; + char **pid_tmpfile; + int sjobs, njobs; + int **sl; + int j; + + OUT=copy_aln (IN, OUT); + pos=aln2pos_simple(IN, IN->nseq); + sprintf ( OUT->name[IN->nseq], "cons"); + + max_seq=vcalloc ( IN->nseq, sizeof (double)); + score_seq=vcalloc ( IN->nseq, sizeof (double)); + lu=declare_int (IN->nseq, IN->len_aln+1); + + //multi Threading stuff + njobs=get_nproc(); + sl=n2splits (njobs,IN->len_aln); + pid_tmpfile=vcalloc (njobs, sizeof (char*)); + + for (sjobs=0,j=0; sjobsnseq; b++) + { + s1=IN->order[b][0]; + r1=pos[b][a]; + if (r1>=0)lu[s1][r1]=1; + } + for (b=0; bnseq; b++) + { + score_res=max_res=NORM_F; + res=NO_COLOR_RESIDUE; + s1=IN->order[b][0]; + r1=pos[b][a]; + if (r1<=0) + { + fprintf (fp, "%d ", res); + continue; + } + + for (x=1;xresidue_index[s1][r1][0];x+=ICHUNK) + { + s2=CL->residue_index[s1][r1][x+SEQ2]; + r2=CL->residue_index[s1][r1][x+R2]; + w2=CL->residue_index[s1][r1][x+WE]; + for (y=1; yresidue_index[s2][r2][0];y+=ICHUNK) + { + s3=CL->residue_index[s2][r2][y+SEQ2]; + r3=CL->residue_index[s2][r2][y+R2]; + w3=CL->residue_index[s2][r2][y+WE]; + + score=MIN(w2,w3); + + max_res+=score; + max_col+=score; + max_seq[b]+=score; + max_aln+=score; + + if (lu[s3][r3]) + { + score_res+=score; + score_col+=score; + score_seq[b]+=score; + score_aln+=score; + } + } + } + res=(max_res==0)?NO_COLOR_RESIDUE:((score_res*10)/max_res); + res=(res==NO_COLOR_RESIDUE)?res:(MIN(res,9)); + fprintf ( fp, "%d ", res); + } + for (b=0; bnseq; b++) + { + s1=IN->order[b][0]; + r1=pos[b][a]; + if (r1>0)lu[s1][r1]=0; + } + + res=(max_col==0)?NO_COLOR_RESIDUE:((score_col*10)/max_col); + res=(res==NO_COLOR_RESIDUE)?res:(MIN(res,9)); + fprintf (fp, "%d ", res); + for (b=0; bnseq; b++)fprintf (fp, "%f %f ", score_seq[b], max_seq[b]); + } + fprintf (fp, "%f %f ", score_aln, max_aln); + vfclose (fp); + myexit (EXIT_SUCCESS); + } + else + { + sjobs++; + } + } + + while (sjobs>=0){vwait(NULL); sjobs--;}//wait for all jobs to complete + + for (j=0; jnseq; b++)//don't forget the consensus + { + fscanf (fp, "%d ", &res); + OUT->seq_al[b][a]=res; + } + for (b=0; bnseq; b++) + { + fscanf (fp, "%f %f", &sseq, &mseq); + score_seq[b]+=sseq; + max_seq[b]+=mseq; + } + } + fscanf (fp, "%f %f", &sseq, &mseq); + score_aln+=sseq; + max_aln+=mseq; + vfclose (fp); + remove (pid_tmpfile[j]); + } + fprintf ( stderr, "\n"); + + IN->score_aln=OUT->score_aln=(max_aln==0)?0:((score_aln*100)/max_aln); + for ( a=0; a< OUT->nseq; a++) + { + OUT->score_seq[a]=(max_seq[a]==0)?0:((score_seq[a]*100)/max_seq[a]); + } + + free_int (lu,-1); + free_int (pos , -1); + vfree (pid_tmpfile); + free_int (sl, -1); + vfree ( score_seq); + vfree ( max_seq); + return OUT; + } + +Alignment * nfork_triplet_coffee_evaluate_output ( Alignment *IN,Constraint_list *CL) + { + Alignment *OUT=NULL; + int **pos; + + double score_col=0, score_aln=0, score_res=0, score=0; + double max_col=0, max_aln=0, max_res=0; + double *max_seq, *score_seq; + + int a,b, x, y,res; + int s1,r1,s2,r2,w2,s3,r3,w3; + int **lu; + + + + OUT=copy_aln (IN, OUT); + pos=aln2pos_simple(IN, IN->nseq); + sprintf ( OUT->name[IN->nseq], "cons"); + + max_seq=vcalloc ( IN->nseq, sizeof (double)); + score_seq=vcalloc ( IN->nseq, sizeof (double)); + lu=declare_int (IN->nseq, IN->len_aln+1); + + + + + score_aln=max_aln=0; + for (a=0; alen_aln; a++) + { + output_completion (stderr,a,IN->len_aln,1, "Final Evaluation"); + score_col=max_col=0; + for (b=0; bnseq; b++) + { + s1=IN->order[b][0]; + r1=pos[b][a]; + if (r1>=0)lu[s1][r1]=1; + } + for (b=0; bnseq; b++) + { + score_res=max_res=NORM_F; + OUT->seq_al[b][a]=NO_COLOR_RESIDUE; + s1=IN->order[b][0]; + r1=pos[b][a]; + if (r1<=0)continue; + for (x=1;xresidue_index[s1][r1][0];x+=ICHUNK) + { + s2=CL->residue_index[s1][r1][x+SEQ2]; + r2=CL->residue_index[s1][r1][x+R2]; + w2=CL->residue_index[s1][r1][x+WE]; + for (y=1; yresidue_index[s2][r2][0];y+=ICHUNK) + { + s3=CL->residue_index[s2][r2][y+SEQ2]; + r3=CL->residue_index[s2][r2][y+R2]; + w3=CL->residue_index[s2][r2][y+WE]; + + score=MIN(w2,w3); + + max_res+=score; + max_col+=score; + max_seq[b]+=score; + max_aln+=score; + + if (lu[s3][r3]) + { + score_res+=score; + score_col+=score; + score_seq[b]+=score; + score_aln+=score; + } + } + } + res=(max_res==0)?NO_COLOR_RESIDUE:((score_res*10)/max_res); + res=(res==NO_COLOR_RESIDUE)?res:(MIN(res,9)); + OUT->seq_al[b][a]=res; + } + for (b=0; bnseq; b++) + { + s1=IN->order[b][0]; + r1=pos[b][a]; + if (r1>0)lu[s1][r1]=0; + } + + res=(max_col==0)?NO_COLOR_RESIDUE:((score_col*10)/max_col); + res=(res==NO_COLOR_RESIDUE)?res:(MIN(res,9)); + OUT->seq_al[IN->nseq][a]=res; + } + fprintf ( stderr, "\n"); + + IN->score_aln=OUT->score_aln=(max_aln==0)?0:((score_aln*100)/max_aln); + for ( a=0; a< OUT->nseq; a++) + { + OUT->score_seq[a]=(max_seq[a]==0)?0:((score_seq[a]*100)/max_seq[a]); + } + + free_int (lu,-1); + free_int (pos , -1); + vfree ( score_seq); + vfree ( max_seq); + return OUT; + } +Alignment * fast_coffee_evaluate_output ( Alignment *IN,Constraint_list *CL) + { + int a,b, c, m,res, s, s1, s2, r1, r2; + Alignment *OUT=NULL; + int **pos, **pos2; + + double score_col=0, score_aln=0, score_res=0; + double max_col, max_aln; + double *max_seq, *score_seq; + int local_m; + int local_nseq; + + + /*NORMALIZE: with the highest scoring pair found in the multiple alignment*/ + + + if ( !CL->evaluate_residue_pair){fprintf ( stderr, "\nWARNING: CL->evaluate_residue_pair Not set\nSet to: extend_residue_pair\n");CL->evaluate_residue_pair= extend_residue_pair; } + + OUT=copy_aln (IN, OUT); + pos=aln2pos_simple(IN, IN->nseq); + pos2=aln2defined_residues (IN, CL); + + max_seq=vcalloc ( IN->nseq, sizeof (double)); + score_seq=vcalloc ( IN->nseq, sizeof (double)); + + + + /*1: Identify the highest scoring pair within the alignment*/ + + for ( m=0, a=0; a< IN->len_aln; a++) + { + for ( b=0; b< IN->nseq; b++) + { + s1=IN->order[b][0]; + r1=pos[b][a]; + + + for ( c=0; c< IN->nseq; c++) + { + s2=IN->order[c][0]; + r2=pos[c][a]; + if ( s1==s2 && !CL->do_self)continue; + + if ( s1< s2)s=(CL->evaluate_residue_pair)( CL, s1, r1, s2, r2); + else s=(CL->evaluate_residue_pair)( CL, s2, r2, s1, r1); + + s=(s!=UNDEFINED)?s:0; + m=MAX(m, s); + } + } + } + + local_m=m; + + sprintf ( OUT->name[IN->nseq], "cons"); + for ( max_aln=0,score_aln=0,a=0; a< IN->len_aln; a++) + { + OUT->seq_al[IN->nseq][a]=NO_COLOR_RESIDUE; + for ( local_nseq=0,b=0; bnseq; b++){local_nseq+=(pos[b][a]>0 && pos2[b][a])?1:0;} + local_m=m*(local_nseq-1); + + for ( max_col=0, score_col=0,b=0; b< IN->nseq; b++) + { + OUT->seq_al[b][a]=NO_COLOR_RESIDUE; + s1=IN->order[b][0]; + r1=pos[b][a]; + + if (r1<=0 || !pos2[b][a]) + { + continue; + } + + for ( score_res=0,c=0; c< IN->nseq; c++) + { + s2=IN->order[c][0]; + r2=pos[c][a]; + + if ((s1==s2 && !CL->do_self) || r2<=0 || !pos2[c][a]){continue;} + max_col +=m; + max_seq[b]+=m; + max_aln +=m; + + if ( s1< s2)s=(CL->evaluate_residue_pair)( CL, s1, r1, s2, r2); + else s=(CL->evaluate_residue_pair)( CL, s2, r2, s1, r1); + s=(s!=UNDEFINED)?s:0; + + score_res+=s; + score_col+=s; + score_seq[b]+=s; + score_aln+=s; + } + + res=(local_m==0)?NO_COLOR_RESIDUE:((score_res*10)/local_m); + (OUT)->seq_al[b][a]=(res==NO_COLOR_RESIDUE)?res:(MIN(res,9)); + + + } + + res=(max_col==0)?NO_COLOR_RESIDUE:((score_col*10)/max_col); + OUT->seq_al[IN->nseq][a]=(res==NO_COLOR_RESIDUE)?res:(MIN(res,9)); + + } + + IN->score_aln=OUT->score_aln=(max_aln==0)?0:((score_aln*100)/max_aln); + for ( a=0; a< OUT->nseq; a++) + { + OUT->score_seq[a]=(max_seq[a]==0)?0:((score_seq[a]*100)/max_seq[a]); + } + + free_int (pos , -1); + free_int (pos2, -1); + + vfree ( score_seq); + vfree ( max_seq); + return OUT; + } + +Alignment * slow_coffee_evaluate_output ( Alignment *IN,Constraint_list *CL) + { + int a,b, c,res, s, s1, s2, r1, r2; + Alignment *OUT=NULL; + int **pos, **pos2; + double max_score_r, score_r, max; + double score_col=0, score_aln=0; + double max_score_col, max_score_aln; + double *max_score_seq, *score_seq; + int ***res_extended_weight; + int n_res_in_col; + + + /* + Residue x: sum of observed extended X.. /sum of possible X.. + */ + + + + + if ( !CL->evaluate_residue_pair){fprintf ( stderr, "\nWARNING: CL->evaluate_residue_pair Not set\nSet to: extend_residue_pair\n");CL->evaluate_residue_pair= extend_residue_pair; } + + + OUT=copy_aln (IN, OUT); + pos=aln2pos_simple(IN, IN->nseq); + pos2=aln2defined_residues (IN, CL); + + max_score_seq=vcalloc ( IN->nseq, sizeof (double)); + score_seq=vcalloc ( IN->nseq, sizeof (double)); + res_extended_weight=declare_arrayN(3,sizeof(int), (CL->S)->nseq, (CL->S)->max_len+1, 2); + max=(CL->normalise)?(100*CL->normalise)*SCORE_K:100; + + for (a=0; a< IN->len_aln; a++) + { + for ( b=0; b< IN->nseq-1; b++) + { + s1=IN->order[b][0]; + r1=pos[b][a]; + for ( c=b+1; c< IN->nseq; c++) + { + s2=IN->order[c][0]; + r2=pos[c][a]; + if ( s1==s2 && !CL->do_self)continue; + else if ( r1<=0 || r2<=0) continue; + else + { + s=(CL->evaluate_residue_pair)( CL, s1, r1, s2, r2); + res_extended_weight[s1][r1][0]+=s*100; + res_extended_weight[s2][r2][0]+=s*100; + res_extended_weight[s1][r1][1]+=max; + res_extended_weight[s2][r2][1]+=max; + } + } + } + } + + + sprintf ( OUT->name[IN->nseq], "cons"); + for ( max_score_aln=0,score_aln=0,a=0; a< IN->len_aln; a++) + { + OUT->seq_al[IN->nseq][a]=NO_COLOR_RESIDUE; + for ( n_res_in_col=0,b=0; bnseq; b++){n_res_in_col+=(pos[b][a]>0 && pos2[b][a]>0)?1:0;} + for ( max_score_col=0, score_col=0,b=0; b< IN->nseq; b++) + { + OUT->seq_al[b][a]=NO_COLOR_RESIDUE; + s1=IN->order[b][0]; + r1=pos[b][a]; + if (r1<=0 || pos2[b][a]<1)continue; + else + { + max_score_r =res_extended_weight[s1][r1][1]; + score_r =res_extended_weight[s1][r1][0]; + if ( max_score_r==0 && n_res_in_col>1)res=0; + else if ( n_res_in_col==1)res=NO_COLOR_RESIDUE; + else res=((score_r*10)/max_score_r); + + + (OUT)->seq_al[b][a]=(res==NO_COLOR_RESIDUE)?res:(MIN(res, 9)); + max_score_col+=max_score_r; + score_col+=score_r; + max_score_seq[b]+=max_score_r; + score_seq[b]+=score_r; + max_score_aln+=max_score_r; + score_aln+=score_r; + } + if ( max_score_col==0 && n_res_in_col>1)res=0; + else if ( n_res_in_col<2)res=NO_COLOR_RESIDUE; + else res=((score_col*10)/max_score_col); + + OUT->seq_al[IN->nseq][a]=(res==NO_COLOR_RESIDUE)?res:(MIN(res,9)); + } + } + IN->score_aln=OUT->score_aln=(max_score_aln==0)?0:((score_aln*100)/max_score_aln); + for ( a=0; a< OUT->nseq; a++) + { + OUT->score_seq[a]=(max_score_seq[a]==0)?0:((score_seq[a]*100)/max_score_seq[a]); + } + + + vfree ( score_seq); + vfree ( max_score_seq); + free_arrayN((void*)res_extended_weight, 3); + + + free_int (pos, -1); + free_int (pos2, -1); + return OUT; + } + +double genepred2sd (Sequence *S); +double genepred2avg (Sequence *S); +double genepred2zsum2 (Sequence *S); +int * genepred2orf_len (Sequence *S); +double genepred2acc (Sequence *S, Sequence *PS); +double seq_genepred2acc (Sequence *S, Sequence *PS, char *name); +Alignment *coffee_seq_evaluate_output ( Alignment *IN, Constraint_list *CL) +{ + int **w, a,b,c,l,i; + int avg, min_avg, best_cycle; + char **pred_list,**weight_list; + FILE *fp; + Sequence *S, *PS; + int ncycle=20; + float nsd, best_score,score, acc; + int min_ne; + Alignment *A; + float *count; + min_ne=CL->ne/10; //avoid side effects due to very relaxed libraries + w=NULL; + pred_list=declare_char (ncycle, 100); + weight_list=declare_char(ncycle,100); + S=CL->S; + fprintf ( stderr, "\nSCORE_MODE: %s\n", CL->genepred_score); + for (a=0; ane>min_ne; a++) + { + if (w);free_int (w, -1); + w=list2residue_total_weight (CL); + PS=dnaseq2geneseq (S, w); + nsd=(float)(genepred2sd(PS)/genepred2avg(PS)); + if ( strm (CL->genepred_score, "nsd"))score=nsd; + else score=1-seq_genepred2acc (S, PS, CL->genepred_score); + fprintf ( stderr, "Cycle: %2d LIB: %6d AVG LENGTH: %6.2f NSD: %8.2f SCORE: %.2f ",a+1,CL->ne,(float) genepred2avg(PS),nsd,score); + + vfree (display_accuracy (genepred_seq2accuracy_counts (S, PS, NULL),stderr)); + pred_list[a]=vtmpnam(NULL); + weight_list[a]=vtmpnam(NULL); + output_fasta_seqS(pred_list[a],PS); + output_array_int (weight_list[a],w); + free_sequence (PS, -1); + + if (a==0 || score ", best_cycle+1, best_score); + vfree (display_accuracy (genepred_seq2accuracy_counts ((CL->S), S, NULL),stderr)); + + genepred_seq2accuracy_counts4all((CL->S), S); + + IN=seq2aln (S,NULL, 1); + IN->score_res=input_array_int (weight_list[best_cycle]); + return IN; +} + +double seq_genepred2acc (Sequence *S, Sequence *PS, char *name) +{ + float *count; + float *acc; + float r; + int ref, target; + + if ( strm (name, "best"))return genepred2acc (S, PS); + + ref=name_is_in_list (name, S->name, S->nseq, 100); + target=name_is_in_list (name, PS->name, PS->nseq, 100); + + if ( target==-1 || ref==-1) + { + printf_exit (EXIT_FAILURE,stderr, "\nERROR: %s is not a valid sequence", name); + } + count=genepred2accuracy_counts (S->seq[ref],PS->seq[target],NULL); + acc=counts2accuracy (count); + + r=acc[3]; + vfree (acc); + vfree (count); + return r; +} + + + +double genepred2acc (Sequence *S, Sequence *PS) +{ + float *count; + float *acc; + float r; + count=genepred_seq2accuracy_counts (S, PS, NULL); + acc=counts2accuracy (count); + + r=acc[3]; + vfree (acc); + vfree (count); + return r; +} + +double genepred2sd (Sequence *S) +{ + double sum=0, sum2=0; + int a, b; + int *len; + len=genepred2orf_len (S); + + for (a=0; anseq; a++) + { + sum+=(double)len[a]; + sum2+=(double)len[a]*(double)len[a]; + } + sum/=(double)S->nseq; + sum2/=S->nseq; + vfree (len); + return sqrt (sum2-(sum*sum)); +} +double genepred2avg (Sequence *S) +{ + int a, b; + double avg=0; + int *len; + len=genepred2orf_len (S); + + for (a=0; anseq; a++)avg+=len[a]; + vfree (len); + return avg/(double)S->nseq; +} +double genepred2zsum2 (Sequence *S) +{ + double sum=0, sum2=0, zscore=0, zsum2=0; + int a, b; + int *len; + double sd, avg; + sd=genepred2sd(S); + avg=genepred2avg (S); + + len=genepred2orf_len (S); + for (a=0; anseq; a++) + { + zscore=((double)len[a]-avg)/sd; + zsum2+=FABS(zscore); + } + zsum2/=(float)S->nseq; + vfree (len); + return zsum2; +} +int *genepred2orf_len (Sequence *S) +{ + int a,b, *len; + len=vcalloc (S->nseq, sizeof (int)); + for (a=0; anseq; a++) + for (b=0; blen[a]; b++) + len[a]+=(isupper(S->seq[a][b])); + return len; +} + +Alignment *coffee_seq_evaluate_output_old2 ( Alignment *IN, Constraint_list *CL) +{ + int **w, a,b,c,l,i; + int avg, min_avg, best_cycle; + char **pred_list; FILE *fp; + Sequence *S, *PS; + int ncycle=100; + w=NULL; + pred_list=declare_char (ncycle, 100); + S=CL->S; + + //CL=expand_constraint_list_4gp(CL); + min_avg=constraint_list2avg(CL); + + for (a=1; ane>0; a++) + { + int t; + if (w);free_int (w, -1); + w=list2residue_total_weight (CL); + CL=relax_constraint_list_4gp (CL); + fprintf (stderr,"\nRELAX CYCLE: %2d AVG: %5d [%10d] ", a, avg=constraint_list2avg(CL), CL->ne); + for (b=0; bnseq; b++)for (c=0; clen[b]; c++)w[b][c]-=1; + + //rescale nuclotide coding weights + + PS=dnaseq2geneseq (S, w); + vfree (display_accuracy (genepred_seq2accuracy_counts (S, PS, NULL),stderr)); + + + free_sequence (PS, PS->nseq); + if ( avgS), S, NULL),stderr));myexit (0); + for (a=0; anseq; a++) + HERE (">%s\n%s", S->name[a], S->seq[a]); + myexit (0); + return seq2aln (S,NULL, 1); +} + + + +Alignment * non_extended_t_coffee_evaluate_output ( Alignment *IN,Constraint_list *CL) + { + int a,b, c,res, s1, s2, r1, r2; + Alignment *OUT=NULL; + int **pos; + int max_score_r, score_r; + double score_col=0, score_aln=0; + int max_score_col, max_score_aln; + double *max_score_seq, *score_seq; + int local_nseq; + int **tot_non_extended_weight; + int **res_non_extended_weight; + int *l; + CLIST_TYPE *entry=NULL; + int p; + int max_score=0; + + entry=vcalloc (CL->entry_len+1, CL->el_size); + if ( !CL->evaluate_residue_pair){fprintf ( stderr, "\nWARNING: CL->evaluate_residue_pair Not set\nSet to: extend_residue_pair\n");CL->evaluate_residue_pair= extend_residue_pair; } + + OUT=copy_aln (IN, OUT); + pos=aln2pos_simple(IN, IN->nseq); + + + max_score_seq=vcalloc ( IN->nseq, sizeof (double)); + score_seq=vcalloc ( IN->nseq, sizeof (double)); + + tot_non_extended_weight=list2residue_total_weight(CL); + res_non_extended_weight=declare_int ((CL->S)->nseq, (CL->S)->max_len+1); + + for (a=0; a< IN->len_aln; a++) + { + for ( b=0; b< IN->nseq-1; b++) + { + s1=IN->order[b][0]; + r1=pos[b][a]; + for ( c=b+1; c< IN->nseq; c++) + { + s2=IN->order[c][0]; + r2=pos[c][a]; + if ( s1==s2 && !CL->do_self)continue; + else if ( r1<=0 || r2<=0) continue; + else + { + entry[SEQ1]=s1; + entry[SEQ2]=s2; + entry[R1]=r1; + entry[R2]=r2; + if ((l=main_search_in_list_constraint (entry,&p,4,CL))!=NULL) + { + res_non_extended_weight[s1][r1]+=l[WE]; + res_non_extended_weight[s2][r2]+=l[WE]; + } + entry[SEQ1]=s2; + entry[SEQ2]=s1; + entry[R1]=r2; + entry[R2]=r1; + if ((l=main_search_in_list_constraint (entry,&p,4,CL))!=NULL) + { + res_non_extended_weight[s1][r1]+=l[WE]; + res_non_extended_weight[s2][r2]+=l[WE]; + } + max_score=MAX(max_score,res_non_extended_weight[s1][r1]); + max_score=MAX(max_score,res_non_extended_weight[s2][r2]); + + } + } + } + } + + sprintf ( OUT->name[IN->nseq], "cons"); + for ( max_score_aln=0,score_aln=0,a=0; a< IN->len_aln; a++) + { + OUT->seq_al[IN->nseq][a]=NO_COLOR_RESIDUE; + for ( local_nseq=0,b=0; bnseq; b++){local_nseq+=(pos[b][a]>0)?1:0;} + + for ( max_score_col=0, score_col=0,b=0; b< IN->nseq; b++) + { + OUT->seq_al[b][a]=NO_COLOR_RESIDUE; + s1=IN->order[b][0]; + r1=pos[b][a]; + if (r1<=0)continue; + else + { + max_score_r =max_score;/*tot_non_extended_weight[s1][r1];*/ + score_r=res_non_extended_weight[s1][r1]; + res=(max_score_r==0 || local_nseq<2 )?NO_COLOR_RESIDUE:((score_r*10)/max_score_r); + + (OUT)->seq_al[b][a]=(res==NO_COLOR_RESIDUE)?res:(MIN(res, 9)); + max_score_col+=max_score_r; + score_col+=score_r; + max_score_seq[b]+=max_score_r; + score_seq[b]+=score_r; + max_score_aln+=max_score_r; + score_aln+=score_r; + } + res=(max_score_col==0 || local_nseq<2)?NO_COLOR_RESIDUE:((score_col*10)/max_score_col); + OUT->seq_al[IN->nseq][a]=(res==NO_COLOR_RESIDUE)?res:(MIN(res,9)); + } + } + IN->score_aln=OUT->score_aln=(max_score_aln==0)?0:((score_aln*100)/max_score_aln); + for ( a=0; a< OUT->nseq; a++) + { + OUT->score_seq[a]=(max_score_seq[a]==0)?0:((score_seq[a]*100)/max_score_seq[a]); + OUT->score_seq[a]=(OUT->score_seq[a]>100)?100:OUT->score_seq[a]; + } + OUT->score_aln=(OUT->score_aln>100)?100:OUT->score_aln; + + vfree ( score_seq); + vfree ( max_score_seq); + + free_int (tot_non_extended_weight, -1); + free_int (res_non_extended_weight, -1); + vfree(entry); + free_int (pos, -1); + + return OUT; + } + + +/*********************************************************************************************/ +/* */ +/* PROFILE/PRofile Functions */ +/* */ +/*********************************************************************************************/ +int channel_profile_profile (int *prf1, int *prf2, Constraint_list *CL); + +Profile_cost_func get_profile_mode_function (char *name, Profile_cost_func func) +{ + int a; + static int nfunc; + static Profile_cost_func *flist; + static char **nlist; + + + + /*The first time: initialize the list of pairwse functions*/ + /*If func==NULL:REturns a pointer to the function associated with a name*/ + /*If name is empty:Prints the name of the function associated with name*/ + + if ( nfunc==0) + { + flist=vcalloc ( 100, sizeof (Pwfunc)); + nlist=declare_char (100, 100); + + flist[nfunc]=cw_profile_profile; + sprintf (nlist[nfunc], "cw_profile_profile"); + nfunc++; + + flist[nfunc]=muscle_profile_profile; + sprintf (nlist[nfunc], "muscle_profile_profile"); + nfunc++; + + flist[nfunc]=channel_profile_profile; + sprintf (nlist[nfunc], "channel_profile_profile"); + nfunc++; + } + + for ( a=0; a0 && r2>0) + { + r1--; + r2--; + + prf1=(Profile1)?(Profile1->P)->count2[r1]:NULL; + prf2=(Profile2)?(Profile2->P)->count2[r2]:NULL; + + if (!prf1) {prf1=dummy; prf1[3]=(CL->S)->seq[s1][r1];} + else if (!prf2){prf2=dummy; prf2[3]=(CL->S)->seq[s2][r2];} + + score=((prf_prf==NULL)?cw_profile_profile:prf_prf) (prf1, prf2, CL); + return score; + } + else + return 0; + } + +int cw_profile_profile_count (int *prf1, int *prf2, Constraint_list *CL) + { + /*see function aln2count2 for prf structure*/ + int a, b, n; + int res1, res2; + double score=0; + + + for ( n=0,a=3; aM[res1-'A'][res2-'A']; + n+=prf1[a+1]*prf2[b+1]; + } + + + score=(score*SCORE_K)/n; + return score; + } +int muscle_profile_profile (int *prf1, int *prf2, Constraint_list *CL) + { + /*see function aln2count2 for prf structure*/ + int a, b; + int res1, res2; + double score=0, fg1, fg2, fi, fj, m; + static double *exp_lu; + if (exp_lu==NULL) + { + exp_lu=vcalloc ( 10000, sizeof (double)); + exp_lu+=2000; + for ( a=-1000; a<1000; a++) + exp_lu[a]=exp((double)a); + } + + + + for (a=3; aM[res1-'A'][res2-'A']);*/ + m=exp_lu[CL->M[res1-'A'][res2-'A']]; + score+=m*fi*fj; + } + } + + fg1=(double)prf1[2]/100; + fg2=(double)prf2[2]/100; + score=(score==0)?0:log(score)*(1-fg1)*(1-fg2); + score=(score*SCORE_K); + /*if ( score<-100)fprintf ( stderr, "\nSCORE %d %d", (int)score, cw_profile_profile(prf1, prf2, CL));*/ + + return (int)score; + } +int cw_profile_profile (int *prf1, int *prf2, Constraint_list *CL) + { + /*see function aln2count2 for prf structure*/ + int a, b, n,p; + int res1, res2; + double score=0; + + + for ( n=0,a=3; aM[res1-'A'][res2-'A']; + } + score=(score*SCORE_K)/((double)(n==0)?1:n); + return score; + } +int cw_profile_profile_old (int *prf1, int *prf2, Constraint_list *CL) + { + /*see function aln2count2 for prf structure*/ + int a, b, n,p; + int res1, res2; + double score=0; + + + + for ( n=0,a=3; aM[res1-'A'][res2-'A']; + } + score=(score*SCORE_K)/((double)(n==0)?1:n); + return score; + } +int channel_profile_profile ( int *prf1, int *prf2, Constraint_list *CL) +{ + + int score=0; + + prf1+=prf1[1]; + prf2+=prf2[1]; + + + if (prf1[0]!=prf1[0]){fprintf ( stderr, "\nERROR: Inconsistent number of channels [channel_profile_profile::FATAL%s]", PROGRAM);} + else + { + int a, n; + for (a=1, n=0; a<=prf1[0]; a++) + { + if (prf1[a]>0 && prf2[a]>0) + { + n++;score+=CL->M[prf1[a]-'A'][prf2[a]-'A']; + + } + } + + if ( n==0)return 0; + + score=(n==0)?0:(score*SCORE_K)/n; + + } + return score; +} + +/*********************************************************************************************/ +/* */ +/* FUNCTIONS FOR GETING THE COST : (Sequences) ->evaluate_residue_pair */ +/* */ +/*********************************************************************************************/ +int initialize_scoring_scheme (Constraint_list *CL) +{ + if (!CL) return 0; + else if (!CL->evaluate_residue_pair)return 0; + else if ( !CL->S) return 0; + else if ( (CL->S)->nseq<2) return 0; + else if ( strlen ((CL->S)->seq[0])==0)return 0; + else if ( strlen ((CL->S)->seq[1])==0)return 0; + else + { + //CL->evaluate_residue_pair (CL,13,1,16,1); + CL->evaluate_residue_pair (CL,0,1,1,1); + + } + return 1; +} + +int evaluate_blast_profile_score (Constraint_list *CL, int s1, int r1, int s2, int r2) +{ + Alignment *PRF1; + Alignment *PRF2; + + + PRF1=(Alignment*)atop(seq2T_value (CL->S, s1, "A", "_RB_")); + PRF2=(Alignment*)atop(seq2T_value (CL->S, s2, "A", "_RB_")); + + return generic_evaluate_profile_score (CL,PRF1,s1, r1, PRF2,s2, r2, CL->profile_mode); +} + +int evaluate_aln_profile_score (Constraint_list *CL, int s1, int r1, int s2, int r2) +{ + + return generic_evaluate_profile_score (CL,seq2R_template_profile((CL->S),s1),s1, r1, seq2R_template_profile(CL->S,s2),s2, r2, CL->profile_mode); +} + + +int evaluate_profile_score (Constraint_list *CL,Alignment *Prf1, int s1, int r1, Alignment *Prf2,int s2, int r2) +{ + + return generic_evaluate_profile_score (CL, Prf1, s1,r1,Prf2, s2,r2,CL->profile_mode); +} + +int evaluate_cdna_matrix_score (Constraint_list *CL, int s1, int r1, int s2, int r2) + { + char a1, a2; + + if (r1>0 && r2>0) + { + r1--; + r2--; + + a1=translate_dna_codon((CL->S)->seq[s1]+r1,'x'); + a2=translate_dna_codon((CL->S)->seq[s2]+r2,'x'); + + + + if (a1=='x' || a2=='x')return 0; + else return CL->M[a1-'A'][a2-'A']*SCORE_K; + } + else + { + return 0; + } + } +int evaluate_physico_score ( Constraint_list *CL, int s1, int r1, int s2, int r2) +{ + int a, b, p; + double tot; + static float **prop_table; + static int n_prop; + static double max; + if (r1<0 || r2<0)return 0; + if ( !prop_table) + { + prop_table= initialise_aa_physico_chemical_property_table(&n_prop); + for (p=0; p< n_prop; p++)max+=100; + max=sqrt(max); + } + a=tolower (( CL->S)->seq[s1][r1]); + b=tolower (( CL->S)->seq[s2][r2]); + + for (tot=0,p=0; p< n_prop; p++) + { + tot+=(double)(prop_table[p][a]-prop_table[p][b])*(prop_table[p][a]-prop_table[p][b]); + } + + tot=(sqrt(tot)/max)*10; + + return (int) tot*SCORE_K; +} + + + +int evaluate_diaa_matrix_score ( Constraint_list *CL, int s1, int r1, int s2, int r2) + { + + static int ****m; + static int *alp; + + if (m==NULL) + { + FILE *fp; + char k1[2], k2[2]; + int v1, v2, c; + char *buf=NULL; + int a; + + m=declare_arrayN(4, sizeof (int), 26, 26, 26, 26); + fp=vfopen ("diaa_mat.mat", "r"); + while ((c=fgetc (fp))!=EOF) + { + + ungetc (c, fp); + buf=vfgets(buf, fp); + + if (c=='#'); + else + { + sscanf (buf, "%s %s %d %d", k1, k2, &v1, &v2); + + m[k1[0]-'a'][k1[1]-'a'][k2[0]-'a'][k2[1]-'a']=v1; + m[k2[0]-'a'][k2[1]-'a'][k1[0]-'a'][k1[1]-'a']=v1; + } + } + vfclose (fp); + alp=vcalloc (256, sizeof (int)); + for (a=0; a<26; a++)alp[a+'a']=1; + alp['b']=0; + alp['j']=0; + alp['o']=0; + alp['u']=0; + alp['x']=0; + alp['z']=0; + } + + + if (r1>0 && r2>0) + { + int s=0, n=0; + char aa1, aa2, aa3, aa4, u; + + r1--; + r2--; + + if (r1>0 && r2>0) + { + aa1=tolower((CL->S)->seq[s1][r1-1]); + aa2=tolower((CL->S)->seq[s1][r1]); + aa3=tolower((CL->S)->seq[s2][r2-1]); + aa4=tolower((CL->S)->seq[s2][r2]); + u=alp[(int)aa1];u+=alp[(int)aa2];u+=alp[(int)aa3];u+=alp[(int)aa4]; + if (u==4) + { + s+=m[aa1-'a'][aa2-'a'][aa3-'a'][aa4-'a']; + n++; + } + } + + aa1=tolower((CL->S)->seq[s1][r1]); + aa2=tolower((CL->S)->seq[s1][r1+1]); + aa3=tolower((CL->S)->seq[s2][r2]); + aa4=tolower((CL->S)->seq[s2][r2+1]); + u=alp[(int)aa1];u+=alp[(int)aa2];u+=alp[(int)aa3];u+=alp[(int)aa4]; + if (u==4) + { + s+=m[aa1-'a'][aa2-'a'][aa3-'a'][aa4-'a']; + n++; + } + if (n)return (s*SCORE_K)/n; + else return 0; + } + return 0;} +int evaluate_monoaa_matrix_score ( Constraint_list *CL, int s1, int r1, int s2, int r2) + { + + static int **m; + static int *alp; + + if (m==NULL) + { + FILE *fp; + char k1[2], k2[2]; + int v1, v2, c; + char *buf=NULL; + int a; + + m=declare_arrayN(2, sizeof (int), 26, 26); + fp=vfopen ("monoaa_mat.mat", "r"); + while ((c=fgetc (fp))!=EOF) + { + + ungetc (c, fp); + buf=vfgets(buf, fp); + + if (c=='#'); + else + { + sscanf (buf, "%s %s %d %d", k1, k2, &v1, &v2); + + m[k1[0]-'a'][k2[0]-'a']=v1; + m[k2[0]-'a'][k1[0]-'a']=v1; + } + } + vfclose (fp); + alp=vcalloc (256, sizeof (int)); + for (a=0; a<26; a++)alp[a+'a']=1; + alp['b']=0; + alp['j']=0; + alp['o']=0; + alp['u']=0; + alp['x']=0; + alp['z']=0; + } + + + if (r1>0 && r2>0) + { + int s=0, n=0; + char aa1, aa3, u; + + r1--; + r2--; + + if (r1>0 && r2>0) + { + aa1=tolower((CL->S)->seq[s1][r1]); + aa3=tolower((CL->S)->seq[s2][r2]); + u=alp[(int)aa1];u+=alp[(int)aa3]; + if (u==2) + { + s+=m[aa1-'a'][aa3-'a']; + n++; + } + } + + if (n)return (s*SCORE_K)/n; + else return 0; + } + return 0;} +int evaluate_matrix_score ( Constraint_list *CL, int s1, int r1, int s2, int r2) + { + + if ( seq2R_template_profile (CL->S,s1) ||seq2R_template_profile (CL->S,s2)) + { + return evaluate_aln_profile_score ( CL, s1,r1, s2, r2); + } + + if (r1>0 && r2>0) + { + r1--; + r2--; + + return CL->M[(CL->S)->seq[s1][r1]-'A'][(CL->S)->seq[s2][r2]-'A']*SCORE_K; + } + else + return 0; + } +int *get_curvature ( int s1, Constraint_list *CL); +int evaluate_curvature_score( Constraint_list *CL, int s1, int r1, int s2, int r2) +{ + static int **st; + int score; + CL->gop=0; + CL->gep=0; + + if (!st) st= vcalloc ((CL->S)->nseq, sizeof (char*)); + if (!st[s1]) + { + st[s1]=get_curvature (s1, CL); + } + if (!st[s2]) + { + st[s2]=get_curvature (s2, CL); + } + + if (r1>0 && r2>0) + { + char p1, p2; + + r1--; + r2--; + + p1=st[s1][r1]; + p2=st[s2][r2]; + + score=p1-p2; + score=FABS(score); + score=20-score; + //HERE ("%d", score); + //if (score<0)HERE ("%d", score); + return score; + } + else + { + return 0; + } + +} +int *get_curvature ( int s1, Constraint_list *CL) +{ + int *array, n=0, a; + char c; + FILE *fp; + char name [1000], b1[100], b2[100]; + float f; + sprintf ( name, "%s.curvature", (CL->S)->name[s1]); + array=vcalloc (strlen ((CL->S)->seq[s1]), sizeof (int)); + fp=vfopen ( name, "r"); + while ( fscanf (fp, "%s %d %c %f\n",b1, &a, &c,&f )==4) + { + if ( c!=(CL->S)->seq[s1][n]){HERE ("ERROR: %c %c", c,(CL->S)->seq[s1][n] );myexit (0);} + else array[n++]=(int)(float)100*(float)f; + } + vfclose (fp); + return array; +} +int evaluate_tm_matrix_score ( Constraint_list *CL, int s1, int r1, int s2, int r2) +{ + static char **st; + float F, RF; + + if (!st) + { + st= vcalloc ((CL->S)->nseq, sizeof (char*)); + RF=atoigetenv ("TM_FACTOR_4_TCOFFEE"); + if ( !RF)RF=10; + } + + if (!st[s1])st[s1]=seq2T_template_string((CL->S),s1); + if (!st[s2])st[s2]=seq2T_template_string((CL->S),s2); + + if (r1<=0 || r2<=0)return 0; + else if (st[s1] && st[s2] && (st[s1][r1-1]==st[s2][r2-1]))F=RF; + else if (st[s1] && st[s2] && (st[s1][r1-1]!=st[s2][r2-1]))F=0; + else F=0; + + return (int)(evaluate_matrix_score (CL, s1, r1, s2, r2))+F; +} +int evaluate_ssp_matrix_score ( Constraint_list *CL, int s1, int r1, int s2, int r2) +{ + static char **st; + float F, RF; + + if (!st) + { + st= vcalloc ((CL->S)->nseq, sizeof (char*)); + RF=atoigetenv ("SSP_FACTOR_4_TCOFFEE"); + if ( !RF)RF=10; + } + + if (!st[s1])st[s1]=seq2T_template_string((CL->S),s1); + if (!st[s2])st[s2]=seq2T_template_string((CL->S),s2); + + if (r1<=0 || r2<=0)return 0; + else if (st[s1] && st[s2] && (st[s1][r1-1]==st[s2][r2-1]))F=RF; + else if (st[s1] && st[s2] && (st[s1][r1-1]!=st[s2][r2-1]))F=0; + else F=0; + + return (int)(evaluate_matrix_score (CL, s1, r1, s2, r2))+F; +} + + +int evaluate_combined_matrix_score ( Constraint_list *CL, int s1, int r1, int s2, int r2) + { + /* + function documentation: start + + int evaluate_matrix_score ( Constraint_list *CL, int s1, int s2, int r1, int r2) + + this function evaluates the score for matching residue S1(r1) wit residue S2(r2) + using Matrix CL->M; + + function documentation: end + */ + + if ( seq2R_template_profile (CL->S,s1) ||seq2R_template_profile (CL->S,s2)) + { + return evaluate_aln_profile_score ( CL, s1,r1, s2, r2); + } + + if (r1>0 && r2>0) + { + r1--; + r2--; + if (r1==0 || r2==0)return CL->M[(CL->S)->seq[s1][r1]-'A'][(CL->S)->seq[s2][r2]-'A']*SCORE_K; + else + { + int A1, A2, B1, B2, a2, b2; + int score; + + A1=toupper((CL->S)->seq[s1][r1-1]); + A2=toupper((CL->S)->seq[s1][r1]); + B1=toupper((CL->S)->seq[s2][r2-1]); + B2=toupper((CL->S)->seq[s2][r2]); + + a2=tolower(A2); + b2=tolower(B2); + A1-='A';A2-='A';B1-='A'; B2-='A';a2-='A';b2-='A'; + + score=CL->M[a2][b2]-FABS((CL->M[A1][A2])-(CL->M[B1][B2])); + score*=SCORE_K; + return score; + } + } + else + return 0; + } + +int residue_pair_non_extended_list ( Constraint_list *CL, int s1, int r1, int s2, int r2 ) + { + + /* + This is the generic Function->works with everything + + int residue_pair_non_extended_list ( Constraint_list *CL, int s1, int r1, int s2, int r2, int field ); + + Computes the non extended score for aligning residue seq1(r1) Vs seq2(r2) + + This function can compare a sequence with itself. + + Associated functions: See util constraint list, list extention functions. + function documentation: end + */ + + int p; + + + static int *entry; + int *r; + int field; + + field = CL->weight_field; + + + if ( r1<=0 || r2<=0)return 0; + else if ( !CL->extend_jit) + { + if ( !entry) entry=vcalloc (LIST_N_FIELDS , sizeof (int)); + entry[SEQ1]=s1; + entry[SEQ2]=s2; + entry[R1]=r1; + entry[R2]=r2; + if ( r1==r2 && s1==s2) return UNDEFINED; + r=main_search_in_list_constraint( entry,&p,4,CL); + if (r==NULL)return 0; + else return r[field]*SCORE_K; + } + else + return UNDEFINED;/*ERROR*/ + + + } + + + +int residue_pair_extended_list_mixt (Constraint_list *CL, int s1, int r1, int s2, int r2 ) + { + int score=0; + + score+= residue_pair_extended_list_quadruplet(CL, s1, r1, s2, r2); + score+= residue_pair_extended_list (CL, s1, r1, s2, r2); + + return score*SCORE_K; + } + +int residue_pair_extended_list_quadruplet (Constraint_list *CL, int s1, int r1, int s2, int r2 ) + { + double score=0; + + int t_s, t_r, t_w, q_s, q_r, q_w; + int a, b; + static int **hasch; + + int field; + /* This measure the quadruplets cost on a pair of residues*/ + + + + field=CL->weight_field; + + if ( r1<=0 || r2<=0)return 0; + if ( !hasch) + { + hasch=vcalloc ( (CL->S)->nseq, sizeof (int*)); + for ( a=0; a< (CL->S)->nseq; a++)hasch[a]=vcalloc ( (CL->S)->len[a]+1, sizeof (int)); + } + + + hasch[s1][r1]=100000; + for (a=1; a< CL->residue_index[s1][r1][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s1][r1][a+SEQ2]; + t_r=CL->residue_index[s1][r1][a+R2]; + t_w=CL->residue_index[s1][r1][a+WE]; + if ( CL->seq_for_quadruplet[t_s]) + { + for ( b=1; bresidue_index[t_s][t_r][0]; b+=ICHUNK) + { + q_s=CL->residue_index[t_s][t_r][b+SEQ2]; + q_r=CL->residue_index[t_s][t_r][b+R2]; + q_w=CL->residue_index[t_s][t_r][b+WE]; + if (CL-> seq_for_quadruplet[q_s]) + hasch[q_s][q_r]=MIN(q_w,t_w); + + } + } + } + + + for (a=1; a< CL->residue_index[s2][r2][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s2][r2][a+SEQ2]; + t_r=CL->residue_index[s2][r2][a+R2]; + t_w=CL->residue_index[s2][r2][a+WE]; + if ( CL->seq_for_quadruplet[t_s]) + { + for ( b=1; bresidue_index[t_s][t_r][0]; b+=ICHUNK) + { + q_s=CL->residue_index[t_s][t_r][b+SEQ2]; + q_r=CL->residue_index[t_s][t_r][b+R2]; + q_w=CL->residue_index[t_s][t_r][b+WE]; + if (hasch[q_s][q_r] && CL->seq_for_quadruplet[q_s]) + score+=MIN(hasch[q_s][q_r],MIN(q_w,t_w)); + } + } + } + + score=(CL->normalise)?((score*CL->normalise)/CL->max_ext_value):score; + + for (a=1; a< CL->residue_index[s1][r1][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s1][r1][a+SEQ2]; + t_r=CL->residue_index[s1][r1][a+R2]; + t_w=CL->residue_index[s1][r1][a+WE]; + if ( CL->seq_for_quadruplet[t_s]) + { + for ( b=1; bresidue_index[t_s][t_r][0]; b+=ICHUNK) + { + q_s=CL->residue_index[t_s][t_r][b+SEQ2]; + q_r=CL->residue_index[t_s][t_r][b+R2]; + hasch[q_s][q_r]=0; + } + } + } + + return (int)(score*SCORE_K); + } + + +Constraint_list * R_extension ( Constraint_list *CL, Constraint_list *R); +int residue_pair_extended_list4rna4 (Constraint_list *CL,int s1, int r1, int s2, int r2 ) +{ + static int rna_lib; + + if (!rna_lib) + { + sprintf ( CL->rna_lib, "%s", seq2rna_lib (CL->S, NULL)); + rna_lib=1; + } + return residue_pair_extended_list4rna2 (CL, s1, r1, s2,r2); +} +int residue_pair_extended_list4rna1 (Constraint_list *CL, int s1, int r1, int s2, int r2 ) +{ + static Constraint_list *R; + if (!R)R=read_rna_lib (CL->S, CL->rna_lib); + return residue_pair_extended_list4rna (CL, R, s1, r1, s2, r2); +} + +int residue_pair_extended_list4rna3 (Constraint_list *CL,int s1, int r1, int s2, int r2 ) +{ + static Constraint_list *R; + if (!R) + { + R=read_rna_lib (CL->S, CL->rna_lib); + rna_lib_extension (CL,R); + } + return residue_pair_extended_list (CL, s1,r1, s2,r2); +} + +int residue_pair_extended_list4rna2 (Constraint_list *CL,int s1, int r1, int s2, int r2 ) +{ + static Constraint_list *R; + + + if (!R) + { + + R=read_rna_lib (CL->S, CL->rna_lib); + rna_lib_extension (CL,R); + + } + + return residue_pair_extended_list4rna (CL, R, s1, r1, s2, r2); +} +int residue_pair_extended_list4rna ( Constraint_list *CL,Constraint_list *R, int s1, int r1, int s2, int r2 ) +{ + + int a, b, n1, n2; + int list1[100]; + int list2[100]; + int score=0, score2; + + + + if ( r1<0 || r2<0)return 0; + n1=n2=0; + + list1[n1++]=r1; + for (a=1; aresidue_index[s1][r1][0]; a+=ICHUNK) + { + list1[n1++]=R->residue_index[s1][r1][a+R2]; + } + + + list2[n2++]=r2; + for (a=1; aresidue_index[s2][r2][0]; a+=ICHUNK) + { + list2[n2++]=R->residue_index[s2][r2][a+R2]; + } + + + score=residue_pair_extended_list ( CL, s1,list1[0], s2,list2[0]); + + for (score2=0,a=1; arna_lib, &n); + + R=declare_constraint_list ( CL->S,NULL, NULL, 0,NULL, NULL); + + for (a=0; a< n; a++) + { + R=read_constraint_list_file (R, list[a]); + } + + } + + if ( r1<0 || r2<0)return 0; + n1=n2=0; + + list1[n1++]=r1; + for (a=1; aresidue_index[s1][r1][0]; a+=ICHUNK) + { + list1[n1++]=R->residue_index[s1][r1][a+R2]; + } + + + list2[n2++]=r2; + for (a=1; aresidue_index[s2][r2][0]; a+=ICHUNK) + { + list2[n2++]=R->residue_index[s2][r2][a+R2]; + } + + + score=residue_pair_extended_list ( CL, s1,list1[0], s2,list2[0]); + + for (score2=0,a=1; aweight_field; + field=WE; + + if ( r1<=0 || r2<=0)return 0; + if ( !hasch || max_len!=(CL->S)->max_len) + { + max_len=(CL->S)->max_len; + if ( hasch) free_int ( hasch, -1); + hasch=declare_int ( (CL->S)->nseq, (CL->S)->max_len+1); + } + + + + /* Check matches for R1 in the indexed lib*/ + hasch[s1][r1]=FORBIDEN; + for (a=1; a< CL->residue_index[s1][r1][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s1][r1][a+SEQ2]; + t_r=CL->residue_index[s1][r1][a+R2]; + hasch[t_s][t_r]=CL->residue_index[s1][r1][a+field]; + } + + /*Check Matches for r1 <-> r2 in the indexed lib */ + for (a=1; a< CL->residue_index[s2][r2][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s2][r2][a+SEQ2]; + t_r=CL->residue_index[s2][r2][a+R2]; + + + if (hasch[t_s][t_r]) + { + if (hasch[t_s][t_r]==FORBIDEN) + { + score+=CL->residue_index[s2][r2][a+field]; + } + else + { + delta=MIN(hasch[t_s][t_r],CL->residue_index[s2][r2][a+field]); + score+=delta; + } + } + } + + clean_residue_pair_hasch ( s1, r1,s2, r2, hasch, CL); + return score; + } +int residue_pair_extended_list_4gp ( Constraint_list *CL, int s1, int r1, int s2, int r2 ) + { + double score=0; + + + + int a, t_s, t_r; + static int **hasch; + static int max_len; + int field; + double delta; + + /* + + function documentation: start + + int residue_pair_extended_list ( Constraint_list *CL, int s1, int r1, int s2, int r2); + + Computes the extended score for aligning residue seq1(r1) Vs seq2(r2) + Computes: matrix_score + non extended score + extended score + + The extended score depends on the function index_res_constraint_list. + This function can compare a sequence with itself. + + Associated functions: See util constraint list, list extention functions. + + function documentation: end + */ + + field=CL->weight_field; + field=WE; + + if ( r1<=0 || r2<=0)return 0; + if ( !hasch || max_len!=(CL->S)->max_len) + { + max_len=(CL->S)->max_len; + if ( hasch) free_int ( hasch, -1); + hasch=declare_int ( (CL->S)->nseq, (CL->S)->max_len+1); + } + + + + /* Check matches for R1 in the indexed lib*/ + hasch[s1][r1]=FORBIDEN; + for (a=1; a< CL->residue_index[s1][r1][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s1][r1][a+SEQ2]; + t_r=CL->residue_index[s1][r1][a+R2]; + hasch[t_s][t_r]=CL->residue_index[s1][r1][a+field]; + } + + /*Check Matches for r1 <-> r2 in the indexed lib */ + for (a=1; a< CL->residue_index[s2][r2][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s2][r2][a+SEQ2]; + t_r=CL->residue_index[s2][r2][a+R2]; + + + if (hasch[t_s][t_r]) + { + if (hasch[t_s][t_r]==FORBIDEN) + { + score+=((float)CL->residue_index[s2][r2][a+2]/NORM_F); + } + else + { + delta=MAX((((float)hasch[t_s][t_r]/NORM_F)),(((float)CL->residue_index[s2][r2][a+field]/NORM_F))); + score+=delta; + } + } + } + + clean_residue_pair_hasch ( s1, r1,s2, r2, hasch, CL); + score/=(CL->S)->nseq; + score *=NORM_F; + + return score; + } + +int residue_pair_extended_list_pc ( Constraint_list *CL, int s1, int r1, int s2, int r2 ) + { + //old norm does not take into account the number of effective intermediate sequences + + double score=0; + int a, t_s, t_r; + static int **hasch; + int nclean; + static int max_len; + int field; + double delta; + float norm1=0; + float norm2=0; + + /* + + function documentation: start + + int residue_pair_extended_list ( Constraint_list *CL, int s1, int r1, int s2, int r2); + + Computes the extended score for aligning residue seq1(r1) Vs seq2(r2) + Computes: matrix_score + non extended score + extended score + + The extended score depends on the function index_res_constraint_list. + This function can compare a sequence with itself. + + Associated functions: See util constraint list, list extention functions. + + function documentation: end + */ + + field=CL->weight_field; + field=WE; + + if ( r1<=0 || r2<=0)return 0; + if ( !hasch || max_len!=(CL->S)->max_len) + { + max_len=(CL->S)->max_len; + if ( hasch) free_int ( hasch, -1); + hasch=declare_int ( (CL->S)->nseq, (CL->S)->max_len+1); + + } + + + /* Check matches for R1 in the indexed lib*/ + hasch[s1][r1]=FORBIDEN; + for (a=1; a< CL->residue_index[s1][r1][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s1][r1][a+SEQ2]; + t_r=CL->residue_index[s1][r1][a+R2]; + hasch[t_s][t_r]=CL->residue_index[s1][r1][a+field]; + norm1++; + + } + + + /*Check Matches for r1 <-> r2 in the indexed lib */ + for (a=1; a< CL->residue_index[s2][r2][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s2][r2][a+SEQ2]; + t_r=CL->residue_index[s2][r2][a+R2]; + norm2++; + + if (hasch[t_s][t_r]) + { + if (hasch[t_s][t_r]==FORBIDEN) + { + score+=((float)CL->residue_index[s2][r2][a+field]/NORM_F); + } + else + { + delta=MIN((((float)hasch[t_s][t_r]/NORM_F)),(((float)CL->residue_index[s2][r2][a+field]/NORM_F))); + score+=delta; + } + } + } + + clean_residue_pair_hasch ( s1, r1,s2, r2, hasch, CL); + + //New Normalization + norm1=MIN(norm1,norm2); + + //Old Normailzation: on the number of sequences, useless when not doiang an all against all + //norm1=(CL->S)->nseq; + + score=(norm1)?score/norm1:0; + + + return score*NORM_F; + } +int residue_pair_extended_list_pc_old ( Constraint_list *CL, int s1, int r1, int s2, int r2 ) + { + //old norm does not take into account the number of effective intermediate sequences + + double score=0; + int a, t_s, t_r; + static int **hasch; + + static int max_len; + int field; + double delta; + + /* + + function documentation: start + + int residue_pair_extended_list ( Constraint_list *CL, int s1, int r1, int s2, int r2); + + Computes the extended score for aligning residue seq1(r1) Vs seq2(r2) + Computes: matrix_score + non extended score + extended score + + The extended score depends on the function index_res_constraint_list. + This function can compare a sequence with itself. + + Associated functions: See util constraint list, list extention functions. + + function documentation: end + */ + + field=CL->weight_field; + field=WE; + + if ( r1<=0 || r2<=0)return 0; + if ( !hasch || max_len!=(CL->S)->max_len) + { + max_len=(CL->S)->max_len; + if ( hasch) free_int ( hasch, -1); + hasch=declare_int ( (CL->S)->nseq, (CL->S)->max_len+1); + } + + + /* Check matches for R1 in the indexed lib*/ + hasch[s1][r1]=FORBIDEN; + for (a=1; a< CL->residue_index[s1][r1][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s1][r1][a+SEQ2]; + t_r=CL->residue_index[s1][r1][a+R2]; + hasch[t_s][t_r]=CL->residue_index[s1][r1][a+field]; + } + + + /*Check Matches for r1 <-> r2 in the indexed lib */ + for (a=1; a< CL->residue_index[s2][r2][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s2][r2][a+SEQ2]; + t_r=CL->residue_index[s2][r2][a+R2]; + + + if (hasch[t_s][t_r]) + { + if (hasch[t_s][t_r]==FORBIDEN) + { + score+=((float)CL->residue_index[s2][r2][a+2]/NORM_F); + } + else + { + delta=MIN((((float)hasch[t_s][t_r]/NORM_F)),(((float)CL->residue_index[s2][r2][a+field]/NORM_F))); + score+=delta; + } + } + } + + clean_residue_pair_hasch ( s1, r1,s2, r2, hasch, CL); + score/=(CL->S)->nseq; + return score*NORM_F; + } + + +int residue_pair_extended_list ( Constraint_list *CL, int s1, int r1, int s2, int r2 ) + { + double score=0; + double max_score=0; + double max_val=0; + + int a, t_s, t_r; + static int **hasch; + static int max_len; + int field; + + /* + new function: self normalized + function documentation: start + + int residue_pair_extended_list ( Constraint_list *CL, int s1, int r1, int s2, int r2); + + Computes the extended score for aligning residue seq1(r1) Vs seq2(r2) + Computes: matrix_score + non extended score + extended score + + The extended score depends on the function index_res_constraint_list. + This function can compare a sequence with itself. + + Associated functions: See util constraint list, list extention functions. + + function documentation: end + */ + + field=CL->weight_field; + field=WE; + + if ( r1<=0 || r2<=0)return 0; + if ( !hasch || max_len!=(CL->S)->max_len) + { + max_len=(CL->S)->max_len; + if ( hasch) free_int ( hasch, -1); + hasch=declare_int ( (CL->S)->nseq, (CL->S)->max_len+1); + } + + + + /* Check matches for R1 in the indexed lib*/ + hasch[s1][r1]=FORBIDEN; + for (a=1; a< CL->residue_index[s1][r1][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s1][r1][a+SEQ2]; + t_r=CL->residue_index[s1][r1][a+R2]; + hasch[t_s][t_r]=CL->residue_index[s1][r1][a+field]; + max_score+=CL->residue_index[s1][r1][a+field]; + } + + /*Check Matches for r1 <-> r2 in the indexed lib */ + for (a=1; a< CL->residue_index[s2][r2][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s2][r2][a+SEQ2]; + t_r=CL->residue_index[s2][r2][a+R2]; + + + if (hasch[t_s][t_r]) + { + if (hasch[t_s][t_r]==FORBIDEN) + { + score+=CL->residue_index[s2][r2][a+field]; + max_score+=CL->residue_index[s2][r2][a+field]; + } + else + { + double delta; + delta=MIN(hasch[t_s][t_r],CL->residue_index[s2][r2][a+field]); + + score+=delta; + max_score-=hasch[t_s][t_r]; + max_score+=delta; + max_val=MAX(max_val,delta); + } + } + else + { + max_score+=CL->residue_index[s2][r2][a+field]; + } + } + + max_score-=hasch[s2][r2]; + clean_residue_pair_hasch ( s1, r1,s2, r2, hasch, CL); + + + if ( max_score==0)score=0; + else if ( CL->normalise) + { + score=((score*CL->normalise)/max_score)*SCORE_K; + if (max_val> CL->normalise) + { + score*=max_val/(double)CL->normalise; + } + } + return (int) score; + } +int ** clean_residue_pair_hasch (int s1, int r1, int s2, int r2,int **hasch, Constraint_list *CL) + { + int a, t_s, t_r; + if ( !hasch) return hasch; + + for (a=1; a< CL->residue_index[s1][r1][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s1][r1][a+SEQ2]; + t_r=CL->residue_index[s1][r1][a+R2]; + hasch[t_s][t_r]=0; + } + hasch[s1][r1]=hasch[s2][r2]=0; + return hasch; + } + +int residue_pair_test_function ( Constraint_list *CL, int s1, int r1, int s2, int r2 ) + { + double score=0; + + int a, t_s, t_r; + static int **hasch; + static int max_len; + int cons1; + int cons2; + + int field; + /* + function documentation: start + + int residue_pair_extended_list ( Constraint_list *CL, int s1, int r1, int s2, int r2); + + Computes the extended score for aligning residue seq1(r1) Vs seq2(r2) + Computes: matrix_score + non extended score + extended score + + The extended score depends on the function index_res_constraint_list. + This function can compare a sequence with itself. + + Associated functions: See util constraint list, list extention functions. + + function documentation: end + */ + + + CL->weight_field=WE; + field=CL->weight_field; + + + if ( r1<=0 || r2<=0)return 0; + if ( !hasch || max_len!=(CL->S)->max_len) + { + max_len=(CL->S)->max_len; + if ( hasch) free_int ( hasch, -1); + hasch=declare_int ( (CL->S)->nseq, (CL->S)->max_len+1); + } + + + + hasch[s1][r1]=1000; + for (a=1; a< CL->residue_index[s1][r1][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s1][r1][a+SEQ2]; + t_r=CL->residue_index[s1][r1][a+R2]; + hasch[t_s][t_r]=CL->residue_index[s1][r1][a+field]; + } + + + for (a=1; a< CL->residue_index[s2][r2][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s2][r2][a+SEQ2]; + t_r=CL->residue_index[s2][r2][a+R2]; + if (hasch[t_s][t_r]) + { + cons1=hasch[t_s][t_r]; + cons2=CL->residue_index[s2][r2][a+field]; + score +=MIN(cons1,cons2); + } + } + + + score=(CL->normalise)?((score*CL->normalise)/CL->max_ext_value):score; + + for (a=1; a< CL->residue_index[s1][r1][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s1][r1][a+SEQ2]; + t_r=CL->residue_index[s1][r1][a+R2]; + hasch[t_s][t_r]=0; + } + hasch[s1][r1]=hasch[s2][r2]=0; + + + return (int)(score*SCORE_K); + } + +int residue_pair_relative_extended_list ( Constraint_list *CL, int s1, int r1, int s2, int r2 ) + { + int a, t_s, t_r; + static int **hasch; + static int max_len; + int score=0; + int total_score=0; + int field; + /* + function documentation: start + + int residue_pair_extended_list ( Constraint_list *CL, int s1, int r1, int s2, int r2); + + Computes the extended score for aligning residue seq1(r1) Vs seq2(r2) + Computes: matrix_score + non extended score + extended score + + The extended score depends on the function index_res_constraint_list. + This function can compare a sequence with itself. + + Associated functions: See util constraint list, list extention functions. + + function documentation: end + */ + + + + field=CL->weight_field; + field=WE; + + if ( r1<=0 || r2<=0)return 0; + if ( !hasch || max_len!=(CL->S)->max_len) + { + max_len=(CL->S)->max_len; + if ( hasch) free_int ( hasch, -1); + hasch=declare_int ( (CL->S)->nseq, (CL->S)->max_len+1); + } + + + + hasch[s1][r1]=100000; + for (a=1; a< CL->residue_index[s1][r1][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s1][r1][a+SEQ2]; + t_r=CL->residue_index[s1][r1][a+R2]; + hasch[t_s][t_r]=CL->residue_index[s1][r1][a+field]; + total_score+=CL->residue_index[s1][r1][a+field]; + } + + + for (a=1; a< CL->residue_index[s2][r2][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s2][r2][a+SEQ2]; + t_r=CL->residue_index[s2][r2][a+R2]; + total_score+=CL->residue_index[s1][r1][a+field]; + if (hasch[t_s][t_r]) + { + if (field==WE){score+=2*MIN(hasch[t_s][t_r],CL->residue_index[s2][r2][a+field]);} + } + } + + score=((CL->normalise*score)/total_score); + + + for (a=1; a< CL->residue_index[s1][r1][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s1][r1][a+SEQ2]; + t_r=CL->residue_index[s1][r1][a+R2]; + hasch[t_s][t_r]=0; + } + hasch[s1][r1]=hasch[s2][r2]=0; + + return score*SCORE_K; + } +int residue_pair_extended_list_g_coffee_quadruplet ( Constraint_list *CL, int s1, int r1, int s2, int r2 ) +{ + int t_s, t_r, t_w, q_s, q_r, q_w; + int a, b; + static int **hasch; + int score=0, s=0; + + int field; + /* This measure the quadruplets cost on a pair of residues*/ + + field=CL->weight_field; + + if ( r1<=0 || r2<=0)return 0; + if ( !hasch) + { + hasch=vcalloc ( (CL->S)->nseq, sizeof (int*)); + for ( a=0; a< (CL->S)->nseq; a++)hasch[a]=vcalloc ( (CL->S)->len[a]+1, sizeof (int)); + } + + + hasch[s1][r1]=100000; + for (a=1; a< CL->residue_index[s1][r1][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s1][r1][a+SEQ2]; + t_r=CL->residue_index[s1][r1][a+R2]; + t_w=CL->residue_index[s1][r1][a+field]; + if ( CL->seq_for_quadruplet[t_s]) + { + for ( b=1; bresidue_index[t_s][t_r][0]; b+=ICHUNK) + { + q_s=CL->residue_index[t_s][t_r][b+SEQ2]; + q_r=CL->residue_index[t_s][t_r][b+R2]; + if (CL-> seq_for_quadruplet[q_s]) + { + + hasch[q_s][q_r]=MIN(CL->residue_index[t_s][t_r][b+2],t_w); + } + } + } + } + + + for (s=0,score=0,a=1; a< CL->residue_index[s2][r2][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s2][r2][a+SEQ2]; + t_r=CL->residue_index[s2][r2][a+R2]; + t_w=CL->residue_index[s2][r2][a+field]; + if ( CL->seq_for_quadruplet[t_s]) + { + for ( b=1; bresidue_index[t_s][t_r][0]; b+=ICHUNK) + { + q_s=CL->residue_index[t_s][t_r][b+SEQ2]; + q_r=CL->residue_index[t_s][t_r][b+R2]; + q_w=CL->residue_index[t_s][t_r][b+field]; + if (hasch[q_s][q_r] && CL->seq_for_quadruplet[q_s]) + s=MIN(hasch[q_s][q_r],MIN(CL->residue_index[t_s][t_r][b+2],q_w)); + score=MAX(score, s); + } + } + } + + for (a=1; a< CL->residue_index[s1][r1][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s1][r1][a+SEQ2]; + t_r=CL->residue_index[s1][r1][a+R2]; + t_w=CL->residue_index[s1][r1][a+field]; + if ( CL->seq_for_quadruplet[t_s]) + { + for ( b=1; bresidue_index[t_s][t_r][0]; b+=ICHUNK) + { + q_s=CL->residue_index[t_s][t_r][b+SEQ2]; + q_r=CL->residue_index[t_s][t_r][b+R2]; + hasch[q_s][q_r]=0; + } + } + } + + return score*SCORE_K; + } +int residue_pair_extended_list_g_coffee ( Constraint_list *CL, int s1, int r1, int s2, int r2 ) + { + int a, t_s, t_r; + static int **hasch; + int score=0,s; + + int field; + /* + function documentation: start + + int residue_pair_extended_list ( Constraint_list *CL, int s1, int r1, int s2, int r2); + + Computes the extended score for aligning residue seq1(r1) Vs seq2(r2) + Computes: matrix_score + non extended score + extended score + + The extended score depends on the function index_res_constraint_list. + This function can compare a sequence with itself. + + Associated functions: See util constraint list, list extention functions. + + function documentation: end + */ + + field=CL->weight_field; + + if ( r1<=0 || r2<=0)return 0; + if ( !hasch) + { + hasch=vcalloc ( (CL->S)->nseq, sizeof (int*)); + for ( a=0; a< (CL->S)->nseq; a++)hasch[a]=vcalloc ( (CL->S)->len[a]+1, sizeof (int)); + } + + + + hasch[s1][r1]=100000; + for (a=1; a< CL->residue_index[s1][r1][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s1][r1][a+SEQ2]; + t_r=CL->residue_index[s1][r1][a+R2]; + hasch[t_s][t_r]=CL->residue_index[s1][r1][a+field]; + } + + + for (s=0, score=0,a=1; a< CL->residue_index[s2][r2][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s2][r2][a+SEQ2]; + t_r=CL->residue_index[s2][r2][a+R2]; + + if (hasch[t_s][t_r]) + { + if (field==WE) + {s=MIN(hasch[t_s][t_r],CL->residue_index[s2][r2][a+WE]); + score=MAX(s,score); + } + } + } + + for (a=1; a< CL->residue_index[s1][r1][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s1][r1][a+SEQ2]; + t_r=CL->residue_index[s1][r1][a+R2]; + hasch[t_s][t_r]=0; + } + hasch[s1][r1]=hasch[s2][r2]=0; + + return score*SCORE_K; + } + +int extend_residue_pair ( Constraint_list *CL, int s1, int r1, int s2, int r2) + { + double score=0; + + int a, t_s, t_r, p; + static int **hasch; + + static int *entry; + int *r; + int field; + + + + /* + This is the generic Function->works with everything + should be gradually phased out + + + int extend_residue_pair ( Constraint_list *CL, int s1, int r1, int s2, int r2, int field ) + + Computes the extended score for aligning residue seq1(r1) Vs seq2(r2) + Computes: matrix_score + non extended score + extended score + + The extended score depends on the function index_res_constraint_list. + This function can compare a sequence with itself. + + Associated functions: See util constraint list, list extention functions. + function documentation: end + */ + + + field=CL->weight_field; + + if ( r1<=0 || r2<=0)return 0; + else if ( !CL->residue_index && CL->M) + { + return evaluate_matrix_score (CL, s1,r1, s2, r2); + } + + else if ( !CL->extend_jit) + { + if ( !entry) entry=vcalloc (LIST_N_FIELDS , sizeof (int)); + entry[SEQ1]=s1; + entry[SEQ2]=s2; + entry[R1]=r1; + entry[R2]=r2; + r=main_search_in_list_constraint( entry,&p,4,CL); + if (r==NULL)return 0; + else return r[field]; + } + else + { + if ( !hasch) + { + hasch=vcalloc ( (CL->S)->nseq, sizeof (int*)); + for ( a=0; a< (CL->S)->nseq; a++)hasch[a]=vcalloc ( (CL->S)->len[a]+1, sizeof (int)); + } + + + + hasch[s1][r1]=100000; + for (a=1; a< CL->residue_index[s1][r1][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s1][r1][a+SEQ2]; + t_r=CL->residue_index[s1][r1][a+R2]; + hasch[t_s][t_r]=CL->residue_index[s1][r1][a+WE]; + } + + + for (a=1; a< CL->residue_index[s2][r2][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s2][r2][a+SEQ2]; + t_r=CL->residue_index[s2][r2][a+R2]; + if (hasch[t_s][t_r]) + { + if (field==WE)score+=MIN(hasch[t_s][t_r],CL->residue_index[s2][r2][a+WE] ); + + } + } + score=(CL->normalise)?((score*CL->normalise)/CL->max_ext_value):score; + for (a=1; a< CL->residue_index[s1][r1][0]; a+=ICHUNK) + { + t_s=CL->residue_index[s1][r1][a+SEQ2]; + t_r=CL->residue_index[s1][r1][a+R2]; + hasch[t_s][t_r]=0; + } + hasch[s1][r1]=hasch[s2][r2]=0; + + return (int)(score*SCORE_K); + } + } +/*********************************************************************************************/ +/* */ +/* FUNCTIONS FOR GETTING THE PW COST : CL->get_dp_cost */ +/* */ +/*********************************************************************************************/ +int get_dp_cost_blosum_matrix (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) +{ + int s1, r1, s2, r2; + static int **matrix; + + if (!matrix) matrix=read_matrice ("blosum62mt"); + s1=A->order[list1[0]][0]; + s2=A->order[list2[0]][0]; + r1=pos1[list1[0]][col1]; + r2=pos2[list2[0]][col2]; + + /*dp cost function: works only with two sequences*/ + + if ( seq2R_template_profile (CL->S,s1) ||seq2R_template_profile (CL->S,s2)) + return evaluate_aln_profile_score ( CL, s1,r1, s2, r2) -CL->nomatch*SCORE_K; + else if (r1>0 && r2>0) + { + r1--; + r2--; + + + return matrix [(CL->S)->seq[s1][r1]-'A'][(CL->S)->seq[s2][r2]-'A']*SCORE_K -CL->nomatch*SCORE_K; + + } + else + return -CL->nomatch*SCORE_K ; +} +int get_dp_cost_pam_matrix (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) +{ + int s1, r1, s2, r2; + static int **matrix; + + if (!matrix) matrix=read_matrice ("pam250mt"); + s1=A->order[list1[0]][0]; + s2=A->order[list2[0]][0]; + r1=pos1[list1[0]][col1]; + r2=pos2[list2[0]][col2]; + + /*dp cost function: works only with two sequences*/ + + + if ( seq2R_template_profile (CL->S,s1) ||seq2R_template_profile (CL->S,s2)) + return evaluate_aln_profile_score ( CL, s1,r1, s2, r2) -CL->nomatch*SCORE_K; + else if (r1>0 && r2>0) + { + r1--; + r2--; + + + return matrix [(CL->S)->seq[s1][r1]-'A'][(CL->S)->seq[s2][r2]-'A']*SCORE_K -CL->nomatch*SCORE_K; + + } + else + return -CL->nomatch*SCORE_K ; +} + +int get_dp_cost_pw_matrix (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) +{ + int s1, r1, s2, r2; + + s1=A->order[list1[0]][0]; + s2=A->order[list2[0]][0]; + r1=pos1[list1[0]][col1]; + r2=pos2[list2[0]][col2]; + + /*dp cost function: works only with two sequences*/ + if ( seq2R_template_profile (CL->S,s1) ||seq2R_template_profile (CL->S,s2)) + return evaluate_aln_profile_score ( CL, s1,r1, s2, r2) -CL->nomatch*SCORE_K; + else if (r1>0 && r2>0) + { + r1--; + r2--; + + + return CL->M[(CL->S)->seq[s1][r1]-'A'][(CL->S)->seq[s2][r2]-'A']*SCORE_K -CL->nomatch*SCORE_K; + + } + else + return -CL->nomatch*SCORE_K ; +} + +/*********************************************************************************************/ +/* */ +/* FUNCTIONS FOR GETTING THE COST : CL->get_dp_cost */ +/* */ +/*********************************************************************************************/ + + + +int get_cdna_best_frame_dp_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) + { + int a, b; + int n=4; + int s; + char a1, a2; + static int l1, l2; + static Alignment *B; + static int **score; + + if ( !score)score=declare_int(3, 2); + + if (!A) + { + free_aln(B); + B=NULL; + return UNDEFINED; + } + if (!B) + { + if (ns1+ns2>2){fprintf ( stderr, "\nERROR: get_cdna_dp_cost mode is only for pair-wise ALN [FATAL]\n");crash("");} + free_aln (B); + B=copy_aln (A, NULL); + + l1=(int)strlen ( A->seq_al[list1[0]]); + for ( b=0; bseq_al[list1[0]][b]=translate_dna_codon (A->seq_al[list1[0]]+b, 'x'); + l2=(int)strlen ( A->seq_al[list2[0]]); + for ( b=0; bseq_al[list2[0]][b]=translate_dna_codon (A->seq_al[list2[0]]+b, 'x'); + } + +/*Set the frame*/ + + for ( a=0; a< 3; a++)score[a][0]=score[a][1]=0; + for ( a=col1-(n*3),b=col2-(n*3); a=l1 || b>=l2)continue; + + a1=tolower(B->seq_al[list1[0]][a]); + a2=tolower(B->seq_al[list2[0]][b]); + + score[a%3][0]+=(a1=='x' || a2=='x')?0:CL->M[a1-'A'][a2-'A']; + score[a%3][1]++; + } + + for ( a=0; a< 3; a++)score[a][0]=(score[a][1]>0)?(score[a][0]/score[a][1]):0; + if ( score[0][0]>score[1][0] && score[0][0]>score[2][0]) + s=score[0][0]; + else if ( score[1][0]>score[0][0] && score[1][0]>score[2][0]) + s=score[1][0]; + else s=score[2][0]; + + return s*SCORE_K; + + } + +int get_dp_cost_quadruplet ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) + { + int score; + + + if ( ns1==1 || ns2==1) + score=slow_get_dp_cost ( A, pos1, ns1, list1,col1, pos2, ns2, list2, col2, CL); + else + score=fast_get_dp_cost_quadruplet ( A, pos1, ns1, list1,col1, pos2, ns2, list2, col2, CL); + + return (score==UNDEFINED)?UNDEFINED:(score-SCORE_K*CL->nomatch); + } +int get_dp_cost ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) + { + int MODE=0; + int score; + + + + if (A==NULL)return 0; + + if (MODE!=2 || MODE==0 || (!CL->residue_index && CL->M) || (!CL->residue_index && CL->T)|| ns1==1 || ns2==1) + score=slow_get_dp_cost ( A, pos1, ns1, list1,col1, pos2, ns2, list2, col2, CL); + else if (MODE==1 || MODE==2) + score=fast_get_dp_cost ( A, pos1, ns1, list1,col1, pos2, ns2, list2, col2, CL); + else + score=0; + + + + return (score==UNDEFINED)?UNDEFINED:(score-SCORE_K*CL->nomatch); + } +int ***make_cw_lu (int **cons, int l, Constraint_list *CL); +int ***make_cw_lu (int **cons, int l, Constraint_list *CL) +{ + int ***lu; + int p, a,r; + + lu=declare_arrayN(3, sizeof (int),l,26, 2); + for ( p=0; pM[r][cons[p][a]-'A']; + lu[p][r][1]+=cons[p][a+1]; + } + } + } + return lu; +} + +int cw_profile_get_dp_cost ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) +{ + static int last_tag; + static int *pr, ***lu; + int score; + static int *list[2], ns[2], **cons[2], ref; + int eva_col,ref_col, a, p, r; + float t1, t2; + + + + + if (last_tag!=A->random_tag) + { + int n1, n2; + + last_tag=A->random_tag; + list[0]=list1;ns[0]=ns1; + list[1]=list2;ns[1]=ns2; + free_int (cons[0],-1);free_int (cons[1],-1);free_arrayN((void*)lu,3); + cons[0]=NULL;cons[1]=NULL;lu=NULL; + + n1=sub_aln2nseq_prf (A, ns[0], list[0]); + n2=sub_aln2nseq_prf (A, ns[1], list[1]); + if ( n1>1 || n2>1) + { + cons[0]=sub_aln2count_mat2 (A, ns[0], list[0]); + cons[1]=sub_aln2count_mat2 (A, ns[1], list[1]); + ref=(ns[0]>ns[1])?0:1; + lu=make_cw_lu(cons[ref],(int)strlen(A->seq_al[list[ref][0]]), CL); + } + } + + if (!lu) + { + char r1, r2; + r1=A->seq_al[list1[0]][col1]; + r2=A->seq_al[list2[0]][col2]; + if ( r1!='-' && r2!='-') + return CL->M[r1-'A'][r2-'A']*SCORE_K -SCORE_K*CL->nomatch; + else + return -SCORE_K*CL->nomatch; + } + else + { + eva_col= (ref==0)?col2:col1; + ref_col= (ref==0)?col1:col2; + pr=cons[1-ref][eva_col]; + t1=t2=0; + for (a=3; a< pr[1]; a+=3) + { + r=tolower(pr[a]); + p= pr[a+1]; + + t1+=lu[ref_col][r-'a'][0]*p; + t2+=lu[ref_col][r-'a'][1]*p; + } + score=(t2==0)?0:(t1*SCORE_K)/t2; + score -=SCORE_K*CL->nomatch; + return score; + } +} +int cw_profile_get_dp_cost_old ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) +{ + static int last_tag; + static int **cons1, **cons2; + int score; + + + if (last_tag!=A->random_tag) + { + last_tag=A->random_tag; + free_int (cons1,-1);free_int (cons2,-1); + cons1=sub_aln2count_mat2 (A, ns1, list1); + cons2=sub_aln2count_mat2 (A, ns2, list2); + } + score=cw_profile_profile (cons1[col1], cons2[col2], CL)-SCORE_K*CL->nomatch; + return score; +} + +int cw_profile_get_dp_cost_window ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) +{ + static int last_tag; + static int **cons1, **cons2; + int a, score, window_size=5, n, p1, p2; + + + if (last_tag!=A->random_tag) + { + last_tag=A->random_tag; + free_int (cons1,-1);free_int (cons2,-1); + cons1=sub_aln2count_mat2 (A, ns1, list1); + cons2=sub_aln2count_mat2 (A, ns2, list2); + } + + for (n=0,score=0,a=0; anomatch; + n++; + } + if (n>0)score/=n; + + return score; + } + +int consensus_get_dp_cost ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) + { + static int last_tag; + static char *seq1, *seq2; + + + /*Works only with matrix*/ + if (last_tag !=A->random_tag) + { + int ls1, ls2, lenls1, lenls2; + + last_tag=A->random_tag; + vfree (seq1);vfree (seq2); + seq1=sub_aln2cons_seq_mat (A, ns1, list1, "blosum62mt"); + seq2=sub_aln2cons_seq_mat (A, ns2, list2, "blosum62mt"); + ls1=list1[ns1-1];ls2=list2[ns2-1]; + lenls1=(int)strlen (A->seq_al[ls1]); lenls2=(int)strlen (A->seq_al[ls2]); + } + + return (CL->M[seq1[col1]-'A'][seq2[col2]-'A']*SCORE_K)-SCORE_K*CL->nomatch; + } + +int fast_get_dp_cost_quadruplet ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) + { + /*WARNING: WORKS ONLY WITH List to Extend*/ + /*That function does a quruple extension beween two columns by pooling the residues together*/ + + double score=0; + + int a,b, c; + int n_gap1=0; + int n_gap2=0; + + int s1, rs1, r1, t_r, t_s,t_w, q_r, q_s, q_w, s2, rs2, r2; + int **buf_pos, buf_ns, *buf_list, buf_col; + + static int **hasch1; + static int **hasch2; + + static int **n_hasch1; + static int **n_hasch2; + + static int **is_in_col1; + static int **is_in_col2; + + + if (ns2>ns1) + { + buf_pos=pos1; + buf_ns=ns1; + buf_list=list1; + buf_col=col1; + + pos1=pos2; + ns1=ns2; + list1=list2; + col1=col2; + + pos2=buf_pos; + ns2=buf_ns; + list2=buf_list; + col2=buf_col; + } + + + if ( !hasch1) + { + + hasch1=declare_int( (CL->S)->nseq, (CL->S)->max_len+1); + hasch2=declare_int( (CL->S)->nseq, (CL->S)->max_len+1); + n_hasch1=declare_int ( (CL->S)->nseq, (CL->S)->max_len+1); + n_hasch2=declare_int( (CL->S)->nseq, (CL->S)->max_len+1); + is_in_col1=declare_int( (CL->S)->nseq, (CL->S)->max_len+1); + is_in_col2=declare_int( (CL->S)->nseq, (CL->S)->max_len+1); + } + + for ( a=0; a< ns1; a++) + { + rs1= list1[a]; + s1=A->order[rs1][0]; + r1=pos1[rs1][col1]; + + if (r1<0)n_gap1++; + else + { + is_in_col1[s1][r1]=1; + for (b=1; b< CL->residue_index[s1][r1][0]; b+=ICHUNK) + { + t_s=CL->residue_index[s1][r1][b+SEQ2]; + t_r=CL->residue_index[s1][r1][b+R2]; + t_w=CL->residue_index[s1][r1][b+WE]; + for ( c=1; c< CL->residue_index[t_s][t_r][0]; c+=ICHUNK) + { + q_s=CL->residue_index[t_s][t_r][c+SEQ2]; + q_r=CL->residue_index[t_s][t_r][c+R2]; + q_w=CL->residue_index[t_s][t_r][c+WE]; + hasch1[q_s][q_r]+=MIN(q_w, t_w); + n_hasch1[q_s][q_r]++; + } + } + } + } + + for ( a=0; a< ns2; a++) + { + rs2=list2[a]; + s2=A->order[rs2][0]; + r2=pos2[rs2][col2]; + + if (r2<0)n_gap2++; + else + { + is_in_col2[s2][r2]=1; + for (b=1; b< CL->residue_index[s2][r2][0]; b+=ICHUNK) + { + t_s=CL->residue_index[s2][r2][b+SEQ2]; + t_r=CL->residue_index[s2][r2][b+R2]; + t_w=CL->residue_index[s2][r2][b+WE]; + for ( c=1; c< CL->residue_index[t_s][t_r][0]; c+=ICHUNK) + { + q_s=CL->residue_index[t_s][t_r][c+SEQ2]; + q_r=CL->residue_index[t_s][t_r][c+R2]; + q_w=CL->residue_index[t_s][t_r][c+WE]; + hasch2[q_s][q_r]+=MIN(t_w, q_w); + n_hasch2[q_s][q_r]++; + } + } + } + } + + + for ( a=0; a< ns2; a++) + { + rs2=list2[a]; + s2=A->order[rs2][0]; + r2=pos1[rs2][col2]; + + if (r2<0); + else + { + for (b=1; b< CL->residue_index[s2][r2][0]; b+=ICHUNK) + { + t_s=CL->residue_index[s2][r2][b+SEQ2]; + t_r=CL->residue_index[s2][r2][b+R2]; + + for ( c=1; c< CL->residue_index[t_s][t_r][0]; c+=ICHUNK) + { + q_s=CL->residue_index[t_s][t_r][c+SEQ2]; + q_r=CL->residue_index[t_s][t_r][c+R2]; + if ( hasch2[q_s][q_r] && hasch1[q_s][q_r]&& !(is_in_col1[q_s][q_r] || is_in_col2[q_s][q_r])) + { + score+=MIN(hasch2[q_s][q_r]*(n_hasch1[q_s][q_r]),hasch1[q_s][q_r]*(n_hasch2[q_s][q_r])); + } + else if ( hasch2[q_s][q_r] && is_in_col1[q_s][q_r]) + { + score+=hasch2[q_s][q_r]*(n_hasch1[q_s][q_r]+1); + } + else if (hasch1[q_s][q_r] && is_in_col2[q_s][q_r]) + { + score+=hasch1[q_s][q_r]*(n_hasch2[q_s][q_r]+1); + } + hasch2[q_s][q_r]=0; + n_hasch2[q_s][q_r]=0; + } + } + hasch2[s2][r2]=0; + is_in_col2[s2][r2]=0; + } + } + + + for ( a=0; a< ns1; a++) + { + rs1= list1[a]; + s1=A->order[rs1][0]; + r1=pos1[rs1][col1]; + + if (r1<0); + else + { + is_in_col1[s1][r1]=0; + hasch1[s1][r1]=0; + for (b=1; b< CL->residue_index[s1][r1][0]; b+=ICHUNK) + { + t_s=CL->residue_index[s1][r1][b+SEQ2]; + t_r=CL->residue_index[s1][r1][b+R2]; + for ( c=1; c< CL->residue_index[t_s][t_r][0]; c+=ICHUNK) + { + q_s=CL->residue_index[t_s][t_r][c+SEQ2]; + q_r=CL->residue_index[t_s][t_r][c+R2]; + hasch1[q_s][q_r]=0; + n_hasch1[q_s][q_r]=0; + } + } + } + } + + + score=(score*SCORE_K)/((ns1-n_gap1)*(ns2-n_gap2)); + score=(CL->normalise)?((score*CL->normalise)/CL->max_ext_value):score; + + return (int)(score-SCORE_K*CL->nomatch); + } + + +int fast_get_dp_cost ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) + { + /*WARNING: WORKS ONLY WITH List to Extend*/ + + double score=0; + + int a,b; + int n_gap1=0; + int n_gap2=0; + + int s1, rs1, r1, t_r, t_s, s2, rs2, r2; + static int **hasch1; + static int **hasch2; + + static int **n_hasch1; + static int **n_hasch2; + + static int **is_in_col1; + static int **is_in_col2; + + + + + if ( !hasch1) + { + + hasch1=declare_int( (CL->S)->nseq, (CL->S)->max_len+1); + hasch2=declare_int( (CL->S)->nseq, (CL->S)->max_len+1); + n_hasch1=declare_int ( (CL->S)->nseq, (CL->S)->max_len+1); + n_hasch2=declare_int( (CL->S)->nseq, (CL->S)->max_len+1); + is_in_col1=declare_int( (CL->S)->nseq, (CL->S)->max_len+1); + is_in_col2=declare_int( (CL->S)->nseq, (CL->S)->max_len+1); + } + + for ( a=0; a< ns1; a++) + { + rs1= list1[a]; + s1=A->order[rs1][0]; + r1=pos1[rs1][col1]; + + if (r1<0)n_gap1++; + else + { + is_in_col1[s1][r1]=1; + for (b=1; b< CL->residue_index[s1][r1][0]; b+=ICHUNK) + { + t_s=CL->residue_index[s1][r1][b+SEQ2]; + t_r=CL->residue_index[s1][r1][b+R2]; + hasch1[t_s][t_r]+=CL->residue_index[s1][r1][b+WE]; + n_hasch1[t_s][t_r]++; + } + } + } + + + for ( a=0; a< ns2; a++) + { + rs2=list2[a]; + s2=A->order[rs2][0]; + r2=pos2[rs2][col2]; + + if (r2<0)n_gap2++; + else + { + is_in_col2[s2][r2]=1; + for (b=1; b< CL->residue_index[s2][r2][0]; b+=ICHUNK) + { + t_s=CL->residue_index[s2][r2][b+SEQ2]; + t_r=CL->residue_index[s2][r2][b+R2]; + + hasch2[t_s][t_r]+=CL->residue_index[s2][r2][b+WE]; + n_hasch2[t_s][t_r]++; + } + } + } + /*return 2;*/ + + if ( ns2order[rs2][0]; + r2=pos1[rs2][col2]; + + if (r2<0); + else + { + for (b=1; b< CL->residue_index[s2][r2][0]; b+=ICHUNK) + { + t_s=CL->residue_index[s2][r2][b+SEQ2]; + t_r=CL->residue_index[s2][r2][b+R2]; + + if ( hasch2[t_s][t_r] && hasch1[t_s][t_r]&& !(is_in_col1[t_s][t_r] || is_in_col2[t_s][t_r])) + { + score+=MIN(hasch2[t_s][t_r]*(n_hasch1[t_s][t_r]),hasch1[t_s][t_r]*(n_hasch2[t_s][t_r])); + } + else if ( hasch2[t_s][t_r] && is_in_col1[t_s][t_r]) + { + score+=hasch2[t_s][t_r]*(n_hasch1[t_s][t_r]+1); + } + else if (hasch1[t_s][t_r] && is_in_col2[t_s][t_r]) + { + score+=hasch1[t_s][t_r]*(n_hasch2[t_s][t_r]+1); + } + hasch2[t_s][t_r]=0; + n_hasch2[t_s][t_r]=0; + } + hasch2[s2][r2]=0; + is_in_col2[s2][r2]=0; + } + } + + + for ( a=0; a< ns1; a++) + { + rs1= list1[a]; + s1=A->order[rs1][0]; + r1=pos1[rs1][col1]; + + if (r1<0); + else + { + is_in_col1[s1][r1]=0; + hasch1[s1][r1]=0; + for (b=1; b< CL->residue_index[s1][r1][0]; b+=ICHUNK) + { + t_s=CL->residue_index[s1][r1][b+SEQ2]; + t_r=CL->residue_index[s1][r1][b+R2]; + + hasch1[t_s][t_r]=0; + n_hasch1[t_s][t_r]=0; + } + } + } + } + else + { + for ( a=0; a< ns1; a++) + { + rs1=list1[a]; + s1=A->order[rs1][0]; + r1=pos1[rs1][col1]; + + if (r1<0); + else + { + for (b=1; b< CL->residue_index[s1][r1][0]; b+=ICHUNK) + { + t_s=CL->residue_index[s1][r1][b+SEQ2]; + t_r=CL->residue_index[s1][r1][b+R2]; + + if ( hasch1[t_s][t_r] && hasch2[t_s][t_r]&& !(is_in_col2[t_s][t_r] || is_in_col1[t_s][t_r])) + { + score+=MIN(hasch1[t_s][t_r]*(n_hasch2[t_s][t_r]),hasch2[t_s][t_r]*(n_hasch1[t_s][t_r])); + } + else if ( hasch1[t_s][t_r] && is_in_col2[t_s][t_r]) + { + score+=hasch1[t_s][t_r]*(n_hasch2[t_s][t_r]+1); + } + else if (hasch2[t_s][t_r] && is_in_col1[t_s][t_r]) + { + score+=hasch2[t_s][t_r]*(n_hasch1[t_s][t_r]+1); + } + hasch1[t_s][t_r]=0; + n_hasch1[t_s][t_r]=0; + } + hasch1[s1][r1]=0; + is_in_col1[s1][r1]=0; + } + } + + + for ( a=0; a< ns2; a++) + { + rs2= list2[a]; + s2=A->order[rs2][0]; + r2=pos1[rs2][col2]; + + if (r2<0); + else + { + is_in_col2[s2][r2]=0; + hasch1[s2][r2]=0; + for (b=1; b< CL->residue_index[s2][r2][0]; b+=ICHUNK) + { + t_s=CL->residue_index[s2][r2][b+SEQ2]; + t_r=CL->residue_index[s2][r2][b+R2]; + + hasch2[t_s][t_r]=0; + n_hasch2[t_s][t_r]=0; + } + } + } + } + score=(score*SCORE_K)/((ns1-n_gap1)*(ns2-n_gap2)); + score=(CL->normalise)?((score*CL->normalise)/CL->max_ext_value):score; + + return (int)(score-SCORE_K*CL->nomatch); + } + +int fast_get_dp_cost_2 ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) + { + double score=0; + + int a, b, s1, s2,r1, r2; + static int n_pair; + + int s; + int res_res=0; + int rs1, rs2; + static int last_ns1; + static int last_ns2; + static int last_top1; + static int last_top2; + static int **check_list; + + + /*New heuristic get dp_cost on a limited number of pairs*/ + /*This is the current default*/ + + + if ( last_ns1==ns1 && last_top1==list1[0] && last_ns2==ns2 && last_top2==list2[0]); + else + { + + + last_ns1=ns1; + last_ns2=ns2; + last_top1=list1[0]; + last_top2=list2[0]; + if ( check_list) free_int (check_list, -1); + check_list=declare_int ( (CL->S)->nseq*(CL->S)->nseq, 3); + + for ( n_pair=0,a=0; a< ns1; a++) + { + s1 =list1[a]; + rs1=A->order[s1][0]; + for ( b=0; b< ns2; b++, n_pair++) + { + s2 =list2[b]; + rs2=A->order[s2][0]; + check_list[n_pair][0]=s1; + check_list[n_pair][1]=s2; + check_list[n_pair][2]=(!CL->DM)?0:(CL->DM)->similarity_matrix[rs1][rs2]; + } + sort_int ( check_list, 3, 2, 0, n_pair-1); + } + } + + if ( !CL->evaluate_residue_pair){fprintf ( stderr, "\nWARNING: CL->evaluate_residue_pair Not set\nSet to: extend_residue_pair\n");CL->evaluate_residue_pair= extend_residue_pair;} + + + for ( a=n_pair-1; a>=0; a--) + { + s1= check_list[a][0]; + rs1=A->order[s1][0]; + r1 =pos1[s1][col1]; + + s2= check_list[a][1]; + rs2=A->order[s2][0]; + r2 =pos2[s2][col2]; + + if ( r1>0 && r2 >0) + {res_res++;} + if ( rs1>rs2) + { + SWAP (rs1, rs2); + SWAP (r1, r2); + } + + if ((s=(CL->evaluate_residue_pair)(CL, rs1, r1, rs2, r2))!=UNDEFINED) score+=s; + else + { + + return UNDEFINED; + } + if ( res_res>=CL->max_n_pair && CL->max_n_pair!=0)a=0; + } + + score=(res_res==0)?0:( (score)/res_res); + score=score-SCORE_K*CL->nomatch; + + return (int)score; + } + + + + +int slow_get_dp_cost ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) + { + double score=0; + + int a, b, s1, s2,r1, r2; + int s; + int gap_gap=0; + int gap_res=0; + int res_res=0; + int rs1, rs2; + static int last_tag; + static int *dummy; + + if (col1<0 || col2<0) return 0; + if ( last_tag !=A->random_tag) + { + last_tag=A->random_tag; + if (!dummy) + { + dummy=vcalloc (10, sizeof(int)); + dummy[0]=1;/*Number of Amino acid types on colum*/ + dummy[1]=5;/*Length of Dummy*/ + dummy[3]='\0';/*Amino acid*/ + dummy[4]=1; /*Number of occurences*/ + dummy[5]=100; /*Frequency in the MSA column*/ + } + } + + if ( !CL->evaluate_residue_pair){fprintf ( stderr, "\nWARNING: CL->evaluate_residue_pair Not set\nSet to: extend_residue_pair\n");CL->evaluate_residue_pair= extend_residue_pair;} + + for ( a=0; a< ns1; a++) + { + for ( b=0; border[s1][0]; + r1 =pos1[s1][col1]; + + s2 =list2[b]; + rs2=A->order[s2][0]; + r2 =pos2[s2][col2]; + + if ( rs1>rs2) + { + SWAP (rs1, rs2); + SWAP (r1, r2); + } + + if (r1==0 && r2==0)gap_gap++; + else if ( r1<0 || r2<0) gap_res++; + else + { + res_res++; + if ((s=(CL->evaluate_residue_pair)(CL, rs1, r1, rs2, r2))!=UNDEFINED) score+=s; + else + { + + return UNDEFINED; + } + } + + } + } + + + score=(res_res==0)?0:( (score)/res_res); + + return score-SCORE_K*CL->nomatch; + + } +int slow_get_dp_cost_pc ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) + { + double score=0; + + int a, b, s1, s2,r1, r2; + int s; + int gap_gap=0; + int gap_res=0; + int res_res=0; + int rs1, rs2; + static int last_tag; + static int *dummy; + + if (col1<0 || col2<0) return 0; + if ( last_tag !=A->random_tag) + { + last_tag=A->random_tag; + if (!dummy) + { + dummy=vcalloc (10, sizeof(int)); + dummy[0]=1;/*Number of Amino acid types on colum*/ + dummy[1]=5;/*Length of Dummy*/ + dummy[3]='\0';/*Amino acid*/ + dummy[4]=1; /*Number of occurences*/ + dummy[5]=100; /*Frequency in the MSA column*/ + } + } + + if ( !CL->evaluate_residue_pair){fprintf ( stderr, "\nWARNING: CL->evaluate_residue_pair Not set\nSet to: extend_residue_pair\n");CL->evaluate_residue_pair= extend_residue_pair;} + + for ( a=0; a< ns1; a++) + { + for ( b=0; border[s1][0]; + r1 =pos1[s1][col1]; + + s2 =list2[b]; + rs2=A->order[s2][0]; + r2 =pos2[s2][col2]; + + if ( rs1>rs2) + { + SWAP (rs1, rs2); + SWAP (r1, r2); + } + + if (r1==0 && r2==0)gap_gap++; + else if ( r1<0 || r2<0) gap_res++; + else + { + res_res++; + if ((s=residue_pair_extended_list_pc(CL, rs1, r1, rs2, r2))!=UNDEFINED) score+=s; + else + { + + return UNDEFINED; + } + } + + } + } + + + score=(res_res==0)?0:( (score)/res_res); + + return score; + + } +int slow_get_dp_cost_test ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) + { + double score=0; + + int a, b, s1, s2,r1, r2; + int gap_gap=0, gap_res=0, res_res=0, rs1, rs2; + + for ( a=0; a< ns1; a++) + { + for ( b=0; border[s1][0]; + r1 =pos1[s1][col1]; + + s2 =list2[b]; + rs2=A->order[s2][0]; + r2 =pos2[s2][col2]; + + if ( rs1>rs2) + { + SWAP (rs1, rs2); + SWAP (r1, r2); + } + + if (r1==0 && r2==0)gap_gap++; + else if ( r1<0 || r2<0) gap_res++; + else + { + res_res++; + score+=residue_pair_extended_list_raw (CL, rs1, r1, rs2, r2); + } + } + } + + return (int)(score*10)/(ns1*ns2); + } + +int sw_get_dp_cost ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) + { + int a, b; + int s1,r1,rs1; + int s2,r2,rs2; + + + + + for ( a=0; a< ns1; a++) + { + s1 =list1[a]; + rs1=A->order[s1][0]; + r1 =pos1[s1][col1]; + if ( r1<=0)continue; + for ( b=0; b< ns2; b++) + { + + + s2 =list2[b]; + rs2=A->order[s2][0]; + r2 =pos2[s2][col2]; + + if (r2<=0)continue; + + + if (sw_pair_is_defined (CL, rs1, r1, rs2, r2)==UNDEFINED)return UNDEFINED; + } + } + + return slow_get_dp_cost ( A, pos1, ns1, list1, col1, pos2, ns2, list2,col2, CL); + + } + + + + + + + + +int get_domain_dp_cost ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2,Constraint_list *CL , int scale , int gop, int gep) + + { + int a, b, s1, s2,r1, r2; + static int *entry; + int *r; + int score=0; + int gap_gap=0; + int gap_res=0; + int res_res=0; + int rs1, rs2; + int flag_list_is_aa_sub_mat=0; + int p; + +/*Needs to be cleanned After Usage*/ + + + + if ( entry==NULL) entry=vcalloc (LIST_N_FIELDS , sizeof (int)); + + for (a=0; a< ns1; a++) + { + s1=list1[a]; + rs1=A->order[s1][0]; + for ( b=0; border[s2][0]; + + entry[SEQ1]=rs1; + entry[SEQ2]=rs2; + r1=entry[R1]=pos1[s1][col1]; + r2=entry[R2]=pos2[s2][col2]; + + if ( !flag_list_is_aa_sub_mat) + { + if ( r1==r2 && rs1==rs2) + { + + return UNDEFINED; + } + else if (r1==0 && r2==0) + { + gap_gap++; + } + else if ( r1<=0 || r2<=0) + { + gap_res++; + } + else if ((r=main_search_in_list_constraint ( entry,&p,4,CL))!=NULL) + { + res_res++; + + if (r[WE]!=UNDEFINED) + { + score+=(r[WE]*SCORE_K)+scale; + } + else + { + fprintf ( stderr, "**"); + return UNDEFINED; + } + } + } + } + } + return score; + score=((res_res+gap_res)==0)?0:score/(res_res+gap_res); + return score; + } + +/*********************************************************************************************/ +/* */ +/* FUNCTIONS FOR ANALYSING AL OR MATRIX */ +/* */ +/*********************************************************************************************/ + +int aln2n_res ( Alignment *A, int start, int end) + { + int a, b; + int score=0; + + for ( a=start; anseq; b++)score+=!is_gap(A->seq_al[b][a]); + return score; + } + +float get_gop_scaling_factor ( int **matrix,float id, int l1, int l2) + { + return id* get_avg_matrix_mm(matrix, AA_ALPHABET); + } + +float get_avg_matrix_mm ( int **matrix, char *alphabet) + { + int a, b; + float naa; + float gop; + int l; + + + l=MIN(20,(int)strlen (alphabet)); + for (naa=0, gop=0,a=0; a=0){naa++;tot+=matrix[alphabet[a]-'A'][alphabet[b]-'A'];} + + } + return tot/naa; +} + +float measure_matrix_enthropy (int **matrix,char *alphabet) + { + + int a, b; + double s, p, q, h=0, tq=0; + float lambda; + float *frequency; + /*frequencies tqken from psw*/ + + frequency=set_aa_frequencies (); + + + lambda=compute_lambda(matrix,alphabet); + fprintf ( stderr, "\nLambda=%f", (float)lambda); + + for ( a=0; a< 20; a++) + for ( b=0; b<=a; b++) + { + s=matrix[alphabet[a]-'A'][alphabet[b]-'A']; + + + p=frequency[alphabet[a]-'A']*frequency[alphabet[b]-'A']; + + if ( p==0)continue; + + q=exp(lambda*s+log(p)); + + tq+=q; + h+=q*log(q/p)*log(2); + + } + + fprintf ( stderr,"\ntq=%f\n", (float)tq); + + return (float) h; + } +float compute_lambda (int **matrix,char *alphabet) +{ + + int a, b; + double lambda, best_lambda=0, delta, best_delta=0, p, tq,s; + static float *frequency; + + if ( !frequency)frequency=set_aa_frequencies (); + + for ( lambda=0.001; lambda<1; lambda+=0.005) + { + tq=0; + for ( a=0; a< 20; a++) + for ( b=0; b<20; b++) + { + p=frequency[alphabet[a]-'A']*frequency[alphabet[b]-'A']; + s=matrix[alphabet[a]-'A'][alphabet[b]-'A']; + tq+=exp(lambda*s+log(p)); + } + delta=fabs(1-tq); + if (lambda==0.001) + { + best_delta=delta; + best_lambda=lambda; + } + else + { + if (delta1)break; + } + fprintf ( stderr, "\nRESULT: %f %f ", best_lambda, best_delta); + return (float) best_lambda; +} + + + +float evaluate_random_match (char *mat, int n, int len,char *alp) +{ + int **matrix; + matrix=read_matrice ( mat); + fprintf ( stderr, "Matrix=%15s ", mat); + return evaluate_random_match2 (matrix, n,len,alp); + +} + +float evaluate_random_match2 (int **matrix, int n, int len,char *alp) +{ + int a, b, c, d, c1, c2, tot; + static int *list; + static float *freq; + float score_random=0; + float score_id=0; + float score_good=0; + float tot_len=0; + float tot_try=0; + + + if ( !list) + { + vsrand(0); + freq=set_aa_frequencies (); + list=vcalloc ( 10000, sizeof (char)); + } + + for (tot=0,c=0,a=0;a<20; a++) + { + b=freq[alp[a]-'A']*1000; + tot+=b; + for (d=0; d=0){score_good+=matrix[list[c1]-'A'][list[c2]-'A']; tot_len++;} + } + + + score_random=score_random/tot_len; + score_id=score_id/tot_len; + score_good=score_good/tot_len; + + fprintf ( stderr, "Random=%8.3f Id=%8.3f Good=%8.3f [%7.2f]\n",score_random, score_id, score_good, tot_len/tot_try); + + return score_random; +} +float compare_two_mat (char *mat1,char*mat2, int n, int len,char *alp) +{ + int **matrix1, **matrix2; + + evaluate_random_match (mat1, n, len,alp); + evaluate_random_match (mat2, n, len,alp); + matrix1=read_matrice ( mat1); + matrix2=read_matrice ( mat2); + matrix1=rescale_matrix(matrix1, 10, alp); + matrix2=rescale_matrix(matrix2, 10, alp); + compare_two_mat_array(matrix1,matrix2, n, len,alp); + return 0; +} + + +int ** rescale_two_mat (char *mat1,char*mat2, int n, int len,char *alp) +{ + float lambda; + int **matrix1, **matrix2; + + lambda=measure_lambda2 (mat1, mat2, n, len, alp)*10; + + fprintf ( stderr, "\nLambda=%.2f", lambda); + matrix2=read_matrice(mat2); + matrix2=neg_matrix2pos_matrix(matrix2); + matrix2=rescale_matrix( matrix2, lambda,"abcdefghiklmnpqrstvwxyz"); + + matrix1=read_matrice(mat1); + matrix1=neg_matrix2pos_matrix(matrix1); + matrix1=rescale_matrix( matrix1,10,"abcdefghiklmnpqrstvwxyz"); + + output_matrix_header ( "stdout", matrix2, alp); + evaluate_random_match2(matrix1, 1000, 100, alp); + evaluate_random_match2(matrix2, 1000, 100, alp); + compare_two_mat_array(matrix1,matrix2, n, len,alp); + + return matrix2; +} +float measure_lambda2(char *mat1,char*mat2, int n, int len,char *alp) +{ + int **m1, **m2; + float f1, f2; + + m1=read_matrice (mat1); + m2=read_matrice (mat2); + + m1=neg_matrix2pos_matrix(m1); + m2=neg_matrix2pos_matrix(m2); + + f1=measure_matrix_pos_avg( m1, alp); + f2=measure_matrix_pos_avg( m2, alp); + + return f1/f2; +} + + +float measure_lambda (char *mat1,char*mat2, int n, int len,char *alp) +{ + int c; + int **matrix1, **matrix2, **mat; + float a; + float best_quality=0, quality=0, best_lambda=0; + + matrix1=read_matrice ( mat1); + matrix2=read_matrice ( mat2); + matrix1=rescale_matrix(matrix1, 10, alp); + matrix2=rescale_matrix(matrix2, 10, alp); + + for (c=0, a=0.1; a< 2; a+=0.05) + { + fprintf ( stderr, "Lambda=%.2f\n", a); + mat=duplicate_int (matrix2,-1,-1); + mat=rescale_matrix(mat, a, alp); + quality=compare_two_mat_array(matrix1,mat, n, len,alp); + quality=MAX((-quality),quality); + + if (c==0 || (best_quality>quality)) + { + c=1; + fprintf ( stderr, "*"); + best_quality=quality; + best_lambda=a; + } + + + evaluate_random_match2(mat, 1000, 100, alp); + evaluate_random_match2(matrix1, 1000, 100, alp); + free_int (mat, -1); + } + + return best_lambda; + +} + +float compare_two_mat_array (int **matrix1,int **matrix2, int n, int len,char *alp) +{ + int a, b, c, d, c1, c2, tot; + static int *list; + static float *freq; + float delta_random=0; + float delta2_random=0; + + float delta_id=0; + float delta2_id=0; + + float delta_good=0; + float delta2_good=0; + + float delta; + + float tot_len=0; + float tot_try=0; + + + + if ( !list) + { + vsrand(0); + freq=set_aa_frequencies (); + list=vcalloc ( 10000, sizeof (char)); + } + + for (tot=0,c=0,a=0;a<20; a++) + { + b=freq[alp[a]-'A']*1000; + tot+=b; + for (d=0; d=0 || matrix2[list[c1]-'A'][list[c2]-'A'] ) + { + delta=matrix1[list[c1]-'A'][list[c2]-'A']-matrix2[list[c1]-'A'][list[c2]-'A']; + delta_good+=delta; + delta2_good+=MAX(delta,(-delta)); + tot_len++; + } + } + + + delta_random=delta_random/tot_len; + delta2_random=delta2_random/tot_len; + + + delta_id=delta_id/tot_len; + delta2_id=delta2_id/tot_len; + + delta_good=delta_good/tot_len; + delta2_good=delta2_good/tot_len; + + + fprintf ( stderr, "\tRand=%8.3f %8.3f\n\tId =%8.3f %8.3f\n\tGood=%8.3f %8.3f\n",delta_random, delta2_random, delta_id,delta2_id, delta_good,delta2_good); + + return delta_good; +} + + + +int ** rescale_matrix ( int **matrix, float lambda, char *alp) +{ + int a, b; + + + for ( a=0; a< 20; a++) + for ( b=0; b< 20; b++) + { + matrix[alp[a]-'A'][alp[b]-'A']= matrix[alp[a]-'A'][alp[b]-'A']*lambda; + } + return matrix; +} +int **mat2inverted_mat (int **matrix, char *alp) +{ + int a, b, min, max, v,l; + int c1,c2, C1, C2; + + l=(int)strlen (alp); + min=max=matrix[alp[0]-'A'][alp[0]-'A']; + for ( a=0; amax)?p[a][b]:max; + } + for (b='a'; b<='z'; b++) + { + p[a][b]=((p[a][b]-min)/(max-min))*10; + + } + } + + return p; +} +Constraint_list * choose_extension_mode ( char *extend_mode, Constraint_list *CL) +{ + //evaluation_functions: residues start at 1, sequences at 0; + + if ( !CL) + { + fprintf ( stderr, "\nWarning: CL was not set"); + return CL; + } + else if ( strm ( extend_mode, "rna0")) + { + CL->evaluate_residue_pair=residue_pair_extended_list; + CL->get_dp_cost =slow_get_dp_cost; + } + else if ( strm ( extend_mode, "rna1") || strm (extend_mode, "rna")) + { + CL->evaluate_residue_pair=residue_pair_extended_list4rna1; + CL->get_dp_cost =slow_get_dp_cost; + } + else if ( strm ( extend_mode, "rna2")) + { + CL->evaluate_residue_pair=residue_pair_extended_list4rna2; + CL->get_dp_cost =slow_get_dp_cost; + } + else if ( strm ( extend_mode, "rna3")) + { + CL->evaluate_residue_pair=residue_pair_extended_list4rna3; + CL->get_dp_cost =slow_get_dp_cost; + } + else if ( strm ( extend_mode, "rna4")) + { + CL->evaluate_residue_pair=residue_pair_extended_list4rna4; + CL->get_dp_cost =slow_get_dp_cost; + } + else if ( strm ( extend_mode, "pc") && !CL->M) + { + CL->evaluate_residue_pair=residue_pair_extended_list_pc; + CL->get_dp_cost =slow_get_dp_cost; + } + else if ( strm ( extend_mode, "triplet") && !CL->M) + { + CL->evaluate_residue_pair=residue_pair_extended_list; + CL->get_dp_cost =get_dp_cost; + } + else if ( strm ( extend_mode, "relative_triplet") && !CL->M) + { + CL->evaluate_residue_pair=residue_pair_relative_extended_list; + CL->get_dp_cost =fast_get_dp_cost_2; + } + else if ( strm ( extend_mode, "g_coffee") && !CL->M) + { + CL->evaluate_residue_pair=residue_pair_extended_list_g_coffee; + CL->get_dp_cost =slow_get_dp_cost; + } + else if ( strm ( extend_mode, "g_coffee_quadruplets") && !CL->M) + { + CL->evaluate_residue_pair=residue_pair_extended_list_g_coffee_quadruplet; + CL->get_dp_cost =slow_get_dp_cost; + } + else if ( strm ( extend_mode, "fast_triplet") && !CL->M) + { + CL->evaluate_residue_pair=residue_pair_extended_list; + CL->get_dp_cost =fast_get_dp_cost; + } + + else if ( strm ( extend_mode, "very_fast_triplet") && !CL->M) + { + CL->evaluate_residue_pair=residue_pair_extended_list; + CL->get_dp_cost =fast_get_dp_cost_2; + } + else if ( strm ( extend_mode, "slow_triplet") && !CL->M) + { + CL->evaluate_residue_pair=residue_pair_extended_list; + CL->get_dp_cost =slow_get_dp_cost; + } + else if ( strm ( extend_mode, "mixt") && !CL->M) + { + CL->evaluate_residue_pair=residue_pair_extended_list_mixt; + CL->get_dp_cost=slow_get_dp_cost; + } + else if ( strm ( extend_mode, "quadruplet") && !CL->M) + { + CL->evaluate_residue_pair=residue_pair_extended_list_quadruplet; + CL->get_dp_cost =get_dp_cost_quadruplet; + } + else if ( strm ( extend_mode, "test") && !CL->M) + { + CL->evaluate_residue_pair=residue_pair_test_function; + CL->get_dp_cost =slow_get_dp_cost_test; + } + else if ( strm ( extend_mode, "ssp")) + { + + CL->evaluate_residue_pair=evaluate_ssp_matrix_score; + CL->get_dp_cost=slow_get_dp_cost; + CL->normalise=1; + } + else if ( strm ( extend_mode, "tm")) + { + + CL->evaluate_residue_pair=evaluate_tm_matrix_score; + CL->get_dp_cost=slow_get_dp_cost; + CL->normalise=1; + } + else if ( strm ( extend_mode, "matrix")) + { + + CL->evaluate_residue_pair=evaluate_matrix_score; + CL->get_dp_cost=cw_profile_get_dp_cost; + CL->normalise=1; + } + else if ( strm ( extend_mode, "curvature")) + { + CL->evaluate_residue_pair=evaluate_curvature_score; + CL->get_dp_cost=slow_get_dp_cost; + CL->normalise=1; + } + else if ( CL->M) + { + CL->evaluate_residue_pair=evaluate_matrix_score; + CL->get_dp_cost=cw_profile_get_dp_cost; + CL->normalise=1; + } + else + { + fprintf ( stderr, "\nERROR: %s is an unknown extend_mode[FATAL:%s]\n", extend_mode, PROGRAM); + myexit (EXIT_FAILURE); + } + + return CL; +} +int ** combine_two_matrices ( int **mat1, int **mat2) +{ + int naa, re1, re2, Re1, Re2, a, b, u, l; + + naa=(int)strlen (BLAST_AA_ALPHABET); + for ( a=0; a< naa; a++) + for ( b=0; b< naa; b++) + { + re1=BLAST_AA_ALPHABET[a]; + re2=BLAST_AA_ALPHABET[b]; + if (re1=='*' || re2=='*'); + else + { + + Re1=toupper(re1);Re2=toupper(re2); + re1-='A';re2-='A';Re1-='A';Re2-='A'; + + l=mat1[re1][re2]; + u=mat2[re1][re2]; + mat1[re1][re2]=mat2[re1][re2]=l; + mat2[Re1][Re2]=mat2[Re1][Re2]=u; + } + } + return mat1; +} + +/* Off the shelves evaluations */ +/*********************************************************************************************/ +/* */ +/* OFF THE SHELVES EVALUATION */ +/* */ +/*********************************************************************************************/ + + +int lat_sum_pair (Alignment *A, char *mat) +{ + int a,b,c, tot=0, v1, v2, score; + int **matrix; + + matrix=read_matrice (mat); + + for (a=0; anseq; a++) + for ( b=0; bnseq; b++) + { + for (c=1; clen_aln; c++) + { + char r11, r12; + + r11=A->seq_al[a][c-1]; + r12=A->seq_al[a][c]; + if (is_gap(r11) || is_gap(r12))continue; + else v1=matrix[r11-'A'][r12-'A']; + + r11=A->seq_al[b][c-1]; + r12=A->seq_al[b][c]; + if (is_gap(r11) || is_gap(r12))continue; + else v2=matrix[r11-'A'][r12-'A']; + + score+=(v1-v2)*(v1-v2); + tot++; + } + } + score=(100*score)/tot; + return (float)score; +} + + + +/* Off the shelves evaluations */ +/*********************************************************************************************/ +/* */ +/* OFF THE SHELVES EVALUATION */ +/* */ +/*********************************************************************************************/ + +int comp_pair ( int len,char *sa, char *sb, int seqA, int seqB,int *tgp_a, int *tgp_b,int gap_op,int gap_ex, int start, int end,int **matrix,int MODE); +int score_gap ( int len, char *sa, char *sb,int seqA, int seqB,int *tgp_a, int *tgp_b, int op, int ex, int start, int end, int MODE); +void evaluate_tgp_decoded_chromosome ( Alignment *A,int **TGP,int start, int end,int MODE); +int gap_type ( char a, char b); + + + +float sum_pair ( Alignment*A,char *mat_name, int gap_op, int gap_ex) + { + int a,b; + float pscore=0; + + int start, end; + static int **tgp; + double score=0; + int MODE=1; + int **matrix; + + matrix=read_matrice (mat_name); + matrix=mat2inverted_mat (matrix, "acdefghiklmnpqrstvwy"); + + start=0; + end=A->len_aln-1; + + if ( tgp==NULL) + tgp= declare_int (A->nseq,2); + + evaluate_tgp_decoded_chromosome ( A,tgp,start, end,MODE); + + for ( a=0; a< A->nseq-1; a++) + for (b=a+1; bnseq; b++) + { + pscore= comp_pair (A->len_aln,A->seq_al[a], A->seq_al[b],a, b,tgp[a], tgp[b],gap_op,gap_ex, start, end,matrix, MODE); + score+=pscore*100; + /*score+=(double)pscore*(int)(PARAM->OFP)->weight[A->order[a][0]][A->order[b][0]];*//*NO WEIGHTS*/ + } + + score=score/(A->nseq*A->nseq); + + return (float)score; + } + +int comp_pair ( int len,char *sa, char *sb, int seqA, int seqB,int *tgp_a, int *tgp_b,int gap_op,int gap_ex, int start, int end,int **matrix,int MODE) + { + int score=0, a, ex; + + + + if ( end-start>=0) + score+= score_gap (len, sa,sb, seqA, seqB,tgp_a, tgp_b, gap_op,gap_ex, start, end,MODE); + + ex=gap_ex; + + + for (a=start; a<=end; a++) + { + if ( is_gap(sa[a]) || is_gap(sb[a])) + { + if (is_gap(sa[a]) && is_gap(sb[a])); + else + { + + score +=ex; + } + } + else + { + score += matrix [sa[a]-'A'][sb[a]-'A']; + + } + } + return score; + } +int score_gap ( int len, char *sa, char *sb,int seqA, int seqB,int *tgp_a, int *tgp_b, int op, int ex, int start, int end, int MODE) + { + int a,b; + int ga=0,gb=0; + int score=0; + + + int right_gap, left_gap; + + + + + + int type; + int flag1=0; + int flag2=0; + int continue_loop; + int sequence_pattern[2][3]; + int null_gap; + int natural_gap=1; + + /*op= gor_gap_op ( 0,seqA, seqB, PARAM); + ex= gor_gap_ext ( 0, seqA, seqB, PARAM);*/ + + + + for (a=start; a<=end; ++a) + { + + type= gap_type ( sa[a], sb[a]); + + if ( type==2 && ga<=gb) + {++ga; + gb=0; + score += op; + } + else if (type==1 && ga >=gb) + { + ++gb; + ga=0; + score +=op; + } + else if (type==0) + { + ga++; + gb++; + } + + else if (type== -1) + ga=gb=0; + + + if (natural_gap==0) + { + if ( type== -1) + flag1=flag2=0; + else if ( type==0) + flag2=1; + else if ( (type==flag1) && flag2==1) + { + score+=op; + flag2=0; + } + else if ( (type!=flag1) && flag2==1) + { + flag1=type; + flag2=0; + } + else if ( flag2==0) + flag1=type; + } + } + /*gap_type -/-:0, X/X:-1 X/-:1, -/X:2*/ +/*evaluate the pattern of gaps*/ + + continue_loop=1; + sequence_pattern[0][0]=sequence_pattern[1][0]=0; + for ( a=start; a<=end && continue_loop==1; a++) + { + left_gap= gap_type ( sa[a], sb[a]); + if ( left_gap!= 0) + { + if ( left_gap==-1) + { + sequence_pattern[0][0]=sequence_pattern[1][0]=0; + continue_loop=0; + } + else + { + null_gap=0; + for (b=a; b<=end && continue_loop==1; b++) + {type=gap_type( sa[b], sb[b]); + if (type==0) + null_gap++; + if ( type!=left_gap && type !=0) + { + continue_loop=0; + sequence_pattern[2-left_gap][0]= b-a-null_gap; + sequence_pattern [1-(2-left_gap)][0]=0; + } + } + if ( continue_loop==1) + { + continue_loop=0; + sequence_pattern[2-left_gap][0]= b-a-null_gap; + sequence_pattern [1-(2-left_gap)][0]=0; + } + } + } + } + + sequence_pattern[0][2]=sequence_pattern[1][2]=1; + for ( a=start; a<=end; a++) + { + if ( !is_gap(sa[a])) + sequence_pattern[0][2]=0; + if ( !is_gap(sb[a])) + sequence_pattern[1][2]=0; + + } + continue_loop=1; + sequence_pattern[0][1]=sequence_pattern[1][1]=0; + for ( a=end; a>=start && continue_loop==1; a--) + { + right_gap= gap_type ( sa[a], sb[a]); + if ( right_gap!= 0) + { + if ( right_gap==-1) + { + sequence_pattern[0][1]=sequence_pattern[1][1]=0; + continue_loop=0; + } + else + { + null_gap=0; + for (b=a; b>=start && continue_loop==1; b--) + {type=gap_type( sa[b], sb[b]); + if ( type==0) + null_gap++; + if ( type!=right_gap && type !=0) + { + continue_loop=0; + sequence_pattern[2-right_gap][1]= a-b-null_gap; + sequence_pattern [1-(2-right_gap)][1]=0; + } + } + if ( continue_loop==1) + { + continue_loop=0; + sequence_pattern[2-right_gap][1]= a-b-null_gap; + sequence_pattern [1-(2-right_gap)][1]=0; + } + } + } + } + +/* +printf ( "\n*****************************************************"); +printf ( "\n%c\n%c", sa[start],sb[start]); +printf ( "\n%d %d %d",sequence_pattern[0][0] ,sequence_pattern[0][1], sequence_pattern[0][2]); +printf ( "\n%d %d %d",sequence_pattern[1][0] ,sequence_pattern[1][1], sequence_pattern[1][2]); +printf ( "\n*****************************************************"); +*/ + +/*correct the scoring*/ + + + if ( MODE==0) + { + if ( FABS(tgp_a[0])>1 && (FABS(tgp_a[0])>FABS( tgp_b[0]))) + score-= (sequence_pattern[0][0]>0)?op:0; + if ( FABS(tgp_b[0])>1 && (FABS(tgp_b[0])> FABS(tgp_a[0]))) + score-= (sequence_pattern[1][0]>0)?op:0; + } + else if ( MODE ==1 || MODE ==2) + { + if ( FABS(tgp_a[0])>1 && (FABS(tgp_a[0])>FABS( tgp_b[0])) && (tgp_a[1]!=1 || sequence_pattern[0][2]==0)) + score-= (sequence_pattern[0][0]>0)?op:0; + if ( FABS(tgp_b[0])>1 && (FABS(tgp_b[0])> FABS(tgp_a[0])) && (tgp_b[1]!=1 || sequence_pattern[1][2]==0)) + score-= (sequence_pattern[1][0]>0)?op:0; + + + if ( tgp_a[0]>=1 && tgp_a[0]==tgp_b[0]) + score -=(sequence_pattern[0][0]>0)?op:0; + if ( tgp_b[0]>=1 && tgp_a[0]==tgp_b[0]) + score-= (sequence_pattern[1][0]>0)?op:0; + + + if ( tgp_a[1]==1 && sequence_pattern[0][2]==0) + score -= ( sequence_pattern[0][1]>0)?op:0; + else if ( tgp_a[1]==1 && sequence_pattern[0][2]==1 && tgp_a[0]<=0) + score -= ( sequence_pattern[0][1]>0)?op:0; + + + if ( tgp_b[1]==1 && sequence_pattern[1][2]==0) + score -= ( sequence_pattern[1][1]>0)?op:0; + else if ( tgp_b[1]==1 && sequence_pattern[1][2]==1 && tgp_b[0]<=0) + score -= ( sequence_pattern[1][1]>0)?op:0; + + if ( MODE==2) + { + if ( tgp_a[0]>0) + score -=sequence_pattern[0][0]*ex; + if ( tgp_b[0]>0) + score -= sequence_pattern[1][0]*ex; + if ( tgp_a[1]>0) + score-=sequence_pattern[0][1]*ex; + if ( tgp_b[1]>0) + score-=sequence_pattern[1][1]*ex; + } + } + + + return score; + + + + } +void evaluate_tgp_decoded_chromosome ( Alignment *A,int **TGP,int start, int end,int MODE) + { + int a,b; + int continue_loop; + + + + if (MODE==11 || MODE==13|| MODE==14) + { + if ( start==0)for ( a=0; anseq; a++)TGP[a][0]=-1; + else for ( a=0; anseq; a++)TGP[a][0]=(is_gap(A->seq_al[a][start-1])==1)?0:1; + + if ( end==A->len_aln-1)for ( a=0; anseq; a++)TGP[a][1]=-1; + else for ( a=0; anseq; a++)TGP[a][1]=(is_gap(A->seq_al[a][start-1])==1)?0:1; + } + else + { + /* 0: in the middle of the alignement + 1: natural end + 2: q left gap is the continuation of another gap that was open outside the bloc ( don't open it) + */ + + for ( a=0; a< A->nseq; a++) + { + TGP[a][0]=1; + TGP[a][1]=1; + for ( b=0; b< start; b++) + if ( !is_gap(A->seq_al[a][b])) + TGP[a][0]=0; + if ( start>0 ) + { + if (is_gap(A->seq_al[a][start-1]) && TGP[a][0]!=1) + {TGP[a][0]=-1; + continue_loop=1; + for ( b=(start-1); b>=0 && continue_loop==1; b--) + {TGP[a][0]-= ( is_gap(A->seq_al[a][b])==1)?1:0; + continue_loop= (is_gap(A->seq_al[a][b])==1)?continue_loop:0; + } + } + } + else if (is_gap(A->seq_al[a][start-1]) && TGP[a][0]==1) + { + TGP[a][0]=1; + continue_loop=1; + for ( b=(start-1); b>=0 && continue_loop==1; b--) + {TGP[a][0]+= ( is_gap(A->seq_al[a][b])==1)?1:0; + continue_loop= (is_gap(A->seq_al[a][b])==1)?continue_loop:0; + } + } + for ( b=(A->len_aln-1); b>end; b--) + if ( !is_gap(A->seq_al[a][b])) + TGP[a][1]=0; + } + } + } +int gap_type ( char a, char b) + { + /*gap_type -/-:0, X/X:-1 X/-:1, -/STAR:2*/ + + if ( is_gap(a) && is_gap(b)) + return 0; + else if ( !is_gap(a) && !is_gap(b)) + return -1; + else if ( !is_gap(a)) + return 1; + else if ( !is_gap(b)) + return 2; + else + return -1; + } + +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/evaluate_dirichlet.c b/binaries/src/tcoffee/t_coffee_source/evaluate_dirichlet.c new file mode 100644 index 0000000..4b6e8c9 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/evaluate_dirichlet.c @@ -0,0 +1,599 @@ +#include +#include +#include +#include +#include +#include +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" +#include "dp_lib_header.h" +static float dm[]={ +0.178091, +1.18065, 0.270671, 0.039848, 0.017576, 0.016415, 0.014268, 0.131916, 0.012391, 0.022599, 0.020358, 0.030727, 0.015315, 0.048298, 0.053803, 0.020662, 0.023612, 0.216147, 0.147226, 0.065438, 0.003758, 0.009621, +0.056591, +1.35583, 0.021465, 0.0103, 0.011741, 0.010883, 0.385651, 0.016416, 0.076196, 0.035329, 0.013921, 0.093517, 0.022034, 0.028593, 0.013086, 0.023011, 0.018866, 0.029156, 0.018153, 0.0361, 0.07177, 0.419641, +0.0960191, +6.66436 ,0.561459, 0.045448, 0.438366, 0.764167, 0.087364, 0.259114, 0.21494, 0.145928, 0.762204, 0.24732, 0.118662, 0.441564, 0.174822, 0.53084, 0.465529, 0.583402, 0.445586, 0.22705, 0.02951, 0.12109, +0.078123, +2.08141, 0.070143, 0.01114, 0.019479, 0.094657, 0.013162, 0.048038, 0.077, 0.032939, 0.576639, 0.072293, 0.02824, 0.080372, 0.037661, 0.185037, 0.506783, 0.073732, 0.071587, 0.042532, 0.011254, 0.028723, +0.0834977, +2.08101, 0.041103, 0.014794, 0.00561, 0.010216, 0.153602, 0.007797, 0.007175, 0.299635, 0.010849, 0.999446, 0.210189, 0.006127, 0.013021, 0.019798, 0.014509, 0.012049, 0.035799, 0.180085, 0.012744, 0.026466, +0.0904123, +2.56819, 0.115607, 0.037381, 0.012414, 0.018179, 0.051778, 0.017255, 0.004911, 0.796882, 0.017074, 0.285858, 0.075811, 0.014548, 0.015092, 0.011382, 0.012696, 0.027535, 0.088333, 0.94434, 0.004373, 0.016741, +0.114468, +1.76606, 0.093461, 0.004737, 0.387252, 0.347841, 0.010822, 0.105877, 0.049776, 0.014963, 0.094276, 0.027761, 0.01004, 0.187869, 0.050018, 0.110039, 0.038668, 0.119471, 0.065802, 0.02543, 0.003215, 0.018742, +0.0682132, +4.98768, 0.452171, 0.114613, 0.06246, 0.115702, 0.284246, 0.140204, 0.100358, 0.55023, 0.143995, 0.700649, 0.27658, 0.118569, 0.09747, 0.126673, 0.143634, 0.278983, 0.358482, 0.66175, 0.061533, 0.199373, +0.234585, +0.0995, 0.005193, 0.004039, 0.006722, 0.006121, 0.003468, 0.016931, 0.003647, 0.002184, 0.005019, 0.00599, 0.001473, 0.004158, 0.009055, 0.00363, 0.006583, 0.003172, 0.00369, 0.002967, 0.002772,0.002686}; + +double int_logB (int *i, int n) + { + static double *array; + int a; + + if ( array==NULL)array=vcalloc ( 1000, sizeof (double)); + + for ( a=0; a< n; a++) + array[a]=(double)i[a]; + return double_logB(array, n); + } +double float_logB (float *i, int n) + { + static double *array; + int a; + + if ( array==NULL)array=vcalloc ( 1000, sizeof (double)); + for ( a=0; a< n; a++) + array[a]=(double)i[a]; + return double_logB(array, n); + } + +double double_logB (double *x, int n) + { + double vx=0; + double result=0; + int i; + + + for ( i=0; iALPHA[a][b]+c); + + return lup; + } + +double double_logB2(int j, double *n,Mixture *D) + { + double vx=0; + double result=0; + int i; + + static double ***lup; + + + + if ( lup==NULL)lup=make_lup_table (D); + + + + for ( i=0; in_aa; i++)vx+=(double)n[i]+D->ALPHA[j][i]; + for ( i=0; in_aa; i++) + { + + + result+=lup[j][i][(int)n[i]]; + } + return result-lgamma2(vx); + } + +double compute_exponant ( double *n, int j, Mixture *D) + { + + if ( j>=9)fprintf ( stderr, "\nPB: j=%d", j); + + return double_logB2(j, n,D)-D->double_logB_alpha[j]; + } + + +double *compute_matrix_p ( double *n,int Nseq) + { + + /* + reads in a frquency list of various amino acids: + + sum freq(aa)=1 (gaps are ignored) + + aa[1]=x1 + aa[2]=x2 + .... + + Outputs a similar list with frequencies 'Blurred' using a pam250 mt + */ + + + + static int **matrix; + double *R; + int a, b; + double v,min, tot; + + + if ( !matrix) + { + matrix=read_matrice ( "pam250mt"); + } + + R=vcalloc ( 26, sizeof (double)); + + + for ( a=0; a<26; a++) + { + if (!is_aa(a+'a'))continue; + if ( n[a]==0)continue; + + for ( b=0; b< 26; b++) + { + if (!is_aa(b+'a'))continue; + v=n[a]*(matrix[a][b]); + if ( v>0) + { + R[b]+=v+(10*n[a]); + } + } + } + + min=R[0]; + for ( min=R[0],a=0; a< 26; a++)min=MIN(min,R[a]); + for ( tot=0, a=0; a< 26; a++) {R[a]-=min;tot+=R[a];} + for ( a=0; a< 26; a++)if ( is_aa(a+'a')){R[a]=R[a]*((float)(100)/(float)tot);} + return R; + } + + +double *compute_dirichlet_p ( double *n,int Nseq) + { + /* + Given a list of frequenceies measured for the residues, this function returns + the p_values associated with each residue in the column + */ + + int a, b; + double X_LIST[100]; + double sum, log_sum, max; + static Mixture *D; + static double *R; + + + + if (!D) + { + D=read_dirichlet (NULL); + + D->n_aa=20; + R=vcalloc ( D->n_aa, sizeof (double)); + D->double_logB_alpha=vcalloc (D->N_COMPONENT , sizeof (double)); + + D->exponant_list=vcalloc (D->N_COMPONENT , sizeof (double)); + precompute_log_B ( D->double_logB_alpha,D); + D->alpha_tot=vcalloc (D->N_COMPONENT , sizeof (double)); + for ( a=0; aN_COMPONENT; a++) + for ( b=0; b< D->n_aa; b++) + D->alpha_tot[a]+=D->ALPHA[a][b]; + } + + + + for ( D->tot_n=0,a=0; a< D->n_aa; a++)D->tot_n+=(double)n[a]; + max=D->exponant_list[0]=compute_exponant ( n, 0, D); + for ( a=1; aN_COMPONENT; a++) + { + D->exponant_list[a]=compute_exponant ( n, a,D); + max= ( max< D->exponant_list[a])?D->exponant_list[a]:max; + } + for ( a=1; aN_COMPONENT; a++)D->exponant_list[a]=D->exponant_list[a]-max; + + + for ( sum=0,log_sum=0,a=0; a< D->n_aa; a++) + { + sum+=X_LIST[a]=compute_X (n, a,D); + } + log_sum=log(sum); + + + for (a=0; an_aa; a++) + { + R[a]=(log(X_LIST[a])-log_sum); + } + + + /* + printf ( "\n["); + for ( a=0;a< n_aa; a++)printf ("%d ", n[a]); + printf ("] score=%f",(float) result ); + + fprintf ( stderr, "\nRESULT=%f", (float)result); + exit(0); + */ + return R; + + } + +void precompute_log_B ( double *table,Mixture *D) + { + int a; + for ( a=0; a< D->N_COMPONENT; a++) + { + table[a]=double_logB ( D->ALPHA[a], D->n_aa); + } + } +double compute_X (double *n,int i,Mixture *D) + { + int j; + double term1, term2,result; + double **alpha; + double *q; + + + + alpha=D->ALPHA; + q=D->DM_Q; + + for (result=0, j=0; jN_COMPONENT; j++) + { + term1=exp (D->exponant_list[j])*q[j]; + term2=(alpha[j][i]+(double)n[i])/(D->alpha_tot[j]+D->tot_n); + result+=term1*term2; + } + return result; + } +Mixture * read_dirichlet ( char *name) + { + FILE *fp; + int a,b, c; + float f; + Mixture *D; + + + D=vcalloc ( 1, sizeof (Mixture)); + + + D->N_COMPONENT=9; + D->ALPHA=vcalloc (9, sizeof (double*)); + for ( a=0; a< 9; a++) + D->ALPHA[a]=vcalloc (20, sizeof (double)); + D->DM_Q=vcalloc (9, sizeof (double)); + + if (name!=NULL) + { + fp=vfopen ( name, "r"); + for ( a=0; a< 9; a++) + { + fscanf(fp, "%f\n", &f); + D->DM_Q[a]=(double)f; + fscanf(fp, "%f", &f); + + for ( b=0; b<20; b++) + { + fscanf(fp, "%f", &f); + D->ALPHA[a][b]=(double)f; + } + fscanf(fp, "\n"); + } + for ( a=0; a< 9; a++) + { + fprintf(stderr, "\n%f\n",(float)D->DM_Q[a] ); + + for ( b=0; b<20; b++) + { + fprintf(stderr, "%f ", (float)D->ALPHA[a][b]); + } + fprintf(stderr, "\n"); + } + fprintf ( stderr, "\nN_C=%d",D->N_COMPONENT ); + vfclose ( fp); + } + else + { + for (c=0, a=0; a< 9;a++) + { + D->DM_Q[a]=dm[c++]; + for (b=0; b<20; b++) + D->ALPHA[a][b]=dm[c++]; + } + } + + return D; + } +int dirichlet_code( char aa) + { + + char x; + + x=tolower (aa); + + if ( (x<'a') || (x>'z')) + crash ( "CODE UNDEFINED"); + else if ( x<='a') + return x-'a'; + else if ( x<='i') + return x-('a'+1); + else if ( x<= 'n') + return x-('a'+2); + else if ( x<='t') + return x-('a'+3); + else if ( x<='w') + return x-('a'+4); + else if ( x=='y') + return x-('a'+5); + else + { + crash ("ERROR in dirichlet_code"); + return 0; + } + return 0; + + } + + +static const double +two52= 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */ +half= 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */ +one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */ +pi = 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */ +a0 = 7.72156649015328655494e-02, /* 0x3FB3C467, 0xE37DB0C8 */ +a1 = 3.22467033424113591611e-01, /* 0x3FD4A34C, 0xC4A60FAD */ +a2 = 6.73523010531292681824e-02, /* 0x3FB13E00, 0x1A5562A7 */ +a3 = 2.05808084325167332806e-02, /* 0x3F951322, 0xAC92547B */ +a4 = 7.38555086081402883957e-03, /* 0x3F7E404F, 0xB68FEFE8 */ +a5 = 2.89051383673415629091e-03, /* 0x3F67ADD8, 0xCCB7926B */ +a6 = 1.19270763183362067845e-03, /* 0x3F538A94, 0x116F3F5D */ +a7 = 5.10069792153511336608e-04, /* 0x3F40B6C6, 0x89B99C00 */ +a8 = 2.20862790713908385557e-04, /* 0x3F2CF2EC, 0xED10E54D */ +a9 = 1.08011567247583939954e-04, /* 0x3F1C5088, 0x987DFB07 */ +a10 = 2.52144565451257326939e-05, /* 0x3EFA7074, 0x428CFA52 */ +a11 = 4.48640949618915160150e-05, /* 0x3F07858E, 0x90A45837 */ +tc = 1.46163214496836224576e+00, /* 0x3FF762D8, 0x6356BE3F */ +tf = -1.21486290535849611461e-01, /* 0xBFBF19B9, 0xBCC38A42 */ +/* tt = -(tail of tf) */ +tt = -3.63867699703950536541e-18, /* 0xBC50C7CA, 0xA48A971F */ +t0 = 4.83836122723810047042e-01, /* 0x3FDEF72B, 0xC8EE38A2 */ +t1 = -1.47587722994593911752e-01, /* 0xBFC2E427, 0x8DC6C509 */ +t2 = 6.46249402391333854778e-02, /* 0x3FB08B42, 0x94D5419B */ +t3 = -3.27885410759859649565e-02, /* 0xBFA0C9A8, 0xDF35B713 */ +t4 = 1.79706750811820387126e-02, /* 0x3F9266E7, 0x970AF9EC */ +t5 = -1.03142241298341437450e-02, /* 0xBF851F9F, 0xBA91EC6A */ +t6 = 6.10053870246291332635e-03, /* 0x3F78FCE0, 0xE370E344 */ +t7 = -3.68452016781138256760e-03, /* 0xBF6E2EFF, 0xB3E914D7 */ +t8 = 2.25964780900612472250e-03, /* 0x3F6282D3, 0x2E15C915 */ +t9 = -1.40346469989232843813e-03, /* 0xBF56FE8E, 0xBF2D1AF1 */ +t10 = 8.81081882437654011382e-04, /* 0x3F4CDF0C, 0xEF61A8E9 */ +t11 = -5.38595305356740546715e-04, /* 0xBF41A610, 0x9C73E0EC */ +t12 = 3.15632070903625950361e-04, /* 0x3F34AF6D, 0x6C0EBBF7 */ +t13 = -3.12754168375120860518e-04, /* 0xBF347F24, 0xECC38C38 */ +t14 = 3.35529192635519073543e-04, /* 0x3F35FD3E, 0xE8C2D3F4 */ +u0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */ +u1 = 6.32827064025093366517e-01, /* 0x3FE4401E, 0x8B005DFF */ +u2 = 1.45492250137234768737e+00, /* 0x3FF7475C, 0xD119BD6F */ +u3 = 9.77717527963372745603e-01, /* 0x3FEF4976, 0x44EA8450 */ +u4 = 2.28963728064692451092e-01, /* 0x3FCD4EAE, 0xF6010924 */ +u5 = 1.33810918536787660377e-02, /* 0x3F8B678B, 0xBF2BAB09 */ +v1 = 2.45597793713041134822e+00, /* 0x4003A5D7, 0xC2BD619C */ +v2 = 2.12848976379893395361e+00, /* 0x40010725, 0xA42B18F5 */ +v3 = 7.69285150456672783825e-01, /* 0x3FE89DFB, 0xE45050AF */ +v4 = 1.04222645593369134254e-01, /* 0x3FBAAE55, 0xD6537C88 */ +v5 = 3.21709242282423911810e-03, /* 0x3F6A5ABB, 0x57D0CF61 */ +s0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */ +s1 = 2.14982415960608852501e-01, /* 0x3FCB848B, 0x36E20878 */ +s2 = 3.25778796408930981787e-01, /* 0x3FD4D98F, 0x4F139F59 */ +s3 = 1.46350472652464452805e-01, /* 0x3FC2BB9C, 0xBEE5F2F7 */ +s4 = 2.66422703033638609560e-02, /* 0x3F9B481C, 0x7E939961 */ +s5 = 1.84028451407337715652e-03, /* 0x3F5E26B6, 0x7368F239 */ +s6 = 3.19475326584100867617e-05, /* 0x3F00BFEC, 0xDD17E945 */ +r1 = 1.39200533467621045958e+00, /* 0x3FF645A7, 0x62C4AB74 */ +r2 = 7.21935547567138069525e-01, /* 0x3FE71A18, 0x93D3DCDC */ +r3 = 1.71933865632803078993e-01, /* 0x3FC601ED, 0xCCFBDF27 */ +r4 = 1.86459191715652901344e-02, /* 0x3F9317EA, 0x742ED475 */ +r5 = 7.77942496381893596434e-04, /* 0x3F497DDA, 0xCA41A95B */ +r6 = 7.32668430744625636189e-06, /* 0x3EDEBAF7, 0xA5B38140 */ +w0 = 4.18938533204672725052e-01, /* 0x3FDACFE3, 0x90C97D69 */ +w1 = 8.33333333333329678849e-02, /* 0x3FB55555, 0x5555553B */ +w2 = -2.77777777728775536470e-03, /* 0xBF66C16C, 0x16B02E5C */ +w3 = 7.93650558643019558500e-04, /* 0x3F4A019F, 0x98CF38B6 */ +w4 = -5.95187557450339963135e-04, /* 0xBF4380CB, 0x8C0FE741 */ +w5 = 8.36339918996282139126e-04, /* 0x3F4B67BA, 0x4CDAD5D1 */ +w6 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ + +static const double zero= 0.00000000000000000000e+00; + +static double sin_pi(double x) +{ + double y,z; + int n,ix; + + ix=(*(long long *)&x)>>32; + ix &= 0x7fffffff; + + if(ix<0x3fd00000) return sin(pi*x); + y = -x; /* x is assume negative */ + + /* + * argument reduction, make sure inexact flag not raised if input + * is an integer + */ + z = floor(y); + if(z!=y) { /* inexact anyway */ + y *= 0.5; + y = 2.0*(y - floor(y)); /* y = |x| mod 2.0 */ + n = (int) (y*4.0); + } else { + if(ix>=0x43400000) { + y = zero; n = 0; /* y must be even */ + } else { + if(ix<0x43300000) z = y+two52; /* exact */ + n=(*(long long *)&x); + n &= 1; + y = n; + n<<= 2; + } + } + switch (n) { + case 0: y = sin(pi*y); break; + case 1: + case 2: y = cos(pi*(0.5-y)); break; + case 3: + case 4: y = sin(pi*(one-y)); break; + case 5: + case 6: y = -cos(pi*(y-1.5)); break; + default: y = sin(pi*(y-2.0)); break; + } + return -y; +} + +double lgamma2 ( double x) +{ + int s; + return lgamma_r ( x, &s); +} +double lgamma_r(double x, int *signgamp) +{ + double t,y,z,nadj=0,p,p1,p2,p3,q,r,w; + int i,hx,lx,ix; + + hx=(*(long long *)&x)>>32; + lx=(*(long long *)&x); + + /* purge off +-inf, NaN, +-0, and negative arguments */ + *signgamp = 1; + ix = hx&0x7fffffff; + if(ix>=0x7ff00000) return x*x; + if((ix|lx)==0) return one/fabs(x); + if(ix<0x3b900000) { /* |x|<2**-70, return -log(|x|) */ + if(hx<0) { + *signgamp = -1; + return -log(-x); + } else return -log(x); + } + if(hx<0) { + if(ix>=0x43300000) /* |x|>=2**52, must be -integer */ + return x/zero; + t = sin_pi(x); + if(t==zero) return one/fabs(t); /* -integer */ + nadj = log(pi/fabs(t*x)); + if(t=0x3FE76944) {y = one-x; i= 0;} + else if(ix>=0x3FCDA661) {y= x-(tc-one); i=1;} + else {y = x; i=2;} + } else { + r = zero; + if(ix>=0x3FFBB4C3) {y=2.0-x;i=0;} /* [1.7316,2] */ + else if(ix>=0x3FF3B4C4) {y=x-tc;i=1;} /* [1.23,1.73] */ + else {y=x-one;i=2;} + } + switch(i) { + case 0: + z = y*y; + p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10)))); + p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11))))); + p = y*p1+p2; + r += (p-0.5*y); break; + case 1: + z = y*y; + w = z*y; + p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12))); /* parallel comp */ + p2 = t1+w*(t4+w*(t7+w*(t10+w*t13))); + p3 = t2+w*(t5+w*(t8+w*(t11+w*t14))); + p = z*p1-(tt-w*(p2+y*p3)); + r += (tf + p); break; + case 2: + p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5))))); + p2 = one+y*(v1+y*(v2+y*(v3+y*(v4+y*v5)))); + r += (-0.5*y + p1/p2); + } + } + else if(ix<0x40200000) { /* x < 8.0 */ + i = (int)x; + t = zero; + y = x-(double)i; + p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6)))))); + q = one+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6))))); + r = half*y+p/q; + z = one; /* lgamma(1+s) = log(s) + lgamma(s) */ + switch(i) { + case 7: z *= (y+6.0); /* FALLTHRU */ + case 6: z *= (y+5.0); /* FALLTHRU */ + case 5: z *= (y+4.0); /* FALLTHRU */ + case 4: z *= (y+3.0); /* FALLTHRU */ + case 3: z *= (y+2.0); /* FALLTHRU */ + r += log(z); break; + } + /* 8.0 <= x < 2**58 */ + } else if (ix < 0x43900000) { + t = log(x); + z = one/x; + y = z*z; + w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6))))); + r = (x-half)*(t-one)+w; + } else + /* 2**58 <= x <= inf */ + r = x*(log(x)-one); + if(hx<0) r = nadj - r; + return r; +} +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/evaluate_for_domain.c b/binaries/src/tcoffee/t_coffee_source/evaluate_for_domain.c new file mode 100644 index 0000000..51afb76 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/evaluate_for_domain.c @@ -0,0 +1,311 @@ +#include +#include +#include +#include +#include +#include +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" + +#include "dp_lib_header.h" + + + + + +int evaluate_moca_domain ( Alignment *A, Constraint_list *CL) + { + /* + function documentation: start + int evaluate_moca_domain ( Alignment *A, Constraint_list *CL) + + This function evaluates a multiple local alignment + If the alignmnent is to be accepted, return score + Else return UNDEFINED + + function documentation: end + */ + + + int score=0; + int start, end, a, b; + Alignment *B=NULL; + char alp[200]; + + + score=UNDEFINED; + end=0; + start=0; + + sprintf ( alp, "acefghiklmnpqrstuvwy"); + + if ( A->len_aln>0) + { + score=(int)(output_maln_pval ( "/dev/null", A)*-100); + return score; + } + else + return 0; + + + + + while ((end+1)!=A->len_aln) + { + end=get_nol_aln_border (A,start,GO_RIGHT); + if ( end==start)break; + fprintf ( stderr, "\n**%d %d (%d)",start, end, A->len_aln); + B=copy_aln (A, B); + B=extract_aln (B,start,end); + for (a=0; anseq; a++) + for ( b=0; blen_aln; b++) + if ( is_gap (B->seq_al[a][b]))B->seq_al[a][b]=alp[(int)rand()%(strlen (alp))]; + + + start=end; + fprintf ( stderr, "==>%d",(int)(output_maln_pval ( "/dev/null", B)*-100) ); + if ( score==UNDEFINED)score=(int)(output_maln_pval ( "/dev/null", B)*-100); + else + score=MAX(score,(int)(output_maln_pval ( "/dev/null", B)*-100)); + + + } + free_aln (B); + return score; + } + + +int moca_slow_get_dp_cost ( Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) + { + int s; + + s=slow_get_dp_cost ( A, pos1, ns1, list1, col1, pos2, ns2, list2, col2, CL); + + + if ( s==UNDEFINED)return UNDEFINED; + else return s+(CL->moca)->moca_scale; + + } +int moca_evaluate_matrix_score ( Constraint_list *CL, int s1, int r1, int s2, int r2) +{ + /* + function documentation: start + int moca_residue_pair_extended_list ( Constraint_list *CL, int s1, int r1, int s2, int r2 ) + + THIS FUNCTION RETURNS THE EXTENDED SCORE OF A PAIR OF RESIDUES + it is meant to work with local aln pair_wise routines, by using (CL->moca)->forbiden_residues + a constant value is substracted from the extended score. + + This function is meant toi be used with omain_dp, therefore, it allows the match of identical residues. + + function documentation: end + */ + + if (unpack_seq_residues ( &s1, &r1, &s2, &r2, CL->packed_seq_lu)==UNDEFINED)return UNDEFINED; + else if ( (CL->moca)->forbiden_residues && ((CL->moca)->forbiden_residues[s1][r1]==UNDEFINED ||(CL->moca)->forbiden_residues[s2][r2]==UNDEFINED))return UNDEFINED; + else if ( s1==s2 && r1 == r2) return UNDEFINED; + else return evaluate_matrix_score(CL, s1, r1, s2, r2); + } + + + + +int moca_residue_pair_extended_list ( Constraint_list *CL, int s1, int r1, int s2, int r2 ) + { + /* + function documentation: start + int moca_residue_pair_extended_list ( Constraint_list *CL, int s1, int r1, int s2, int r2 ) + + THIS FUNCTION RETURNS THE EXTENDED SCORE OF A PAIR OF RESIDUES + it is meant to work with local aln pair_wise routines, by using (CL->moca)->forbiden_residues + a constant value is substracted from the extended score. + + This function is meant toi be used with omain_dp, therefore, it allows the match of identical residues. + + function documentation: end + */ + + if (unpack_seq_residues ( &s1, &r1, &s2, &r2, CL->packed_seq_lu)==UNDEFINED)return UNDEFINED; + else if ( (CL->moca)->forbiden_residues && ((CL->moca)->forbiden_residues[s1][r1]==UNDEFINED ||(CL->moca)->forbiden_residues[s2][r2]==UNDEFINED))return UNDEFINED; + else if ( s1==s2 && r1 == r2) return UNDEFINED; + else return residue_pair_extended_list (CL, s1, r1, s2, r2); + + + } + +int **cache_cl_with_moca_domain (Alignment *A, Constraint_list *CL) + { + /* + function documentation: start + int **cache_cl_with_moca_domain (Alignment *A, Constraint_list *CL) + + Read a multiple alignmnent + Given all the residues (CL->S)->seq[x][y] contained in the maln + Set (CL->moca)->forbiden_residues[x][y] to UNDEFINED + return (CL->moca)->forbiden_residues + + WARNING + You must make sure that the evalation strategy uses (CL->moca)->forbiden_residues + (CL->moca)->forbiden_residues[0][1]->first residue(1) of First sequence(0) + function documentation: end + */ + + int **pos; + int a, b; + + pos=aln2pos_simple(A, A->nseq); + + if ( !(CL->moca)->forbiden_residues)(CL->moca)->forbiden_residues=declare_int ((CL->S)->nseq, strlen ((CL->S)->seq[0])+1); + + for ( a=0; anseq;a++) + for ( b=0; b< A->len_aln; b++) + (CL->moca)->forbiden_residues[A->order[a][0]][pos[a][b]]=UNDEFINED; + + free_int (pos, -1); + return (CL->moca)->forbiden_residues; + } +Alignment *make_moca_nol_aln ( Alignment *A, Constraint_list *CL) +{ + + return A; +} + +/*********************************************************************************************/ +/* */ +/* DOMAIN Z SCORE EVALUATION */ +/* */ +/*********************************************************************************************/ + +int evaluate_domain_aln_z_score (Alignment *A, int start, int end,Constraint_list *CL, char *alphabet) + { + int a; + static Alignment *B; + double score, ref_score; + double N_EVAL=1000; + double sum=0, sum2=0; + + + if ( A==NULL || A->nseq==0 || A->len_aln==0)return 0; + ref_score=(double)evaluate_domain_aln (A,start, end,CL); + for (sum=0, sum2=0,a=0;anseq, end-start, alphabet); + score=(double)evaluate_domain_aln (B,0,B->len_aln,CL); + sum+=score; + sum2+=score*score; + } + score=(return_z_score(ref_score, sum, sum2, N_EVAL)*100)/A->len_aln; + + return(int) score; + } + +int evaluate_domain_aln ( Alignment *A, int start, int end,Constraint_list *CL) + { + int a, b, c; + int score, c1, c2; + static int **mat; + + /* + function documentation: start + + This function uses a pam250 to evaluate the sum of pairs score of A, + between position start(included) to position end (exluded), + + the numbering starts 0 + function documentation: end + */ + + if ( !mat)mat=read_matrice ( "pam250mt"); + + for ( c=start, score=0; cnseq-1; a++) + for ( b=a+1; b< A->nseq; b++) + { + c1=tolower(A->seq_al[a][c]); + c2=tolower(A->seq_al[b][c]); + + if ( !is_gap (c1) && !is_gap(c2))score+=mat[c1-'A'][c2-'A']; + } + } + return score; + } + +int unpack_seq_residues ( int *s1, int *r1, int *s2, int *r2, int **packed_seq_lu) + { + /* Given a series of sequences concatenated (packed), and the coordinates of two residues + This function translates the coordinates into the real ones and allows evaluation + Note for this function residues go from [1->N], sequences from [0->N[ + This is true for in and out comming residues number + NOTE: The sequence cannot be guessed when the residues r1 or r2 are GAPS, therefore UNDEFINED is returned + NOTE: Concatenated sequences are separated with X, such residues cause an UNDEFINED to be returned + */ + + if ( packed_seq_lu==NULL)return 1; + else if ( s1[0]!=s2[0])return 1; + else if ( r1[0]<=0 || r2[0]<=0)return UNDEFINED; + else if ( packed_seq_lu[r1[0]][0]==UNDEFINED || packed_seq_lu[r2[0]][0]==UNDEFINED)return UNDEFINED; + else + { + s1[0]=packed_seq_lu[r1[0]][0]; + r1[0]=packed_seq_lu[r1[0]][1]; + + s2[0]=packed_seq_lu[r2[0]][0]; + r2[0]=packed_seq_lu[r2[0]][1]; + } + return 1; + } + +Alignment * unpack_seq_aln ( Alignment *A,Constraint_list *CL) + { + int a, b, r_seq, r_start, r_len; + + + if (!CL->packed_seq_lu) return A; + + for (a=0; a< A->nseq; a++) + { + r_seq =CL->packed_seq_lu[A->order[a][1]+1][0]; + r_start=CL->packed_seq_lu[A->order[a][1]+1][1]; + + A->order[a][0]=r_seq; + A->order[a][1]=r_start-1; + + for ( r_len=0,b=0; b< A->len_aln; b++)r_len+=!is_gap(A->seq_al[a][b]); + sprintf ( A->name[a],"%s_%d_%d", (A->S)->name[r_seq], r_start, r_start+r_len-1); + } + + return A; + } + + +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/evaluate_for_struc.c b/binaries/src/tcoffee/t_coffee_source/evaluate_for_struc.c new file mode 100644 index 0000000..d02faef --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/evaluate_for_struc.c @@ -0,0 +1,2854 @@ +#include +#include +#include +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" +#include "dp_lib_header.h" +void print_atom ( Atom*A); + +float **** quantile_apdb_filtration ( Alignment *A, float ****residues, Constraint_list *CL,Pdb_param *PP, FILE *fp); +float **** irmsdmin_apdb_filtration ( Alignment *A, float ****residues, Constraint_list *CL,Pdb_param *PP, FILE *fp); +int apdb ( int argc, char *argv[]) + { + + Constraint_list *CL=NULL; + Sequence *S=NULL; + Alignment *A=NULL; + Alignment *EA=NULL; + Pdb_param *pdb_param; + + Fname *F=NULL; + char *file_name; + int a,c; + + int n_pdb; + +/*PARAMETERS VARIABLES*/ + int garbage; + char *parameters; + FILE *fp_parameters; + + int quiet; + char *se_name; + FILE *le=NULL; + + char **list_file; + int n_list; + char **struc_to_use; + int n_struc_to_use; + + char *aln; + char *repeat_seq; + char *repeat_pdb; + + char *color_mode; + char *comparison_io; + + int n_excluded_nb; + + float maximum_distance; + float similarity_threshold; + float md_threshold; + + + int print_rapdb; + + char *outfile; + char *run_name; + + char *apdb_outfile; + char *cache; + + char **out_aln_format; + int n_out_aln_format; + + char *output_res_num; + char *local_mode; + float filter; + int filter_aln; + int irmsd_graph; + int nirmsd_graph; + int n_template_file; + char **template_file_list; + char *mode; + int prot_min_sim; + int prot_max_sim; + int prot_min_cov; + int pdb_min_sim; + int pdb_max_sim; + int pdb_min_cov; + int gapped; + + + char *prot_blast_server; + char *pdb_blast_server; + + + char *pdb_db; + char *prot_db; + int min_ncol; + + argv=standard_initialisation (argv, &argc); + +/*PARAMETER PROTOTYPE: READ PARAMETER FILE */ + declare_name (parameters); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-parameters" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "R_F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Read the files in the parameter file" ,\ + /*Parameter*/ ¶meters ,\ + /*Def 1*/ "NULL" ,\ + /*Def 2*/ "stdin" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + if ( parameters && parameters[0]) + { + argv[argc]=vcalloc ( VERY_LONG_STRING, sizeof(char)); + a=0; + fp_parameters=vfopen (parameters, "r"); + while ((c=fgetc (fp_parameters))!=EOF)argv[1][a++]=c; + vfclose (fp_parameters); + argv[argc][a]='\0'; + argc++; + argv=break_list ( argv, &argc, "=:;, \n"); + } +/*PARAMETER PROTOTYPE*/ + declare_name (se_name); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-quiet" ,\ + /*Flag*/ &quiet ,\ + /*TYPE*/ "W_F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "ND" ,\ + /*Parameter*/ &se_name ,\ + /*Def 1*/ "stderr" ,\ + /*Def 2*/ "/dev/null" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + + le=vfopen ( se_name, "w"); + fprintf ( le, "\nPROGRAM: %s\n",argv[0]); + +/*PARAMETER PROTOTYPE: IN */ + list_file=declare_char ( 200, STRING); + n_list=get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-in" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 200 ,\ + /*DOC*/ "ND" ,\ + /*Parameter*/ list_file ,\ + /*Def 1*/ "",\ + /*Def 2*/ "stdin" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +/*PARAMETER PROTOTYPE: IN */ + struc_to_use=declare_char ( 200, STRING); + n_struc_to_use=get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-struc_to_use" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 200 ,\ + /*DOC*/ "ND" ,\ + /*Parameter*/ struc_to_use ,\ + /*Def 1*/ "",\ + /*Def 2*/ "stdin" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +/*PARAMETER PROTOTYPE: COMPARISON IO */ + declare_name (comparison_io); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-io_format" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 200 ,\ + /*DOC*/ "ND" ,\ + /*Parameter*/ &comparison_io,\ + /*Def 1*/ "hsgd0123456",\ + /*Def 2*/ "" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +/*PARAMETER PROTOTYPE: ALN */ + declare_name (aln); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-aln" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "ND" ,\ + /*Parameter*/ &aln,\ + /*Def 1*/ "",\ + /*Def 2*/ "stdin" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +/*PARAMETER PROTOTYPE: ALN */ + + declare_name (repeat_seq); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-repeat_seq" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "ND" ,\ + /*Parameter*/ &repeat_seq,\ + /*Def 1*/ "",\ + /*Def 2*/ "stdin" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +/*PARAMETER PROTOTYPE: ALN */ + declare_name (repeat_pdb); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-repeat_pdb" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "ND" ,\ + /*Parameter*/ &repeat_pdb,\ + /*Def 1*/ "",\ + /*Def 2*/ "stdin" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +/*PARAMETER PROTOTYPE: Nb to exclude */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-n_excluded_nb" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Exclude the N Nb on each side of the central residue. -1 triggers an automatic setting equal to the window size corresponding to the sphere" ,\ + /*Parameter*/ &n_excluded_nb ,\ + /*Def 1*/ "-1" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +/*PARAMETER PROTOTYPE: diatances to count */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-similarity_threshold" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "ND" ,\ + /*Parameter*/ &similarity_threshold,\ + /*Def 1*/ "70" ,\ + /*Def 2*/ "70" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +/*PARAMETER PROTOTYPE: diatances to count */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-filter" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Filter by only keeping the best quantile" ,\ + /*Parameter*/ &filter,\ + /*Def 1*/ "1.00" ,\ + /*Def 2*/ "1.00" ,\ + /*Min_value*/ "-1.00" ,\ + /*Max Value*/ "1.00" \ + ); +/*PARAMETER PROTOTYPE: diatances to count */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-filter_aln" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Lower Case For Residues Filtered Out" ,\ + /*Parameter*/ &filter_aln,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "0" ,\ + /*Max Value*/ "1" \ + ); +/*PARAMETER PROTOTYPE: diatances to count */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-irmsd_graph" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Outputs the irmsd, position/position" ,\ + /*Parameter*/ &irmsd_graph,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "0" ,\ + /*Max Value*/ "1" \ + ); +/*PARAMETER PROTOTYPE: diatances to count */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-nirmsd_graph" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Outputs the NIRMSD VS N Removed Residues Curve" ,\ + /*Parameter*/ &nirmsd_graph,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "0" ,\ + /*Max Value*/ "1" \ + ); +/*PARAMETER PROTOTYPE: -rmsd_threshold */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-md_threshold" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "ND" ,\ + /*Parameter*/ &md_threshold ,\ + /*Def 1*/ "1" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +/*PARAMETER PROTOTYPE: -maximum distances */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-maximum_distance" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "ND" ,\ + /*Parameter*/ &maximum_distance ,\ + /*Def 1*/ "10" ,\ + /*Def 2*/ "10" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + + +/*PARAMETER PROTOTYPE: -print_rapdb */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-print_rapdb" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Prints the neighborhood of each pair of aligned residues, along with the associated local score" ,\ + /*Parameter*/ &print_rapdb ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +/*PARAMETER PROTOTYPE: RUN_NAME */ + declare_name (run_name); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-run_name" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "W_F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "ND" ,\ + /*Parameter*/ &run_name ,\ + /*Def 1*/ "default" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "default" ,\ + /*Max Value*/ "any" \ + ); +/*PARAMETER PROTOTYPE: OUTFILE */ +/*PARAMETER PROTOTYPE: OUTFILE */ + declare_name ( outfile); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-outfile" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "W_F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "ND" ,\ + /*Parameter*/ &outfile ,\ + /*Def 1*/ "no" ,\ + /*Def 2*/ "default" ,\ + /*Min_value*/ "default" ,\ + /*Max Value*/ "any" \ + ); +/*PARAMETER PROTOTYPE: OUTFILE */ + declare_name ( apdb_outfile); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-apdb_outfile" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "W_F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "ND" ,\ + /*Parameter*/ &apdb_outfile ,\ + /*Def 1*/ "stdout" ,\ + /*Def 2*/ "default" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +/*PARAMETER PROTOTYPE: OUTPUT_FORMAT */ + out_aln_format=declare_char ( 200, STRING); + n_out_aln_format=get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-output" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 200 ,\ + /*DOC*/ "ND" ,\ + /*Parameter*/ out_aln_format,\ + /*Def 1*/ "score_html" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + + + +/*PARAMETER PROTOTYPE: INFILE */ + declare_name (color_mode); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-color_mode" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "ND" ,\ + /*Parameter*/ &color_mode ,\ + /*Def 1*/ "apdb" ,\ + /*Def 2*/ "irmsd" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +/*PARAMETER PROTOTYPE: INFILE */ + declare_name (output_res_num); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-seqnos" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "ND" ,\ + /*Parameter*/ &output_res_num ,\ + /*Def 1*/ "off" ,\ + /*Def 2*/ "on" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + declare_name (cache); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-cache" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "W_F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "use,ignore,update,local, directory name" ,\ + /*Parameter*/ &cache ,\ + /*Def 1*/ "use" ,\ + /*Def 2*/ "update" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + + declare_name (local_mode); + get_cl_param( \ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-local_mode" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "W_F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Mode for choosing the Neighborhood (bubble or window)\nWhen selecting window, maximum distance becomes the window 1/2 size, in residues\nWhen using sphere, maximum_distance is the sphere radius in Angstrom" ,\ + /*Parameter*/ &local_mode ,\ + /*Def 1*/ "sphere" ,\ + /*Def 2*/ "window" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +/*PARAMETER PROTOTYPE: IN */ + template_file_list=declare_char (100, STRING); + n_template_file=get_cl_param( \ + /*argc*/ argc , \ + /*argv*/ argv , \ + /*output*/ &le ,\ + /*Name*/ "-template_file" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1000 ,\ + /*DOC*/ "List of templates file for the sequences",\ + /*Parameter*/ template_file_list , \ + /*Def 1*/ "_SELF_P_",\ + /*Def 2*/ "stdin" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + /*PARAMETER PROTOTYPE: MODE */ + declare_name (mode); + get_cl_param( \ + /*argc*/ argc , \ + /*argv*/ argv , \ + /*output*/ &le ,\ + /*Name*/ "-mode" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Mode: irmsd, ",\ + /*Parameter*/ &mode , \ + /*Def 1*/ "irmsd",\ + /*Def 2*/ "stdin" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + + + + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-prot_min_sim" ,\ + /*Flag*/ &prot_min_sim ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Minimum similarity between a sequence and its PDB target" ,\ + /*Parameter*/ &prot_min_sim ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "20" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + set_int_variable ("prot_min_sim", prot_min_sim); + +get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-prot_max_sim" ,\ + /*Flag*/ &prot_max_sim ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Maximum similarity between a sequence and its BLAST relatives" ,\ + /*Parameter*/ &prot_max_sim ,\ + /*Def 1*/ "90" ,\ + /*Def 2*/ "100" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + set_int_variable ("prot_max_sim", prot_max_sim); + +get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-prot_min_cov" ,\ + /*Flag*/ &prot_min_cov ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Minimum coverage of a sequence by its BLAST relatives" ,\ + /*Parameter*/ &prot_min_cov ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "0" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +set_int_variable ("prot_min_cov", prot_min_cov); + +get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-pdb_min_sim" ,\ + /*Flag*/ &pdb_min_sim ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Minimum similarity between a sequence and its PDB target" ,\ + /*Parameter*/ &pdb_min_sim ,\ + /*Def 1*/ "35" ,\ + /*Def 2*/ "35" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + + set_int_variable ("pdb_min_sim", pdb_min_sim); + get_cl_param( \ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-pdb_max_sim" ,\ + /*Flag*/ &pdb_max_sim ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Maximum similarity between a sequence and its PDB target" ,\ + /*Parameter*/ &pdb_max_sim ,\ + /*Def 1*/ "100" ,\ + /*Def 2*/ "0" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + set_int_variable ("pdb_max_sim", pdb_max_sim); + get_cl_param( \ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-pdb_min_cov" ,\ + /*Flag*/ &pdb_min_cov ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Minimum coverage of a sequence by its PDB target" ,\ + /*Parameter*/ &pdb_min_cov ,\ + /*Def 1*/ "50" ,\ + /*Def 2*/ "25" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +set_int_variable ("pdb_min_cov", pdb_min_cov); + + + +declare_name (pdb_blast_server); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-pdb_blast_server" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "W_F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "ND" ,\ + /*Parameter*/&pdb_blast_server ,\ + /*Def 1*/ "EBI" ,\ + /*Def 2*/ "default" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +declare_name (prot_blast_server); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-blast" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "W_F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "ND" ,\ + /*Parameter*/&prot_blast_server ,\ + /*Def 1*/ "" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + //make sure that -blast and -blast_server are both supported blast>blast_server + if ( !prot_blast_server[0]) + { + get_cl_param( \ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-blast_server" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "W_F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "ND" ,\ + /*Parameter*/&prot_blast_server ,\ + /*Def 1*/ "EBI" ,\ + /*Def 2*/ "default" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + } + set_string_variable ("blast_server", prot_blast_server); + + + + declare_name (pdb_db); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-pdb_db" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "W_F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Non Redundant PDB database" ,\ + /*Parameter*/&pdb_db ,\ + /*Def 1*/ "pdb" ,\ + /*Def 2*/ "default" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + set_string_variable ("pdb_db", pdb_db); + + +declare_name (prot_db); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-protein_db" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "W_F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "ND" ,\ + /*Parameter*/&prot_db ,\ + /*Def 1*/ "uniprot" ,\ + /*Def 2*/ "default" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + + get_cl_param( \ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-gapped" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "ND" ,\ + /*Parameter*/&gapped ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + get_cl_param( \ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-min_ncol" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "minimum number of columns (negative: fraction)" ,\ + /*Parameter*/&min_ncol ,\ + /*Def 1*/ "4" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + // set the correct mode: + if ( strm (argv[0], "trmsd"))sprintf (mode, "trmsd"); + + set_string_variable ("prot_db", prot_db); + + + if (argc==1){myexit (EXIT_SUCCESS);} + + if ( strm (outfile,"no"))n_out_aln_format=0; + + get_cl_param( argc, argv,&le, NULL,NULL,NULL,0,0,NULL); + prepare_cache (cache); + + + if (strm ( aln, "")) + sprintf ( aln, "%s", argv[1]); + + if (!is_aln (aln)) + { + printf_exit (EXIT_FAILURE, stderr, "\n\n---- ERROR: File %s must be a valid alignment [FATAL:%s-%s]\n\n",aln,argv[0], PROGRAM); + } + + pdb_param=vcalloc ( 1, sizeof(Pdb_param)); + + pdb_param->similarity_threshold=similarity_threshold; + + pdb_param->md_threshold=md_threshold; + pdb_param->maximum_distance=maximum_distance; + + if ( n_excluded_nb>0) + pdb_param->n_excluded_nb=n_excluded_nb; + else if ( n_excluded_nb==-1) + pdb_param->n_excluded_nb=(int)((float)maximum_distance/(float)1.57); + /* Exclude all the nb within the bubble at +1, +2, +n*/ + pdb_param->print_rapdb=print_rapdb; + pdb_param->comparison_io=comparison_io; + + pdb_param->local_mode=local_mode; + pdb_param->color_mode=lower_string (color_mode); + pdb_param->filter=filter; + pdb_param->filter_aln=filter_aln; + pdb_param->irmsd_graph=irmsd_graph; + pdb_param->nirmsd_graph=nirmsd_graph; + + sprintf ( list_file[n_list++], "S%s", aln); + + + if (!strm (repeat_seq, "")) + { + + sprintf ( template_file_list[0], "%s", process_repeat (list_file[0], repeat_seq, repeat_pdb)); + fprintf ( le, "\n##Turn a repeat List into a Template File\n"); + le=display_file_content (le,template_file_list[0]); + fprintf ( le, "\n\n"); + } + S=read_seq_in_n_list (list_file, n_list, NULL, NULL); + + le=display_sequences_names ( S,le,0, 0); + + if ( n_template_file) + { + fprintf ( le, "\nLooking For Sequence Templates:\n"); + for ( a=0; a< n_template_file; a++) + { + fprintf ( le, "\n\tTemplate Type: [%s] Mode Or File: [%s] [Start", template_type2type_name(template_file_list[a]), template_file_list[a]); + S=seq2template_seq(S, template_file_list[a], F); + fprintf ( le, "]"); + } + } + + if ( !strm (run_name, "default")) + { + F=parse_fname(run_name); + sprintf (F->name, "%s", F->full); + } + else + { + F=parse_fname (aln); + } + + for ( a=0; a< S->nseq; a++) + { + char *p; + + p=seq2T_value (S, a, "template_file", "_P_"); + + if (p)sprintf (S->file[a], "%s",p); + } + + CL=declare_constraint_list ( S,NULL, NULL, 0,NULL, NULL); + CL->T=vcalloc (S->nseq,sizeof (Ca_trace*)); + + + for ( n_pdb=0,a=0; anseq; a++) + { + if ( !is_pdb_file ( S->file[a])){CL->T[a]=NULL;continue;} + CL->T[a]=read_ca_trace (S->file[a], "ATOM"); + CL->T[a]=trim_ca_trace (CL->T[a], S->seq[a]); + (CL->T[a])->pdb_param=pdb_param; + n_pdb++; + } + + A=declare_aln (S); + + + A->residue_case=KEEP_CASE; + A=main_read_aln(aln, A); + EA=copy_aln (A, EA); + A->CL=CL; + + if ( strm (apdb_outfile, "default")) + sprintf ( apdb_outfile, "%s.apdb_result", F->name); + + if ( n_pdb<2) + { + FILE *fp; + fp=vfopen (apdb_outfile, "w"); + fprintf (fp, "\nYour Alignment Does Not Contain Enough Sequences With a known Structure\n"); + fprintf (fp, "To Use APDB, your alignment must include at least TWO sequences with a known structure.\n"); + fprintf (fp, "These sequences must be named according to their PDB identifier, followed by the chain index (if any) ex: 1fnkA\n"); + fprintf (fp, "[FATAL:%s]\n", PROGRAM); + vfclose (fp); + } + else if ( strm (mode, "irmsd")) + { + EA=analyse_pdb ( A, EA, apdb_outfile); + } + else if ( strm (mode, "msa2tree") || strm (mode, "trmsd")) + { + EA=msa2struc_dist ( A, EA,F->name, gapped, min_ncol); + } + le=display_output_filename ( le, "APDB_RESULT", "APDB_RESULT_FORMAT_01", apdb_outfile, CHECK); + + if ( n_pdb>=2) + { + declare_name (file_name); + for ( a=0; a< n_out_aln_format; a++) + { + if ( strm2( outfile, "stdout", "stderr"))sprintf (file_name, "%s", outfile); + else if ( strm (outfile, "default")) + sprintf (file_name, "%s.%s",F->name, out_aln_format[a]); + else + sprintf (file_name, "%s.%s",outfile,out_aln_format[a]); + + output_format_aln (out_aln_format[a],A,EA,file_name); + le=display_output_filename ( le, "MSA", out_aln_format[a], file_name, CHECK); + } + } + return EXIT_SUCCESS; + } + + + +Constraint_list * set_constraint_list4align_pdb (Constraint_list *CL,int seq, char *dp_mode, char *local_mode, char *param_file) +{ + static Constraint_list *PWCL; + static Pdb_param *pdb_param; + char **x; + int n; + + if ( !CL) + { + free_constraint_list (PWCL); + return NULL; + } + else if ( !PWCL) + { + PWCL=declare_constraint_list ( CL->S,NULL, NULL, 0,NULL, NULL); + + pdb_param=vcalloc ( 1, sizeof(Pdb_param)); + pdb_param->N_ca=0; + pdb_param->max_delta=2.0; + pdb_param->maximum_distance=14; + declare_name (pdb_param->local_mode); + sprintf (pdb_param->local_mode, "%s", local_mode); + pdb_param->scale=50; + + PWCL->pw_parameters_set=1; + PWCL->S=CL->S; + PWCL->lalign_n_top=10; + PWCL->sw_min_dist=10; + + PWCL->T=vcalloc ( (PWCL->S)->nseq, sizeof (Ca_trace*)); + + PWCL->extend_jit=0; + PWCL->maximise=1; + /*PWCL->gop=-40;*/ + PWCL->gop=-50; + PWCL->gep=-20; + sprintf (CL->matrix_for_aa_group, "vasiliky"); + PWCL->use_fragments=0; + PWCL->ktup=0; + PWCL->TG_MODE=1; + } + + + if ( param_file && check_file_exists ( param_file) ) + { + if ( (x=get_parameter ( "-nca", &n, param_file))!=NULL){pdb_param->N_ca=atoi(x[0]);free_char (x, -1);} + if ( (x=get_parameter ( "-max_delta", &n, param_file))!=NULL){pdb_param->max_delta=atof(x[0]);free_char (x, -1);} + if ( (x=get_parameter ( "-maximum_distance", &n, param_file))!=NULL){pdb_param->maximum_distance=atoi(x[0]);free_char (x, -1);} + if ( (x=get_parameter ( "-local_mode", &n, param_file))!=NULL){sprintf (pdb_param->local_mode, "%s",x[0]);free_char (x, -1);} + if ( (x=get_parameter ( "-scale", &n, param_file))!=NULL){pdb_param->scale=atoi(x[0]);free_char (x, -1);} + if ( (x=get_parameter ( "-gapopen", &n, param_file))!=NULL){PWCL->gop=atoi(x[0]);free_char (x, -1);} + if ( (x=get_parameter ( "-gapext" , &n, param_file))!=NULL){PWCL->gep=atof(x[0]);free_char (x, -1);} + + } + + + + + sprintf ( PWCL->dp_mode, "%s", dp_mode); + + if (strm (PWCL->dp_mode, "lalign"))sprintf (PWCL->dp_mode,"sim_pair_wise_lalign"); + else if (strm (PWCL->dp_mode, "sw"))sprintf (PWCL->dp_mode,"gotoh_pair_wise_sw"); + + local_mode=pdb_param->local_mode; + if ( strm ( local_mode, "hasch_ca_trace_nb")) PWCL->evaluate_residue_pair=evaluate_ca_trace_nb; + else if ( strm ( local_mode, "hasch_ca_trace_bubble")) PWCL->evaluate_residue_pair=evaluate_ca_trace_bubble; + else if ( strm ( local_mode, "hasch_ca_trace_sap1_bubble")) PWCL->evaluate_residue_pair=evaluate_ca_trace_sap1_bubble; + else if ( strm ( local_mode, "hasch_ca_trace_sap2_bubble")) PWCL->evaluate_residue_pair=evaluate_ca_trace_sap2_bubble; + + else if ( strm ( local_mode, "hasch_ca_trace_transversal")) PWCL->evaluate_residue_pair=evaluate_ca_trace_transversal; + else if ( strm ( local_mode, "hasch_ca_trace_bubble_2")) PWCL->evaluate_residue_pair=evaluate_ca_trace_bubble_2; + else if ( strm ( local_mode, "hasch_ca_trace_bubble_3")) PWCL->evaluate_residue_pair=evaluate_ca_trace_bubble_3; + else if ( strm ( local_mode, "custom_pair_score_function1")) PWCL->evaluate_residue_pair=custom_pair_score_function1; + else if ( strm ( local_mode, "custom_pair_score_function2")) PWCL->evaluate_residue_pair=custom_pair_score_function2; + else if ( strm ( local_mode, "custom_pair_score_function3")) PWCL->evaluate_residue_pair=custom_pair_score_function3; + else if ( strm ( local_mode, "custom_pair_score_function4")) PWCL->evaluate_residue_pair=custom_pair_score_function4; + else if ( strm ( local_mode, "custom_pair_score_function5")) PWCL->evaluate_residue_pair=custom_pair_score_function5; + else if ( strm ( local_mode, "custom_pair_score_function6")) PWCL->evaluate_residue_pair=custom_pair_score_function6; + else if ( strm ( local_mode, "custom_pair_score_function7")) PWCL->evaluate_residue_pair=custom_pair_score_function7; + else if ( strm ( local_mode, "custom_pair_score_function8")) PWCL->evaluate_residue_pair=custom_pair_score_function8; + else if ( strm ( local_mode, "custom_pair_score_function9")) PWCL->evaluate_residue_pair=custom_pair_score_function9; + else if ( strm ( local_mode, "custom_pair_score_function10")) PWCL->evaluate_residue_pair=custom_pair_score_function10; + + + else + { + fprintf ( stderr, "\n%s is an unknown hasch mode, [FATAL]\n", local_mode); + myexit (EXIT_FAILURE); + } + + if ( PWCL->T[seq]); + else + { + PWCL->T[seq]=read_ca_trace (is_pdb_struc((CL->S)->name[seq]), "ATOM"); + (PWCL->T[seq])->pdb_param=pdb_param; + PWCL->T[seq]=trim_ca_trace (PWCL->T[seq], (CL->S)->seq[seq]); + PWCL->T[seq]=hasch_ca_trace(PWCL->T[seq]); + + } + + + return PWCL; +} + + + +int evaluate_ca_trace_nb (Constraint_list *CL, int s1, int r1, int s2, int r2) + { + + return (int)(neighborhood_match(CL, s1,r1, s2, r2, (CL->T[s1])->Chain,(CL->T[s2])->Chain )); + } +int evaluate_ca_trace_sap2_bubble (Constraint_list *CL, int s1, int r1, int s2, int r2) + { + + + + return sap2_neighborhood_match (CL, s1, r1, s2, r2, (CL->T[s1])->Bubble,(CL->T[s2])->Bubble ); + + } +int evaluate_ca_trace_sap1_bubble (Constraint_list *CL, int s1, int r1, int s2, int r2) + { + /* + Function documentation: start + + int evaluate_ca_trace_sap1_bubble (Constraint_list *CL, int s1, int s2, int r1, int r2) + This function evaluates the cost for matching two residues: + + a1 is the cost for matching the two neighborood ( bubble type), using sap + a1: [0,+100], +100 is the best possible match. + a2 is the residue type weight: + min=worst substitution value + best=best of r1/r1, r2/r2-min + + a2=(r1/r2 -min)/best --> a1:[0, 100] + + score=a1*a2-->[-inf, +10000]; + */ + + + + float a1; + + + a1=(int) sap1_neighborhood_match (CL, s1, r1, s2, r2, (CL->T[s1])->Bubble,(CL->T[s2])->Bubble ); + + return (int)a1; + + + } +int evaluate_ca_trace_bubble (Constraint_list *CL, int s1, int r1, int s2, int r2) + { + /* + Function documentation: start + + int evaluate_ca_trace_bubble (Constraint_list *CL, int s1, int s2, int r1, int r2) + This function evaluates the cost for matching two residues: + + a1 is the cost for matching the two neighborood ( bubble type) + a1: [-inf,+100-scale], +100-scale is the best possible match. + + */ + + + + float a1; + + + + a1=(int) neighborhood_match (CL, s1, r1, s2, r2, (CL->T[s1])->Bubble,(CL->T[s2])->Bubble )-((CL->T[s1])->pdb_param)->scale; + + return a1; + + + } +int evaluate_ca_trace_transversal (Constraint_list *CL, int s1, int r1, int s2, int r2) + { + return (int)(transversal_match (CL, s1, r1, s2, r2, (CL->T[s1])->Transversal,(CL->T[s2])->Transversal )); + } + +int evaluate_ca_trace_bubble_3 (Constraint_list *CL, int s1, int r1, int s2, int r2) + { + /*This Mode evaluates : + + 1-The Bubble + 2-The Match of the transversal residues + */ + + int a1, l1; + int a2, l2; + int a; + + l1=MAX(( (CL->T[s1])->Chain )->nb[r1][0] ,((CL->T[s2])->Chain )->nb[r2][0]); + l2=MAX(( (CL->T[s1])->Bubble)->nb[r1][0], ((CL->T[s2])->Bubble)->nb[r2][0]); + + a1=(int)(neighborhood_match (CL, s1, r1, s2, r2, (CL->T[s1])->Bubble,(CL->T[s2])->Bubble )); + a2=(int)(transversal_match (CL, s1, r1, s2, r2, (CL->T[s1])->Transversal,(CL->T[s2])->Transversal )); + + if ( !l1 && !l2)return 0; + a=(a1+a2)/2; + return a; + } +int evaluate_ca_trace_bubble_2 (Constraint_list *CL, int s1, int r1, int s2, int r2) + { + /*This Mode evaluates : + 1-The Ca neighborhood + 2-The Bubble + */ + + + return (int)((neighborhood_match (CL, s1, r1, s2, r2, (CL->T[s1])->Chain,(CL->T[s2])->Chain ))); + } + + +/*********************************************************************************************/ +/* */ +/* FUNCTIONS FOR COMPARING TWO NEIGHBORHOODS:START */ +/* */ +/*********************************************************************************************/ +float matrix_match (Constraint_list *CL, int s1, int r1, int s2, int r2, Struct_nb *nbs1, Struct_nb *nbs2) + + { + /* + Function documentation: start + + float matrix_match (Constraint_list *CL, int s1, int s2, int r1, int r2, Struct_nb *nbs1, Struct_nb *nbs2) + This function evaluates the matrix for matching two residues: + + min=worst substitution value + best=best of r1/r1, r2/r2-min + + a2=(r1/r2 -min)/best --> a1:[0, 100] + + score=a1*a2-->[-inf, +10000]; + */ + + + + float a2; + float m1, m2, m; + static float min=0; + int a, b; + + if ( !CL->M) + { + CL->M=read_matrice ( "pam250mt"); + min=CL->M[0][0]; + for ( a=0; a< 26; a++) + for ( b=0; b< 26; b++)min=MIN(min, CL->M[a][b]); + } + + if ( r1<=0 || r2<=0)return 0; + m1=CL->M[(CL->S)->seq[s1][r1-1]-'A'][(CL->S)->seq[s1][r1-1]-'A']-min; + m2=CL->M[(CL->S)->seq[s2][r2-1]-'A'][(CL->S)->seq[s2][r2-1]-'A']-min; + m=MAX(m1, m2); + a2=(CL->M[(CL->S)->seq[s1][r1-1]-'A'][(CL->S)->seq[s2][r2-1]-'A']-min)/m; + + return a2; + } + + +float transversal_match (Constraint_list *CL, int s1, int r1, int s2, int r2, Struct_nb *nbs1, Struct_nb *nbs2) + { + int a, l1, l2; + float score=0; + float delta, max_delta; + float max; + Pdb_param*PP; + + PP=(CL->T[s1])->pdb_param; + max_delta=PP->max_delta; + + l1=nbs1->nb[r1][0]; + l2=nbs2->nb[r2][0]; + + if ( l1!=l2 || l1<(PP->N_ca)) return 0; + + + max=MAX(l1, l2)*max_delta; + for ( delta=0,a=0; a< l2 ; a++) + { + + delta+=max_delta-FABS((nbs1->d_nb[r1][a]-nbs2->d_nb[r2][a])); + } + score=(delta*100)/max; + + + + return score; + } + +float neighborhood_match (Constraint_list *CL, int s1, int r1, int s2, int r2, Struct_nb *nbs1, Struct_nb *nbs2) + { + static float **table; + static int table_size; + int a, b, l1, l2; + float score=0; + float ins, del, sub; + float delta, max_delta; + float max; + Pdb_param*PP; + + + PP=(CL->T[s1])->pdb_param; + max_delta=PP->max_delta; + + + if ( r1> 0 && r2 >0) {r1--; r2--;} + else return 0; + + l1=nbs1->nb[r1][0]; + l2=nbs2->nb[r2][0]; + + if (table_size< (MAX(l1, l2)+1)) + { + table_size=MAX(l1, l2)+1; + if ( table)free_float (table, -1); + table=NULL; + } + if ( !table) table=declare_float (table_size, table_size); + + + max=MAX(l1, l2)*max_delta; + if ( max==0)return 0; + + + table[0][0]=0; + for ( b=1; b<=l2; b++) + { + table[0][b]=0; + } + for ( a=1; a<=l1; a++) + { + table[a][0]=0; + for ( b=1; b<=l2 ; b++) + { + + delta=max_delta-FABS((nbs1->d_nb[r1][a]-nbs2->d_nb[r2][b])); + + del=table[a-1][b]; + ins=table[a][b-1]; + sub= table[a-1][b-1]+delta; + + if ( del >= ins && del >= sub)score=del; + else if ( ins >= del && ins >= sub) score=ins; + else score=sub; + table[a][b]=score; + } + } + + + score=((((score)*100)/max)); + + + return score; + } + +float sap1_neighborhood_match (Constraint_list *CL, int s1, int r1, int s2, int r2, Struct_nb *nbs1, Struct_nb *nbs2) + { + /* + Function documentation: start + + float sap1_neighborhood_match (Constraint_list *CL, int s1, int s2, int r1, int r2, Struct_nb *nbs1, Struct_nb *nbs2) + This function is adapted from Taylor, Orengo, Protein Structure Alignment JMB 1989, (208)1-22 + It is the first function where + score= A/(|dra-drb|+b) + + Function documentation: end + */ + + static float **table; + static int table_size; + int a, b, l1, l2; + float score=0; + float ins, del, sub; + float delta; + float max; + + int A=50; + int B=5; + + + + + + + if ( r1> 0 && r2 >0) {r1--; r2--;} + else return 0; + + l1=nbs1->nb[r1][0]; + l2=nbs2->nb[r2][0]; + + if (table_size< (MAX(l1, l2)+1)) + { + table_size=MAX(l1, l2)+1; + if ( table)free_float (table, -1); + table=NULL; + } + if ( !table) table=declare_float (table_size, table_size); + + + max=MAX(l1, l2)*(A/B); + if ( max==0)return 0; + + + table[0][0]=0; + for ( b=1; b<=l2; b++) + { + table[0][b]=0; + } + for ( a=1; a<=l1; a++) + { + table[a][0]=0; + for ( b=1; b<=l2 ; b++) + { + + delta=A/(FABS((nbs1->d_nb[r1][a]-nbs2->d_nb[r2][b]))+B); + + del=table[a-1][b]; + ins=table[a][b-1]; + sub= table[a-1][b-1]+delta; + if ( del >= ins && del >= sub)score=del; + else if ( ins >= del && ins >= sub) score=ins; + else score=sub; + table[a][b]=score; + } + } + + + score=((score*100))/(max); + + + return score; + } + +float sap2_neighborhood_match (Constraint_list *CL, int s1, int r1, int s2, int r2, Struct_nb *nbs1, Struct_nb *nbs2) + { + /* + Function documentation: start + + float sap1_neighborhood_match (Constraint_list *CL, int s1, int s2, int r1, int r2, Struct_nb *nbs1, Struct_nb *nbs2) + This function is adapted from Taylor, Orengo, Protein Structure Alignment JMB 1989, (208)1-22 + It is the first function where + score= A/(|dra-drb|+b) + + Function documentation: end + */ + + static float **table; + static int table_size; + int a, b, l1, l2; + float score=0; + float ins, del, sub; + float delta; + float max; + + Amino_acid **pep1; + Amino_acid **pep2; + static Atom *vX_1, *vY_1, *vZ_1; + static Atom *vX_2, *vY_2, *vZ_2; + static Atom *ca1, *ca2; + float val; + + int A=50; + int B=2; + + + + + if ( r1> 0 && r2 >0) {r1--; r2--;} + else return 0; + + /*Make up the referencial*/ + pep1=(CL->T[s1])->peptide_chain; + pep2=(CL->T[s2])->peptide_chain; + + /*Get Referencial for CA1*/ + if ( (pep1[r1])->C)vX_1 =diff_atom(pep1[r1]->C,pep1[r1]->CA, vX_1); + if ( (pep1[r1])->N)vY_1 =diff_atom(pep1[r1]->N,pep1[r1]->CA, vY_1); + if ( (pep1[r1])->CB)vZ_1=diff_atom(pep1[r1]->CB,(pep1[r1])->CA,vZ_1); + else vZ_1=add_atom (vX_1, vY_1, vZ_1); + + + + + + /*Get Referencial for CA2*/ + if ( (pep2[r2])->C)vX_2 =diff_atom((pep2[r2])->C,(pep2[r2])->CA, vX_2); + if ( (pep2[r2])->N)vY_2 =diff_atom((pep2[r2])->N,(pep2[r2])->CA, vY_2); + if ( (pep2[r2])->CB)vZ_2=diff_atom((pep2[r2])->CB,(pep2[r2])->CA, vZ_2); + else vZ_2=add_atom (vX_2, vY_2, vZ_2); + + + + + /*END OF GETTING REFERENCIAL*/ + + /*Test + if ( r1>1 && r2>1) + { + fprintf (stdout,"\n\t*******"); + + fprintf (stdout, "RESIDUE %d %c", r1, (CL->S)->seq[s1][r1]); + if ( (pep1[r1])->CA)fprintf (stdout,"\n\tCA ");print_atom (pep1[r1]->CA ); + if ( (pep1[r1])->C)fprintf (stdout,"\n\tC ");print_atom (pep1[r1]->C ); + if ( (pep1[r1])->N)fprintf (stdout,"\n\tN ");print_atom (pep1[r1]->N ); + if ( (pep1[r1])->CB)fprintf (stdout,"\n\tCB ");print_atom (pep1[r1]->CB ); + fprintf (stdout,"\n\t*******"); + fprintf (stdout,"\n\tvX ");print_atom ( vX_1); + fprintf (stdout,"\n\tvY ");print_atom ( vY_1); + fprintf (stdout,"\n\tvZ ");print_atom ( vZ_1); + + ca1= copy_atom ((pep1[r1-1])->CA, ca1); + ca1 =diff_atom(ca1,(pep1[r1])->CA, ca1); + fprintf (stdout,"\n\tca ");print_atom ( ca1); + fprintf ( stdout, "\n\tSQ1=%d ", (int)square_atom(ca1)); + ca1=reframe_atom(vX_1, vY_1, vZ_1, ca1, ca1); + fprintf ( stdout, "\n\tSQ2=%d ", (int)square_atom(ca1)); + fprintf (stdout,"\n\tca ");print_atom ( ca1); + fprintf (stdout,"\n\n"); + } + */ + + l1=nbs1->nb[r1][0]; + l2=nbs2->nb[r2][0]; + + if (table_size< (MAX(l1, l2)+1)) + { + table_size=MAX(l1, l2)+1; + if ( table)free_float (table, -1); + table=NULL; + } + if ( !table) table=declare_float (table_size, table_size); + + + max=MAX(l1, l2)*(A/B); + + if ( max==0)return 0; + + + table[0][0]=0; + for ( b=1; b<=l2; b++) + { + table[0][b]=0; + } + + for ( a=1; a<=l1; a++) + { + ca1=copy_atom ((CL->T[s1])->structure[nbs1->nb[r1][a]], ca1); + ca1=diff_atom(ca1,(pep1[r1])->CA, ca1); + ca1=reframe_atom(vX_1, vY_1, vZ_1, ca1, ca1); + + table[a][0]=0; + for ( b=1; b<=l2 ; b++) + { + ca2 =copy_atom((CL->T[s2])->structure[nbs2->nb[r2][b]], ca2); + ca2 =diff_atom(ca2,(pep2[r2])->CA, ca2); + ca2 =reframe_atom(vX_2, vY_2, vZ_2, ca2, ca2); + + ca2=diff_atom(ca2,ca1,ca2); + val=square_atom (ca2); + + val=(float)sqrt ((double)val); + + delta=A/(val+B); + + + del=table[a-1][b]; + ins=table[a][b-1]; + sub= table[a-1][b-1]+delta; + + if ( del >= ins && del >= sub)score=del; + else if ( ins >= del && ins >= sub) score=ins; + else score=sub; + table[a][b]=score; + } + } + + + score=(((score*100))/(max)-50); + + + return score; + } + +/*********************************************************************************************/ +/* */ +/* APDB */ +/* */ +/*********************************************************************************************/ +float **** irmsdmin_apdb_filtration ( Alignment *A, float ****residues, Constraint_list *CL, Pdb_param *PP, FILE *fp) +{ + int s1, s2, a,col1, n,n2=0, t,flag; + int **pos, **list; + float nirmsd, min_nirmsd,max_nirmsd,ref_sum, sum, sum2; + float **normalized_len; + + normalized_len=declare_float (A->nseq+1, A->nseq+1); + for (s1=0; s1nseq; s1++) + { + int l1, l2, r1, r2, p; + for (s2=0; s2nseq; s2++) + { + for ( l1=l2=p=0; p< A->len_aln; p++) + { + r1=A->seq_al[s1][p]; + r2=A->seq_al[s2][p]; + if (!is_gap(r1) && isupper(r1))l1++; + if (!is_gap(r2) && isupper(r2))l2++; + } + normalized_len[s1][s2]=MIN(l1,l2); + } + } + + pos=aln2pos_simple (A, A->nseq); + for ( s1=0; s1< A->nseq; s1++) + for ( s2=0; s2nseq; s2++) + { + if ( s1==s2) continue; + else if (!(CL->T[A->order[s1][0]]) || !(CL->T[A->order[s2][0]]))continue; + + list=declare_int (A->len_aln, 2); + + for ( sum=0,n=0,col1=0; col1< A->len_aln; col1++) + { + if ( islower (A->seq_al[s1][col1]) || islower ( A->seq_al[s2][col1]))continue; + else if ( pos[s1][col1]<=0 || pos[s2][col1]<=0 ) continue; + else if ( residues[s1][s2][pos[s1][col1]-1][0]==0)continue; + + list[n][0]=pos[s1][col1]-1; + list[n][1]=(int)100000*residues[s1][s2][pos[s1][col1]-1][4]; + sum2+=residues[s1][s2][pos[s1][col1]-1][4]; + n++; + } + + if (n==0)return residues; + + sort_int_inv (list, 2, 1,0, n-1); + for (sum=0,a=0; a=max_nirmsd) && flag==1)break; + n2=a; + } + + sum=ref_sum; + for (a=0; anirmsd_graph) + { + fprintf ( stdout, "\n_NIRMSD_GRAPH %s %s POS: %4d Removed: %4d NiRMSD: %.2f", A->name[s1], A->name[s2], list[a][0],a,(nirmsd/100000)*normalized_len[s1][s2]); + } + } + } + + if ( PP->print_rapdb) + { + for ( a=0; a0 && a<=t)fprintf ( stdout, "\nRAPDB QUANTILE REMOVE S1: %3d S2: %3d COL: %3d SCORE*100: %d", s1, s2, list[a][0], list[a][1]); + else if ( list[a][1]>0 && a>t)fprintf ( stdout, "\nRAPDB QUANTILE KEEP S1: %3d S2: %3d COL: %3d SCORE*100: %d", s1, s2, list[a][0], list[a][1]); + } + } + + fprintf ( stdout, "\n# MINIMISATION FILTER ON: NiRMSD minimsation resulted in the removal of %d [out of %d] Columns On the alignment %s Vs %s\n", t, n, A->name[s1], A->name[s2]); + for ( a=0; a<=t; a++) + { + + residues[s1][s2][list[a][0]][0]=0; + residues[s1][s2][list[a][0]][1]=0; + residues[s1][s2][list[a][0]][2]=0; + residues[s1][s2][list[a][0]][3]=0; + residues[s1][s2][list[a][0]][4]=-1; + + } + + free_int (list, -1); + } + free_float (normalized_len, -1); + return residues; +} +float **** quantile_apdb_filtration ( Alignment *A, float ****residues, Constraint_list *CL, Pdb_param *PP,FILE *fp) +{ + int s1, s2, a,col1, n, t; + int **pos, **list; + + pos=aln2pos_simple (A, A->nseq); + for ( s1=0; s1< A->nseq; s1++) + for ( s2=0; s2nseq; s2++) + { + if ( s1==s2) continue; + else if (!(CL->T[A->order[s1][0]]) || !(CL->T[A->order[s2][0]]))continue; + + list=declare_int (A->len_aln, 2); + + for ( n=0,col1=0; col1< A->len_aln; col1++) + { + if ( islower (A->seq_al[s1][col1]) || islower ( A->seq_al[s2][col1]))continue; + else if ( pos[s1][col1]<=0 || pos[s2][col1]<=0 ) continue; + + list[n][0]=pos[s1][col1]-1; + list[n][1]=(int)100*residues[s1][s2][pos[s1][col1]-1][4]; + n++; + + } + + sort_int_inv (list, 2, 1,0, n-1); + + t=quantile_rank ( list,1, n,PP->filter); + + if ( PP->print_rapdb) + { + for ( a=0; a0 && a0 && a>t)fprintf ( stdout, "\nRAPDB QUANTILE KEEP S1: %3d S2: %3d COL: %3d SCORE*100: %d", s1, s2, list[a][0], list[a][1]); + } + } + + for ( a=0; aCL; + + for ( s1=0; s1< (A->S)->nseq; s1++) + if ( CL->T[s1]){PP=(CL->T[s1])->pdb_param;break;} + + if (PP->irmsd_graph)irmsd_graph =vfopen ((irmsd_file =vtmpnam (NULL)),"w"); + + fprintf ( fp, "\nAPDB_RESULT_FORMAT_02\n"); + residues=analyse_pdb_residues ( A, A->CL,PP); + if ( PP->filter>=0)residues=quantile_apdb_filtration (A, residues, A->CL,PP, fp); + else if ( PP->filter<0)residues=irmsdmin_apdb_filtration (A, residues, A->CL,PP, fp); + + pos=aln2pos_simple (A, A->nseq); + + + + + + /*Compute the alignment length for normalization*/ + normalize_len=declare_float (A->nseq+1, A->nseq+1); + for (s1=0; s1nseq; s1++) + { + int l1, l2, r1, r2; + for (s2=0; s2nseq; s2++) + { + for ( l1=l2=p=0; p< A->len_aln; p++) + { + r1=A->seq_al[s1][p]; + r2=A->seq_al[s2][p]; + if (!is_gap(r1) && isupper(r1))l1++; + if (!is_gap(r2) && isupper(r2))l2++; + } + normalize_len[s1][s2]=MIN(l1,l2); + } + } + + msa_len=msa_tot=msa_m1=msa_m2=msa_m3=msa_m4=msa_m5=0; + + for ( s1=0; s1< A->nseq; s1++) + { + if ( !(CL->T[A->order[s1][0]]))continue; + seq_len=seq_tot=seq_m1=seq_m2=seq_m3=seq_m4=seq_m5=0; + for ( s2=0; s2< A->nseq; s2++) + { + if ( s1==s2)continue; + if ( !(CL->T[A->order[s2][0]]))continue; + pair_tot=pair_m1=pair_m2=pair_m3=pair_m4=pair_m5=0; + for ( p=0; p< A->len_aln; p++) + { + r1=A->seq_al[s1][p]; + r2=A->seq_al[s2][p]; + b=pos[s1][p]-1; + + + if (PP->filter_aln) + { + if (is_gap(r1) || is_gap(r2) || residues[s1][s2][b][0]==0) + { + A->seq_al[s1][p]=tolower(r1); + A->seq_al[s2][p]=tolower(r2); + } + else + { + A->seq_al[s1][p]=toupper(r1); + A->seq_al[s2][p]=toupper(r2); + } + + } + + if ( PP->irmsd_graph && ( is_gap(r1) || is_gap(r2) || residues[s1][s2][b][0]==0)) + { + + fprintf ( irmsd_graph, "\n_IRMSD_GRAPH %10s %10s ALN: %c%c iRMSD: -1.00", A->name[s1], A->name[s2],A->seq_al[s1][p], A->seq_al[s2][p]); + } + + if (is_gap(r1) || is_gap(r2) || residues[s1][s2][b][0]==0)continue; + pair_tot++; + + /*APDB*/ + m2=(residues[s1][s2][b][2]*100)/residues[s1][s2][b][0]; + if (m2>PP->similarity_threshold){pair_m3++;} + + /*iRMSD*/ + + m4=residues[s1][s2][b][4]; + + if ( PP->irmsd_graph ) + { + fprintf ( irmsd_graph, "\nIRMSD_GRAPH %10s %10s ALN: %c%c iRMSD: %.2f", A->name[s1], A->name[s2],A->seq_al[s1][p], A->seq_al[s2][p], m4); + } + pair_m4+=m4; + } + pair_len=normalize_len[s1][s2]; + if ( s1>s2) + { + + fprintf ( pairwise, "\n\n#PAIRWISE: %s Vs %s",A->name[s1], A->name[s2]); + fprintf ( pairwise, "\n\tPAIRWISE EVALUATED: %6.2f %% [%s Vs %s] ", (pair_len==0)?-1:(pair_tot*100)/pair_len,A->name[s1], A->name[s2]); + fprintf ( pairwise, "\n\tPAIRWISE APDB: %6.2f %% [%s Vs %s] ", (pair_tot==0)?-1:(pair_m3*100)/pair_tot,A->name[s1], A->name[s2]); + fprintf ( pairwise, "\n\tPAIRWISE iRMSD: %6.2f Angs [%s Vs %s]", (pair_tot==0)?-1:pair_m4/pair_tot,A->name[s1], A->name[s2]); + fprintf ( pairwise, "\n\tPAIRWISE NiRMSD: %6.2f Angs [%s Vs %s] [%d pos]", (pair_tot==0)?-1:(pair_m4*pair_len)/(pair_tot*pair_tot), A->name[s1], A->name[s2], (int)pair_tot); + fprintf ( pairwise, "\n\tRAPDB PAIRS PAIRWISE N_NONEMPTY_PAIRS %d N_MAXIMUM_PAIRS %d",(int) pair_tot, (int)pair_len); + msa_m3+=pair_m3; + msa_m4+=pair_m4; + msa_tot+=pair_tot; + msa_len+=pair_len; + } + seq_m3+=pair_m3; + seq_m4+=pair_m4; + seq_tot+=pair_tot; + seq_len+=pair_len; + + } + + fprintf ( average, "\n\n#AVERAGE For Sequence %s", A->name[s1]); + fprintf ( average, "\n\tAVERAGE EVALUATED: %6.2f %% [%s]", (seq_len==0)?-1:(seq_tot*100)/seq_len, A->name[s1]); + fprintf ( average, "\n\tAVERAGE APDB: %6.2f %% [%s]", (seq_tot==0)?-1:(seq_m3*100)/seq_tot, A->name[s1]); + fprintf ( average, "\n\tAVERAGE iRMSD: %6.2f Angs [%s]", (seq_tot==0)?-1:seq_m4/seq_tot, A->name[s1]); + fprintf ( average, "\n\tAVERAGE NiRMS: %6.2f Angs [%s]", (seq_tot==0)?-1:(seq_m4*seq_len)/(seq_tot*seq_tot), A->name[s1]); + if ( strm (PP->color_mode, "apdb"))ST->score_seq[s1]=(seq_tot==0)?-1:(seq_m3*100)/pair_tot; + if (PP->print_rapdb)fprintf (average, "\n\tRAPDB PAIRS AVERAGE N_NONEMPTY_PAIRS %d N_MAXIMUM_PAIRS %d", (int)pair_tot, (int)pair_len); + + if ( strm (PP->color_mode, "irmsd"))ST->score_seq[s1]=(seq_tot==0)?-1:10*((seq_m4*pair_len)/(seq_tot*seq_tot)); + + } + fprintf ( total, "\n\n#TOTAL for the Full MSA"); + fprintf ( total, "\n\tTOTAL EVALUATED: %6.2f %% ", (msa_len==0)?-1:(msa_tot*100)/msa_len); + fprintf ( total, "\n\tTOTAL APDB: %6.2f %% ", (msa_tot==0)?-1:(msa_m3*100)/msa_tot); + fprintf ( total, "\n\tTOTAL iRMSD: %6.2f Angs", (msa_tot==0)?-1:msa_m4/msa_tot); + fprintf ( total, "\n\tTOTAL NiRMSD: %6.2f Angs", (msa_tot==0)?-1:(msa_m4*msa_len)/(msa_tot*msa_tot)); + if (PP->print_rapdb)fprintf (total, "\n\tRAPDB PAIRS TOTAL N_NONEMPTY_PAIRS: %d N_MAXIMUM_PAIRS %d", (int)msa_tot, (int)msa_len); + + if ( strm (PP->color_mode, "apdb")) ST->score_aln=ST->score=A->score_aln=A->score=(msa_tot==0)?-1:(msa_m3*100)/msa_tot; + if ( strm (PP->color_mode, "irmsd"))ST->score_aln=ST->score=A->score_aln=A->score=(msa_tot==0)?-1:10*((msa_m4*msa_len)/(msa_tot*msa_tot)); + + vfclose (average);vfclose (total); vfclose (pairwise);if (PP->irmsd_graph)vfclose (irmsd_graph); + fp=display_file_content (fp, pairwise_file); + fp=display_file_content (fp, average_file); + fp=display_file_content (fp, total_file); + if ( PP->irmsd_graph)fp=display_file_content (fp, irmsd_file); + + fprintf ( fp, "\n\n# EVALUATED: Fraction of Pairwise Columns Evaluated\n"); + fprintf ( fp, "# APDB: Fraction of Correct Columns according to APDB\n"); + fprintf ( fp, "# iRMDS: Average iRMSD over all evaluated columns\n"); + fprintf ( fp, "# NiRMDS: iRMSD*MIN(L1,L2)/Number Evaluated Columns\n"); + fprintf ( fp, "# Main Parameter: -maximum_distance %.2f Angstrom\n", PP->maximum_distance); + + fprintf ( fp, "# Undefined values are set to -1 and indicate LOW Alignment Quality\n"); + fp=print_program_information (fp, NULL); + + + + + /*Color Output*/ + for (iRMSD_max=0,iRMSD_min=10000,s1=0; s1nseq; s1++) + for ( s2=0; s2< A->nseq; s2++) + for (p=0; plen_aln; p++) + { + if ( residues[s1][s2][p][4]>0) + { + iRMSD_max=MAX(iRMSD_max, residues[s1][s2][p][4]); + iRMSD_min=MAX(iRMSD_min, residues[s1][s2][p][4]); + } + + } + iRMSD_unit=iRMSD_max/8; + + for (p=0; p< A->len_aln; p++) + for ( s1=0; s1< A->nseq; s1++) + { + + for ( p=0; p< A->len_aln; p++) + { + r1=A->seq_al[s1][p]; + b=pos[s1][p]-1; + if ( is_gap(r1) || !(CL->T[A->order[s1][0]])) + ST->seq_al[s1][p]=NO_COLOR_RESIDUE; + else + { + float tot_m2=0, tot_m4=0, v=0; + seq_m2=seq_m4=0; + + for (s2=0; s2< A->nseq; s2++) + { + r2=A->seq_al[s1][p]; + if ( s1==s2) continue; + if (is_gap(r2) || !(CL->T[A->order[s1][0]]) || residues[s1][s2][b][0]==0)continue; + + seq_m2+=m2=(residues[s1][s2][b][2]*100)/residues[s1][s2][b][0]; + tot_m2++; + + m4=residues[s1][s2][b][4]; + if (m4>=0) + { + seq_m4+=m4; + tot_m4++; + } + } + + if (strm ( PP->color_mode, "apdb")) + { + if (tot_m2==0)v=NO_COLOR_RESIDUE; + else v=MIN((seq_m2/(10*tot_m2)),9); + } + else if ( strm (PP->color_mode, "irmsd")) + { + if ( tot_m4==0)v=NO_COLOR_RESIDUE; + else v=(8-(int)((seq_m4/(iRMSD_unit*tot_m4))))+1; + } + ST->seq_al[s1][p]=v; + + } + } + } + for ( p=0; plen_aln; p++) ST->seq_al[A->nseq][p]=NO_COLOR_RESIDUE; + + + ST->generic_comment=vcalloc ( 100, sizeof (int)); + if ( strm (PP->color_mode, "apdb")) + { + sprintf ( ST->generic_comment, "# APDB Evaluation: Color Range Blue-[0 %% -- 100 %%]-Red\n# Sequence Score: APDB\n# Local Score: APDB\n\n"); + } + else if ( strm (PP->color_mode, "irmsd")) + { + sprintf ( ST->generic_comment, "\n# iRMSD Evaluation:\n# Sequence score: NiRMSD (Angstrom*10)\n# Local Score: iRMSD, Blue-[%.2f Ang. -- 0.00 Ang.]-Red \n", iRMSD_max); + } + + fprintf ( fp, "\n"); + vfclose (fp); + free_int (pos, -1); + return ST; + } +float **** analyse_pdb_residues ( Alignment *A, Constraint_list *CL, Pdb_param *pdb_param) + { + + int **pos; + int s1, s2, rs1, rs2; + int col1, col2; + float ****distances; + + /*Distances[Nseq][len_aln][4] + distances...[0]: Number of residues within the bubble + distances...[1]: Absolute difference of distance of residues within Bubble + distances...[2]: Number of residues within the bubble with Delta dist < md_threshold + distances ..[3]: Sum of squared difference of distances + distances ..[4]: iRMSD + */ + float d1, d2,delta; + int wd1, wd2; + int in_bubble=0; + int real_res1_col1=0; + int real_res1_col2; + int real_res2_col1; + int real_res2_col2; + Pdb_param *PP; + int print_rapdb; + float nrapdb, rapdb; + Alignment *BA=NULL; + + PP=pdb_param; + print_rapdb=PP->print_rapdb; + + distances=declare_arrayN(4, sizeof (float), A->nseq, A->nseq, 0, 0); + + /*Pre-computation of the internal distances----> T[seq]->ca_dist[len][len]*/ + /*Can be avoided if distance_on_request set to 1 */ + + for ( s1=0; s1< A->nseq; s1++) + { + rs1=A->order[s1][0]; + if (CL->T[rs1] && !(CL->T[rs1])->ca_dist)(CL->T[rs1])->ca_dist=measure_ca_distances(CL->T[rs1]); + for ( s2=0; s2< A->nseq; s2++) + { + distances[s1][s2]=declare_float ( A->len_aln, 6); + } + } + pos=aln2pos_simple (A, A->nseq); + + for ( s1=0; s1< A->nseq; s1++) + for ( col1=0; col1< A->len_aln; col1++) + for ( s2=0; s2nseq; s2++) + { + rs1=A->order[s1][0]; + rs2=A->order[s2][0]; + rapdb=0; + nrapdb=0; + if ( s1==s2) continue; + else if (!(CL->T[rs1]) || !(CL->T[rs2]))continue; + else if ( islower (A->seq_al[s1][col1]) || islower ( A->seq_al[s2][col1]))continue; + else if ( pos[s1][col1]<=0 || pos[s2][col1]<=0 ) continue; + + if ( print_rapdb && s2>s1) + { + + fprintf ( stdout, "RAPDB S1: %s S2: %s POS %d %d %c %d %c ", A->name[s1], A->name[s2], col1+1, pos[s1][col1],A->seq_al[s1][col1], pos[s2][col1],A->seq_al[s2][col1]); + BA=copy_aln (A, BA); + lower_string (BA->seq_al[s1]); + lower_string (BA->seq_al[s2]); + BA->seq_al[s1][col1]=toupper (BA->seq_al[s1][col1]); + BA->seq_al[s2][col1]=toupper (BA->seq_al[s2][col1]); + } + + for ( col2=0; col2len_aln; col2++) + { + + if (pos[s1][col2]<=0 || pos[s2][col2]<=0 )continue; + else if ( FABS((pos[s1][col2]-pos[s1][col1]))<=PP->n_excluded_nb)continue; + else if ( FABS((pos[s2][col2]-pos[s2][col1]))<=PP->n_excluded_nb)continue; + else if ( islower (A->seq_al[s1][col2]) || islower ( A->seq_al[s2][col2]))continue; + + real_res1_col1=pos[s1][col1]-1; + real_res1_col2=pos[s1][col2]-1; + + real_res2_col1=pos[s2][col1]-1; + real_res2_col2=pos[s2][col2]-1; + + d1=(CL->T[rs1])->ca_dist[real_res1_col1][real_res1_col2]; + d2=(CL->T[rs2])->ca_dist[real_res2_col1][real_res2_col2]; + + if ( d1==UNDEFINED || d2 == UNDEFINED) continue; + + + + if ( strm ( PP->local_mode, "sphere")) + { + in_bubble= (d1maximum_distance && d2maximum_distance)?1:0; ; + } + else if ( strm ( PP->local_mode, "window")) + { + wd1=FABS((pos[s1][col2]-pos[s1][col1])); + wd2=FABS((pos[s2][col2]-pos[s2][col1])); + in_bubble= (wd1maximum_distance && wd2maximum_distance)?1:0; ; + } + + if (in_bubble) + { + if ( print_rapdb && s2 >s1) + { + fprintf ( stdout, "NB %d %d %c %d %c ", col2, pos[s1][col2], A->seq_al[s1][col2], pos[s2][col2], A->seq_al[s2][col2]); + BA->seq_al[s1][col2]=toupper (BA->seq_al[s1][col2]); + BA->seq_al[s2][col2]=toupper (BA->seq_al[s2][col2]); + } + delta=FABS((d1-d2)); + if (deltamd_threshold) + distances[s1][s2][real_res1_col1][2]++; + distances[s1][s2][real_res1_col1][1]+=delta; + distances[s1][s2][real_res1_col1][0]++; + distances[s1][s2][real_res1_col1][3]+=delta*delta; + nrapdb++; + rapdb+=delta*delta; + } + } + + if ( nrapdb==0)distances[s1][s2][real_res1_col1][4]=-1; + else distances[s1][s2][real_res1_col1][4]=(float)sqrt((double)(rapdb/nrapdb)); + + if ( print_rapdb && s2>s1) + { + if (nrapdb==0) + { + fprintf ( stdout, "APDB: UNDEFINED\n"); + } + else + { + + fprintf ( stdout, " APDB: %.2f ",(float)sqrt((double)(rapdb/nrapdb))); + BA->residue_case=KEEP_CASE;unalign_residues (BA, s1, s2); + fprintf ( stdout,"SEQ1: %s %s SEQ2: %s %s\n", BA->name[s1], BA->seq_al[s1], BA->name[s2], BA->seq_al[s2]); + } + } + + } + + free_aln (BA); + free_int (pos, -1); + return distances; + } +int pair_res_suitable4trmsd (int s1,int col1, int col2, Alignment *A, int **pos, Pdb_param *PP, Constraint_list *CL,int *s); +int aln_column_contains_gap (Alignment *A, int c); +float aln2ncol4trmsd(Alignment *A, int **pos, Constraint_list *CL, int **lc); +int pair_columns_suitable4trmsd(int col1, int col2, Alignment *A, int **pos, Pdb_param *PP, Constraint_list *CL,int *s); +int column_is_suitable4trmsd(int col1,Alignment *A, int **pos, Pdb_param *PP, Constraint_list *CL,int *s); + + + +NT_node trmsdmat2tree (float **dm, int **count,Alignment *A); +Alignment * msa2struc_dist ( Alignment *A, Alignment *ST, char *results, int gapped, int min_ncol4trmsd) + { + + int **pos, c; + FILE *tl; + int s1, s2, rs1, rs2; + int col1, col2; + float ****distances; + float **dm,**tdm; + int **count,**tcount; + int print_subtrees=0; + float min, max; + + /*Distances[Nseq][len_aln][4] + distances...[0]: Number of residues within the bubble + distances...[1]: Absolute difference of distance of residues within Bubble + distances...[2]: Number of residues within the bubble with Delta dist < md_threshold + distances ..[3]: Sum of squared difference of distances + distances ..[4]: iRMSD + */ + Pdb_param *pdb_param; + Constraint_list *CL; + int a, b, ncol, npos,n; + float d1, d2,delta; + int wd1, wd2; + int in_bubble=0; + int real_res1_col1=0; + int real_res1_col2; + int real_res2_col1; + int real_res2_col2; + Pdb_param *PP; + int print_rapdb; + float nrapdb, rapdb; + Alignment *BA=NULL; + NT_node *T0,*T1,*T2,*PT, *POS; + NT_node BT0, BT10,BT50, BT100=NULL,RBT; + char **pair_pos_list; + + int ntree=0, ntree2; + + Alignment *B; + char *pos_list; + char *tot_pos_list; + + char *struc_tree10; + char *struc_tree100; + char *struc_tree50; + char *struc_tree0; + char *consense_file; + + char *color_struc_tree; + int **score; + int proceed=1; + int **lc; + int used; + + if (min_ncol4trmsd<0) + { + min_ncol4trmsd*=-1; + min_ncol4trmsd=(min_ncol4trmsd*A->len_aln)/100; + } + else if ( min_ncol4trmsd>=A->len_aln) + { + min_ncol4trmsd=A->len_aln-1; + } + + lc=declare_int (A->nseq, 2); + for (a=0; anseq; a++)lc[a][0]=a; + + declare_name(tot_pos_list); + sprintf ( tot_pos_list, "%s.struc_tree.list", results); + + declare_name(consense_file); + sprintf (consense_file, "%s.struc_tree.consense_output", results); + + declare_name(pos_list); + sprintf ( pos_list, "%s.pos_list", results); + + declare_name(struc_tree0); + sprintf ( struc_tree0, "%s.struc_tree.consensus",results); + + declare_name(struc_tree10); + sprintf ( struc_tree10, "%s.struc_tree10",results); + + declare_name(struc_tree100); + sprintf ( struc_tree100, "%s.struc_tree100",results); + + declare_name(struc_tree50); + sprintf ( struc_tree50, "%s.struc_tree50",results); + + declare_name(color_struc_tree); + sprintf ( color_struc_tree, "%s.struc_tree.html", results); + + pair_pos_list=declare_char (A->len_aln*A->len_aln+1, 100); + T1=vcalloc (A->len_aln*A->len_aln+1, sizeof (NT_node)); + T2=vcalloc (A->len_aln+1, sizeof (NT_node)); + + PT=vcalloc (A->len_aln*A->len_aln+1, sizeof (NT_node)); + POS=vcalloc (A->len_aln+1, sizeof (NT_node)); + + CL=A->CL; + + //Check all sequences have a PDB structure + + for (used=0,a=0; anseq; a++) + { + if ( ! seq2P_template_file(A->S,a)) + { + add_warning (stderr, "Sequence %s removed from the dataset [No Usable Structure]", A->name[a]); + } + else + { + if (used!=a) + { + sprintf (A->name[used], "%s", A->name[a]); + sprintf (A->seq_al[used], "%s", A->seq_al[a]); + for (b=0; b<4; b++)A->order[used][b]=A->order[a][b]; + } + used++; + } + } + + A->nseq=used; + + if (A->nseq<2)myexit (fprintf_error(stderr, "Two sequences at least must have a known structure")); + + for ( s1=0; s1< (A->S)->nseq; s1++) + if ( CL->T[s1]){PP=(CL->T[s1])->pdb_param;break;} + + for ( s1=0; s1< A->nseq; s1++) + { + rs1=A->order[s1][0]; + if (CL->T[rs1] && !(CL->T[rs1])->ca_dist)(CL->T[rs1])->ca_dist=measure_ca_distances(CL->T[rs1]); + } + pos=aln2pos_simple (A, A->nseq); + + dm=declare_float (A->nseq, A->nseq); + count=declare_int (A->nseq, A->nseq); + tdm=declare_float (A->nseq, A->nseq); + tcount=declare_int (A->nseq, A->nseq); + + PP->maximum_distance=1000; + sprintf ( PP->local_mode, "sphere"); + + while ((npos=aln2ncol4trmsd(A,pos,CL,lc))nseq>1) + { + + sort_int_inv (lc,2, 1, 0,A->nseq-1); + add_information (stderr, "Remove Sequence [%s] that contains %d un-suitable positions", A->name[lc[0][0]], lc[0][1]); + A=remove_seq_from_aln (A, A->name[lc[0][0]]); + ungap_aln (A); + pos=aln2pos_simple (A, A->nseq); + } + if (!A->nseq) + { + myexit (fprintf_error(stderr,"No suitable pair of column supporting a tree")); + } + else + fprintf ( stderr, "\n---- Number of usable positions: %d [%.2f %%]\n", npos, ((float)npos*100)/(float)A->len_aln); + + tl=vfopen (tot_pos_list, "w"); + for (ncol=0,ntree=0, col1=0; col1< A->len_aln; col1++) + { + int w,tree, cont; + //output_completion (stderr, col1, A->len_aln,1, "Sample Columns"); + if (!gapped && aln_column_contains_gap (A, col1))continue; + for ( cont=1,ntree2=0,col2=0; col2len_aln; col2++) + { + for (s1=0; s1< A->nseq-1; s1++) + { + rs1=A->order[s1][0]; + if (!pair_res_suitable4trmsd (s1,col1, col2, A, pos, PP, CL, &w))continue; + for ( s2=s1+1; s2nseq; s2++) + { + if (!pair_res_suitable4trmsd (s2,col1, col2, A, pos, PP, CL, &w))continue; + + rs2=A->order[s2][0]; + real_res1_col1=pos[s1][col1]-1; + real_res1_col2=pos[s1][col2]-1; + real_res2_col1=pos[s2][col1]-1; + real_res2_col2=pos[s2][col2]-1; + + d1=(CL->T[rs1])->ca_dist[real_res1_col1][real_res1_col2]; + d2=(CL->T[rs2])->ca_dist[real_res2_col1][real_res2_col2]; + + delta=FABS((d1-d2)); + dm[s1][s2]=dm[s2][s1]+=delta; + tdm[s1][s2]=tdm[s2][s1]+=delta; + tcount[s1][s2]++; + tcount[s2][s1]++; + + count[s1][s2]++; + count[s2][s1]++; + } + } + } + + + + if ((POS[col1]=trmsdmat2tree (dm, count, A))) + { + T1[ntree]=POS[col1]; + fprintf (tl, "\n>Tree_%d Column\n", col1+1); + print_tree (T1[ntree], "newick", tl); + ntree++; + } + } + vfclose (tl); + + if (!ntree){fprintf ( stderr, "\nERROR: No suitable pair of column supporting a tree [FATAL]\n"); exit (EXIT_SUCCESS);} + + score=treelist2avg_treecmp (T1, NULL); + display_output_filename( stderr,"TreeList","newick",tot_pos_list, CHECK); + + if (treelist_file2consense (tot_pos_list, NULL, consense_file)) + { + display_output_filename( stderr,"ConsenseTree","phylip",consense_file, CHECK); + } + else + { + fprintf ( stderr, "\nPhylip is not installed: the program could not produce the consense output. This is not mandatory but useful"); + } + + //consensus tree + + if ((BT100=treelist2filtered_bootstrap (T1, NULL,score, 1.0))) + { + vfclose (print_tree (BT100,"newick", vfopen (struc_tree0, "w"))); + display_output_filename( stderr,"Tree","newick",struc_tree0, CHECK); + } + if (print_subtrees) + { + + if ( (BT0=trmsdmat2tree (tdm, tcount, A))) + { + vfclose (print_tree (BT0,"newick", vfopen (struc_tree0, "w"))); + display_output_filename( stderr,"Tree","newick",struc_tree0, CHECK); + } + if ((BT10=treelist2filtered_bootstrap (T1, NULL,score, 0.1))) + { + vfclose (print_tree (BT10,"newick", vfopen (struc_tree10, "w"))); + display_output_filename( stderr,"Tree","newick",struc_tree10, CHECK); + } + + if ((BT50=treelist2filtered_bootstrap (T1, NULL, score,0.5))) + { + vfclose (print_tree (BT50,"newick", vfopen (struc_tree50, "w"))); + display_output_filename( stderr,"Tree","newick",struc_tree50, CHECK); + } + } + + + if (!BT100)BT100=treelist2filtered_bootstrap (T1, NULL,score, 1.0); + + RBT=BT100; + if (RBT) + { + B=copy_aln (A, NULL); + for (a=0; alen_aln; a++) + { + int score; + Tree_sim *S=NULL; + + if (POS[a]) + { + S=tree_cmp (POS[a], RBT); + score=S->uw/10; + } + else + { + score=NO_COLOR_RESIDUE; + } + + for (b=0; bnseq; b++) + { + if ( is_gap (B->seq_al[b][a]) || score == NO_COLOR_RESIDUE) + { + B->seq_al[b][a]=NO_COLOR_RESIDUE; + } + else + { + B->seq_al[b][a]=S->uw/10; + } + } + if (S)vfree (S); + } + + output_format_aln ("score_html", A,B,color_struc_tree); + display_output_filename( stderr,"Colored MSA","score_html",color_struc_tree, CHECK); + free_aln (BA); + fprintf ( stderr, "\n"); + } + fprintf ( stderr, "\n"); + free_int (pos, -1); + exit (EXIT_SUCCESS); + return NULL; + } +NT_node trmsdmat2tree (float **dm, int **count,Alignment *A) +{ + float min, max; + int s1, s2; + NT_node T; + int ns; + int **dm_int; + + ns=A->nseq; + for (s1=0; s1nseq-1; s1++) + for (s2=s1+1; s2nseq; s2++) + { + dm_int[s1][s2]=dm_int[s2][s1]=((dm[s1][s2])/(max))*100; + } + T=compute_std_tree_2(A, dm_int, "_TMODE_upgma"); + free_int (dm_int, -1); + for (s1=0; s1order[s1][0]; + if ( !(CL->T[rs])){s[0]=s1; return 0;} + else if (is_gap (A->seq_al[s1][col1])){s[0]=s1;return 0;} + else if (is_gap (A->seq_al[s1][col2])){s[0]=s1;return 0;} + + else if (islower(A->seq_al[s1][col1])){s[0]=s1; return 0;} + else if (islower(A->seq_al[s1][col2])){s[0]=s1; return 0;} + + else if ( FABS(((pos[s1][col2])-(pos[s1][col1])))<=PP->n_excluded_nb){s[0]=s1;return 0;} + else if ((CL->T[rs])->ca_dist[pos[s1][col1]-1][pos[s1][col2]-1]==UNDEFINED){s[0]=s1;return 0;} + return 1; +} +int pair_columns_suitable4trmsd(int col1, int col2, Alignment *A, int **pos, Pdb_param *PP, Constraint_list *CL,int *s) +{ + int s1; + if (!column_is_suitable4trmsd (col1, A, pos, PP, CL,s))return 0; + if (!column_is_suitable4trmsd (col2, A, pos, PP, CL,s))return 0; + for (s1=0; s1nseq; s1++) + { + int rs, rr1, rr2; + + rs=A->order[s1][0]; + if ( FABS(((pos[s1][col2])-(pos[s1][col1])))<=PP->n_excluded_nb){s[0]=s1;return 0;} + if ((CL->T[rs])->ca_dist[pos[s1][col1]-1][pos[s1][col2]-1]==UNDEFINED){s[0]=s1;return 0;} + rr1=pos[s1][col1]-1; + rr2=pos[s1][col2]-1; + if ((CL->T[rs])->ca_dist[rr1][rr2]>PP->maximum_distance){s[0]=s1;return 0;} + } + return 1; +} +int column_is_suitable4trmsd(int col1,Alignment *A, int **pos, Pdb_param *PP, Constraint_list *CL,int *s) +{ + int s1; + for ( s1=0; s1nseq; s1++) + { + int rs; + rs=A->order[s1][0]; + if ( !(CL->T[rs])){s[0]=s1; return 0;} + else if (is_gap (A->seq_al[s1][col1])){s[0]=s1;return 0;} + else if (islower(A->seq_al[s1][col1])){s[0]=s1; return 0;} + } + return 1; +} +int aln_column_contains_gap (Alignment *A, int c) +{ + int a, b; + if ( !A || c>=A->len_aln || c<0) + { + printf ( "\nERROR: values out of range in aln_column_contains_gap [FATL:%s]\n", PROGRAM); + exit (EXIT_FAILURE); + } + for ( a=0; anseq; a++) if ( is_gap(A->seq_al[a][c]))return 1; + return 0; +} + + +float aln2ncol4trmsd(Alignment *A, int **pos, Constraint_list *CL, int **lc) +{ + //This function estimates the number of columns suitable for constructing a trmsd + int col1, s1, ncol, n, rs1, real_res1_col1; + + for (s1=0; s1nseq; s1++){lc[s1][0]=s1; lc[s1][1]=0;} + for (ncol=0,col1=0; col1< A->len_aln; col1++) + { + for (n=0,s1=0; s1nseq; s1++) + { + real_res1_col1=pos[s1][col1]-1; + rs1=A->order[s1][0]; + + if (real_res1_col1<0)lc[s1][1]++; + else if (!((CL->T[A->order[s1][0]])->ca[real_res1_col1]))lc[s1][1]++; + else n++; + } + if (n==A->nseq) + { + ncol++; + } + } + return ncol; +} + +float square_atom ( Atom *X) +{ + + return X->x*X->x + X->y*X->y + X->z*X->z; +} +Atom* reframe_atom ( Atom *X, Atom*Y, Atom *Z, Atom *IN, Atom *R) + { + float new_x, new_y, new_z; + + if ( R==NULL)R=vcalloc ( 1, sizeof (Atom)); + + + new_x= X->x*IN->x + Y->x*IN->y +Z->x*IN->z; + new_y= X->y*IN->x + Y->y*IN->y +Z->y*IN->z; + new_z= X->z*IN->x + Y->z*IN->y +Z->z*IN->z; + + R->x=new_x; + R->y=new_y; + R->z=new_z; + return R; + } + +Atom* add_atom ( Atom *A, Atom*B, Atom *R) +{ + if ( R==NULL)R=vcalloc ( 1, sizeof (Atom)); + + R->x=A->x+B->x; + R->y=A->y+B->y; + R->z=A->z+B->z; + + return R; +} +Atom* diff_atom ( Atom *A, Atom*B, Atom *R) +{ + if ( R==NULL)R=vcalloc ( 1, sizeof (Atom)); + + R->x=A->x-B->x; + R->y=A->y-B->y; + R->z=A->z-B->z; + + return R; +} + +Atom * copy_atom ( Atom *A, Atom*R) +{ + if ( R==NULL)R=vcalloc ( 1, sizeof (Atom)); + R->num=A->num; + R->res_num=A->res_num; + R->x=A->x; + R->y=A->y; + R->z=A->z; + + sprintf( R->type, "%s", A->type); + return R; +} + void print_atom (Atom *A) +{ + fprintf ( stdout, "%.2f %.2f %.2f", A->x, A->y, A->z); +} +/************************************************************************/ +/* */ +/* NUSSINOV */ +/* */ +/************************************************************************/ + +/*---------prototypes ----------*/ +static void computeBasePairMatrix(int**M,char*S,int l, int T); +static int backtrack(int a,int b,int**M,char*S,char*P, int T); + + + +static int basePair(char x, char y) +{ + static short **mat; + + if (!mat) + { + char alp[20]; + int a, b, c1, c2, lc1, lc2; + mat=declare_short (256, 256); + sprintf ( alp, "AGCTUagctu"); + for (a=0; amax ){ + max = numBasePairs[i][j-1]; + index = n; + // j not basepaired with some k such that i max ){ + max = val; + index=i; + } + for(k=i; k<=j-THRESHOLD; k++){ + val = basePair(S[k],S[j]) + numBasePairs[i][k-1] + + numBasePairs[k+1][j-1]; + if (val > max) { + max = val; + index=k; + } + } + numBasePairs[i][j]=max; + if (index +#include +#include +#include +#include +// #include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" +#include "dp_lib_header.h" +#include "fastal_lib_header.h" +#include "fast_tree_header.h" + + +// #include +// #define CHUNKSIZE 100 +// #define N 1000 + + +//Fastal_param *param_set; + + +/*! \mainpage T-Coffee Index Page + * + * \section intro_sec Introduction + * + * This is the introduction. + * + * \section install_sec Installation + * + * \subsection step1 Step 1: Opening the box + * + * etc... + * \section fastal_sec Fastal + * + * This program is a very fast aligner. It is capable of aligning huge sets of sequences because it keeps as much as necessary on hard disk. + */ + + + + +/*! + * \file fastal.c + * \brief Source code for the fastal algorithm + */ + + + +//************************** sparse dynamic aligning ********************************************************** + + +void +fill_arguments_sparse(Sparse_dynamic_param* method_arguments_p) +{ + method_arguments_p->diagonals = vcalloc(3,sizeof(Diagonal)); + method_arguments_p->dig_length = vcalloc(1,sizeof(int)); + *method_arguments_p->dig_length = 3; + method_arguments_p->list = NULL; + method_arguments_p->list_length = vcalloc(1,sizeof(int)); + *method_arguments_p->list_length = 0; + method_arguments_p->file_name1 = vtmpnam(NULL); + method_arguments_p->file_name2 = vtmpnam(NULL); +} + +void +free_sparse(Sparse_dynamic_param* method_arguments_p) +{ + vfree(method_arguments_p->diagonals); + vfree(method_arguments_p->dig_length); + vfree(method_arguments_p->list_length); +} + + +/** + * \brief One run of sparse dynamic programming. + * + * \param profiles The profiles. + * \param param_set The fastal parameters. + * \param method_arguments_p The method arguments. + * \param is_dna Sequences are DNA (\a is_dna = 1) or protein. + * \param edit_file The edit file. + * \param prof_file the profile file. + * \param number Number of the parent node. + * \return The length of the alignment. + */ +int +sparse_dyn(Fastal_profile **profiles, + Fastal_param *param_set, + void *method_arguments_p, + int is_dna, + FILE *edit_file, + FILE *prof_file, + int number) +{ +// printf("WHAT THE HELL ARE YOU DOING HERE?\n"); + Sparse_dynamic_param *arguments = (Sparse_dynamic_param*)method_arguments_p; +// static char *file_name1 = vtmpnam(NULL); +// static char *file_name2 = vtmpnam(NULL); + char *file_name1 = arguments->file_name1; + char *file_name2 = arguments->file_name2; + char *seq1, *seq2; + Fastal_profile *tmp1 = profiles[0]; + Fastal_profile *tmp2 = profiles[1]; + + seq1 = profile2consensus(tmp1, param_set); + seq2 = profile2consensus(tmp2, param_set); + + + int **diagonals_p = &(arguments->diagonals); + int num_diagonals = -1; + if (!strcmp(param_set->diag_method, "blastz")) + { + FILE *cons_f = fopen(file_name1,"w"); + fprintf(cons_f, ">%i\n", tmp1->prf_number); + fprintf(cons_f, "%s", seq1); + fprintf( cons_f, "\n"); + fclose(cons_f); + cons_f = fopen(file_name2,"w"); + fprintf(cons_f, ">%i\n", tmp2->prf_number); + fprintf(cons_f, "%s", seq2); + fprintf( cons_f, "\n"); + fclose(cons_f); + num_diagonals = seq_pair2blastz_diagonal(file_name1, file_name2, diagonals_p, arguments->dig_length, strlen(seq1),strlen(seq2), is_dna); + } + else if (!strcmp(param_set->diag_method, "blast")) + { + FILE *cons_f = fopen(file_name1,"w"); + fprintf(cons_f, ">%i\n", tmp1->prf_number); + fprintf(cons_f, "%s", seq1); + fprintf( cons_f, "\n"); + fclose(cons_f); + cons_f = fopen(file_name2,"w"); + fprintf(cons_f, ">%i\n", tmp2->prf_number); + fprintf(cons_f, "%s", seq2); + fprintf( cons_f, "\n"); + fclose(cons_f); + int l1 = strlen(seq1); + int l2 = strlen(seq2); + num_diagonals = seq_pair2blast_diagonal(file_name1, file_name2, diagonals_p, arguments->dig_length, l1, l2, is_dna); +// int *num_p = &num_diagonals; +// Segment* seg = extend_diagonals(*diagonals_p, num_p, l1, l2); +// printf("A: %i\n", num_diagonals); + } + else if (!strcmp(param_set->diag_method, "ktup")) + { + num_diagonals = seq_pair2diagonal_own(seq1, seq2, diagonals_p, arguments->dig_length, strlen(seq1),strlen(seq2), is_dna, 3); +// num_diagonals = seq_pair2diagonal_swift(seq1, seq2, diagonals_p, arguments->dig_length, strlen(seq1),strlen(seq2), is_dna, 3); + } + + +// arguments->diagonals = diagonals_p[0]; +// arguments->list = segments2int(seg, *num_p, seq1, seq2, profiles[0], profiles[1], arguments->list_length, param_set); + +// t ** segments2int_gap(Segment *diagonals, int num_diagonals, char *seq1, char *seq2, Fastal_profile *profile1, Fastal_profile *profile2, int *num_points, Fastal_param *param_set); + +// arguments->list = diagonals2int_dot(arguments->diagonals, num_diagonals, seq1, seq2, profiles[0], profiles[1], arguments->list_length, param_set); +// arguments->list = diagonals2int_euclidf(arguments->diagonals, num_diagonals, seq1, seq2, profiles[0], profiles[1], arguments->list_length, param_set); + arguments->list = diagonals2int_gap_test(arguments->diagonals, num_diagonals, seq1, seq2, profiles[0], profiles[1], arguments->list_length, param_set); +// arguments->list = diagonals2int(arguments->diagonals, num_diagonals, seq1, seq2, arguments->list_length, param_set); + int alignment_length = list2linked_pair_wise_fastal(profiles[0], profiles[1], param_set, arguments->list, *arguments->list_length, edit_file, prof_file, number); + int x; + + for (x = 0; x < *arguments->list_length; ++x) + { + vfree(arguments->list[x]); + } + vfree(arguments->list); + arguments->list = NULL; + vfree(seq1); + vfree(seq2); + return alignment_length; +} + + +int +fastal_compare (const void * a, const void * b) +{ + return (*(int*)a - *(int*)b); +} + + +/** + * \brief Makes a sorted list out of diagonals. + * + * \param diagonals A list of diagonals to use during dynamic programming. + * \param num_diagonals Number of diagonals. + * \param seq1 Sequence 1. + * \param seq2 Sequence 2. + * \param num_points Number of points in the list + * \param param_set Fastal parameters. + * \return A 2-dim array which contains all points needed for the sparse dynamic programming algorithm. + */ +int ** +diagonals2int(int *diagonals, + int num_diagonals, + char *seq1, + char *seq2, + int *num_points, + Fastal_param *param_set) +{ + + int l1 = strlen(seq1); + int l2 = strlen(seq2); + int gep = param_set->gep; + + int dig_length; + if (seq1 > seq2) + dig_length = l1; + else + dig_length = l2; + + int current_size = num_diagonals*dig_length + l1 +l2; + + int **list = vcalloc(current_size, sizeof(int*)); + int *diags = vcalloc(num_diagonals, sizeof(int)); + int i; + for (i = 0; i < num_diagonals; ++i) + { + diags[i] = l1 - diagonals[i*3] + diagonals[i*3+1]; + } + + qsort (diags, num_diagonals, sizeof(int), fastal_compare); + + + int *diagx = vcalloc(num_diagonals, sizeof(int)); + int *diagy = vcalloc(num_diagonals, sizeof(int)); + + + //+1 because diagonals start here at position 1, like in "real" dynamic programming + int a = -1, b = -1; + for (i = 0; i < num_diagonals; ++i) + { + if (diags[i] < l1) + { + diagx[i] = l1 - diags[i]; + diagy[i] = 0; + a= i; + } + else + break; + } + ++a; + b=a-1; + for (; i < num_diagonals; ++i) + { + diagx[i] = 0; + diagy[i] = diags[i]-l1; + b = i; + } + + vfree(diags); + int tmpy_pos; + int tmpy_value; + int **M = param_set->M; + int *last_y = vcalloc(l2+1, sizeof(int)); + int *last_x = vcalloc(l1+1, sizeof(int)); + last_y[0] = 0; + + last_x[0] = 0; + list[0] = vcalloc(6, sizeof(int)); + + int list_pos = 1; + int dig_num = l1; + int tmp_l2 = l2 + 1; + + //left border + for (; list_pos < tmp_l2; ++list_pos) + { + list[list_pos] = vcalloc(6, sizeof(int)); + list[list_pos][0] = 0; + list[list_pos][1] = list_pos; + last_y[list_pos] = list_pos; + list[list_pos][2] = list_pos*gep; + list[list_pos][4] = list_pos-1; + } + + int pos_x = 0; + int y; + int tmp_l1 = l1-1; + while (pos_x < tmp_l1) + { + if (list_pos + num_diagonals+2 > current_size) + { + current_size += num_diagonals*1000; + list = vrealloc(list, current_size * sizeof(int*)); + } + //upper border + list[list_pos] = vcalloc(6, sizeof(int)); + list[list_pos][0] = ++pos_x; + list[list_pos][1] = 0; + list[list_pos][2] = pos_x * gep; + list[list_pos][3] = last_y[0]; + tmpy_value = list_pos; + tmpy_pos = 0; + last_x[pos_x] = list_pos; + ++list_pos; + + //diagonals + for (i = a; i <= b; ++i) + { + list[list_pos] = vcalloc(6, sizeof(int)); + + list[list_pos][0] = ++diagx[i]; + + list[list_pos][1] = ++diagy[i]; + list[list_pos][3] = last_y[diagy[i]]; + list[list_pos][4] = list_pos-1; + list[list_pos][5] = last_y[diagy[i]-1]; + list[list_pos][2] = M[toupper(seq1[diagx[i]-1])-'A'][toupper(seq2[diagy[i]-1])-'A']; + last_y[tmpy_pos] = tmpy_value; + tmpy_value = list_pos; + tmpy_pos = diagy[i]; + + ++list_pos; + } + last_y[tmpy_pos] = tmpy_value; + + + //lower border + if (list[list_pos-1][1] != l2) + { + list[list_pos] = vcalloc(6, sizeof(int)); + list[list_pos][0] = pos_x; + list[list_pos][1] = l2; + list[list_pos][3] = last_y[l2]; + + list[list_pos][2] = -1000; + list[list_pos][4] = list_pos-1; + if (pos_x > l2) + list[list_pos][5] = last_x[pos_x-l2]; + else + list[list_pos][5] = l2-pos_x; + last_y[l2] = list_pos; + ++list_pos; + + } + + + if ((b >= 0) && (diagy[b] == l2)) + --b; + + if ((a >0) && (diagx[a-1] == pos_x)) + --a; + } + + + dig_num = -1; + if (list_pos + l2+2 > current_size) + { + current_size += list_pos + l2 + 2; + list = vrealloc(list, current_size * sizeof(int*)); + } + + +// right border + list[list_pos] = vcalloc(6, sizeof(int)); + list[list_pos][0] = l1; + list[list_pos][1] = 0; + list[list_pos][3] = last_x[l1-1]; + list[list_pos][2] = -1000; + ++list_pos; + + + + for (i = 1; i <= l2; ++i) + { + list[list_pos] = vcalloc(6, sizeof(int)); + list[list_pos][0] = l1; + list[list_pos][1] = i; + list[list_pos][3] = last_y[i]; + list[list_pos][4] = list_pos-1; + y = last_y[i-1]; + if ((list[y][0] == l1-1) && (list[y][1] == i-1)) + { + list[list_pos][5] = y; + list[list_pos][2] = M[toupper(seq1[l1-1])-'A'][toupper(seq2[i-1])-'A']; + } + else + { + if (i <= l1) + { + list[list_pos][5] = last_x[l1-i]; + } + else + { + list[list_pos][5] = i-l1; + } + list[list_pos][2] = -1000; + } + ++list_pos; + } + + list[list_pos - l2][2] = -1000; + + *num_points = list_pos; + vfree(diagx); + vfree(diagy); + + + return list; +} + + +/** + * \brief Makes a sorted list out of diagonals. + * + * \param diagonals A list of diagonals to use during dynamic programming. + * \param num_diagonals Number of diagonals. + * \param seq1 Sequence 1. + * \param seq2 Sequence 2. + * \param num_points Number of points in the list + * \param param_set Fastal parameters. + * \return A 2-dim array which contains all points needed for the sparse dynamic programming algorithm. + */ +int ** +diagonals2int_gap_test(int *diagonals, int num_diagonals, char *seq1, char *seq2, Fastal_profile *profile1, Fastal_profile *profile2, int *num_points, Fastal_param *param_set) +{ + int alphabet_size = param_set->alphabet_size; + int l1 = strlen(seq1); + int l2 = strlen(seq2); + int gep = param_set->gep; + + int current_size = l2+l1; + + int **list = vcalloc(current_size, sizeof(int*)); + int *diags = vcalloc(num_diagonals, sizeof(int)); + int i; + for (i = 0; i < num_diagonals; ++i) + { + diags[i] = l1 - diagonals[i*3] + diagonals[i*3+1]; + } + qsort (diags, num_diagonals, sizeof(int), fastal_compare); + + + int *diagx = vcalloc(num_diagonals, sizeof(int)); + int *diagy = vcalloc(num_diagonals, sizeof(int)); + int *old_pos = vcalloc(num_diagonals, sizeof(int)); + + //+1 because diagonals start here at position 1, like in "real" dynamic programming + int a = -1, b = -1; + for (i = 0; i < num_diagonals; ++i) + { + + if (diags[i] < l1) + { + diagx[i] = l1 - diags[i]; + diagy[i] = 0; + a= i; + } + else + break; + } + ++a; + b=a-1; + for (; i < num_diagonals; ++i) + { + diagx[i] = 0; + diagy[i] = diags[i]-l1; + b = i; + } + + vfree(diags); + int tmpy_pos; + int tmpy_value; + int **M = param_set->M; + int *last_y = vcalloc(l2+1, sizeof(int)); + int *last_x = vcalloc(l1+1, sizeof(int)); + last_y[0] = 0; + + last_x[0] = 0; + list[0] = vcalloc(6, sizeof(int)); + + int list_pos = 1; + int dig_num = l1; + int tmp_l2 = l2 + 1; + + //left border + for (; list_pos < tmp_l2; ++list_pos) + { + list[list_pos] = vcalloc(6, sizeof(int)); + list[list_pos][0] = 0; + list[list_pos][1] = list_pos; + last_y[list_pos] = list_pos; + list[list_pos][2] = list_pos*gep; + list[list_pos][4] = list_pos-1; + } + + int pos_x = 0; +// int diags_old = l2; + +// int tmp = l1; + int y; + int tmp_l1 = l1-1; + while (pos_x < tmp_l1) + { + if (list_pos + num_diagonals+2 > current_size) + { + current_size += num_diagonals*1000; + list = vrealloc(list, current_size * sizeof(int*)); + } + //upper border + list[list_pos] = vcalloc(6, sizeof(int)); + list[list_pos][0] = ++pos_x; + list[list_pos][1] = 0; + list[list_pos][2] = pos_x * gep; + list[list_pos][3] = last_y[0]; + tmpy_value = list_pos; + tmpy_pos = 0; + last_x[pos_x] = list_pos; + ++list_pos; + + //diagonals + for (i = a; i <= b; ++i) + { + list[list_pos] = vcalloc(6, sizeof(int)); + + list[list_pos][0] = ++diagx[i]; + + list[list_pos][1] = ++diagy[i]; + list[list_pos][3] = last_y[diagy[i]]; + list[list_pos][4] = list_pos-1; + list[list_pos][5] = last_y[diagy[i]-1]; + + + + +//SIMPLEGAP + int num_seq = profile1->number_of_sequences + profile2->number_of_sequences; + double gap_num = 0; + int char_c; + for (char_c = 0; char_c < alphabet_size; ++char_c) + { + + gap_num += profile1->prf[char_c][diagx[i]-1] + profile2->prf[char_c][diagy[i]-1]; + } + + gap_num /= num_seq; + + list[list_pos][2] = M[toupper(seq1[diagx[i]-1])-'A'][toupper(seq2[diagy[i]-1])-'A'] * gap_num; + +// CLUSTAL +// int num_seq = profile1->number_of_sequences + profile2->number_of_sequences; +// double gap_num = 0; +// int char_c, char_c2; +// for (char_c = 0; char_c < alphabet_size; ++char_c) +// for (char_c2 = 0; char_c2 < alphabet_size; ++char_c2) +// { +// gap_num += (profile1->prf[char_c][diagx[i]-1]/profile1->number_of_sequences) * (profile2->prf[char_c][diagy[i]-1]/profile2->number_of_sequences) * M[param_set->pos2char[char_c]-'A'][param_set->pos2char[char_c2]-'A']; +// } +// list[list_pos][2] = gap_num; + + + last_y[tmpy_pos] = tmpy_value; + tmpy_value = list_pos; + tmpy_pos = diagy[i]; + + ++list_pos; + } + last_y[tmpy_pos] = tmpy_value; + + + //lower border + if (list[list_pos-1][1] != l2) + { + list[list_pos] = vcalloc(6, sizeof(int)); + list[list_pos][0] = pos_x; + list[list_pos][1] = l2; + list[list_pos][3] = last_y[l2]; + + list[list_pos][2] = -1000; + list[list_pos][4] = list_pos-1; + if (pos_x > l2) + list[list_pos][5] = last_x[pos_x-l2]; + else + list[list_pos][5] = l2-pos_x; + last_y[l2] = list_pos; + ++list_pos; + + } + + + if ((b >= 0) && (diagy[b] == l2)) + --b; + + if ((a >0) && (diagx[a-1] == pos_x)) + --a; + } + + + dig_num = -1; + if (list_pos + l2+2 > current_size) + { + current_size += list_pos + l2 + 2; + list = vrealloc(list, current_size * sizeof(int*)); + } + + +// right border + list[list_pos] = vcalloc(6, sizeof(int)); + list[list_pos][0] = l1; + list[list_pos][1] = 0; + list[list_pos][3] = last_x[l1-1]; + list[list_pos][2] = -1000; + ++list_pos; + + + + for (i = 1; i <= l2; ++i) + { + list[list_pos] = vcalloc(6, sizeof(int)); + list[list_pos][0] = l1; + list[list_pos][1] = i; + list[list_pos][3] = last_y[i]; + list[list_pos][4] = list_pos-1; + y = last_y[i-1]; + if ((list[y][0] == l1-1) && (list[y][1] == i-1)) + { + list[list_pos][5] = y; + int num_seq = profile1->number_of_sequences + profile2->number_of_sequences; + double gap_num = 0; + int char_c; + for (char_c = 0; char_c < alphabet_size; ++char_c) + { + gap_num += profile1->prf[char_c][l1-1] + profile2->prf[char_c][i-1]; + } + + gap_num /= num_seq; + + list[list_pos][2] = M[toupper(seq1[l1-1])-'A'][toupper(seq2[i-1])-'A'] * gap_num; + } + else + { + if (i <= l1) + { + list[list_pos][5] = last_x[l1-i]; + } + else + { + list[list_pos][5] = i-l1; + } + list[list_pos][2] = -1000; + } + ++list_pos; + } + + list[list_pos - l2][2] = -1000; + + *num_points = list_pos; + vfree(diagx); + vfree(diagy); + vfree(old_pos); + + return list; +} + + +int ** +diagonals2int_euclidf(int *diagonals, int num_diagonals, char *seq1, char *seq2, Fastal_profile *profile1, Fastal_profile *profile2, int *num_points, Fastal_param *param_set) +{ + int alphabet_size = param_set->alphabet_size; + int l1 = strlen(seq1); + int l2 = strlen(seq2); + int gep = param_set->gep; + + int current_size = l2+l1; + + int **list = vcalloc(current_size, sizeof(int*)); + int *diags = vcalloc(num_diagonals, sizeof(int)); + int i; + for (i = 0; i < num_diagonals; ++i) + { + diags[i] = l1 - diagonals[i*3] + diagonals[i*3+1]; + } + + qsort (diags, num_diagonals, sizeof(int), fastal_compare); + + + int *diagx = vcalloc(num_diagonals, sizeof(int)); + int *diagy = vcalloc(num_diagonals, sizeof(int)); + int *old_pos = vcalloc(num_diagonals, sizeof(int)); + + //+1 because diagonals start here at position 1, like in "real" dynamic programming + int a = -1, b = -1; + for (i = 0; i < num_diagonals; ++i) + { + + if (diags[i] < l1) + { + diagx[i] = l1 - diags[i]; + diagy[i] = 0; + a= i; + } + else + break; + } + ++a; + b=a-1; + for (; i < num_diagonals; ++i) + { + diagx[i] = 0; + diagy[i] = diags[i]-l1; + b = i; + } + + vfree(diags); + int tmpy_pos; + int tmpy_value; +// int **M = param_set->M; + int *last_y = vcalloc(l2+1, sizeof(int)); + int *last_x = vcalloc(l1+1, sizeof(int)); + last_y[0] = 0; + + last_x[0] = 0; + list[0] = vcalloc(6, sizeof(int)); + + int list_pos = 1; + int dig_num = l1; + int tmp_l2 = l2 + 1; + + //left border + for (; list_pos < tmp_l2; ++list_pos) + { + list[list_pos] = vcalloc(6, sizeof(int)); + list[list_pos][0] = 0; + list[list_pos][1] = list_pos; + last_y[list_pos] = list_pos; + list[list_pos][2] = list_pos*gep; + list[list_pos][4] = list_pos-1; + } + + int pos_x = 0; +// int diags_old = l2; + +// int tmp = l1; + int y; + int tmp_l1 = l1-1; + while (pos_x < tmp_l1) + { + if (list_pos + num_diagonals+2 > current_size) + { + current_size += num_diagonals*1000; + list = vrealloc(list, current_size * sizeof(int*)); + } + //upper border + list[list_pos] = vcalloc(6, sizeof(int)); + list[list_pos][0] = ++pos_x; + list[list_pos][1] = 0; + list[list_pos][2] = pos_x * gep; + list[list_pos][3] = last_y[0]; + tmpy_value = list_pos; + tmpy_pos = 0; + last_x[pos_x] = list_pos; + ++list_pos; + + //diagonals + for (i = a; i <= b; ++i) + { + list[list_pos] = vcalloc(6, sizeof(int)); + + list[list_pos][0] = ++diagx[i]; + + list[list_pos][1] = ++diagy[i]; + list[list_pos][3] = last_y[diagy[i]]; + list[list_pos][4] = list_pos-1; + list[list_pos][5] = last_y[diagy[i]-1]; + int char_c; + double tmp_score = 0; + double freq1, freq2; + for (char_c = 0; char_c < alphabet_size; ++char_c) + { + freq1 = (double)profile1->prf[char_c][diagx[i]-1] / profile1->number_of_sequences; + + freq2 = (double)profile2->prf[char_c][diagy[i]-1] / profile2->number_of_sequences; + + tmp_score += ( freq1 - freq2) * (freq1 - freq2); + } + + list[list_pos][2] = 10 - sqrt(tmp_score); + + last_y[tmpy_pos] = tmpy_value; + tmpy_value = list_pos; + tmpy_pos = diagy[i]; + + ++list_pos; + } + last_y[tmpy_pos] = tmpy_value; + + + //lower border + if (list[list_pos-1][1] != l2) + { + list[list_pos] = vcalloc(6, sizeof(int)); + list[list_pos][0] = pos_x; + list[list_pos][1] = l2; + list[list_pos][3] = last_y[l2]; + + list[list_pos][2] = -1000; + list[list_pos][4] = list_pos-1; + if (pos_x > l2) + list[list_pos][5] = last_x[pos_x-l2]; + else + list[list_pos][5] = l2-pos_x; + last_y[l2] = list_pos; + ++list_pos; + + } + + + if ((b >= 0) && (diagy[b] == l2)) + --b; + + if ((a >0) && (diagx[a-1] == pos_x)) + --a; + } + + + dig_num = -1; + if (list_pos + l2+2 > current_size) + { + current_size += list_pos + l2 + 2; + list = vrealloc(list, current_size * sizeof(int*)); + } + + +// right border + list[list_pos] = vcalloc(6, sizeof(int)); + list[list_pos][0] = l1; + list[list_pos][1] = 0; + list[list_pos][3] = last_x[l1-1]; + list[list_pos][2] = -1000; + ++list_pos; + + + + for (i = 1; i <= l2; ++i) + { + list[list_pos] = vcalloc(6, sizeof(int)); + list[list_pos][0] = l1; + list[list_pos][1] = i; + list[list_pos][3] = last_y[i]; + list[list_pos][4] = list_pos-1; + y = last_y[i-1]; + if ((list[y][0] == l1-1) && (list[y][1] == i-1)) + { + list[list_pos][5] = y; + int char_c; + int tmp_score = 0; + double freq1, freq2; + for (char_c = 0; char_c < alphabet_size; ++char_c) + { + freq1 = profile1->prf[char_c][l1-1] / profile1->number_of_sequences; + freq2 = profile2->prf[char_c][i-1] / profile2->number_of_sequences; + tmp_score += ( freq1 - freq2) * (freq2 - freq1); + } + list[list_pos][2] = 10 - sqrt(tmp_score); +// list[list_pos][2] = M[toupper(seq1[l1-1])-'A'][toupper(seq2[i-1])-'A']; + } + else + { + if (i <= l1) + { + list[list_pos][5] = last_x[l1-i]; + } + else + { + list[list_pos][5] = i-l1; + } + list[list_pos][2] = -1000; + } + ++list_pos; + } + + list[list_pos - l2][2] = -1000; + + *num_points = list_pos; + vfree(diagx); + vfree(diagy); + vfree(old_pos); + + return list; +} + +int ** +diagonals2int_dot(int *diagonals, int num_diagonals, char *seq1, char *seq2, Fastal_profile *profile1, Fastal_profile *profile2, int *num_points, Fastal_param *param_set) +{ + int alphabet_size = param_set->alphabet_size; + int l1 = strlen(seq1); + int l2 = strlen(seq2); + int gep = param_set->gep; + + int current_size = l2+l1; + + int **list = vcalloc(current_size, sizeof(int*)); + int *diags = vcalloc(num_diagonals, sizeof(int)); + int i; + for (i = 0; i < num_diagonals; ++i) + { + diags[i] = l1 - diagonals[i*3] + diagonals[i*3+1]; + } + + qsort (diags, num_diagonals, sizeof(int), fastal_compare); + + + int *diagx = vcalloc(num_diagonals, sizeof(int)); + int *diagy = vcalloc(num_diagonals, sizeof(int)); + int *old_pos = vcalloc(num_diagonals, sizeof(int)); + + //+1 because diagonals start here at position 1, like in "real" dynamic programming + int a = -1, b = -1; + for (i = 0; i < num_diagonals; ++i) + { + + if (diags[i] < l1) + { + diagx[i] = l1 - diags[i]; + diagy[i] = 0; + a= i; + } + else + break; + } + ++a; + b=a-1; + for (; i < num_diagonals; ++i) + { + diagx[i] = 0; + diagy[i] = diags[i]-l1; + b = i; + } + + vfree(diags); + int tmpy_pos; + int tmpy_value; +// int **M = param_set->M; + int *last_y = vcalloc(l2+1, sizeof(int)); + int *last_x = vcalloc(l1+1, sizeof(int)); + last_y[0] = 0; + + last_x[0] = 0; + list[0] = vcalloc(6, sizeof(int)); + + int list_pos = 1; + int dig_num = l1; + int tmp_l2 = l2 + 1; + + //left border + for (; list_pos < tmp_l2; ++list_pos) + { + list[list_pos] = vcalloc(6, sizeof(int)); + list[list_pos][0] = 0; + list[list_pos][1] = list_pos; + last_y[list_pos] = list_pos; + list[list_pos][2] = list_pos*gep; + list[list_pos][4] = list_pos-1; + } + + int pos_x = 0; +// int diags_old = l2; + +// int tmp = l1; + int y; + int tmp_l1 = l1-1; + while (pos_x < tmp_l1) + { + if (list_pos + num_diagonals+2 > current_size) + { + current_size += num_diagonals*1000; + list = vrealloc(list, current_size * sizeof(int*)); + } + //upper border + list[list_pos] = vcalloc(6, sizeof(int)); + list[list_pos][0] = ++pos_x; + list[list_pos][1] = 0; + list[list_pos][2] = pos_x * gep; + list[list_pos][3] = last_y[0]; + tmpy_value = list_pos; + tmpy_pos = 0; + last_x[pos_x] = list_pos; + ++list_pos; + + //diagonals + for (i = a; i <= b; ++i) + { + list[list_pos] = vcalloc(6, sizeof(int)); + + list[list_pos][0] = ++diagx[i]; + + list[list_pos][1] = ++diagy[i]; + list[list_pos][3] = last_y[diagy[i]]; + list[list_pos][4] = list_pos-1; + list[list_pos][5] = last_y[diagy[i]-1]; + int char_c; + double tmp_score = 0; + double freq1, freq2; + for (char_c = 0; char_c < alphabet_size; ++char_c) + { + freq1 = (double)profile1->prf[char_c][diagx[i]-1] / profile1->number_of_sequences; + + freq2 = (double)profile2->prf[char_c][diagy[i]-1] / profile2->number_of_sequences; + + tmp_score += freq1 * freq2; + } + + list[list_pos][2] = tmp_score * 10; + + last_y[tmpy_pos] = tmpy_value; + tmpy_value = list_pos; + tmpy_pos = diagy[i]; + + ++list_pos; + } + last_y[tmpy_pos] = tmpy_value; + + + //lower border + if (list[list_pos-1][1] != l2) + { + list[list_pos] = vcalloc(6, sizeof(int)); + list[list_pos][0] = pos_x; + list[list_pos][1] = l2; + list[list_pos][3] = last_y[l2]; + + list[list_pos][2] = -1000; + list[list_pos][4] = list_pos-1; + if (pos_x > l2) + list[list_pos][5] = last_x[pos_x-l2]; + else + list[list_pos][5] = l2-pos_x; + last_y[l2] = list_pos; + ++list_pos; + + } + + + if ((b >= 0) && (diagy[b] == l2)) + --b; + + if ((a >0) && (diagx[a-1] == pos_x)) + --a; + } + + + dig_num = -1; + if (list_pos + l2+2 > current_size) + { + current_size += list_pos + l2 + 2; + list = vrealloc(list, current_size * sizeof(int*)); + } + + +// right border + list[list_pos] = vcalloc(6, sizeof(int)); + list[list_pos][0] = l1; + list[list_pos][1] = 0; + list[list_pos][3] = last_x[l1-1]; + list[list_pos][2] = -1000; + ++list_pos; + + + + for (i = 1; i <= l2; ++i) + { + list[list_pos] = vcalloc(6, sizeof(int)); + list[list_pos][0] = l1; + list[list_pos][1] = i; + list[list_pos][3] = last_y[i]; + list[list_pos][4] = list_pos-1; + y = last_y[i-1]; + if ((list[y][0] == l1-1) && (list[y][1] == i-1)) + { + list[list_pos][5] = y; + int char_c; + int tmp_score = 0; + double freq1, freq2; + for (char_c = 0; char_c < alphabet_size; ++char_c) + { + freq1 = profile1->prf[char_c][l1-1] / profile1->number_of_sequences; + freq2 = profile2->prf[char_c][i-1] / profile2->number_of_sequences; + tmp_score += freq2 * freq1; + } + list[list_pos][2] = tmp_score * 10; +// list[list_pos][2] = M[toupper(seq1[l1-1])-'A'][toupper(seq2[i-1])-'A']; + } + else + { + if (i <= l1) + { + list[list_pos][5] = last_x[l1-i]; + } + else + { + list[list_pos][5] = i-l1; + } + list[list_pos][2] = -1000; + } + ++list_pos; + } + + list[list_pos - l2][2] = -1000; + + *num_points = list_pos; + vfree(diagx); + vfree(diagy); + vfree(old_pos); + + return list; +} + + +void +combine_profiles2file(int **prf1, + int **prf2, + int pos1, + int pos2, + Fastal_param *param_set, + FILE *prof_f, + char state) +{ + int alphabet_size = param_set->alphabet_size; + char *pos2aa = &(param_set->pos2char[0]); + int i; + int x = 0; + if (state == 'M') + { + for (i = 0; i < alphabet_size; ++i) + if (prf1[i][pos1] + prf2[i][pos2] > 0) + { + if (x) + fprintf(prof_f," %c%i", pos2aa[i],prf1[i][pos1]+prf2[i][pos2]); + else + fprintf(prof_f,"%c%i", pos2aa[i],prf1[i][pos1]+prf2[i][pos2]); + x = 1; + } + fprintf(prof_f,"\n"); + } + else if (state == 'D') + { + for (i = 0; i < alphabet_size; ++i) + if (prf2[i][pos2] > 0) + { + if (x) + fprintf(prof_f," %c%i", pos2aa[i],prf2[i][pos2]); + else + fprintf(prof_f,"%c%i", pos2aa[i],prf2[i][pos2]); + x = 1; + } + fprintf(prof_f,"\n"); + } + else + { + for (i = 0; i < alphabet_size; ++i) + if (prf1[i][pos1] > 0) + { + if (x) + fprintf(prof_f," %c%i", pos2aa[i],prf1[i][pos1]); + else + fprintf(prof_f,"%c%i", pos2aa[i],prf1[i][pos1]); + x = 1; + } + fprintf(prof_f,"\n"); + } +} + + + +#define LIN(a,b,c) a[b*5+c] +/** + * Calculates a fast and sparse dynamic programming matrix + * + * \param prf1 Profile of first sequence. + * \param prf2 Profile of second sequence. + * \param param_set The parameter for the alignment. + * \param list The list of diagonals. + * \param n number of dots. + * \param edit_f File to save the edit information. + * \param prof_f File to save the profile. + * \param node_number Number of the new profile. + */ +int +list2linked_pair_wise_fastal(Fastal_profile *prf1, + Fastal_profile *prf2, + Fastal_param *param_set, + int **list, + int n, + FILE *edit_f, + FILE *prof_f, + int node_number) +{ + int a,b, i, j, LEN=0, start_trace = -1; + int pi, pj,ij, delta_i, delta_j, prev_i, prev_j; +// static int **slist; + static long *MI, *MJ, *MM,*MT2; +// static int *sortseq; + static int max_size; + int gop, gep, igop, igep; + int l1, l2, l, ls; + char **al; + int ni=0, nj=0; + long score; + int nomatch = param_set->nomatch; + + l1=prf1->length; + l2=prf2->length; + + al=declare_char (2,l1+l2+1); + + + + igop=param_set->gop; + gep=igep=param_set->gep; + if (n>max_size) + { + max_size=n; + + vfree (MI);vfree (MJ); vfree (MM); + + MI=vcalloc (5*n, sizeof (long)); + MJ=vcalloc (5*n, sizeof (long)); + MM=vcalloc (5*n, sizeof (long)); + + } + else + { + for (a=0; a=(LIN(MM,pi,0)+gop))?'i':'m'; + + LIN(MJ,a,0)=MAX(LIN(MJ,pj,0),(LIN(MM,pj,0)+gop))+delta_j*gep; + LIN(MJ,a,1)=pj; + LIN(MJ,a,2)=0; + LIN(MJ,a,3)=delta_j; + + LIN(MJ,a,4)=(LIN(MJ,pj,0) >=LIN(MM,pj,0)+gop)?'j':'m'; + + if (a>1 && (ls=list[a][0]-list[ij][0])==(list[a][1]-list[ij][1])) + { + LIN(MM,a,0)=MAX3(LIN(MM,ij,0),LIN(MI,ij,0),LIN(MJ,ij,0))+list[a][2]-(ls*nomatch); + + LIN(MM,a,1)=ij; + LIN(MM,a,2)=ls; + LIN(MM,a,3)=ls; + if ( LIN(MM,ij,0) >=LIN(MI,ij,0) && LIN(MM,ij,0)>=LIN(MJ,ij,0))LIN(MM,a,4)='m'; + else if ( LIN(MI,ij,0) >= LIN(MJ,ij,0))LIN(MM,a,4)='i'; + else LIN(MM,a,4)='j'; + + } + else + { + LIN(MM,a,0)=UNDEFINED; + LIN(MM,a,1)=-1; + } + } + + a=start_trace; + if (LIN(MM,a,0)>=LIN(MI,a,0) && LIN(MM,a,0) >=LIN(MJ,a,0))MT2=MM; + else if ( LIN(MI,a,0)>=LIN(MJ,a,0))MT2=MI; + else MT2=MJ; + + score=MAX3(LIN(MM,a,0), LIN(MI,a,0), LIN(MJ,a,0)); + + i=l1; + j=l2; + + while (!(i==0 &&j==0)) + { + int next_a; + l=MAX(LIN(MT2,a,2),LIN(MT2,a,3)); + // HERE ("%c from %c %d %d SCORE=%d [%d %d] [%2d %2d]", T2[a][5],T2[a][4], T2[a][2], T2[a][3], T2[a][0], gop, gep, i, j); + if (i==0) + { + while ( j>0) + { + al[0][LEN]=0; + al[1][LEN]=1; + j--; LEN++; + } + } + else if (j==0) + { + while ( i>0) + { + al[0][LEN]=1; + al[1][LEN]=0; + i--; LEN++; + } + } + +// else if (l==0) {HERE ("L=0 i=%d j=%d",l, i, j);exit (0);} + else + { + for (b=0; bprf_number, prf2->prf_number, prf1->is_leaf, prf2->is_leaf); + fprintf(prof_f, "%i\n0\n%i\n1\n%i\n", node_number,LEN, prf1->number_of_sequences+prf2->number_of_sequences); + + char statec[] = {'M','D','I'}; + int num = 0; + int state = 0; + i = 0; + j = 0; + + for ( b=0; b< LEN; b++) + { + if ((al[0][b]==1) && (al[1][b]==1)) + { + + combine_profiles2file(prf1->prf, prf2->prf, i, j, param_set, prof_f, 'M'); + ++i; + ++j; + if (state != 0) + { + fprintf(edit_f, "%c%i\n",statec[state], num); + num =1; + state = 0; + } + else + ++num; + } + else if (al[0][b]==1) + { +// prf1->prf[param_set->alphabet_size-1] += prf2->num_sequences; + combine_profiles2file(prf1->prf, prf2->prf, i, j, param_set, prof_f, 'I'); + ++i; + if (state != 2) + { + fprintf(edit_f, "%c%i\n",statec[state], num); + num =1; + state = 2; + } + else + ++num; + } + else if (al[1][b]==1) + { +// prf2->prf[param_set->alphabet_size-1] += prf1->num_sequences; + combine_profiles2file(prf1->prf, prf2->prf, i, j, param_set, prof_f, 'D'); + ++j; + if (state != 1) + { + fprintf(edit_f, "%c%i\n",statec[state], num); + num =1; + state = 1; + } + else + ++num; + } + } + + + fprintf(edit_f, "%c%i\n",statec[state], num); + num =1; + state = 1; + + + fprintf(edit_f,"*\n"); + fprintf(prof_f,"*\n"); + free_char (al, -1); +// exit(0); + return LEN; +} + + + + + + +/** + * \brief Turns a profile into a consensus sequence. + * + * The character with the highest number of occurences is used as consensus. Gaps are not included. For example: 10 '-' and one 'A' would give 'A' as consensus. + * \param profile The profile. + * \param file_name Name of the file to save the consensus sequence in. + * \param param_set The parameter of the fastal algorithm. + * \return the sequence + */ +char* +profile2consensus(Fastal_profile *profile, Fastal_param *param_set) +{ + +// FILE *cons_f = fopen(file_name,"w"); +// fprintf(cons_f, ">%i\n", profile->prf_number); + char* seq = vcalloc(profile->length+1, sizeof(char)); + int i, j; + int most_pos = -1, most; + int alphabet_size = param_set->alphabet_size; + int **prf = profile->prf; + char *pos2char = param_set->pos2char; + for (i = 0; i < profile->length; ++i) + { + most = -1; + for (j = 0; j < alphabet_size; ++j) + { + if (prf[j][i] > most) + { + most = prf[j][i]; + most_pos = j; + } + } + seq[i] = pos2char[most_pos]; +// fprintf(cons_f, "%c",pos2char[most_pos]); + } + return seq; +} + + +int +diag_compare (const void * a, const void * b) +{ + return (((Diagonal_counter*)b)->count - ((Diagonal_counter*)a)->count); +} + +/** + * \brief Calculates the diagonals between two sequences. + * + * Uses to calculate the diagonals. + * \param seq_file1 File with sequence 1. + * \param seq_file2 File with sequence 2. + * \param diagonals An array where the diagonal points will be stored. + * \param dig_length length of \a diagonals . + * \param num_points Number of points in all diagonals. + * \return number of diagonals; + */ +int +seq_pair2diagonal_own(char *seq1, + char *seq2, + int **diagonals, + int *dig_length, + int l1, + int l2, + int is_dna, + int word_length) +{ +// word_length = 7; + int word_number, i; + int ng; + if (is_dna) + { + word_number = (int)pow(5, word_length); + ng = 4; + } + else + { + word_number = (int)pow(24, word_length); + ng = 24; + } + int **word_index = vcalloc(word_number, sizeof(int*)); + for (i = 0 ; i < word_number; ++i) + { + word_index[i] = vcalloc(20, sizeof(int)); + word_index[i][0] = 2; + word_index[i][1] = 20; + } + + + //making of k-tup index of seq1 + + int *prod=vcalloc (word_length, sizeof(int)); + for ( i=0; i window_length-3) + diag_index[i2 - tmp[j] + l1].count = window_length+100; + else + --diag_index[i2 - tmp[j] + l1].count; + } + } + + + //choose diagonals + int *diags = diagonals[0]; + int current_pos = 0; + + + qsort (diag_index, num, sizeof(Diagonal_counter*), diag_compare); + + i = 0; + int y, x; + while (diag_index[i].count > window_length+10) + { + if (current_pos > (*dig_length)-3) + { + (*dig_length) += 30; + diags = vrealloc(diags, sizeof(int)*(*dig_length)); + } + + + y = diag_index[i].diagonal - l1; + if (y < 0) + { + x = y * (-1); + y = 0; + } + else + { + x = 0; + } + diags[current_pos++] = x; + diags[current_pos++] = y; + diags[current_pos++] = 200; + ++i; + } + + vfree(diag_index); + for (i = 0; i < word_number; ++i) + vfree(word_index[i]); + vfree(word_index); + diagonals[0] = diags; + return current_pos/3; +} + + + +int +seq_pair2diagonal_swift(char *seq1, + char *seq2, + int **diagonals, + int *dig_length, + int l1, + int l2, + int is_dna, + int word_length) +{ + int word_number, i; + int ng; + if (is_dna) + { + word_number = (int)pow(5, word_length); + ng = 5; + } + else + { + word_number = (int)pow(24, word_length); + ng = 24; + } + int **word_index = vcalloc(word_number, sizeof(int*)); + for (i = 0 ; i < word_number; ++i) + { + word_index[i] = vcalloc(20, sizeof(int)); + word_index[i][0] = 2; + word_index[i][1] = 20; + } + + + //making of k-tup index of seq1 + + int *prod=vcalloc (word_length, sizeof(int)); + for ( i=0; i window_length) + { + if (diag_index[tmp_index].count < threshold) + { + diag_index[tmp_index].count = 0; + diag_index[tmp_index].start = i; + diag_index[tmp_index].end = i + word_length; + } + + } + else + { + ++(diag_index[tmp_index].count); + } + } + + } + + + + // choose diagonals + int *diags = diagonals[0]; + int current_pos = 0; + int x, y; + for (i = 0; i < num; ++i) + { + if (diag_index[i].count > threshold) + { + if (current_pos > (*dig_length)-3) + { + (*dig_length) += 30; + diags = vrealloc(diags, sizeof(int)*(*dig_length)); + } + y = diag_index[i].diagonal - l1; + if (y < 0) + { + x = y * (-1); + y = 0; + } + else + { + x = 0; + } + diags[current_pos++] = x; + diags[current_pos++] = y; + diags[current_pos++] = 200; + } + } + + vfree(diag_index); + for (i = 0; i < word_number; ++i) + vfree(word_index[i]); + vfree(word_index); + diagonals[0] = diags; + + return current_pos/3; +} + + + +/** + * \brief Calculates the diagonals between two sequences. + * + * Uses a k-tup index to choose diagonals. + * \param seq_file1 File with sequence 1. + * \param seq_file2 File with sequence 2. + * \param diagonals An array where the diagonal points will be stored. + * \param dig_length length of \a diagonals . + * \param num_points Number of points in all diagonals. + * \return number of diagonals; + */ +int +seq_pair2blast_diagonal(char *seq_file_name1, + char *seq_file_name2, + int **diagonals, + int *dig_length, + int l1, + int l2, + int is_dna) +{ +// static int blast_measure[12]={0,0,0,0,0,0,0,0,0,0,0,0}; + int *diag = vcalloc(l1 + l2, sizeof(int)); + char *out_file = vtmpnam(NULL); + char blast_command[200]; +// char blast_command2[200]; +// if (x) +// { +// int i; +// printf("BLAST-Types:\n"); +// for (i = 0; i < 11; ++i) +// { +// printf("Type %i: %i\n", i, blast_measure[i]); +// } +// return 0; +// } +// char blast_command2[600]; +// sprintf(blast_command2, "less %s", out_file); + + if (is_dna) + { + sprintf(blast_command, "bl2seq -p blastn -i %s -j %s -D 1 -g F -o %s -S 1 -F F", seq_file_name1, seq_file_name2, out_file); + } + else + { + sprintf(blast_command, "bl2seq -p blastp -i %s -j %s -D 1 -g F -o %s -F F -S 1", seq_file_name1, seq_file_name2, out_file); + } + system(blast_command); + + int *diags = diagonals[0]; + FILE *diag_f = fopen(out_file,"r"); + char line[300]; + fgets(line, 300, diag_f); + fgets(line, 300, diag_f); + fgets(line, 300, diag_f); + + + char delims[] = "\t"; + int length, pos_q, pos_d; + int current_pos = 0; + while (fgets(line, 300, diag_f) != NULL) + { + strtok(line, delims); + strtok(NULL, delims); + strtok(NULL, delims); + length = atoi(strtok(NULL, delims)); + strtok(NULL, delims); + strtok(NULL, delims); + pos_q = atoi(strtok(NULL, delims))-1; + strtok(NULL, delims); + pos_d = atoi(strtok(NULL, delims))-1; + + if (current_pos >= *dig_length-20) + { + (*dig_length) += 90; + diags = vrealloc(diags, sizeof(int)*(*dig_length)); + } + if (diag[l1-(pos_q)+pos_d] == 0) + { + diag[l1-(pos_q)+pos_d] =1; + diags[current_pos++] = pos_q; + diags[current_pos++] = pos_d; + diags[current_pos++] = length; + } + + } + fclose(diag_f); + int round = 0; + int e_threshold = 10; + while ((current_pos == 0) && (round < 10)) + { + if (is_dna) + { + sprintf(blast_command, "bl2seq -p blastn -i %s -j %s -D 1 -g F -o %s -S 1 -F F -W 6 -e %i", seq_file_name1, seq_file_name2, out_file, e_threshold); + } + else + { + sprintf(blast_command, "bl2seq -p blastp -i %s -j %s -D 1 -g F -o %s -F F -S 1 -e %i", seq_file_name1, seq_file_name2, out_file, e_threshold); + } + system(blast_command); + e_threshold *= 10; + FILE *diag_f = fopen(out_file,"r"); + char line[300]; + fgets(line, 300, diag_f); + fgets(line, 300, diag_f); + fgets(line, 300, diag_f); + + + char delims[] = "\t"; + while (fgets(line, 300, diag_f) != NULL) + { + strtok(line, delims); + strtok(NULL, delims); + strtok(NULL, delims); + length = atoi(strtok(NULL, delims)); + strtok(NULL, delims); + strtok(NULL, delims); + pos_q = atoi(strtok(NULL, delims))-1; + strtok(NULL, delims); + pos_d = atoi(strtok(NULL, delims))-1; + + if (current_pos >= *dig_length-20) + { + (*dig_length) += 90; + diags = vrealloc(diags, sizeof(int)*(*dig_length)); + } + if (diag[l1-(pos_q)+pos_d] == 0) + { + diag[l1-(pos_q)+pos_d] =1; + diags[current_pos++] = pos_q; + diags[current_pos++] = pos_d; + diags[current_pos++] = length; + } + } + fclose(diag_f); + ++round; + if (current_pos < 27) + current_pos = 0; + } +// ++blast_measure[round]; + + if (current_pos == 0) + { + printf("BLAST NOT SUCCESFULL\n"); + if (l1 < l2) + { + int i; + int diff = l2 - l1 + 10; + for (i = diff; i > 0; --i) + { + if (current_pos >= *dig_length-20) + { + (*dig_length) += 90; + diags = vrealloc(diags, sizeof(int)*(*dig_length)); + } + diags[current_pos++] = 0; + diags[current_pos++] = i; + diags[current_pos++] = 100; + } + diff = 10; +// printf("A: %i\n", diff); + for (i = 0; i < diff; ++i) + { + if (current_pos >= *dig_length-20) + { + (*dig_length) += 90; + diags = vrealloc(diags, sizeof(int)*(*dig_length)); + } + diags[current_pos++] = i; + diags[current_pos++] = 0; + diags[current_pos++] = 100; + } + } + else + { + int i; + int diff = 10; +// printf("A: %i\n", diff); + for (i = diff; i > 0; --i) + { + if (current_pos >= *dig_length-20) + { + (*dig_length) += 90; + diags = vrealloc(diags, sizeof(int)*(*dig_length)); + } + diags[current_pos++] = 0; + diags[current_pos++] = i; + diags[current_pos++] = 100; + } + diff = l1 - l2 + 10; + for (i = 0; i < diff; ++i) + { + if (current_pos >= *dig_length-20) + { + (*dig_length) += 90; + diags = vrealloc(diags, sizeof(int)*(*dig_length)); + } + diags[current_pos++] = i; + diags[current_pos++] = 0; + diags[current_pos++] = 100; + } + + } + } + + + vfree(diag); + + diagonals[0] = diags; + return current_pos/3; +} + + + +int +seq_pair2blat_diagonal(char *seq_file_name1, + char *seq_file_name2, + int **diagonals, + int *dig_length, + int l1, + int l2, + int is_dna) +{ + int *diag = vcalloc(l1 + l2, sizeof(int)); + char *out_file = vtmpnam(NULL); + char blast_command[200]; +// char blast_command2[200]; +// char blast_command2[600]; +// sprintf(blast_command2, "less %s", out_file); + + if (is_dna) + { + sprintf(blast_command, "blat %s %s %s -out=blast8 -q=dna -t=dna -maxGap=0 >/dev/null 2>/dev/null", seq_file_name2, seq_file_name1, out_file); + } + else + { + sprintf(blast_command, "blat %s %s %s -out=blast8 -prot -maxGap=0 >/dev/null 2>/dev/null", seq_file_name2, seq_file_name1, out_file); + } + system(blast_command); + + int *diags = diagonals[0]; + FILE *diag_f = fopen(out_file,"r"); + char line[300]; +// fgets(line, 300, diag_f); +// fgets(line, 300, diag_f); +// fgets(line, 300, diag_f); + + + char delims[] = "\t"; + int length, pos_q, pos_d; + int current_pos = 0; + while (fgets(line, 300, diag_f) != NULL) + { + strtok(line, delims); + strtok(NULL, delims); + strtok(NULL, delims); + length = atoi(strtok(NULL, delims)); + strtok(NULL, delims); + strtok(NULL, delims); + pos_q = atoi(strtok(NULL, delims))-1; + strtok(NULL, delims); + pos_d = atoi(strtok(NULL, delims))-1; + + if (current_pos >= *dig_length-20) + { + (*dig_length) += 90; + diags = vrealloc(diags, sizeof(int)*(*dig_length)); + } + if (diag[l1-(pos_q)+pos_d] == 0) + { + diag[l1-(pos_q)+pos_d] =1; + diags[current_pos++] = pos_q; + diags[current_pos++] = pos_d; + diags[current_pos++] = length; + } + } + if (current_pos == 0) + { + printf("BLAT NOT SUCCESFULL\n"); + if (l1 < l2) + { + int i; + int diff = l2 - l1 + 10; + for (i = diff; i > 0; --i) + { + if (current_pos >= *dig_length-20) + { + (*dig_length) += 90; + diags = vrealloc(diags, sizeof(int)*(*dig_length)); + } + diags[current_pos++] = 0; + diags[current_pos++] = i; + diags[current_pos++] = 100; + } + diff = 10; +// printf("A: %i\n", diff); + for (i = 0; i < diff; ++i) + { + if (current_pos >= *dig_length-20) + { + (*dig_length) += 90; + diags = vrealloc(diags, sizeof(int)*(*dig_length)); + } + diags[current_pos++] = i; + diags[current_pos++] = 0; + diags[current_pos++] = 100; + } + } + else + { + int i; + int diff = 10; +// printf("A: %i\n", diff); + for (i = diff; i > 0; --i) + { + if (current_pos >= *dig_length-20) + { + (*dig_length) += 90; + diags = vrealloc(diags, sizeof(int)*(*dig_length)); + } + diags[current_pos++] = 0; + diags[current_pos++] = i; + diags[current_pos++] = 100; + } + diff = l1 - l2 + 10; + for (i = 0; i < diff; ++i) + { + if (current_pos >= *dig_length-20) + { + (*dig_length) += 90; + diags = vrealloc(diags, sizeof(int)*(*dig_length)); + } + diags[current_pos++] = i; + diags[current_pos++] = 0; + diags[current_pos++] = 100; + } + + } + } + +// printf("END\n"); + vfree(diag); + fclose(diag_f); + diagonals[0] = diags; + return current_pos/3; +} + + + +/** + * \brief Calculates the diagonals between two sequences. + * + * Uses blastz to calculate the diagonals. + * \param seq_file1 File with sequence 1. + * \param seq_file2 File with sequence 2. + * \param diagonals An array where the diagonal points will be stored. + * \param dig_length length of \a diagonals . + * \param num_points Number of points in all diagonals. + * \return number of diagonals; + */ +int +seq_pair2blastz_diagonal(char *seq_file_name1, + char *seq_file_name2, + int **diagonals, + int *dig_length, + int l1, + int l2, + int is_dna) +{ + int *diag = vcalloc(l1 + l2, sizeof(int)); + char *out_file = vtmpnam(NULL); + char blast_command[200]; +// char blast_command2[200]; +// char blast_command2[600]; +// sprintf(blast_command2, "less %s", out_file); + + if (is_dna) + { + sprintf(blast_command, "~/Download/blastz-source/blastz %s %s B=0 K=10000> %s", seq_file_name1, seq_file_name2, out_file); + } + else + { + printf("SORRY - no BLASTZ with amino accid\n"); + exit(0); + } + system(blast_command); + + int *diags = diagonals[0]; + FILE *diag_f = fopen(out_file,"r"); + char line[300]; + char delims[] = " "; +// char *result = NULL; + int length, pos_q, pos_d; + int current_pos = 0; + while (fgets(line, 300, diag_f) != NULL) + { + if (line[0] == 'a') + { + char *line_tmp; + while (fgets(line, 300, diag_f) != NULL) + { + if (line[0] == '}') + break; + + if (line[2] == 'l') + { + line_tmp = &line[4]; + if (current_pos >= *dig_length-20) + { + (*dig_length) += 90; + diags = vrealloc(diags, sizeof(int)*(*dig_length)); + } + pos_q = atoi(strtok(line_tmp, delims)); + pos_d = atoi(strtok(NULL, delims)); + length = atoi(strtok(NULL, delims) - pos_q); + if (diag[l1-(pos_q)+pos_d] == 0) + { + diag[l1-(pos_q)+pos_d] =1; + diags[current_pos++] = pos_q; + diags[current_pos++] = pos_d; + diags[current_pos++] = length; + } + } + } + } + } + + + if (current_pos == 0) + { + printf("BLASTZ NOT SUCCESFULL\n"); + if (l1 < l2) + { + int i; + int diff = l2 - l1 + 10; + + for (i = diff; i > 0; --i) + { + if (current_pos >= *dig_length-20) + { + (*dig_length) += 90; + diags = vrealloc(diags, sizeof(int)*(*dig_length)); + } + diags[current_pos++] = 0; + diags[current_pos++] = i; + diags[current_pos++] = 100; + } + diff = 10; + + for (i = 0; i < diff; ++i) + { + if (current_pos >= *dig_length-20) + { + (*dig_length) += 90; + diags = vrealloc(diags, sizeof(int)*(*dig_length)); + } + diags[current_pos++] = i; + diags[current_pos++] = 0; + diags[current_pos++] = 100; + } + } + else + { + int i; + int diff = 10; + + for (i = diff; i > 0; --i) + { + if (current_pos >= *dig_length-20) + { + (*dig_length) += 90; + diags = vrealloc(diags, sizeof(int)*(*dig_length)); + } + diags[current_pos++] = 0; + diags[current_pos++] = i; + diags[current_pos++] = 100; + } + diff = l1 - l2 + 10; + for (i = 0; i < diff; ++i) + { + if (current_pos >= *dig_length-20) + { + (*dig_length) += 90; + diags = vrealloc(diags, sizeof(int)*(*dig_length)); + } + diags[current_pos++] = i; + diags[current_pos++] = 0; + diags[current_pos++] = 100; + } + + } + } + + vfree(diag); + fclose(diag_f); + diagonals[0] = diags; + return current_pos/3; +} + + + +//************************** needleman-wunsch aligning ********************************************************** + + +void +fill_arguments_nw(Nw_param* method_arguments_p, int alphabet_size) +{ + method_arguments_p-> dyn_matrix = vcalloc(1,sizeof(double*)); + method_arguments_p->dyn_matrix[0] = vcalloc(1,sizeof(double)); + method_arguments_p->length1 = vcalloc(1,sizeof(int)); + method_arguments_p->length2 = vcalloc(1,sizeof(int)); + *method_arguments_p->length1 = 1; + *method_arguments_p->length2 = 1; + method_arguments_p->sumup_prf = vcalloc(alphabet_size+1,sizeof(int*)); + int i; + for (i = 0; i < alphabet_size+1; ++i) + method_arguments_p->sumup_prf[i] = vcalloc(1,sizeof(int)); + method_arguments_p->sumup_length = vcalloc(1,sizeof(int)); + *method_arguments_p->sumup_length = 1; +} + + +void +free_nw(Nw_param* method_arguments_p, int alphabet_size) +{ + free_dyn_matrix(*method_arguments_p->length1,method_arguments_p->dyn_matrix); + int i; + for (i = 0; i <= alphabet_size; ++i) + { + vfree(method_arguments_p->sumup_prf[i]); + } + vfree(method_arguments_p->sumup_prf); + vfree(method_arguments_p->length1); + vfree(method_arguments_p->length2); + vfree(method_arguments_p->sumup_length); +} + + +/** + * \brief One run of needleman-wunsch dynamic programming. + * + * \param profiles The profiles. + * \param param_set The fastal parameters. + * \param method_arguments_p The method arguments. + * \param is_dna Sequences are DNA (\a is_dna = 1) or protein. + * \param edit_file The edit file. + * \param prof_file the profile file. + * \param number Number of the parent node. + * \return The length of the alignment. + */ +int +nw_dyn(Fastal_profile **profiles, Fastal_param *param_set, void *method_arguments_p, int is_dna, FILE *edit_file, FILE *prof_file, int number) +{ + Nw_param *arguments = (Nw_param*)method_arguments_p; +// int old_length1 = *arguments->length1; +// int old_length2 = *arguments->length2; + arguments->dyn_matrix = resize_dyn_matrix(arguments->dyn_matrix, *arguments->length1, *arguments->length2, profiles[0]->length+1, profiles[1]->length+1); + *arguments->length1 = profiles[0]->length+1; + *arguments->length2 = profiles[1]->length+1; + int alignment_length = prf_nw(profiles[0], profiles[1], arguments->dyn_matrix, edit_file, arguments->sumup_prf, arguments->sumup_length, param_set); + write2file(arguments->sumup_prf, alignment_length, prof_file, number,profiles[0]->number_of_sequences + profiles[1]->number_of_sequences, param_set); + return alignment_length; +} + + +/** + * \brief This method takes a profile and turns it into a sumed up version. + * + * Required for NW-algorithm. + * \param profile The profile to sum up. + * \param sumup A field where the result will be stored. + * \param param_set Parameters for the fastal algorithm. + * \return The new \a sumup. + */ +int** +sumup_profile(Fastal_profile *profile, + int **sumup, + Fastal_param *param_set) +{ + + char *pos2aa = &(param_set->pos2char[0]); + int alphabet_size = param_set->alphabet_size; + int **M = param_set->M; + int prof_length = profile->length; + + int i,j,k; + + for (i = 0; i < prof_length; ++i) + { + sumup[alphabet_size][i] = 0; + for (k = 0; k < alphabet_size; ++k) + { + sumup[k][i] = 0; + sumup[alphabet_size][i] += profile->prf[k][i]; + for (j = 0; j < alphabet_size; ++j) + { + sumup[k][i] += profile->weight * profile->prf[j][i] * M[pos2aa[j]-'A'][pos2aa[k]-'A']; + } + } + } + + return sumup; +} + + +/** + * \brief Turns the dynamic programming matrix into a editfile and calculates the new profile. + * + * Required for NW-algorithm. + * \param prog_matrix The dynamic programming matrix. + * \param prf1 The first profile. + * \param prf2 The second profile. + * \param edit_f A File object (already opened) to write the edit sequence into. + * \param prf_field A 2-dim array to save the new profile into. + * \param field_length Length of the new profile. + * \param param_set Parameters of the Fastal-Algorithm + */ +int +nw_matrix2edit_file(double **prog_matrix, //dynamic programming matrix + Fastal_profile *prf1, //profile of dim1 + Fastal_profile *prf2, //profile of dim2 + FILE *edit_f, //file to safe the edit in + int **prf_field, //space to safe the new profile + int *field_length, + Fastal_param *param_set) //length of prf_field +{ +// int **M = param_set->M; + int alphabet_size = param_set->alphabet_size; + double gap_cost = param_set -> gop; + fprintf(edit_f, "%i\n%i\n%i\n%i\n",prf1->prf_number, prf2->prf_number, prf1->is_leaf, prf2->is_leaf); + int sum[] = {0,0,0}; + char sumc[] = {'M','I','D'}; + int last = 0; + int n = 0; + int m = 0; + int field_pos = 0; + int i; + int prf1_length = prf1->length; + int prf2_length = prf2->length; + while ((n < prf1_length) && (m < prf2_length)) + { + //if necesarry allocate more memory for result + if ((*field_length)-alphabet_size < field_pos) + { + (*field_length) += ENLARGEMENT_PER_STEP; + + for (i = 0; i prf[i][n]; + } + ++n; + ++ field_pos; + + if (last != 1) + { + fprintf(edit_f,"%c%i\n",sumc[last],sum[last]); + sum[last] = 0; + } + last = 1; + ++sum[last]; + } + else if (prog_matrix[n][m] == (prog_matrix[n][m+1] +gap_cost)) + { + + for (i = 0; iprf[i][m]; + } + ++m; + ++ field_pos; + if (last != 2) + { + fprintf(edit_f,"%c%i\n",sumc[last],sum[last]); + sum[last] = 0; + } + last = 2; + ++sum[last]; + } + else + { + for (i = 0; iprf[i][n] + prf2->prf[i][m]; + } + ++n; + ++m; + ++ field_pos; + if (last != 0) + { + fprintf(edit_f,"%c%i\n",sumc[last],sum[last]); + sum[last] = 0; + } + last = 0; + ++sum[last]; + } + } + fprintf(edit_f,"%c%i\n",sumc[last],sum[last]); + + //gaps in prf2 + last = 0; + while (n < prf1_length) + { + for (i = 0; iprf[i][n]; + } + ++n; + ++ field_pos; + ++last; + } + if (last > 0) + fprintf(edit_f,"I%i\n",last); + + //gaps in prf1 + last = 0; + while (m < prf2_length) + { + for (i = 0; iprf[i][m]; + } + ++m; + ++ field_pos; + ++last; + } + if (last > 0) + fprintf(edit_f,"D%i\n",last); + fprintf(edit_f,"*\n"); + return field_pos; +} + + + +/** + * \brief Pairwise alignments of profile is done here. + * + * \param profile1 Profile of sequence 1 + * \param profile2 Profile of sequence 2 + * \param prog_matrix Matrix for dynamic programming + * \param edit_file_name The edit_file_name + * \param sumup_prf The sumup version of profile 1, which later contains the aligned profile. + * \param sumup_length Contains the length of the aligned profile. + * \return length of the aligned profile + */ +int +prf_nw(Fastal_profile *profile1, + Fastal_profile *profile2, + double **prog_matrix, + FILE *edit_file_name, + int **sumup_prf, + int *sumup_length, + Fastal_param *param_set) +{ + int alphabet_size = param_set->alphabet_size; + double gap_cost = param_set->gop; + + int i; + if (*sumup_length < profile1->length) + { + for (i = 0; i < alphabet_size+1; ++i) + { + sumup_prf[i] = vrealloc(sumup_prf[i], profile1->length*sizeof(int)); + } + *sumup_length = profile1->length; + } + sumup_prf = sumup_profile(profile1, sumup_prf, param_set); + + + + int j,k; + int prof1_length = profile1->length; + int prof2_length = profile2->length; + +// int** M = param_set->M; + double match_score; +// int amino_counter; + int residue_pairs = 0; + + for (i = prof2_length; i > 0; --i) + { + prog_matrix[prof1_length][i] = gap_cost * (prof2_length-i); + } + + i = prof1_length-1; + prog_matrix[prof1_length][prof2_length] = 0.0; + while (i >=0) + { + j = prof2_length-1; + + prog_matrix[i][prof2_length] = gap_cost*(prof1_length-i); + while (j >=0) + { + match_score = 0.0; + residue_pairs = 0; + for (k = 0; k < alphabet_size; ++k) + { + residue_pairs += profile2->prf[k][j]; + match_score += (profile2->prf[k][j] * sumup_prf[k][i]); + } + match_score /= (residue_pairs * sumup_prf[alphabet_size][i]); + prog_matrix[i][j] = MAX3(prog_matrix[i+1][j+1]+match_score, prog_matrix[i+1][j]+gap_cost, prog_matrix[i][j+1]+gap_cost); + + --j; + } + --i; + } + return nw_matrix2edit_file(prog_matrix, profile1, profile2, edit_file_name, sumup_prf, sumup_length, param_set); +} + + +/************** GOTOH ***********************/ + + +void +fill_arguments_gotoh(Gotoh_param* method_arguments_p, int alphabet_size) +{ + method_arguments_p->m_matrix = vcalloc(1,sizeof(double*)); + method_arguments_p->m_matrix[0] = vcalloc(1,sizeof(double)); + method_arguments_p->d_matrix = vcalloc(1,sizeof(double*)); + method_arguments_p->d_matrix[0] = vcalloc(1,sizeof(double)); + method_arguments_p->i_matrix = vcalloc(1,sizeof(double*)); + method_arguments_p->i_matrix[0] = vcalloc(1,sizeof(double)); + method_arguments_p->length1 = vcalloc(1,sizeof(int)); + method_arguments_p->length2 = vcalloc(1,sizeof(int)); + method_arguments_p->log_saver = vcalloc(alphabet_size+1, sizeof(double*)); + *method_arguments_p->length1 = 1; + *method_arguments_p->length2 = 1; + method_arguments_p->sumup_prf = vcalloc(alphabet_size+1,sizeof(int*)); + int i; + for (i = 0; i < alphabet_size+1; ++i) + { + method_arguments_p->sumup_prf[i] = vcalloc(1,sizeof(int)); + method_arguments_p->log_saver[i] = vcalloc(1, sizeof(double)); + } + method_arguments_p->sumup_length = vcalloc(1,sizeof(int)); + *method_arguments_p->sumup_length = 1; +} + + +void +free_gotoh(Gotoh_param* method_arguments_p, int alphabet_size) +{ + free_dyn_matrix(*method_arguments_p->length1,method_arguments_p->m_matrix); + free_dyn_matrix(*method_arguments_p->length1,method_arguments_p->i_matrix); + free_dyn_matrix(*method_arguments_p->length1,method_arguments_p->d_matrix); + + int i; + for (i = 0; i <= alphabet_size; ++i) + { + vfree(method_arguments_p->sumup_prf[i]); + } + vfree(method_arguments_p->sumup_prf); + vfree(method_arguments_p->length1); + vfree(method_arguments_p->length2); + vfree(method_arguments_p->sumup_length); +} + + +int +gotoh_dyn(Fastal_profile **profiles, Fastal_param *param_set, void *method_arguments_p, int is_dna, FILE *edit_file, FILE *prof_file, int number) +{ + Gotoh_param *arguments = (Gotoh_param*)method_arguments_p; + arguments->m_matrix = resize_dyn_matrix(arguments->m_matrix, *arguments->length1, *arguments->length2, profiles[0]->length+1, profiles[1]->length+1); + arguments->i_matrix = resize_dyn_matrix(arguments->i_matrix, *arguments->length1, *arguments->length2, profiles[0]->length+1, profiles[1]->length+1); + arguments->d_matrix = resize_dyn_matrix(arguments->d_matrix, *arguments->length1, *arguments->length2, profiles[0]->length+1, profiles[1]->length+1); + int i; + if (profiles[1]->length > *arguments->length2-1) + { + for (i = 0; i < param_set->alphabet_size; ++i) + { + arguments->log_saver[i] = vrealloc(arguments->log_saver[i], (profiles[1]->length)*sizeof(double*)); + } + } + *arguments->length1 = profiles[0]->length+1; + *arguments->length2 = profiles[1]->length+1; + int alignment_length = prf_gotoh(profiles[0], profiles[1], edit_file, arguments, param_set); + write2file(arguments->sumup_prf, alignment_length, prof_file, number, profiles[0]->number_of_sequences + profiles[1]->number_of_sequences, param_set); + return alignment_length; +} + + +int +gotoh_matrix2edit_file(double **m_matrix, //dynamic programming matrix + double **v_matrix, //dynamic programming matrix + double **h_matrix, //dynamic programming matrix + Fastal_profile *prf1, //profile of dim1 + Fastal_profile *prf2, //profile of dim2 + FILE *edit_f, //file to safe the edit in + int **prf_field, //space to safe the new profile + int *field_length, + Fastal_param *param_set) //length of prf_field +{ + double comp_num = log((double)prf1->number_of_sequences) + log((double)prf2->number_of_sequences); + int** M = param_set->M; + int alphabet_size = param_set->alphabet_size; + double gep = param_set -> gep; + fprintf(edit_f, "%i\n%i\n%i\n%i\n",prf1->prf_number, prf2->prf_number, prf1->is_leaf, prf2->is_leaf); + int sum[] = {0,0,0}; + char sumc[] = {'M','I','D'}; + int last = 0; + int n = 0; + int m = 0; + int field_pos = 0; + int i; + int prf1_length = prf1->length; + int prf2_length = prf2->length; + int current_mode = 0; + //determine start mode + char *pos2char = param_set->pos2char; + if (h_matrix[n][m] == m_matrix[n][m]) + { + current_mode = 2; + } + else + { + + if (v_matrix[n][m] == m_matrix[n][m]) + { + current_mode = 1; + } + else + { + current_mode = 0; + } + } +// printf("%f %f %f - %i\n",h_matrix[n][m],v_matrix[n][m],m_matrix[n][m], current_mode); + while ((n < prf1_length) && (m < prf2_length)) + { + //if necesarry allocate more memory for result + if ((*field_length)-alphabet_size < field_pos) + { + (*field_length) += ENLARGEMENT_PER_STEP; + + for (i = 0; i prf[i][m]; + } + if (h_matrix[n][m] != (h_matrix[n][m+1]+gep)) + { + current_mode = 0; + } + ++m; + ++ field_pos; + if (last != 2) + { + fprintf(edit_f,"%c%i\n",sumc[last],sum[last]); + sum[last] = 0; + } + last = 2; + ++sum[last]; + } + else + { + if (current_mode== 1) + { + for (i = 0; iprf[i][n]; + } + if (v_matrix[n][m] != (v_matrix[n+1][m]+gep)) + { + current_mode = 0; + } + ++n; + ++ field_pos; + + if (last != 1) + { + fprintf(edit_f,"%c%i\n",sumc[last],sum[last]); + sum[last] = 0; + } + last = 1; + ++sum[last]; + } + else + { + double match_score = 0.0; + int char_c, char_c2; + for (char_c = 0; char_c < alphabet_size; ++char_c) + { + for (char_c2 = 0; char_c2 < alphabet_size; ++char_c2) + { + + if ((log(prf1->prf[char_c][n]) != -1) && ( log(prf2->prf[char_c2][m]) != -1)) + { + match_score += exp(log((double)prf1->prf[char_c][n]) + log((double)prf2->prf[char_c2][m])-comp_num) * M[pos2char[char_c]-'A'][pos2char[char_c2]-'A']; + } + } + } + if (m_matrix[n+1][m+1] + match_score != m_matrix[n][m]) + { + if (m_matrix[n][m] == v_matrix[n][m]) + { + current_mode = 1; + continue; + } + if (m_matrix[n][m] == h_matrix[n][m]) + { + current_mode = 2; + continue; + } + } + for (i = 0; iprf[i][n] + prf2->prf[i][m]; + } + ++n; + ++m; + ++ field_pos; + if (last != 0) + { + fprintf(edit_f,"%c%i\n",sumc[last],sum[last]); + sum[last] = 0; + } + last = 0; + ++sum[last]; + } + } + + } + fprintf(edit_f,"%c%i\n",sumc[last],sum[last]); + + int needed = MAX(prf1_length -n, prf2_length -m); + + if ((*field_length) - needed -10 < field_pos) + { + (*field_length) += needed +10; + + for (i = 0; i prf[i][n]; + } + ++n; + ++ field_pos; + ++last; + } + if (last > 0) + fprintf(edit_f,"I%i\n",last); + + //gaps in prf1 + last = 0; + while (m < prf2_length) + { + for (i = 0; iprf[i][m]; + } + ++m; + ++ field_pos; + ++last; + } + if (last > 0) + fprintf(edit_f,"D%i\n",last); + + fprintf(edit_f,"*\n"); + return field_pos; +} + + + + +/** + * \brief The gotoh dynamic programming algorithm. + * + * \param profile1 The first profile. + */ +int +prf_gotoh(Fastal_profile *profile1, + Fastal_profile *profile2, + FILE *edit_file_name, + Gotoh_param *arguments, + Fastal_param *param_set) +{ + +// printf("I AM HERE - again\n"); + int **sumup_prf = arguments->sumup_prf; + int *sumup_length = arguments->sumup_length; + int alphabet_size = param_set->alphabet_size; + double gop = param_set->gop; + double gep = param_set->gep; + + const int INF = -999999; + int i; + + double **m_matrix = arguments->m_matrix; + double **h_matrix = arguments->i_matrix; + double **v_matrix = arguments->d_matrix; + + int j; + int prof1_length = profile1->length; + int prof2_length = profile2->length; + + int** M = param_set->M; + double match_score; + for (i = prof2_length; i >= 0; --i) + { + m_matrix[prof1_length][i] = gop + gep * (prof2_length-i); + v_matrix[prof1_length][i] = INF; + h_matrix[prof1_length][i] = m_matrix[prof1_length][i]; + } + + m_matrix[prof1_length][prof2_length] = 0.0; + h_matrix[prof1_length][prof2_length] = INF; + v_matrix[prof1_length][prof2_length] = INF; + int l; + double comp_num = log((double)profile1->number_of_sequences) + log((double)profile2->number_of_sequences); + static double *log_test = NULL; + if (!log_test) + log_test = vcalloc(alphabet_size, sizeof(double)); +// int k; + int **prf1 = profile1->prf; + int **prf2 = profile2->prf; + double **log_test2 = arguments->log_saver; + for (l = 0; l < alphabet_size; ++l) + { + for (i = 0; i < profile2->length; ++i) + { + if (prf2[l][i] > 0) + { + log_test2[l][i] = log(prf2[l][i]); + } + else + log_test2[l][i] = -1; + } + } + + char *pos2char = param_set->pos2char; + i = prof1_length-1; + while (i >=0) + { + j = prof2_length-1; + + for (l = 0; l < alphabet_size; ++l) + { + if (prf1[l][i] > 0) + log_test[l] = log((double)prf1[l][i]); + else + log_test[l] = -1; + } + m_matrix[i][prof2_length] = gop + gep *(prof1_length-i); + v_matrix[i][prof2_length] = m_matrix[i][prof2_length]; + h_matrix[i][prof2_length] = INF; + while (j >=0) + { + + match_score = 0.0; + v_matrix[i][j] = (MAX(v_matrix[i+1][j], m_matrix[i+1][j] + gop) + gep); + h_matrix[i][j] = (MAX(h_matrix[i][j+1], m_matrix[i][j+1] + gop) + gep); + + int char_c, char_c2; + int num = 0; + for (char_c = 0; char_c < alphabet_size; ++char_c) + { + for (char_c2 = 0; char_c2 < alphabet_size; ++char_c2) + { + + if ((log_test[char_c] != -1) && (log_test2[char_c2][j] != -1)) + { + match_score += exp(log_test[char_c] + log_test2[char_c2][j]-comp_num) * M[pos2char[char_c]-'A'][pos2char[char_c2]-'A']; + } + } + } + + m_matrix[i][j] = m_matrix[i+1][j+1]+match_score; + + if (m_matrix[i][j] < v_matrix[i][j]) + { + m_matrix[i][j] = v_matrix[i][j]; + } + if (m_matrix[i][j] < h_matrix[i][j]) + { + m_matrix[i][j] = h_matrix[i][j]; + } + + --j; + } + --i; + } + return gotoh_matrix2edit_file(m_matrix, v_matrix, h_matrix, profile1, profile2, edit_file_name, sumup_prf, sumup_length, param_set); +} + + +/************* OTHER STUFF ******************/ + +/** + * \brief Writes the alignment into the profile file and the edit file. + * + * \param profiles The two profiles to combine. + * \param alignment The alinment information. + * \param alignment The length of the alignment. + * \param edit_f The edit file. + * \param prof_f The profile file. + * \param node_number the new node number. + */ +void +alignment2files(Fastal_profile **profiles, + Fastal_param *param_set, + int **alignment, + int alignment_length, + FILE *edit_f, + FILE *prof_f, + int node_number) +{ + fprintf(edit_f, "%i\n%i\n%i\n%i\n",profiles[0]->prf_number, profiles[1]->prf_number, profiles[0]->is_leaf, profiles[1]->is_leaf); + fprintf(prof_f, "%i\n0\n%i\n1\n", node_number, alignment_length); + + int **prf1 = profiles[0]->prf; + int **prf2 = profiles[1]->prf; + int i = 0; + int pos = 0; + int pos1, pos2; + + char statec[] = {'M','D','I'}; + int num = 0; + int state = 0; + + while (i < alignment_length) + { + + pos1 = alignment[0][pos]; + pos2 = alignment[1][pos]; + // match + if ((pos1 != -1) && (pos2 != -1)) + { + + combine_profiles2file(prf1, prf2, pos1, pos2, param_set, prof_f, 'M'); + if (state != 0) + { + fprintf(edit_f, "%c%i\n",statec[state], num); + num =1; + state = 0; + } + else + ++num; + ++i; + } + // insertion in seq 1 + else if (pos1 != -1) + { + combine_profiles2file(prf1, prf2, pos1, pos2, param_set, prof_f, 'I'); + if (state != 2) + { + fprintf(edit_f, "%c%i\n",statec[state], num); + num =1; + state = 2; + } + else + ++num; + ++i; + } + // deletion in seq 1 + else if (pos2 != -1) + { + combine_profiles2file(prf1, prf2, pos1, pos2, param_set, prof_f, 'D'); + if (state != 1) + { + fprintf(edit_f, "%c%i\n",statec[state], num); + num =1; + state = 1; + } + else + ++num; + ++i; + } + ++pos; + } + fprintf(edit_f, "%c%i\n",statec[state], num); + + fprintf(edit_f,"*\n"); + fprintf(prof_f,"*\n"); + +} + + +//******************************* OTHER STUFF *********************** + +/** + * \brief Reads the sequence from a given position in a fasta file and turns it into a profile. + * + * \param seq_file The file where the sequence is stored. + * \param off_set The off_set from the beginning of the file to the position of the sequence name. + * \param profile The profile where the sequence will be stored into. + * \param prf_number The number of this profile. + */ +void +file_pos2profile(FILE *seq_file, //File with sequences + long off_set, //offset of sequence from the beginning of file point to the sequence name, not to the sequence itself + Fastal_profile *profile, //profile to save into + int prf_number, //number of the profile + Fastal_param *param_set) +{ + int alphabet_size = param_set->alphabet_size; + profile->is_leaf = 1; + profile->number_of_sequences = 1; + int *aa2pos = &(param_set->char2pos[0]); + const int LINE_LENGTH = 500; + char line[LINE_LENGTH]; + profile->num_sequences = 1; + profile->prf_number = prf_number; + fseek (seq_file , off_set , SEEK_SET ); + + fgets (line, LINE_LENGTH , seq_file); + int seq_length = 0; + int i, j, x; + + while(fgets(line, LINE_LENGTH, seq_file)!=NULL) + { + if (line[0] != '>') + { + line[LINE_LENGTH-1] = '\n'; + if (seq_length + LINE_LENGTH >= profile->allocated_memory) + { + for (i = 0; i < alphabet_size; ++i) + { + profile->prf[i] = vrealloc(profile->prf[i], (profile->allocated_memory+PROFILE_ENLARGEMENT)*sizeof(int)); + } + profile->allocated_memory += PROFILE_ENLARGEMENT; + } + + i = 0; + x = 0; + while ((line[i] != '\n') && (line[i] != '\0')) + { + if (line[i] != '-') + { + for(j = 0; jprf[j][seq_length+x] = 0; + profile->prf[aa2pos[toupper((short)line[i])]][seq_length+x] = 1; + ++x; + } + ++i; + } + seq_length += x; + + } + else + break; + } + profile->length = seq_length; + +} + + + +/** + * \brief Constructs index of fasta_file. + * + * The index is of length n (n= number of sequences in the given multi fasta file.). In the order of appearance in the file the position of each sequence in the file is stored. + * \param file_name The file with the sequences. + * \param file_positions Array to save the positions in. + * \return The number of sequences in \a file_name. + */ +int +make_index_of_file(char *file_name, //file with sequences + long **file_positions) //array to save the positions +{ + const int LINE_LENGTH = 150; + (*file_positions) = vcalloc(ENLARGEMENT_PER_STEP, sizeof(long)); + + FILE *file = fopen(file_name,"r"); + + char line[LINE_LENGTH]; + + int num_of_sequences = 0; + int mem_for_pos = ENLARGEMENT_PER_STEP; + + + if (file == NULL) + { + printf("FILE NOT FOUND\n"); + exit(1); + } + else + { + (*file_positions)[num_of_sequences] = ftell(file); + while(fgets(line, LINE_LENGTH , file)!=NULL) + { +// int length = strlen(line); + if (line[0] == '>') + { + ++num_of_sequences; + + if (num_of_sequences == mem_for_pos) + { + (*file_positions) = vrealloc((*file_positions),(ENLARGEMENT_PER_STEP+mem_for_pos) * sizeof(long)); + mem_for_pos += ENLARGEMENT_PER_STEP; + } + } + (*file_positions)[num_of_sequences] = ftell(file); + } + } + + fclose(file); + return num_of_sequences; +} + + + +/** + * \brief Reads a profile from a profile file. + * + * \param prof A Fastal_profile object to save the profile in. + * \param profile_f file where the profile is stored. + * \param position Position of the profile in \a profile_f. + * \param param_set The parameter set for Fastal + */ + +void +profile_file2profile(Fastal_profile *prof, //structure to save the profile in + FILE *profile_f, //file where the profile is stored + long position, //position in profile_f where the profile is stored + Fastal_param *param_set) +{ + + int alphabet_size = param_set->alphabet_size; + + int *aa2pos = &(param_set->char2pos[0]); + + + fseek(profile_f,position,SEEK_SET); + const int LINE_LENGTH = 500; + char line[500]; + + fgets(line, LINE_LENGTH, profile_f); + + prof->prf_number = atoi(line); + fgets(line, LINE_LENGTH, profile_f); + prof->is_leaf = atoi(line); + + fgets(line, LINE_LENGTH, profile_f); + prof->length = atoi(line); + fgets(line, LINE_LENGTH, profile_f); + prof->weight = atoi(line); + fgets(line, LINE_LENGTH, profile_f); + prof->number_of_sequences = atoi(line); + int i,j; + if (prof->length > prof->allocated_memory) + for (i = 0;i < alphabet_size; ++i) + { + prof->prf[i] = vrealloc(prof->prf[i],prof->length*sizeof(int)); + } + prof->allocated_memory = prof->length; + char delims[] = " "; + char *result = NULL; + char *result_num = NULL; + + int length = prof->length; + + for (i = 0; i < length; ++i) + { + for(j = 0; jprf[j][i] = 0; + fgets(line, LINE_LENGTH , profile_f); + result = strtok( line, delims ); + + while( result != NULL) + { + result_num = &result[1]; + prof->prf[aa2pos[(short)result[0]]][i] = atoi(result_num); + result = strtok( NULL, delims ); + } + } +} + + + +/** + * \brief Writes a profile into a file + * + * \param profile Pointer to the profile which has to be saved. + * \param file A File object (already opened) to write the profile to. + * \param param_set The parameters for the fastal algorithm. + */ +void +profile2file(Fastal_profile *profile, //the profile to save + FILE* file, //file to save in + Fastal_param *param_set) +{ + int alphabet_size = param_set->alphabet_size; + + char *pos2aa = &(param_set->pos2char[0]); + + fseek(file,0,SEEK_SET); + + fprintf(file,"%i\n", profile->prf_number); + + + fprintf(file,"%i\n", profile->is_leaf); + fprintf(file,"%i\n", profile->length); + fprintf(file,"%i\n", profile->weight); + int i = 0, j = 0; + int max = profile->length; + int x= 0; + --alphabet_size; + while (i < max) + { + for (j = 0; j < alphabet_size; ++j) + if (profile->prf[j][i] > 0) + { + if (x) + fprintf(file," %c%i", pos2aa[j],profile->prf[j][i]); + else + fprintf(file,"%c%i", pos2aa[j],profile->prf[j][i]); + x = 1; + } + if (profile->prf[j][i] > 0) + { + if (x) + fprintf(file," %c%i", pos2aa[j],profile->prf[j][i]); + else + fprintf(file,"%c%i", pos2aa[j],profile->prf[j][i]); + x = 1; + } + x = 0; + fprintf(file,"\n"); + ++i; + } + fprintf(file,"*\n"); +} + + + +/** +* Reads the profile out of an alignment (NOT IN USE) +*/ +// void +// file2profile(FILE* profile_f, //file to read the profile of +// Fastal_profile *prof, //profile saved in here +// int prf_number, //number of the profile +// Fastal_param *param_set) +// { +// int alphabet_size = param_set->alphabet_size; +// +// int *aa2pos = &(param_set->char2pos[0]); +// +// +// fseek(profile_f,0,SEEK_SET); +// const int LINE_LENGTH = 500; +// char line[500]; +// +// fgets(line, LINE_LENGTH, profile_f); +// prof->prf_number = atoi(line); +// fgets(line, LINE_LENGTH, profile_f); +// prof->is_leaf = atoi(line); +// +// fgets(line, LINE_LENGTH, profile_f); +// prof->length = atoi(line); +// +// fgets(line, LINE_LENGTH, profile_f); +// prof->weight = atoi(line); +// int i,j; +// if (prof->length > prof->allocated_memory) +// for (i = 0;i < alphabet_size; ++i) +// { +// prof->prf[i] = vrealloc(prof->prf[i],prof->length*sizeof(int)); +// } +// +// char delims[] = " "; +// char *result = NULL; +// char *result_num = NULL; +// +// int length = prof->length; +// +// for (i = 0; i < length; ++i) +// { +// for(j = 0; jprf[j][i] = 0; +// fgets(line, LINE_LENGTH , profile_f); +// result = strtok( line, delims ); +// +// while( result != NULL) +// { +// result_num = &result[1]; +// prof->prf[aa2pos[(short)result[0]]][i] = atoi(result_num); +// result = strtok( NULL, delims ); +// } +// } +// } + + + + + + +/** + * \brief Writes the sequence into the alignment_file. + * + * \param aligned_sequence Pattern of aligned sequence. + * \param sequence_file File with sequences. + * \param sequence_position Positions of sequences in \a sequence_file. + * \param alignment_file The file to write the sequence into. + * +*/ +void +edit_seq2aligned_seq(char *aligned_sequence, //pattern for aligned sequence + FILE *sequence_file, //file with all the sequences + long sequence_position, //position in sequence file with the correct sequence + FILE *alignment_file) //file to write the alignment into +{ + fseek(sequence_file, sequence_position, SEEK_SET); + const int LINE_LENGTH = 300; + char line[LINE_LENGTH]; + fgets (line, LINE_LENGTH , sequence_file); + fprintf(alignment_file,"%s", line); //writing of sequence name + int pos = 0; + int i = 0; + while(fgets(line, LINE_LENGTH, sequence_file)!=NULL) + { + if (line[0] != '>') + { + + line[LINE_LENGTH-1] = '\n'; + i = 0; + while ((line[i] != '\n') && (line[i] != '\0')) + { + while (aligned_sequence[pos] == '-') + { + + fprintf(alignment_file,"-"); + ++pos; + } + if (line[i] != '-') + { + + fprintf(alignment_file,"%c",line[i]); + ++pos; + } + ++i; +// ++pos; + } + } + else + break; + } + while (aligned_sequence[pos] != '\n') + { + fprintf(alignment_file,"-"); + ++pos; + } + fprintf(alignment_file,"\n"); +} + + + +/** + * \brief Recursive function to turn the edit_file into the alignment. + * + * \param sequence_file File with all sequences. + * \param sequence_position The array of sequence positions in \a sequence_file + * \param edit_file File to safe the edit profiles in. + * \param edit_positions Array saving the coorespondence between edit profile and position in \a edit_file + * \param node_number The current node. + * \param number_of_sequences The number of sequences. + * \param aligned_sequence The sequence that is edited. + * \param alignment_length The length of the alignment. + * \param edit_seq_file File that saves the edited_sequences of the internal nodes. + * \param offset Saves the size of the edited_sequences. + * \param alignment_file File where the alignment is saved. + */ +void +edit2alignment(FILE *sequence_file, //sequence file + long *seq_positions, //sequence positions + FILE *edit_file, //file saving the edit profiles + long *edit_positions, //array saving the correspondence between edit profile and position in edit_file + int node_number, //the current node + int number_of_sequences, //number of sequences + char *aligned_sequence, //the sequence that is edited + int alignment_length, //length of the alignment - and thus of aligned_sequence + FILE *edit_seq_file, //file saving the edited_sequences of the internal nodes + int offset, //saves the size of the edited_sequence + FILE* alignment_file) //file saving the alignments +{ + fseek(edit_file, edit_positions[node_number-number_of_sequences], SEEK_SET); + const int LINE_LENGTH = 50; + char line[LINE_LENGTH]; + fgets(line, LINE_LENGTH , edit_file); + int child1 = atoi(line); + fgets(line, LINE_LENGTH , edit_file); + int child2 = atoi(line); + fgets(line, LINE_LENGTH , edit_file); + int is_leaf1 = atoi(line); + fgets(line, LINE_LENGTH , edit_file); + int is_leaf2 = atoi(line); + +// static char seq_line[10]; +// printf("SO EINE VERDAMMTE SCHEISE ABER AUCH\n"); + char x; + int number; + int pos = 0; + + //first child + while(fgets(line, LINE_LENGTH , edit_file)!=NULL) + { + + x = line[0]; + if (x == '*') + break; + number = atoi(&line[1]); + if (x == 'M') + { + while (number > 0) + { + if (aligned_sequence[pos] == 'X') + --number; + ++pos; + } + } + else if (x == 'I') + { + while (number > 0) + { + if (aligned_sequence[pos] == 'X') + --number; + ++pos; + } + } + else if (x == 'D') + { + while (number > 0) + { + if (aligned_sequence[pos] == 'X') + { + aligned_sequence[pos] = '-'; + --number; + } + ++pos; + } + } + } + + if (is_leaf1) + { +// printf("LEAF\n"); + edit_seq2aligned_seq(aligned_sequence, sequence_file, seq_positions[child1], alignment_file); + } + else + { + fprintf(edit_seq_file, "%s", aligned_sequence); + edit2alignment(sequence_file, seq_positions, edit_file, edit_positions, child1, number_of_sequences, aligned_sequence, alignment_length, edit_seq_file, offset, alignment_file); + } + + //second child + fseek(edit_seq_file, offset, SEEK_CUR); + fgets(aligned_sequence, alignment_length+3, edit_seq_file); + fseek(edit_seq_file, offset, SEEK_CUR); + + pos = 0; + fseek(edit_file, edit_positions[node_number-number_of_sequences], SEEK_SET); + while(fgets(line, LINE_LENGTH , edit_file)!=NULL) + { + x = line[0]; + if (x == '*') + break; + number = atoi(&line[1]); + if (x == 'M') + { + while (number > 0) + { + if (aligned_sequence[pos] == 'X') + --number; + ++pos; + } + } + else if (x == 'I') + { + while (number > 0) + { + if (aligned_sequence[pos] == 'X') + { + aligned_sequence[pos] = '-'; + --number; + } + ++pos; + } + } + else if (x == 'D') + { + while (number > 0) + { + if (aligned_sequence[pos] == 'X') + --number; + ++pos; + } + } + } + + if (is_leaf2) + { + edit_seq2aligned_seq(aligned_sequence, sequence_file, seq_positions[child2], alignment_file); + } + else + { + fprintf(edit_seq_file, "%s", aligned_sequence); + edit2alignment(sequence_file, seq_positions, edit_file, edit_positions, child2, number_of_sequences, aligned_sequence, alignment_length, edit_seq_file, offset, alignment_file); + } +} + + + + +// * The file has the follwing format (# and text behind are only comments and not included into the file): +// * 1 # Number of profile. +// * 1 # is leaf. +// * 5 # Number of columns in the profile. +// * 4A 1C # In the first column are 4 'A' and 1 'C' +// * 3G # In the second column are 3 'G' +// * 5A # In the third column are 5 'A' +// * 2A 3C # In the fourth column are 2 'A' and 3 'C' +// * 5C # In the fifth column are 5 'C' +// * * # Marks the end of this profile + + + +/** + * \brief Writes a profile to a file. + * + * \param sumup_prf The profile array, not a real profile. + * \param length The length of the profile. The format can be seen in ./test.txt + * \param file The FILE object to write the the profile into. + * \param is_dna The type of sequence. + * \param number The number of the profile. + */ +void +write2file(int **sumup_prf, + int length, + FILE *file, + int number, + int num_sequences, + Fastal_param *param_set) +{ + char *pos2aa = &(param_set->pos2char[0]); + fprintf(file,"%i\n0\n%i\n1\n%i\n",number, length, num_sequences ); + int i, j; + int alphabet_size = param_set->alphabet_size; + + i = 0; + int x = 0; + while (i < length) + { + for (j = 0; j < alphabet_size; ++j) + if (sumup_prf[j][i] > 0) + { + if (x) + fprintf(file," %c%i", pos2aa[j],sumup_prf[j][i]); + else + fprintf(file,"%c%i", pos2aa[j],sumup_prf[j][i]); + x = 1; + } + x = 0; + fprintf(file,"\n"); + ++i; + } + fprintf(file,"*\n"); +} + + + +//************************************* main function of the fasta algorithm *********************************************** + +/** +* \brief main of the fastal algorithm +*/ +int +fastal_main(int argc, //number of arguments + char **argv) //arguments first = fastal, second = tree +{ + + int i; + //pointer to arguments + void * method_arguments_p; + int (*alignment_function)(Fastal_profile **profiles, Fastal_param *param_set, void *method_arguments_p, int is_dna, FILE *edit_file, FILE *prof_file, int number); + + struct Fastal_arguments arguments; + + arg_parse (argc, argv, &arguments); + + Fastal_param *param_set = vcalloc(1,sizeof(Fastal_param)); + + fill_parameters(arguments.is_dna, param_set, arguments.method, arguments.diag_method, arguments.mat); + param_set->gep = arguments.gep; + param_set->gop = arguments.gop; + +// printf("%s",arguments.mat); + if (arguments.evaluate) + { + printf("Calculate Sum of pairs Score\n"); + printf("Score: %f\n", calculate_sum_of_pairs_score_affine(arguments.sequence_file, param_set->M, param_set->gop, param_set->gep)); + vfree(param_set); + exit(0); + } + + + if (arguments.agreement_score) + { + complete_agreement_score(arguments.aln2test, arguments.aln_ref); + return 0; + } + + + if (arguments.num_ref_aln) + { + compute_ref_alignments(arguments.sequence_file, arguments.aln_ref, arguments.num_ref_aln, arguments.num_seq_in_ref); + return 0; + } + + + + int alphabet_size = param_set->alphabet_size; + + + //sequence file management +// char **seq_name; + long *file_positions = NULL; + long **tmp = &file_positions; + int number_of_sequences = make_index_of_file(arguments.sequence_file, tmp); + + + + //edit file management + +// long current_edit_pos; + long *edit_positions = vcalloc(number_of_sequences,sizeof(long)); + + + //profile management + Fastal_profile **profiles = vcalloc(3,sizeof(Fastal_profile*)); + initiate_profiles(profiles, param_set); + FILE * prof_file = fopen(vtmpnam(NULL),"w+"); + long* profile_positions = vcalloc(4,sizeof(long*)); + int max_prof = 4; + int saved_prof = 0; + + + printf("METHOD: %s\n",param_set->method); + if (strcmp(param_set->method, "fast") == 0) + { + method_arguments_p = vcalloc(1,sizeof(Sparse_dynamic_param)); + fill_arguments_sparse((Sparse_dynamic_param*)method_arguments_p); + alignment_function = sparse_dyn; + } + else if (strcmp(param_set->method, "nw") == 0) + { + method_arguments_p = vcalloc(1,sizeof(Nw_param)); + fill_arguments_nw((Nw_param*)method_arguments_p, alphabet_size); + alignment_function = nw_dyn; + } + else if (strcmp(param_set->method, "gotoh") == 0) + { + method_arguments_p = vcalloc(1,sizeof(Gotoh_param)); + fill_arguments_gotoh((Gotoh_param*)method_arguments_p, alphabet_size); + alignment_function = gotoh_dyn; + } + else if (strcmp(param_set->method, "udisc") == 0) + { + method_arguments_p = vcalloc(1,sizeof(Udisc_param)); + fill_arguments_gotoh((Gotoh_param*)method_arguments_p, alphabet_size); + alignment_function = gotoh_dyn; + + } + else + { + printf("ERROR - METHOD"); + exit(1); + } + + + if (arguments.gap_iterate) + { + iterate(param_set, method_arguments_p, arguments.sequence_file, arguments.output_file, arguments.gap_iterate); + return 0; + } + + if (arguments.tree_file == NULL) + { + arguments.tree_file = vtmpnam(NULL); + printf("CONSTRUCT TREE\n"); + if (strcmp(arguments.tree_method, "parttree")==0) + { + make_partTree(arguments.sequence_file, arguments.tree_file, arguments.tree_param1, arguments.tree_param2, arguments.is_dna, 0); + } + else if (strcmp(arguments.tree_method, "oligotree") == 0) + { + compute_oligomer_distance_tree(arguments.sequence_file, param_set->char2pos, arguments.tree_file, arguments.tree_param2, arguments.tree_param1, param_set->alphabet_size); + } + + if (arguments.tree_only == 1) + return 0; + } + + + if (arguments.tree_out == 1) + { + char tree_out_file_name[500]; + sprintf(tree_out_file_name, "%s.tree",arguments.output_file); + char const LINE_LENGTH = 50; + char line[LINE_LENGTH]; + + FILE* in = fopen(arguments.tree_file, "r"); + FILE* out = fopen(tree_out_file_name, "w"); + while( (fgets(line, LINE_LENGTH, in)) != NULL) + fprintf(out, "%s", line); + fclose(in); + fclose(out); + } + + + + + + FILE *seq_file = fopen(arguments.sequence_file,"r"); +// FILE *edit_file = fopen(vtmpnam(NULL),"w+"); + FILE *edit_file = fopen("aha","w+"); + + printf("CONSTRUCT ALIGNMENT\n"); + FILE *tree_file = fopen(arguments.tree_file,"r"); + const int LINE_LENGTH = 100; + char line[LINE_LENGTH]; + char delims[] = " "; + int node[3]; + int alignment_length = -1; + node[2] = -1; + + + //bottom-up traversal + while(fgets(line, LINE_LENGTH, tree_file)!=NULL) + { + //read profiles + node[0] = atoi(strtok(line,delims)); + node[1] = atoi(strtok(NULL,delims)); + node[2] = atoi(strtok(NULL,delims)); + + //getting profile of second child + if (node[1] < number_of_sequences) + { + file_pos2profile(seq_file, file_positions[node[1]], profiles[1], node[1], param_set); //profile to save into + } + else + { + profile_file2profile(profiles[1], prof_file, profile_positions[--saved_prof], param_set); + fseek (prof_file , profile_positions[saved_prof] , SEEK_SET); + } + + //getting profile of first child + if (node[0] < number_of_sequences) + { + file_pos2profile(seq_file, file_positions[node[0]], profiles[0], node[0], param_set); //profile to save into + } + else + { + profile_file2profile(profiles[0], prof_file, profile_positions[--saved_prof], param_set); + fseek (prof_file , profile_positions[saved_prof] , SEEK_SET); + } + + + if (saved_prof == max_prof) + { + max_prof += 5; + profile_positions = vrealloc(profile_positions, max_prof*sizeof(long)); + } + + edit_positions[node[2]-number_of_sequences] = ftell(edit_file); + profile_positions[saved_prof] = ftell(prof_file); + ++saved_prof; + + //aligning the sequences + alignment_length = alignment_function(profiles, param_set, method_arguments_p, arguments.is_dna, edit_file, prof_file, node[2]); + } + + +// bottom-down traversal (edit_files --> alignment) +// tmp_out_file_name = vtmpnam(NULL); + +// FILE *alignment_file = fopen(tmp_out_file_name, "w"); + FILE *alignment_file = fopen(arguments.output_file, "w"); + FILE *edit_seq_file = fopen(vtmpnam(NULL),"w+"); + + char *aligned_sequence = vcalloc(alignment_length+3, sizeof(char)); + + + long offset = ftell(edit_seq_file); + for (i = 0; i < alignment_length; ++i) + { + fprintf(edit_seq_file, "X"); + aligned_sequence[i] = 'X'; + } + aligned_sequence[i]= '\n'; + aligned_sequence[i+1]= '\0'; + fprintf(edit_seq_file, "\n"); + offset = (ftell(edit_seq_file) - offset)*-1; + + + edit2alignment(seq_file, file_positions, edit_file, edit_positions, node[2], number_of_sequences, aligned_sequence, alignment_length, edit_seq_file, offset, alignment_file); + fclose(alignment_file); + fclose(tree_file); + fclose(edit_file); + fclose(seq_file); + fclose(edit_seq_file); + + //set stuff for the next cycle +// arguments.sequence_file = tmp_out_file_name; + + +// // //DEBUG +// // char copy_command[500]; +// // sprintf(copy_command, "cp %s %s_%i", tmp_out_file_name, arguments.output_file, cycle); +// // system(copy_command); +// ++cycle; +// } + +// printf("HERE_COPY\n"); +// char copy_command[2000]; +// sprintf(copy_command, "mv %s %s", tmp_out_file_name, arguments.output_file); +// printf("%s\n", copy_command); +// int error = system(copy_command); +// printf("ERROR %i\n", error); + + + //free_memory & close files + fclose(prof_file); + free_fastal_profile(profiles[0], alphabet_size); + free_fastal_profile(profiles[1], alphabet_size); + vfree(profiles); + vfree(profile_positions); + + + +// number_of_sequences + + + if (arguments.score) + { + printf("Calculate Score\n"); + double aln_score = calculate_sum_of_pairs_score_affine(arguments.output_file, param_set->M, param_set->gop, param_set->gep); + printf("SCORE: %f\n", aln_score); + } + + + + + + if (!strcmp(param_set->method, "fast")) + { + free_sparse((Sparse_dynamic_param*)method_arguments_p); + } + else if (!strcmp(param_set->method, "nw")) + { + free_nw((Nw_param*)method_arguments_p, alphabet_size); + } + else if (!strcmp(param_set->method, "gotoh")) + { + free_gotoh((Gotoh_param*)method_arguments_p, alphabet_size); + } + + vfree(param_set); + + //free_memory & close files + + vfree(edit_positions); + + + return 0; +} + + + + +//****************** toolbox *************************** + + +/** + * \brief Enlargement of the dynamic programming matrix in case it is to small. + * + * \param dyn_matrix The dynamic programming matrix. + * \param old_length1 Current size of dimension 1. + * \param old_length2 Current size of dimension 2. + * \param length1 New size of dimension 1. + * \param length2 New size of dimension 2. + * \return Pointer to the new array. + */ +double** +resize_dyn_matrix(double **dyn_matrix, //the dynamic programming matrix + int old_length1, //old length of dimension 1 + int old_length2, //old length of dimension 2 + int length1, //new minimum length of dimension 1 + int length2) //new maximum length of dimension 2 +{ + int i; + if (old_length1 < length1) + { + dyn_matrix = vrealloc(dyn_matrix,length1*sizeof(double*)); + for (i = old_length1; i < length1; ++i) + dyn_matrix[i] = vcalloc(old_length2,sizeof(double)); + old_length1 = length1; + } + + if (old_length2 < length2) + { + for (i = 0;ialphabet_size; + int i,j; + for (i =0; i < 3; ++i) + { + profiles[i] = vcalloc(1,sizeof(Fastal_profile)); + profiles[i]->weight = 1; + profiles[i]->is_leaf = 1; + profiles[i]->prf = vcalloc(alphabet_size, sizeof(int*)); + for (j = 0; j < alphabet_size; ++j) + { + profiles[i]->prf[j] = vcalloc(PROFILE_ENLARGEMENT, sizeof(int)); + } + profiles[i]->allocated_memory = PROFILE_ENLARGEMENT; + } +} + + + + +/** + * \brief frees all memory occupied by the profile + * + * \param profile The profile to free. + * \param alphabet_size The alphabet_size. + */ +void +free_fastal_profile(Fastal_profile* profile, int alphabet_size) +{ + --alphabet_size; + for (;alphabet_size >= 0; --alphabet_size) + vfree(profile->prf[alphabet_size]); + vfree(profile->prf); +} + + +/** + * \brief Initialize the Fastal parameter set. + * + * \param is_dna 1 when sequences are dna, 0 when not + * \param param_set The fastal parameter set. + * \param method The method to use in Fastal. +*/ +void +fill_parameters(int is_dna, Fastal_param *param_set, char *method, char *diag_method, char *mat) +{ + sprintf(param_set->method,"%s",method); + sprintf(param_set->diag_method,"%s",diag_method); + int i; + printf("%s",mat); + param_set->M = read_matrice(mat); + if (is_dna) + { + param_set->alphabet_size = 4; + char tmp1[] = {'A','C','G','T'}; + +// int tmp2[] = { 0, 1, 1, 0, -1, -1, 2, 0, -1, -1, 3, -1, 1, 0, -1, -1, -1, 0, 1, 3, 4, -1, 3, -1, 1, -1}; + for (i = 0; ialphabet_size; ++i) + param_set->pos2char[i] = tmp1[i]; +// for (i = 0; i<26; ++i) +// param_set->char2pos[i] = tmp2[i]; + param_set->char2pos['A'] = 0; + param_set->char2pos['B'] = 1; + param_set->char2pos['C'] = 1; + param_set->char2pos['D'] = 0; + param_set->char2pos['G'] = 2; + param_set->char2pos['H'] = 0; + param_set->char2pos['K'] = 3; + param_set->char2pos['M'] = 1; + param_set->char2pos['N'] = 0; + param_set->char2pos['R'] = 0; + param_set->char2pos['S'] = 1; + param_set->char2pos['T'] = 3; + param_set->char2pos['U'] = 3; + param_set->char2pos['W'] = 3; + param_set->char2pos['Y'] = 1; +// param_set->M[0][3] = param_set->M[3][0] = -10; +// param_set->M[1][2] = param_set->M[2][1] = -10; +// param_set->M[0][1] = param_set->M[0][2] = param_set->M[1][0] = param_set->M[2][0] = -10; +// param_set->M[3][1] = param_set->M[3][2] = param_set->M[1][3] = param_set->M[2][3] = -10; + } + else + { + param_set->alphabet_size = 21; + char tmp1[] = {'A','C','D','E','F','G','H','I','K','L','M','N','P','Q','R','S','T','V','W','Y','X'}; +// int tmp2[] = { 0, 20, 1, 5, 16, 4, 2, 6, 7, 21, 8, 9, 10, 11, -1, 12, 13, 14, 15, 3, -1, 17, 18, 22, 19, 23}; + for (i = 0; ialphabet_size; ++i) + param_set->pos2char[i] = tmp1[i]; +// for (i = 0; i<26; ++i) +// param_set->char2pos[i] = tmp2[i]; + param_set->char2pos['A'] = 0; + param_set->char2pos['B'] = 20; + param_set->char2pos['C'] = 1; + param_set->char2pos['D'] = 2; + param_set->char2pos['E'] = 3; + param_set->char2pos['F'] = 4; + param_set->char2pos['G'] = 5; + param_set->char2pos['H'] = 6; + param_set->char2pos['I'] = 7; + param_set->char2pos['J'] = 20; + param_set->char2pos['K'] = 8; + param_set->char2pos['L'] = 9; + param_set->char2pos['M'] = 10; + param_set->char2pos['N'] = 11; + param_set->char2pos['P'] = 12; + param_set->char2pos['Q'] = 13; + param_set->char2pos['R'] = 14; + param_set->char2pos['S'] = 15; + param_set->char2pos['T'] = 16; + param_set->char2pos['V'] = 17; + param_set->char2pos['W'] = 18; + param_set->char2pos['X'] = 20; + param_set->char2pos['Y'] = 19; + param_set->char2pos['X'] = 20; + } +} + + + +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/fastal_lib_header.h b/binaries/src/tcoffee/t_coffee_source/fastal_lib_header.h new file mode 100644 index 0000000..90fceac --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/fastal_lib_header.h @@ -0,0 +1,367 @@ + + +#define ENLARGEMENT_PER_STEP 50 +#define PROFILE_ENLARGEMENT 550 + +// static char pos2aa[] = {'A','C','D','E','F','G','H','I','K','L','M','N','P','Q','R','S','T','V','W','Y'}; + + +/** + * \brief Struct to save a diagonal + * + */ +typedef struct +{ + ///Start of diagonal in seq1. + int x; + ///Start of diagonal in seq2. + int y; + ///Length of the diagonal. + int length; + ///expansion at the beginning; + int front_exp; + ///expansion at the end; + int end_exp; +} +Diagonal; + + + + +/** + * \brief Struct to save all informations of a profile. + * + */ +typedef struct +{ + /// Number of sequences in this profile + int num_sequences; + /// number of the profile + int prf_number; + ///0 = combination of two profiles, 1 = profile of a single sequence -> name1 = seq_name + int is_leaf; + ///length of the profile + int length; + ///weight of the sequence + int weight; + ///saves the amount of allocated memory + int allocated_memory; + ///the profile itself [alphabet_size][profile_length] + int **prf; + ///number_of_sequences + int number_of_sequences; +} +Fastal_profile; + +/** + * \brief Struct to save all parameters for fastal. + * + */ +typedef struct +{ + /// size of alphabet_size + int alphabet_size; + /// converting char2position (for profile) + int char2pos[256]; + /// converting pos2char (for profile) + char pos2char[256]; + /// gap opening costs + double gop; + /// gap extension costs + double gep; + /// nomatch??? + int nomatch; + ///method to align profile + char method[20]; + ///scoring Matrix; + int **M; + ///saves the diag method -> move to sparse! + char diag_method[30]; +} +Fastal_param; + +/** + * \brief Struct to save the parameters and memory for the sparse dynamic programming algorithm. + */ +typedef struct +{ + /// saves the diagonals + int *diagonals; + /// saves .... + int *dig_length; + /// list of points to be considered during the alignment process + int **list; + /// number of points in \a list + int *list_length; + char *file_name1; + char *file_name2; + // static char *file_name1 = vtmpnam(NULL); +// static char *file_name2 = vtmpnam(NULL); +} +Sparse_dynamic_param; + + +typedef struct +{ + int window_length; + int step_legnth; + int threshold; + int oligo_length; + int distance; +} +Udisc_param; + + +/** + * \brief Struct to save the parameters and memory for the needleman-wunsch algorithm. + */ +typedef struct +{ + /// dynamic programming matrix + double ** dyn_matrix; + /// length of dimension 1 + int *length1; + /// length of dimension 2 + int *length2; + /// summed up version of profile + int **sumup_prf; + /// number of entries in \a sumup_prf + int *sumup_length; +} +Nw_param; + + + +/** + * \brief Struct to save the parameters and memory for the Gotoh algorithm. + */ +typedef struct +{ + /// dynamic programming matrix + double ** m_matrix; + /// dynamic programming matrix + double ** i_matrix; + /// dynamic programming matrix + double ** d_matrix; + /// length of dimension 1 + int *length1; + /// length of dimension 2 + int *length2; + /// summed up version of profile + int **sumup_prf; + /// number of entries in \a sumup_prf + int *sumup_length; + /// log saver + double **log_saver; +} +Gotoh_param; + + + + +typedef struct +{ + int diagonal; + int count; + int start; + int end; +} +Swift_diagonal; + + +typedef struct +{ + int diagonal; + int count; +} +Diagonal_counter; + +//tree +void generate_random_tree(int number); + + +Fastal_profile* make_profile_of_sequence(char *seq_name, char *sequence, int number); + + + +//Definite use + +//********************* input/output ********************************** +void file2profile(FILE* profile_f, Fastal_profile *profile, int prf_number, Fastal_param *param_set); +void file_pos2profile(FILE *seq_file, long off_set, Fastal_profile *profile, int prf_number, Fastal_param *param_set); +void profile2file(Fastal_profile *profile, FILE* prf_f, Fastal_param *param_set); + +//index +int make_index_of_file(char *file_name, long **result); + + +//********************* pairwise alignment methods ************************ + + //Needleman-Wunsch + int prf_nw(Fastal_profile *profile1, Fastal_profile *profile2, double **prog_matrix, FILE *edit_file_name, int **sumup_prf, int *sumup_length, Fastal_param *param_set); + int nw_matrix2edit_file(double **prog_matrix, Fastal_profile *profile1, Fastal_profile *profile2, FILE *edit_f, int **prf_field, int *field_length, Fastal_param *param_set); + int** sumup_profile(Fastal_profile *profile, int **sumup_prf, Fastal_param *param_set); + void write2file(int **sumup_prf, int length, FILE *file, int number, int num_sequences, Fastal_param *param_set); + + //Gotoh + void free_gotoh(Gotoh_param* method_arguments_p, int alphabet_size); + void fill_arguments_gotoh(Gotoh_param* method_arguments_p, int alphabet_size); + int prf_gotoh(Fastal_profile *profile1, Fastal_profile *profile2, FILE *edit_file_name, Gotoh_param *arguments, Fastal_param *param_set); + + //Sparse dynamic programming + void free_sparse(Sparse_dynamic_param* method_arguments_p); + void fill_arguments_sparse(Sparse_dynamic_param* method_arguments_p); + int **diagonals2int(int *diagonals, int num_diagonals, char *seq1, char *seq2, int *num_points, Fastal_param *param_set); + int seq_pair2blast_diagonal(char *seq_file_name1, char *seq_file_name2, int **diagonals, int *dig_length, int l1, int l2, int is_dna); + int sparse_dyn(Fastal_profile **profiles, Fastal_param *param_set, void *method_arguments_p, int is_dna, FILE *edit_file, FILE *prof_file, int number); + char *profile2consensus(Fastal_profile *profile, Fastal_param *param_set); + int ** diagonals2int_gap_test(int *diagonals, int num_diagonals, char *seq1, char *seq2, Fastal_profile *profile1, Fastal_profile *profile2, int *num_points, Fastal_param *param_set); + int ** diagonals2int_euclidf(int *diagonals, int num_diagonals, char *seq1, char *seq2, Fastal_profile *profile1, Fastal_profile *profile2, int *num_points, Fastal_param *param_set); + int ** diagonals2int_dot(int *diagonals, int num_diagonals, char *seq1, char *seq2, Fastal_profile *profile1, Fastal_profile *profile2, int *num_points, Fastal_param *param_set); + int seq_pair2blastz_diagonal(char *seq_file_name1, char *seq_file_name2, int **diagonals, int *dig_length, int l1, int l2, int is_dna); + int list2linked_pair_wise_fastal(Fastal_profile *prf1, Fastal_profile *prf2, Fastal_param *param_set, int **list, int n, FILE *edit_f, FILE *prof_f, int node_number); + +//edit_files 2 alignment +void edit2alignment(FILE *sequence_file, long *seq_positions, FILE *edit_file, long *edit_positions, int node_number, int number_of_sequences, char *aligned_sequence, int alignment_length, FILE *edit_seq_file, int offset, FILE* alignment_file); +void edit_seq2aligned_seq(char *aligned_sequence, FILE *sequence_file, long sequence_position, FILE *alignment_file); + + +//main +int fastal(int argc, char **argv); +void alignment2files(Fastal_profile **profiles, Fastal_param *param_set,int **alignment, int alignment_length, FILE *edit_f, FILE *prof_f, int node_number); + +//toolbox +double calculate_sum_of_pairs_score_affine(char *alignment_file_name, int **score_matrix, double gop, double gep); +double calculate_sum_of_pairs_score_affine_test(char *alignment_file_name, int **score_matrix, double gop, double gep); +void initiate_profile_files(FILE **profile_files); +void initiate_profiles(Fastal_profile **profiles, Fastal_param *param_set); +void free_fastal_profile(Fastal_profile *profile, int alphabet_size); +double **resize_dyn_matrix(double **dyn_matrix, int old_length1, int old_length2, int length1, int length2); +void free_dyn_matrix(int length1, double **dyn_matrix); +void fill_parameters(int is_dna, Fastal_param *param_set, char *method, char *diag_method, char *mat); + + +int seq_pair2diagonal_own(char *seq1, char *seq2, int **diagonals, int *dig_length, int l1, int l2, int is_dna, int word_length); + + + + + + + +typedef struct +{ + ///field saving the positions [x1,y1,l1,x2,y2,l2,...] + int *segments; + /// points to the current used segment + int *current_pos; + /// saves the previous diagonal position. + int prev_position; + /// diagonal number +// int diagonal_num; +} +Segment; + + +Segment* extend_diagonals(Diagonal *diagonals, int *num_diagonals, int l1, int l2); +int seq_pair2blast_diagonal2(char *seq_file_name1, char *seq_file_name2, Diagonal **diagonals, int *dig_length, int l1, int l2, int is_dna); + +int ** segments2int(Segment *diagonals, int num_diagonals, char *seq1, char *seq2, Fastal_profile *profile1, Fastal_profile *profile2, int *num_points, Fastal_param *param_set); +// #include "string.h" + +struct Fastal_arguments +{ +// char *args[2]; + //IO + + + char *sequence_file; + char *tree_file; + char *output_file; + int tree_out; + + char *method; + int is_dna; + double gop; + double gep; + + + + char *diag_method; +// Tree Computation +// int retree; + int gap_iterate; + int tree_only; + char *tree_method; + int tree_param1; + int tree_param2; + + + //Scoring + char *mat; + int agreement_score; + int evaluate; + int score; + int num_ref_aln; + int num_seq_in_ref; + char *aln_ref; + char *aln2test; +}; + + + + +void tree_parse(struct Fastal_arguments *arguments, char* param); + + + +void arg_parse (int argc, char **argv, struct Fastal_arguments *arguments); + + + +//sum of pairs score +double calculate_sum_of_pairs_score_affine(char *alignment_file_name, int **score_matrix, double gop, double gep); + + +//compare with reference alignment +void make_ref_alignment(char *seq_file_name, char *tree_file_name, char *ref_aln_name, int num_seq_in_ref); +double agreement_score(char *ref_file_name, char *aln_file_name); + + +void seq2profile2(char *seq, Fastal_profile *prf, int *char2pos); +void split_set(FILE *aln_file_name, Fastal_profile *gap_prf, Fastal_profile *no_gap_prf, char *seq, int index, int *char2pos, char* split_file_name); +void iterate(Fastal_param *param, void *method_arguments_p, char *aln_file_name, char *out_file_name, int iteration_number); + +void edit2seq_pattern(FILE *edit_file, char *seq1, char *seq2); +int *del_gap_from_profile(Fastal_profile *prf, int alphabet_size, int *gap_list, int *gap_list_length, int *num_gaps); + +void write_iterated_aln(char* old_aln_file_name, char* new_aln_file_name, char *gap_file_name, char *seq1, int *gap_list1, int num_gap1, char *seq2, int *gap_list2, int num_gap2); +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/fastal_opt_parsing.c b/binaries/src/tcoffee/t_coffee_source/fastal_opt_parsing.c new file mode 100644 index 0000000..f028832 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/fastal_opt_parsing.c @@ -0,0 +1,258 @@ + +#include "string.h" +#include "stdio.h" +#include "stdlib.h" +#include "fastal_lib_header.h" + + +void +tree_parse(struct Fastal_arguments *arguments, char* param) +{ + char delims[] = ""; + arguments->tree_method = strtok(param,delims); + if (arguments->tree_method == "parttree") + { + arguments->tree_param1 = 6; + arguments->tree_param2 = 150; + } + char *tmp = strtok(NULL,delims); + if (tmp != NULL) + { + arguments->tree_param1 = atoi(tmp); + arguments->tree_param2 = atoi(strtok(NULL,delims)); + } +// printf("A: %s %i %i", arguments->tree_method, arguments->tree_param1, arguments->tree_param2); +} + + + +void +arg_parse (int argc, char **argv, struct Fastal_arguments *arguments) +{ +// default values + + arguments->diag_method = "blast"; + arguments->output_file = "out->aln"; + arguments->tree_file = NULL; + arguments->gep = -1; + arguments->gop = -10; + arguments->method = "fast"; + arguments->tree_method = "oligotree"; + arguments->mat="dna_idmat"; + arguments->tree_only = 0; + arguments->evaluate = 0; + arguments->score = 0; +// arguments->retree = 0; + arguments->agreement_score = 0; + arguments->num_ref_aln = 0; + arguments->is_dna = 1; + arguments->aln_ref = NULL; + arguments->aln2test = NULL; + arguments->tree_out = 0; + arguments->gap_iterate = 0; + + + int i = 1; + char *param; + + for (i = 0; i < argc; ++i) + { + param = argv[i]; + if ( ( !strcmp(param, "-d" )) || ( !strcmp(param, "--is_dna"))) + { + arguments->is_dna = 1; + arguments->mat = "dna_idmat"; + } + else if ( ( !strcmp(param, "-a" )) || ( !strcmp(param, "--is_aa"))) + { + arguments->is_dna = 0; + arguments->mat = "blosum62mt"; + + } +// printf("%s\n", arguments->mat); + } + if (arguments->is_dna) + { + arguments->tree_param1 = 2; + arguments->tree_param2 = 5; + } + else + { + arguments->tree_param1 = 1; + arguments->tree_param2 = 10; + } + + + i = 1; + while (i < argc) + { + param = argv[i]; + if ( ( !strcmp(param, "-i" )) || ( !strcmp(param, "--in"))) + { + arguments->sequence_file = argv[++i]; + } + else if ( ( !strcmp(param, "-t" )) || ( !strcmp(param, "--tree_file"))) + { + arguments->tree_file = argv[++i]; + } + else if ( !strcmp(param, "--mat")) + { + arguments->mat = argv[++i]; + } + else if ( !strcmp(param, "--tree_method")) + { + tree_parse(arguments, argv[++i]); +// arguments->tree_file = argv[++i]; + } + else if ( ( !strcmp(param, "-o" )) || ( !strcmp(param, "--outfile"))) + { + arguments->output_file = argv[++i]; + } + else if ( ( !strcmp(param, "-m" )) || ( !strcmp(param, "--method"))) + { + ++i; + if ( (!strcmp(argv[i], "fast")) || (!strcmp(argv[i], "nw")) || (!strcmp(argv[i], "gotoh")) || (!strcmp(argv[i], "udisc")) ) + arguments->method = argv[i]; + else + { + printf("Method %s unknown\n", argv[i]); + exit(1); + } + } + else if ( ( !strcmp(param, "-b" )) || ( !strcmp(param, "--diag_method"))) + { + ++i; + if ( (!strcmp(argv[i], "blast")) || (!strcmp(argv[i], "blastz")) || (!strcmp(argv[i], "blat")) || (!strcmp(argv[i], "ktup"))) + arguments->diag_method = argv[i]; + else + { + printf("DIAG Method %s unknown\n", argv[i]); + exit(1); + } + } + else if ( ( !strcmp(param, "-d" )) || ( !strcmp(param, "--is_dna"))) + { + arguments->is_dna = 1; + } + else if ( ( !strcmp(param, "-a" )) || ( !strcmp(param, "--is_aa"))) + { + arguments->is_dna = 0; + } + else if ( ( !strcmp(param, "-g" )) || ( !strcmp(param, "--gop"))) + { + arguments->gop = atof(argv[++i]); + } +// else if ( ( !strcmp(param, "-r" )) || ( !strcmp(param, "--retree"))) +// { +// arguments->retree = atoi(argv[++i]); +// } + else if ( ( !strcmp(param, "-e" )) || ( !strcmp(param, "--gep"))) + { + arguments->gep = atof(argv[++i]); + } + else if ( ( !strcmp(param, "-k" )) || ( !strcmp(param, "--p1"))) + { + arguments->tree_param1 = atoi(argv[++i]); + } + else if ( ( !strcmp(param, "-c" )) || ( !strcmp(param, "--p2"))) + { + arguments->tree_param2 = atoi(argv[++i]); + } + else if ( !strcmp(param, "--eval_aln")) + { + arguments->evaluate = 1; + } + else if ( ( !strcmp(param, "-s" )) || ( !strcmp(param, "--score"))) + { + arguments->score = 1; + } + else if ( !strcmp(param, "--tree_out")) + { + arguments->tree_out = 1; + } + else if ( !strcmp(param, "--tree_only")) + { + arguments->tree_only = 1; + } + else if ( !strcmp(param, "--agreement_score")) + { + arguments->agreement_score = 1; + } + else if ( !strcmp(param, "--make_ref_aln")) + { + arguments->num_ref_aln = atoi(argv[++i]); + arguments->num_seq_in_ref = atoi(argv[++i]); + } + else if ( !strcmp(param, "--aln_ref")) + { + arguments->aln_ref = argv[++i]; + } + else if ( !strcmp(param, "--gap_iterate")) + { + arguments->gap_iterate = atoi(argv[++i]); + } + else if ( !strcmp(param, "--aln2test")) + { + arguments->aln2test = argv[++i]; + } + else if ( ( !strcmp(param, "-h" )) || ( !strcmp(param, "--help")) || ( !strcmp(param, "-?" ))) + { + printf("Fastal - a fast alignment tool\n"); + printf("-i --in The sequence_file\n"); + printf("-t --tree_file The treefile\n"); + printf(" --tree_method The method to produce the tree:\n"); + printf(" oligo - very fast method\n"); + printf(" parttree - method like in mafft\n"); + printf("-o --outfile The output file\n"); + printf("-m --method The method to use:\n"); + printf(" fast - fast approximate algorithm [default]\n"); + printf(" nw - needleman-wunsch\n"); + printf(" gotoh - gotoh\n"); + printf("-d --is_dna Sequence are DNA\n"); + printf("-a --is_aa Sequences are amino acids\n"); + printf("-g --gop Gap opening costs\n"); + printf("-e --gep Gap extension costs\n"); + printf("-r --retree Number of reconstructions [default=0]\n"); + printf(" --tree_only only tree is produced\n"); + printf(" --eval_aln calculates only the sum-of-pairs-score of a given alignment\n"); + printf("-s --score calculates the sum of paris score after construction of an alignment. Can take a long time. [default: off]\n"); +// printf(" --make_ref_aln calculates the sum of paris score after construction of an alignment. Can take a long time. [default: off]\n"); + exit(0); + } + else + { + printf("Argument %s unknown\n", param); + exit(1); + } + ++i; + } +} +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/fsa_dp.c b/binaries/src/tcoffee/t_coffee_source/fsa_dp.c new file mode 100644 index 0000000..0a201cb --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/fsa_dp.c @@ -0,0 +1,2541 @@ +#include +#include +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" +#include "dp_lib_header.h" + +#define hmm_add(x,y) ((x==UNDEFINED || y==UNDEFINED)?UNDEFINED:(x+y)) +#define MAX_EMISSION 256 + +/*********************************************************************************/ +/* */ +/* */ +/* Procons dp */ +/* */ +/* */ +/*********************************************************************************/ +char alphabetDefault[] = "ARNDCQEGHILKMFPSTWYV"; +double emitPairsDefault[20][20] = { + {0.02373072f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00244502f, 0.01775118f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00210228f, 0.00207782f, 0.01281864f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00223549f, 0.00161657f, 0.00353540f, 0.01911178f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00145515f, 0.00044701f, 0.00042479f, 0.00036798f, 0.01013470f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00219102f, 0.00253532f, 0.00158223f, 0.00176784f, 0.00032102f, 0.00756604f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00332218f, 0.00268865f, 0.00224738f, 0.00496800f, 0.00037956f, 0.00345128f, 0.01676565f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00597898f, 0.00194865f, 0.00288882f, 0.00235249f, 0.00071206f, 0.00142432f, 0.00214860f, 0.04062876f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00114353f, 0.00132105f, 0.00141205f, 0.00097077f, 0.00026421f, 0.00113901f, 0.00131767f, 0.00103704f, 0.00867996f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00318853f, 0.00138145f, 0.00104273f, 0.00105355f, 0.00094040f, 0.00100883f, 0.00124207f, 0.00142520f, 0.00059716f, 0.01778263f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00449576f, 0.00246811f, 0.00160275f, 0.00161966f, 0.00138494f, 0.00180553f, 0.00222063f, 0.00212853f, 0.00111754f, 0.01071834f, 0.03583921f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00331693f, 0.00595650f, 0.00257310f, 0.00252518f, 0.00046951f, 0.00312308f, 0.00428420f, 0.00259311f, 0.00121376f, 0.00157852f, 0.00259626f, 0.01612228f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00148878f, 0.00076734f, 0.00063401f, 0.00047808f, 0.00037421f, 0.00075546f, 0.00076105f, 0.00066504f, 0.00042237f, 0.00224097f, 0.00461939f, 0.00096120f, 0.00409522f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00165004f, 0.00090768f, 0.00084658f, 0.00069041f, 0.00052274f, 0.00059248f, 0.00078814f, 0.00115204f, 0.00072545f, 0.00279948f, 0.00533369f, 0.00087222f, 0.00116111f, 0.01661038f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00230618f, 0.00106268f, 0.00100282f, 0.00125381f, 0.00034766f, 0.00090111f, 0.00151550f, 0.00155601f, 0.00049078f, 0.00103767f, 0.00157310f, 0.00154836f, 0.00046718f, 0.00060701f, 0.01846071f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00631752f, 0.00224540f, 0.00301397f, 0.00285226f, 0.00094867f, 0.00191155f, 0.00293898f, 0.00381962f, 0.00116422f, 0.00173565f, 0.00250962f, 0.00312633f, 0.00087787f, 0.00119036f, 0.00180037f, 0.01346609f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00389995f, 0.00186053f, 0.00220144f, 0.00180488f, 0.00073798f, 0.00154526f, 0.00216760f, 0.00214841f, 0.00077747f, 0.00248968f, 0.00302273f, 0.00250862f, 0.00093371f, 0.00107595f, 0.00147982f, 0.00487295f, 0.01299436f, 0.0f, 0.0f, 0.0f}, + {0.00039119f, 0.00029139f, 0.00021006f, 0.00016015f, 0.00010666f, 0.00020592f, 0.00023815f, 0.00038786f, 0.00019097f, 0.00039549f, 0.00076736f, 0.00028448f, 0.00016253f, 0.00085751f, 0.00015674f, 0.00026525f, 0.00024961f, 0.00563625f, 0.0f, 0.0f}, + {0.00131840f, 0.00099430f, 0.00074960f, 0.00066005f, 0.00036626f, 0.00070192f, 0.00092548f, 0.00089301f, 0.00131038f, 0.00127857f, 0.00219713f, 0.00100817f, 0.00054105f, 0.00368739f, 0.00047608f, 0.00102648f, 0.00094759f, 0.00069226f, 0.00999315f, 0.0f}, + {0.00533241f, 0.00169359f, 0.00136609f, 0.00127915f, 0.00119152f, 0.00132844f, 0.00178697f, 0.00194579f, 0.00071553f, 0.01117956f, 0.00914460f, 0.00210897f, 0.00197461f, 0.00256159f, 0.00135781f, 0.00241601f, 0.00343452f, 0.00038538f, 0.00148001f, 0.02075171f} +}; + +static void DisplayMatState ( MatState *S, char *s); + + + + + + +void check_viterbiL ( Alignment *A,int *ns, int **ls, Constraint_list *CL); +MatState *viterbi2path2 ( double ***Sc, int ***St, Hmm *H, MatState *S, MatState *E); +void testfunc ( MatState *S, char *s); + +#ifdef IN_PGROGRESS +/*********************************************************************************/ +/* */ +/* */ +/* MSA Analyzer */ +/* */ +/* */ +/*********************************************************************************/ +Alignment * analyze_alignment ( Alignment *A) +{ + evaluate_alignment (A); + H=define_msa_model (-100); + M=seq_viterbi_hmm (A->seq_al[0], H); + path=seq_viterbi2path ( seq, H, M); +} + + +Hmm* define_msa_model(double penalty) +{ + Hmm *H; + double freeT=0; + int n=0; + HmmState *S; + + + H=declare_hmm(2); + H->freeT=freeT=0; + + H->forbiden=FORBIDEN; + H->start=START_STATE; + H->end=END_STATE; + + /*define START*/ + S=H->S[n]; + sprintf (S->name, "START"); S->state=n; + + S->DI=0; + S->DJ=0; + S->em=freeT; + + sprintf ( (S->T[S->nT])->name, "C") ;(S->T[S->nT])->tr=freeT ;S->nT++; + sprintf ( (S->T[S->nT])->name, "W");(S->T[S->nT])->tr=freeT ;S->nT++; + n++; + /*define END*/ + S=H->S[n]; + sprintf (S->name, "END"); S->state=n; + S->DI=0; + S->DJ=0; + S->em=freeT; + n++; + + /*define Correct*/ + S=H->S[n]; + sprintf (S->name, "C"); S->state=n; + S->DI=1; + S->DJ=0; + S->em=H->forbiden; + S->em_func=em_correct_msa; + + sprintf ( (S->T[S->nT])->name, "C") ;(S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "W");(S->T[S->nT])->tr=penalty ;S->nT++; + sprintf ( (S->T[S->nT])->name, "END"); (S->T[S->nT])->tr=freeT;S->nT++; + n++; + + /*define Wrong*/ + S=H->S[n]; + sprintf (S->name, "INSERT"); S->state=n; + S->DI=1; + S->DJ=0; + S->em=H->forbiden; + S->em_func=em_wrong_msa; + sprintf ( (S->T[S->nT])->name, "C") ; (S->T[S->nT])->tr=penalty;S->nT++; + sprintf ( (S->T[S->nT])->name, "W"); (S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "END"); (S->T[S->nT])->tr=-gop;S->nT++; + n++; + + /*define LInsert*/ + S=H->S[n]; + sprintf (S->name, "LINSERT"); S->state=n; + S->DI=1; + S->DJ=0; + S->em=lgep; + + sprintf ( (S->T[S->nT])->name, "INSERT") ;(S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "LINSERT");(S->T[S->nT])->tr=freeT;S->nT++; + n++; + + H=bound_hmm ( H); + return H; +} +#endif +/*********************************************************************************/ +/* */ +/* */ +/* simple HMM: Viterbi */ +/* */ +/* */ +/*********************************************************************************/ +double pavie_em_func (Hmm*H, HmmState *S, int v); +Hmm* define_full_model(int nstate,char **state_list, char *model_name,Generic_em_func evaluation_func ); +char **produce_state_name (int nstate,char **list, char *model_name, Hmm* H); +double** seq_viterbi_hmm (char *seq, Hmm *H); +int * seq_viterbi2path (char *s, Hmm *H, double **M); +double analyze_sequence ( char *seq, Hmm*H); + +double pavie_emission (Hmm*H, HmmState *S, int v) +{ + char *n; + + + n=S->name; + + if ( v==n[0] || ( v=='*' && n[0]=='E')) return H->freeT; + return H->forbiden; +} +Hmm* define_full_model(int nstate, char **list, char *model_name, Generic_em_func emission_function) +{ + /*list: a list of the state names: does not include START or END*/ + /*model_name: a string that will be appended to the names in list*/ + + Hmm *H; + int a,n; + HmmState *S; + + + H=declare_hmm(nstate+2); + H->freeT=0; + + H->forbiden=FORBIDEN; + H->start=START_STATE; + H->end=END_STATE; + + list=produce_state_name (nstate,list, model_name, H); + nstate+=2; + + for (n=0; nS[n]; + S->state=n; + sprintf ( S->name, "%s", list[n]); + S->em_func2=emission_function; + if (n==H->end || n==H->start){S->DI=0;S->DJ=0;} + else S->DI=1;S->DJ=0; + + /*Emmissions*/ + S->em_func2=emission_function; + for (a=0; a< MAX_EMISSION; a++)S->em2[a]=H->freeT; + + for (a=0; aend; a++) + { + if (a!=H->start && !(n==H->start && a==H->end) ) + { + sprintf ( (S->T[S->nT])->name, "%s", list[a]); + (S->T[S->nT])->tr=H->freeT; + S->nT++; + } + } + } + return H; +} + +char **produce_state_name (int nstate,char **list, char *model_name, Hmm* H) +{ + int a,b,c; + char **new_list; + nstate+=2; + + new_list=declare_char ( nstate, 100); + for ( a=0, b=0, c=0; a< nstate; a++) + { + if ( a==H->start)sprintf ( new_list[a], "START"); + else if ( a==H->end)sprintf ( new_list[a], "END"); + else if ( list==NULL){sprintf ( new_list[a], "%c%s", 'a'+b, (model_name)?model_name:"");b++;} + else {sprintf ( new_list[a], "%c%s", list[a][c], (model_name)?model_name:"");c++;} + } + return new_list; +} + +int seq_viterbi_pair_wise (Alignment *A,int*ns, int **ls,Constraint_list *CL) +{ + ungap(A->seq_al[0]); + analyze_sequence (A->seq_al[0], NULL); + myexit (EXIT_FAILURE); + return 1; +} +double analyze_sequence ( char *seq, Hmm *H) +{ + + double **M; + int *path; + + if ( H==NULL) + { + H=define_full_model(5, NULL,"_first", pavie_emission); + H=bound_hmm(H); + DisplayHmm (H); + } + M=seq_viterbi_hmm (seq, H); + path=seq_viterbi2path (seq, H, M); + return M[H->end][strlen (seq)]; +} + + +double** seq_viterbi_hmm (char *seq, Hmm *H) +{ + /*Given a model H and a sequence seq*/ + double **M; + double e, v, max; + int i,pi, bestk, s, k, l1; + HmmState *S1, *S2; + + + l1=strlen (seq); + M=declare_double (H->nS*2,l1+2); + + /*Handle the start*/ + M[H->start][0]=0; + for ( i=0; i<=l1; i++) + { + for ( s=0; s< H->nS; s++) + { + S1=H->S[s]; + pi=i-S1->DI; + max=H->forbiden; + bestk=H->forbiden; + if ( pi<0){M[s][i]=H->forbiden;}/*Boundary*/ + else + { + if (pi==0) {max=H->T[(int)H->start][s];bestk=H->start;}/*Start*/ + else + { + for (k=1; k<=H->fromM[S1->state][0]; k++) + { + S2=H->S[H->fromM[s][k]]; + if ( S2->state==H->start || S2->state==H->end)continue; + v=hmm_add((M[S2->state][pi]),(H->T[S2->state][S1->state])); + if ( v!=H->forbiden && (max==H->forbiden || v>max)){max=v;bestk=S2->state;} + } + } + if (S1->em2)e=S1->em2[(int)seq[pi]]; + else e=S1->em_func2(H,S1, (int)seq[pi]); + + e=hmm_add (e,max); + + M[s][i]=e; + M[s+H->nS][i]=bestk; + } + } + } + /*Terminate viterbi: connect the path to the END state*/ + max=UNDEFINED; + bestk=UNDEFINED; + for (k=0; k< H->nS; k++) + { + if (k==H->start || k==H->end); + else + { + v=(M[k][l1]==H->forbiden || H->T[k][H->end]==H->forbiden)?H->forbiden:M[k][l1]+H->T[k][H->end]; + if ( max==H->forbiden || v>max){bestk=k;max=v;} + } + } + M[H->end][l1]=max; + M[H->nS+H->end][l1]=bestk; + return M; +} + +int * seq_viterbi2path (char *s, Hmm *H, double **M) +{ + int i,l,l1; + int *path; + HmmState *S1; + int cs; + + l1=strlen (s); + path=vcalloc (l1+1, sizeof (int)); + i=l1; + l=0; + cs=M[H->nS+H->end][i]; + + while (i>0) + { + + S1=H->S[cs]; + path[l++]=cs; + + cs=M[H->nS+cs][i]; + i-=S1->DI; + /*fprintf ( stderr, "%d", cs);*/ + } + invert_list_int (path, l); + path[l++]=H->forbiden; + + return path; +} + +/*********************************************************************************/ +/* */ +/* */ +/* pairHMM: Viterbi */ +/* */ +/* */ +/*********************************************************************************/ +Hmm* define_mnm_model(Constraint_list *CL); +int viterbi_pair_wise_OLD (Alignment *A,int*ns, int **ls,Constraint_list *CL) +{ + int l1, l2, a; + double ***M; + int *path; + Hmm * H; + + A->pos=aln2pos_simple( A, -1, ns, ls); + + // H=define_mnm_model (CL); + H=define_two_mat_model (CL); + + l1=strlen (A->seq_al[ls[0][0]]); + l2=strlen (A->seq_al[ls[1][0]]); + M=viterbi_hmm (A, ns, ls, H, CL); + path=viterbi2path (l1,l2, H,M); + A=viterbipath2aln (A,ns,ls,path, H); + A->score=A->score_aln=M[H->end][l1][l2]; + for ( a=0; a< H->nS*2; a++)free_double (M[a], -1); + vfree (M); + free_int (A->pos, -1); + A->pos=NULL; + + free_Hmm (H); + vfree (path); + + return A->score_aln; +} + +Alignment * viterbipath2aln (Alignment *A, int *ns,int **ls,int *tb, Hmm *H) +{ + char **aln; + char *char_buf; + int a, b, c, len, ch; + HmmState *S; + int l[2]; + + len=0;while (tb[len]!=H->forbiden)len++; + + if ( A->declared_len<=len)A=realloc_aln2 ( A,A->max_n_seq,2*len); + aln=A->seq_al; + + char_buf=vcalloc (len+1, sizeof (char)); + l[0]=strlen ( A->seq_al[ls[0][0]]); + l[1]=strlen ( A->seq_al[ls[1][0]]); + + for ( c=0; c< 2; c++) + for ( a=0; a< ns[c]; a++) + { + for (ch=0, b=0; bS[tb[b]]; + if ( (c==0 && S->DI)|| (c==1 && S->DJ) ) + char_buf[b]=aln[ls[c][a]][ch++]; + else + char_buf[b]='-'; + } + char_buf[b]='\0'; + sprintf (aln[ls[c][a]],"%s", char_buf); + if ( l[c]!=ch){fprintf (stderr, "\nERROR: Wrong Size Of Alignmnent (Real %d, Observed %d)[FATAL:%s]",l[c], ch, PROGRAM);} + } + A->len_aln=len; + A->nseq=ns[0]+ns[1]; + + vfree(char_buf); + return A; +} + +double*** viterbi_hmm (Alignment *A,int *ns, int **ls, Hmm *H, Constraint_list *CL) +{ + double ***M; + double e, v, max; + int a, i,pi, bestk,j,pj, s, k, l1, l2; + HmmState *S1, *S2; + + l1=strlen (A->seq_al[ls[0][0]]); + l2=strlen (A->seq_al[ls[1][0]]); + + M=vcalloc (H->nS*2, sizeof (double**)); + for ( a=0; anS*2; a++)M[a]=declare_double (l1+2, l2+2); + + /*Handle the start*/ + + M[H->start][0][0]=0; + for ( i=0; i<=l1; i++) + for ( j=0; j<=l2; j++) + { + for ( s=0; s< H->nS; s++) + { + S1=H->S[s]; + pi=i-S1->DI; + pj=j-S1->DJ; + max=H->forbiden; + bestk=H->forbiden; + if ( pi<0 ||pj<0){M[s][i][j]=H->forbiden;}/*Boundary*/ + else + { + if (pi+pj==0) {max=H->T[H->start][s];bestk=H->start;}/*Start*/ + else + { + for (k=1; k<=H->fromM[S1->state][0]; k++) + { + S2=H->S[H->fromM[s][k]]; + if ( S2->state==H->start || S2->state==H->end)continue; + v=(M[S2->state][pi][pj]==H->forbiden)?H->forbiden:(M[S2->state][pi][pj]+H->T[S2->state][S1->state]); + if ( v!=H->forbiden && (max==H->forbiden || v>max)){max=v;bestk=S2->state;} + } + } + + e=(S1->em==H->forbiden)?S1->em_func (A, A->pos, ns[0], ls[0],i-1, A->pos,ns[1], ls[1], j-1, CL):S1->em; + e=(max==H->forbiden || e==H->forbiden)?H->forbiden:e+max; + + M[s][i][j]=e; + M[s+H->nS][i][j]=bestk; + } + } + } + + /*Terminate viterbi: connect the path to the END state*/ + max=UNDEFINED; + bestk=UNDEFINED; + for (k=0; k< H->nS; k++) + { + if (k==H->start || k==H->end); + else + { + v=(M[k][l1][l2]==H->forbiden || H->T[k][H->end]==H->forbiden)?H->forbiden:M[k][l1][l2]+H->T[k][H->end]; + if ( max==H->forbiden || v>max){bestk=k;max=v;} + } + } + M[H->end][l1][l2]=max; + M[H->nS+H->end][l1][l2]=bestk; + + return M; +} + +/*********************************************************************************/ +/* */ +/* */ +/* HMM: Decode/Traceback */ +/* */ +/* */ +/*********************************************************************************/ +int * traceback (Alignment *A,int *ns, int **ls, Hmm *H, Constraint_list *CL,MatState *S, MatState *E, int **seg_list) + +{ + int *path; + int l=0; + MatState *N; + int l1, l2; + + l1=strlen (A->seq_al[ls[0][0]]); + l2=strlen (A->seq_al[ls[1][0]]); + path=vcalloc ( l1+l2+1, sizeof (int)); + + while ( S->st!=H->end) + { + DisplayMatState (S, "\n\tTraceback"); + N=S->n; + if ( N && S && (((N->i-S->i)>1) ||((N->j-S->j)>1))) + { + RviterbiD_hmm (A,ns,ls,H,CL,S,N,seg_list); + N=S->n; + } + + path[l++]=S->st; + ManageMatState (FREE,S); + S=N; + } + + path[l]=H->forbiden; + return path; +} + +int * viterbi2path (int l1,int l2, Hmm *H, double ***M) +{ + int i, j,l; + int *path; + HmmState *S1; + int cs; + + l=0; + path=vcalloc (l1+l2+1, sizeof (int)); + i=l1;j=l2; + l=0; + cs=M[H->nS+H->end][i][j]; + + while (i>0|| j>0) + { + + S1=H->S[cs]; + path[l++]=cs; + + cs=M[H->nS+cs][i][j]; + i-=S1->DI; + j-=S1->DJ; + /*fprintf ( stderr, "%d", cs);*/ + } + invert_list_int (path, l); + path[l++]=H->forbiden; + + return path; +} + +/*********************************************************************************/ +/* */ +/* */ +/* HMM Viterbi Linear */ +/* */ +/* */ +/*********************************************************************************/ + + +int viterbiL_pair_wise (Alignment *A,int*ns, int **ls,Constraint_list *CL) +{ + int l1, l2; + int *path; + Hmm * H; + MatState *Start; + MatState *End; + + A->pos=aln2pos_simple( A, -1, ns, ls); + Start=ManageMatState ( DECLARE, NULL); + End=ManageMatState ( DECLARE, NULL); + H=define_simple_model (CL); + l1=strlen (A->seq_al[ls[0][0]]); + l2=strlen (A->seq_al[ls[1][0]]); + + + + Start->i=0 ;Start->j=0 ; Start->st=H->start;Start->sc=0; + End->i =l1; End->j=l2; End ->st=H->end; + Start=RviterbiL_hmm (A, ns, ls, H, CL, Start,End); + path=traceback (A, ns, ls, H, CL, Start,NULL, NULL); + + A=viterbipath2aln (A,ns,ls,path, H); + + free_Hmm (H); + free_int (A->pos, -1); + A->pos=NULL; + + return A->score_aln; +} + + +MatState* RviterbiL_hmm (Alignment *A,int *ns, int **ls, Hmm *H, Constraint_list *CL,MatState *S, MatState *E) +{ + MatState *MS, *ME; + MS=S; + ME=E; + + viterbiL_hmm (A,ns, ls,H, CL, S, E); + + + if ( S->n==E)return S; + if ( E->sc==H->forbiden) + { + DisplayHmm (H); + fprintf ( stderr, "\nERROR: The Requested Model (Cf Above) Cannot Produce the Pair-Alignment\nYou must allow extra possible transitions\n[FATAL:%s]", PROGRAM); + myexit ( EXIT_FAILURE); + } + E=S->n; + + while (S!=ME) + { + int d1, d2, align; + d1=MinDeltaMatState(S,E); + d2=MaxDeltaMatState(S,E); + align=((d1==1 && d2==1) || ( d1==0))?0:1; + if (align)RviterbiL_hmm (A,ns, ls,H, CL,S,E); + S=E; + E=S->n; + } + return MS; +} + +#define Dim(i,j) (i*LenJ+j) +MatState* viterbiL_hmm (Alignment *A,int *ns, int **ls, Hmm *H, Constraint_list *CL, MatState *S,MatState *E) +{ + int current, previous,row, prow; + double v; + int a,i,j,pi,pj, s, k; + int start_i, start_j, end_i, end_j, l1, l2; + HmmState *S1, *S2; + MatState *CC, *PCC,*tS, *tE, *mark=NULL; + int midpoint; + + + static MatState ***M; + + + static int LenJ, LenI; + int MaxDelta=50, DeltaI, DeltaJ; + + + + DisplayMatState (S, "\n\tS"); + DisplayMatState (E, "\n\tE"); + + + if ( A==NULL) + { + for ( a=0; a<2; a++)memset(M[a],0,LenJ*LenI*sizeof (MatState*)); + free_arrayN((void **)M, 3);M=NULL; + ManageMatState ( FREE_ALL, NULL); + return NULL; + } + + + if ( MatStateAreIdentical ( S, E))return NULL; + l1=strlen (A->seq_al[ls[0][0]]);l2=strlen (A->seq_al[ls[1][0]]); + + midpoint=S->i+((E->i-S->i)/2); + DeltaI=E->i-S->i; + DeltaJ=E->j-S->j; + + start_i=S->i;end_i=E->i;start_j=S->j;end_j=E->j; + current=0;previous=1; + + + if ( !M) + { + LenI=l2+1; + LenJ=H->nS; + M=declare_arrayN(3, sizeof ( MatState),2,LenI*LenJ,0); + } + + + /*MAKE THE VITERBI FROM S(tart) to E(nd)*/ + mark=ManageMatState ( MARK, mark); + for (i=start_i; i<=end_i; i++) + { + row=current; + for ( j=start_j; j<=end_j; j++) + { + DeltaJ=((FABS(j-i))nS-1;s>=0; s--) + { + S1=H->S[s];pi=i-S1->DI;prow=S1->DI;pj=j-S1->DJ; + + CC=M[row][Dim(j,s)]=CopyMatState(NULL, M[row][Dim(j,s)]); + CC->i=i; CC->j=j; CC->st=s;PCC=NULL; + + if (i==start_i && j==start_j && s==S->st){CC=CopyMatState(S,CC);} + else if ( i==end_i && j==end_j && E->st!=H->end && s!=E->st)CC->sc=H->forbiden; + else if ( pisc=H->forbiden;} + else + { + for (k=1; k<=H->fromM[S1->state][0]; k++) + { + S2=H->S[H->fromM[s][k]]; + PCC=M[prow][Dim((j-S1->DJ),(S2->state))]; + + if ( !PCC)PCC=NULL; + else if ( pi+pj!=0 && S2->state==H->start); + else if ( !(pi==l1 && pj==l2) && s==H->end); + else + { + + v=hmm_add(CC->sc,H->T[PCC->st][CC->st]); + + v=lu_RviterbiD_hmm(A,ns, ls, H, CL,PCC,CC, NULL); + if ( v!=H->forbiden && (CC->sc==H->forbiden || v> CC->sc)){CC->sc=v; CC->pst=S2->state;CC->p=PCC;} + } + } + } + if (CC->sc==H->forbiden); + else if (i==midpoint || DeltaI<=MaxDelta||DeltaJ<=MaxDelta ||(i==start_i && j==start_j && s==S->st) ) + { + CC->m=(CC->p)?(CC->p)->m:NULL; + PCC=CopyMatState(CC,NULL); + PCC->m=CC->m;CC->m=PCC; + } + else CC->m=(CC->p)?(CC->p)->m:NULL; + } + } + prow=previous; + for ( j=start_j; j<=end_j && i!=end_i; j++) + { + for ( s=H->nS-1;s>=0; s--) + { + + CC=(M[prow][Dim(j,s)]);M[prow][Dim(j,s)]=M[row][Dim(j,s)];M[row][Dim(j,s)]=CC; + if (M[prow][Dim(j,s)]) M[row ][Dim(j,s)]=CopyMatState ( M[prow][Dim(j,s)], M[row][Dim(j,s)]); + + } + } + + } + + mark=ManageMatState ( MARK,mark); + row=current; + + + if ( E->st==H->end || E->st==H->forbiden){E=CopyMatState ((M[row][Dim(end_j,E->st)]),E);} + + + + + PCC=CopyMatState (M[row][Dim(end_j,E->st)], NULL); + + if ( MatStateAreIdentical(PCC,PCC->m))PCC=PCC->m; + tS=tE=PCC; + while (PCC->m) + { + tS=CopyMatState (PCC->m,NULL); tS->n=PCC; PCC->p=tS;PCC=tS; + } + + if (tS==tE); + else + { + S->n=tS->n; (S->n)->p=S; + E->p=tE->p; (E->p)->n=E; + } + for ( a=0; a<2; a++)memset(M[a],0,LenJ*LenI*sizeof (MatState*)); + ManageMatState ( FREE_MARK,mark); + + + while (S && S->p!=E){S->m=NULL;S=S->n;}/*Clean the memory of the rturned Cells*/ + return NULL; +} + +/*********************************************************************************/ +/* */ +/* */ +/* HMM Viterbi Diagonals */ +/* */ +/* */ +/*********************************************************************************/ +int viterbiD_pair_wise (Alignment *A,int*ns, int **ls,Constraint_list *CL) +{ + int l1, l2; + int *path; + Hmm * H; + MatState *Start; + MatState *End; + int **seg_list; + int a, b, c; + int main_i; + int main_j; + + + A->pos=aln2pos_simple( A, -1, ns, ls); + + Start=ManageMatState ( DECLARE, NULL); + End=ManageMatState ( DECLARE, NULL); + H=define_simple_model (CL); + l1=strlen (A->seq_al[ls[0][0]]); + l2=strlen (A->seq_al[ls[1][0]]); + + main_i=MAX(1,(l2-l1)+1); + main_j=MAX(1,(l1-l2)+1); + + seg_list=declare_arrayN(2, sizeof (int), l1+l2+3, 3); + seg_list[0][0]=DIAGONALS; + + + c=1; + for ( b=1,a=l1; a>= 1; a--) + { + if (a<50 || (b==main_i && a==main_j)) + { + seg_list[c][0]=a; + seg_list[c][1]=b; + seg_list[c][2]=MIN((l1-a), (l2-b)); + c++; + } + } + + + for ( b=2,a=1; b<= l2; b++, c++) + { + if (b<50 || (b==main_i && a==main_j)) + { + seg_list[c][0]=a; + seg_list[c][1]=b; + seg_list[c][2]=MIN((l1-a), (l2-b)); + } + } + + + seg_list[c][0]=FORBIDEN; + + Start->i=0 ;Start->j=0 ; Start->st=H->start;Start->sc=0; + End->i =l1; End->j=l2; End ->st=H->end; + Start=RviterbiD_hmm (A, ns, ls, H, CL, Start,End,seg_list); + + + path=traceback (A, ns, ls, H, CL, Start,NULL, NULL); + + + + A=viterbipath2aln (A,ns,ls,path, H); + + viterbiD_hmm (NULL, ns, ls, H, CL, Start,End, seg_list); + free_Hmm (H); + free_int (A->pos, -1); + free_arrayN((void **)seg_list, 2); + + A->pos=NULL; + return A->score_aln; +} + + +double lu_RviterbiD_hmm (Alignment *A,int *ns, int **ls, Hmm *H, Constraint_list *CL,MatState *S, MatState *E, int **seg_list) +{ + HmmState *S1; + double sc, sc2,e, t; + static MatState *cS=NULL, *cE=NULL; + double min, max; + max=MAX((E->i-S->i), (E->j-S->j)); + min=MIN((E->i-S->i), (E->j-S->j)); + + + if ( S->sc==H->forbiden) return H->forbiden; + else if (min==0) + { + e=hmm_add(S->sc,H->T[S->st][E->st]); + if ( H->T[E->st][E->st]!=H->forbiden)e=hmm_add(e, (max-1)*H->T[E->st][E->st]); + if ( (H->S[E->st])->em!=H->forbiden) e=hmm_add(e, max *(H->S[E->st])->em ); + return e; + } + else if ( min>0 && max>1) + { + + fprintf ( stderr, "\nWarning: Disjoined Diagonals"); + DisplayMatState (S, "\n\tS"); + DisplayMatState (E, "\n\tE"); + + + cS=CopyMatState ( S,cS); + cE=CopyMatState ( E,cE); + cE->sc=H->forbiden; + viterbiD_hmm (A,ns,ls, H,CL,cS, cE, NULL); + sc2=cE->sc; + + return sc2; + } + else + { + S1=H->S[E->st]; + t=H->T[S->st][E->st]; + e=(S1->em==H->forbiden)?S1->em_func (A, A->pos, ns[0], ls[0],E->i-1, A->pos,ns[1], ls[1], E->j-1, CL):S1->em; + sc=hmm_add(S->sc,t); + sc=hmm_add(sc,e); + return sc; + } + return H->forbiden; +} + + +MatState* RviterbiD_hmm (Alignment *A,int *ns, int **ls, Hmm *H, Constraint_list *CL,MatState *S, MatState *E, int **seg_list) +{ + MatState *MS, *ME; + MS=S; + ME=E; + + viterbiD_hmm (A,ns, ls,H, CL, S, E, seg_list); + + + if ( S->n==E)return S; + if ( E->sc==H->forbiden) + { + DisplayHmm (H); + fprintf ( stderr, "\nERROR: The Requested Model (Cf Above) Cannot Produce the Pair-Alignment\nYou must allow extra possible transitions\n[FATAL:%s]", PROGRAM); + myexit ( EXIT_FAILURE); + } + E=S->n; + + while (S!=ME) + { + int d1, d2, align; + d1=MinDeltaMatState(S,E); + d2=MaxDeltaMatState(S,E); + align=((d1==1 && d2==1) || ( d1==0))?0:1; + if (align)RviterbiD_hmm (A,ns, ls,H, CL,S,E, seg_list); + S=E; + E=S->n; + } + return MS; +} + +#define Dim(i,j) (i*LenJ+j) +MatState* viterbiD_hmm (Alignment *A,int *ns, int **ls, Hmm *H, Constraint_list *CL, MatState *S,MatState *E, int **seg_list) +{ + int current, previous,row, prow; + double v; + int a,b,i,j,pi,pj, s, k; + int start_i, start_j, end_i, end_j, l1, l2; + HmmState *S1, *S2; + MatState *CC, *PCC,*tS, *tE, *mark=NULL; + int midpoint; + + int dj; + int dc; + int *jlist=NULL; + static int **main_jlist; + static MatState ***M; + static int *toclean; + int ntoclean; + static int LenJ, LenI; + int MaxDelta=50, DeltaI, DeltaJ; + int mode; + + DisplayMatState (S, "\n\tS"); + DisplayMatState (E, "\n\tE"); + + + if ( A==NULL) + { + free_arrayN((void **)main_jlist, 2);main_jlist=NULL; + + for ( a=0; a<2; a++)memset(M[a],0,LenJ*LenI*sizeof (MatState*)); + free_arrayN((void **)M, 3);M=NULL; + vfree (toclean); + ManageMatState ( FREE_ALL, NULL); + return NULL; + } + + + if ( MatStateAreIdentical ( S, E))return NULL; + l1=strlen (A->seq_al[ls[0][0]]);l2=strlen (A->seq_al[ls[1][0]]); + + midpoint=S->i+((E->i-S->i)/2); + DeltaI=E->i-S->i; + + + start_i=S->i;end_i=E->i;start_j=S->j;end_j=E->j; + current=0;previous=1; + + + if ( !M) + { + LenI=l2+1; + LenJ=H->nS; + M=declare_arrayN(3, sizeof ( MatState),2,LenI*LenJ,0); + toclean=vcalloc ( LenI*LenJ, sizeof (int)); + } + + if ( !main_jlist)main_jlist= seglist2table(seg_list, l1, l2); + + + /*MAKE THE VITERBI FROM S(tart) to E(nd)*/ + mark=ManageMatState ( MARK, mark); + mode=(!seg_list)?ALL:seg_list[0][0]; + + for (ntoclean=0,i=start_i; i<=end_i; i++) + { + row=current; + + if ( mode==ALL)jlist=main_jlist[0]; + else if ( mode==DIAGONALS)jlist=(i==0)?main_jlist[0]:main_jlist[1]; + else if ( mode==SEGMENTS) jlist=main_jlist[i+2]; + + + for ( dj=1; dj<=jlist[0]; dj++) + { + DeltaJ=((FABS(dj-i))end_j)continue; + for ( s=H->nS-1;s>=0; s--) + { + S1=H->S[s];pi=i-S1->DI;prow=S1->DI; + + if ( S1->DI && S1->DJ){pj=j-S1->DJ;} + else if ( !S1->DJ)pj=j; + else if ( dj>1)pj=jlist[dj-S1->DJ]+dc; + else pj=-1; + + if (!M[row][Dim(j,s)])toclean[ntoclean]=Dim(j,s); + + CC=M[row][Dim(j,s)]=CopyMatState(NULL, M[row][Dim(j,s)]); + CC->i=i; CC->j=j; CC->st=s;PCC=NULL; + + if (i==start_i && j==start_j && s==S->st){CC=CopyMatState(S,CC);} + else if ( i==end_i && j==end_j && E->st!=H->end && s!=E->st)CC->sc=H->forbiden; + else if ( pisc=H->forbiden;} + else + { + for (k=1; k<=H->fromM[S1->state][0]; k++) + { + S2=H->S[H->fromM[s][k]]; + + if ( S1->DI && S1->DJ)PCC=M[prow][Dim((j-S1->DJ),(S2->state))]; + else PCC=M[prow][Dim((jlist[dj-S1->DJ]+dc),(S2->state))]; + + if ( !PCC)PCC=NULL; + else if ( pi+pj!=0 && S2->state==H->start); + else if ( !(pi==l1 && pj==l2) && s==H->end); + else + { + v=lu_RviterbiD_hmm(A,ns, ls, H, CL,PCC,CC, NULL); + if ( v!=H->forbiden && (CC->sc==H->forbiden || v> CC->sc)){CC->sc=v; CC->pst=S2->state;CC->p=PCC;} + } + } + } + if (CC->sc==H->forbiden); + else if (i==midpoint || DeltaI<=MaxDelta||DeltaJ<=MaxDelta ||(i==start_i && j==start_j && s==S->st) ) + { + CC->m=(CC->p)?(CC->p)->m:NULL; + PCC=CopyMatState(CC,NULL); + PCC->m=CC->m;CC->m=PCC; + } + else CC->m=(CC->p)?(CC->p)->m:NULL; + } + } + prow=previous; + for ( dj=1; dj<=jlist[0] && i!=end_i; dj++) + { + dc=(mode==DIAGONALS && dj!=1)?i:0; + j=jlist[dj]+dc; + if ( jend_j)continue; + + for ( s=H->nS-1;s>=0; s--) + { + + CC=(M[prow][Dim(j,s)]);M[prow][Dim(j,s)]=M[row][Dim(j,s)];M[row][Dim(j,s)]=CC; + if (!M[row][Dim(j,s)])toclean[ntoclean++]=Dim(j,s); + if (M[prow][Dim(j,s)]) M[row ][Dim(j,s)]=CopyMatState ( M[prow][Dim(j,s)], M[row][Dim(j,s)]); + + } + } + + } + + mark=ManageMatState ( MARK,mark); + row=current; + + + if ( E->st==H->end || E->st==H->forbiden){E=CopyMatState ((M[row][Dim(end_j,E->st)]),E);} + + + + + PCC=CopyMatState (M[row][Dim(end_j,E->st)], NULL); + + if ( MatStateAreIdentical(PCC,PCC->m))PCC=PCC->m; + tS=tE=PCC; + while (PCC->m) + { + tS=CopyMatState (PCC->m,NULL); tS->n=PCC; PCC->p=tS;PCC=tS; + } + + if (tS==tE); + else + { + S->n=tS->n; (S->n)->p=S; + E->p=tE->p; (E->p)->n=E; + } + + ManageMatState ( FREE_MARK,mark); + + + for ( a=0; ap!=E){S->m=NULL;S=S->n;}/*Clean the memory of the rturned Cells*/ + return NULL; +} + +/*********************************************************************************/ +/* */ +/* */ +/* HMM Viterbi Diagonals GLOBAL/LOCAL */ +/* */ +/* */ +/*********************************************************************************/ + +int viterbiDGL_pair_wise (Alignment *A,int*ns, int **ls,Constraint_list *CL) +{ + int l1, l2; + int *path; + Hmm * H; + MatState *Start; + MatState *End; + int **seg_list; + int a, b, c; + int main_i; + int main_j; + + + A->pos=aln2pos_simple( A, -1, ns, ls); + + Start=ManageMatState ( DECLARE, NULL); + End=ManageMatState ( DECLARE, NULL); + H=define_simple_model (CL); + l1=strlen (A->seq_al[ls[0][0]]); + l2=strlen (A->seq_al[ls[1][0]]); + + main_i=MAX(1,(l2-l1)+1); + main_j=MAX(1,(l1-l2)+1); + + seg_list=declare_arrayN(2, sizeof (int), l1+l2+3, 3); + seg_list[0][0]=DIAGONALS; + + + c=1; + for ( b=1,a=l1; a>= 1; a--) + { + if (a<50 || (b==main_i && a==main_j)) + { + seg_list[c][0]=a; + seg_list[c][1]=b; + seg_list[c][2]=MIN((l1-a), (l2-b)); + c++; + } + } + + + for ( b=2,a=1; b<= l2; b++, c++) + { + if (b<50 || (b==main_i && a==main_j)) + { + seg_list[c][0]=a; + seg_list[c][1]=b; + seg_list[c][2]=MIN((l1-a), (l2-b)); + } + } + + + seg_list[c][0]=FORBIDEN; + + Start->i=0 ;Start->j=0 ; Start->st=H->start;Start->sc=0; + End->i =l1; End->j=l2; End ->st=H->end; + Start=RviterbiDGL_hmm (A, ns, ls, H, CL, Start,End,seg_list); + + + path=traceback (A, ns, ls, H, CL, Start,NULL, NULL); + + + + A=viterbipath2aln (A,ns,ls,path, H); + + viterbiD_hmm (NULL, ns, ls, H, CL, Start,End, seg_list); + free_Hmm (H); + free_int (A->pos, -1); + free_arrayN((void **)seg_list, 2); + + A->pos=NULL; + return A->score_aln; +} + + +double lu_RviterbiDGL_hmm (Alignment *A,int *ns, int **ls, Hmm *H, Constraint_list *CL,MatState *S, MatState *E, int **seg_list) +{ + HmmState *S1; + double sc, sc2,e, t; + static MatState *cS=NULL, *cE=NULL; + double min, max; + max=MAX((E->i-S->i), (E->j-S->j)); + min=MIN((E->i-S->i), (E->j-S->j)); + + + + + if ( S==NULL || E==NULL || S->sc==H->forbiden) return H->forbiden; + else if ( S->st==H->start) return 0; + else if ( E->st==H->end) return S->sc; + else if (min==0) + { + e=hmm_add(S->sc,H->T[S->st][E->st]); + if ( H->T[E->st][E->st]!=H->forbiden)e=hmm_add(e, (max-1)*H->T[E->st][E->st]); + if ( (H->S[E->st])->em!=H->forbiden) e=hmm_add(e, max *(H->S[E->st])->em ); + return e; + } + else if ( min>0 && max>1) + { + + fprintf ( stderr, "\nWarning: Disjoined Diagonals"); + DisplayMatState (S, "\n\tS"); + DisplayMatState (E, "\n\tE"); + + + cS=CopyMatState ( S,cS); + cE=CopyMatState ( E,cE); + cE->sc=H->forbiden; + viterbiD_hmm (A,ns,ls, H,CL,cS, cE, NULL); + sc2=cE->sc; + + return sc2; + } + else + { + S1=H->S[E->st]; + t=H->T[S->st][E->st]; + e=(S1->em==H->forbiden)?S1->em_func (A, A->pos, ns[0], ls[0],E->i-1, A->pos,ns[1], ls[1], E->j-1, CL):S1->em; + sc=hmm_add(S->sc,t); + sc=hmm_add(sc,e); + return sc; + } + return H->forbiden; +} + + +MatState* RviterbiDGL_hmm (Alignment *A,int *ns, int **ls, Hmm *H, Constraint_list *CL,MatState *S, MatState *E, int **seg_list) +{ + MatState *MS, *ME; + MS=S; + ME=E; + + viterbiDGL_hmm (A,ns, ls,H, CL, S, E, seg_list); + + + if ( S->n==E)return S; + if ( E->sc==H->forbiden) + { + DisplayHmm (H); + fprintf ( stderr, "\nERROR: The Requested Model (Cf Above) Cannot Produce the Pair-Alignment\nYou must allow extra possible transitions\n[FATAL:%s]", PROGRAM); + myexit ( EXIT_FAILURE); + } + E=S->n; + + while (S!=ME) + { + int d1, d2, align; + d1=MinDeltaMatState(S,E); + d2=MaxDeltaMatState(S,E); + align=((d1==1 && d2==1) || ( d1==0))?0:1; + if (align)RviterbiDGL_hmm (A,ns, ls,H, CL,S,E, seg_list); + S=E; + E=S->n; + } + return MS; +} + + +#define Dim(i,j) (i*LenJ+j) +MatState* viterbiDGL_hmm (Alignment *A,int *ns, int **ls, Hmm *H, Constraint_list *CL, MatState *S,MatState *E, int **seg_list) +{ + int current, previous,row, prow; + double v; + int a,i,j,pi,pj, s, k; + int start_i, start_j, end_i, end_j, l1, l2; + HmmState *S1, *S2; + MatState *CC, *PCC,*tS, *tE,*bestE,*bestS, *mark=NULL; + int midpoint; + + int dj; + int dc; + int *jlist=NULL; + static int **main_jlist; + static MatState ***M; + static int *toclean; + int ntoclean; + static int LenJ, LenI; + int MaxDelta=50, DeltaI, DeltaJ; + int mode; + + + + DisplayMatState (S, "\n\tS"); + DisplayMatState (E, "\n\tE"); + + + if ( A==NULL) + { + free_arrayN((void **)main_jlist, 2);main_jlist=NULL; + + for ( a=0; a<2; a++)memset(M[a],0,LenJ*LenI*sizeof (MatState*)); + free_arrayN((void **)M, 3);M=NULL; + vfree (toclean); + ManageMatState ( FREE_ALL, NULL); + return NULL; + } + + + if ( MatStateAreIdentical ( S, E))return NULL; + l1=strlen (A->seq_al[ls[0][0]]);l2=strlen (A->seq_al[ls[1][0]]); + + midpoint=S->i+((E->i-S->i)/2); + DeltaI=E->i-S->i; + + + start_i=S->i;end_i=E->i;start_j=S->j;end_j=E->j; + current=0;previous=1; + + + if ( !M) + { + LenI=l2+1; + LenJ=H->nS; + M=declare_arrayN(3, sizeof ( MatState),2,LenI*LenJ,0); + toclean=vcalloc ( LenI*LenJ, sizeof (int)); + } + + if ( !main_jlist)main_jlist= seglist2table(seg_list, l1, l2); + + + /*MAKE THE VITERBI FROM S(tart) to E(nd)*/ + mark=ManageMatState ( MARK, mark); + mode=(!seg_list)?ALL:seg_list[0][0]; + bestE=CopyMatState (E, NULL); + bestS=CopyMatState (NULL, NULL); + for (ntoclean=0,i=start_i; i<=end_i; i++) + { + row=current; + + if ( mode==ALL)jlist=main_jlist[0]; + else if ( mode==DIAGONALS)jlist=(i==0)?main_jlist[0]:main_jlist[1]; + else if ( mode==SEGMENTS) jlist=main_jlist[i+2]; + + + for ( dj=1; dj<=jlist[0]; dj++) + { + DeltaJ=(FABS(dj-i)end_j)continue; + for ( s=H->nS-1;s>=0; s--) + { + if ( s==S->st)continue; + S1=H->S[s];pi=i-S1->DI;prow=S1->DI; + + if ( S1->DI && S1->DJ){pj=j-S1->DJ;} + else if ( !S1->DJ)pj=j; + else if ( dj>1)pj=jlist[dj-S1->DJ]+dc; + else pj=-1; + + if (!M[row][Dim(j,s)])toclean[ntoclean]=Dim(j,s); + + CC=M[row][Dim(j,s)]=CopyMatState(NULL, M[row][Dim(j,s)]); + CC->i=i; CC->j=j; CC->st=s;PCC=NULL; + + if (i==start_i && j==start_j && s==S->st){CC=CopyMatState(S,CC);} + else if ( s==S->st); + else if ( i==end_i && j==end_j && E->st!=H->end && s!=E->st)CC->sc=H->forbiden; + + else if ( pisc=H->forbiden;} + else + { + for (k=1; k<=H->fromM[S1->state][0]; k++) + { + S2=H->S[H->fromM[s][k]]; + + if ( S1->DI && S1->DJ)PCC=M[prow][Dim((j-S1->DJ),(S2->state))]; + else PCC=M[prow][Dim((jlist[dj-S1->DJ]+dc),(S2->state))]; + + if ( S2->state==H->start){PCC=bestS;PCC->st=0;PCC->sc=0;PCC->m=PCC->n=PCC->p=NULL;} + + v=lu_RviterbiDGL_hmm(A,ns, ls, H, CL,PCC,CC, NULL); + if ( v!=H->forbiden && (CC->sc==H->forbiden || v> CC->sc)){CC->sc=v; CC->pst=S2->state;CC->p=PCC;} + } + } + if ( CC->sc==H->forbiden); + else if ( bestE->sc==H->forbiden || bestE->sc>CC->sc) + { + bestE=CopyMatState(CC, bestE); + bestE->m=(CC->p)->m; + } + else if (CC->p && (CC->p)->st==H->start) + { + CC->m=CopyMatState (CC->p, NULL); + } + else if (i==midpoint || DeltaI<=MaxDelta||DeltaJ<=MaxDelta ||(i==start_i && j==start_j && s==S->st) ) + { + CC->m=(CC->p)?(CC->p)->m:NULL; + PCC=CopyMatState(CC,NULL); + PCC->m=CC->m;CC->m=PCC; + } + else CC->m=(CC->p)?(CC->p)->m:NULL; + } + } + prow=previous; + for ( dj=1; dj<=jlist[0] && i!=end_i; dj++) + { + dc=(mode==DIAGONALS && dj!=1)?i:0; + j=jlist[dj]+dc; + if ( jend_j)continue; + + for ( s=H->nS-1;s>=0; s--) + { + + CC=(M[prow][Dim(j,s)]);M[prow][Dim(j,s)]=M[row][Dim(j,s)];M[row][Dim(j,s)]=CC; + /*if (!M[row][Dim(j,s)])toclean[ntoclean++]=Dim(j,s);*/ + if (M[prow][Dim(j,s)]) M[row ][Dim(j,s)]=CopyMatState ( M[prow][Dim(j,s)], M[row][Dim(j,s)]); + + } + } + + } + + mark=ManageMatState ( MARK,mark); + row=current; + + + if ( E->st==H->end || E->st==H->forbiden){E=CopyMatState ((M[row][Dim(end_j,E->st)]),E);} + PCC=CopyMatState (bestE, NULL); + + if ( MatStateAreIdentical(PCC,PCC->m))PCC=PCC->m; + tS=tE=PCC; + while (PCC->m) + { + tS=CopyMatState (PCC->m,NULL); tS->n=PCC; PCC->p=tS;PCC=tS; + } + + if (tS==tE); + else + { + CopyMatState ( tS, S); + CopyMatState ( tE, E); + } + ManageMatState ( FREE_MARK,mark); + + for ( a=0; a<2; a++)memset(M[a],0,LenJ*LenI*sizeof (MatState*)); + + while (S && S->p!=E){S->m=NULL;S=S->n;}/*Clean the memory of the rturned Cells*/ + return NULL; +} + + +/*********************************************************************************/ +/* */ +/* */ +/* HMM Viterbi Diagonals PROCESSING */ +/* */ +/* */ +/*********************************************************************************/ +int **seglist2table ( int **seglist,int l1, int l2) + { + int **valuesT; + int *bvalues; + int line, a,si, sj, ei, j, c; + + /*All: 0*/ + valuesT=vcalloc ((l1+2)+3, sizeof (int*)); + valuesT[0]=vcalloc (l2+2, sizeof (int)); + for (a=0; a<=l2; a++)valuesT[0][++valuesT[0][0]]=a; + + if ( !seglist) return valuesT; + /*Diagonals: 1*/ + valuesT[1]=vcalloc (l1+l2+2, sizeof (int)); + bvalues=vcalloc (l1+l2+2, sizeof (int)); + c=1; + while (seglist[c][0]!=FORBIDEN) + { + + si=seglist[c][0]; + sj=seglist[c][1]; + + bvalues[(sj-si)+l1]=1; + c++; + } + valuesT[1][++valuesT[1][0]]=0; + for (a=0; a<=(l1+l2); a++) + { + if (bvalues[a]) + { + valuesT[1][++valuesT[1][0]]=a-l1; + } + + } + vfree (bvalues); + + /*Segments: 2*/ + valuesT[2]=vcalloc (l2+2, sizeof (int)); + for (a=0; a<=l2; a++)valuesT[2][++valuesT[2][0]]=a; + + bvalues=vcalloc (l2+2, sizeof (int)); + for ( line=1; line<=l1; line++) + { + bvalues[0]=c=0; + bvalues[++bvalues[0]]=0; + while (seglist[c][0]!=FORBIDEN) + { + si=seglist[c][0]; + ei=si+seglist[c][2]; + sj=seglist[c][1]; + j=sj+(line-si); + if ( lineei); + else if (j>=0 && j<=l2 && seglist[c][2]) + { + bvalues[++bvalues[0]]=j; + } + c++; + } + valuesT[line+2]=vcalloc (bvalues[0]+1, sizeof (int)); + for ( a=0; a<=bvalues[0]; a++) valuesT[line+2][a]=bvalues[a]; + } + vfree (bvalues); + return valuesT; + } + + + +/*********************************************************************************/ +/* */ +/* */ +/* HMM modeling */ +/* */ +/* */ +/*********************************************************************************/ + +Hmm* declare_hmm(int n) + { + Hmm *H; + int a, b; + + H=vcalloc (1, sizeof (Hmm)); + H->nS=n; + H->S=vcalloc (H->nS, sizeof (HmmState*)); + for (a=0; anS; a++) + { + H->S[a]=vcalloc (1, sizeof (HmmState)); + (H->S[a])->em2=vcalloc (MAX_EMISSION, sizeof (double)); + + (H->S[a])->T=vcalloc ( H->nS, sizeof (StateTrans*)); + for ( b=0; b< H->nS; b++) + (H->S[a])->T[b]=vcalloc (1, sizeof (StateTrans)); + } + return H; + } + +Hmm* free_Hmm(Hmm*H) + { + int a, b; + + H=vcalloc (1, sizeof (Hmm)); + free_double (H->T, -1); + free_int ( H->fromM, -1); + free_int ( H->toM, -1); + + for (a=0; a< H->nS; a++) + { + + for ( b=0; b< H->nS; b++) + { + vfree ((H->S[a])->em2); + vfree((H->S[a])->T[b]); + } + vfree((H->S[a])->T); + vfree(H->S[a]); + } + vfree (H->S); + vfree (H); + return NULL; + } + +void DisplayHmm ( Hmm *H) +{ + int a, b; + HmmState *S1, *S2; + + for ( a=0; a< H->nS; a++) + { + S1=H->S[a]; + fprintf ( stderr, "\nSTATE %d: %s\n",S1->state,S1->name); + fprintf ( stderr, "\n\tDI %d", S1->DI); + fprintf ( stderr, "\n\tDJ %d", S1->DJ); + fprintf ( stderr, "\n\tE %f", (float)S1->em); + + fprintf ( stderr, "\nReached FROM: "); + for ( b=1; b<=H->fromM[a][0]; b++) + { + S2=H->S[H->fromM[a][b]]; + fprintf ( stderr, "[ %s %f ] ", S2->name, H->T[S2->state][S1->state]); + } + fprintf ( stderr, "\nGoes TO: "); + for ( b=1; b<=H->toM[a][0]; b++) + { + S2=H->S[H->toM[a][b]]; + fprintf ( stderr, "[ %s %f ] ", S2->name, H->T[S1->state][S2->state]); + } + } + return; +} +Hmm * bound_hmm ( Hmm *H) +{ + int a, b, c; + char **name; + HmmState *S; + + name=declare_char(H->nS, 100); + H->T=declare_double ( H->nS, H->nS); + + for ( a=0; a< H->nS; a++) + { + sprintf ( name[a], "%s", (H->S[a])->name); + H->order=MAX(H->order, (H->S[a])->DI); + H->order=MAX(H->order, (H->S[a])->DJ); + } + + for ( a=0; a< H->nS; a++)for (b=0; bnS; b++)H->T[a][b]=H->forbiden; + for (a=0; a< H->nS; a++) + { + S=H->S[a]; + for ( b=0; b< S->nT; b++) + { + c=name_is_in_list ((S->T[b])->name, name, H->nS, 100); + if ( c!=-1)H->T[a][c]=(S->T[b])->tr; + } + } + + /*Bound the model: + bM[state][0]=n_allowed transitions + bM[state][1]=first allowed transition + */ + + H->toM=declare_int ( H->nS, H->nS); + H->fromM=declare_int ( H->nS, H->nS); + + for ( a=0; a< H->nS; a++) + for ( b=0; b< H->nS; b++) + { + if ( H->T[a][b]!=H->forbiden ) + { + {H->fromM[b][0]++; H->fromM[b][H->fromM[b][0]]=a;} + {H->toM[a][0]++; H->toM[a][H->toM[a][0]]=b;} + } + } + for ( a=0; a< H->nS; a++) + { + if (( H->S[a])->em!=H->forbiden)( H->S[a])->em*=SCORE_K; + for ( b=0; b< H->nS; b++) + if ( H->T[a][b]!=H->forbiden)H->T[a][b]*=SCORE_K; + } + free_arrayN((void**)name, 2); + return H; +} + +/*********************************************************************************/ +/* */ +/* */ +/* Memory Management */ +/* */ +/* */ +/*********************************************************************************/ + +MatState * ManageMatState(int Mode, MatState *C) +{ + static MatState *Fheap; + static MatState *Aheap; + MatState *Cmark, *Pmark; + static int alloc, free; + if (!Fheap || Fheap->Hp==NULL) + { + int c=0; + int extension=1000; + if (!Fheap){Fheap=vcalloc (1, sizeof (MatState));Fheap->free=1;free++;} + if (!Aheap)Aheap=vcalloc (1, sizeof (MatState)); + while ( c!=extension) + { + C=vcalloc ( 1, sizeof (MatState)); + C->free=1;Fheap->Hn=C;C->Hp=Fheap; + Fheap=C; + c++; + free++; + } + } + + if ( Mode==DECLARE) + { + + C=Fheap; + Fheap=Fheap->Hp; + C->Hn=C->Hp=NULL; + if ( Aheap){Aheap->Hn=C;C->Hp=Aheap;Aheap=C;} + else Aheap=C; + alloc++; + free--; + C->free=0; + C=CopyMatState(NULL, C); + return C; + } + else if ( Mode==FREE) + { + if ( !C || C->free==1); + else + { + C=CopyMatState(NULL, C); + C->free=1; + if (C->Hp==NULL && C==Aheap)crash (""); + if (C==Aheap)Aheap=C->Hp; + if (C->Hn){(C->Hn)->Hp=C->Hp;} + if (C->Hp){(C->Hp)->Hn=C->Hn;} + C->Hp=C->Hn=NULL; + Fheap->Hn=C;C->Hp=Fheap; + Fheap=C; + alloc--; + free++; + } + return NULL; + } + else if ( Mode==FREE_ALL) + { + while ( Aheap) + { + C=Aheap->Hp; + vfree (Aheap); + Aheap=C; + } + while ( Fheap) + { + C=Fheap->Hp; + vfree (Fheap); + Fheap=C; + } + } + else if ( Mode==INFO) + { + fprintf ( stderr, "\nAllocated: %d Free %d", alloc, free); + } + else if ( Mode==MARK) + { + + if (C==NULL); + else {C->Mn=Aheap;Aheap->Mp=C;} + + return Aheap; + } + else if ( Mode==UNMARK) + { + Pmark=Cmark=NULL; + } + else if ( Mode == FREE_MARK) + { + Cmark=C; + Pmark=C->Mp; + + if ( Cmark==Pmark)return NULL; + else if ( Cmark==Aheap) + {Aheap=Pmark;C=Pmark->Hn;Pmark->Hn=NULL;} + else + { + (Cmark->Hn)->Hp=Pmark; + C=Pmark->Hn; + Pmark->Hn=Cmark->Hn; + } + + Fheap->Hn=C; + C->Hp=Fheap; + Fheap=Cmark; + Fheap->Hn=NULL; + + C=Fheap; + while (C && !C->free) + { + free++;alloc--; + C->free=1; + C=C->Hp; + } + + } + return NULL; +} + + +MatState* CopyMatState ( MatState*I, MatState*O) +{ + if (O==NULL || O->free==1) O=ManageMatState(DECLARE, NULL); + if (I==NULL || I->free==1)I=NULL; + O->i =(I)?I->i:0; + O->j =(I)?I->j:0; + O->st =(I)?I->st:FORBIDEN; + O->pst=(I)?I->pst:FORBIDEN; + O->sc =(I)?I->sc:FORBIDEN; + O->n =(I)?I->n:NULL; + O->p =(I)?I->p:NULL; + O->m =(I)?I->m:NULL; + O->s =(I)?I->m:NULL; + + return O; +} + +/*********************************************************************************/ +/* */ +/* */ +/* Comparisons */ +/* */ +/* */ +/*********************************************************************************/ +int MaxDeltaMatState (MatState*S, MatState*E) +{ + if ( !S || !E) return -1; + else return MAX((E->i-S->i),(E->j-S->j)); +} +int MinDeltaMatState (MatState*S, MatState*E) +{ + if ( !S || !E) return -1; + else return MIN((E->i-S->i),(E->j-S->j)); +} +int MatStateAreIdentical (MatState*I, MatState*O) +{ + if ( !I || !O)return 0; + + if ( I->i!=O->i)return 0; + if ( I->j!=O->j)return 0; + if ( I->st!=O->st)return 0; + return 1; +} + + + +Hmm* define_probcons_model(Constraint_list *CL) +{ + Hmm *H; + double gop=-10; + double gep=-1; + double lgop=-100; + double lgep=-100; + double freeT=0; + int n=0; + HmmState *S; + + + H=declare_hmm(7); + H->freeT=freeT=0; + + H->forbiden=FORBIDEN; + H->start=START_STATE; + H->end=END_STATE; + + /*define START*/ + S=H->S[n]; + sprintf (S->name, "START"); S->state=n; + + S->DI=0; + S->DJ=0; + S->em=freeT; + + sprintf ( (S->T[S->nT])->name, "MATCH") ;(S->T[S->nT])->tr=freeT ;S->nT++; + sprintf ( (S->T[S->nT])->name, "INSERT");(S->T[S->nT])->tr=freeT ;S->nT++; + sprintf ( (S->T[S->nT])->name, "DELETE");(S->T[S->nT])->tr=freeT ;S->nT++; + sprintf ( (S->T[S->nT])->name, "END") ;(S->T[S->nT])->tr=freeT ;S->nT++; + + n++; + /*define END*/ + S=H->S[n]; + sprintf (S->name, "END"); S->state=n; + S->DI=0; + S->DJ=0; + S->em=freeT; + n++; + + /*define Match*/ + S=H->S[n]; + sprintf (S->name, "MATCH"); S->state=n; + S->DI=1; + S->DJ=1; + S->em=H->forbiden; + S->em_func=CL->get_dp_cost; + + sprintf ( (S->T[S->nT])->name, "MATCH") ;(S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "INSERT");(S->T[S->nT])->tr=gop ;S->nT++; + sprintf ( (S->T[S->nT])->name, "DELETE");(S->T[S->nT])->tr=gop ;S->nT++; + sprintf ( (S->T[S->nT])->name, "END"); (S->T[S->nT])->tr=freeT;S->nT++; + + n++; + + /*define Insert*/ + S=H->S[n]; + sprintf (S->name, "INSERT"); S->state=n; + S->DI=1; + S->DJ=0; + S->em=gep; + sprintf ( (S->T[S->nT])->name, "MATCH") ; (S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "INSERT"); (S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "LINSERT");(S->T[S->nT])->tr=lgop ;S->nT++; + sprintf ( (S->T[S->nT])->name, "END"); (S->T[S->nT])->tr=-gop;S->nT++; + + n++; + + /*define LInsert*/ + S=H->S[n]; + sprintf (S->name, "LINSERT"); S->state=n; + S->DI=1; + S->DJ=0; + S->em=lgep; + + sprintf ( (S->T[S->nT])->name, "INSERT") ;(S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "LINSERT");(S->T[S->nT])->tr=freeT;S->nT++; + + n++; + + + /*define Delete*/ + S=H->S[n]; + sprintf (S->name, "DELETE"); S->state=n; + S->DI=0; + S->DJ=1; + S->em=gep; + + sprintf ( (S->T[S->nT])->name, "MATCH") ;(S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "DELETE") ;(S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "LDELETE") ;(S->T[S->nT])->tr=lgop ;S->nT++; + sprintf ( (S->T[S->nT])->name, "END") ;(S->T[S->nT])->tr=-gop;S->nT++; + + n++; + + /*define LDelete*/ + S=H->S[n]; + sprintf (S->name, "LDELETE"); S->state=n; + S->DI=0; + S->DJ=1; + S->em=lgep; + sprintf ( (S->T[S->nT])->name, "DELETE") ;(S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "LDELETE");(S->T[S->nT])->tr=freeT;S->nT++; + + n++; + + + H=bound_hmm ( H); + return H; +} + +Hmm* define_mnm_model(Constraint_list *CL) +{ + Hmm *H; + double gop=20; + + + + double freeT=0; + int n=0; + HmmState *S; + + + H=declare_hmm(6); + H->freeT=freeT=0; + + H->forbiden=FORBIDEN; + H->start=START_STATE; + H->end=END_STATE; + + /*define START*/ + S=H->S[n]; + sprintf (S->name, "START"); S->state=n; + + S->DI=0; + S->DJ=0; + S->em=freeT; + + sprintf ( (S->T[S->nT])->name, "MATCH") ;(S->T[S->nT])->tr=freeT ;S->nT++; + sprintf ( (S->T[S->nT])->name, "INSERT");(S->T[S->nT])->tr=freeT ;S->nT++; + sprintf ( (S->T[S->nT])->name, "DELETE");(S->T[S->nT])->tr=freeT ;S->nT++; + sprintf ( (S->T[S->nT])->name, "NOMATCH");(S->T[S->nT])->tr=freeT ;S->nT++; + sprintf ( (S->T[S->nT])->name, "END") ;(S->T[S->nT])->tr=freeT ;S->nT++; + + n++; + /*define END*/ + S=H->S[n]; + sprintf (S->name, "END"); S->state=n; + S->DI=0; + S->DJ=0; + S->em=freeT; + n++; + + /*define Match*/ + S=H->S[n]; + sprintf (S->name, "MATCH"); S->state=n; + S->DI=1; + S->DJ=1; + S->em=H->forbiden; + S->em_func=CL->get_dp_cost; + + sprintf ( (S->T[S->nT])->name, "MATCH") ;(S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "NOMATCH");(S->T[S->nT])->tr=gop ;S->nT++; + sprintf ( (S->T[S->nT])->name, "END"); (S->T[S->nT])->tr=freeT;S->nT++; + + n++; + + /*define NOMatch*/ + S=H->S[n]; + sprintf (S->name, "NOMATCH"); S->state=n; + S->DI=1; + S->DJ=1; + S->em=freeT; + S->em_func=NULL; + + sprintf ( (S->T[S->nT])->name, "NOMATCH") ;(S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "MATCH") ;(S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "INSERT");(S->T[S->nT])->tr=freeT ;S->nT++; + sprintf ( (S->T[S->nT])->name, "DELETE");(S->T[S->nT])->tr=freeT ;S->nT++; + sprintf ( (S->T[S->nT])->name, "END"); (S->T[S->nT])->tr=freeT;S->nT++; + + n++; + /*define Insert*/ + S=H->S[n]; + sprintf (S->name, "INSERT"); S->state=n; + S->DI=1; + S->DJ=0; + S->em=freeT; + sprintf ( (S->T[S->nT])->name, "NOMATCH") ; (S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "INSERT") ; (S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "END"); (S->T[S->nT])->tr=freeT;S->nT++; + + n++; + + /*define Delete*/ + S=H->S[n]; + sprintf (S->name, "DELETE"); S->state=n; + S->DI=0; + S->DJ=1; + S->em=freeT; + + sprintf ( (S->T[S->nT])->name, "NOMATCH") ;(S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "DELETE") ;(S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "END") ;(S->T[S->nT])->tr=freeT;S->nT++; + + n++; + + + H=bound_hmm ( H); + return H; +} + +Hmm* define_simple_model(Constraint_list *CL) +{ + Hmm *H; + double gop=-10; + double gep=-1; + double freeT=0; + int n=0; + HmmState *S; + + + H=declare_hmm(5); + H->freeT=freeT=0; + + H->forbiden=FORBIDEN; + H->start=START_STATE; + H->end=END_STATE; + + /*define START*/ + S=H->S[n]; + sprintf (S->name, "START"); S->state=n; + + S->DI=0; + S->DJ=0; + S->em=freeT; + + sprintf ( (S->T[S->nT])->name, "MATCH") ;(S->T[S->nT])->tr=freeT ;S->nT++; + sprintf ( (S->T[S->nT])->name, "INSERT");(S->T[S->nT])->tr=freeT ;S->nT++; + sprintf ( (S->T[S->nT])->name, "DELETE");(S->T[S->nT])->tr=freeT ;S->nT++; + sprintf ( (S->T[S->nT])->name, "END") ;(S->T[S->nT])->tr=freeT ;S->nT++; + + n++; + /*define END*/ + S=H->S[n]; + sprintf (S->name, "END"); S->state=n; + S->DI=0; + S->DJ=0; + S->em=freeT; + n++; + + /*define Match*/ + S=H->S[n]; + sprintf (S->name, "MATCH"); S->state=n; + S->DI=1; + S->DJ=1; + S->em=H->forbiden; + S->em_func=CL->get_dp_cost; + + sprintf ( (S->T[S->nT])->name, "MATCH") ;(S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "INSERT");(S->T[S->nT])->tr=gop ;S->nT++; + sprintf ( (S->T[S->nT])->name, "DELETE");(S->T[S->nT])->tr=gop ;S->nT++; + sprintf ( (S->T[S->nT])->name, "END"); (S->T[S->nT])->tr=freeT;S->nT++; + + n++; + + /*define Insert*/ + S=H->S[n]; + sprintf (S->name, "INSERT"); S->state=n; + S->DI=1; + S->DJ=0; + S->em=gep; + sprintf ( (S->T[S->nT])->name, "MATCH") ; (S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "INSERT"); (S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "DELETE"); (S->T[S->nT])->tr=freeT;S->nT++; + + sprintf ( (S->T[S->nT])->name, "END"); (S->T[S->nT])->tr=-gop;S->nT++; + + n++; + + + /*define Delete*/ + S=H->S[n]; + sprintf (S->name, "DELETE"); S->state=n; + S->DI=0; + S->DJ=1; + S->em=gep; + + sprintf ( (S->T[S->nT])->name, "MATCH") ;(S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "DELETE") ;(S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "INSERT"); (S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "END") ;(S->T[S->nT])->tr=-gop;S->nT++; + + n++; + + H=bound_hmm ( H); + return H; +} + +Hmm* define_two_mat_model(Constraint_list *CL) +{ + Hmm *H; + double gop=-15; + double gep=-2; + double lgop=-6; + double lgep=-1; + double freeT=0; + int n=0; + HmmState *S; + + + H=declare_hmm(8); + H->freeT=freeT=0; + + H->forbiden=FORBIDEN; + H->start=START_STATE; + H->end=END_STATE; + + /*define START*/ + S=H->S[n]; + sprintf (S->name, "START"); S->state=n; + + S->DI=0; + S->DJ=0; + S->em=freeT; + + sprintf ( (S->T[S->nT])->name, "MATCH1") ;(S->T[S->nT])->tr=freeT ;S->nT++; + sprintf ( (S->T[S->nT])->name, "MATCH2") ;(S->T[S->nT])->tr=freeT ;S->nT++; + + sprintf ( (S->T[S->nT])->name, "INSERT");(S->T[S->nT])->tr=freeT ;S->nT++; + sprintf ( (S->T[S->nT])->name, "DELETE");(S->T[S->nT])->tr=freeT ;S->nT++; + sprintf ( (S->T[S->nT])->name, "END") ;(S->T[S->nT])->tr=freeT ;S->nT++; + + n++; + /*define END*/ + S=H->S[n]; + sprintf (S->name, "END"); S->state=n; + S->DI=0; + S->DJ=0; + S->em=freeT; + n++; + + /*define Match*/ + S=H->S[n]; + sprintf (S->name, "MATCH1"); S->state=n; + S->DI=1; + S->DJ=1; + S->em=H->forbiden; + S->em_func=get_dp_cost_pam_matrix; + + sprintf ( (S->T[S->nT])->name, "MATCH1") ;(S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "INSERT");(S->T[S->nT])->tr=gop ;S->nT++; + sprintf ( (S->T[S->nT])->name, "DELETE");(S->T[S->nT])->tr=gop ;S->nT++; + sprintf ( (S->T[S->nT])->name, "END"); (S->T[S->nT])->tr=freeT;S->nT++; + + n++; + + /*define Match*/ + S=H->S[n]; + sprintf (S->name, "MATCH2"); S->state=n; + S->DI=1; + S->DJ=1; + S->em=H->forbiden; + S->em_func=get_dp_cost_blosum_matrix; + + sprintf ( (S->T[S->nT])->name, "MATCH2") ;(S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "INSERT");(S->T[S->nT])->tr=gop ;S->nT++; + sprintf ( (S->T[S->nT])->name, "DELETE");(S->T[S->nT])->tr=gop ;S->nT++; + sprintf ( (S->T[S->nT])->name, "END"); (S->T[S->nT])->tr=freeT;S->nT++; + + n++; + + /*define Insert*/ + S=H->S[n]; + sprintf (S->name, "INSERT"); S->state=n; + S->DI=1; + S->DJ=0; + S->em=gep; + sprintf ( (S->T[S->nT])->name, "MATCH2") ; (S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "MATCH1") ; (S->T[S->nT])->tr=freeT;S->nT++; + + sprintf ( (S->T[S->nT])->name, "INSERT"); (S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "LINSERT");(S->T[S->nT])->tr=lgop ;S->nT++; + sprintf ( (S->T[S->nT])->name, "END"); (S->T[S->nT])->tr=-gop;S->nT++; + + n++; + + /*define LInsert*/ + S=H->S[n]; + sprintf (S->name, "LINSERT"); S->state=n; + S->DI=1; + S->DJ=0; + S->em=lgep; + + sprintf ( (S->T[S->nT])->name, "INSERT") ;(S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "LINSERT");(S->T[S->nT])->tr=freeT;S->nT++; + + n++; + + + /*define Delete*/ + S=H->S[n]; + sprintf (S->name, "DELETE"); S->state=n; + S->DI=0; + S->DJ=1; + S->em=gep; + + sprintf ( (S->T[S->nT])->name, "MATCH2") ;(S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "MATCH1") ;(S->T[S->nT])->tr=freeT;S->nT++; + + sprintf ( (S->T[S->nT])->name, "DELETE") ;(S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "LDELETE") ;(S->T[S->nT])->tr=lgop ;S->nT++; + sprintf ( (S->T[S->nT])->name, "END") ;(S->T[S->nT])->tr=-gop;S->nT++; + n++; + + /*define LDelete*/ + S=H->S[n]; + sprintf (S->name, "LDELETE"); S->state=n; + S->DI=0; + S->DJ=1; + S->em=lgep; + sprintf ( (S->T[S->nT])->name, "DELETE") ;(S->T[S->nT])->tr=freeT;S->nT++; + sprintf ( (S->T[S->nT])->name, "LDELETE");(S->T[S->nT])->tr=freeT;S->nT++; + n++; + + if ( n!=H->nS) + { + fprintf ( stderr, "\nERROR in HMM definition [FATAL:%s]", PROGRAM); + myexit (EXIT_FAILURE); + } + + H=bound_hmm ( H); + return H; +} +void DisplayMatState ( MatState *S, char *s) +{ + if ( S==NULL)fprintf ( stderr, "%s: Cell is undefined", s); + else fprintf ( stderr, "%s: i=%d j=%d st=%d pst=%d sc=%d Free %d", s, S->i, S->j, S->st, S->pst, (int)S->sc, S->free); +} +void testfunc ( MatState *S, char *s) +{ + if ( S==NULL)return; + fprintf ( stderr, "\n#### %s ", s); + while ( S){DisplayMatState ( S,"\n\t");S=S->n;} + fprintf ( stderr, "\n"); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifdef BACKHERE + + if ( i>0 && j>0) + m=emit_pair_default[alphabetDefault[seq1[a]]][alphabetDefault[seq2[a]]]; + /*Match*/ + F[M][i][j]=F[M][i-1][j-1]; + + + + M[Match][i][j]=m+log_add3( M[Match][i-step_i][j-step_j],M[I][i-step_i][j],M[D][i][j-step_j]); + M[D ][i][j]=log_add3(gep,M[Match][i ][j-step_j]+gop,M[D][i ][j-step_j]); + M[I ][i][j]=log_add3(gep,M[Match][i-step_i][j ]+gop,M[I][i-step_i][j ]); + + /*Long gaps + M[Match][i][j]=log_add3(M[Match][i][j], M[LI][i-step_i][j],M[LD][i][j-step_j]); + M[LI ][i][j]=log_add3(lgep, M[I][i-step_i][j ]+lgop,M[LI][i-step_i][j ]); + M[LD ][i][j]=log_add3(lgep, M[D][i ][j-step_j]+lgop,M[LD][i ][j-step_j]); + */ + + } + } + retun M; +MatState* RviterbiL_hmm (Alignment *A,int *ns, int **ls, Hmm *H, Constraint_list *CL,MatState *S, MatState *E) +{ + MatState *Mid; + Mid=viterbiL_hmm (A,ns, ls,H, CL, S, E); + + if (!Mid) + { + return S; + } + else if ( Mid->n) + { + return Mid; + } + + else + { + Mid->p=S;S->n=Mid; + Mid->n=E;E->p=Mid; + RviterbiL_hmm (A,ns, ls,H, CL,S, Mid); + RviterbiL_hmm (A,ns, ls,H, CL,Mid, E); + return S; + } +} + +MatState* viterbiL_hmm (Alignment *A,int *ns, int **ls, Hmm *H, Constraint_list *CL, MatState *S,MatState *E) +{ + int current,memory, dim; + double e, v,t; + int i,j,pi,pj, s, k; + int start_i, start_j, end_i, end_j, l1, l2; + HmmState *S1, *S2; + static MatState ****M; + static int maxl; + MatState *Mid=NULL; + + MatState *CC, *PCC; + int midpoint; + int Delta; + + + if ( MatStateAreIdentical ( S, E))return NULL; + + l1=strlen (A->seq_al[ls[0][0]]); + l2=strlen (A->seq_al[ls[1][0]]); + + midpoint=S->i+(E->i-S->i)/2; + Delta=E->i-S->i; + + start_i=S->i;end_i=E->i; + start_j=S->j;end_j=E->j; + + dim=H->order+2;current=0;memory=H->order+1; + if (!M || (l2+1)>maxl) + { free_arrayN((void **)M, 4); + M=declare_arrayN(4, sizeof ( MatState), dim, maxl=(l2+1), H->nS,1); + } + + /*MAKE THE VITERBI FROM S(tart) to E(nd)*/ + for ( i=start_i; i<=end_i; i++) + { + M= (MatState****)recycle ( (void **)M,H->order+1,1); + for ( j=start_j; j<=end_j; j++) + { + for ( s=H->nS-1;s>=0; s--) + { + + S1=H->S[s]; + pi=i-S1->DI;pj=j-S1->DJ; + CC=M[current][j][s]; + CC->i=i; CC->j=j; CC->st=s;CC->sc=H->forbiden;CC->p=CC->n=CC->m=NULL;CC->sc=H->forbiden; + if (i==start_i && j==start_j && s==S->st) {CopyMatState(S,CC);} + else if ( i==end_i && j==end_j && s==E->st && s!=H->end) + { + S2=H->S[E->pst]; + CopyMatState(E,CC); + CC->p=M[S1->DI][j-S1->DJ][S2->state]; + } + else if ( pisc=H->forbiden;} + else + { + for (k=1; k<=H->fromM[S1->state][0]; k++) + { + S2=H->S[H->fromM[s][k]]; + PCC=M[S1->DI][j-S1->DJ][S2->state]; + + if ( pi+pj!=0 && S2->state==H->start) {t=H->forbiden;} + else if ( !(pi==l1 && pj==l2) && s==H->end){t=H->forbiden;} + else t=H->T[S2->state][S1->state]; + + v=hmm_add(t,PCC->sc); + if ( v!=H->forbiden && (CC->sc==H->forbiden || v> CC->sc)){CC->sc=v; CC->pst=S2->state;CC->p=PCC;} + } + + e=(S1->em==H->forbiden)?S1->em_func (A, A->pos, ns[0], ls[0],i-1, A->pos,ns[1], ls[1], j-1, CL):S1->em; + CC->sc=hmm_add(CC->sc,e); + } + + if (i==midpoint)CC->m=CopyMatState(CC, M[memory][j][s]); + else if (i>midpoint && CC->sc!=H->forbiden) CC->m=(M[S1->DI][j-S1->DJ][CC->pst])->m; + } + } + } + + if ( E->st==H->end)CopyMatState ((M[current][end_j][E->st]),E); + + if ( Delta>1) + { + Mid=CopyMatState ((M[current][end_j][E->st])->m,NULL); + } + else if ( Delta==1) + { + CC=M[current][E->j][E->st]; + Mid=E; + while (!MatStateAreIdentical (CC->p, S) ) + { + Mid->p=CopyMatState(CC->p,NULL); + (Mid->p)->n=Mid; + Mid=Mid->p;CC=CC->p; + } + Mid->p=S; + S->n=Mid; + Mid=S; + } + + return Mid; +} +#endif +/*********************************COPYRIGHT NOTICE**********************************/ +/*© Centre National de la Recherche Scientifique (CNRS) */ +/*and */ +/*Please Cite: Notredame*/ +/*Mon May 17 20:15:35 MDT 2004. */ +/*All rights reserved.*/ +/*NOTICE: |*/ +/* This file is an integral part of the */ +/* ALIGN_TWO_SEQ Software. */ +/* Its content is protected and all */ +/* the conditions mentioned in the licensing */ +/* agreement of the software apply to this file.*/ +/*............................................... |*/ +/* If you need some more information, or if you */ +/* wish to obtain a full license, please contact: */ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/*********************************COPYRIGHT NOTICE**********************************/ +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/header_list b/binaries/src/tcoffee/t_coffee_source/header_list new file mode 100644 index 0000000..87051df --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/header_list @@ -0,0 +1,13 @@ +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/define_header.h +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/dev1_lib_header.h +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/dev2_lib_header.h +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/dev3_lib_header.h +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/dev4_lib_header.h +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/dp_lib_header.h +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/fast_tree_header.h +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/fastal_lib_header.h +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/io_lib_header.h +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/matrices.h +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/perl_header_lib.h +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/t_coffee.h +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/util_lib_header.h diff --git a/binaries/src/tcoffee/t_coffee_source/hsearch.c b/binaries/src/tcoffee/t_coffee_source/hsearch.c new file mode 100644 index 0000000..7f7a3d6 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/hsearch.c @@ -0,0 +1,290 @@ + +#include +#include +#include +#include + + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" + +HaschT * hcreate ( int n_elements,struct Hasch_data * declare_data(struct Hasch_entry *), struct Hasch_data *free_data(struct Hasch_data *) ) + { + HaschT *T; + int a; + + n_elements=n_elements*2+1; + + T=vcalloc ( 1, sizeof (HaschT)); + T->ne=n_elements; + T->p=vcalloc (n_elements,sizeof ( Hasch_entry*)); + for ( a=0; ap[a]=allocate_hasch_entry(NULL,DECLARE,declare_data, free_data); + } + return T; + } +HaschT *hdestroy (HaschT *T,struct Hasch_data * declare_data(struct Hasch_entry *), struct Hasch_data *free_data(struct Hasch_data *) ) + + + { + int a; + Hasch_entry *p, *pp; + + if ( T==NULL)return NULL; + + for (a=0; a< T->ne; a++) + { + p=T->p[a]; + while (p) + { + pp=p; + p=p->n; + allocate_hasch_entry(pp,FREE, declare_data, free_data); + } + } + vfree (T->p); + vfree ( T); + return NULL; + } + + +Hasch_entry* hsearch (HaschT *T, int k, int action, struct Hasch_data * declare_data(struct Hasch_entry *), struct Hasch_data *free_data(struct Hasch_data *) ) + + + { + /*action: FIND,ADD, REMOVE*/ + Hasch_entry *p, *pi; + int h; + + + + /* find the key: k->h*/ + + h=k%T->ne; + + + if ( action==ADD || action==FIND) + { + p=pi=T->p[h]; + while (p && p->k!=k){p=p->n;} + if (action==ADD && !p) + { + p=insert_hasch_entry_in_list (pi, NULL, NULL, declare_data, free_data); + p->k=k; + } + else if (action==FIND && !p)p=NULL; + return p; + } + else if ( action==REMOVE) + { + allocate_hasch_entry(hsearch ( T, k, FIND, declare_data, free_data), FREE, declare_data, free_data); + return NULL; + } + return NULL; + } + + +Hasch_entry * extract_hasch_entry_from_list (Hasch_entry *e, struct Hasch_data * declare_data(struct Hasch_entry *), struct Hasch_data *free_data(struct Hasch_data *) ) + + + { + /*extracts entry e and returns p, or next if is NULL*/ + Hasch_entry *p=NULL, *n=NULL; + + if (!e); + else + { + p=e->p; + n=e->n; + + if (p)p->n=n; + if (n)n->p=p; + e->p=e->n=NULL; + } + return e; + } + +Hasch_entry * insert_hasch_entry_in_list (Hasch_entry *p, Hasch_entry *e, Hasch_entry *n, struct Hasch_data * declare_data(struct Hasch_entry *), struct Hasch_data *free_data(struct Hasch_data *) ) + + +{ + /*inserts entry e between entry p and entry n and returns e*/ + + if (!e)e=allocate_hasch_entry (NULL,DECLARE, declare_data, free_data); + + + + if (!p && !n); + else if ( !p)p=n->p; + else if ( !n)n=p->n; + + e->p=p; + if (p)p->n=e; + + e->n=n; + if (n)n->p=e; + + return e; + } + +Hasch_entry * allocate_hasch_entry (Hasch_entry *e, int action,struct Hasch_data * declare_data(struct Hasch_entry *), struct Hasch_data *free_data(struct Hasch_data *) ) + + +{ + static Hasch_entry *s; + Hasch_entry *ns; + + if ( !s)s=vcalloc ( 1, sizeof (Hasch_entry)); + + if ( action==DECLARE) + { + ns=s->p; + e=extract_hasch_entry_from_list (s, declare_data, free_data); + if ( e->free_data)(e->free_data)(e->data); + e->declare_data=declare_data; + e->free_data=free_data; + e->declare_data (e); + e->k=UNDEFINED; + s=ns; + } + else if ( action==FREE) + { + extract_hasch_entry_from_list (e,declare_data, free_data ); + e->k=UNDEFINED; + if ( e->free_data)e->data=(e->free_data)(e->data); + e->free_data=NULL; + e->declare_data=NULL; + s=insert_hasch_entry_in_list (s, e, NULL, declare_data, free_data); + + } + else if ( action==FREE_STACK) + { + while (s) + { + e=s->p; + allocate_hasch_entry (s, FREE, declare_data,free_data); + vfree (s); + s=e; + } + } + else crash ("Unknown MODE for allocate_hasch_entry\n"); + return e; + } + +/*********************************************************************/ +/* */ +/* Get string key */ +/* */ +/* */ +/*********************************************************************/ + + +int string2key (char *s, Char_node *n) +{ + static Char_node *root; + + if ( !root)root=declare_char_node (DECLARE); + + if ( n==NULL && s==NULL) + { + declare_char_node (FREE_STACK); + } + else if (n==NULL) + { + return string2key(s, root); + } + else if ( s[0]=='\0') + { + return n->key; + } + else + { + return string2key(s+1, (n->c[(int)s[0]])?(n->c[(int)s[0]]):(n->c[(int)s[0]]=declare_char_node (DECLARE))); + } + return 0; +} + +Char_node * declare_char_node (int action) +{ +static struct Char_node **heap; +static int heap_size, free_heap, a; +static int key; + if ( action==DECLARE) + { + if ( free_heap==0) + { + free_heap=100; + + heap=vrealloc (heap,(heap_size+free_heap)*sizeof (struct Char_node *)); + for ( a=heap_size; ac=vcalloc ( 256, sizeof (Char_node*)); + (heap[a])->key=key++; + } + heap_size+=free_heap; + } + return heap[heap_size-(free_heap--)]; + } + else if ( action==FREE_STACK) + { + for (a=0; a< heap_size; a++) + { + heap[a]->key=key++; + vfree ( heap[a]->c); + (heap[a])->c=vcalloc ( 256, sizeof (Char_node*)); + } + free_heap=heap_size; + return NULL; + } + return NULL; +} + +/* old declare_char_node (too hungry) +Char_node * declare_char_node (int action) +{ + static int key; + Char_node *cn; + static Char_node *root; + + if ( action==DECLARE) + { + cn=vcalloc (1, sizeof (Char_node)); + cn->key=++key; + cn->c=vcalloc (256, sizeof (Char_node *)); + + } + return cn; +} +*/ +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/io_func.c b/binaries/src/tcoffee/t_coffee_source/io_func.c new file mode 100644 index 0000000..d9816e9 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/io_func.c @@ -0,0 +1,1532 @@ +#include +#include +#include +#include +#include +#include +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" +#include "matrices.h" + +#define DEFAULT_COLOR -1 +#define GAP_COLOR -2 +#define INK_COLOR -3 + +Sequence * cw_read_sequences ( char *seq_name) + { + Sequence *S; + + + char **seq=NULL; + char **name=NULL; + int *len=NULL; + int nseq=0; + int min_len=0; + int max_len=0; + int a; + + get_sequence ( seq_name, &nseq, &seq, &name, &len, &min_len, &max_len); + + S=declare_sequence ( min_len, max_len, nseq); + for ( a=0; a< nseq; a++)sprintf ( S->file[a], "%s", seq_name); + + for ( a=0; anseq; a++) + { + S->len[a]=len[a]; + sprintf ( S->name[a],"%s", name[a]); + vfree ( name[a]); + sprintf ( S->seq[a], "%s", seq[a]); + vfree ( seq[a]); + } + vfree (seq); + vfree (name); + vfree (len); + S=get_sequence_type ( S); + return S; + } +char * get_string_type (char *S) + { + int a, l; + int protein=0, dna=0,rna=0, tot=0; + char *type; + static char *ltype; + static int warning; + + if ( !ltype) + declare_name(ltype); + + declare_name(type); + l=(int)strlen (S); + + if (l==0) + { + sprintf ( type, "UNKNOWN"); + return type; + } + + for ( a=0; a98 && rna>0)sprintf ( type, "RNA"); + else if ( dna>98)sprintf ( type, "DNA"); + else sprintf ( type, "PROTEIN"); + + sprintf ( ltype, "%s", type); + return type; + } + +Alignment* get_aln_type (Alignment *A) + { + if ( !A) return A; + + if ( A->S && !(A->S)->type)(A->S)->type=vcalloc (30, sizeof (char)); + + if ( A->S && (A->S)->type[0]!='\0') + { + ; + } + else if (A->S!=NULL && (A->S)->type[0]=='\0') + { + A->S=get_sequence_type (A->S); + } + else if (A->S==NULL) + { + A->S=aln2seq (A); + A->S=get_sequence_type(A->S); + } + return A; + } + + + +char *unset_mode () +{ + return set_mode (UNSET, NULL); +} +char *store_mode (char *val) +{ + return set_mode (SET, val); +} +char *retrieve_mode () +{ + return set_mode (GET,NULL); +} +char *set_mode (int mode, char *val) +{ + static char type[100]; + if (mode==SET) + { + if (!val)printf_exit (EXIT_FAILURE, stderr, "Error: programme mode unset in io_func.c:set_seq_type"); + sprintf ( type,"%s", val); + } + else if ( mode==GET) + { + ; + } + else if ( mode==UNSET) + { + type[0]='\0'; + } + else + { + printf_exit (EXIT_FAILURE, stderr, "Error: unknown mode in function io_func.c:set_seq_type, use SET, GET or UNSET"); + } + return type; +} +/************************************************************/ + + + +char *unset_seq_type () +{ + return set_seq_type (UNSET, NULL); +} +char *store_seq_type (char *val) +{ + return set_seq_type (SET, val); +} +char *retrieve_seq_type () +{ + return set_seq_type (GET,NULL); +} +char *set_seq_type (int mode, char *val) +{ + static char type[100]; + if (mode==SET) + { + if (!val)printf_exit (EXIT_FAILURE, stderr, "Error: sequence type unset in io_func.c:set_seq_type"); + sprintf ( type,"%s", val); + } + else if ( mode==GET) + { + ; + } + else if ( mode==UNSET) + { + type[0]='\0'; + } + else + { + printf_exit (EXIT_FAILURE, stderr, "Error: unknown mode in function io_func.c:set_seq_type, use SET, GET or UNSET"); + } + return type; +} +char * get_array_type (int n, char **seq) +{ + char *buf, *buf2; + int a, tot=0; + buf2=vcalloc ( 100, sizeof (char)); + + + for ( tot=0,a=0; atype, "%s", get_array_type (S->nseq, S->seq)); + return S; +} + + +void get_sequence (char *seq_file,int *NSEQ, char ***SEQ, char ***SN, int **sl, int *min, int *max) + { + int a,b; + int min_len; + int max_len; + int nseq; + + int **SL; + + nseq=NSEQ[0]= readseqs ( seq_file, SEQ, SN, &SL); + sl[0]=vcalloc ( nseq, sizeof (int)); + + + min_len= max_len= (SL)[0][0]; + for ( a=0; a (SL)[a][0])?(SL)[a][0]:min_len; + max_len= ( max_len < (SL)[a][0])?(SL)[a][0]:max_len; + } + min[0]=min_len; + max[0]=max_len; + } + +int ** get_matrix ( char *name, char *format) + { + + if ( strm ( "blast", format))return read_blast_matrix ( name); + else if ( strm ( "clustalw", format))return read_matrice(name); + else + { + fprintf ( stderr, "\nError:\nUnknowm Format %s for Matrix %s[FATAL]", format, name); + myexit (EXIT_FAILURE); + } + return NULL; + } +void display_matrix (int **mat); +int ** read_matrice (char *mat_name_in) + { + int a,b,c, l; + + char *AA; + FILE *fp; + int **matrice; + int **matrix2; + char mat_name[200]; + int *vector=NULL; + + AA=vcalloc (256, sizeof (char)); + sprintf (AA, "abcdefghiklmnpqrstvwxyz"); + l=strlen(AA); + + + + + if ( strm2 (mat_name_in, "pam", "PAM"))sprintf ( mat_name, "pam250mt"); + else if (strm2 (mat_name_in, "blosum", "BLOSUM"))sprintf ( mat_name, "blosum62mt"); + else if (strm3 (mat_name_in, "id", "ID", "idmat"))sprintf ( mat_name, "idmat"); + else sprintf ( mat_name, "%s", mat_name_in); + + /*Read Header Matrices*/ + if (strm(mat_name, "pam250mt"))vector=pam250mt; + else if (strm(mat_name, "idmat"))vector=idmat; + else if (strm(mat_name, "dna_idmat"))vector=idmat; + else if (strm(mat_name, "est_idmat"))vector=est_idmat; + else if (strm(mat_name, "md_350mt"))vector=md_350mt; + else if (strm(mat_name, "md_250mt"))vector=md_250mt; + else if (strm(mat_name, "md_120mt"))vector=md_120mt; + else if (strm(mat_name, "md_40mt" ))vector= md_40mt; + else if (strm(mat_name, "pam350mt" ))vector=pam350mt; + else if (strm(mat_name, "pam160mt" ))vector=pam160mt; + else if (strm(mat_name, "pam120mt" ))vector=pam120mt; + + else if (strm(mat_name, "blosum80mt" ))vector=blosum80mt; + else if (strm(mat_name, "blosum62mt" ))vector=blosum62mt; + else if (strm(mat_name, "exon2mt" ))vector=blosum62mt; + else if (strm(mat_name, "blosum62mt3" ))vector=blosum62mt3; + + else if (strm(mat_name, "blosum62mt2" ))vector=blosum62mt2; + else if (strm(mat_name, "blosum55mt" ))vector=blosum55mt; + else if (strm(mat_name, "blosum50mt" ))vector=blosum50mt; + else if (strm(mat_name, "blosum45mt" ))vector=blosum45mt; + + else if (strm(mat_name, "blosum40mt" ))vector=blosum40mt; + else if (strm(mat_name, "blosum30mt" ))vector=blosum30mt; + else if (strm(mat_name, "beta_mat" ))vector=beta_mat; + else if (strm(mat_name, "alpha_mat" ))vector=alpha_mat; + else if (strm(mat_name, "coil_mat" ))vector=coil_mat; + + else if (strm(mat_name, "rblosum80mt" ))vector=rblosum80mt; + else if (strm(mat_name, "rblosum62mt" ))vector=rblosum62mt; + else if (strm(mat_name, "rblosum30mt" ))vector=rblosum30mt; + + else if (strm(mat_name, "rpam250mt" ))vector=rpam250mt; + else if (strm(mat_name, "rpam350mt" ))vector=rpam350mt; + else if (strm(mat_name, "rpam160mt" ))vector=rpam160mt; + else if (strm(mat_name, "rpam120mt" ))vector=rpam120mt; + + else if (strm(mat_name, "tmpam250mt" ))vector=tmpam250mt; + else if (strm(mat_name, "rtmpam250mt" ))vector=rtmpam250mt; + + else if (strm(mat_name, "rbeta_mat" ))vector=rbeta_mat; + else if (strm(mat_name, "ralpha_mat" ))vector=ralpha_mat; + else if (strm(mat_name, "rcoil_mat" ))vector=rcoil_mat; + else if (strm (mat_name, "jtttm250mt"))vector=jtttm250mt; + + else if (strm (mat_name, "promoter_tf1"))vector=promoter_tf1; + else if (strm (mat_name, "blosumR"))vector=blosumR; + + /*Header Matrices*/ + if(vector) + { + matrice=declare_int ( 256, 256); + for (a=0; a0)return matrix; + else + { + for ( b=0; br; + g=&C->g; + b=&C->b; + + if ( val==10)val--; + sprintf ( C->html_color_class, "value%d",val); + + + if (val<=9 && val>=0) + { + + sprintf ( C->html_color, "%s", html_code[val]); + r[0]=ps_code[val][0]; + g[0]=ps_code[val][1]; + b[0]=ps_code[val][2]; + } + + else if (val==DEFAULT_COLOR || val==NO_COLOR_RESIDUE || val==NO_COLOR_GAP || (val>'A' && val<'z')) + { + C->html_color[0]='\0'; + sprintf ( C->html_color_class, "valuedefault"); + r[0]=1.; + g[0]=1; + b[0]=1; + + } + else if (val==GAP_COLOR) + { + C->html_color[0]='\0'; + sprintf ( C->html_color_class, "valuegap"); + r[0]=1.; + g[0]=1; + b[0]=1; + } + else if (val==INK_COLOR ) + { + sprintf ( C->html_color, "000000"); + sprintf ( C->html_color_class, "valueink"); + r[0]=0.; + g[0]=0; + b[0]=0; + } + return; + + + } + +// void output_tm_mark(FILE_format *fps) +// { +// Color *box_c=vcalloc ( 1, sizeof (Color)); +// Color *ink; +// get_rgb_values_format (INK_COLOR, (ink =vcalloc ( 1, sizeof (Color)))); +// +// get_rgb_values_format ( 5, box_c); +// fps=print_format_char ( " IN ", box_c,ink,fps); +// +// get_rgb_values_format ( 9, box_c); +// fps=print_format_char ( " HEL ", box_c,ink,fps); +// +// get_rgb_values_format ( 0, box_c); +// fps=print_format_char ( "OUT", box_c,ink,fps); +// } + +int output_color_format ( Alignment *B,Alignment *Sin,char *name, \ +FILE_format *(*vfopen_format) ( char *),\ +FILE_format *(*print_format_string) ( char * ,Color *, Color *, FILE_format*),\ +FILE_format *(*print_format_char) ( int ,Color *, Color *, FILE_format*),\ +void (*get_rgb_values_format) ( int ,Color *),\ +FILE_format* (*vfclose_format) ( FILE_format *)) + { + int a, b, c; + int max_name_len=15; + int max_len=0; + char *buf2, *buf3; + + static char *buf; + int s; + int *n_residues; + static FILE_format *fps; + Color *ink; + Color *box_c; + Color *white; + Alignment *S; + + + S=copy_aln (B, NULL); + + buf2=vcalloc (Sin->len_aln+1, sizeof (char)); + buf3=vcalloc ( B->len_aln+1, sizeof (char)); + for ( a=0; anseq; a++) + { + int i,n, r; + + i=name_is_in_list ( B->name[a], Sin->name, Sin->nseq, -1); + if (i==-1)continue; + sprintf (buf2, "%s", Sin->seq_al[i]);ungap(buf2); + sprintf (buf3, "%s", S->seq_al[a]);ungap(buf3); + + if ( strlen (buf2) !=strlen(buf3)) + { + + fprintf ( stderr, "\nERROR: Incompatible cache ON sEQ: %s\n", S->name[a]); + fprintf ( stderr, "\n%s\n%s", buf2, buf3); + fprintf ( stderr, "\n\n%s\n%s", Sin->seq_al[i],S->seq_al[a]); exit (EXIT_FAILURE); + } + + for (n=0,b=0;blen_aln; b++) + { + r=S->seq_al[a][b]; + if (!is_gap(r)) + { + S->seq_al[a][b]=buf2[n++]; + } + } + } + + S=aln2number(S); + vfree (buf2); + + box_c=vcalloc ( 1, sizeof (Color)); + get_rgb_values_format (DEFAULT_COLOR, (white=vcalloc ( 1, sizeof (Color)))); + get_rgb_values_format (INK_COLOR, (ink =vcalloc ( 1, sizeof (Color)))); + + n_residues=vcalloc ( B->nseq+1, sizeof (int)); + for ( a=0; anseq; a++)n_residues[a]=B->order[a][1]; + + fps=vfopen_format( name); + if ( buf==NULL) + { + buf=vcalloc (10000, sizeof (int)); + } + + if ( max_len==0) + { + for ( a=0; a< B->nseq; a++) + {if ( strlen (B->name[a])>max_len) + max_len= strlen ( (B->name[a])); + } + } + if ( max_len>max_name_len)max_len=max_name_len; + + sprintf (buf, "\n%s, %s(%s)\n%s\n",PROGRAM,VERSION,DATE, AUTHOR); + fps=print_format_string ( buf,white, ink, fps); + + if(B->output_tm == 1) + { + fps=print_format_char ( '\n', white, ink, fps); + get_rgb_values_format ( 5, box_c); + fps=print_format_string ( " IN ", box_c,ink,fps); + + get_rgb_values_format ( 9, box_c); + fps=print_format_string ( " HEL ", box_c,ink,fps); + + get_rgb_values_format ( 0, box_c); + fps=print_format_string ( " OUT ", box_c,ink,fps); + } + + fps=print_format_string ( "\n\n",white,ink, fps); + + fps->line-=max_len; + fps->line=fps->line-fps->line%3; + + + + + for (a=0; alen_aln; a+=fps->line) + { + + if ( (fps->n_line+(B->nseq+4))>fps->max_line_ppage && !((B->nseq+4)>fps->max_line_ppage)) + { + fps=print_format_char ( fps->eop,white, ink, fps); + } + + for (b=0; b<=B->nseq; b++) + { + sprintf (buf,"%-*.*s ",max_len+2, max_len,(b==B->nseq)?"":S->name[b]); + fps=print_format_string ( buf,white, ink, fps); + if(B->output_res_num) + { + sprintf (buf, " %4d ", n_residues[b]+1); + fps=print_format_string ( buf,white, ink, fps); + } + + for (fps->in_seq=1,c=a;cline && clen_aln;c++) + { + if (b==B->nseq) + { + n_residues[b]++; + get_rgb_values_format (DEFAULT_COLOR,box_c); + s=analyse_aln_column ( B, c); + } + else + { + n_residues[b]+=!is_gap(B->seq_al[b][c]); + s=B->seq_al[b][c]; + if (!is_gap(s) && S->seq_al[b][c]!=NO_COLOR_RESIDUE ) + { + get_rgb_values_format ( S->seq_al[b][c], box_c); + } + else + { + get_rgb_values_format (GAP_COLOR, box_c); + } + } + fps=print_format_char ( s,box_c, ink,fps); + } + fps->in_seq=0; + + if(B->output_res_num) + { + sprintf (buf, " %4d ", n_residues[b]); + fps=print_format_string ( buf,white, ink, fps); + } + + fps=print_format_char ( '\n', white, ink, fps); + + } + fps=print_format_string ( "\n\n",white, ink, fps); + } + fps=print_format_string ( "\n\n\n",white, ink,fps); + + + vfclose_format( fps); + free_aln (S); + vfree (n_residues); + return 1; + + } + +int output_reliability_format ( Alignment *B,Alignment *S,char *name, \ +FILE_format *(*vfopen_format) ( char *),\ +FILE_format *(*print_format_string) ( char * ,Color *, Color *, FILE_format*),\ +FILE_format *(*print_format_char) ( int ,Color *, Color *, FILE_format*),\ +void (*get_rgb_values_format) ( int ,Color *),\ +FILE_format* (*vfclose_format) ( FILE_format *)) + { + int a, b, c,l; + int max_name_len=15; + int max_len=0; + static char *buf,*buf2; + int s; + static FILE_format *fps; + Color *ink; + Color *box_c; + Color *white; + int *n_residues; + + + box_c=vcalloc ( 1, sizeof (Color)); + get_rgb_values_format (DEFAULT_COLOR, (white=vcalloc ( 1, sizeof (Color)))); + get_rgb_values_format (INK_COLOR, (ink =vcalloc ( 1, sizeof (Color)))); + + n_residues=vcalloc ( B->nseq+1, sizeof (int)); + for ( a=0; anseq; a++)n_residues[a]=B->order[a][1]; + + + fps=vfopen_format( name); + if ( buf==NULL) + { + buf=vcalloc (10000, sizeof (int)); + buf2=vcalloc (10000, sizeof (int)); + } + + if ( max_len==0) + { + for ( a=0; a< B->nseq; a++) + {if ( strlen (B->name[a])>max_len) + max_len= strlen ( (B->name[a])); + } + } + + if ( vfopen_format==vfopen_ascii) + { + fps->line+= max_len; + } + else if ( max_len>max_name_len)max_len=max_name_len; + + + + sprintf (buf, "%s, %s(%s)\n%s\nCPU TIME:%d sec.\n%s",PROGRAM,VERSION,DATE, AUTHOR, (B->cpu+get_time())/1000, (S->generic_comment)?S->generic_comment:""); + fps=print_format_string ( buf,white, ink, fps); + sprintf (buf, "SCORE=%d\n*\n", S->score_aln); + fps=print_format_string ( buf,white, ink, fps); + + sprintf ( buf2, " BAD AVG GOOD"); + l=strlen(buf2); + get_rgb_values_format ( DEFAULT_COLOR, box_c); + fps=print_format_char ( buf2[0],box_c, ink, fps); + for ( a=1; ascore_seq && a< B->nseq; a++) + { + get_rgb_values_format (S->score_seq[a]/10, box_c); + sprintf ( buf, "%-*.*s ", max_len+2,max_len, S->name[a]); + fps=print_format_string ( buf,box_c, ink,fps); + sprintf ( buf, ": %3d\n", S->score_seq[a]); + fps=print_format_string ( buf,white, ink,fps); + } + //Print the Consensus score + get_rgb_values_format (S->score_aln/10, box_c); + sprintf ( buf, "%-*.*s ", max_len+2,max_len, S->name[S->nseq]); + fps=print_format_string ( buf,box_c, ink,fps); + sprintf ( buf, ": %3d\n", S->score_aln); + fps=print_format_string ( buf,white, ink,fps); + + fps=print_format_string ( "\n",white, ink,fps); + + + + fps->line-=max_len; + fps->line=fps->line-(fps->line%3); + + for (a=0; alen_aln; a+=fps->line) + { + + if ( (fps->n_line+(B->nseq+4))>fps->max_line_ppage && !((B->nseq+4)>fps->max_line_ppage)) + { + fps=print_format_char ( fps->eop,white, ink, fps); + } + + for (b=0; b<=S->nseq; b++) + { + if ( b==S->nseq && print_format_string !=print_ascii_string) fps=print_format_string ( "\n",white, ink, fps); + sprintf (buf,"%-*.*s ",max_len+2,max_len,S->name[b]); + fps=print_format_string ( buf,white, ink, fps); + if(B->output_res_num) + { + sprintf (buf, " %4d ", n_residues[b]+1); + fps=print_format_string ( buf,white, ink, fps); + } + + for (fps->in_seq=1,c=a;cline && clen_aln;c++) + { + if (b==S->nseq) + { + + if (S->score_seq) + { + int s; + s=S->seq_al[b][c]; + if ( s>='0' && s<='9')s-='0'; + get_rgb_values_format (s,box_c); + } + else get_rgb_values_format (DEFAULT_COLOR,box_c); + n_residues[b]++; + s=analyse_aln_column ( B, c); + } + else + { + n_residues[b]+=!is_gap(B->seq_al[b][c]); + //s=toupper(B->seq_al[b][c]); + s=B->seq_al[b][c]; + if (!is_gap(s) && S->seq_al[b][c]!=NO_COLOR_RESIDUE ) + { + get_rgb_values_format ( S->seq_al[b][c], box_c); + + } + else + { + get_rgb_values_format (GAP_COLOR, box_c); + + } + + } + fps=print_format_char ( s,box_c, ink,fps); + } + fps->in_seq=0; + + if(B->output_res_num) + { + sprintf (buf, " %4d ",n_residues[b]); + fps=print_format_string ( buf,white, ink, fps); + } + + fps=print_format_char ( '\n', white, ink, fps); + + } + fps=print_format_string ( "\n\n",white, ink, fps); + } + fps=print_format_string ( "\n\n\n",white, ink,fps); + vfclose_format( fps); + return 1; + + } + + +/*****************************************************************************/ +/* PDF FUNCTIONS */ +/* */ +/*****************************************************************************/ +int output_color_pdf ( Alignment *B,Alignment *S, char *name) + { + char *tmp_name; + char command[LONG_STRING]; + + +#ifndef PS2PDF + fprintf (stderr, "\nPDF FORMAT IS NOT SUPPORTED: INSTALL THE PROGRAM PS2PDF\n"); + myexit (EXIT_FAILURE); +#else + tmp_name=vtmpnam(NULL); + + output_color_ps (B, S, tmp_name); + sprintf ( command, "%s %s %s", PS2PDF, tmp_name, name); + my_system ( command); + vremove ( tmp_name); +#endif + + + return 1; + } +int output_reliability_pdf ( Alignment *B,Alignment *S, char *name) + { + char *tmp_name; + char command[LONG_STRING]; + + + +#ifndef PS2PDF + fprintf (stderr, "\nPDF FORMAT IS NOT SUPPORTED: INSTALL THE PROGRAM PS2PDF\n"); + myexit (EXIT_FAILURE); +#else + tmp_name=vtmpnam(NULL); + + output_reliability_ps (B, S, tmp_name); + sprintf ( command, "%s %s %s", PS2PDF, tmp_name, name); + my_system ( command); + vremove ( tmp_name); +#endif + + + return 1; + } +/*****************************************************************************/ +/* POST SCRIPT FUNCTIONS */ +/* */ +/*****************************************************************************/ +int output_color_ps ( Alignment *B,Alignment *S, char *name) + { + output_color_format (B, S, name, vfopen_ps,print_ps_string,print_ps_char,get_rgb_values_ps, vfclose_ps); + return 1; + } +int output_reliability_ps ( Alignment *B,Alignment *S, char *name) + { + output_reliability_format (B, S, name, vfopen_ps,print_ps_string,print_ps_char,get_rgb_values_ps, vfclose_ps); + return 1; + } +FILE_format *print_ps_string( char *s, Color *box, Color *ink, FILE_format *fps) + { + int l; + int a; + + l=strlen (s); + + for ( a=0; a< l; a++) + { + fps=print_ps_char (s[a], box, ink, fps); + } + return fps; + } + + +FILE_format * print_ps_char ( int c, Color *box, Color *ink, FILE_format *f) + { + + int ch; + int cw; + + ch=f->font+3; + cw=f->font-2; + + if ( c=='(' || c==')')return f; + else if (c!='\n' && c!=f->eop) + { + fprintf(f->fp,"%d %d moveto\n", f->x,f->y); + fprintf(f->fp,"0 %d rlineto\n%d 0 rlineto\n0 -%d rlineto\nclosepath\n",ch,cw,ch ); + fprintf(f->fp,"%3.1f %3.1f %3.1f setrgbcolor\nfill\n%3.1f %3.1f %3.1f setrgbcolor\n", box->r,box->g,box->b, ink->r, ink->g, ink->b); + fprintf(f->fp,"%d %d moveto\n(%c) show\n", f->x+1,f->y+3, c); + + f->x+=cw; + } + else + { + f->n_line++; + if ( f->n_line==f->max_line_ppage || c==f->eop) + { + + f->n_line=0; + f->x=f->x0; + f->y=f->y0; + fprintf(f->fp,"showpage\n"); + f->n_pages++; + fprintf ( f->fp, "%c%cPage: %d %d\n",'%', '%', f->n_pages, f->n_pages); + } + else + { + f->x=f->x0; + f->y-=ch; + } + } + return f; + } +void get_rgb_values_ps ( int val, Color *C) + { + get_rgb_values ( val, C); + } + + + +FILE_format* vfopen_ps ( char *name) + { + FILE_format*fps; + + fps=vcalloc ( 1, sizeof ( FILE_format)); + fps->font=9; + fps->max_line_ppage=60; + fps->line=get_msa_line_length (0, 0);/*N char per line*/ + fps->x0=15; + fps->y0=750; + fps->eop='^'; + + fps->fp=vfopen ( name, "w"); + fprintf(fps->fp,"%%!PS-Adobe-2.0\n/Courier findfont\n%d scalefont\nsetfont\n",fps->font); + fprintf(fps->fp, "%%%%Pages: (atend)\n"); + fprintf(fps->fp,"newpath\n"); + ++(fps->n_pages); + fprintf (fps->fp, "%%%%Page: %d %d\n", fps->n_pages, fps->n_pages); + fprintf (fps->fp,"%d %d translate\n",fps->x0, fps->y0); + return fps; + } + +FILE_format* vfclose_ps ( FILE_format *fps) + { + + fprintf(fps->fp,"showpage\n"); + fprintf ( fps->fp, "%%%%Pages: %d\n", fps->n_pages); + fprintf(fps->fp,"%%%%EOF"); + fprintf(fps->fp,"%%%%\n"); + vfclose ( fps->fp); + vfree (fps); + return NULL; + } +/*****************************************************************************/ +/* HTML FUNCTIONS */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +//JM_ADD +/*****************************************************************************/ +void output_hit_matrix(char *fileName, float **ffpHitScoreMatrix, int nl) +{ + int i, j; + FILE *fp; + + fp=vfopen(fileName, "w"); + for(i = 0; i < nl; i++) + { + for(j = 0; j < i; j++) + fprintf(fp, "%6.2f ", ffpHitScoreMatrix[j][i-j]); + for(j = i; j < nl; j++) + fprintf(fp, "%6.2f ", ffpHitScoreMatrix[i][j-i]); + fprintf(fp, "\n"); + } + vfclose(fp); +} +int output_hit_color_format (Alignment *B, float **ffPScoreTable, int nl, char *name, \ +FILE_format *(*vfopen_format) ( char *),\ +FILE_format *(*print_format_string) ( char * ,Color *, Color *, FILE_format*),\ +FILE_format *(*print_format_char) ( int ,Color *, Color *, FILE_format*),\ +void (*get_rgb_values_format) ( int ,Color *),\ +FILE_format* (*vfclose_format) ( FILE_format *)); +int output_hit_color_html (Alignment *B, float **ffPScoreTable, int nl, char *name) +{ + output_hit_color_format (B, ffPScoreTable, nl, name, vfopen_html,print_html_string,print_html_char,get_rgb_values_html, vfclose_html); + return 1; +} + +int output_hit_color_format (Alignment *B, float **ffPScoreTable, int nl, char *name, \ +FILE_format *(*vfopen_format) ( char *),\ +FILE_format *(*print_format_string) ( char * ,Color *, Color *, FILE_format*),\ +FILE_format *(*print_format_char) ( int ,Color *, Color *, FILE_format*),\ +void (*get_rgb_values_format) ( int ,Color *),\ +FILE_format* (*vfclose_format) ( FILE_format *)) +{ + int a, b; + int max_name_len=15; + int max_len=0; + + static char *buf; + static FILE_format *fps; + Color *ink; + Color *box_c; + Color *white; + + box_c=vcalloc ( 1, sizeof (Color)); + get_rgb_values_format (DEFAULT_COLOR, (white=vcalloc ( 1, sizeof (Color)))); + get_rgb_values_format (INK_COLOR, (ink =vcalloc ( 1, sizeof (Color)))); + + if ( max_len==0) + { + for ( a=0; a< B->nseq; a++) + { + if ( strlen (B->name[a])>max_len) + max_len= strlen ( (B->name[a])); + } + } + if ( max_len>max_name_len)max_len=max_name_len; + + if ( buf==NULL) + buf=vcalloc (10000, sizeof (int)); + int iEmptyChr = 32; //SPACE ASCIICODE + int iColorValue; + fps=vfopen_format(name); + for (a=0; a < nl; a++) + { + sprintf (buf,"%*d ", max_len+2, a); + fps=print_format_string ( buf,white, ink, fps); + for(b = 0; b < a; b++) + { + iColorValue = (int)((ffPScoreTable[b][a-b]*9)/100); + get_rgb_values_format (iColorValue, box_c); + fps=print_format_char (iEmptyChr,box_c, ink,fps); + } + for(b = a; b < nl; b++) + { + iColorValue = (int)((ffPScoreTable[a][b-a]*9)/100); + get_rgb_values_format (iColorValue, box_c); + fps=print_format_char (iEmptyChr,box_c, ink,fps); + } + fps=print_format_char ('\n', white, ink, fps); + } + vfclose_format(fps); + vfree(buf); + vfree(box_c); + return 1; +} + +/*****************************************************************************/ + +int output_color_html ( Alignment *B,Alignment *S, char *name) + { + output_color_format (B, S, name, vfopen_html,print_html_string,print_html_char,get_rgb_values_html, vfclose_html); + return 1; + } +int output_reliability_html ( Alignment *B,Alignment *S, char *name) + { + output_reliability_format (B, S, name, vfopen_html,print_html_string,print_html_char,get_rgb_values_html, vfclose_html); + return 1; + } +FILE_format *print_html_string( char *s, Color *box, Color *ink, FILE_format *fhtml) + { + int l; + int a; + + l=strlen (s); + + for ( a=0; a< l; a++) + { + fhtml=print_html_char (s[a], box, ink, fhtml); + } + fhtml=print_html_char (CLOSE_HTML_SPAN,NULL,NULL,fhtml); + return fhtml; + } + + +FILE_format * print_html_char ( int c, Color *box, Color *ink, FILE_format *f) + { + char html_color[100]; + int in_span, new_color; + char string[1000]; + + + if (c==CLOSE_HTML_SPAN) + { + if (f->in_html_span)fprintf ( f->fp, ""); + f->in_html_span=0; + return f; + } + + + in_span=f->in_html_span; + new_color=1-(strm (box->html_color_class, f->previous_html_color)); + + + + sprintf (f->previous_html_color, "%s", box->html_color_class); + sprintf ( html_color, "class=%s", box->html_color_class); + + + if ( c!=' ')sprintf ( string, "%c", c); + else sprintf ( string, " "); + + if ( !in_span && c!='\n' && c!=f->eop) + { + fprintf ( f->fp, "%s",html_color,string ); + f->in_html_span=1; + } + else if (in_span && !new_color && c!='\n' && c!=f->eop) + { + + fprintf ( f->fp, "%s",string); + } + else if (in_span && new_color && c!='\n' && c!=f->eop) + { + fprintf ( f->fp, "%s",html_color,string); + } + else if ( c=='\n') + { + if ( f->in_html_span)fprintf ( f->fp, ""); + fprintf ( f->fp, "
    "); + sprintf ( f->previous_html_color, "no_color_set"); + f->in_html_span=0; + f->n_line++; + } + + + + + + return f; + } + +void get_rgb_values_html ( int val, Color *C) + { + get_rgb_values ( val, C); + } + +FILE_format* vfopen_html ( char *name) + { + FILE_format*fhtml; + Color *color; + int a; + + color=vcalloc ( 1, sizeof (Color)); + + fhtml=vcalloc ( 1, sizeof ( FILE_format)); + fhtml->font=11; + fhtml->max_line_ppage=100000; + fhtml->line=get_msa_line_length (0, 0);/*N char per line*/ + fhtml->x0=15; + fhtml->y0=800; + fhtml->eop='^'; + sprintf ( fhtml->previous_html_color, "no_value_set"); + fhtml->fp=vfopen ( name, "w"); + + fprintf(fhtml->fp,"\n"); + fprintf(fhtml->fp,""); + + return fhtml; + } +FILE_format* vfclose_html ( FILE_format *fhtml) + { + if ( fhtml->in_html_span)fprintf(fhtml->fp,""); + fprintf(fhtml->fp,"\n"); + vfclose ( fhtml->fp); + vfree (fhtml); + return NULL; + } +/*****************************************************************************/ +/* ascii FUNCTIONS */ +/* */ +/*****************************************************************************/ +int output_color_ascii ( Alignment *B,Alignment *S, char *name) + { + output_color_format (B, S, name, vfopen_ascii,print_ascii_string,print_ascii_char,get_rgb_values_ascii, vfclose_ascii); + return 1; + } +int output_reliability_ascii ( Alignment *B,Alignment *S, char *name) + { + output_reliability_format (B, S, name, vfopen_ascii,print_ascii_string,print_ascii_char,get_rgb_values_ascii, vfclose_ascii); + return 1; + } + +FILE_format *print_ascii_string( char *s, Color *box, Color *ink, FILE_format *fascii) + { + int l; + int a; + + l=strlen (s); + + for ( a=0; a< l; a++) + { + fascii=print_ascii_char (s[a], box, ink, fascii); + } + return fascii; + } + + +FILE_format * print_ascii_char ( int c, Color *box, Color *ink, FILE_format *f) + { + if (box->ascii_value>=0 && f->in_seq)fprintf ( f->fp, "%c", box->ascii_value); + else fprintf ( f->fp, "%c",c); + return f; + } + + +void get_rgb_values_ascii ( int val, Color *C) + { + + if ( val==NO_COLOR_RESIDUE)C->ascii_value='-'; + else if ( val==NO_COLOR_GAP)C->ascii_value='*'; + else if ( val>9)C->ascii_value='#'; + else if ( val>=0 && val<=9) C->ascii_value=val+'0'; + else C->ascii_value=val; + } + +FILE_format* vfopen_ascii ( char *name) + { + FILE_format*fascii; + fascii=vcalloc ( 1, sizeof ( FILE_format)); + fascii->font=11; + fascii->max_line_ppage=100000; + fascii->line=get_msa_line_length (0,0);/*N char per line*/ + fascii->x0=15; + fascii->y0=800; + fascii->eop='^'; + fascii->fp=vfopen ( name, "w"); + + + return fascii; + } +FILE_format* vfclose_ascii ( FILE_format *fascii) + { + vfclose ( fascii->fp); + vfree (fascii); + return NULL; + } + + +/*****************************************************************************/ +/* seq_score output */ +/* */ +/*****************************************************************************/ + +int output_seq_reliability_ascii ( Alignment *B,Alignment *S, char *name) +{ + FILE *fp; + int a; + int max_len=0; + for ( a=0; a< B->nseq; a++) + {if ( strlen (B->name[a])>max_len) + max_len= strlen ( (B->name[a])); + } + + fp=vfopen ( name, "w"); + fprintf ( fp, "ALN_SCORE %d\n", S->score_aln); + for ( a=0; a< S->nseq; a++)fprintf (fp, "SEQ_SCORE %*.*s %3d\n", max_len+2,max_len,S->name[a],S->score_seq[a]); + vfclose (fp); + + return 1; +} + +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/io_lib_header.h b/binaries/src/tcoffee/t_coffee_source/io_lib_header.h new file mode 100644 index 0000000..dd44ef5 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/io_lib_header.h @@ -0,0 +1,1120 @@ +/*DEBUGGING*/ +/*#include "mshell.h"*/ +/*MEMORY MANAGEMENT*/ +#include +#define MY_EPS 1000*DBL_EPSILON +//Maximum number of tries for interactibve things +#define MAX_N_TRIES 3 + +//Maximum CACHE and Temporary file size and age (Mb and days, 0: unlimited) +#define TMP_MAX_SIZE 0 +#define TMP_MAX_KEEP 10 +#define CACHE_MAX_SIZE 2000 +#define CACHE_MAX_KEEP 180 +#define MAX_N_PID 260000 +//Importnat Values Affecting the Program Behavior +#define O2A_BYTE 50 +#define SCORE_K 10 +#define NORM_F 1000 +#define PAVIE_MAT_FACTOR 1000 +#define MAXID 100 +#define CLEAN_FUNCTION NULL +#define MINSIM_4_TCOFFEE 25 //The minimum similarity between a sequence and its PDB template +#define MINCOV_4_TCOFFEE 25 //The minimum similarity between a sequence and its PDB template + + +#define TRACE_TYPE int +#define MAX_LEN_FOR_DP 600 + + +#define GIVE_MEMORY_BACK 0 +#define MEMSET0 1 +#define NO_MEMSET0 0 +/*OUTPUT DEFINITIONS*/ +#define NO_COLOR_RESIDUE 127 +#define NO_COLOR_GAP 126 +#define CLOSE_HTML_SPAN -1 +/*SPECIAL_CODES*/ +#define GAP_CODE 60 +/*TYPE DEFINITIONS*/ + +//Formats +#define BLAST_XML 100 +#define BLAST_TXT 101 + +/*SWITCHES*/ + + +#define USED 1 +#define UNUSED 2 + + +#define TEMPLATES 1 +#define NOTEMPLATES 0 + +#define EXTEND 1 +#define RESIZE 2 + +#define SEN 0 +#define SPE 1 +#define REC 2 +#define SEN2 2 + +#define ALL 1 +#define SEGMENTS 2 +#define DIAGONALS 3 + +#define START_STATE 0 +#define END_STATE 1 + +#define KEEP_CASE 2 /*Hard set in several places*/ +#define LOWER_CASE 0 +#define UPPER_CASE 1 +#define CHANGE_CASE 3 +#define KEEP_GAP 0 +#define RM_GAP 1 + +#define KEEP_NAME 1 + +#define CHECK 0 +#define NO_CHECK 1 +#define FORCE 2 +#define STORE 3 +#define FLUSH 4 +#define DUMP 5 + + +#define ON 8 +#define OFF 9 +#define LOCKED_ON 10 +#define LOCKED_OFF 11 + +#define YES 12 +#define NO 13 +#define MAYBE 14 + +#define NEVER 15 +#define ALWAYS 16 +#define SOMETIMES 17 + +#define UPPER 18 +#define LOWER 19 +#define DELETE 20 +#define SWITCHCASE 21 + +#define VECTOR 22 +#define NON_VECTOR 23 +#define NON_PROFILE 24 +#define BOOTSTRAP 25 + +#define HEADER 26 +#define NO_HEADER 27 + +#define VERY_VERBOSE 28 +#define VERBOSE 29 +#define SHORT 30 +#define VERY_SHORT 31 + +#define OVERLAP 32 +#define NO_OVERLAP 33 + +#define PRINT 34 +#define NO_PRINT 35 + +#define FREE_ALN 36 +#define DECLARE_ALN 37 +#define EXTRACT_ALN 38 +#define CLEAN 39 +#define INTERACTIVE 40 +#define NON_INTERACTIVE 41 +#define PAD 42 +#define NO_PAD 43 + +#define SET 44 +#define UNSET 45 +#define RESET 48 +#define ISSET 49 +#define GET 50 + +#define ENV 52 +#define LLOCK 53 +#define LERROR 54 +#define LWARNING 55 +#define LSET 56 +#define LRESET 57 +#define LCHECK 58 +#define LREAD 59 +#define LRELEASE 60 + +#define RETURN_ON_FAILURE 61 +#define EXIT_ON_FAILURE 62 +#define IGNORE_FAILURE 63 + +#define _START 64 +#define _TERM 65 + +#define GOP 0 +#define GCP 1 +#define GEP 2 + +#define BOTTOM 0 +#define TOP 1 + +#define FORWARD -1 +#define BACKWARD 1 + +#define GO_LEFT -1 +#define GO_RIGHT 1 + +#define LOCAL 1 +#define GLOBAL 2 +#define LALIGN 3 +#define MOCCA 4 + +#define TRUE 1 +#define FALSE 0 + +#define NEW 1 +#define OLD 0 + +#define RANDOM 0 +#define DETERMINISTIC 1 + +#define GREEDY 1 +#define NON_GREEDY 0 + +#define IS_FATAL 1 +#define IS_NOT_FATAL 0 +#define NO_REPORT 2 +#define INSTALL 3 +#define INSTALL_OR_DIE 4 + +#define OPTIONAL 1 +#define NON_OPTIONAL 0 + +#define GV_MAXIMISE 1 +#define GV_MINIMISE 0 + +#define MAXIMISE 1 +#define MINIMISE 0 + +#define ALLOWED 0 +#define FORBIDEN -99999999 +#define END_ARRAY -99999990 +#define SOFT_COPY 1 +#define HARD_COPY 2 + +#define VERY_SLOW 0 +#define SLOW 1 +#define FAST 2 +#define VERY_FAST 3 +#define SUPER_FAST 4 +#define ULTRA_FAST 5 + +#define CODE 1 +#define DECODE 2 +#define CODELIST 3 + +/*Identity measure*/ +#define UNGAPED_POSITIONS 1 +#define ALIGNED_POSITIONS 2 +#define AVERAGE_POSITIONS 3 +#define NOMATRIX NULL +#define NOGROUP NULL +#define NOALN NULL + +/*SIZE DEFINITIONS*/ +#define SIZE_OF_INT 10 +#define UNDEFINED FORBIDEN +#define UNDEFINED_INT UNDEFINED +#define UNDEFINED_FLOAT UNDEFINED +#define UNDEFINED_DOUBLE UNDEFINED +#define UNDEFINED_CHAR 125 +#define UNDEFINED_SHORT -125 +#define UNDEFINED_2 0 +#define UNDEFINED_RESIDUE '>' + + + +#define FACTOR 1 +#define MAX_N_SEQ 1 +#define MAX_N_ALN 1 +#define MAX_LEN_ALN 1 +#define MAX_N_LIST 100 + +#define COMMENT_SIZE 1000 +#define MAXNAMES 100 +#define FILENAMELEN 500 /* Max. file name length */ +#define MAX_N_PARAM 2000 +#define MAX_PARAM_LEN 200 +#define MAX_LINE_LENGTH 10000 +#define ALN_LINE_LENGTH 50 +#define SHORT_STRING 10 +#define STRING 300 +#define LONG_STRING 1000 +#define VERY_LONG_STRING 10000 + +#define AA_ALPHABET "acdefghiklmnpqrstvwy-ACDEFGHIKLMNPQRSTVWY" +#define DNA_ALPHABET "AGCTUNRYMKSWHBVD-agctunrymkswhbvd" +#define RNAONLY_ALPHABET "Uu" +#define BLAST_AA_ALPHABET "arndcqeghilkmfpstwyvbzx*" +#define NAMES_ALPHABET "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_|�-!%@&#-+=." + +#define SIZEOF_AA_MAT 60 +#define GAP_LIST "-.#*~" +#define SSPACE " " + +#define MATCH 1 +#define UNALIGNED 2 +#define GAP 3 + +#define MNE 3 +#define CODE4PROTEINS 10 +#define CODE4DNA 20 + +#define STOCKHOLM_CHAR 'z' +#define STOCKHOLM_STRING "z" + + +/*CODE SHORT CUTS*/ + +/*1-COMMAND LINE PROCESSING*/ +#define GET_COMMAND_LINE_INFO ((strncmp ( argv[1], "-h",2)==0)||(strncmp ( argv[1], "-man",4)==0)||(strncmp ( argv[1], "-",1)!=0)) +#define NEXT_ARG_IS_FLAG ((argc<=(a+1)) ||(( argv[a+1][0]=='-') && !(is_number(argv[a+1])))) + + +/*UTIL MACROS*/ +#define BORDER(p1,l1,p2,l2) ((p1==0 || p2==0 || p1==l1 || p2==l2)?1:0) +#define GET_CASE(f,c) ((f==UPPER_CASE)?toupper(c):((f==LOWER_CASE)?tolower(c):c)) + +#define SWAP(x,y) {x=x+y;y=x+y; x=y-x; y=y-2*x;} +#define SWAPP(x,y,tp) {tp=y;y=x;x=tp;} + +#define MAX(x, y) (((x) >(y)) ? (x):(y)) +#define MAX2(x, y) (((x) >(y)) ? (x):(y)) +#define MAX3(x,y,z) (MAX(MAX(x,y),z)) +#define MAX4(a,b,c,d) (MAX(MAX(a,b),MAX(c,d))) +#define MAX5(a,b,c,d,e) (MAX2((MAX3(a,b,c)),(MAX2(d,e)))) +#define MAX6(a,b,c,d,e,f) (MAX2((MAX3(a,b,c)),(MAX3(c,d,e)))) + +#define MIN(x, y) (((x) <(y)) ? (x):(y)) +#define FABS(x) ((x<0)?(-x):(x)) +#define is_defined(x) ((x==UNDEFINED)?0:1) +#define a_better_than_b(x,y,m) ((m==1)?(((x)>(y))?1:0):(((x)<(y))?1:0)) +#define is_in_range(x,min,max) ((x>=min && x<=max)?1:0) +/*#define bod_a_b(x,y,m) ((m==1)?(MAX((x),(y))):(MIN((x),(y)))) +#define bo_a_b(x,y,m) ((x==UNEFINED)?y:((y==UNDEFINED)?x:bod_a_b(y,y,m))) +#define best_of_a_b(x,y,m) ((x==UNDEFINED && y==UNDEFINED)?(UNDEFINED):(bo_a_b(x,y,m))) +*/ + + +#define DIE(x) HERE(x);exit(0); +#define best_of_a_b(x,y,m) ((m==1)?(MAX((x),(y))):(MIN((x),(y)))) + +#define strm(x,y) ((vstrcmp((x),(y))==0)?1:0) +#define strnm(x,y,n) ((vstrncmp((x),(y),(n))==0)?1:0) +#define strm2(a,b,c) (strm(a,b) || strm(a,c)) +#define strm3(a,b,c,d) (strm2(a,b,c) || strm(a,d)) +#define strm4(a,b,c,d,e) (strm2(a,b,c) || strm2(a,d,e)) +#define strm5(a,b,c,d,e,f) (strm2(a,b,c) || strm3(a,d,e,f)) +#define strm6(a,b,c,d,e,f,g) (strm3(a,b,c,d) || strm3(a,e,f,g)) +#define declare_name(x) (x=vcalloc (MAX(FILENAMELEN,L_tmpnam)+1, sizeof (char))) +#define is_parameter(x) (x[0]=='-' && !isdigit(x[1])) + +/*Freing functions*/ +#define free_2(a, b) free(a);free(b) +#define free_1(a) free(a) +#define free_3(a, b, c) free_2(a,b);free_1(c) +#define free_4(a, b, c,d) free_2(a,b);free_2(c,d) +#define free_5(a, b, c,d,e) free_3(a,b,e);free_2(c,d) +#define free_6(a, b, c,d,e,f) free_3(a,b,e);free_3(c,d,f) +#define free_7(a, b, c,d,e,f,g) free_3(a,b,e);free_4(c,d,f,g) +/*2-FILE PARSING*/ +#define SEPARATORS "\n \t,;" +#define LINE_SEPARATOR "\n#TC_LINE_SEPARATOR\n" +#define TC_REC_SEPARATOR "#### TC REC SEPARATOR ###" + +/*END 1-*/ + + +/*WIDOWS/UNIX DISTINCTIONS +#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) || defined(__MSDOS__) || defined(__DOS__) || defined(__NT__) || defined(__WIN32__) +#define WIN32 +#define TO_NULL_DEVICE " >nul" +#define NULL_DEVICE "nul" +#define CWF "/" +#else +#define TO_NULL_DEVICE " >/dev/null 2>&1" +#define NULL_DEVICE "/dev/null" +*/ + +#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) || defined(__MSDOS__) || defined(__DOS__) || defined(__NT__) || defined(__WIN32__) +#define WIN32 +#define TO_NULL_DEVICE " >>t_coffee.log" +#define NULL_DEVICE "t_coffee.log" +#define CWF "/" /*ClustalW Flag*/ +#else +#define TO_NULL_DEVICE " >>/dev/null 2>&1" +#define NULL_DEVICE "/dev/null" + + +#define CWF "-" /*ClustaW Flag*/ +#endif + +/*Generic Data*/ +#define EMAIL "cedric.notredame@europe.com" +#define URL "http://www.tcoffee.org" + +#define PERL_HEADER "#!/usr/bin/env perl" + +//Optimize the Score Computation in DP +#define TC_SCORE_2(x,y) (SCORE_K*CL->M[Aln->seq_al[l_s[0][0]][x]-'A'][Aln->seq_al[l_s[1][0]][y]-'A']-SCORE_K*CL->nomatch) +#define TC_SCORE_N(x,y) ((CL->get_dp_cost)(Aln, pos, ns[0], l_s[0], x, pos, ns[1], l_s[1], y, CL)) +#define TC_SCORE(x,y) ((CL->get_dp_cost==slow_get_dp_cost && CL->evaluate_residue_pair==evaluate_matrix_score && ns[0]+ns[1]==2 && x>=0 && j>=0)? (TC_SCORE_2(x,y)):(TC_SCORE_N(x,y))) + +#define NULL_2 NULL,NULL +#define NULL_3 NULL_2,NULL +#define NULL_4 NULL_2,NULL_2 +#define NULL_5 NULL_3,NULL_2 +#define NULL_6 NULL_4,NULL_2 +#define NULL_7 NULL_5,NULL_2 +typedef struct + { + char *mode; + char *comments; + int nseq; + char **seq_name; + float **PW_SD; + float **PW_ID; + float *SEQ_W; + }Weights; + +typedef struct + { + int **list; + int tot_list; + int **stem; + int tot_stem; + int n_fields; + int nseq; + int *len; + int ***struc; + struct Sequence *S; + }Structure; + +struct Sequence + { + char **file; /* file[Nseq][FILENAMELEN] name of the file that contributed each sequence*/ + char **seq_comment; /* seq_comment[Nseq][LONG_STRING] comment read in the file */ + char **aln_comment; /*id*/ + char **seq; /*seq[Nseq][sequence] sequences*/ + int *len; /*len[Nseq] length of each sequence*/ + int max_len; /*Lenght of the longest seq */ + int min_len; /*Length of the shortest seq*/ + int nseq; /*nseq*/ + int max_nseq; /*Maximum number of sequences in the datastruct*/ + char **name; /*name[Nseq][MAXNAMELEN]*/ + int **dc; /*coordinates on the disk. Coordinates set if seq[i]==NULL*/ +/*Constraint list*/ + struct Constraint_list *CL; + int contains_gap; /*set to 1 if gaps are to be kept*/ + char *type; /*PROTEIN, DNA*/ + Weights *W; /*Associated weights*/ + char template_file[FILENAMELEN+1]; + struct Template **T; + + +}; +typedef struct Sequence Sequence; + +//_E_ +struct Template +{ + char seq_type[10]; + struct X_template *P;//PDB structure + struct X_template *F;//RNA secondary structure + struct X_template *S;//sequence + struct X_template *R;//Profile + struct X_template *G;//Genomic structure + struct X_template *T;//transmembrane + struct X_template *E;//secondary structure + struct X_template *U;//Unicode, strings + + struct X_template *RB; +}; +typedef struct Template Template; +//_E_ +struct X_template +{ + char seq_name[FILENAMELEN+1]; + char template_type[FILENAMELEN+1]; + char template_format[100]; + char template_name[FILENAMELEN+1]; + char template_file[FILENAMELEN+1]; + + struct P_template *VP; + struct F_template *VF; + struct S_template *VS; + struct R_template *VR; + struct G_template *VG; + struct T_template *VT; + struct E_template *VE; + struct U_template *VU; + + +}; +typedef struct X_template X_template; + +// +struct P_template +{ + char pdb_id[100]; +}; +typedef struct P_template P_template; + +//RNA secondary Structure +struct F_template +{ + int l; +}; +typedef struct F_template F_template; + + +struct S_template +{ + Sequence *S; +}; +typedef struct S_template S_template; + +//Prile associated with a sequence +struct R_template +{ + struct Alignment *A; +}; +typedef struct R_template R_template; + +//Genomic Information +struct G_template +{ + Sequence *S; +}; +typedef struct G_template G_template; + + +struct T_template +{ + Sequence *S; +}; +typedef struct T_template T_template; + +//_E_ +struct E_template +{ + Sequence *S; +}; +typedef struct E_template E_template; + +struct U_template +{ + int *list; +}; +typedef struct U_template U_template; + + +typedef struct + { + int max_len; + int alp_size; + char *alphabet; + int **count3; + int **count; + int **count2; + }Profile; + +struct Alignment + { +/*Size*/ + int max_len; + int min_len; + int * len; + //int *weight; + int declared_len; + int max_n_seq; + int nseq; + int len_aln; +/*Generic Information*/ + char *generic_comment; +/*Sequence Information*/ + char **file; + char **seq_comment; + char **aln_comment; + char **name; + + char **expanded_order; + char **tree_order; + char **seq_al; + + int **order; + Profile *P; + Sequence *S; + struct Dp_Result *Dp_result; + struct Constraint_list *CL; + + int **seq_cache; /*Contains the index of the residues: + The sequence Numbering is relative to the sequences, and not to the alignmnent + + seq_cache[0][1]=3 + indicates that in the aln residue (0)1 corresponds to [order[0][0]][3] + residues: 1...N + Sequences 0...M + */ + int **cdna_cache; /*Contains the information about wheather a nucleotide is coding or not*/ + /*Only defined if used */ + + +/*Weight*/ + float *col_weight; + float *seq_weight; + float **res_weight; +/*Score*/ + int * score_seq; + int ** score_res; + int score_aln; + int score; + int ibit; + int cpu; + int finished; + +/*Input/Output Options*/ + int output_res_num; + int residue_case; /*1 for lower, 0 for Upper, 2 for keeping unchanged*/ + int expand; + int output_tm; +/*Must Not be copied*/ + int used; + int num; + int **pos; +/*For linked lists*/ + struct Alignment * A; + /*Misc*/ + int random_tag; + + }; + +typedef struct Alignment Alignment; +typedef struct + { + int in_seq; + FILE *fp; + int font; + int x0; + int y0; + int x; + int y; + int n_pages; + int max_line_ppage; + int n_line; + int line; + int eop; + int in_html_span; + char previous_html_color[100]; + + } +FILE_format; + +typedef struct + { + float r; + float g; + float b; + char html_color[30]; + char html_color_class[30]; + int ascii_value; + } +Color; + + +Sequence * fill_sequence_struc ( int nseq, char **sequences, char **seq_name); +Sequence * cw_read_sequences ( char *seq_name); +Sequence * get_sequence_type (Sequence *S); +char * get_array_type (int n, char **s); +Alignment* get_aln_type (Alignment *A); + +char * get_string_type (char *string); + +char *store_mode (char *val); +char *retrieve_mode (); +char *unset_mode (); +char *set_mode (int mode, char *val); + +char *store_seq_type (char *val); +char *retrieve_seq_type (); +char *unset_seq_type (); +char *set_seq_type (int mode, char *val); + +void get_sequence (char *seq_file,int *NSEQ, char ***SEQ, char ***SN, int **sl, int *min, int *max); + +int ** get_matrix ( char *name, char *format); +int ** read_matrice (char *mat_name); +int **neg_matrix2pos_matrix ( int **matrix); + + +void print_aln ( Alignment *B); + +int output_reliability_ps ( Alignment *B,Alignment *S, char *name); +int output_reliability_pdf ( Alignment *B,Alignment *S, char *name); +int output_reliability_html ( Alignment *B,Alignment *S, char *name); +int output_color_ps ( Alignment *B,Alignment *S, char *name); +int output_color_pdf ( Alignment *B,Alignment *S, char *name); +int output_color_html ( Alignment *B,Alignment *S, char *name); +int output_hit_color_html (Alignment *B, float **ffPScoreTable, int nl, char *name); //JM_ADD +void output_hit_matrix(char *fileName, float **ffpHitScoreMatrix, int nl); //JM_ADD +void get_rgb_values(int val, Color *C); +int output_reliability_format ( Alignment *B,Alignment *S, char *name, \ +FILE_format *(*vfopen_format) ( char *),\ +FILE_format *(*print_format_string) ( char * ,Color *, Color *, FILE_format*),\ +FILE_format *(*print_format_char) ( int ,Color *, Color *, FILE_format*),\ +void (*get_rgb_values_format) ( int ,Color *),\ +FILE_format* (*vfclose_format) ( FILE_format *)); +int output_score_format ( Alignment *B,Alignment *S, char *name, \ +FILE_format *(*vfopen_format) ( char *),\ +FILE_format *(*print_format_string) ( char * ,Color *, Color *, FILE_format*),\ +FILE_format *(*print_format_char) ( int ,Color *, Color *, FILE_format*),\ +void (*get_rgb_values_format) ( int ,Color *),\ +FILE_format* (*vfclose_format) ( FILE_format *)); + + +FILE_format * print_ps_string ( char *s , Color *box, Color *ink, FILE_format *f); +FILE_format * print_ps_char ( int c, Color *box, Color *ink, FILE_format *f); + + + +void get_rgb_values_ps ( int val, Color *C); +FILE_format* vfopen_ps ( char *name); +FILE_format* vfclose_ps ( FILE_format *fps); + +FILE_format *print_html_string( char *s, Color *box, Color *ink, FILE_format *fhtml); +FILE_format * print_html_char ( int c, Color *box, Color *ink, FILE_format *f); +void get_rgb_values_html ( int val, Color *C); +FILE_format* vfopen_html ( char *name); +FILE_format* vfclose_html ( FILE_format *fhtml); + +int output_reliability_ascii ( Alignment *B,Alignment *S, char *name); +int output_color_ascii ( Alignment *B,Alignment *S, char *name); + +FILE_format *print_ascii_string( char *s, Color *box, Color *ink, FILE_format *fascii); +FILE_format * print_ascii_char ( int c, Color *box, Color *ink, FILE_format *f); +void get_rgb_values_ascii ( int val, Color *C); + +FILE_format* vfopen_ascii ( char *name); +FILE_format* vfclose_ascii ( FILE_format *fascii); +int output_seq_reliability_ascii ( Alignment *B,Alignment *S, char *name); +/*********************CLUSTALW.H*********************************************/ +/****************************************************************************/ + + /* + Main header file for ClustalW. Uncomment ONE of the following 4 lines + depending on which compiler you wish to use. + */ + +#define VMS 1 /*VAX or ALPHA VMS */ + +/*#define MAC 1 Think_C for MacIntosh */ + +/*#define MSDOS 1 Turbo C for PC's */ + +/*#define UNIX 1 Ultrix/Decstation, Gnu C for + Sun, IRIX/SGI, OSF1/ALPHA */ + +/***************************************************************************/ +/***************************************************************************/ + + + + + +#define MAXTITLES 60 /* Title length */ + + +#define UNKNOWN 0 +#define EMBLSWISS 1 +#define PIR 2 +#define PEARSON 3 +#define GDE 4 +#define CLUSTAL 5 /* DES */ +#define MSF 6 /* DES */ +#define USER 7 /* DES */ + +#define PAGE_LEN 22 /* Number of lines of help sent to screen */ + +#ifdef VMS /* Defaults for VAX VMS */ +#define DIRDELIM ']' /* Last character before file name in full file + specs */ +#define SEQ_MAX_LEN 10000 /* Max Sequence Length */ +#define MAXN 500 /* Max Number of Sequences */ +#define FSIZE 25000 /* Work space for pairwise alignments */ +#define MAXTREE 5000 /* Max Nodes for phylogenetic tree */ +#define LINELENGTH 60 /* Output line length */ +#define GCG_LINELENGTH 50 /* Output line length for GCG output */ + +#elif MAC +#define DIRDELIM ':' +#define SEQ_MAX_LEN 1000 +#define MAXN 30 +#define FSIZE 5000 +#define MAXTREE 1000 +#define LINELENGTH 50 +#define GCG_LINELENGTH 50 + + +#elif MSDOS +#define DIRDELIM '\\' +#define SEQ_MAX_LEN 1300 +#define MAXN 30 +#define FSIZE 5000 +#define MAXTREE 1000 +#define LINELENGTH 50 +#define GCG_LINELENGTH 50 + +#elif UNIX +#define DIRDELIM '/' +#define SEQ_MAX_LEN 10000 +#define MAXN 500 +#define FSIZE 25000 +#define MAXTREE 5000 +#define LINELENGTH 60 +#define GCG_LINELENGTH 50 +#endif + +#define NUMRES 26 /* max size of comparison matrix */ + +#define INPUT 0 +#define ALIGNED 1 + +#define LEFT 1 +#define RIGHT 2 + +#define NODE 0 +#define LEAF 1 + +#define GAPCOL 32 /* position of gap open penalty in profile */ +#define LENCOL 33 /* position of gap extension penalty in profile */ + +typedef struct node { /* phylogenetic tree structure */ + struct node *left; + struct node *right; + struct node *parent; + float dist; + int leaf; + int order; + char name[64]; +} stree, *treeptr; + +void *ckalloc(size_t); +void * ckvrealloc(void *,size_t); +void ckfree(void *); + +int readseqs(char *saga_file,char ***SAGA_SEQ, char*** SAGA_NAMES, int ***SAGA_LEN) ;/*first_seq is the #no. of the first seq. to read */ + + +typedef struct treesim{ + float w; + float uw; + float d; + + float max_w; + float max_uw; + float max_d; + + int rf; + int n;//n nodes; + int nseq;// nseq in the common subset + }Tree_sim; + + +typedef struct tnode *NT_node; + +/** +* Node of a tree +*/ +typedef struct tnode{ + int visited; + char *name; + char *file; + + ///The parent node + NT_node parent; + ///Left child node + NT_node left; + ///Right child node + NT_node right; + NT_node bot; + /// is leaf? + int isseq; + int seq; + int maxnseq; + int nseq; + + ///contains a list of the sequences + int *lseq; + ///contains a coded version of the node: 10010101 + int *lseq2; + ///contains distances to the root, in nodes + int *idist; + ///contains real distances *1000 + int *ldist; + float dist; + float bootstrap; + float dp; + int order; + int aligned; + ///Number of leave below the considered node + int leaf; + ///Number of nodes below the considered node + int node; + int group; + float score; + int align; + char *seqal; + int index; + int fork; + }Treenode; + +typedef struct split_struc Split; + +typedef struct split_struc{ + char *split; + int n; + int tot; + float score; + char **tlist;//Not used yet + Sequence *S; + NT_node *L; +}Split_struc; + +NT_node main_prune_tree ( NT_node T, Sequence *S); +NT_node prune_tree ( NT_node T, Sequence *S); +/*********************************************************************/ +/* */ +/* dpa_tree_manipulation */ +/* */ +/* */ +/*********************************************************************/ +char *tree2Ngroup (Alignment *A, NT_node T, int max_n, char *fname, char *mat4dist); +int tree2group_file ( NT_node T,Sequence *S, int maxnseq, int minsim, char *name); + +NT_node seq2dpa_tree (Sequence *S, char *align_mode); +NT_node tree2dpa_tree (NT_node T, Alignment *A, char *matrix4distance); +FILE * tree2group ( NT_node T,Sequence *S,int maxnseq, int mindist,char *name, FILE *fp); + + +NT_node tree2collapsed_tree (NT_node T, int n, char **string); + +/*********************************************************************/ +/* */ +/* tree comparison */ +/* */ +/* */ +/*********************************************************************/ +int main_compare_cog_tree (NT_node T1, char *cogfile); +int main_compare_aln_tree (NT_node T1, Alignment *A, FILE *fp); +int compare_aln_tree (NT_node T, Alignment *A, int *n, FILE *fp); + +int main_compare_splits (NT_node T1, NT_node T2, char *mode, FILE *fp); +Tree_sim * tree_cmp( NT_node T1, NT_node T2); +NT_node tree_scan (Alignment *A,NT_node RT, char *pscan, char *ptree); + +int print_node_list (NT_node T, Sequence *S); +NT_node main_compare_trees ( NT_node T1, NT_node T2, FILE *fp); +NT_node main_compare_trees_list ( NT_node T1, Sequence *S, FILE *fp); + +float compare_trees ( NT_node T1, NT_node T2, int nseq, int mode); +float search_node ( NT_node B, NT_node T, int nseq, int mode); +float evaluate_node_similarity ( NT_node B, NT_node T, int nseq, int mode); + +int compare_node ( int *b1, int *b2, int n); +void display_node (NT_node N, char *string,int nseq); +NT_node index_tree_node (NT_node T); +NT_node simple_recode_tree (NT_node T, int nseq); +NT_node recode_tree ( NT_node T, Sequence *S); +int compare_branch2 ( int *b1, int *b2, int n); + +/*********************************************************************/ +/* */ +/* FJ_tree Computation */ +/* */ +/* */ +/*********************************************************************/ +NT_node similarities_file2tree (char *mat); +NT_node tree_compute ( Alignment *A, int n, char ** arg_list); +static NT_node compute_std_tree (Alignment *A, int n, char **arg_list); +NT_node compute_std_tree_2 (Alignment *A, int **s, char *arg_list); +NT_node aln2fj_tree(NT_node T, Alignment *A, int limit,char* mode); +Alignment * filter_aln4tree (Alignment *A, int n,int fg,char* mode); + +/*********************************************************************/ +/* */ +/* Tree Filters and MAnipulation */ +/* */ +/* */ +/*********************************************************************/ +int tree2star_nodes (NT_node R, int n_max); +NT_node aln2tree (Alignment *A); +NT_node reset_boot_tree ( NT_node R, int n); +NT_node tree_dist2normalized_tree_dist ( NT_node R, float max); +NT_node reset_dist_tree ( NT_node R, float n); +NT_node* free_treelist ( NT_node *R); +NT_node free_tree ( NT_node R); +NT_node realloc_tree( NT_node R, int n); +NT_node free_tree_node ( NT_node R); + +Sequence * tree2seq (NT_node R, Sequence *S); +NT_node rename_seq_in_tree ( NT_node R, char ***list); + +NT_node balance_tree (NT_node); +int tree2nseq ( NT_node R); +int tree_file2nseq ( char *file); + +int tree2nleaf ( NT_node R); +int tree2nnode ( NT_node R); +int tree2_nnode_unresolved (NT_node R, int *l); + +FILE* display_tree ( NT_node R, int n, FILE *fp); +void clear_tree (NT_node T); +int display_leaf ( NT_node T, FILE *fp); +int display_leaf_below_node ( NT_node T, FILE *fp); +NT_node display_leaf_nb (NT_node T, int n, FILE *fp, char *name); +NT_node display_splits (NT_node T,Sequence *S, FILE *fp); +int tree2split_list (NT_node T, int nseq, int **split_list, int *n); + +NT_node reroot_tree ( NT_node TREE, NT_node T); +NT_node straighten_tree ( NT_node P, NT_node C, float new_dist); +NT_node unroot_tree ( NT_node T); +FILE* print_tree_list ( NT_node *T,char *format, FILE *fp); +FILE* print_tree ( NT_node T,char *format, FILE *fp); +char *tree2string (NT_node T); +char *tree2file (NT_node T, char *name, char *mode); + +int print_newick_tree ( NT_node T, char *name); +FILE * rec_print_tree ( NT_node T, FILE *fp); + + +NT_node find_longest_branch ( NT_node T, NT_node L); +NT_node shift_root ( NT_node R); + +int ** tree2cluster (NT_node T, float thres); +int ** make_sub_tree_list ( NT_node **T, int nseq, int n_node); +void make_all_sub_tree_list ( NT_node N, int **list, int *n); +void make_one_sub_tree_list ( NT_node T, int *list); +NT_node main_read_tree(char *treefile); + +NT_node new_read_tree ( char *teefile); +NT_node new_get_node (NT_node T, FILE *fp); + + +NT_node** simple_read_tree(char *treefile); +void free_read_tree (NT_node **BT); +NT_node** read_tree(char *treefile, int *nnodes,int nseq, char **seq_names); +FILE * create_linear_tree ( char **name, int n, FILE *fp); +FILE * create_tree(NT_node ptree, NT_node parent,int *numseq,int *ntotal,int *nnodes,NT_node **lu, FILE *fp); +NT_node declare_tree_node (int nseq); +void set_info(NT_node p, NT_node parent, int pleaf, char *pname, float pdist, float bootstrap); +NT_node insert_tree_node(NT_node pptr); +FILE * skip_space(FILE *fd); +void create_tree_node(NT_node pptr, NT_node parent); +float calc_mean(NT_node nptr, float *maxdist, int nseq,NT_node **lu); +NT_node insert_root(NT_node p, float diff); +float calc_root_mean(NT_node root, float *maxdist, int neq, NT_node **lu); +NT_node reroot(NT_node ptree, int nseq, int ntotal, int nnodes, NT_node **lu); + + +Alignment *seq2seq_chain (Alignment *A,Alignment *B, char *arg); + +float display_avg_bootstrap ( NT_node T); +float tree2tot_dist ( NT_node T, int mode); +int tree2n_branches(NT_node T, int mode); +int **display_tree_from_node (NT_node T, int up, int down, int **array); +NT_node tree2node ( char *name, NT_node T); +NT_node * tree2node_list (NT_node T, NT_node *L); +NT_node tree2root ( NT_node T); +int new_tree_sort ( char *name, NT_node T); + + +NT_node split2tree ( NT_node RT,Sequence *LIST, char *param); +NT_node * read_tree_list (Sequence *S); + +int count_groups( Sequence *S, char *s); + +Split ** count_splits( NT_node RT, Sequence *S, char *s); +NT_node *treelist2prune_treelist (Sequence *S, Sequence *TS, FILE *out); +int** treelist2groups (Sequence *S, Sequence *ST, char *depth, FILE *out); +int treelist2splits (Sequence *S, Sequence *ST); +int treelist2leafgroup ( Sequence *S, Sequence *TS, char *taxon); +int ***tree2dist ( NT_node T, Sequence *S, int ***d); +int treelist2frame (Sequence *S, Sequence *TS); +int** treelist2lti ( Sequence *S, Sequence *TS, int nb, FILE *out); + +float simple_tree_cmp (NT_node T1, NT_node T2,Sequence *S, int mode); + +int treelist2dmat ( Sequence *S); +NT_node new_declare_tree_node (); +int count_tree_groups( Sequence *LIST, char *group_file); +int node_sort ( char *name, NT_node T); +int treelist2n (NT_node *L); +int ** treelist2avg_treecmp (NT_node *L, char *file); +NT_node treelist2bootstrap ( NT_node *L, char *file); +NT_node treelist2filtered_bootstrap ( NT_node *L, char *file, int **score,float f); + +Sequence * treelist2seq ( Sequence *S); +Sequence * treelist2sub_seq ( Sequence *S, int f); + +int treelist_file2consense (char *tree_file, char *outtree, char *outfile); +/* General purpose header file - rf 12/90 */ + +#ifndef _H_general +#define _H_general + + + +#define pint int /* cast ints in printf statements as pint */ +typedef int Boolean; /* Is already defined in THINK_C */ + +#undef TRUE +#undef FALSE +#define TRUE 1 +#define FALSE 0 + +#define EOS '\0' /* End-Of-String */ +#define MAXLINE 512 /* Max. line length */ + + +#endif /* ifndef _H_general */ +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/iteration.c b/binaries/src/tcoffee/t_coffee_source/iteration.c new file mode 100644 index 0000000..b0d5090 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/iteration.c @@ -0,0 +1,610 @@ + +#include +#include +#include +// #include +// #include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "fastal_lib_header.h" + + +/** + * Adds a single sequence to a profile. + * \param seq The sequence. + * \param prf The profile. + */ +void +seq2profile2(char *seq, Fastal_profile *prf, int *char2pos) +{ +// printf("SEDQ: %s\n", seq); + int **prf_in = prf->prf; + int i = -1; + --seq; + while (*(++seq) !='\0') + { + if (*seq != '-') + ++(prf_in[char2pos[*seq]][++i]); + else + ++i; +// ++seq; + } +} + + + + +// typedef struct +// { +// /// Number of sequences in this profile +// int num_sequences; +// /// number of the profile +// int prf_number; +// ///0 = combination of two profiles, 1 = profile of a single sequence -> name1 = seq_name +// int is_leaf; +// ///length of the profile +// int length; +// ///weight of the sequence +// int weight; +// ///saves the amount of allocated memory +// int allocated_memory; +// ///the profile itself [alphabet_size][profile_length] +// int **prf; +// ///number_of_sequences +// int number_of_sequences; +// } +// Fastal_profile; + + + + + +/** + * Deletes all gap columns from the profile. + * + * \param prf The profile. + * \param alphabet_size The size of the alphabet. + * \param gap_list The gap_list. + * \param gap_list_length The length of the gap list. + * \param num_gaps The number of gaps. + * \return The new gap list. + */ +int * +del_gap_from_profile(Fastal_profile *prf, int alphabet_size, int *gap_list, int *gap_list_length, int *num_gaps) +{ + int i; + int pos = -1; + int not_gap = 0; + int gap_pos = 0; + int write_pos = 0; +// int gap_counter = 0; + int **prf_in = prf->prf; + int prf_length = prf->length; + + while (gap_pos < prf_length) + { +// printf("PRF1: %i %i %i %i\n", prf_in[0][gap_pos], prf_in[1][gap_pos], prf_in[2][gap_pos], prf_in[3][gap_pos]); + + not_gap = 0; + for (i = 0; i < alphabet_size; ++i) + { + if (prf_in[i][gap_pos]) + { + not_gap = 1; +// printf("ARG: %i\n", i); + break; + } + } + if (not_gap) + { + + if (gap_pos != write_pos) + { + for (i = 0; i < alphabet_size; ++i) + { + prf_in[i][write_pos] = prf_in[i][gap_pos]; + } + } + ++write_pos; + } + else + { + + if (++pos >= *gap_list_length) + { + *gap_list_length += 10; + gap_list = vrealloc(gap_list, (*gap_list_length)*sizeof(int)); + } + gap_list[pos] = gap_pos; +// ++gap_counter; + } + ++gap_pos; + } +// printf("DEEEEEEEEEEEEEEEEEL %i %i\n", gap_counter, pos+1); + + *num_gaps = pos+1; + prf->length -= *num_gaps; + return gap_list; +} + + +/** + * Splits a given alignment according to a given position. + * \param alignment_file The alignment file. + * \param gap_prf Saves the profile with the gap sequences. + * \param no_gap_prf Saves the profile of the non gap sequences. + * \param seq A temporary place to save the sequence. + * \param index The index where to look for the gaps. + * \param char2pos The character to position translation array. + */ +void +split_set(FILE *alignment_file, Fastal_profile *gap_prf, Fastal_profile *no_gap_prf, char *seq, int index, int *char2pos, char* split_file_name) +{ + FILE *split_set_file1 = fopen("GAP", "w"); + FILE *split_set_file2 = fopen("NOGAP", "w"); +// FILE *shorted = fopen("SHORTT.fa", "w"); + printf("INDEX: %i\n",index); + fseek (alignment_file , 0 , SEEK_SET); + FILE *split_file = fopen(split_file_name, "w"); + int i,j; + const int LINE_LENGTH = 200; + char line[LINE_LENGTH]; + int pos = -1; + int overall_pos = -1; + fgets(line, LINE_LENGTH , alignment_file); +// fprintf(shorted, "%s", line); + while(fgets(line, LINE_LENGTH , alignment_file)!=NULL) + { + pos = -1; + if (line[0] == '>') + { +// fprintf(shorted, "%s", line); + if (seq[index] == '-') + { + + seq[++overall_pos] = '\0'; + fprintf(split_file, "g\n"); + fprintf(split_set_file1,"%s\n",seq); + seq2profile2(seq, gap_prf, char2pos); + ++(gap_prf->number_of_sequences); + } + else + { + seq[++overall_pos] = '\0'; + fprintf(split_file, "n\n"); + fprintf(split_set_file2,"%s\n",seq); + seq2profile2(seq, no_gap_prf, char2pos); + ++(no_gap_prf->number_of_sequences); + } + overall_pos = -1; + + } + else + { +// for (j = 35; j < 96; ++j) +// { +// fprintf(shorted, "%c", line[j]); +// } +// fprintf(shorted, "\n"); + while ((line[++pos] != '\n') && (line[pos] != '\0')) + { + seq[++overall_pos] = line[pos]; + } + } + } + + if (seq[index] == '-') + { + seq[++overall_pos] = '\0'; + fprintf(split_file, "g\n"); + seq2profile2(seq, gap_prf, char2pos); + ++(gap_prf->number_of_sequences); + } + else + { + seq[++overall_pos] = '\0'; + fprintf(split_file, "n\n"); + seq2profile2(seq, no_gap_prf, char2pos); + ++(no_gap_prf->number_of_sequences); + } + fclose(split_file); +} + + +Fastal_profile * +enlarge_prof(Fastal_profile *prof, int new_length, int alphabet_size) +{ + if (new_length > prof->allocated_memory) + { + int i; + for (i = 0;i < alphabet_size; ++i) + { + prof->prf[i] = vrealloc(prof->prf[i],new_length*sizeof(int)); + } + prof->allocated_memory = new_length; + } + return prof; +} + + + + +void +iterate(Fastal_param *param, void *method_arguments_p, char *aln_file_name, char *out_file_name_end, int iteration_number) +{ +// calculate alignment length + +//count gap + int it_coutner_2 = 0; + const int LINE_LENGTH = 200; + char line[LINE_LENGTH]; + char *seq1 = vcalloc(1,sizeof(char)); + char *seq2 = vcalloc(1,sizeof(char)); + Fastal_profile **profiles = vcalloc(3,sizeof(Fastal_profile*)); + initiate_profiles(profiles, param); + Fastal_profile *gap_prf = profiles[0]; + Fastal_profile *no_gap_prf = profiles[1]; + int alphabet_size = param->alphabet_size; + + int *gap_list_1 = vcalloc(1, sizeof(int)); + int *gap_list_1_length = vcalloc(1, sizeof(int)); + *gap_list_1_length = 1; + int num_gaps_1 = 0; + int *gap_list_2 = vcalloc(1, sizeof(int)); + int *gap_list_2_length = vcalloc(1, sizeof(int)); + *gap_list_2_length = 1; + int num_gaps_2 = 0; + + int alignment_length = 1; + //from here repeat! + int it_counter = 0; + char *out_file_name = aln_file_name; + int *gap_profile = vcalloc(alignment_length, sizeof(int)); + +// while (it_counter < alignment_length) +// { + + + FILE *alignment_file = fopen(aln_file_name,"r"); + if (alignment_file == NULL) + { + printf("Could not open alignment file %s\n", aln_file_name); + exit(1); + } + + + + alignment_length = 0; + int tmp_len = -1; + fgets(line, LINE_LENGTH , alignment_file); + while(fgets(line, LINE_LENGTH , alignment_file)!=NULL) + { + tmp_len = -1; + if (line[0] == '>') + { + break; + } + while ((line[++tmp_len] != '\n') && (line[tmp_len] != '\0')); + alignment_length += tmp_len; + } + // printf("ALN_LENGTH %i\n", alignment_length); + seq1 =vrealloc(seq1, (1+alignment_length)*sizeof(char)); + + gap_profile = vrealloc(gap_profile, alignment_length * sizeof(int)); + int i; + for (i = 0; i < alignment_length; ++i) + { + gap_profile[i] = 0; + } + + int number_of_sequences = 0; + int pos = -1; + fseek (alignment_file , 0 , SEEK_SET); + while(fgets(line, LINE_LENGTH , alignment_file)!=NULL) + { + if (line[0] == '>') + { + ++number_of_sequences; + pos = -1; + } + else + { + i = -1; + while ((line[++i] != '\n') && (line[i] != '\0')) + { + ++pos; + if (line[i] == '-') + { + ++gap_profile[pos]; + } + } + } + } + + double max_entrop = 0; + int column_index = 0; + double entrop = 0; + double last = 0; + double p; + + +// for (i = it_counter; i<=it_counter; ++i) +// { +// p = gap_profile[i]/(double)number_of_sequences; +// if (!p) +// { +// entrop = 0; +// } +// else +// { +// entrop = (-1)*(p*log(p) + (1-p)*log(1-p) ) ; +// } +// if (entrop > max_entrop) +// { +// column_index = i; +// max_entrop = entrop; +// } +// last = entrop; +// } +// ++it_counter; +// if (max_entrop < 0.6) +// { +// printf("CONTINUE %f\n",entrop); +// continue; +// } + +// column_index = 18;//it_counter-1; +// if (column_index == 19) + column_index = 58; + out_file_name = vtmpnam(NULL); + + char *edit_file_name = "EDIT";//vtmpnam(NULL); + FILE *edit_file = fopen(edit_file_name,"w"); + char *profile_file_name = vtmpnam(NULL); + FILE *profile_file = fopen(profile_file_name,"w"); + char *split_file_name = "AHA";//vtmpnam(NULL); + ++it_coutner_2; + + gap_prf = enlarge_prof(gap_prf, alignment_length, alphabet_size); + no_gap_prf = enlarge_prof(no_gap_prf, alignment_length, alphabet_size ); + no_gap_prf->number_of_sequences = 0; + gap_prf->number_of_sequences = 0; + + split_set(alignment_file, gap_prf, no_gap_prf, seq1, column_index, param->char2pos, split_file_name); + gap_prf -> length = alignment_length; + no_gap_prf -> length = alignment_length; + + + gap_list_1 = del_gap_from_profile(gap_prf, alphabet_size, gap_list_1, gap_list_1_length, &num_gaps_1 ); + gap_list_2 = del_gap_from_profile(no_gap_prf, alphabet_size, gap_list_2, gap_list_2_length, &num_gaps_2 ); + + + fclose(alignment_file); + profiles[0] = gap_prf; + profiles[1] = no_gap_prf; + + alignment_length = gotoh_dyn(profiles, param, method_arguments_p, 0, edit_file, profile_file, 0); + seq1 =vrealloc(seq1, (1+alignment_length)*sizeof(char)); + seq2 =vrealloc(seq2, (1+alignment_length)*sizeof(char)); + + fclose(edit_file); + edit_file = fopen(edit_file_name,"r"); + edit2seq_pattern(edit_file, seq1, seq2); + fclose(edit_file); + fclose(profile_file); + + write_iterated_aln(aln_file_name, out_file_name, split_file_name, seq1, gap_list_1, num_gaps_1, seq2, gap_list_2, num_gaps_2); + aln_file_name = out_file_name; + +// if (it_coutner_2 == 2) +// break; +// } + char command[1000]; + sprintf(command, "mv %s %s",out_file_name, out_file_name_end); + system(command); + + vfree(seq1); + vfree(seq2); + vfree(gap_list_1); + vfree(gap_list_2); + if (!strcmp(param->method, "fast")) + { + free_sparse((Sparse_dynamic_param*)method_arguments_p); + } + else if (!strcmp(param->method, "nw")) + { + free_nw((Nw_param*)method_arguments_p, alphabet_size); + } + else if (!strcmp(param->method, "gotoh")) + { + free_gotoh((Gotoh_param*)method_arguments_p, alphabet_size); + } +} + + + + +void +write_iterated_aln(char* old_aln_file_name, char* new_aln_file_name, char *gap_file_name, char *seq1, int *gap_list1, int num_gap1, char *seq2, int *gap_list2, int num_gap2) +{ + int i; +// for (i = 0; i < num_gap1; ++i) +// { +// printf("%i ", gap_list1[i]); +// } +// printf("\n-----\n"); +// for (i = 0; i < num_gap2; ++i) +// { +// printf("%i ", gap_list2[i]); +// } +// printf("\n"); +// +// printf("%s\n%s\n",seq1, seq2); +// printf("EX: %i\n", gap_list1[0]); + FILE *gap_file = fopen(gap_file_name, "r"); + FILE *new_aln_file = fopen(new_aln_file_name, "w"); +// if (new_aln_file == NULL) +// printf("AHA\n"); + FILE *old_aln_file = fopen(old_aln_file_name, "r"); + + const int GAPLINE_LENGTH = 5; + char gapline[GAPLINE_LENGTH]; + char *seq; + int *gap_list; + int num_gap; + + const int ALNLINE_LENGTH = 200; + char alnline[ALNLINE_LENGTH]; + + int alnline_pos = -1; + int overall_aln_pos = -1; + int pattern_pos = -1; + int gap_pos = 0; + + +// fprintf(new_aln_file, "%s", alnline); + while(fgets(gapline, GAPLINE_LENGTH , gap_file)!=NULL) + { + + //this is the sequence name + fgets(alnline, ALNLINE_LENGTH , old_aln_file); + fprintf(new_aln_file,"%s",alnline); + //getting (part if) the sequence + fgets(alnline, ALNLINE_LENGTH , old_aln_file); + if (gapline[0] == 'g') + { + seq = seq1; + gap_list = gap_list1; + num_gap = num_gap1; + } + else + { + seq = seq2; + gap_list = gap_list2; + num_gap = num_gap2; + } + overall_aln_pos = 0; + pattern_pos = 0; + gap_pos = 0; + alnline_pos = -1; + + //go along the pattern + while (seq[pattern_pos] != '\0') + { + if (seq[pattern_pos] == '-') + { + ++pattern_pos; + fprintf(new_aln_file,"-"); + continue; + } + //get next part of the sequence if you are at the end + if ((alnline[++alnline_pos] == '\n') || (alnline[alnline_pos] == '\0')) + { + alnline_pos = 0; + fgets(alnline, ALNLINE_LENGTH, old_aln_file); + } + if ((gap_pos < num_gap) && (overall_aln_pos == gap_list[gap_pos])) + { + ++gap_pos; + ++overall_aln_pos; + continue; + } + fprintf(new_aln_file,"%c",alnline[alnline_pos]); + ++overall_aln_pos; + ++pattern_pos; + } + fprintf(new_aln_file,"\n"); + } + + fclose(new_aln_file); + fclose(old_aln_file); + fclose(gap_file); +} + + +void +edit2seq_pattern(FILE *edit_file, char *seq1, char *seq2) +{ + + fseek(edit_file, 0, SEEK_SET); + const int LINE_LENGTH = 50; + char line[LINE_LENGTH]; + fgets(line, LINE_LENGTH , edit_file); +// int child1 = atoi(line); + fgets(line, LINE_LENGTH , edit_file); +// int child2 = atoi(line); + fgets(line, LINE_LENGTH , edit_file); +// int is_leaf1 = atoi(line); + fgets(line, LINE_LENGTH , edit_file); +// int is_leaf2 = atoi(line); + + char x; + int number; + int pos = -1; + while(fgets(line, LINE_LENGTH , edit_file)!=NULL) + { +// printf("%s\n",line); + x = line[0]; + if (x == '*') + break; + number = atoi(&line[1]); + if (x == 'M') + { + while (--number >= 0) + { + seq1[++pos] = 'X'; + seq2[pos] = 'X'; + } + } + else if (x == 'I') + { + while (--number >= 0) + { + seq1[++pos] = 'X'; + seq2[pos] = '-'; + } + } + else if (x == 'D') + { + while (--number >= 0) + { +// printf("POS: %i\n", pos); + seq1[++pos] = '-'; + seq2[pos] = 'X'; + } + } + } + seq1[++pos] = '\0'; + seq2[pos] = '\0'; +// printf("%s\n%s\n",seq1, seq2); +} +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/makefile b/binaries/src/tcoffee/t_coffee_source/makefile new file mode 100644 index 0000000..d2d00da --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/makefile @@ -0,0 +1,11 @@ + +t_coffee: util_constraints_list.o util_job_handling.o util_dps.o util_domain_constraints_list.o util_analyse_constraints_list.o util_aln_analyze.o aln_convertion_util.o util_declare.o hsearch.o random.o util_make_tree.o util.o reformat_struc.o reformat.o aln_compare.o io_func.o pb_util_read_sequence.o pb_util_read_seq_util.o tree_util.o util_graph_maln.o util_dp_clean_maln.o util_dp_ssec_pwaln.o util_dp_sim.o util_dp_mm_nw.o util_dp_gotoh_nw.o util_dp_suboptimal_nw.o util_dp_cdna_fasta_nw.o util_dp_generic_fasta_nw.o util_dp_fasta_nw.o util_dp_fasta_sw.o util_dp_gotoh_sw.o util_dp_est.o util_domain_dp_drivers.o util_dp_drivers.o util_domain_dp.o CUSTOM_evaluate_for_struc.o evaluate_for_struc.o evaluate_for_domain.o evaluate_dirichlet.o evaluate.o showpair.o fsa_dp.o pavie_dp.o dev1.o dev2.o dev3.o dev4.o fastal.o parttree.o tree.o diagonal.o fastal_opt_parsing.o scoring.o iteration.o t_coffee.o + $(CC) $(CFLAGS) -o t_coffee util_constraints_list.o util_job_handling.o util_dps.o util_domain_constraints_list.o util_analyse_constraints_list.o util_aln_analyze.o aln_convertion_util.o util_declare.o hsearch.o random.o util_make_tree.o util.o reformat_struc.o reformat.o aln_compare.o io_func.o pb_util_read_sequence.o pb_util_read_seq_util.o tree_util.o util_graph_maln.o util_dp_clean_maln.o util_dp_ssec_pwaln.o util_dp_sim.o util_dp_mm_nw.o util_dp_gotoh_nw.o util_dp_suboptimal_nw.o util_dp_cdna_fasta_nw.o util_dp_generic_fasta_nw.o util_dp_fasta_nw.o util_dp_fasta_sw.o util_dp_gotoh_sw.o util_dp_est.o util_domain_dp_drivers.o util_dp_drivers.o util_domain_dp.o CUSTOM_evaluate_for_struc.o evaluate_for_struc.o evaluate_for_domain.o evaluate_dirichlet.o evaluate.o showpair.o fsa_dp.o pavie_dp.o dev1.o dev2.o dev3.o dev4.o fastal.o parttree.o tree.o diagonal.o fastal_opt_parsing.o scoring.o iteration.o t_coffee.o -lm + +all: t_coffee TMalign + +clean: + rm *.o + +TMalign: + $(FCC) TMalign.f -o TMalign diff --git a/binaries/src/tcoffee/t_coffee_source/matrices.h b/binaries/src/tcoffee/t_coffee_source/matrices.h new file mode 100644 index 0000000..4e0f240 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/matrices.h @@ -0,0 +1,1009 @@ + +char *amino_acid_order = "ABCDEFGHIKLMNPQRSTVWXYZ"; + +//Jones Taylor Thornton, tm matrix, +//H JOND940101 +//D The 250 PAM transmembrane protein exchange matrix (Jones et al., 1994) +//R LIT:2006072 PMID:8112466 +//A Jones, D.T., Taylor, W.R. and Thornton, J.M. +//T A mutation data matrix for transmembrane proteins +//J FEBS Lett. 339, 269-275 (1994) +int jtttm250mt[]={ + 2, + 0, 0, + 0, 0, 6, + 0, 0, -3, 12, + 0, 0, -3, 8, 13, + -2, 0, 1, -6, -6, 5, + 1, 0, -1, 3, 3, -4, 6, + -3, 0, -1, 3, 2, -3, -3, 11, + 0, 0, -1, -3, -4, -1, -2, -4, 2, + -2, 0, -3, 3, 1, -5, -1, 4, -4, 12, + -2, 0, -1, -5, -5, 1, -4, -4, 1, -4, 3, + -1, 0, -1, -3, -3, 0, -3, -3, 1, -1, 1, 3, + -1, 0, -1, 6, 1, -4, -2, 3, -3, 5, -4, -2, 11, + 0, 0, -4, -2, -3, -4, -2, -4, -3, -4, -1, -3, -2, 11, + -2, 0, -3, 2, 7, -4, -1, 7, -4, 6, -2, -2, 3, 0, 11, + -1, 0, -1, 1, 2, -4, 0, 5, -3, 9, -3, 0, 2, -3, 6, 7, + 2, 0, 1, 0, 0, -1, 1, -2, -1, -1, -2, -2, 2, -1, -1, -1, 3, + 1, 0, 0, 0, -1, -2, 0, -2, 0, -2, -1, 0, 1, -1, -2, -1, 2, 3, + 0, 0, 0, -3, -2, -1, -1, -4, 2, -4, 0, 1, -3, -3, -4, -2, -1, 0, 2, + -4, 0, 1, -4, -3, -3, -2, -1, -3, 3, -2, -2, -3, -6, 0, 5, -3, -4, -2, 12, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -3, 0, 3, -2, -5, 2, -5, 6, -4, 1, -3, -3, -1, -5, 0, -1, 0, -3, -4, -2, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + +int blosum30mt[]={ + 4, + 0, 5, + -3, -2, 17, + 0, 5, -3, 9, + 0, 0, 1, 1, 6, + -2, -3, -3, -5, -4, 10, + 0, 0, -4, -1, -2, -3, 8, + -2, -2, -5, -2, 0, -3, -3, 14, + 0, -2, -2, -4, -3, 0, -1, -2, 6, + 0, 0, -3, 0, 2, -1, -1, -2, -2, 4, + -1, -1, 0, -1, -1, 2, -2, -1, 2, -2, 4, + 1, -2, -2, -3, -1, -2, -2, 2, 1, 2, 2, 6, + 0, 4, -1, 1, -1, -1, 0, -1, 0, 0, -2, 0, 8, + -1, -2, -3, -1, 1, -4, -1, 1, -3, 1, -3, -4, -3, 11, + 1, -1, -2, -1, 2, -3, -2, 0, -2, 0, -2, -1, -1, 0, 8, + -1, -2, -2, -1, -1, -1, -2, -1, -3, 1, -2, 0, -2, -1, 3, 8, + 1, 0, -2, 0, 0, -1, 0, -1, -1, 0, -2, -2, 0, -1, -1, -1, 4, + 1, 0, -2, -1, -2, -2, -2, -2, 0, -1, 0, 0, 1, 0, 0, -3, 2, 5, + 1, -2, -2, -2, -3, 1, -3, -3, 4, -2, 1, 0, -2, -4, -3, -1, -1, 1, 5, + -5, -5, -2, -4, -1, 1, 1, -5, -3, -2, -2, -3, -7, -3, -1, 0, -3, -5, -3, 20, + 0, -1, -2, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, -2, -1, + -4, -3, -6, -1, -2, 3, -3, 0, -1, -1, 3, -1, -4, -2, -1, 0, -2, -1, 1, 5, -1, 9, + 0, 0, 0, 0, 5, -4, -2, 0, -3, 1, -1, -1, -1, 0, 4, 0, -1, -1, -3, -1, 0, -2, 4}; + +int blosum40mt[]={ + 5, + -1, 5, + -2, -2, 16, + -1, 6, -2, 9, + -1, 1, -2, 2, 7, + -3, -3, -2, -4, -3, 9, + 1, -1, -3, -2, -3, -3, 8, + -2, 0, -4, 0, 0, -2, -2, 13, + -1, -3, -4, -4, -4, 1, -4, -3, 6, + -1, 0, -3, 0, 1, -3, -2, -1, -3, 6, + -2, -3, -2, -3, -2, 2, -4, -2, 2, -2, 6, + -1, -3, -3, -3, -2, 0, -2, 1, 1, -1, 3, 7, + -1, 4, -2, 2, -1, -3, 0, 1, -2, 0, -3, -2, 8, + -2, -2, -5, -2, 0, -4, -1, -2, -2, -1, -4, -2, -2, 11, + 0, 0, -4, -1, 2, -4, -2, 0, -3, 1, -2, -1, 1, -2, 8, + -2, -1, -3, -1, -1, -2, -3, 0, -3, 3, -2, -1, 0, -3, 2, 9, + 1, 0, -1, 0, 0, -2, 0, -1, -2, 0, -3, -2, 1, -1, 1, -1, 5, + 0, 0, -1, -1, -1, -1, -2, -2, -1, 0, -1, -1, 0, 0, -1, -2, 2, 6, + 0, -3, -2, -3, -3, 0, -4, -4, 4, -2, 2, 1, -3, -3, -3, -2, -1, 1, 5, + -3, -4, -6, -5, -2, 1, -2, -5, -3, -2, -1, -2, -4, -4, -1, -2, -5, -4, -3, 19, + 0, -1, -2, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -2, -1, -1, 0, 0, -1, -2, -1, + -2, -3, -4, -3, -2, 4, -3, 2, 0, -1, 0, 1, -2, -3, -1, -1, -2, -1, -1, 3, -1, 9, + -1, 2, -3, 1, 5, -4, -2, 0, -4, 1, -2, -2, 0, -1, 4, 0, 0, -1, -3, -2, -1, -2, 5}; + +int blosum45mt[]={ + 5, + -1, 4, + -1, -2, 12, + -2, 5, -3, 7, + -1, 1, -3, 2, 6, + -2, -3, -2, -4, -3, 8, + 0, -1, -3, -1, -2, -3, 7, + -2, 0, -3, 0, 0, -2, -2, 10, + -1, -3, -3, -4, -3, 0, -4, -3, 5, + -1, 0, -3, 0, 1, -3, -2, -1, -3, 5, + -1, -3, -2, -3, -2, 1, -3, -2, 2, -3, 5, + -1, -2, -2, -3, -2, 0, -2, 0, 2, -1, 2, 6, + -1, 4, -2, 2, 0, -2, 0, 1, -2, 0, -3, -2, 6, + -1, -2, -4, -1, 0, -3, -2, -2, -2, -1, -3, -2, -2, 9, + -1, 0, -3, 0, 2, -4, -2, 1, -2, 1, -2, 0, 0, -1, 6, + -2, -1, -3, -1, 0, -2, -2, 0, -3, 3, -2, -1, 0, -2, 1, 7, + 1, 0, -1, 0, 0, -2, 0, -1, -2, -1, -3, -2, 1, -1, 0, -1, 4, + 0, 0, -1, -1, -1, -1, -2, -2, -1, -1, -1, -1, 0, -1, -1, -1, 2, 5, + 0, -3, -1, -3, -3, 0, -3, -3, 3, -2, 1, 1, -3, -3, -3, -2, -1, 0, 5, + -2, -4, -5, -4, -3, 1, -2, -3, -2, -2, -2, -2, -4, -3, -2, -2, -4, -3, -3, 15, + 0, -1, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, -2, -1, + -2, -2, -3, -2, -2, 3, -3, 2, 0, -1, 0, 0, -2, -3, -1, -1, -2, -1, -1, 3, -1, 8, + -1, 2, -3, 1, 4, -3, -2, 0, -3, 1, -2, -1, 0, -1, 4, 0, 0, -1, -3, -2, -1, -2, 4}; + +int blosum50mt[] = { + 5, + -2, 5, + -1, -3, 13, + -2, 5, -4, 8, + -1, 1, -3, 2, 6, + -3, -4, -2, -5, -3, 8, + 0, -1, -3, -1, -3, -4, 8, + -2, 0, -3, -1, 0, -1, -2, 10, + -1, -4, -2, -4, -4, 0, -4, -4, 5, + -1, 0, -3, -1, 1, -4, -2, 0, -3, 6, + -2, -4, -2, -4, -3, 1, -4, -3, 2, -3, 5, + -1, -3, -2, -4, -2, 0, -3, -1, 2, -2, 3, 7, + -1, 4, -2, 2, 0, -4, 0, 1, -3, 0, -4, -2, 7, + -1, -2, -4, -1, -1, -4, -2, -2, -3, -1, -4, -3, -2, 10, + -1, 0, -3, 0, 2, -4, -2, 1, -3, 2, -2, 0, 0, -1, 7, + -2, -1, -4, -2, 0, -3, -3, 0, -4, 3, -3, -2, -1, -3, 1, 7, + 1, 0, -1, 0, -1, -3, 0, -1, -3, 0, -3, -2, 1, -1, 0, -1, 5, + 0, 0, -1, -1, -1, -2, -2, -2, -1, -1, -1, -1, 0, -1, -1, -1, 2, 5, + 0, -4, -1, -4, -3, -1, -4, -4, 4, -3, 1, 1, -3, -3, -3, -3, -2, 0, 5, + -3, -5, -5, -5, -3, 1, -3, -3, -3, -3, -2, -1, -4, -4, -1, -3, -4, -3, -3, 15, + -1, -1, -2, -1, -1, -2, -2, -1, -1, -1, -1, -1, -1, -2, -1, -1, -1, 0, -1, -3, -1, + -2, -3, -3, -3, -2, 4, -3, 2, -1, -2, -1, 0, -2, -3, -1, -1, -2, -2, -1, 2, -1, 8, + -1, 2, -3, 1, 5, -4, -2, 0, -3, 1, -3, -1, 0, -1, 4, 0, 0, -1, -3, -2, -1, -2, 5}; + + +int blosum55mt[]={ + 5, + -2, 5, + 0, -4, 13, + -2, 5, -4, 8, + -1, 1, -4, 2, 7, + -3, -5, -3, -5, -4, 9, + 0, -1, -3, -2, -3, -4, 8, + -2, 0, -4, -1, -1, -1, -2, 11, + -2, -4, -2, -4, -4, 0, -5, -4, 6, + -1, 0, -4, -1, 1, -4, -2, 0, -4, 6, + -2, -4, -2, -5, -4, 1, -5, -3, 2, -3, 6, + -1, -3, -2, -4, -3, 0, -3, -2, 2, -2, 3, 8, + -2, 4, -3, 2, 0, -4, 0, 1, -4, 0, -4, -3, 8, + -1, -2, -3, -2, -1, -5, -3, -3, -3, -1, -4, -3, -2, 10, + -1, 0, -4, 0, 2, -4, -2, 1, -4, 2, -3, 0, 0, -1, 7, + -2, -1, -4, -2, 0, -3, -3, 0, -4, 3, -3, -2, -1, -3, 1, 8, + 2, 0, -1, 0, 0, -3, 0, -1, -3, 0, -3, -2, 1, -1, 0, -1, 5, + 0, -1, -1, -1, -1, -3, -2, -2, -1, -1, -2, -1, 0, -1, -1, -1, 2, 6, + 0, -4, -1, -4, -3, -1, -4, -4, 4, -3, 1, 1, -4, -3, -3, -3, -2, 0, 5, + -4, -5, -4, -5, -3, 2, -3, -3, -3, -4, -3, -2, -5, -5, -2, -3, -4, -3, -4, 15, + -1, -1, -2, -2, -1, -2, -2, -1, -1, -1, -1, -1, -1, -2, -1, -1, -1, -1, -1, -3, -1, + -2, -3, -3, -3, -2, 4, -4, 2, -1, -2, -1, -1, -2, -4, -1, -2, -2, -2, -2, 3, -1, 9, + -1, 2, -4, 1, 5, -4, -3, 0, -4, 1, -3, -2, 0, -1, 4, 0, 0, -1, -3, -3, -1, -2, 5}; + +int blosum62mt[]={ + 4, + -2, 4, + 0, -3, 9, + -2, 4, -3, 6, + -1, 1, -4, 2, 5, + -2, -3, -2, -3, -3, 6, + 0, -1, -3, -1, -2, -3, 6, + -2, 0, -3, -1, 0, -1, -2, 8, + -1, -3, -1, -3, -3, 0, -4, -3, 4, + -1, 0, -3, -1, 1, -3, -2, -1, -3, 5, + -1, -4, -1, -4, -3, 0, -4, -3, 2, -2, 4, + -1, -3, -1, -3, -2, 0, -3, -2, 1, -1, 2, 5, + -2, 3, -3, 1, 0, -3, 0, 1, -3, 0, -3, -2, 6, + -1, -2, -3, -1, -1, -4, -2, -2, -3, -1, -3, -2, -2, 7, + -1, 0, -3, 0, 2, -3, -2, 0, -3, 1, -2, 0, 0, -1, 5, + -1, -1, -3, -2, 0, -3, -2, 0, -3, 2, -2, -1, 0, -2, 1, 5, + 1, 0, -1, 0, 0, -2, 0, -1, -2, 0, -2, -1, 1, -1, 0, -1, 4, + 0, -1, -1, -1, -1, -2, -2, -2, -1, -1, -1, -1, 0, -1, -1, -1, 1, 5, + 0, -3, -1, -3, -2, -1, -3, -3, 3, -2, 1, 1, -3, -2, -2, -3, -2, 0, 4, + -3, -4, -2, -4, -3, 1, -2, -2, -3, -3, -2, -1, -4, -4, -2, -3, -3, -2, -3, 11, + 0, -1, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -1, -1, 0, 0, -1, -2, -1, + -2, -3, -2, -3, -2, 3, -3, 2, -1, -2, -1, -1, -2, -3, -1, -2, -2, -2, -1, 2, -1, 7, + -1, 1, -3, 1, 4, -3, -2, 0, -3, 1, -3, -1, 0, -1, 3, 0, 0, -1, -2, -3, -1, -2, 4}; + +int blosum62mt3[]={ + 0, + -2, 0, + 0, -3, 0, + -2, 4, -3, 0, + -1, 1, -4, 2, 0, + -2, -3, -2, -3, -3, 0, + 0, -1, -3, -1, -2, -3, 0, + -2, 0, -3, -1, 0, -1, -2, 0, + -1, -3, -1, -3, -3, 0, -4, -3, 0, + -1, 0, -3, -1, 1, -3, -2, -1, -3, 0, + -1, -4, -1, -4, -3, 0, -4, -3, 2, -2, 0, + -1, -3, -1, -3, -2, 0, -3, -2, 1, -1, 2, 0, + -2, 3, -3, 1, 0, -3, 0, 1, -3, 0, -3, -2, 0, + -1, -2, -3, -1, -1, -4, -2, -2, -3, -1, -3, -2, -2, 0, + -1, 0, -3, 0, 2, -3, -2, 0, -3, 1, -2, 0, 0, -1, 0, + -1, -1, -3, -2, 0, -3, -2, 0, -3, 2, -2, -1, 0, -2, 1, 0, + 1, 0, -1, 0, 0, -2, 0, -1, -2, 0, -2, -1, 1, -1, 0, -1, 0, + 0, -1, -1, -1, -1, -2, -2, -2, -1, -1, -1, -1, 0, -1, -1, -1, 1, 0, + 0, -3, -1, -3, -2, -1, -3, -3, 3, -2, 1, 1, -3, -2, -2, -3, -2, 0, 0, + -3, -4, -2, -4, -3, 1, -2, -2, -3, -3, -2, -1, -4, -4, -2, -3, -3, -2, -3, 0, + 0, -1, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -1, -1, 0, 0, -1, -2, 0, + -2, -3, -2, -3, -2, 3, -3, 2, -1, -2, -1, -1, -2, -3, -1, -2, -2, -2, -1, 2, -1, 0, + -1, 1, -3, 1, 4, -3, -2, 0, -3, 1, -3, -1, 0, -1, 3, 0, 0, -1, -2, -3, -1, -2, 0}; + +int blosum62mt2[]={ + 0, + -2, 4, + 0, -3, 0, + -2, 4, -3, 2, + -1, 1, -4, 2, 2, + -2, -3, -2, -3, -3, 3, + 0, -1, -3, -1, -2, -3, 0, + -2, 0, -3, -1, 0, -1, -2, 2, + -1, -3, -1, -3, -3, 0, -4, -3, 2, + -1, 0, -3, -1, 1, -3, -2, -1, -3, 2, + -1, -4, -1, -4, -3, 0, -4, -3, 2, -2, 1, + -1, -3, -1, -3, -2, 0, -3, -2, 1, -1, 2, 0, + -2, 3, -3, 1, 0, -3, 0, 1, -3, 0, -3, -2, 0, + -1, -2, -3, -1, -1, -4, -2, -2, -3, -1, -3, -2, -2, 0, + -1, 0, -3, 0, 2, -3, -2, 0, -3, 1, -2, 0, 0, -1, 2, + -1, -1, -3, -2, 0, -3, -2, 0, -3, 2, -2, -1, 0, -2, 1, 0, + 1, 0, -1, 0, 0, -2, 0, -1, -2, 0, -2, -1, 1, -1, 0, -1, 1, + 0, -1, -1, -1, -1, -2, -2, -2, -1, -1, -1, -1, 0, -1, -1, -1, 1, 1, + 0, -3, -1, -3, -2, -1, -3, -3, 3, -2, 1, 1, -3, -2, -2, -3, -2, 0, 1, + -3, -4, -2, -4, -3, 1, -2, -2, -3, -3, -2, -1, -4, -4, -2, -3, -3, -2, -3, 1, + 0, -1, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -1, -1, 0, 0, -1, -2, -1, + -2, -3, -2, -3, -2, 3, -3, 2, -1, -2, -1, -1, -2, -3, -1, -2, -2, -2, -1, 2, -1, 3, + -1, 1, -3, 1, 4, -3, -2, 0, -3, 1, -3, -1, 0, -1, 3, 0, 0, -1, -2, -3, -1, -2, 4}; + + +int blosum80mt[]={ + 7, + -3, 6, + -1, -6, 13, + -3, 6, -7, 10, + -2, 1, -7, 2, 8, + -4, -6, -4, -6, -6, 10, + 0, -2, -6, -3, -4, -6, 9, + -3, -1, -7, -2, 0, -2, -4, 12, + -3, -6, -2, -7, -6, -1, -7, -6, 7, + -1, -1, -6, -2, 1, -5, -3, -1, -5, 8, + -3, -7, -3, -7, -6, 0, -7, -5, 2, -4, 6, + -2, -5, -3, -6, -4, 0, -5, -4, 2, -3, 3, 9, + -3, 5, -5, 2, -1, -6, -1, 1, -6, 0, -6, -4, 9, + -1, -4, -6, -3, -2, -6, -5, -4, -5, -2, -5, -4, -4, 12, + -2, -1, -5, -1, 3, -5, -4, 1, -5, 2, -4, -1, 0, -3, 9, + -3, -2, -6, -3, -1, -5, -4, 0, -5, 3, -4, -3, -1, -3, 1, 9, + 2, 0, -2, -1, -1, -4, -1, -2, -4, -1, -4, -3, 1, -2, -1, -2, 7, + 0, -1, -2, -2, -2, -4, -3, -3, -2, -1, -3, -1, 0, -3, -1, -2, 2, 8, + -1, -6, -2, -6, -4, -2, -6, -5, 4, -4, 1, 1, -5, -4, -4, -4, -3, 0, 7, + -5, -8, -5, -8, -6, 0, -6, -4, -5, -6, -4, -3, -7, -7, -4, -5, -6, -5, -5, 16, + -1, -3, -4, -3, -2, -3, -3, -2, -2, -2, -2, -2, -2, -3, -2, -2, -1, -1, -2, -5, -2, + -4, -5, -5, -6, -5, 4, -6, 3, -3, -4, -2, -3, -4, -6, -3, -4, -3, -3, -3, 3, -3, 11, + -2, 0, -7, 1, 6, -6, -4, 0, -6, 1, -5, -3, -1, -2, 5, 0, -1, -2, -4, -5, -1, -4, 6}; + +int pam120mt[]={ + 3, + 0, 4, + -3, -6, 9, + 0, 4, -7, 5, + 0, 3, -7, 3, 5, + -4, -5, -6, -7, -7, 8, + 1, 0, -4, 0, -1, -5, 5, + -3, 1, -4, 0, -1, -3, -4, 7, + -1, -3, -3, -3, -3, 0, -4, -4, 6, + -2, 0, -7, -1, -1, -7, -3, -2, -3, 5, + -3, -4, -7, -5, -4, 0, -5, -3, 1, -4, 5, + -2, -4, -6, -4, -3, -1, -4, -4, 1, 0, 3, 8, + -1, 3, -5, 2, 1, -4, 0, 2, -2, 1, -4, -3, 4, + 1, -2, -4, -3, -2, -5, -2, -1, -3, -2, -3, -3, -2, 6, + -1, 0, -7, 1, 2, -6, -3, 3, -3, 0, -2, -1, 0, 0, 6, + -3, -2, -4, -3, -3, -5, -4, 1, -2, 2, -4, -1, -1, -1, 1, 6, + 1, 0, 0, 0, -1, -3, 1, -2, -2, -1, -4, -2, 1, 1, -2, -1, 3, + 1, 0, -3, -1, -2, -4, -1, -3, 0, -1, -3, -1, 0, -1, -2, -2, 2, 4, + 0, -3, -3, -3, -3, -3, -2, -3, 3, -4, 1, 1, -3, -2, -3, -3, -2, 0, 5, + -7, -6, -8, -8, -8, -1, -8, -3, -6, -5, -3, -6, -4, -7, -6, 1, -2, -6, -8, 12, + -1, -1, -4, -2, -1, -3, -2, -2, -1, -2, -2, -2, -1, -2, -1, -2, -1, -1, -1, -5, -2, + -4, -3, -1, -5, -5, 4, -6, -1, -2, -5, -2, -4, -2, -6, -5, -5, -3, -3, -3, -2, -3, 8, + -1, 2, -7, 3, 4, -6, -2, 1, -3, -1, -3, -2, 0, -1, 4, -1, -1, -2, -3, -7, -1, -5, 4}; + +int pam160mt[]={ + 2, + 0, 3, + -2, -4, 9, + 0, 3, -5, 4, + 0, 2, -5, 3, 4, + -3, -4, -5, -6, -5, 7, + 1, 0, -3, 0, 0, -4, 4, + -2, 1, -3, 0, 0, -2, -3, 6, + -1, -2, -2, -3, -2, 0, -3, -3, 5, + -2, 0, -5, 0, -1, -5, -2, -1, -2, 4, + -2, -4, -6, -4, -3, 1, -4, -2, 2, -3, 5, + -1, -3, -5, -3, -2, 0, -3, -3, 2, 0, 3, 7, + 0, 2, -4, 2, 1, -3, 0, 2, -2, 1, -3, -2, 3, + 1, -1, -3, -2, -1, -4, -1, -1, -2, -2, -3, -2, -1, 5, + -1, 1, -5, 1, 2, -5, -2, 2, -2, 0, -2, -1, 0, 0, 5, + -2, -1, -3, -2, -2, -4, -3, 1, -2, 3, -3, -1, -1, -1, 1, 6, + 1, 0, 0, 0, 0, -3, 1, -1, -2, -1, -3, -2, 1, 1, -1, -1, 2, + 1, 0, -2, -1, -1, -3, -1, -2, 0, 0, -2, -1, 0, 0, -1, -1, 1, 3, + 0, -2, -2, -3, -2, -2, -2, -2, 3, -3, 1, 1, -2, -2, -2, -3, -1, 0, 4, + -5, -5, -7, -6, -7, -1, -7, -3, -5, -4, -2, -4, -4, -5, -5, 1, -2, -5, -6, 12, + 0, -1, -3, -1, -1, -3, -1, -1, -1, -1, -2, -1, 0, -1, -1, -1, 0, 0, -1, -4, -1, + -3, -3, 0, -4, -4, 5, -5, 0, -2, -4, -2, -3, -2, -5, -4, -4, -3, -3, -3, -1, -3, 8, + 0, 2, -5, 2, 3, -5, -1, 1, -2, 0, -3, -2, 1, -1, 3, 0, -1, -1, -2, -6, -1, -4, 3}; + +int pam250mt[]={ + 2, + 0, 3, + -2, -4, 12, + 0, 3, -5, 4, + 0, 3, -5, 3, 4, + -3, -4, -4, -6, -5, 9, + 1, 0, -3, 1, 0, -5, 5, + -1, 1, -3, 1, 1, -2, -2, 6, + -1, -2, -2, -2, -2, 1, -3, -2, 5, + -1, 1, -5, 0, 0, -5, -2, 0, -2, 5, + -2, -3, -6, -4, -3, 2, -4, -2, 2, -3, 6, + -1, -2, -5, -3, -2, 0, -3, -2, 2, 0, 4, 6, + 0, 2, -4, 2, 1, -3, 0, 2, -2, 1, -3, -2, 2, + 1, -1, -3, -1, -1, -5, 0, 0, -2, -1, -3, -2, 0, 6, + 0, 1, -5, 2, 2, -5, -1, 3, -2, 1, -2, -1, 1, 0, 4, + -2, -1, -4, -1, -1, -4, -3, 2, -2, 3, -3, 0, 0, 0, 1, 6, + 1, 0, 0, 0, 0, -3, 1, -1, -1, 0, -3, -2, 1, 1, -1, 0, 2, + 1, 0, -2, 0, 0, -3, 0, -1, 0, 0, -2, -1, 0, 0, -1, -1, 1, 3, + 0, -2, -2, -2, -2, -1, -1, -2, 4, -2, 2, 2, -2, -1, -2, -2, -1, 0, 4, + -6, -5, -8, -7, -7, 0, -7, -3, -5, -3, -2, -4, -4, -6, -5, 2, -2, -5, -6, 17, + 0, -1, -3, -1, -1, -2, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, 0, 0, -1, -4, -1, + -3, -3, 0, -4, -4, 7, -5, 0, -1, -4, -1, -2, -2, -5, -4, -4, -3, -3, -2, 0, -2, 10, + 0, 2, -5, 3, 3, -5, 0, 2, -2, 0, -3, -2, 1, 0, 3, 0, 0, -1, -2, -6, -1, -4, 3}; + +int pam350mt[]={ + 2, + 1, 3, + -2, -5, 18, + 1, 3, -6, 4, + 1, 3, -6, 4, 4, + -4, -5, -5, -6, -6, 13, + 2, 1, -4, 1, 1, -6, 5, + -1, 1, -4, 1, 1, -2, -2, 7, + 0, -2, -3, -2, -2, 2, -2, -2, 5, + -1, 1, -6, 1, 0, -6, -1, 1, -2, 5, + -2, -4, -7, -4, -4, 3, -4, -2, 4, -3, 8, + -1, -2, -6, -3, -2, 1, -3, -2, 3, 0, 5, 6, + 0, 2, -4, 2, 2, -4, 1, 2, -2, 1, -3, -2, 2, + 1, 0, -3, 0, 0, -5, 0, 0, -2, -1, -3, -2, 0, 6, + 0, 2, -6, 2, 3, -5, -1, 3, -2, 1, -2, -1, 1, 1, 4, + -1, 0, -4, -1, 0, -5, -2, 2, -2, 4, -3, 0, 1, 0, 2, 7, + 1, 1, 0, 1, 0, -4, 1, -1, -1, 0, -3, -2, 1, 1, 0, 0, 1, + 1, 0, -2, 0, 0, -3, 1, -1, 0, 0, -2, -1, 1, 1, 0, -1, 1, 2, + 0, -2, -2, -2, -2, -1, -1, -2, 4, -2, 3, 2, -2, -1, -2, -3, -1, 0, 5, + -7, -6,-10, -8, -8, 1, -8, -3, -6, -4, -2, -5, -5, -7, -5, 4, -3, -6, -7, 27, + 0, 0, -3, -1, 0, -2, -1, 0, 0, -1, -1, 0, 0, 0, 0, -1, 0, 0, 0, -5, -1, + -4, -4, 1, -5, -5, 11, -6, 0, 0, -5, 0, -2, -3, -6, -5, -5, -3, -3, -2, 1, -2, 14, + 0, 2, -6, 3, 3, -6, 0, 2, -2, 1, -3, -2, 2, 0, 3, 1, 0, 0, -2, -7, 0, -5, 3}; + +int md_40mt[]={ + 9, + 0, 0, + -7, 0, 16, + -6, 0,-13, 11, + -5, 0,-15, 3, 11, +-11, 0, -5,-15,-16, 13, + -3, 0, -7, -4, -4,-15, 10, + -9, 0, -6, -4, -8, -7,-10, 14, + -6, 0,-11,-12,-12, -5,-13,-11, 11, + -8, 0,-12, -8, -3,-16, -9, -6,-11, 11, + -9, 0,-10,-14,-13, -1,-14, -7, -1,-12, 9, + -6, 0, -9,-12,-11, -7,-12, -9, 1, -7, 1, 14, + -6, 0, -8, 1, -5,-12, -5, 0, -8, -1,-12, -9, 12, + -2, 0,-11,-11,-11,-11, -9, -4,-11,-10, -5,-10, -9, 12, + -7, 0,-12, -6, 0,-14, -9, 2,-12, -1, -6, -8, -5, -3, 12, + -7, 0, -5,-10, -8,-15, -4, 0,-10, 3, -9, -8, -6, -6, 0, 11, + 0, 0, -2, -6, -8, -6, -2, -6, -8, -7, -7, -8, 1, -1, -7, -5, 9, + 1, 0, -7, -8, -8,-11, -7, -7, -2, -5, -9, -2, -2, -4, -7, -6, 1, 10, + -1, 0, -7, -9, -8, -6, -8,-12, 4,-12, -2, 0,-10, -9,-11,-11, -7, -4, 10, +-14, 0, -4,-15,-15, -7, -7,-13,-13,-13, -8,-11,-14,-14,-11, -4, -9,-12,-10, 18, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +-13, 0, -2, -8,-14, 2,-13, 2, -9,-13, -9,-11, -6,-13, -9,-10, -7,-10,-11, -6, 0, 14, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +int md_120mt[]={ + 6, + 0, 0, + -3, 0, 14, + -2, 0, -7, 8, + -2, 0, -8, 5, 8, + -6, 0, -2, -9,-10, 11, + 0, 0, -3, 0, -1, -9, 8, + -4, 0, -2, -1, -3, -2, -4, 11, + -1, 0, -5, -7, -7, -1, -6, -6, 7, + -4, 0, -6, -2, 0, -9, -4, -1, -6, 8, + -4, 0, -5, -8, -8, 2, -8, -4, 2, -6, 7, + -2, 0, -5, -7, -6, -2, -6, -5, 3, -4, 3, 10, + -1, 0, -3, 3, -1, -6, -1, 2, -4, 1, -6, -5, 8, + 0, 0, -5, -5, -5, -5, -4, -1, -5, -4, -2, -5, -3, 9, + -3, 0, -6, -1, 2, -7, -4, 4, -6, 2, -3, -4, -1, 0, 9, + -3, 0, -2, -4, -3, -8, -1, 2, -6, 4, -5, -4, -2, -2, 2, 8, + 2, 0, 0, -2, -3, -3, 0, -2, -3, -3, -3, -3, 2, 1, -3, -2, 5, + 2, 0, -3, -3, -4, -6, -2, -3, 0, -2, -4, 0, 1, 0, -3, -3, 2, 6, + 1, 0, -3, -5, -5, -2, -4, -6, 5, -6, 1, 2, -5, -4, -6, -6, -3, 0, 7, + -8, 0, 0, -9, -9, -3, -3, -6, -7, -6, -4, -6, -8, -8, -6, -1, -5, -7, -6, 17, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -7, 0, 2, -4, -7, 5, -8, 4, -5, -7, -4, -6, -2, -7, -4, -5, -3, -6, -6, -2, 0, 12, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +int md_250mt[]={ + 2, + 0, 0, + -1, 0, 11, + -1, 0, -3, 5, + -1, 0, -4, 4, 5, + -3, 0, 0, -5, -5, 8, + 1, 0, -1, 1, 1, -5, 5, + -2, 0, 0, 0, 0, 0, -2, 6, + 0, 0, -2, -3, -3, 0, -3, -3, 4, + -1, 0, -3, 0, 1, -5, -1, 1, -3, 5, + -1, 0, -2, -4, -4, 2, -4, -2, 2, -3, 5, + 0, 0, -2, -3, -3, 0, -3, -2, 3, -2, 3, 6, + 0, 0, -1, 2, 1, -3, 0, 1, -2, 1, -3, -2, 3, + 1, 0, -2, -2, -2, -2, -1, 0, -2, -1, 0, -2, -1, 6, + -1, 0, -3, 0, 2, -4, -1, 3, -3, 2, -2, -2, 0, 0, 5, + -1, 0, -1, -1, 0, -4, 0, 2, -3, 4, -3, -2, 0, -1, 2, 5, + 1, 0, 1, 0, -1, -2, 1, -1, -1, -1, -2, -1, 1, 1, -1, -1, 2, + 2, 0, -1, -1, -1, -2, 0, -1, 1, -1, -1, 0, 1, 1, -1, -1, 1, 2, + 1, 0, -2, -3, -2, 0, -2, -3, 4, -3, 2, 2, -2, -1, -3, -3, -1, 0, 4, + -4, 0, 1, -5, -5, -1, -1, -3, -4, -3, -2, -3, -4, -4, -3, 0, -3, -4, -3, 15, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -3, 0, 2, -2, -4, 5, -4, 4, -2, -3, -1, -3, -1, -3, -2, -2, -1, -3, -3, 0, 0, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +int md_350mt[]={ + 1, + 0, 0, + 0, 0, 9, + 0, 0, -2, 3, + 0, 0, -2, 3, 3, + -2, 0, 1, -3, -4, 6, + 1, 0, 0, 1, 1, -3, 4, + -1, 0, 0, 0, 0, 0, -1, 3, + 0, 0, -1, -2, -2, 1, -2, -2, 3, + -1, 0, -1, 0, 1, -3, 0, 1, -2, 3, + -1, 0, -1, -3, -3, 2, -2, -1, 2, -2, 3, + 0, 0, -1, -2, -2, 1, -2, -1, 2, -2, 2, 3, + 0, 0, -1, 1, 1, -2, 0, 1, -1, 1, -2, -1, 2, + 1, 0, -1, -1, -1, -2, -1, 0, -1, -1, 0, -1, 0, 4, + -1, 0, -2, 1, 1, -2, 0, 2, -2, 2, -1, -1, 0, 0, 3, + -1, 0, 0, 0, 0, -3, 0, 1, -2, 3, -2, -1, 0, 0, 2, 3, + 1, 0, 0, 0, 0, -1, 1, 0, -1, 0, -1, -1, 1, 1, 0, 0, 1, + 1, 0, 0, 0, -1, -1, 0, -1, 0, 0, -1, 0, 0, 1, -1, 0, 1, 1, + 0, 0, -1, -2, -2, 0, -1, -2, 2, -2, 1, 2, -1, -1, -2, -2, 0, 0, 2, + -3, 0, 1, -4, -3, 0, -1, -2, -3, -2, -1, -2, -3, -3, -2, 0, -2, -3, -2, 14, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -2, 0, 2, -2, -2, 5, -3, 3, -1, -2, 0, -1, -1, -2, -1, -1, -1, -2, -2, 0, 0, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +int idmat[]={ +10, + 0, 10, + 0, 0, 10, + 0, 0, 0, 10, + 0, 0, 0, 0, 10, + 0, 0, 0, 0, 0, 10, + 0, 0, 0, 0, 0, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,10}; + +int dna_idmat[]={ +10, + -1, 10, + -1, -1, 10, + -1, -1, -1, 10, + -1, -1, -1, -1, 10, + -1, -1, -1, -1, -1, 10, + -1, -1, -1, -1, -1, -1, 10, + -1, -1, -1, -1, -1, -1, -1, 10, + -1, -1, -1, -1, -1, -1, -1, -1, 10, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,10, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,10, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,10, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,10, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,10}; + +int est_idmat[]={ +10, + -10, 10, + -10, -10, 10, + -10, -10, -10, 10, + -10, -10, -10, -10, 10, + -10, -10, -10, -10, -10, 10, + -10, -10, -10, -10, -10, -10, 10, + -10, -10, -10, -10, -10, -10, -10, 10, + -10, -10, -10, -10, -10, -10, -10, -10, 10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, 10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, 10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, 10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, 10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, 10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, 10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, 10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, 10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, 10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,10}; + +/*These are the three structure specific matrices descibed by Luthy, R., McLachlan, A.D. and Eisenberg, D. + in Proteins 10, 229-239 (1991), taken from http://www.genome.ad.jp/dbget/dbget2.html + ID: coil :LUTR910107 + ID: alpha:LUTR910108 + ID: beta :LUTR910109 +*/ +int coil_mat []={ + 11, + 0, 0, + 3, 0, 108, + 2, 0, -5, 27, + 2, 0, 7, -9, 15, +-15, 0, 3, -11, -4, 83, + 1, 0, 4, -15, -4, 2, 41, + 5, 0, 4, 108, -6, -13, -3, 55, + 27, 0, -11, 3, -2, -14, 0, -1, 49, + -9, 0, 3, 4, -21, -2, -3, -4, -7, 38, + -5, 0, 14, 7, -5, 2, 2, -6, -3, 1, 48, + -9, 0, 3, 4, -6, -16, -23, -9, -7, -1, 7, 52, + 28, 0, 1, 2, 27, 7, -5, -9, -9, 108, -15, 3, 10, +108, 0, 8, 14, 41, 0, -2, -4, -10, -3, 1, -15, 4, 58, + 10, 0, 3, -9, 3, -4, 3, 3, 8, 6, -15, 15, 5, -6, 14, + 1, 0, 10, 3, 1, 108, 5, 27, -5, -9, -9, -15, 2, 3, 2, 28, + 3, 0, -15, 3, -3, -8, -12, -5, -6, -9, -19, -14, 4, 4, -2, 7, 19, + 7, 0, 6, 3, 0, -7, 55, -18, -8, -7, 6, -20, -11, 2, -5, 4, 3, 31, +-11, 0, -6, -15, -23, -6, -4, -3, 19, -15, -6, -22, 3, -11, -4, 14, -1, -7, 37, + 4, 0, 15, 3, 2, -8, -1, -12, -22, -2, 5, -19, 14, 4, -21, 4, 0, -9, -1, 129, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 0, -4, 8, -3, -30, -6, 49, -10, -7, -12, -18, 3, 3, -6, -11, 3, 2, 2, -5, 0, 59, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +int alpha_mat []={ + 23, + 0, 0, + 5, 0, 51, + 1, 0, 4, 28, + 0, 0, 5, 1, 23, + -4, 0, 5, 1, 3, 88, + 3, 0, 5, -4, 2, 4, 37, + 7, 0, 6, 51, 3, 5, -6, 52, + 28, 0, 1, 1, 6, -21, 2, -6, 38, + 1, 0, 0, 5, 4, -2, 3, -7, -10, 34, + 4, 0, 11, 5, 4, 3, 5, -6, -19, -6, 45, + 1, 0, 4, 6, 3, -23, -5, -12, -14, -4, 9, 40, + 19, 0, 3, 0, 28, 5, 4, 1, 1, 51, -4, 1, 13, + 51, 0, 10, 11, 37, 1, 1, -6, -8, -5, 2, -22, 5, 59, + 13, 0, 1, 1, 0, 2, 4, 5, 10, 7, -5, 23, 7, 3, 11, + -1, 0, 13, 5, 3, 51, 7, 28, 4, 1, 1, -4, 1, 1, 0, 19, + 1, 0, -5, 0, -6, 2, -1, -10, -14, -9, -6, -22, 6, 3, 6, 5, 17, + 5, 0, 7, 4, 2, 3, 52, -8, -18, 3, 4, -24, 1, 4, 4, 5, 2, 14, + 1, 0, 3, -5, -5, 5, -7, -19, 7, -6, -2, -28, 4, 7, 3, 11, 2, -38, 40, + 5, 0, 23, 5, 5, 5, -6, -9, -19, -2, 3, -4, 11, 5, 4, 6, 2, -43, -8, 162, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 0, 2, 10, 3, -2, -6, 38, -14, -7, -1, -19, 0, 5, 3, 1, 4, -29, -6, -19, 0, 97, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +int beta_mat []={ + 23, + 0, 0, + 4, 0, 97, + 1, 0, -5, 49, + -1, 0, 9, -5, 31, +-16, 0, 8, -11, 6, 57, + 2, 0, 7, -16, 12, 8, 54, + 13, 0, 9, 97, 2, -30, -4, 55, + 49, 0, -11, 0, 0, -22, 2, -7, 28, +-19, 0, 0, 7, -18, 2, 17, -12, -10, 34, + -5, 0, 31, 9, 1, 7, 13, -9, -7, -3, 34, + -5, 0, 2, 9, 4, -9, -12, -17, -13, 1, 14, 25, + 40, 0, 2, -1, 49, 9, -5, -19, -5, 97, -16, 0, 15, + 97, 0, 17, 31, 54, 5, 5, -13, -34, -2, 8, -11, 7, 78, + 15, 0, 0, -19, 0, 12, 2, 8, 17, 11, -21, 31, 13, 2, 31, + -2, 0, 15, 4, 2, 97, 13, 49, -5, -5, -19, -16, 1, 0, -1, 40, + 0, 0, -21, 0, -4, -6, -5, -13, -12, -5, -23, -9, 9, 7, 0, 9, 26, + 9, 0, 11, 2, 2, 2, 55, -11, -14, -28, 12, -21, -11, 1, 1, 7, 4, 21, +-11, 0, 2, -21, -12, -2, -12, -7, 13, 2, -1, -13, 2, -10, 6, 31, 2, -22, 23, + 7, 0, 31, 8, 13, -7, -7, -15, -15, -3, 10, -31, 31, 6, -18, 9, 6, -17, -5, 133, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 12, 17, 17, -12, -9, 28, -13, -3, 0, -12, 0, 8, 4, -11, 2, -5, -5, -5, 0, 47, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +/*EXPERIMENTAL MATRICES: Blosum Series*/ +/*Blosum Series rescaled on blosum62mt, +Lambda Blosum30mt=17 +Lambda Blosum62mt=10 +Lambda Blosum80mt=4.5 +*/ + +int rblosum30mt []={ + 52, + 33, 56, + 18, 23, 113, + 33, 56, 18, 75, + 33, 33, 37, 37, 61, + 23, 18, 18, 9, 14, 80, + 33, 33, 14, 28, 23, 18, 71, + 23, 23, 9, 23, 33, 18, 18, 99, + 33, 23, 23, 14, 18, 33, 28, 23, 61, + 33, 33, 18, 33, 42, 28, 28, 23, 23, 52, + 28, 28, 33, 28, 28, 42, 23, 28, 42, 23, 52, + 37, 23, 23, 18, 28, 23, 23, 42, 37, 42, 42, 61, + 33, 52, 28, 37, 28, 28, 33, 28, 33, 33, 23, 33, 71, + 28, 23, 18, 28, 37, 14, 28, 37, 18, 37, 18, 14, 18, 85, + 37, 28, 23, 28, 42, 18, 23, 33, 23, 33, 23, 28, 28, 33, 71, + 28, 23, 23, 28, 28, 28, 23, 28, 18, 37, 23, 33, 23, 28, 47, 71, + 37, 33, 23, 33, 33, 28, 33, 28, 28, 33, 23, 23, 33, 28, 28, 28, 52, + 37, 33, 23, 28, 23, 23, 23, 23, 33, 28, 33, 33, 37, 33, 33, 18, 42, 56, + 37, 23, 23, 23, 18, 37, 18, 18, 52, 23, 37, 33, 23, 14, 18, 28, 28, 37, 56, + 9, 9, 23, 14, 28, 37, 37, 9, 18, 23, 23, 18, 0, 18, 28, 33, 18, 9, 18, 128, + 0, -1, -2, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, -2, -1, + -4, -3, -6, -1, -2, 3, -3, 0, -1, -1, 3, -1, -4, -2, -1, 0, -2, -1, 1, 5, -1, 9, + 0, 0, 0, 0, 5, -4, -2, 0, -3, 1, -1, -1, -1, 0, 4, 0, -1, -1, -3, -1, 0, -2, 4, + + +}; + + + +int rblosum62mt[]={ + 80, + 20, 80, + 40, 10, 130, + 20, 80, 10, 100, + 30, 50, 0, 60, 90, + 20, 10, 20, 10, 10, 100, + 40, 30, 10, 30, 20, 10, 100, + 20, 40, 10, 30, 40, 30, 20, 120, + 30, 10, 30, 10, 10, 40, 0, 10, 80, + 30, 40, 10, 30, 50, 10, 20, 30, 10, 90, + 30, 0, 30, 0, 10, 40, 0, 10, 60, 20, 80, + 30, 10, 30, 10, 20, 40, 10, 20, 50, 30, 60, 90, + 20, 70, 10, 50, 40, 10, 40, 50, 10, 40, 10, 20, 100, + 30, 20, 10, 30, 30, 0, 20, 20, 10, 30, 10, 20, 20, 110, + 30, 40, 10, 40, 60, 10, 20, 40, 10, 50, 20, 40, 40, 30, 90, + 30, 30, 10, 20, 40, 10, 20, 40, 10, 60, 20, 30, 40, 20, 50, 90, + 50, 40, 30, 40, 40, 20, 40, 30, 20, 40, 20, 30, 50, 30, 40, 30, 80, + 40, 30, 30, 30, 30, 20, 20, 20, 30, 30, 30, 30, 40, 30, 30, 30, 50, 90, + 40, 10, 30, 10, 20, 30, 10, 10, 70, 20, 50, 50, 10, 20, 20, 10, 20, 40, 80, + 10, 0, 20, 0, 10, 50, 20, 20, 10, 10, 20, 30, 0, 0, 20, 10, 10, 20, 10, 150, + 0, -1, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -1, -1, 0, 0, -1, -2, -1, + -2, -3, -2, -3, -2, 3, -3, 2, -1, -2, -1, -1, -2, -3, -1, -2, -2, -2, -1, 2, -1, 7, + -1, 1, -3, 1, 4, -3, -2, 0, -3, 1, -3, -1, 0, -1, 3, 0, 0, -1, -2, -3, -1, -2, 4, + + }; +int rblosum80mt[]={ +77, + 25, 72, + 36, 10, 108, + 25, 72, 5, 93, + 31, 46, 5, 51, 82, + 20, 10, 20, 10, 10, 93, + 41, 31, 10, 25, 20, 10, 87, + 25, 36, 5, 31, 41, 31, 20, 103, + 25, 10, 31, 5, 10, 36, 5, 10, 77, + 36, 36, 10, 31, 46, 15, 25, 36, 15, 82, + 25, 5, 25, 5, 10, 41, 5, 15, 51, 20, 72, + 31, 15, 25, 10, 20, 41, 15, 20, 51, 25, 56, 87, + 25, 67, 15, 51, 36, 10, 36, 46, 10, 41, 10, 20, 87, + 36, 20, 10, 25, 31, 10, 15, 20, 15, 31, 15, 20, 20, 103, + 31, 36, 15, 36, 56, 15, 20, 46, 15, 51, 20, 36, 41, 25, 87, + 25, 31, 10, 25, 36, 15, 20, 41, 15, 56, 20, 25, 36, 25, 46, 87, + 51, 41, 31, 36, 36, 20, 36, 31, 20, 36, 20, 25, 46, 31, 36, 31, 77, + 41, 36, 31, 31, 31, 20, 25, 25, 31, 36, 25, 36, 41, 25, 36, 31, 51, 82, + 36, 10, 31, 10, 20, 31, 10, 15, 62, 20, 46, 46, 15, 20, 20, 20, 25, 41, 77, + 15, 0, 15, 0, 10, 41, 10, 20, 15, 10, 20, 25, 5, 5, 20, 15, 10, 15, 15, 124, + -1, -3, -4, -3, -2, -3, -3, -2, -2, -2, -2, -2, -2, -3, -2, -2, -1, -1, -2, -5, -2, + -4, -5, -5, -6, -5, 4, -6, 3, -3, -4, -2, -3, -4, -6, -3, -4, -3, -3, -3, 3, -3, 11, + -2, 0, -7, 1, 6, -6, -4, 0, -6, 1, -5, -3, -1, -2, 5, 0, -1, -2, -4, -5, -1, -4, 6, +}; +int rpam120mt[]={ + 52, + 38, 57, + 24, 9, 81, + 38, 57, 4, 62, + 38, 52, 4, 52, 62, + 19, 14, 9, 4, 4, 77, + 43, 38, 19, 38, 33, 14, 62, + 24, 43, 19, 38, 33, 24, 19, 72, + 33, 24, 24, 24, 24, 38, 19, 19, 67, + 28, 38, 4, 33, 33, 4, 24, 28, 24, 62, + 24, 19, 4, 14, 19, 38, 14, 24, 43, 19, 62, + 28, 19, 9, 19, 24, 33, 19, 19, 43, 38, 52, 77, + 33, 52, 14, 48, 43, 19, 38, 48, 28, 43, 19, 24, 57, + 43, 28, 19, 24, 28, 14, 28, 33, 24, 28, 24, 24, 28, 67, + 33, 38, 4, 43, 48, 9, 24, 52, 24, 38, 28, 33, 38, 38, 67, + 24, 28, 19, 24, 24, 14, 19, 43, 28, 48, 19, 33, 33, 33, 43, 67, + 43, 38, 38, 38, 33, 24, 43, 28, 28, 33, 19, 28, 43, 43, 28, 33, 52, + 43, 38, 24, 33, 28, 19, 33, 24, 38, 33, 24, 33, 38, 33, 28, 28, 48, 57, + 38, 24, 24, 24, 24, 24, 28, 24, 52, 19, 43, 43, 24, 28, 24, 24, 28, 38, 62, + 4, 9, 0, 0, 0, 33, 0, 24, 9, 14, 24, 9, 19, 4, 9, 43, 28, 9, 0, 96, + -1, -1, -4, -2, -1, -3, -2, -2, -1, -2, -2, -2, -1, -2, -1, -2, -1, -1, -1, -5, -2, + -4, -3, -1, -5, -5, 4, -6, -1, -2, -5, -2, -4, -2, -6, -5, -5, -3, -3, -3, -2, -3, 8, + -1, 2, -7, 3, 4, -6, -2, 1, -3, -1, -3, -2, 0, -1, 4, -1, -1, -2, -3, -7, -1, -5, 4, +}; +int rpam160mt[]={ + 47, + 36, 52, + 26, 15, 83, + 36, 52, 10, 57, + 36, 47, 10, 52, 57, + 20, 15, 10, 5, 10, 73, + 41, 36, 20, 36, 36, 15, 57, + 26, 41, 20, 36, 36, 26, 20, 68, + 31, 26, 26, 20, 26, 36, 20, 20, 62, + 26, 36, 10, 36, 31, 10, 26, 31, 26, 57, + 26, 15, 5, 15, 20, 41, 15, 26, 47, 20, 62, + 31, 20, 10, 20, 26, 36, 20, 20, 47, 36, 52, 73, + 36, 47, 15, 47, 41, 20, 36, 47, 26, 41, 20, 26, 52, + 41, 31, 20, 26, 31, 15, 31, 31, 26, 26, 20, 26, 31, 62, + 31, 41, 10, 41, 47, 10, 26, 47, 26, 36, 26, 31, 36, 36, 62, + 26, 31, 20, 26, 26, 15, 20, 41, 26, 52, 20, 31, 31, 31, 41, 68, + 41, 36, 36, 36, 36, 20, 41, 31, 26, 31, 20, 26, 41, 41, 31, 31, 47, + 41, 36, 26, 31, 31, 20, 31, 26, 36, 36, 26, 31, 36, 36, 31, 31, 41, 52, + 36, 26, 26, 20, 26, 26, 26, 26, 52, 20, 41, 41, 26, 26, 26, 20, 31, 36, 57, + 10, 10, 0, 5, 0, 31, 0, 20, 10, 15, 26, 15, 15, 10, 10, 41, 26, 10, 5, 99, + 0, -1, -3, -1, -1, -3, -1, -1, -1, -1, -2, -1, 0, -1, -1, -1, 0, 0, -1, -4, -1, + -3, -3, 0, -4, -4, 5, -5, 0, -2, -4, -2, -3, -2, -5, -4, -4, -3, -3, -3, -1, -3, 8, + 0, 2, -5, 2, 3, -5, -1, 1, -2, 0, -3, -2, 1, -1, 3, 0, -1, -1, -2, -6, -1, -4, 3, +}; +int rpam250mt[]={ + 42, + 34, 47, + 25, 17, 85, + 34, 47, 12, 51, + 34, 47, 12, 47, 51, + 21, 17, 17, 8, 12, 72, + 38, 34, 21, 38, 34, 12, 55, + 30, 38, 21, 38, 38, 25, 25, 60, + 30, 25, 25, 25, 25, 38, 21, 25, 55, + 30, 38, 12, 34, 34, 12, 25, 34, 25, 55, + 25, 21, 8, 17, 21, 42, 17, 25, 42, 21, 60, + 30, 25, 12, 21, 25, 34, 21, 25, 42, 34, 51, 60, + 34, 42, 17, 42, 38, 21, 34, 42, 25, 38, 21, 25, 42, + 38, 30, 21, 30, 30, 12, 34, 34, 25, 30, 21, 25, 34, 60, + 34, 38, 12, 42, 42, 12, 30, 47, 25, 38, 25, 30, 38, 34, 51, + 25, 30, 17, 30, 30, 17, 21, 42, 25, 47, 21, 34, 34, 34, 38, 60, + 38, 34, 34, 34, 34, 21, 38, 30, 30, 34, 21, 25, 38, 38, 30, 34, 42, + 38, 34, 25, 34, 34, 21, 34, 30, 34, 34, 25, 30, 34, 34, 30, 30, 38, 47, + 34, 25, 25, 25, 25, 30, 30, 25, 51, 25, 42, 42, 25, 30, 25, 25, 30, 34, 51, + 8, 12, 0, 4, 4, 34, 4, 21, 12, 21, 25, 17, 17, 8, 12, 42, 25, 12, 8, 107, + 0, -1, -3, -1, -1, -2, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, 0, 0, -1, -4, -1, + -3, -3, 0, -4, -4, 7, -5, 0, -1, -4, -1, -2, -2, -5, -4, -4, -3, -3, -2, 0, -2, 10, + 0, 2, -5, 3, 3, -5, 0, 2, -2, 0, -3, -2, 1, 0, 3, 0, 0, -1, -2, -6, -1, -4, 3, +}; +int rpam350mt[]={ + 39, + 36, 43, + 26, 16, 92, + 36, 43, 13, 46, + 36, 43, 13, 46, 46, + 19, 16, 16, 13, 13, 76, + 39, 36, 19, 36, 36, 13, 49, + 29, 36, 19, 36, 36, 26, 26, 56, + 33, 26, 23, 26, 26, 39, 26, 26, 49, + 29, 36, 13, 36, 33, 13, 29, 36, 26, 49, + 26, 19, 9, 19, 19, 43, 19, 26, 46, 23, 59, + 29, 26, 13, 23, 26, 36, 23, 26, 43, 33, 49, 53, + 33, 39, 19, 39, 39, 19, 36, 39, 26, 36, 23, 26, 39, + 36, 33, 23, 33, 33, 16, 33, 33, 26, 29, 23, 26, 33, 53, + 33, 39, 13, 39, 43, 16, 29, 43, 26, 36, 26, 29, 36, 36, 46, + 29, 33, 19, 29, 33, 16, 26, 39, 26, 46, 23, 33, 36, 33, 39, 56, + 36, 36, 33, 36, 33, 19, 36, 29, 29, 33, 23, 26, 36, 36, 33, 33, 36, + 36, 33, 26, 33, 33, 23, 36, 29, 33, 33, 26, 29, 36, 36, 33, 29, 36, 39, + 33, 26, 26, 26, 26, 29, 29, 26, 46, 26, 43, 39, 26, 29, 26, 23, 29, 33, 49, + 9, 13, 0, 6, 6, 36, 6, 23, 13, 19, 26, 16, 16, 9, 16, 46, 23, 13, 9, 122, + 0, 0, -3, -1, 0, -2, -1, 0, 0, -1, -1, 0, 0, 0, 0, -1, 0, 0, 0, -5, -1, + -4, -4, 1, -5, -5, 11, -6, 0, 0, -5, 0, -2, -3, -6, -5, -5, -3, -3, -2, 1, -2, 14, + 0, 2, -6, 3, 3, -6, 0, 2, -2, 1, -3, -2, 2, 0, 3, 1, 0, 0, -2, -7, 0, -5, 3, +}; +int ralpha_mat []={ + 42, + 27, 27, + 31, 27, 60, + 28, 27, 30, 46, + 27, 27, 31, 28, 42, + 25, 27, 31, 28, 29, 84, + 29, 27, 31, 25, 29, 30, 51, + 32, 27, 31, 60, 29, 31, 23, 61, + 46, 27, 28, 28, 31, 14, 29, 23, 52, + 28, 27, 27, 31, 30, 26, 29, 23, 21, 49, + 30, 27, 35, 31, 30, 29, 31, 23, 15, 23, 57, + 28, 27, 30, 31, 29, 12, 24, 20, 18, 25, 33, 53, + 40, 27, 29, 27, 46, 31, 30, 28, 28, 60, 25, 28, 36, + 60, 27, 34, 35, 51, 28, 28, 23, 22, 24, 29, 13, 31, 66, + 36, 27, 28, 28, 27, 29, 30, 31, 34, 32, 24, 42, 32, 29, 35, + 27, 27, 36, 31, 29, 60, 32, 46, 30, 28, 28, 25, 28, 28, 27, 40, + 28, 27, 24, 27, 23, 29, 27, 21, 18, 22, 23, 13, 31, 29, 31, 31, 38, + 31, 27, 32, 30, 29, 29, 61, 22, 16, 29, 30, 12, 28, 30, 30, 31, 29, 36, + 28, 27, 29, 24, 24, 31, 23, 15, 32, 23, 26, 9, 30, 32, 29, 35, 29, 3, 53, + 31, 27, 42, 31, 31, 31, 23, 22, 15, 26, 29, 25, 35, 31, 30, 31, 29, 0, 22, 132, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 0, 2, 10, 3, -2, -6, 38, -14, -7, -1, -19, 0, 5, 3, 1, 4, -29, -6, -19, 0, 97, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +int rbeta_mat[]={ + 44, + 26, 26, + 29, 26, 102, + 27, 26, 22, 64, + 25, 26, 33, 22, 50, + 14, 26, 32, 17, 31, 70, + 28, 26, 31, 14, 35, 32, 68, + 36, 26, 33, 102, 28, 3, 23, 69, + 64, 26, 17, 26, 26, 9, 28, 21, 48, + 11, 26, 26, 31, 12, 28, 39, 17, 18, 52, + 22, 26, 50, 33, 27, 31, 36, 19, 21, 24, 52, + 22, 26, 28, 33, 29, 19, 17, 13, 16, 27, 37, 45, + 57, 26, 28, 25, 64, 33, 22, 11, 22, 102, 14, 26, 38, +102, 26, 39, 50, 68, 30, 30, 16, 0, 24, 32, 17, 31, 87, + 38, 26, 26, 11, 26, 35, 28, 32, 39, 35, 10, 50, 36, 28, 50, + 24, 26, 38, 29, 28, 102, 36, 64, 22, 22, 11, 14, 27, 26, 25, 57, + 26, 26, 10, 26, 23, 21, 22, 16, 17, 22, 8, 19, 33, 31, 26, 33, 46, + 33, 26, 35, 28, 28, 28, 69, 17, 15, 4, 35, 10, 17, 27, 27, 31, 29, 42, + 17, 26, 28, 10, 17, 24, 17, 21, 36, 28, 25, 16, 28, 18, 31, 50, 28, 9, 44, + 31, 26, 50, 32, 36, 21, 21, 14, 14, 24, 34, 2, 50, 31, 12, 33, 31, 13, 22, 130, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 12, 17, 17, -12, -9, 28, -13, -3, 0, -12, 0, 8, 4, -11, 2, -5, -5, -5, 0, 47, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; +int rcoil_mat[]={ + 36, + 27, 27, + 29, 27, 124, + 28, 27, 22, 51, + 28, 27, 33, 18, 40, + 13, 27, 29, 17, 23, 101, + 27, 27, 30, 13, 23, 28, 64, + 31, 27, 30, 124, 21, 15, 24, 76, + 51, 27, 17, 29, 25, 14, 27, 26, 71, + 18, 27, 29, 30, 8, 25, 24, 23, 20, 61, + 22, 27, 39, 33, 22, 28, 28, 21, 24, 27, 70, + 18, 27, 29, 30, 21, 12, 6, 18, 20, 26, 33, 73, + 52, 27, 27, 28, 51, 33, 22, 18, 18, 124, 13, 29, 36, +124, 27, 34, 39, 64, 27, 25, 23, 18, 24, 27, 13, 30, 79, + 36, 27, 29, 18, 29, 23, 29, 29, 34, 32, 13, 40, 31, 21, 39, + 27, 27, 36, 29, 27, 124, 31, 51, 22, 18, 18, 13, 28, 29, 28, 52, + 29, 27, 13, 29, 24, 19, 16, 22, 21, 18, 9, 14, 30, 30, 25, 33, 44, + 33, 27, 32, 29, 27, 20, 76, 10, 19, 20, 32, 9, 17, 28, 22, 30, 29, 55, + 17, 27, 21, 13, 6, 21, 23, 24, 44, 13, 21, 7, 29, 17, 23, 39, 26, 20, 60, + 30, 27, 40, 29, 28, 19, 26, 16, 7, 25, 31, 9, 39, 30, 8, 30, 27, 18, 26, 143, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 0, -4, 8, -3, -30, -6, 49, -10, -7, -12, -18, 3, 3, -6, -11, 3, 2, 2, -5, 0, 59, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; +int tmpam250mt[]={ + 2, + 0, 0, + 2, 0, 6, + -1, 0, 0, 12, + 0, 0, 6, -1, 13, + -3, 0, 1, -3, 3, 5, + 1, 0, 3, -3, 1, 7, 6, + 6, 0, 2, 6, 0, -1, -3, 11, + 12, 0, -3, -2, -2, -5, 5, 0, 2, + -1, 0, 0, 3, -1, 0, 3, -3, -3, 12, + 0, 0, 11, 6, 3, 5, 3, -3, -2, -2, 3, + -1, 0, 2, 2, -1, -2, -1, -3, -4, -1, 9, 3, + 7, 0, 1, 0, 12, 6, 0, -1, -1, 6, -3, -2, 11, + 6, 0, 8, 11, 6, 0, 2, -4, -1, -2, 3, -4, 3, 11, + 11, 0, -2, -1, 0, 1, 2, 1, 8, 7, -3, 13, 6, 0, 11, + -1, 0, 11, 2, 1, 6, 6, 12, 0, -1, -1, -3, -1, -2, 0, 7, + -2, 0, -3, 0, -3, -3, -3, -4, -2, -3, -3, -4, 2, 2, -2, 6, 3, + 6, 0, 7, 2, 5, -2, 11, -2, -5, -1, 6, -6, -3, -1, 3, 3, 1, 3, + -3, 0, 0, -3, -1, 0, -3, -2, 1, -3, 4, -6, 2, 1, 3, 11, 0, -3, 2, + 3, 0, 13, 1, 3, -2, 0, -4, -4, -2, 1, 1, 11, 2, -1, 2, -1, -4, -1, 12, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 0, 1, 8, 3, -4, -3, 2, -4, -3, -1, -4, 0, 0, -1, -3, 1, 5, 0, -3, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; +int rtmpam250mt[]={ + 32, + 24, 24, + 32, 24, 49, + 20, 24, 24, 73, + 24, 24, 49, 20, 77, + 12, 24, 28, 12, 36, 45, + 28, 24, 36, 12, 28, 53, 49, + 49, 24, 32, 49, 24, 20, 12, 69, + 73, 24, 12, 16, 16, 4, 45, 24, 32, + 20, 24, 24, 36, 20, 24, 36, 12, 12, 73, + 24, 24, 69, 49, 36, 45, 36, 12, 16, 16, 36, + 20, 24, 32, 32, 20, 16, 20, 12, 8, 20, 61, 36, + 53, 24, 28, 24, 73, 49, 24, 20, 20, 49, 12, 16, 69, + 49, 24, 57, 69, 49, 24, 32, 8, 20, 16, 36, 8, 36, 69, + 69, 24, 16, 20, 24, 28, 32, 28, 57, 53, 12, 77, 49, 24, 69, + 20, 24, 69, 32, 28, 49, 49, 73, 24, 20, 20, 12, 20, 16, 24, 53, + 16, 24, 12, 24, 12, 12, 12, 8, 16, 12, 12, 8, 32, 32, 16, 49, 36, + 49, 24, 53, 32, 45, 16, 69, 16, 4, 20, 49, 0, 12, 20, 36, 36, 28, 36, + 12, 24, 24, 12, 20, 24, 12, 16, 28, 12, 40, 0, 32, 28, 36, 69, 24, 12, 32, + 36, 24, 77, 28, 36, 16, 24, 8, 8, 16, 28, 28, 69, 32, 20, 32, 20, 8, 20, 73, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 0, 1, 8, 3, -4, -3, 2, -4, -3, -1, -4, 0, 0, -1, -3, 1, 5, 0, -3, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; +int promoter_tf1[]={ + 0, + 0, 0, + 0, 0, 0, + 0, 0, 0, 6, + 0, 0, 0, 1, 6, + 0, 0, 0, 2, 2, 5, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 2, 1, 0, 6, + 0, 0, 0, 1, -1, -1, 0, -2, 6, + 0, 0, 0, -3, 1, -2, 0, -3, 1, 6, + 0, 0, 0, -2, -1, 2, 0, -2, 2, 1, 6, + 0, 0, 0, -1, -1, -1, 0, 1, 2, 2, 2, 6, + 0, 0, 0, 1, -1, 0, 0, -2, 1, -2, -1, -1, 6, + 0, 0, 0, -2, 2, -1, 0, -2, -2, 1, -2, -1, 2, 6, + 0, 0, 0, -3, -3, 2, 0, -4, -3, -3, 0, -3, 1, 0, 4, + 0, 0, 0, -2, -1, -2, 0, 2, -2, -2, -2, 2, 1, 2, 0, 6, + 0, 0, 0, 1, -1, -1, 0, -1, 1, -2, -2, -1, 1, -2, -3, -1, 6, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, -2, 2, -2, 0, -2, -1, 2, -2, 0, -2, 1, -3, -1, 1, 0, 6, + 0, 0, 0, -2, -2, 2, 0, -2, -2, -2, 2, -1, -1, -2, 0, -1, 2, 0, 1, 5, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, -1, -2, -2, 0, 2, -2, -2, -2, 2, -2, -3, -4, 1, 2, 0, 2, 1, 0, 6, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; +int blosumR[]={ + 0, + 0, 0, + 0, 0, 0, + 0, 0, 0, 6, + 0, 0, 0, 1, 6, + 0, 0, 0, 2, 2, 5, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 2, 1, 0, 6, + 0, 0, 0, 1, -1, -1, 0, -2, 6, + 0, 0, 0, -3, 1, -2, 0, -3, 1, 6, + 0, 0, 0, -2, -1, 2, 0, -2, 2, 1, 6, + 0, 0, 0, -1, -1, -1, 0, 1, 2, 2, 2, 6, + 0, 0, 0, 1, -1, 0, 0, -2, 1, -2, -1, -1, 6, + 0, 0, 0, -2, 2, -1, 0, -2, -2, 1, -2, -1, 2, 6, + 0, 0, 0, -3, -3, 2, 0, -4, -3, -3, 0, -3, 1, 0, 4, + 0, 0, 0, -2, -1, -2, 0, 2, -2, -2, -2, 2, 1, 2, 0, 6, + 0, 0, 0, 1, -1, -1, 0, -1, 1, -2, -2, -1, 1, -2, -3, -1, 6, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, -2, 2, -2, 0, -2, -1, 2, -2, 0, -2, 1, -3, -1, 1, 0, 6, + 0, 0, 0, -2, -2, 2, 0, -2, -2, -2, 2, -1, -1, -2, 0, -1, 2, 0, 1, 5, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, -1, -2, -2, 0, 2, -2, -2, -2, 2, -2, -3, -4, 1, 2, 0, 2, 1, 0, 6, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/parttree.c b/binaries/src/tcoffee/t_coffee_source/parttree.c new file mode 100644 index 0000000..9376819 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/parttree.c @@ -0,0 +1,1495 @@ +#include +#include +#include +#include +#include +#include +// #include + +#include "fast_tree_header.h" +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" +#include "dp_lib_header.h" +//TODO: -change kick-out value +// -pass arrays in partTree_r + +/*! + * \file parttree.c + * \brief Source code for PartTree algorithm. + */ + + + +#define ENLARGEMENT_PER_STEP 50 + + + +void +print_fastal_tree(Tree_fastal *tree, + int pos, + FILE *tree_file, + int num_seq) +{ + if (tree[pos].left >= num_seq) + print_fastal_tree(tree, tree[pos].left-num_seq, tree_file, num_seq); + if (tree[pos].right >= num_seq) + print_fastal_tree(tree, tree[pos].right-num_seq, tree_file, num_seq); + + fprintf(tree_file, "%i %i %i\n", tree[pos].left, tree[pos].right, tree[pos].name); +} + + + + + +PartTree_param *param_set; + + +//********************** UPGMA ***************************** + +/** + * Function to write tree to file in fastal_format. Leafs in \a tree are leafs in the complete tree as well. + * + * \param tree The root node of the (sub)tree. + * \param param_set Parameter of PartTree. + * \param start_write_here Current node to write into. + * \return position in tree + * \see tree_process + */ +int +tree_process_simple(NT_node tree, + PartTree_param *param_set, + int start_write_here) +{ + if (tree->isseq) + { +// printf("T: %s\n", tree->name); + return atoi(tree->name); + } + else + { + Tree_fastal *tree_flat = ¶m_set->tree[start_write_here]; + tree_flat->name = start_write_here +param_set->num_sequences; + if (start_write_here == param_set->pos_tree) + { + ++param_set->pos_tree; + } + start_write_here = param_set->pos_tree; + int left = tree_process_simple(tree->left, param_set, start_write_here); + start_write_here = param_set->pos_tree; + int right = tree_process_simple(tree->right, param_set, start_write_here); + tree_flat->index = NULL; + tree_flat->right = right; + tree_flat->left = left; + return tree_flat->name; + } +} + + +void +read_sequence_from_position(FILE *file, long position1, char *seq) +{ + fseek(file, position1, SEEK_SET); + char line[500]; + int pos = -1; + while ((fgets(line, 500, file) != NULL) && (line[0] != '>')) + { + int l = -1; + while ((line[++l] != '\n') && (line[l] != '\0')) + seq[++pos] = line[l]; + } + seq[++pos] = '\0'; +} + +// char* +// read_sequence_from_position(FILE *file, long position1, long position2) +// { +// +// } + +/** +* Function to write tree to file in fastal_format. Leafs in \a tree do not need to be leafs in the complete tree. +* +* \param tree The root node of the (sub)tree. +* \param param_set Parameter of PartTree. +* \param clusters Number of sequences in each cluster. +* \param subgroup The sequences for each cluster. +* \param start_write_here Current node to write into. +* \return position in tree +* \see tree_process_simple +*/ +int +tree_process(NT_node tree, + PartTree_param *param_set, + int *clusters, + int *subgroup, + int start_write_here) +{ + if (tree->isseq) + { + int node_num = atoi(tree->name); + int num_in_sub = clusters[node_num+1] - clusters[node_num]; +// printf("NUM: %i %i %i %i\n",node_num, num_in_sub, clusters[node_num+1], clusters[node_num]); + if (num_in_sub > 1) + { + Tree_fastal *tree_flat = ¶m_set->tree[start_write_here]; + tree_flat->name = start_write_here +param_set->num_sequences; + if (start_write_here == param_set->pos_tree) + { + ++param_set->pos_tree; + } + tree_flat->left = -1; + tree_flat->right = -1; + tree_flat->index = &subgroup[clusters[node_num]]; + + tree_flat->num_leafs = num_in_sub; + return tree_flat->name; + } + else + { + return(subgroup[clusters[node_num]]); + } + } + else + { +// printf("TREEPOS: %i\n",param_set->pos_tree); + Tree_fastal *tree_flat = ¶m_set->tree[start_write_here]; + tree_flat->name = start_write_here +param_set->num_sequences; + if (start_write_here == param_set->pos_tree) + { + ++param_set->pos_tree; + } + start_write_here = param_set->pos_tree; + int left = tree_process(tree->left, param_set, clusters, subgroup, start_write_here); + start_write_here = param_set->pos_tree; + int right = tree_process(tree->right, param_set, clusters, subgroup, start_write_here); + tree_flat->index = NULL; + tree_flat->right = right; + tree_flat->left = left; + return tree_flat->name; + } +} + + +/** +* \brief Calculates tree out of distance matrix. +* +* Calculates the upgma tree using a given distance matrix. +* \param mat The distance matrix. +* \param nseq Number of sequences. +* \param fname Filename for temporary storage. +* \param seqnames Names of the sequences. +* \return The calculated UPGMA Tree. +*/ +NT_node ** int_dist2upgma_tree_fastal (int **mat, int nseq, char *fname, char **seqnames) +{ + NT_node *NL, T; + int a, n, *used; + int tot_node; + if (upgma_node_heap (NULL)) + { + printf_exit ( EXIT_FAILURE,stderr, "\nERROR: non empty heap in upgma [FATAL]"); + } + NL=vcalloc (nseq, sizeof (NT_node)); + + for (a=0; aname, "%s", seqnames[a]); + NL[a]->isseq=1; + NL[a]->leaf=1; + } + used=vcalloc ( nseq, sizeof (int)); + n=nseq; + while (n>1) + { + T=upgma_merge(mat, NL,used, &n, nseq); + } + vfree (used); + vfclose (print_tree (T, "newick", vfopen (fname, "w"))); + upgma_node_heap (NULL); + vfree (NL); + + return read_tree (fname,&tot_node, nseq, seqnames); +} + + + + +//Part_Tree + +/*! +* \brief Constructs a guide tree for multiple sequence alignment. +* +* This algorithm is an implementation of the partTree algorithm (PartTree: an algorithm to build an approximate tree from a large number of unaligned +* sequences. Katoh et al. 2007). +* \param sequence_f Filename of file with sequences. +* \param tree_f Filename of file where the tree will be stored. +* \param ktup Size of the ktups. +* \param subgroup Parameter for subgroupsize. +*/ +void +make_partTree(char *sequence_f, + char *tree_f, + int ktup, + int subgroup, + int is_dna, + int retree) +{ + long *file_positions = NULL; + long **tmp1 = &file_positions; + int *seq_lengths = NULL; + int **tmp2 = &seq_lengths; + int number_of_sequences; + param_set = vcalloc(1,sizeof(PartTree_param)); + param_set->ktup = ktup; + param_set->subgroup = subgroup; + Tree_fastal *tree; + + + if (!retree) + { + //make index + char *ktup_table = vtmpnam(NULL); + param_set->num_sequences = number_of_sequences = make_pos_len_index_of_file(sequence_f, ktup_table, tmp1, tmp2, ktup, is_dna); + tree = vcalloc(number_of_sequences-1,sizeof(Tree_fastal)); + param_set->tree = tree; + param_set->ktup_positions = file_positions; + param_set->seq_lengths = seq_lengths; + param_set->threshold = 0.01; + param_set->ktup_table_f = fopen(ktup_table,"r"); + + + partTree_r(param_set); + } + else + { + + //make index + param_set->num_sequences = number_of_sequences = make_pos_len_index_of_file_retree(sequence_f, tmp1, tmp2); + tree = vcalloc(number_of_sequences-1,sizeof(Tree_fastal)); + param_set->tree = tree; + param_set->ktup_positions = file_positions; + param_set->seq_lengths = seq_lengths; + param_set->threshold = 0.01; + param_set->ktup_table_f = fopen(sequence_f,"r"); + + partTree_retree(param_set); + + } + + FILE * tree_file = fopen(tree_f,"w"); + print_fastal_tree(tree, 0, tree_file, number_of_sequences); + fclose(tree_file); + vfree(tree); +// exit(1); +} + + +/** +* Filters seed set. +* +* \param sequence_group Sequences to filter. +* \param dist_mat The distance matrix. +* \param seed_set_cleaned ordered_seed_set. +* \param param_set Parameters for PartTree algorithm. +* \return number in the filtered set. +*/ +int +filter(int *sequence_group, + int **dist_mat, + int *seed_set_cleaned, + PartTree_param *param_set) +{ + int i, j; + int num_in_subgroup = param_set->subgroup; + int *seq_lengths = param_set->seq_lengths; + int num_in_clean = 0; + double threshold = param_set->threshold; +// printf("threshold: %f\n", threshold); + double min; + for (i = 0; i < num_in_subgroup; ++i) + { + if (!seed_set_cleaned[i]) + continue; + for (j = i+1; j < num_in_subgroup; ++j) + { + min = MIN(seq_lengths[sequence_group[i]], seq_lengths[sequence_group[j]]); +// printf("MINIMUM: %i\n",min); + min = (threshold * min); +// printf("MINIMUM: %f\n",min); + if (seed_set_cleaned[j] &&(dist_mat[i][j] < min)) + { + if (seq_lengths[sequence_group[i]] < seq_lengths[sequence_group[j]]) + { + seed_set_cleaned[i] = 0; + break; + } + else + seed_set_cleaned[j] = 0; + } + } + } + + for (i = 0; i < num_in_subgroup; ++i) + { + num_in_clean += seed_set_cleaned[i]; + } + int max = num_in_subgroup -1; + i = 0; + int tmp; +// printf("CLEAN: %i\n", num_in_clean); + while (i < num_in_clean) + { + if (seed_set_cleaned[i]) + { + ++i; + } + else + { + seed_set_cleaned[i] = seed_set_cleaned[max]; + seed_set_cleaned[max] = 0; + tmp = sequence_group[i]; + sequence_group[i] = sequence_group[max]; + sequence_group[max] = tmp; + --max; + } + } + return num_in_clean; +} + + + + + +/*! +* \brief Function to create a tree using the PartTree algorithm. +* +* \param param_set A \a PartTree_param object containing all necessary parameters and the data. +* \return The node_number. +*/ +void +partTree_r(PartTree_param *param_set) +{ + + int num_of_tree_nodes = param_set->num_sequences-1; + int loop_tree_node; + + Tree_fastal *tree = param_set->tree; +// int this_node = param_set->pos_tree; + + int i; + int tsize = param_set->tsize; + + + //get some memory + short *table1 = vcalloc(tsize, sizeof(short)); + short *table2 = vcalloc(tsize, sizeof(short)); + char **names = declare_char(param_set->subgroup, 8); + int **dist_mat = declare_int(param_set->subgroup, param_set->subgroup); + int **dist_mat2 = declare_int(param_set->subgroup, param_set->subgroup); + char * file_name_tmp = vtmpnam(NULL); + int *seed_set_cleaned = vcalloc(param_set->subgroup, sizeof(int)); + FILE *table_f = param_set->ktup_table_f; + long *file_positions = param_set->ktup_positions; + int max_n_group = param_set->subgroup; + int num_in_subgroup = param_set->subgroup; + int *seq_lengths = param_set->seq_lengths; + int *clusters = vcalloc(param_set->subgroup+1, sizeof(int)); + int *min_dist = vcalloc(param_set->num_sequences, sizeof(int)); + int *belongs_to = vcalloc(param_set->num_sequences, sizeof(int)); + + + + + + + //Prepare first node + + tree[0].index = vcalloc(param_set->num_sequences,sizeof(int)); + int *index = tree[0].index; + for (i = 0; i< param_set->num_sequences; ++i) + index[i] = i; + tree[0].name = param_set->pos_tree +param_set->num_sequences; + + tree[0].num_leafs = param_set->num_sequences; + int *sequence_group2 = vcalloc(param_set->num_sequences,sizeof(int)); + + Tree_fastal *current_node; + for (loop_tree_node = 0; loop_tree_node < num_of_tree_nodes; ++loop_tree_node) + { +// printf("ROUND: %i\n", loop_tree_node); + current_node = &tree[loop_tree_node]; + index= current_node->index; + if (current_node->index == NULL) + { + continue; + } + int num_sequences = current_node->num_leafs; + + //if number of sequences in this group smaller than number subgoup size: make tree, finisch + if (num_sequences <= max_n_group) + { + dist_mat = make_distance_matrix(table_f, file_positions, index, num_sequences, dist_mat); + for (i = 0; i < num_sequences; ++i) + { + sprintf(names[i],"%i", current_node->index[i]); + } + NT_node **tree= (int_dist2upgma_tree_fastal (dist_mat, num_sequences, file_name_tmp , names)); + tree_process_simple(tree[0][0], param_set,loop_tree_node); + continue; + } + + + for (i = 0; i < num_in_subgroup; ++i) + { + seed_set_cleaned[i] = 1; + } + + //finde longest sequence and put into the first field + + int index_longest = 0; + int length_of_longest = 0; + + for(i = 0; i < num_sequences; ++i) + { + if (seq_lengths[index[i]] > length_of_longest) + { + index_longest = i; + length_of_longest = seq_lengths[index[i]]; + } + } + int tmp = index[index_longest]; + index[index_longest] = index[0]; + index[0] = tmp; + + //distance of longest to rest + int seq_index = 1; + int min= euclidean_dist(table_f, file_positions[index[0]], file_positions[index[1]], table1, table2, param_set->tsize); + for (i = 2; i < num_sequences; ++i) + { + tmp = euclidean_dist_half(table_f, file_positions[index[i]], table1, table2, param_set->tsize); + if (tmp < min) + { + min = tmp; + seq_index = i; + } + } + + //get the new seed_set in the first n spaces + tmp = index[1]; + index[1] = index[seq_index]; + index[seq_index] = tmp; + int r,j; + num_in_subgroup = param_set->subgroup; + + + for (i = 2; i < num_in_subgroup; ++i) + { + r = i + rand() / ( RAND_MAX / ( num_sequences-i) + 1 ); +// printf("RANDOM: %i\n",r); + tmp = index[r]; + index[r] = index[i]; + index[i] = tmp; + } + + //Calculate matrix + dist_mat = make_distance_matrix(table_f, file_positions, index, param_set->subgroup, dist_mat); + + //Filter out sequences that are to similar & reorder + + NT_node **upgma_tree; + + + int num_in_clean = filter(index, dist_mat, seed_set_cleaned, param_set); + + + if (num_in_clean ==1) + { + num_in_clean = 2; + seed_set_cleaned[1] = 1; + } + //make_tree + int col = 0; + int row = 0; + for (i = 0; i < num_in_subgroup; ++i) + { + if (seed_set_cleaned[i]) + { + row = col+1; + for (j = i+1; j < num_in_subgroup; ++j) + { + if (seed_set_cleaned[j]) + { + dist_mat2[row][col] = dist_mat2[col][row] = dist_mat[i][j]; + ++row; + } + } + ++col; + } + } + for (i = 0; i < num_in_clean; ++i) + { + sprintf(names[i],"%i",i); + } + upgma_tree= (int_dist2upgma_tree_fastal (dist_mat2, num_in_clean, file_name_tmp , names)); + + + //cluster + //calculate distances from n' to N + get_table(table1, table_f, file_positions[index[0]]); + for (j = num_in_clean; j < num_sequences; ++j) + { + min_dist[j] = euclidean_dist_half(table_f, file_positions[index[j]], table1, table2, param_set->tsize); + belongs_to[j] = 0; + } + for(i = 1; i < num_in_clean; ++i) + { + get_table(table1, table_f, file_positions[index[i]]); + belongs_to[i] = i; + for (j = num_in_clean; j < num_sequences; ++j) + { + tmp = euclidean_dist_half(table_f, file_positions[index[j]], table1, table2, param_set->tsize); + if (tmp < min_dist[j]) + { + min_dist[j] = tmp; + belongs_to[j] = i; + } + } + } + + //how_many sequences has each cluster + for (j = 0; j <= num_in_subgroup; ++j) + { + clusters[j] = 0; + } + for (j = 0; j < num_sequences; ++j) + { + ++clusters[belongs_to[j]]; + } +// for (j = 0; j <= num_in_subgroup; ++j) +// { +// printf("CL: %i ",clusters[j]); +// } +// printf("\n"); + for(i = 1; i < num_in_clean; ++i) + { + clusters[i] += clusters[i-1]; + } + clusters[num_in_clean] = clusters[num_in_clean-1]; + + for (i = 0; i < num_sequences; ++i) + { + sequence_group2[--clusters[belongs_to[i]]] = index[i]; + } + + for (i = 0; i < num_sequences; ++i) + { + index[i] = sequence_group2[i]; + } + + + for (i = 0; i < num_in_clean; ++i) + { + sprintf(names[i],"%i",i); + } + tree_process(upgma_tree[0][0], param_set, clusters, index, loop_tree_node); + NT_node tmp_tree = upgma_tree[3][0]; + vfree(upgma_tree[0]); + vfree(upgma_tree[1]); + vfree(upgma_tree[2]); + vfree(upgma_tree[3]); + vfree(upgma_tree); + free_tree(tmp_tree); + } + vfree(min_dist); + vfree(belongs_to); + vfree(clusters); +} + + + +/*! + * \brief Makes the distance matrix between all sequences. + * + * \param table_file File with the ktup tables + * \param file_positions Index of positions where the tabels are stored in \a table_file + * \param sequence_group the group of sequences + * \param number number of sequences + * \param dist_mat distance matrix + * \return the distance matrix. (same as \a dist_mat ) +*/ +int ** +make_distance_matrix(FILE *table_f, + long *file_positions, + int *sequence_group, + int number, + int **dist_mat) +{ + static short *table1 = NULL; + static short *table2; + int tsize = param_set->tsize; + if (table1 == NULL) + { + table1 = vcalloc(tsize, sizeof(short)); + table2 = vcalloc(tsize, sizeof(short)); + } + int i, j, num = number-1; + for (i = 0; i < num; ++i) + { + j = i+1; + dist_mat[i][j] = dist_mat[j][i]= euclidean_dist(table_f, file_positions[sequence_group[i]], file_positions[sequence_group[j]], table1, table2, tsize); + ++j; + for (; j < number; ++j) + { + dist_mat[i][j] = dist_mat[j][i] = euclidean_dist_half(table_f, file_positions[sequence_group[j]], table1, table2, tsize); + } + } + return dist_mat; +} + + +int ** +make_distance_matrix_sim(FILE *aln_f, + long *file_positions, + int *sequence_group, + int number, + int **dist_mat) +{ + static char *seq1 = NULL; + static char *seq2; + char line[500]; + if (seq1 == NULL) + { + int length = 0; + int i; + fseek(aln_f, file_positions[0], SEEK_SET); + fgets(line, 500, aln_f); + while (line[0] != '>') + { + i = -1; + while ((line[++i] != '\n') && (line[i] != '\0')); + length += i; + fgets(line, 500, aln_f); + } + seq1 = vcalloc(length+1, sizeof(short)); + seq2 = vcalloc(length+1, sizeof(short)); + } + + + int i, j, num = number-1, pos; + for (i = 0; i < num; ++i) + { + + fseek(aln_f, file_positions[sequence_group[i]], SEEK_SET); + + + pos = -1; + while ((fgets(line, 500, aln_f) != NULL) && (line[0] != '>')) + { + int l = -1; + while ((line[++l] != '\n') && (line[l] != '\0')) + seq1[++pos] = line[l]; + } + seq1[++pos] = '\0'; + + for (j = i+1; j < number; ++j) + { + pos = -1; + fseek(aln_f, file_positions[sequence_group[j]], SEEK_SET); + while ((fgets(line, 500, aln_f) != NULL) && (line[0] != '>')) + { + int l = -1; + while ((line[++l] != '\n') && (line[l] != '\0')) + seq2[++pos] = line[l]; + } + seq2[++pos] = '\0'; + dist_mat[i][j] = dist_mat[j][i] = 100 - fast_aln2sim_mat2(seq1, seq2); + } + } + return dist_mat; +} + + +/** +* Replaces the coded sequence with coded tuples +* +* \param coded_seq The coded sequence which will be replaced by the tuple number +* \param ktup Size of the ktup +* \param ng Coded alphabet size +* \param length Lengths of coded sequence +*/ +void +makepointtable_fast(int *coded_seq, //sequence + int ktup, //ktup size + int ng, //hmm... + int length) //length of coded_seq +{ + int point, a; + register int *p; + static int *prod; + + if (!prod) + { + prod=vcalloc ( ktup, sizeof (int)); + for ( a=0; a 0) + fprintf(tables_f, "%i %i\n", point, table[point]); + } + fprintf(tables_f, "*\n"); +} + + +/** JUST FOR TEST */ +void +make_fast_tree(char *file_name, + int n, + int ktup) +{ + + make_partTree(file_name, "TREE_OUT", ktup, n, 1, 0); + +} + + + +/** +* \brief Reads ktup_table from file +* +* \param table Table to save the file content in. +* \param tables_f File in which the tables are stored. +* \param index Position of the table in \a tables_f +*/ +void +get_table(short *table, //Table to save the readings in + FILE* tables_f, //File with tables + long index) //index positin of ktup-tables +{ + fseek(tables_f, index, SEEK_SET); + const int LINE_LENGTH = 101; + char line[LINE_LENGTH]; + fgets(line, LINE_LENGTH, tables_f); + + char delims[] = " "; + char *result = NULL; + int code; + + while (line[0] != '*') + { + result = strtok( line, delims ); + code = atoi(result); + table[code] = atoi(strtok( NULL, delims)); + fgets(line, LINE_LENGTH, tables_f); + } +} + + + +/** +* \brief calculates the euclidean ktub distance between two sequences +* +* @param ktup_f, ktup_file +* @param pos1 position of sequence 1 in \a ktup_f +* @param pos2 position of sequence 2 in \a ktup_f +* @param table1 Saves the number of occurences for each ktup in sequence 1 +* @param table2 Saves the number of occurences for each ktup in sequence 2 +*/ +int +euclidean_dist(FILE* ktup_f, //ktup_file + long pos1, //position of table1 + long pos2, //position of table2 + short *table1, //table to save ktups in + short *table2, //table to save ktups in + int length) +{ + const int LINE_LENGTH = 101; + char line[LINE_LENGTH]; + + + char delims[] = " "; + char *result = NULL; + int code; + + fseek(ktup_f, pos1, SEEK_SET); + fgets(line, LINE_LENGTH, ktup_f); + int i; + for (i = 0; i < length; ++i) + { + table1[i] = 0; + table2[i] = 0; + } + while (line[0] != '*') + { + result = strtok( line, delims ); + code = atoi(result); + table1[code] = atoi(strtok( NULL, delims)); + fgets(line, LINE_LENGTH, ktup_f); + } + fseek(ktup_f, pos2, SEEK_SET); + fgets(line, LINE_LENGTH, ktup_f); + while (line[0] != '*') + { + result = strtok( line, delims ); + code = atoi(result); + table2[code] = atoi(strtok( NULL, delims)); + fgets(line, LINE_LENGTH, ktup_f); + } + + int dist = 0; + for (i = 0; i < length; ++i) + { + dist += (table1[i]-table2[i])*(table1[i]-table2[i]); + } + return dist; +} + + + +/** + * \brief calculates the euclidean ktub distance between two sequences. + * + * The difference to \a euclidean_dist is, that this uses the ktups stored in \a table1 + * @param ktup_f, ktup_file + * @param pos2 position of sequence 2 in \a ktup_f + * @param table1 Saves the number of occurences for each ktup in sequence 1 + * @param table2 Saves the number of occurences for each ktup in sequence 2 + * \see euclidean_dist + */ +int +euclidean_dist_half(FILE* ktup_f, //ktup_file + long pos2, //position of table1 + short *table1, //table to save ktups in + short *table2, //table to save ktups in + int length) +{ + const int LINE_LENGTH = 101; + char line[LINE_LENGTH]; + + + char delims[] = " "; + char *result = NULL; + int code; + + fseek(ktup_f, pos2, SEEK_SET); + fgets(line, LINE_LENGTH, ktup_f); + int i; + for (i = 0; i < length; ++i) + { + table2[i] = 0; + } + while (line[0] != '*') + { + result = strtok( line, delims ); + code = atoi(result); + table2[code] = atoi(strtok( NULL, delims)); + fgets(line, LINE_LENGTH, ktup_f); + } + + int dist = 0; + for (i = 0; i < length; ++i) + { + dist += (table1[i]-table2[i])*(table1[i]-table2[i]); + } + return dist; +} + + + + +/** +* Makes an index of a file +*/ +int +make_pos_len_index_of_file(char *file_name, //file with sequences + char *ktable_f, //file with the ktup-tables + long **file_positions, //array to save the positions + int **seq_lengths, //array to save the sequence length + int ktup, //length of ktup + int is_dna) //type of the seuqence +{ + //preparations for recoding sequence + int *aa; + int a, b; + + int ng = 0; + char **gl; + if (is_dna) + { + gl=declare_char (5,13); + sprintf ( gl[ng++], "Aa"); + sprintf ( gl[ng++], "Gg"); + sprintf ( gl[ng++], "TtUu"); + sprintf ( gl[ng++], "Cc"); + sprintf ( gl[ng++], "NnRrYyDdMmWw"); + } + else + { + gl=make_group_aa ( &ng, "mafft"); + } + aa=vcalloc ( 256, sizeof (int)); + for ( a=0; atsize = tsize; + param_set->ng = ng; + + int *table=vcalloc ( tsize,sizeof (int)); + + + //Reading and recoding squences + const int LINE_LENGTH = 501; + int *coded_seq = vcalloc(2*LINE_LENGTH, sizeof(int)); + int allocated_mem = 2*LINE_LENGTH; + + (*file_positions) = vcalloc(ENLARGEMENT_PER_STEP, sizeof(long)); + (*seq_lengths) = vcalloc(ENLARGEMENT_PER_STEP, sizeof(int)); + + + FILE *file = fopen(file_name,"r"); + + char line[LINE_LENGTH]; + + int num_of_sequences = 0; + int str_len = 0; + int mem_for_pos = ENLARGEMENT_PER_STEP; + + int real_len; + int *c_seq; + + FILE *tables_f = fopen(ktable_f, "w"); + + + if (file == NULL) + { + printf("FILE NOT FOUND\n"); + exit(1); + } + else + { + + while(fgets(line, LINE_LENGTH , file)!=NULL) + { + if ( str_len >= allocated_mem - LINE_LENGTH) + { + allocated_mem += LINE_LENGTH; + coded_seq = vrealloc(coded_seq, allocated_mem*sizeof(int)); + } + + int i; + + if (line[0] == '>') + { + if (num_of_sequences >0) + { + (*seq_lengths)[num_of_sequences-1] = str_len; +// printf("len: %i\n", str_len); + c_seq = coded_seq; + makepointtable_fast(coded_seq,ktup,ng, str_len); + + (*file_positions)[num_of_sequences-1] = ftell(tables_f ); + for (i=0; i < tsize; ++i) + table[i] = 0; + makecompositiontable_fastal(tables_f, table, coded_seq,tsize ); + + + } + str_len = 0; + ++num_of_sequences; + + if (num_of_sequences == mem_for_pos) + { + mem_for_pos += ENLARGEMENT_PER_STEP; + (*file_positions) = vrealloc((*file_positions), mem_for_pos * sizeof(long)); + (*seq_lengths) = vrealloc((*seq_lengths), mem_for_pos * sizeof(int)); + } + } + else + { + int i; + real_len = strlen(line); + if (line[real_len-1] == '\n') + --real_len; + for (i = 0; i < real_len; ++i) + { + coded_seq[str_len++] = aa[(short)line[i]]; + } + } + } + } + + (*seq_lengths)[num_of_sequences-1] = str_len; + c_seq = coded_seq; + makepointtable_fast(coded_seq,ktup,ng, str_len); + (*file_positions)[num_of_sequences] = ftell(tables_f ); + makecompositiontable_fastal(tables_f, table, coded_seq,tsize ); + fclose(file); + fclose(tables_f); + return num_of_sequences; +} + + +/** + * Makes an index of a file + */ +int +make_pos_len_index_of_file_retree(char *file_name, //file with sequences + long **file_positions, //array to save the positions + int **seq_lengths) //array to save the sequence length +{ + +// printf("HALLO\n"); + //Reading sequences + const int LINE_LENGTH = 501; + (*file_positions) = vcalloc(ENLARGEMENT_PER_STEP, sizeof(long)); + (*seq_lengths) = vcalloc(ENLARGEMENT_PER_STEP, sizeof(int)); + + + FILE *file = fopen(file_name,"r"); + + char line[LINE_LENGTH]; + + int num_of_sequences = 0; + int mem_for_pos = ENLARGEMENT_PER_STEP; +// fgets(line, LINE_LENGTH , file) + int seq_len = 0; + + + if (file == NULL) + { + printf("FILE NOT FOUND\n"); + exit(1); + } + else + { + int i; + while(fgets(line, LINE_LENGTH , file)!=NULL) + { +// line[LINE_LENGTH -2] = '\n'; + if (line[0] == '>') + { + (*file_positions)[num_of_sequences] = ftell(file); + if (num_of_sequences >0) + { + (*seq_lengths)[num_of_sequences-1] = seq_len; + seq_len = 0; + } + ++num_of_sequences; + + if (num_of_sequences == mem_for_pos) + { + mem_for_pos += ENLARGEMENT_PER_STEP; + (*file_positions) = vrealloc((*file_positions), mem_for_pos * sizeof(long)); + (*seq_lengths) = vrealloc((*seq_lengths), mem_for_pos * sizeof(int)); + } + } + else + { + i = -1; + while ((line[++i] != '\n') && (line[i] != '\0')) + { + if (line[i] != '-') + { +// printf("A: %c\n", line[i]); + ++seq_len; + } + } + } + } + } + (*seq_lengths)[num_of_sequences-1] = seq_len; +// printf("%i %li\n", (*seq_lengths)[0], (*file_positions)[0]); +// printf("%i %li\n", (*seq_lengths)[1], (*file_positions)[1]); + fclose(file); + return num_of_sequences; +} + + + +int logid_score2 ( int sim, int len) +{ + float score; + + if ( len==0)return (int)(0.33*(float)MAXID); + + score=(float)sim/(float)len; + if (score>0.9) score=1.0; + else score=-log10 (1.0-score); + + score=(score*MAXID); + return score; +} + + +int fast_aln2sim_mat2 (char *seq1, char *seq2) +{ + int r1, r2; + int len = 0; + int sim = 0; + int c = -1; + int simm=100; +// printf("SEQ: %s %s\n", seq1, seq2); + while (seq1[++c] != '\0') + { + r1=tolower (seq1[c]); + r2=tolower (seq2[c]); + if ((r1 == '-') && (r2 == '-')) continue; + if (r1==r2) sim++; + len++; + } + + + simm = logid_score2 ( sim, len); + return simm; +} + + + +/*! + * \brief Function to create a tree using the PartTree algorithm. + * + * \param param_set A \a PartTree_param object containing all necessary parameters and the data. + * \return The node_number. + */ +void +partTree_retree(PartTree_param *param_set) +{ + int num_of_tree_nodes = param_set->num_sequences-1; + int loop_tree_node; + + Tree_fastal *tree = param_set->tree; +// int this_node = param_set->pos_tree; + + int i; +// int tsize = param_set->tsize; + + + //get some memory +// short *table1 = vcalloc(tsize, sizeof(short)); +// short *table2 = vcalloc(tsize, sizeof(short)); + char **names = declare_char(param_set->subgroup, 8); + int **dist_mat = declare_int(param_set->subgroup, param_set->subgroup); + int **dist_mat2 = declare_int(param_set->subgroup, param_set->subgroup); + char * file_name_tmp = vtmpnam(NULL); + int *seed_set_cleaned = vcalloc(param_set->subgroup, sizeof(int)); + FILE *aln_f = param_set->ktup_table_f; + long *file_positions = param_set->ktup_positions; + int max_n_group = param_set->subgroup; + int num_in_subgroup = param_set->subgroup; + int *seq_lengths = param_set->seq_lengths; + int *clusters = vcalloc(param_set->subgroup+1, sizeof(int)); + int *min_dist = vcalloc(param_set->num_sequences, sizeof(int)); + int *belongs_to = vcalloc(param_set->num_sequences, sizeof(int)); + + int aln_length = 1; + fseek(aln_f, file_positions[0], SEEK_SET); + char line[500]; + while ((fgets(line, 500, aln_f) != NULL) && (line[0] != '>')) + { + i = -1; + while ((line[++i] != '\n') && (line[i] != '\0')); + aln_length += i; + } + char *seq1 = vcalloc(aln_length, sizeof(char)); + char *seq2 = vcalloc(aln_length, sizeof(char)); + + //Prepare first node + + tree[0].index = vcalloc(param_set->num_sequences,sizeof(int)); + int *index = tree[0].index; + for (i = 0; i< param_set->num_sequences; ++i) + index[i] = i; + tree[0].name = param_set->pos_tree +param_set->num_sequences; + + tree[0].num_leafs = param_set->num_sequences; + int *sequence_group2 = vcalloc(param_set->num_sequences,sizeof(int)); +// + Tree_fastal *current_node; + for (loop_tree_node = 0; loop_tree_node < num_of_tree_nodes; ++loop_tree_node) + { +// printf("ROUND: %i\n", loop_tree_node); + current_node = &tree[loop_tree_node]; + index= current_node->index; + if (current_node->index == NULL) + { + continue; + } + int num_sequences = current_node->num_leafs; + + //if number of sequences in this group smaller than number subgoup size: make tree, finisch + if (num_sequences <= max_n_group) + { + dist_mat = make_distance_matrix_sim(aln_f, file_positions, index, num_sequences, dist_mat); + for (i = 0; i < num_sequences; ++i) + { + sprintf(names[i],"%i", current_node->index[i]); + } + NT_node **tree= (int_dist2upgma_tree_fastal (dist_mat, num_sequences, file_name_tmp , names)); + tree_process_simple(tree[0][0], param_set,loop_tree_node); + continue; + } + + + for (i = 0; i < num_in_subgroup; ++i) + { + seed_set_cleaned[i] = 1; + } + + //finde longest sequence and put into the first field + + int index_longest = 0; + int length_of_longest = 0; + + for(i = 0; i < num_sequences; ++i) + { + if (seq_lengths[index[i]] > length_of_longest) + { + index_longest = i; + length_of_longest = seq_lengths[index[i]]; + } + } + int tmp = index[index_longest]; + index[index_longest] = index[0]; + index[0] = tmp; + + //distance of longest to rest + int seq_index = 1; + read_sequence_from_position(aln_f, file_positions[index[0]], seq1); + int min = -1; + + + for (i = 1; i < num_sequences; ++i) + { + read_sequence_from_position(aln_f, file_positions[index[1]], seq2); + tmp = 100 - fast_aln2sim_mat2(seq1, seq2); + if (tmp < min) + { + min = tmp; + seq_index = i; + } + } + + //get the new seed_set in the first n spaces + tmp = index[1]; + index[1] = index[seq_index]; + index[seq_index] = tmp; + int r,j; + num_in_subgroup = param_set->subgroup; + + + for (i = 2; i < num_in_subgroup; ++i) + { + r = i + rand() / ( RAND_MAX / ( num_sequences-i) + 1 ); + tmp = index[r]; + index[r] = index[i]; + index[i] = tmp; + } + + //Calculate matrix + dist_mat = make_distance_matrix_sim(aln_f, file_positions, index, param_set->subgroup, dist_mat); +// +// //Filter out sequences that are to similar & reorder +// + NT_node **upgma_tree; + + + int num_in_clean = filter(index, dist_mat, seed_set_cleaned, param_set); + + + if (num_in_clean ==1) + { + num_in_clean = 2; + seed_set_cleaned[1] = 1; + } + //make_tree + int col = 0; + int row = 0; + for (i = 0; i < num_in_subgroup; ++i) + { + if (seed_set_cleaned[i]) + { + row = col+1; + for (j = i+1; j < num_in_subgroup; ++j) + { + if (seed_set_cleaned[j]) + { + dist_mat2[row][col] = dist_mat2[col][row] = dist_mat[i][j]; + ++row; + } + } + ++col; + } + } + for (i = 0; i < num_in_clean; ++i) + { + sprintf(names[i],"%i",i); + } + upgma_tree= (int_dist2upgma_tree_fastal (dist_mat2, num_in_clean, file_name_tmp , names)); + + +// //cluster +// //calculate distances from n' to N + read_sequence_from_position(aln_f, file_positions[index[0]], seq1); +// get_table(table1, table_f, file_positions[index[0]]); + for (j = num_in_clean; j < num_sequences; ++j) + { + read_sequence_from_position(aln_f, file_positions[index[j]], seq2); + min_dist[j] = 100 - fast_aln2sim_mat2(seq1, seq2); +// min_dist[j] = euclidean_dist_half(table_f, file_positions[index[j]], table1, table2, param_set->tsize); + belongs_to[j] = 0; + } + for(i = 1; i < num_in_clean; ++i) + { + read_sequence_from_position(aln_f, file_positions[index[0]], seq1); +// get_table(table1, table_f, file_positions[index[i]]); + belongs_to[i] = i; + for (j = num_in_clean; j < num_sequences; ++j) + { + read_sequence_from_position(aln_f, file_positions[index[j]], seq2); + tmp = 100 - fast_aln2sim_mat2(seq1, seq2); +// tmp = euclidean_dist_half(table_f, file_positions[index[j]], table1, table2, param_set->tsize); + if (tmp < min_dist[j]) + { + min_dist[j] = tmp; + belongs_to[j] = i; + } + } + } +// + //how_many sequences has each cluster + for (j = 0; j <= num_in_subgroup; ++j) + { + clusters[j] = 0; + } + for (j = 0; j < num_sequences; ++j) + { + ++clusters[belongs_to[j]]; + } +// for (j = 0; j <= num_in_subgroup; ++j) +// { +// printf("CL: %i ",clusters[j]); +// } +// printf("\n"); + for(i = 1; i < num_in_clean; ++i) + { + clusters[i] += clusters[i-1]; + } + clusters[num_in_clean] = clusters[num_in_clean-1]; + + for (i = 0; i < num_sequences; ++i) + { + sequence_group2[--clusters[belongs_to[i]]] = index[i]; + } + + for (i = 0; i < num_sequences; ++i) + { + index[i] = sequence_group2[i]; + } + + + for (i = 0; i < num_in_clean; ++i) + { + sprintf(names[i],"%i",i); + } + tree_process(upgma_tree[0][0], param_set, clusters, index, loop_tree_node); + NT_node tmp_tree = upgma_tree[3][0]; + vfree(upgma_tree[0]); + vfree(upgma_tree[1]); + vfree(upgma_tree[2]); + vfree(upgma_tree[3]); + vfree(upgma_tree); + free_tree(tmp_tree); + } +// exit(1); + vfree(min_dist); + vfree(belongs_to); + vfree(clusters); +} + +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/pavie_dp.c b/binaries/src/tcoffee/t_coffee_source/pavie_dp.c new file mode 100644 index 0000000..9f91014 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/pavie_dp.c @@ -0,0 +1,1411 @@ +#include +#include +#include +#include +#include +#include +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" +#include "dp_lib_header.h" + + +static double mc_delta_matrix ( int ***mat1, int ***mat2, char **alp, int nch); +static double delta_matrix ( int **mat1,int **mat2, char *alp); +static double ***pavie_seq2pavie_fmat (Sequence *S,double *gop, double *gep, char **mat, char *idmat, int id_threshold, int sample_size, int nch, char *param ); +static int **pavie_fmat2pavie_logodd_mat (double **fmat, char *alp); +static double **pavie_aln2fmat(Alignment *A, double **fmat, char *idmat, int id_threshold, int ch, int nch, char *param); +static int pavie_mat2pavie_id_mat ( int **mat,char *in_name, char *alp, char *ignore, char *force,int T, char *out_name); +static double paviemat2gep ( int **mat, char *alp); +static Alignment *align_pavie_sequences (char *seq0,char *seq1,char **mat,double *gop,double *gep,int nch, char *param); +static int pavie_score (char *s0,int p0, char *s1,int p1,char **mat_file, double *gop, double *gep, int nch, float factor, char *param); +static char **seq2pavie_alp (Sequence *S, int nch); +static Sequence * seq2pavie_seq ( Sequence *S, int nch); +static FILE* output_pavie_aln (Alignment *A, int nch, FILE *fp); +static char **output_pavie_mat_list ( int ***current_mat, double *gep, char **alp, int nch,char *prefix,int cycle, char **mat_name); +static float pavie_aln2id ( Alignment *A, int mode); +static int check_pavie_cl ( char *string); +float pavie_aln2delta_age ( Alignment *A,int s0, int s1, int a0, int a1); + +static float tgep_factor; +static int id_thres_used_aln; +static int log_odd_mode; +Sequence * pavie_seq2noisy_seq ( Sequence *S, int freq, char *alp) +{ + int a, b, l1, l2; + + vsrand(0); + + if (alp==NULL) + { + char **x; + x=seq2pavie_alp (S,1); + alp=x[0]; + } + + l2=strlen (alp); + for (a=0; a< S->nseq; a++) + { + l1=strlen (S->seq[a]); + for ( b=0; bseq[a][b]=alp[rand()%l2]; + } + } + return S; +} +Sequence * pavie_seq2random_seq ( Sequence *S, char *subst) +{ + int a, b, r, l; + + + vsrand (0); + r=subst[0]; subst++; + l=strlen (subst); + for ( a=0; a< S->nseq; a++) + for (b=0; blen[a]; b++) + if ( S->seq[a][b]==r)S->seq[a][b]=subst[rand()%l]; + return S; +} + +double **pavie_seq2pavie_aln(Sequence *S,char *mat, char *mode) +{ + int a, b,c, nch=0; + char **mat_list; + char *buf; + + double *gep, *gop; + Alignment *A; + char **alp; + char *pavie_idmat; + FILE *fp; + double **dist_mat; + float score; + + check_pavie_cl (mode); + + mat_list=declare_char (100, 100); + + if ( is_matrix (mat)) + { + sprintf ( mat_list[nch++], "%s", mat); + } + else + { + fp=vfopen (mat,"r"); + while ( (c=fgetc(fp))!=EOF) + { + ungetc(c, fp); + fscanf (fp, "%s\n",mat_list[nch++]); + } + vfclose (fp); + } + + alp=seq2pavie_alp (S, nch); + S=seq2pavie_seq (S, nch); + + gop=vcalloc (nch, sizeof (double)); + gep=vcalloc (nch, sizeof (double)); + + for ( a=0; a< nch; a++) + { + int **m; + char *st; + int v; + m=read_matrice (mat_list[a]); + if ((st=vstrstr(mode, "_GEP"))) + { + sscanf ( st, "_GEP%d_", &v); + gep[a]=v*-1; + } + else if ( m[0][GAP_CODE]==0) + { + gep[a]=paviemat2gep(m,alp[a]); + } + else + { + gep[a]=m[0][GAP_CODE]; + } + free_int (m, -1); + } + + + if ( (buf=vstrstr (mode, "_TGEPF"))) + { + + sscanf (buf, "_TGEPF%f_", &tgep_factor); + tgep_factor/=(float)100; + } + else + { + tgep_factor=0.5; + } + + pavie_idmat=vtmpnam(NULL); + + pavie_mat2pavie_id_mat (NULL,"idmat", alp[0],"X","",1,pavie_idmat); + dist_mat=declare_double ( S->nseq, S->nseq); + + + + for ( a=0; a< S->nseq-1; a++) + { + for ( b=a+1; b< S->nseq; b++) + { + int a0, a1; + float delta_a; + + + if ( ! strstr (mode, "_MSA_")) + { + A=align_pavie_sequences (S->seq[a],S->seq[b],mat_list,gop,gep,nch, mode); + sprintf ( A->name[0], "%s", S->name[a]); + sprintf ( A->name[1], "%s", S->name[b]); + } + else + { + + A=strings2aln ( 2, S->name[a], S->seq[a], S->name[b], S->seq[b]); + sprintf ( A->seq_al[0], "%s", S->seq[a]); + sprintf ( A->seq_al[1], "%s", S->seq[b]); + A->len_aln=strlen (S->seq[a]); + ungap_aln (A); + } + + if (strm (mode, "_ID01_"))A->score=score=pavie_aln2id (A, 1); + else if ( vstrstr (mode, "_ID02_"))A->score=score=pavie_aln2id (A, 2); + else if ( vstrstr (mode, "_ID04_"))A->score=score=pavie_aln2id (A, 4); + else if ( vstrstr (mode, "_ID05_"))A->score=score=pavie_aln2id (A, 5); + else if ( vstrstr (mode, "_ID06_"))A->score=score=pavie_aln2id (A, 6); + + else A->score=score=pavie_aln2id (A, 1); + + a0=S->seq[a][strlen(S->seq[a])+1]; + a1=S->seq[b][strlen(S->seq[b])+1]; + + delta_a=pavie_aln2delta_age (A, 0, 1, a0, a1); + + if ( vstrstr (mode, "_MATDIST_")) + dist_mat[a][b]=dist_mat[b][a]=(double)(vstrstr (mode, "_ID05") || vstrstr (mode, "_ID06"))?-score*100:(100-score); + else if ( vstrstr (mode, "_MATSIM_")) + dist_mat[a][b]=dist_mat[b][a]=(double)(score); + + + if ( !vstrstr (mode, "_MAT") ) + { + fprintf ( stdout, "#############\nAlignment %s %s: %d %% ID SCORE %d DELTA_AGE %.2f\n", S->name[a], S->name[b], A->score, A->score_aln, delta_a); + output_pavie_aln (A,nch, stdout); + } + free_aln(A); + } + } + + if ( vstrstr (mode, "_MAT") && !vstrstr ( mode, "_NOPRINT_")) + { + if ( vstrstr (mode, "_MFORMAT2")) + { + int max, n; + float *tot,s, bigtot=0; + + for (max=0, a=0; a< S->nseq; a++)max=MAX(max,(strlen (S->name[a]))); + tot=vcalloc ( S->nseq, sizeof (float)); + fprintf (stdout, "# TC_DISTANCE_MATRIX_FORMAT_01\n"); + for ( a=0; anseq; a++) + fprintf ( stdout, "# SEQ_INDEX %s %d\n",S->name[a],a); + fprintf ( stdout, "# PW_SEQ_DISTANCES \n"); + for (n=0,a=0;a< S->nseq-1; a++) + { + for ( b=a+1; bnseq; b++, n++) + { + s=dist_mat[a][b]; + + fprintf (stdout, "BOT\t %4d %4d\t %5.2f %*s\t %*s\t %5.2f\n", a,b,s,max,S->name[a], max, S->name[b], s); + fprintf (stdout, "TOP\t %4d %4d\t %5.2f %*s\t %*s\t %5.2f\n", b,a,s,max,S->name[b], max, S->name[a], s); + tot[a]+=s; + tot[b]+=s; + bigtot+=s; + } + } + for ( a=0; a< S->nseq; a++) + { + fprintf (stdout, "AVG\t %d\t %*s\t %*s\t %5.2f\n", a,max,S->name[a], max, "*", tot[a]/(S->nseq-1)); + } + vfree (tot); + fprintf (stdout, "TOT\t %*s\t %*s\t %5.2f\n", max,"TOT", max, "*", bigtot/n); + vfclose (stdout); + } + else + { + for ( a=0; anseq; a++) + { + fprintf ( stdout, "\n%s ", S->name[a]); + for ( b=0; b< S->nseq; b++) + fprintf ( stdout, "%6d ", (int)(dist_mat[a][b]*100)); + } + } + } + + return dist_mat; +} + +float pavie_aln2delta_age ( Alignment *A,int s0, int s1, int a0, int a1) +{ + int a,r0, r1, g0, g1, n; + float delta; + for (n=0, delta=0, a=0; a< A->len_aln; a++) + { + r0=A->seq_al[s0][a]; + r1=A->seq_al[s1][a]; + + g0=!is_gap(r0); + g1=!is_gap(r1); + + a0+=g0;a1+=g1; + if ( g0 && g1) + { + delta+=FABS((a0-a1)); + n++; + } + } + delta/=(float)((n)?n:1); + return delta; +} + +int **pavie_seq2trained_pavie_mat(Sequence *S, char *param) +{ + double ***fmat; + int ***current_mat; + int ***previous_mat; + char **alp; + + char **mat_file; + double d,delta_min=10; + double *gep; + double *gop; + + char ignore[100]; + char force [100]; + char pavie_idmat[100]; + int id_threshold; + int sample_size; + char *b; + int a,n=0,nch=1; + char *buf; + + check_pavie_cl (param); + + if ( !param)param=vcalloc (1, sizeof (char)); + + if ((b=vstrstr(param,"_THR")))sscanf ( b, "_THR%d_", &id_threshold); + else id_threshold=0; + + sample_size=0; + if ((b=vstrstr(param,"_SAMPLE")))sscanf ( b, "_SAMPLE%d_", &sample_size); + if ((b=vstrstr(param,"_PARALOGOUS"))) + { + sscanf ( b, "_PARALOGOUS%d_", &sample_size); + sample_size*=-1; + } + + if ((b=vstrstr(param,"_CHANNEL")))sscanf ( b, "_CHANNEL%d_", &nch); + else nch=1; + + if ( (buf=vstrstr (param, "_TGEPF"))) + { + sscanf (buf, "_TGEPF%f_", &tgep_factor); + tgep_factor/=(float)100; + } + else + { + tgep_factor=0.5; + } + if ( (buf=vstrstr (param, "_PAMLOGODD_"))) + { + log_odd_mode=1; + } + /*Declare Arrays*/ + gep=vcalloc (nch, sizeof (double)); + gop=vcalloc (nch, sizeof (double)); + mat_file=declare_char ( nch, 100); + current_mat =vcalloc ( nch, sizeof (double**)); + previous_mat=vcalloc ( nch, sizeof (double**)); + + + sprintf (ignore, "X"); + force[0]='\0'; + sprintf ( pavie_idmat, "pavie_idmat"); + + + + alp=seq2pavie_alp (S, nch); + + S=seq2pavie_seq (S, nch); + + pavie_mat2pavie_id_mat (NULL,"idmat", alp[0],ignore,force,1,pavie_idmat); + + for ( a=0; adelta_min) + { + + fprintf ( stdout, "\nDelta=%d: ",(int) d); + for (a=0; anseq-exclude_id; a++) + { + + output_completion ( stderr,a+1,S->nseq,1, ""); + + for ( b=a+exclude_id; b< S->nseq; b++) + { + tot++; + + A=align_pavie_sequences (S->seq[a],S->seq[b],mat,gop,gep,nch,param); + + for ( chan=0; chan< nch; chan++) + { + + fmat[chan]=pavie_aln2fmat (A, fmat[chan], idmat, id_threshold, chan, nch, param); + } + free_aln (A); + } + } + } + else + { + int c; + static int **list; + + if ( sample_size>0 && !list) + { + if ( exclude_id==0)sample_size*=3; + if (!list) + { + list=declare_int ((sample_size+1), 2); + vsrand(0); + tot=0; + while (totnseq);b=rand()%(S->nseq); + if ( a!=b) + { + list[tot][0]=a;list[tot][1]=b; + tot++; + if ( exclude_id==0) + { + list[tot][0]=a;list[tot][1]=a; + tot++; + list[tot][0]=b;list[tot][1]=b; + tot++; + } + } + } + } + } + else if ( sample_size<0 && !list) + { + + int **sim; + int m; + sim=seq2sim_mat (S, "idmat"); + sample_size*=-1; + list=declare_int (S->nseq*S->nseq, 2); + + m=S->nseq-exclude_id; + for (a=0; anseq; b++) + { + if ( sim[a][b]>sample_size) + { + list[tot][0]=a; + list[tot][1]=b; + tot++; + fprintf ( stderr, "\n%s %s: %d", S->name[a], S->name[b], sim[a][b]); + fprintf ( stderr, "\nKeep %s Vs %s : %d%% ID", S->name[a], S->name[b], sim[a][b]); + } + } + free_int(sim, -1); + } + + for (c=0; cseq[a],S->seq[b],mat,gop,gep,nch, param); + for (chan=0; chan< nch; chan++) + fmat[chan]=pavie_aln2fmat (A, fmat[chan], idmat, id_threshold,chan, nch, param); + + free_aln (A); + output_completion ( stderr,c,tot,1, ""); + } + } + fprintf ( stderr, "\n\tSample_size: %d Used alignments: %d\n", tot, id_thres_used_aln); + return fmat; +} + + + +int **pavie_fmat2pavie_logodd_mat (double **fmat, char *alp) +{ + int s1, s2,S1, S2; + double r1, r2; + int **mat; + int a, b; + int ns; + int logodd=0; + + + ns=strlen (alp); + mat=declare_int (256, 256); + + for ( a=0; alen_aln/nch); + start=l*ch; + A->len_aln=l; + A->seq_al[0]+=start; + A->seq_al[1]+=start; + + + + if ( fmat==NULL)fmat=declare_double(300, 300); + + if ( vstrstr (param, "_TWE00_"))w=100; + else if ( vstrstr (param, "_TWE01_"))w=pavie_aln2id (A, 1); + else if ( vstrstr (param, "_TWE02_"))w=pavie_aln2id (A, 2); + else if ( vstrstr (param, "_TWE03_"))w=pavie_aln2id (A, 3); + else if ( vstrstr (param, "_TWE04_"))w=pavie_aln2id (A, 4); + else if ( vstrstr (param, "_TWE05_"))w=pavie_aln2id (A, 5); + else if ( vstrstr (param, "_TWE06_"))w=pavie_aln2id (A, 6); + + else w=pavie_aln2id (A, 3); + + id=pavie_aln2id(A, 3); + + + if (idlen_aln*=nch; + A->seq_al[0]-=start;A->seq_al[1]-=start; + return fmat; + } + else + { + id_thres_used_aln++; + for ( a=0; alen_aln; a++) + { + c1=tolower(A->seq_al[0][a]); + c2=tolower(A->seq_al[1][a]); + fmat[c1][c2]+=w; + + fmat[c1][0]++; + fmat[c1][1]+=w; + + fmat[c2][0]++; + fmat[c1][1]+=w; + + fmat[0][0]+=2; + fmat[1][1]+=2*w; + } + A->len_aln*=nch; + A->seq_al[0]-=start;A->seq_al[1]-=start; + + return fmat; + } +} + +int pavie_mat2pavie_id_mat ( int **mat,char *in_name, char *alp, char *ignore, char *force,int T, char *out_name) +{ + int n1, n2, n3; + int s1, s2, S1, S2; + int a, b; + int **idmat; + + if (mat==NULL && in_name==NULL) return 0; + else if (mat==NULL) + { + mat=read_matrice (in_name); + } + + + idmat=declare_int ( 256, 256); + n1=strlen (alp); + n2=strlen (ignore); + n3=strlen (force); + + for (a=0; a< n1; a++) + for ( b=0; b=T)?PAVIE_MAT_FACTOR:0; + } + for (a=0; alen_aln=strlen (seq0); + A->nseq=2; + A->score=A->score_aln=100; + sprintf ( A->seq_al[0], "%s", seq1); + sprintf ( A->seq_al[1], "%s", seq0); + return A; + } + + + x=seq0; + y=seq1; + + XL=strlen (x)/nch; + YL=strlen (y)/nch; + + + ax=vcalloc ( (YL+XL)*nch+1, sizeof (char)); + ay=vcalloc ( (YL+XL)*nch+1, sizeof (char)); + bufx=vcalloc ( (YL+XL)*nch+1, sizeof (char)); + bufy=vcalloc ( (YL+XL)*nch+1, sizeof (char)); + + F=declare_double (XL+2, YL+2); + T=declare_int (XL+2, YL+2); + + + /*Fill stage*/ + F[0][0] = 0; + for(i = 1; i <=XL; i++) + { + + F[i][0] = F[i-1][0]+pavie_score (x,i-1,NULL,GAP_CODE,mat, gop, gep, nch, factor, param) /*CL->M[x[i-1]-'A'][gap]*/; + + T[i][0] = GY; + } + + for(j = 1; j <= YL; j++) + { + + F[0][j] = F[0][j-1]+pavie_score (NULL,GAP_CODE,y,j-1,mat, gop, gep, nch, factor, param)/*CL->M[y[j-1]-'A'][gap]*/; + T[0][j] = GX; + } + + + for(i = 1; i <= XL; i++) + { + for(j = 1; j <= YL; j++) + { + + match = F[i-1][j-1] + /*CL->M[x[i-1]-'A'][y[j-1]-'A']*/pavie_score (x,i-1,y, j-1,mat, gop, gep, nch, 1, param); + gap_inY= F[i-1][j] + /*CL->M[x[i-1]-'A'][gap]*/ pavie_score (x,i-1, NULL,GAP_CODE,mat, gop, gep, nch, (j==YL)?factor:1, param); + gap_inX= F[i][j-1] + /*+ CL->M[y[j-1]-'A'][gap]*/ pavie_score (NULL,GAP_CODE,y, j-1,mat, gop, gep, nch, (i==XL)?factor:1, param); + + if ( match >= gap_inY && match >=gap_inX){F[i][j]=match; T[i][j]=MXY;} + else if ( gap_inX>=gap_inY){F[i][j]=gap_inX; T[i][j]=GX;} + else {F[i][j]=gap_inY; T[i][j]=GY;} + } + } + /*Trace back stage*/ + + + i = XL; + j = YL; + len=0; + while(!(i==0 && j==0)) + { + + if (T[i][j]==MXY) + { + ax[len]=1;i--; + ay[len]=1;j--; + } + else if ( T[i][j]==GY) + { + ax[len]=1;i--; + ay[len]='-'; + } + else if ( T[i][j]==GX) + { + ax[len]='-'; + ay[len]=1;j--; + } + len++; + } + + for (a=0; alen_aln=strlen (ax); + A->nseq=2; + A->score=A->score_aln=F[XL][YL]; + + for (a=0, b=0, c=0; alen_aln; a++) + { + if (ax[a]==1)ax[a]=seq0[b++]; + if (ay[a]==1)ay[a]=seq1[c++]; + } + + + + sprintf ( A->seq_al[0], "%s", ax); + sprintf ( A->seq_al[1], "%s", ay); + + vfree (ax); vfree(ay);vfree (bufx); vfree (bufy);free_double(F, -1); free_int (T, -1); + return A; +} + + +int pavie_score (char *s0,int p0, char *s1,int p1,char **mat_file, double *gop, double *gep, int nch, float factor, char *param) + + { + static char *cmat; + static int ***mat; + static int use_age; + static int mchscore=-1; + + int l0, l1, c0, c1; + int a, score=0; + + if ( !use_age) + { + strget_param ( param, "_AGECHANNEL", "-1", "%d", &use_age); + + } + if (mchscore==-1) + { + strget_param (param, "_MCHSCORE", "0", "%d", &mchscore); + + } + + if ( !cmat || !mat_file || !strm (cmat, mat_file[0])) + { + if ( !cmat)cmat=vcalloc ( 100, sizeof (char)); + sprintf ( cmat, "%s", (mat_file)?mat_file[0]:"idmat"); + if ( !mat)mat=vcalloc ( nch, sizeof (int**)); + for ( a=0; a< nch; a++) + { + if ( mat[a])free_int (mat[a], -1); + mat[a]=read_matrice ((mat_file)?mat_file[a]:"idmat"); + + } + } + + l0=(s0)?strlen (s0)/nch:0; + l1=(s1)?strlen (s1)/nch:0; + + if (mchscore==0); + else if (mchscore==1) score=999999; + else if (mchscore==2)score=-9999999; + else + { + HERE ("Error: mchscore >2 [FATAL]\n"); + exit (EXIT_FAILURE); + } + for ( a=0; a< nch; a++) + { + int s; + c0=(s0)?s0[l0*a+p0]-'A':p0; + c1=(s1)?s1[l1*a+p1]-'A':p1; + if ( c0==GAP_CODE)s=(gep[a]!=0)?gep[a]:mat[a][c1][GAP_CODE]; + else if ( c1==GAP_CODE)s=(gep[a]!=0)?gep[a]:mat[a][c0][GAP_CODE]; + else s=mat[a][c0][c1]; + + if (mchscore==0)score+=s; + else if (mchscore==1)score=MIN(s, score); + else if (mchscore==2)score=MAX(s, score); + + + } + + if ( use_age>0 && s0 && s1) + { + + int a0, a1; + int s; + + a0=s0[strlen(s0)+1]; + a1=s1[strlen(s1)+1]; + + a0+=p0; + a1+=p1; + s=use_age*FABS((a0-a1))*-1; + + if (mchscore==0)score+=s; + else if (mchscore==1)score=MIN(s, score); + else if (mchscore==2)score=MAX(s, score); + } + + + score*=factor; + return score; + } +Sequence * seq2pavie_seq ( Sequence *S, int nch) + { + char *buf, *p; + int a, b; + + S->nseq/=nch; + + for (b=0; bnseq; b++) + { + + buf=vcalloc ((strlen (S->seq[b])*nch)+10, sizeof (char)); + for ( a=0; a< nch; a++) + { + strcat (buf, S->seq[b+(S->nseq)*a]); + vfree ( S->seq[b+(S->nseq)*a]); + } + S->seq[b]=buf; + /*Code Age on the byte just after the string termination*/ + + if ((p=strstr (S->seq_comment[b], "FIRSTYEAR"))) + { + sscanf ( p, "FIRSTYEAR%d", (int*)&(S->seq[strlen(buf)+1])); + } + + } + return S; + } +char **seq2pavie_alp (Sequence *S, int nch) + { + int a, n; + char **alp; + + n=S->nseq/nch; + alp=vcalloc (nch, sizeof (char*)); + for ( a=0; a< nch; a++) + { + alp[a]=array2alphabet (S->seq+n*a, n, "-."); + } + return alp; + } +FILE *output_pavie_aln (Alignment *A, int nch, FILE *fp) +{ + int a, b, c,d, l, start, end; + Alignment *B; + Sequence *S; + B=declare_aln2(A->nseq*nch+nch, A->len_aln); + + + + l=A->len_aln/nch; + + for ( a=0; a< nch; a++) + { + for (b=0; b< A->nseq; b++, B->nseq++) + { + sprintf (B->name[B->nseq], "%s.c%d", A->name[b], a); + start=l*a;end=start+l; + for (d=0,c=start; cseq_al[B->nseq][d]=A->seq_al[b][c]; + B->seq_al[B->nseq][d]='\0'; + } + if ( a!=nch-1) + { + B->name[B->nseq][0]='\0'; + for ( b=0; bseq_al[B->nseq][b]='^'; + B->nseq++; + } + } + + B->len_aln=l; + fp=output_Alignment_without_header (B,fp); + S=free_aln (B); + free_sequence (S, S->nseq); + return fp; + +} +char **output_pavie_mat_list ( int ***current_mat, double *gep, char **alp, int nch,char *prefix,int cycle, char **mat_name) +{ + int a; + char mat_list_name[100]; + FILE *fp; + char latest[1000]; + char current[1000]; + char command[1000]; + + sprintf ( mat_list_name, "pavie_matrix%s.cycle_%d.mat_list", prefix, cycle+1); + fp=vfopen ( mat_list_name, "w"); + fprintf ( stderr, "\n\tOutput Pavie Matrix: %s", mat_list_name); + for ( a=0; a< nch; a++) + { + sprintf ( mat_name[a], "pavie_matrix%s.ch_%d.cy_%d.pavie_mat", prefix,a+1, cycle+1); + sprintf (latest, "pavie_matrix%s.ch_%d.cy_last.pavie_mat",prefix,a+1); + sprintf ( current, "matrix.ch%d.pavie_mat", a); + fprintf ( stderr, "\n\t Channel %d Matrix: %s",a+1, mat_name[a]); + output_pavie_mat (current_mat[a],mat_name[a],gep[a], alp[a]); + sprintf ( command, "cp %s %s", mat_name[a], latest); + system (command); + sprintf ( command, "cp %s %s", latest, current); + system (command); + fprintf ( fp, "%s\n", mat_name[a]); + } + vfclose (fp); + return mat_name; +} + + +int pavie_pair_wise (Alignment *A,int *ns, int **l_s,Constraint_list *CL ) +{ + double **F; int **T; + char *x,*y; + char *ax, *ay; + int XL, YL, len; + int i, j; + double match, gap_inX, gap_inY, MXY=1, GX=2, GY=3; + int gap=GAP_CODE; + char *ix, *iy; + float factor=0.5; + + + /*factor: + decreases terminal gap penalties with a factor X + factor=1: terminal gap penalties <=> internal gap penalties + */ + + + + x=A->seq_al[l_s[0][0]]; + y=A->seq_al[l_s[1][0]]; + XL=strlen (x); + YL=strlen (y); + + ax=vcalloc ( YL+XL+1, sizeof (char)); + ay=vcalloc ( YL+XL+1, sizeof (char)); + + + F=declare_double (XL+2, YL+2); + T=declare_int (XL+2, YL+2); + + + /*Fill stage*/ + F[0][0] = 0; + for(i = 1; i <=XL; i++) + { + + F[i][0] = F[i-1][0]+(CL->M[x[i-1]-'A'][gap]*factor); + T[i][0] = GY; + } + + for(j = 1; j <= YL; j++) + { + F[0][j] = F[0][j-1]+CL->M[y[j-1]-'A'][gap]*factor; + T[0][j] = GX; + } + + + for(i = 1; i <= XL; i++) + { + for(j = 1; j <= YL; j++) + { + + match = F[i-1][j-1] + CL->M[x[i-1]-'A'][y[j-1]-'A']; + gap_inY= F[i-1][j] + (CL->M[x[i-1]-'A'][gap]*(j==YL)?factor:1); + gap_inX= F[i][j-1] + (CL->M[y[j-1]-'A'][gap]*(i==XL)?factor:1); + + if ( match >= gap_inY && match >=gap_inX){F[i][j]=match; T[i][j]=MXY;} + else if ( gap_inX>=gap_inY){F[i][j]=gap_inX; T[i][j]=GX;} + else {F[i][j]=gap_inY; T[i][j]=GY;} + } + } + /*Trace back stage*/ + A->score=A->score_aln=F[XL][YL]; + + i = XL; + j = YL; + len=0; + while(!(i==0 && j==0)) + { + + if (T[i][j]==MXY) + { + ax[len]=x[--i]; + ay[len]=y[--j]; + } + else if ( T[i][j]==GY) + { + ax[len]=x[--i]; + ay[len]='-'; + } + else if ( T[i][j]==GX) + { + ax[len]='-'; + ay[len]=y[--j]; + } + len++; + } + ax[len]='\0'; + ay[len]='\0'; + + ix=invert_string (ax); iy=invert_string(ay); + A=realloc_aln (A,len+1); + + sprintf ( A->seq_al[l_s[0][0]], "%s", ix); + sprintf ( A->seq_al[l_s[1][0]], "%s", iy); + A->nseq=2; + A->len_aln=len; + + vfree (ax); vfree(ay);vfree(ix); vfree(iy); free_double(F, -1); free_int (T, -1); + return A->score; +} + +float pavie_aln2id ( Alignment *A, int mode) +{ + int a, id=0, match=0, l1=0, l2=0, r1, r2, is_res1, is_res2; + + + + for (a=0; alen_aln; a++) + { + r1=A->seq_al[0][a]; + r2=A->seq_al[1][a]; + + + is_res1=(!is_gap(r1) && r1!='x' && r1!='X')?1:0; + is_res2=(!is_gap(r2) && r2!='x' && r2!='X')?1:0; + + l1+=is_res1; + l2+=is_res2; + + + if ( is_res1 && is_res2 ) + { + match++; + id+=(r1==r2)?1:0; + } + } + + + if ( mode==1)return (match==0)?0:((id*100)/match); + else if (mode ==2) return (A->len_aln==0)?0:((id*100)/A->len_aln); + else if (mode ==3) return (MIN(l1,l2)==0)?0:((id*100)/(MIN(l1,l2))); + else if (mode ==4) return (MAX(l1,l2)==0)?0:((id*100)/(MAX(l1,l2))); + else if (mode ==5)return (A->score_aln * -1)/*/PAVIE_MAT_FACTOR*/; + else if (mode ==6)return ((MAX(l1,l2)==0)?0:((A->score_aln)/(MAX(l1,l2))))*-1; + else + { + fprintf ( stderr, "\nUnknown Mode [pavie_aln2id:FATAL:%s]", PROGRAM); + myexit (EXIT_FAILURE); + return EXIT_FAILURE; + } + +} + +int check_pavie_cl ( char *string) +{ + if ( !string || string[0]=='\0' ) return 1; + else if (( string[0]!='_') ||string [strlen (string)-1]!='_') + { + fprintf ( stderr, "ERROR: parameters must start and finish with an underscore: _parameters_ [FATAL:%s]\n", PROGRAM); + myexit (EXIT_FAILURE); + } + return 1; +} + +Alignment *pavie_seq2pavie_sort ( Sequence *S, char *mat, char *mode) +{ + int a, b, c=0, avg_c; + int **avg; + double **dm; + Alignment *A=NULL; + char **new_order; + + if ( vstrstr (mode, "_IDSORT_") || vstrstr (mode, "_MASTERSORT")) + { + char *buf; + buf=vcat ( mode, "_MATDIST_NOPRINT_"); + dm=pavie_seq2pavie_aln (S, mat,buf); + avg=declare_int (S->nseq, 2); + if ( vstrstr (mode,"_IDSORT_")) + { + + for ( a=0; a< S->nseq; a++) + { + avg[a][0]=a; + for ( b=0; bnseq; b++) + if ( b!=a)avg[a][1]+=(int) dm[a][b]; + avg[a][1]/=S->nseq-1; + } + sort_int ( avg, 2, 1, 0, S->nseq-1); + + c=avg[0][0]; + avg_c=avg[0][1]; + fprintf ( stderr, "\nAVG\t %s\t %s\t %d",S->name[c],"avg", avg_c); + } + else if ( vstrstr (mode, "_MASTERSORT")) + { + char name[100]; + char *s; + s=vstrstr(mode, "_MASTERSORT"); + mode=substitute ( mode, "_", " "); + sscanf (s, " MASTERSORT%s", name); + + mode=substitute (mode, " ", "_"); + c=name_is_in_list ( name, S->name, S->nseq, 100); + + if ( c==-1) + { + fprintf ( stderr, "\nERROR: Sequence %s is not in the dataset [FATAL:%s]", name, PROGRAM); + myexit (EXIT_FAILURE); + } + } + + for ( a=0; anseq; a++) + { + avg[a][0]=a; + if ( a!=c)avg[a][1]=dm[c][a]; + else avg[a][1]=-1; + } + + sort_int ( avg, 2, 1, 0, S->nseq-1); + + new_order=declare_char ( S->nseq, 100); + sprintf (new_order[0], "%s", S->name[c]); + for ( a=1; anseq; a++) + { + sprintf ( new_order[a], "%s", S->name[avg[a][0]]); + + fprintf ( stderr, "\nTOP\t %s\t %s\t %d", S->name[c],new_order[a] , avg[a][1]); + } + + fprintf ( stderr, "\n"); + A=seq2aln (S, NULL,RM_GAP); + A=reorder_aln (A, new_order, A->nseq); + vfree ( buf); + free_double(dm, -1);free_int (avg, -1);free_char (new_order, -1); + } + else if ( vstrstr ( mode, "_TREESORT_")) + { + A=pavie_seq2pavie_msa (S, mat, mode); + } + else + { + fprintf ( stderr, "\nERROR: pavie_seq2sort <_IDSORT_ | _TREESORT_>"); + } + return A; + +} +NT_node pavie_seq2pavie_tree (Sequence *S, char *mat, char *mode) +{ + double **dm; + char *tree_name,*buf; + + + buf=vcat (mode,"_MATDIST_NOPRINT_"); + dm=pavie_seq2pavie_aln (S, mat,buf); + dist2nj_tree (dm,S->name, S->nseq,tree_name=vtmpnam (NULL)); + + free_double(dm, -1);vfree (buf); + + return main_read_tree (tree_name); +} + +Alignment* pavie_seq2pavie_msa ( Sequence *S, char *mat_in, char *mode) +{ + Constraint_list *CL; + char **alp, *s; + Alignment *A; + NT_node **FT, T; + int a; + char mat[100]; + + + A=seq2aln (S, NULL, RM_GAP); + CL=declare_constraint_list (S, NULL, NULL, 0, NULL, NULL); + sprintf ( CL->dp_mode, "myers_miller_pair_wise"); + sprintf ( CL->tree_mode, "nj"); + sprintf ( CL->distance_matrix_mode, "idscore"); + CL=choose_extension_mode ("matrix", CL); + + if ( !is_matrix (mat_in)) + { + FILE *fp; + fp=vfopen ( mat_in, "r"); + fscanf (fp, "%s", mat); + vfclose (fp); + add_warning( stderr, "\nWarning: Multiple Channel Not Supported. Used First Channel Only for MSA [Matrix: %s][WARNING:%s]", mat, PROGRAM); + } + else + { + sprintf ( mat, "%s", mat_in); + } + + CL->M=read_matrice (mat); + CL->gop=0; + + alp=seq2pavie_alp (S, 1); + CL->gep=paviemat2gep(CL->M, alp[0]); + + + CL->pw_parameters_set=1; + CL->local_stderr=stderr; + + if ( vstrstr (mode, "_QUICKTREE_")) + { + FT=make_tree (A, CL, CL->gop, CL->gep,S, NULL,MAXIMISE); + T=FT[3][0]; + } + else if ( (s=vstrstr (mode, "_USETREE"))) + { + char fname[100]; + mode=substitute ( mode, "_", " "); + sscanf (s, " USETREE%s", fname); + mode=substitute (mode, " ", "_"); + T=main_read_tree (fname); + } + else + { + T=pavie_seq2pavie_tree ( S, mat_in, mode); + } + + for ( a=0; a< A->nseq; a++)ungap (A->seq_al[a]); + + tree_aln (T->left,T->right,A,(CL->S)->nseq, CL); + A=reorder_aln ( A,A->tree_order,A->nseq); + + return A; +} +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/pb_util_read_seq_util.c b/binaries/src/tcoffee/t_coffee_source/pb_util_read_seq_util.c new file mode 100644 index 0000000..43a6867 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/pb_util_read_seq_util.c @@ -0,0 +1,374 @@ +#include +#include +#include +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" + + +/* +* Prototypes +*/ + + +void fatal(char *,...); +void error(char *,...); +void warning(char *,...); +char *rtrim(char *); +char *blank_to_(char *); /* DES change blanks to _ */ +char *upstr(char *); +char *lowstr(char *); +void getstr(char *,char *); +double getreal(char *,double,double,double); +int getint(char *,int,int,int); +void do_system(void); +Boolean linetype(char *,char *); +Boolean blankline(char *); +void get_path(char *,char *); + +/* +* ckalloc() +* +* Tries to allocate "bytes" bytes of memory. Exits program if failed. +* Return value: +* Generic pointer to the newly allocated memory. +*/ + +void *ckalloc(size_t bytes) +{ + register void *ret; + extern void *vcalloc (size_t nelem, size_t elsize); + + if( (ret = vcalloc(bytes, sizeof(char))) == NULL) +/* + if( (ret = vmalloc(bytes)) == NULL) +*/ + fatal("Out of memory\n"); + else + return ret; + return ret; +} + +/* +* ckvrealloc() +* +* Tries to vreallocate "bytes" bytes of memory. Exits program if failed. +* Return value: +* Generic pointer to the re-allocated memory. +*/ + +void *ckvrealloc(void *ptr, size_t bytes) +{ + register void *ret; + extern void *vrealloc (void *ptr, size_t size); + + if( (ret = vrealloc(ptr, bytes)) == NULL) + fatal("Out of memory\n"); + else + return ret; + return ret; +} + +/* +* ckfree() +* +* Tries to free memory allocated by ckalloc. +* Return value: +* None. +*/ + +void ckfree(void *ptr) +{ + vfree(ptr); +} + + +/* +* fatal() +* +* Prints error msg to stderr and exits. +* Variadic parameter list can be passed. +* +* Return values: +* none +*/ + +void fatal( char *msg,...) +{ + va_list ap; + + va_start(ap,msg); + fprintf(stderr,"\n\nFATAL ERROR: "); + vfprintf(stderr,msg,ap); + fprintf(stderr,"\n\n"); + va_end(ap); + myexit(EXIT_FAILURE); +} + +/* +* error() +* +* Prints error msg to stderr. +* Variadic parameter list can be passed. +* +* Return values: +* none +*/ + +void error( char *msg,...) +{ + va_list ap; + + va_start(ap,msg); + fprintf(stderr,"\n\nERROR: "); + vfprintf(stderr,msg,ap); + fprintf(stderr,"\n\n"); + va_end(ap); +} + +/* +* warning() +* +* Prints warning msg to stderr. +* Variadic parameter list can be passed. +* +* Return values: +* none +*/ + +void warning( char *msg,...) +{ + va_list ap; + + va_start(ap,msg); + fprintf(stderr,"\n\nWARNING: "); + vfprintf(stderr,msg,ap); + fprintf(stderr,"\n\n"); + va_end(ap); +} + + +/* +* rtrim() +* +* Removes trailing blanks from a string +* +* Return values: +* Pointer to the processed string +*/ + +char * rtrim(char *str) +{ + register int p; + + p = strlen(str) - 1; + + while ( isspace(str[p]) ) + p--; + + str[p + 1] = EOS; + + return str; +} + + +/* +* blank_to_() +* +* Replace blanks in a string with underscores +* +* Also replaces , ; : ( or ) with _ +* +* Return value: +* Pointer to the processed string +*/ + +char * blank_to_(char *str) +{ + int i,p; + + + p = strlen(str) - 1; + for(i=0;i<=p;i++) + { + if( strrchr(";,():",str[i]))str[i]='_'; + else if (isspace(str[i])); + } + return str; +} + + +/* +* upstr() +* +* Converts string str to uppercase. +* Return values: +* Pointer to the converted string. +*/ + +char * upstr(char *str) +{ + register char *s = str; + + while( (*s = toupper(*s)) ) + s++; + + return str; +} + +/* +* lowstr() +* +* Converts string str to lower case. +* Return values: +* Pointer to the converted string. +*/ + +char * lowstr(char *str) +{ + register char *s = str; + + while( (*s = tolower(*s)) ) + s++; + + return str; +} + +void getstr(char *instr,char *outstr) +{ + fprintf(stdout,"%s: ",instr); + fgets(outstr, 100, stdin); +} + +double getreal(char *instr,double minx,double maxx,double def) +{ + int status; + double ret; + char line[MAXLINE]; + + while(TRUE) { + fprintf(stdout,"%s (%.1lf-%.1lf) [%.1lf]: ",instr,minx,maxx,def); + fgets(line, MAXLINE, stdin); + status=sscanf(line,"%lf",&ret); + if(status == EOF) return def; + if(ret>maxx) { + fprintf(stderr,"ERROR: Max. value=%.1lf\n\n",maxx); + continue; + } + if(retmaxx) { + fprintf(stderr,"ERROR: Max. value=%d\n\n",(pint)maxx); + continue; + } + if(ret-1;--i) { + if(str[i]==DIRDELIM) { + i = -1; + break; + } + if(str[i]=='.') break; + } + if(i<0) + strcat(path,"."); + else + path[i+1]=EOS; +} +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/pb_util_read_sequence.c b/binaries/src/tcoffee/t_coffee_source/pb_util_read_sequence.c new file mode 100644 index 0000000..b25049e --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/pb_util_read_sequence.c @@ -0,0 +1,562 @@ +/********* Sequence input routines for CLUSTAL W *******************/ +/* DES was here. FEB. 1994 */ +/* Now reads PILEUP/MSF and CLUSTAL alignment files */ + +#include +#include +#include +#include +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" + +/* +* Prototypes +*/ + +extern Boolean linetype(char *,char *); +extern Boolean blankline(char *); +extern void warning(char *,...); +extern void error(char *,...); +extern char * rtrim(char *); +extern char * blank_to_(char *); +extern void getstr(char *,char *); + +void fill_chartab(void); + + +static void get_seq(char *,char *,int *,char *); +static void get_clustal_seq(char *,char *,int *,char *,int); +static void get_msf_seq(char *,char *,int *,char *,int); +static void check_infile(int *); + + + + +static int count_clustal_seqs(void); +static int count_msf_seqs(void); + +/* + * Global variables + */ + +static FILE *fin; + + +char *amino_acid_codes = "ABCDEFGHIKLMNPQRSTUVWXYZ-"; /* DES */ +char *nucleic_acid_order = "ACGTUN"; +static int seqFormat; +static char chartab[128]; + +void fill_chartab(void) /* Create translation and check table */ +{ + register int i; + register int c; + + + for(i=0;i<128;chartab[i++]=0); + for(i=0,c=0;c<=amino_acid_codes[i];i++) + chartab[c]=chartab[tolower(c)]=c; + +} + +static void get_msf_seq(char *sname,char *seq,int *len,char *tit,int seqno) +/* read the seqno_th. sequence from a PILEUP multiple alignment file */ +{ + static char *line; + int i,j,k; + unsigned char c; + if ( !line)line=vcalloc ( (MAXLINE+1), sizeof (char)); + + fseek(fin,0,0); /* start at the beginning */ + + *len=0; /* initialise length to zero */ + for(i=0;;i++) { + if(fgets(line,MAXLINE+1,fin)==NULL) return; /* read the title*/ + if(linetype(line,"/") ) break; /* lines...ignore*/ + } + + while (fgets(line,MAXLINE+1,fin) != NULL) { + if(!blankline(line)) { + + for(i=1;i') + break; /* EOL */ + + if( (c=chartab[c])) + {seq[++(*len)]=c; + } + } + if(*len == SEQ_MAX_LEN || c == '>') break; + } + break; +/**********************************************/ + case GDE: + + while(*line != '#' ||*line != '%' ) + fgets(line,MAXLINE+1,fin); + + + + + for (i=1;i<=MAXNAMES;i++) { + if (line[i] == '(' || line[i] == '\n') + { + i--; + break; + } + sname[i-1] = line[i]; + } + sname[i]=EOS; + offset=0; + if (sname[i-1] == '(') sscanf(&line[i],"%d",&offset); + else offset = 0; + for(i=MAXNAMES-1;i > 0;i--) + if(isspace(sname[i])) { + sname[i]=EOS; + break; + } + blank_to_(sname); + + + *tit=EOS; + + *len=0; + for (i=0;i SEQ_MAX_LEN) + { + error("Sequence too long. Maximum is %d",(pint)SEQ_MAX_LEN); + return 0; /* also return zero if too many */ + } + + + + for ( a=0; a') { /* no */ + seqFormat=(line[3] == ';')?PIR:PEARSON; /* distinguish PIR and Pearson */ + (*nseqs)++; + } + else if((*line == '"') || (*line == '%') || (*line == '#')) { + seqFormat=GDE; /* GDE format */ + if (*line == '%') { + (*nseqs)++; + + } + else if (*line == '#') { + (*nseqs)++; + + } + } + else { + seqFormat=UNKNOWN; + return; + } + + while(fgets(line,MAXLINE+1,fin) != NULL) { + switch(seqFormat) { + case EMBLSWISS: + if( linetype(line,"ID") ) + (*nseqs)++; + break; + case PIR: + case PEARSON: + if( *line == '>' ) + (*nseqs)++; + break; + case GDE: + if(( *line == '%' ) ) + (*nseqs)++; + else if (( *line == '#') ) + (*nseqs)++; + break; + case CLUSTAL: + *nseqs = count_clustal_seqs(); +/* DES */ /* fprintf(stdout,"\nnseqs = %d\n",(pint)*nseqs); */ + fseek(fin,0,0); + return; + break; + case MSF: + *nseqs = count_msf_seqs(); + fseek(fin,0,0); + return; + break; + case USER: + default: + break; + } + } + fseek(fin,0,0); +} + + +static int count_clustal_seqs(void) +/* count the number of sequences in a clustal alignment file */ +{ + static char *line; + int nseqs; + + if ( !line)line=vcalloc ( (MAXLINE+1), sizeof (char)); + + while (fgets(line,MAXLINE+1,fin) != NULL) { + if(!blankline(line)) break; /* Look for next non- */ + } /* blank line */ + nseqs = 1; + + while (fgets(line,MAXLINE+1,fin) != NULL) { + if(blankline(line)) return nseqs; + nseqs++; + } + + return 0; /* if you got to here-funny format/no seqs.*/ +} + +static int count_msf_seqs(void) +{ +/* count the number of sequences in a PILEUP alignment file */ + + static char *line; + int nseqs; + + if ( !line)line=vcalloc ( (MAXLINE+1), sizeof (char)); + + while (fgets(line,MAXLINE+1,fin) != NULL) { + if(linetype(line,"/")) break; + } + + while (fgets(line,MAXLINE+1,fin) != NULL) { + if(!blankline(line)) break; /* Look for next non- */ + } /* blank line */ + nseqs = 1; + + while (fgets(line,MAXLINE+1,fin) != NULL) { + if(blankline(line)) return nseqs; + nseqs++; + } + + return 0; /* if you got to here-funny format/no seqs.*/ +} + + + +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/perl_header_lib.h b/binaries/src/tcoffee/t_coffee_source/perl_header_lib.h new file mode 100644 index 0000000..3773cc0 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/perl_header_lib.h @@ -0,0 +1,8586 @@ +char *PerlScriptName[]={"rec_sum.pl","count.pl","p\ +rocess_list.pl","make_license.pl","CCsed.script","\ +msa2bootstrap.pl","t_coffee_dpa","t_coffee_dpa2","\ +tc_generic_method.pl","generic_method.tc_method","\ +clustalw_method.tc_method","extract_from_pdb","ins\ +tall.pl","clean_cache.pl","nature_protocol.pl","mo\ +cca","dalilite.pl","wublast.pl","blastpgp.pl","ncb\ +iblast_lwp.pl","wublast_lwp.pl","RNAplfold2tclib.p\ +l","fasta_seq2RNAplfold_templatefile.pl","fasta_se\ +q2hmmtop_fasta.pl","fasta_seq2consan_aln.pl","clus\ +talw_aln2fasta_aln.pl","msf_aln2fasta_aln.pl","bla\ +st_aln2fasta_aln.pl","blast_xml2fasta_aln.pl","fas\ +ta_aln2fasta_aln_unique_name.pl","newick2name_list\ +.pl","excel2fasta.pl","any_file2unix_file.pl","End\ +List"};char *PerlScriptFile[]={"use File::Copy;\nu\ +se Env qw(HOST);\nuse Env qw(HOME);\nuse Env qw(US\ +ER);\n$x_field=0;\n$y_field=1;\n$interval=0;\n$fil\ +e=\"stdin\";\n$print_avg=1;\n$print_sd=0;\n$print_\ +sum=0;\n$print_n=0;\nforeach $value ( @ARGV)\n \ +{\n if ($value ne $ARGV[$np]) \n {\n ;\n \ + }\n elsif($value eq \"-print_all\")\n {\n \ + $print_sd=$print_avg=$print_n=$print_sum=1;\n \ + $np++;\n }\n elsif($value eq \"-print_sum\"\ +)\n {\n $print_sum=1;\n $print_avg=0;\\ +n $np++;\n }\n elsif($value eq \"-print_n\\ +")\n {\n $print_n=1;\n $print_avg=0;\n\ + $np++;\n }\n elsif($value eq \"-print_avg\ +\")\n {\n $print_avg=1;\n $print_avg=0\ +;\n $np++;\n }\n elsif($value eq \"-sd\")\\ +n {\n $print_sd=1;\n $print_avg=0;\n \ + $np++;\n }\n elsif($value eq \"-h\")\n \ +{\n $header=1;\n $np++;\n }\n elsif ($\ +value eq \"-i\")\n {\n $interval= $ARGV[++\ +$np];\n $np++;\n }\n elsif ($value eq \ +\"-r\")\n {\n $min= $ARGV[++$np];\n $m\ +ax= $ARGV[++$np];\n $np++;\n }\n \n el\ +sif ($value eq \"-x\")\n {\n $x_field= $AR\ +GV[++$np]-1;\n $np++;\n }\n elsif ($va\ +lue eq \"-y\")\n {\n \n while ($ARGV\ +[$np+1] && !($ARGV[$np+1]=~/\\-/))\n {\n $y\ +_field[$nyf++]=$ARGV[++$np]-1;\n $y_field_set=1;\\ +n }\n\n $np++;\n }\n elsif ($val\ +ue eq \"-file\")\n {\n $file= $ARGV[++$np]\ +;\n $file_set=1;\n $np++;\n } \ + \n elsif ( $value eq \"h\" || $value eq \"-h\" \ +|| $value eq \"-H\" || $value eq \"-help\" || $val\ +ue eq \"help\")\n {\n print STDOUT \"data_an\ +alyse: Analyse and discretization of data\\n\";\n \ + print STDOUT \" -file: ,.\\n\";\n p\ +rint STDOUT \" -x: ,\ +...............\\n\";\n print STDOUT \"\ + -y: ,..............\ +.\\n\";\n print STDOUT \" -i:,...............\\n\";\\ +n print STDOUT \" -i:<0:only one interva\ +l>\\n\";\n print STDOUT \" -r:\\n\";\n print STDOUT \" -sd: prin\ +t standard deviation on the Y\";\n print STDOU\ +T \" -h : print column header \\n\";\n \ +exit (0);\n }\n elsif ($value=~/-/)\n {\n \ +print \"$value is not a valid FLAG[FATAL]\\n\";\n \ + exit (0);\n } \n elsif ($list eq \"\") \n \ + {\n $file=$ARGV[$np];\n $np++;\n }\\ +n \n \n }\n\n\n\n\n\nif ($file eq \"stdin\")\\ +n {\n $remove_file=1;\n $file=\"tmp$$\";\n open (F\ +, \">$file\");\n while ()\n {\n print F $\ +_;\n }\n close (F);\n \n ;}\n\n\nopen(F,$file);\\ +n\nif ($interval)\n {\n $interval_size=($max-$\ +min)/$interval;\n }\nwhile ()\n {\n $line=\ +$_;\n if (!/\\S/){next;}\n @list=($line=~/(\\ +\S+)/g);\n \n if ($interval==0){$bin=0;}\n \ + else{$bin=int (($list[$x_field]-$min)/($interval\ +_size));}\n\n \n if ($bin && $bin==$interval\ +){$bin--;}\n for ( $a=0; $a<$nyf; $a++)\n \ +{\n $sum{$a}{$bin}+=$list[$y_field[$a]];\n $sum2{$\ +a}{$bin}+=$list[$y_field[$a]]*$list[$y_field[$a]];\ +\n $n{$a}{$bin}++;\n }\n }\n\nif (!$interval\ +){$interval=1;}\nfor ( $a=0; $a<$interval; $a++)\n\ + {\n printf ( \"%3d %3d \", $interval_size*$a,\ + $interval_size*($a+1));\n for ( $b=0; $b<$nyf;\ + $b++) \n {\n $i=$interval*$a;\n if ( $n{$b}{\ +$a}==0)\n {\n $avg=0;\n $sd=0;\n }\n e\ +lse\n {\n $avg=$sum{$b}{$a}/$n{$b}{$a};\n \ + $sd=sqrt($sum2{$b}{$a}*$n{$b}{$a}-$sum{$b}{$a}*$\ +sum{$b}{$a})/($n{$b}{$a}*$n{$b}{$a});\n }\n if (\ +$print_n) {printf \"%10.4f \", $n{$b}{$a};}\n if (\ +$print_sum){printf \"%10.4f \", $sum{$b}{$a};}\n i\ +f ($print_avg){printf \"%10.4f \", $avg}\n if ($pr\ +int_sd) {printf \"%10.4f \", $sd;}\n }\n p\ +rintf (\"\\n\");\n }\n\n\nif ( $remove_file){unli\ +nk $file;}\n","use File::Copy;\nuse Env qw(HOST);\\ +nuse Env qw(HOME);\nuse Env qw(USER);\n\nforeach $\ +v (@ARGV){$cl.=$v;}\n\n\nif ( $cl=~/-k(\\d+)/){$k=\ +$1;}\nelse {$k=1;}\nif ( $cl=~/-w(\\d+)/){$w=$1;}\\ +nelse {$w=-1;}\nif ( $cl=~/-p(\\d+)/){$p=$1;}\nels\ +e {$p=-1;}\n\nwhile ()\n {\n @l=($_=~/(\ +\\S+)/g);\n $v=$l[$k-1];\n if ( !$h{$v}){@ll\ +=($v, @ll);}\n \n if ( $w==-1)\n {$h{$v\ +}++;}\n else\n {$h{$v}+=$l[$w-1];}\n\n \ +if ($p!=-1){$print{$v}=$l[$p-1];}\n\n }\nforeach \ +$v (@ll)\n {\n print \"$v $print{$v} $h{$v}\\n\ +\";\n }\n","\nuse Env qw(HOST);\nuse Env qw(HOME)\ +;\nuse Env qw(USER);\n$random_tag=int (rand 10000)\ ++1;\n$unique_prefix=\"$$.$HOST.$random_tag\";\n$qu\ +eue=\"distillery.and.mid\";\n$monitor=0;\n$stderr_\ +file=\"/dev/null\";\n$stdio_file=\"/dev/null\";\n$\ +log_file=\"/dev/null\";\n$pause_time=0;\n$max_sub_\ +jobs=60;\n$min_sub_jobs=30;\n$output_all=0;\n$var=\ +'\\$';\n\nforeach $value ( @ARGV)\n {\n if ($va\ +lue ne $ARGV[$np]) \n {\n ;\n }\n elsi\ +f ($value eq \"-max_sub_jobs\")\n {\n $max\ +_sub_jobs= $ARGV[++$np];\n $np++;\n } \ +\n elsif ($value eq \"-min_sub_jobs\" )\n {\n \ + $min_sub_jobs= $ARGV[++$np];\n $np++;\n \ + }\n elsif ($value eq \"-para\")\n {\n \ + $para=1;\n $monitor=1;\n $np++;\n \ + }\n elsif ($value eq \"-monitor\") \n {\n \ + $monitor=1;\n $np++;\n }\n elsif ($value\ + eq \"-no_monitor\") \n {\n $monitor=0;\n \ + $np++;\n }\n elsif ($value eq \"-queue\")\\ +n {\n $queue=$ARGV[++$np];\n $np++;\n \ + } \n elsif ($value eq \"-stderr_file\")\n \ +{\n $stderr_file=$ARGV[++$np];\n $np++;\n \ + }\n elsif ($value eq \"-stdio_file\")\n {\\ +n $stdio_file=$ARGV[++$np];\n $np++;\n \ + }\n elsif ($value eq \"-output_all\")\n {\n \ + $output_all=1;\n $np++;\n }\n elsif ($v\ +alue eq \"-pause\") \n {\n $pause_time=$AR\ +GV[++$np];\n $np++;\n }\n elsif ($value eq\ + \"-log\")\n {\n $log=1;\n \n \ + if ($ARGV[$np+1]=~/\\-\\S+/) \n {\ +\n $log_file=\"stderr\";\n }\n \ + else \n {\n $log_file=$ARGV[++$np]; \ +\n ++$np;\n \n }\n }\n elsif \ +( $value eq \"-com\")\n {\n \n if (!$ARGV[$n\ +p+1]=~/^\\'/) { $com=$ARGV[++$np];}\n else {$com=\ +$ARGV[++$np];}\n\n $np++;\n }\n elsif ( $\ +value eq \"-check\")\n {\n \n if (!$ARGV\ +[$np+1]=~/^\\'/) { $check=$ARGV[++$np];}\n els\ +e {$check=$ARGV[++$np];}\n $np++;\n }\n elsi\ +f ($com eq \"\") \n {\n $com_set=1;\n \ +$com=$ARGV[$np];\n \n $np++;\n }\n els\ +if ($list eq \"\") \n {\n $list_set=1;\n \ + $list=$ARGV[$np];\n $np++;\n }\n elsif \ +( $var_set eq \"\")\n {\n $var_set=1;\n \ + $var=$ARGV[$np];\n $np++;\n }\n }\n\n\n\\ +n\nif ( $com eq \"\"){print \"You Need to Provide \ +a Command [FATAL]\\n\";\n die;\n }\n\n\\ +n\nif ($list_set==0) \n {\n $x= int (rand 10\ +0000)+1;\n $tmp_file_name=\"tmp_file_$x\";\n \ + open ( TMP, \">$tmp_file_name\");\n while ()\n {\n print TMP $_;\n }\n close\ + (TMP);\n open (F, $tmp_file_name);\n }\nels\ +e \n {\n open (F, $list);\n }\n\nif ($par\ +a==0) \n {\n\n @tc_list= ;\n close (\ +F); \n \n foreach $val(@tc_list) \n {\\ +n \n \n \n $loc_com=$com;\\ +n if ($check){$loc_check=$check;}\n \n\ + @i_val=($val=~/([^\\s]+)/g);\n \n \ + if ( $#i_val==0)\n {\n if ($check){$loc_che\ +ck=~s/$var/$i_val[0]/g;}\n $loc_com=~s/$var/$i_\ +val[0]/g;\n }\n else\n {\n for ($n=1; $\ +n<=$#i_val+1;$n++ )\n {\n \n $s\ +ub=\"$var$n\";\n \n $loc_com=~s/$sub\ +/$i_val[$n-1]/g;\n if ($check){$loc_check=~\ +s/$var/$i_val[0]/g;}\n }\n }\n if ( $c\ +heck && -e $loc_check)\n {\n print STDERR \"sk\ +ipping $loc_com...\\n\";\n }\n else\n {\\ +n system \"$loc_com\";\n }\n }\n exit;\\ +n }\n\nelsif ($para==1) \n {\n print STDE\ +RR \"do parallel execution of: \\\"$com $list\\\"\\ +\n\";\n \n if ($log==1) \n {\n if ($log_file\ + eq \"stdout\" || $log_file eq \"stderr\" ) \n {\\ +n $log_file=\"\";\n }\n\n else \n \ + {\n system \"echo LOG FILE> $log_file\";\n \n \ + }\n }\n else \n {\n open ( OUT, \">/dev/\ +null\");\n }\n \n \n $id=0;\n $n_sub=0;\n\ + while ($val=) \n { \n $job\ +_log[$id]=\"$HOME/tmp/$unique_prefix.$id.log_file\\ +";\n \n $job=$unique_prefix.\"_$id\";\n \ + open (JOB, \">$job\");\n \n $loc_com=$co\ +m;\n chop $val;\n\n $loc_com=~s/\\$/$val/g\ +;\n \n print JOB \"#!/bin/csh\\n\";\n pri\ +nt JOB \"#\\$ -cwd\\n\";\n print JOB \"#\\$ -N\ + $unique_prefix\\n\";\n if ($queue && !($queue\ + eq \" \")) {print JOB \"#\\$ -l $queue\\n\";}\n \ + print JOB \"#\\n\"; \n print JOB\ + \"$loc_com\\n\";\n print JOB \"echo FINISHED \ + >> $job_log[$id]\\n\";\n print JOB \"pwd\\n\"\ +;\n \n close (JOB);\n if ( $output_all\ +==1)\n {\n system \"qsub $job > $unique_prefix\\ +"; \n }\n else\n {system \"qsub $job\ + -e $stderr_file -o $stdio_file >$unique_prefix\";\ + \n } \n\n\n\n print STDERR \"\ +$id: $output_all\\n\";\n $n_sub++;\n if ( \ +$max_sub_jobs && $n_sub==$max_sub_jobs) \n {\n $\ +n_sub=monitor_process($min_sub_jobs,@job_log); \ +\n \n } \n \n unlink $uniqu\ +e_prefix;\n sleep $pause_time;\n $id++;\n \ + }\n\n close (OUT);\n close (F);\n\n p\ +rint STDERR \"Your $id Jobs Have Been Submited (NA\ +ME=$unique_prefix)\\n\";\n monitor_process (0, \ +@job_log);\n foreach $file(@job_log) {if (-e $f\ +ile) {unlink($file);}}\n \n }\n\nsub monitor\ +_process ( @job_list)\n {\n my (@job_list)=@\ +_;\n my $min_sub_jobs=shift (@job_list);\n m\ +y $n_sub_jobs;\n my $finished;\n my $n=0;\n\\ +n $n_sub_jobs=-1;\n $finished=0;\n print \ +STDERR \"\\nMonitor Batch: [$min_sub_jobs]\";\n \ + \n while (!$finished && (($n_sub_jobs>$min_\ +sub_jobs)|| $n_sub_jobs==-1) ) \n {\n $finished=1;\ +\n $n_sub_jobs=0;\n $n=0;\n foreach $file (@job_li\ +st)\n {\n \n if (-e $file){;}\n else \n \ + {\n $finished=0; $n_sub_jobs++;\n \ + }\n }\n system \"sleep 1\";\n \ + }\n \n return $n_sub_jobs;\n }\n \n \ + \nif ($tmp_file_name){unlink($tmp_file_name);}\n\ +","\n\nforeach ($np=0; $np<=$#ARGV; $np++)\n {\\ +n $value=$ARGV[$np];\n\n if ($value eq \"-fi\ +le\")\n {\n $file= $ARGV[++$np];\n \ +}\n elsif ($value eq \"-type\")\n {\n \ + $type= $ARGV[++$np];\n }\n elsif ($valu\ +e eq \"-institute\")\n {\n $institute=\ + $ARGV[++$np];\n }\n elsif ($value eq \"-a\ +uthor\")\n {\n $author= $ARGV[++$np];\\ +n }\n elsif ($value eq \"-date\")\n {\ +\n $date= $ARGV[++$np];\n }\n elsi\ +f ($value eq \"-program\")\n {\n $prog\ +ram= $ARGV[++$np];\n }\n elsif ($value eq \ +\"-email\")\n {\n $email= $ARGV[++$np]\ +;\n }\n else\n {\n print \"$value is \ +an unkown argument[FATAL]\\n\";\n exit (1);\n \ + }\n }\n\n\n\nopen F, $file || die;\nprint $INSTI\ +TUTE;\nif ( $type eq \"c\"){print \"/*************\ +*****************COPYRIGHT NOTICE*****************\ +**************/\\n\";}\nif ( $type eq \"perl\"){pr\ +int \"##############################COPYRIGHT NOTI\ +CE##############################/\\n\";}\nif ( $ty\ +pe eq \"txt\"){print \"---------------------------\ +----COPYRIGHT NOTICE------------------------------\ +/\\n\";}\n\n\nwhile ()\n {\n s/\\$INSTITUTE/$\ +institute/g;\n s/\\$AUTHOR/$author/g;\n s/\\$DAT\ +E/$date/g;\n s/\\$PROGRAM/$program/g; \n s/\\$E\ +MAIL/$email/g; \n if ( $type eq \"txt\"){print $\ +_;}\n elsif ($type eq \"c\"){chop $_; print \"\\/\ +*$_*\\/\\n\";}\n elsif ($type eq \"perl\"){print \ +\"\\#$_\";}\n}\nclose (F);\nif ( $type eq \"c\"){p\ +rint \"/******************************COPYRIGHT NO\ +TICE*******************************/\\n\";}\nif ( \ +$type eq \"perl\"){print \"#######################\ +#######COPYRIGHT NOTICE###########################\ +###/\\n\";}\nif ( $type eq \"txt\"){print \"------\ +-------------------------COPYRIGHT NOTICE---------\ +---------------------/\\n\";}\n\n","\nwhile (<>) \\ +n {\n s/\\=cc/123456789/g;\n s/\\bcc/\\$\\(CC\\)/g\ +;\n s/123456789/\\=cc/g;\n print $_;\n }\n\n","$ve\ +rsion=\"1.00\";\n$rseed= int(rand(100000))+1;\n\n\\ +nif ( $#ARGV==-1)\n {\n print \"msa2bootstrap \ +-i -input -n -o -tmode -dmode -alignpg -rtree -stype -r\ +ecompute -system \";\n print \"\\n\ +\\t-i: input file, can be sequneces, msa, matrix, \ +trees, type is specified via -input\";\n print \ +\"\\n\\t-input: Type of input data\";\n print \\ +"\\n\\t\\tmsa: msa in fasta format\";\n print \\ +"\\n\\t\\tseq: compute an msa with -alignpg\";\n \ + print \"\\n\\t\\tmatrix: phylipp distance matrix\ + fed directly to method -tmode [caveat: tmode=nj o\ +r upgma]\";\n print \"\\n\\t\\ttree: list of ne\ +wick trees directly fed to consence in order to ge\ +nerate a bootstraped tree\";\n \n print \"\\\ +n\\t-n: number of bootstrap replicates\";\n pri\ +nt \"\\n\\t-o: name of the output tree. Files are \ +not overwritten. Use -recompute to overwrite exist\ +ing file\";\n print \"\\n\\t-tmode: tree mode: \ +nj|upgma|parsimony|ml\";\n print \"\\n\\t-dmode\ +: distance mode\";\n print \"\\n\\t-alignpg: pr\ +ogram for aligning sequences (t_coffee=default)\";\ +\n print \"\\n\\t-rtree: replicate tree file (d\ +efault: no file)\";\n print \"\\n\\t-rmsa: repl\ +icate msa file (default: no file)\";\n print \"\ +\\n\\t-rmat: replicate matrix file (default: no fi\ +le)\";\n print \"\\n\\t-stype: sequence type: p\ +rotein, dna or cdna\";\n print \"\\n\\t-recompu\ +te: force files to be overwritten\";\n print \"\ +\\n\\t-system: cygwin|unix\";\n \n\n \n \ + &my_exit (EXIT_FAILURE);\n }\nforeach $arg (@ARG\ +V){$command.=\"$arg \";}\n\nprint \"CLINE: $comman\ +d\\n\";\n$threshold=100;\n$trim_msa=0;\n$stype=\"p\ +rot\";\nprint \"msa2bootstrap \";\n\n$system=\"cyg\ +win\";\nif(($command=~/\\-system (\\S+)/))\n {\n \ + $system=$1;\n if ( $system eq \"cygwin\")\n \ + {\n $exec_extension=\".exe\";\n }\n e\ +lsif ( $system eq \"unix\")\n {\n $exec_exten\ +sion=\"\";\n print \"system=Unix\";die;\n }\n\ + else\n {\n print \"msa2boostrap: -system=\ +$system is an unknown mode [FATAL]\\n\"; die;\n \ + }\n \n print \"-system $system \";\n }\n\ +if(($command=~/\\-stype (\\S+)/))\n {\n $stype\ +=$1;\n }\nprint \"-stype=$stype \";\n\n\n\nif(($c\ +ommand=~/\\-i (\\S+)/))\n {\n $msa=$1;\n pr\ +int \"-i $msa \";\n }\n\nif(($command=~/\\-rtree \ +(\\S+)/))\n {\n $rtree=$1;\n print \"-rtree\ +=$rtree \";\n }\n\nif(($command=~/\\-rmsa (\\S+)/\ +))\n {\n $rmsa=$1;\n }\nif(($command=~/\\-rma\ +t (\\S+)/))\n {\n $rmat=$1;\n }\n$input=\"seq\ +\";\nif(($command=~/\\-input (\\S+)/))\n {\n $\ +input=$1;\n }\nprint \"-input=$input \";\n\n$dmod\ +e=\"kimura\";\nif(($command=~/\\-dmode (\\S+)/))\n\ + {\n $dmode=$1;\n }\nprint \"-dmode=$dmode \"\ +;\n$alignpg=\"muscle\";\nif(($command=~/\\-alignpg\ + (\\S+)/))\n {\n $alignpg=$1;\n }\nprint \"-a\ +lignpg=$dmode \";\n\n$tmode=\"nj\";\nif(($command=\ +~/\\-tmode (\\S+)/))\n {\n $tmode=$1;\n }\npr\ +int \"-tmode=$tmode \";\n$recompute=0;\nif(($comma\ +nd=~/\\-recompute/))\n {\n $recompute=1;\n \ +print \"-recompute \";\n }\n\n$out=$msa;\n$out=~s\ +/\\..*//;\n$out.=\".bph\";\nif(($command=~/\\-o (\\ +\S+)/))\n {\n $out=$1;\n \n }\nprint \"-ou\ +t=$out \";\nif (-e $out && !$recompute)\n {\n \ +print \"\\nNo Computation Required $out already ex\ +ists\\n\";\n &my_exit (EXIT_SUCCESS);\n \n \ +}\n\n$n=100;\nif(($command=~/\\-n (\\d+)/))\n {\n\ + $n=$1;\n }\nprint \"-n=$n \";\n$seed=3;\nif((\ +$command=~/\\-s (\\d+)/))\n {\n $seed=$1;\n }\ +\nprint \"-s=$seed \";\n\nif(($command=~/\\-run_na\ +me (\\d+)/))\n {\n $suffix=$1;\n }\nelse\n {\ +\n $msa=~/([^.]+)/;\n $suffix=$1;\n }\nprin\ +t \"-run_name=$suffix\\n\";\n\n\nif ( $input eq \"\ +seq\")\n {\n $seq=$msa;\n $msa=\"$suffix.pr\ +ot_msa\";\n \n if ($stype eq \"cdna\")\n \ + {\n $cdna_seq=$seq;\n $clean_cdna_seq=&vtmpnam()\ +;\n $seq=&vtmpnam();\n `t_coffee -other_pg seq_ref\ +ormat -in $cdna_seq -action +clean_cdna >$clean_cd\ +na_seq`;\n `t_coffee -other_pg seq_reformat -in $c\ +lean_cdna_seq -action +translate >$seq`;\n \n \ + }\n\n if (!-e $msa || $recompute)\n {\n p\ +rint \"\\n##### Compute an MSA With $alignpg\\n\\ +";\n \n if ( $alignpg eq \"t_coffee\")\n {`$alig\ +npg $seq -outfile=$msa >/dev/null 2>/dev/null`;}\n\ + elsif ( $alignpg eq \"muscle\")\n {\n `$ali\ +gnpg -in $seq > $msa 2>/dev/null`;\n }\n elsif (\ + $alignpg eq \"clustalw\")\n {\n `$alignpg -\ +infile=$seq -outfile=$msa -quicktree >/dev/null 2>\ +/dev/null`;\n }\n elsif ( $align eq \"mafft\")\n\ + {\n `$alignpg $seq > $msa >/dev/null 2>/dev\ +/null`;\n }\n else\n {\n `$alignpg -in=$se\ +q -outfile=$msa`;\n }\n }\n if (!-e $msa\ +)\n {\n print \"\\nError: $alignpg Could Not \ +produce the MSA $msa [FATAL]\\n\";\n }\n\n \ + if ($stype eq \"cdna\")\n {\n $msa2=\"$suffi\ +x.cdna_msa\";\n `t_coffee -other_pg seq_reformat -\ +in $clean_cdna_seq -in2 $msa -action +thread_dna_o\ +n_prot_aln -output fasta_aln >$msa2`;\n $msa=$msa\ +2;\n }\n \n $input=\"msa\";\n }\n\n\n\\ +n$seqboot_o=&vtmpnam();\n$seqboot_c=&vtmpnam();\n\\ +n$protdist_o=&vtmpnam();\n$protdist_c=&vtmpnam();\\ +nif ( $input eq \"msa\")\n {\n if ($tmode eq \\ +"nj\" || $tmode eq \"upgma\"){$input=\"matrix\";}\\ +n \n $lmsa= &vtmpnam ();\n `t_coffee -oth\ +er_pg seq_reformat -in $msa -output phylip_aln > $\ +lmsa`;\n \n if ( -e \"outfile\"){unlink (\"o\ +utfile\");}\n # run seqboot\n \n if ( $n>1)\ +\n {\n print \"Run SeqBoot .....\";\n open (F\ +, \">$seqboot_c\");\n print F \"$lmsa\\nR\\n$n\\nY\ +\\n$seed\\n\";\n close (F);\n `seqboot$exec_extens\ +ion < $seqboot_c`;\n if ( -e \"outfile\"){ print \ +\"[OK]\\n\";}\n else { print \"[FAILED]\\n\";&my_e\ +xit (EXIT_FAILURE);}\n `mv outfile $seqboot_o`;\n \ + }\n else\n {\n `cp $lmsa $seqboot_o`;\ +\n }\n\n if ($rmsa){`cp $seqboot_o $rmsa`;\ +}\n \n if ($tmode eq \"nj\" || $tmode eq \"u\ +pgma\")\n {\n if ( $stype eq \"prot\")\n {\\ +n # run protdist\n print \"Run Protdist [d\ +mode=$dmode]\";\n if ($dmode eq \"kimura\")\n \ + {\n $dmode=\"P\\nP\\nP\";\n }\n e\ +lse\n {\n print \"\\n$dmode is an unknown m\ +ode for Protdist [FATAL:msa2bootstrap.pl]\\n\";\n \ + &my_exit (EXIT_FAILURE);\n }\n open (F,\ + \">$protdist_c\");\n if ($n>1){print F \"$seq\ +boot_o\\n$dmode\\nM\\nD\\n$n\\nY\\n\";}\n else\ + {printf F \"$seqboot_o\\n$dmode\\nY\\n\";}\n \ +close (F);\n `protdist$exec_extension < $prot\ +dist_c`;\n if ( -e \"outfile\"){ print \"[OK]\\ +\n\";}\n else { print \"[FAILED]\\n\";&my_exit\ + (EXIT_FAILURE);}\n `mv outfile $protdist_o`;\\ +n \n }\n elsif ( $stype eq \"cdna\" || $stype e\ +q \"dna\")\n {\n print \"Run dnadist [dmode=\ +default\";\n open (F, \">$protdist_c\");\n \ + if ($n>1){print F \"$seqboot_o\\nM\\nD\\n$n\\nY\\\ +n\";}\n else {printf F \"$seqboot_o\\nY\\n\";}\ +\n close (F);\n `protdist$exec_extension \ +< $protdist_c`;\n if ( -e \"outfile\"){ print \ +\"[OK]\\n\";}\n else { print \"[FAILED]\\n\";&\ +my_exit (EXIT_FAILURE);}\n `mv outfile $protdi\ +st_o`;\n }\n }\n }\nelsif ( $input eq \"ma\ +trix\")\n {\n $protdist_o=&vtmpnam();\n pri\ +nt \"MSA: $msa\\n\";\n `cp $msa $protdist_o`;\n\ + $n=1;\n }\n\n\n\n\n\n$nb_o=&vtmpnam();\n$nb_c\ +=&vtmpnam();\nif ($input eq \"matrix\" && $tmode n\ +e \"parsimony\" && $tmode ne \"ml\")\n {\n pri\ +nt \"Run neighbor [tmode=$tmode]\";\n\n if ($tm\ +ode eq \"nj\")\n {\n $tmode=\"\\nN\\nN\";\n \ + }\n elsif ( $tmode eq \"upgma\")\n {\n\ + $tmode = \"\\nN\";\n }\n else\n {\n \ +print \"\\n ERROR: $tmode is an unknown tree compu\ +tation mode\\n\";\n &my_exit (EXIT_FAILURE);\n \ + }\n\n open (F, \">$nb_c\");\n if ($n>1){pr\ +int F \"$protdist_o$tmode\\nM\\n$n\\n$seed\\nY\\n\\ +";}\n else {print F \"$protdist_o$tmode\\nY\\n\\ +";}\n close (F);\n\n `neighbor$exec_extensio\ +n < $nb_c`;\n if ( -e \"outtree\"){ print \"[N\ +eighbor OK]\\n\";}\n else { print \"[FAILED]\\n\ +\";&my_exit (EXIT_FAILURE);}\n `mv outtree $nb_\ +o`;\n unlink (\"outfile\");\n }\nelsif ($input\ + eq \"msa\" && $tmode eq \"parsimony\")\n {\n \ +if ( -e \"outfile\"){unlink (\"outfile\");}\n i\ +f ( -e \"outtree\"){unlink (\"outtree\");}\n \n\ + if ($stype eq \"prot\")\n {\n print \"Run\ + protpars [tmode=$tmode]\";\n open (F, \">$nb_c\")\ +;\n if ($n>1){print F \"$seqboot_o\\nM\\nD\\n$n\\n\ +$seed\\n10\\nY\\n\";}\n else {print F \"$seqboot_o\ +\\nY\\n\";}\n close (F);\n `protpars$exec_extensio\ +n < $nb_c`;\n }\n elsif ( $stype eq \"dna\ +\" || $stype eq \"cdna\")\n {\n print \"Run d\ +napars [tmode=$tmode]\";\n open (F, \">$nb_c\");\n\ + if ($n>1){print F \"$seqboot_o\\nM\\nD\\n$n\\n$se\ +ed\\n10\\nY\\n\";}\n else {print F \"$seqboot_o\\n\ +Y\\n\";}\n close (F);\n `dnapars$exec_extension <\ + $nb_c`;\n }\n if ( -e \"outtree\"){ print\ + \"[OK]\\n\";}\n else { print \"[FAILED]\\n\";&\ +my_exit (EXIT_FAILURE);}\n `mv outtree $nb_o`;\\ +n unlink (\"outfile\");\n }\nelsif ($input eq \\ +"msa\" && $tmode eq \"ml\")\n {\n if ( -e \"ou\ +tfile\"){unlink (\"outfile\");}\n if ( -e \"out\ +tree\"){unlink (\"outtree\");}\n \n if ($sty\ +pe eq \"prot\")\n {\n print \"Error: ML impos\ +sible with Protein Sequences [ERROR]\";\n &my_exit\ + (EXIT_FAILURE);\n }\n elsif ( $stype eq \\ +"dna\" || $stype eq \"cdna\")\n {\n print \"R\ +un dnaml [tmode=$tmode]\";\n open (F, \">$nb_c\");\ +\n if ($n>1){print F \"$seqboot_o\\nM\\nD\\n$n\\n$\ +seed\\n10\\nY\\n\";}\n else {print F \"$seqboot_o\\ +\nY\\n\";}\n close (F);\n `dnaml$exec_extension <\ + $nb_c`;\n }\n if ( -e \"outtree\"){ print\ + \"[OK]\\n\";}\n else { print \"[FAILED]\\n\";&\ +my_exit (EXIT_FAILURE);}\n `mv outtree $nb_o`;\\ +n unlink (\"outfile\");\n }\n\n\nelse\n {\n \ + `cp $msa $nb_o`;\n $n=2;\n }\n\nif ($rmsa && \ +-e $seqboot_o){print \"\\nOutput List of $n Replic\ +ate MSA: $rmsa\\n\";`cp $seqboot_o $rmsa`;}\nif ($\ +rmat && -e $protdist_o){print \"\\nOutput List of \ +$n Replicate MATRICES: $rmat\\n\";`cp $protdist_o \ +$rmat`;}\nif ($rtree && -e $nb_o){print \"\\nOutpu\ +t List of $n Replicate TREES: $rtree\\n\";`cp $nb_\ +o $rtree`;}\n\n\n\n$con_o=&vtmpnam();\n$con_c=&vtm\ +pnam();\nif ($n >1)\n {\n print \"Run Consense\ +.....\";\n open (F, \">$con_c\");\n print F \ +\"$nb_o\\nY\\n\";\n close (F);\n `consense$e\ +xec_extension < $con_c`;\n if ( -s \"outtree\"\ + > 0) { print \"[OK]\\n\";}\n else { print \"[\ +FAILED]\\n\";&my_exit (EXIT_FAILURE);}\n `mv ou\ +ttree $con_o`;\n unlink (\"outfile\");\n }\nel\ +se\n {\n `cp $nb_o $con_o`;\n }\n\n\n`cp $con\ +_o $out`;\nif ( !-e $out)\n {\n print \"Tree C\ +omputation failed [FAILED]\\n\";\n &my_exit (EX\ +IT_FAILURE);\n }\nelsif ($n>1)\n {\n print \"\ +\\nOutput Bootstrapped Tree: $out\\n\";\n $avg=\ +`t_coffee -other_pg seq_reformat -in $out -action \ ++avg_bootstrap`;\n $avg=~s/\\n//g;\n print \\ +"$avg\\n\";\n }\nelse\n {\n print \"\\nOutput\ + Tree: $out\\n\";\n }\n\nopen (F, \"$out\");\nwhi\ +le ()\n {\n \n $tree.=$_;\n }\nclose (F\ +);\n$tree=~s/\\n//g;\nprint \"BPH: $tree\\n\";\n\n\ +\n&my_exit (EXIT_SUCCESS);\n\nsub my_exit \n {\n \ + my $m=@_[0];\n &clean_vtmpnam();\n exit (\ +$m);\n }\nsub vtmpnam \n {\n my $file;\n\n\n \ + $ntmp++;\n $file=\"tmp4msa2bootstrap.$rseed.\ +$$.$ntmp\";\n \n push (@tmpfile, $file);\n \ + return $file;\n }\nsub clean_vtmpnam \n {\n \ + my $t;\n foreach $t (@tmpfile)\n {\n if (\ + -e $t){unlink ($t)};\n }\n }\n","use Env;\n\ +$seq_reformat=\"t_coffee -other_pg seq_reformat \"\ +;\n$VersionTag=\"1.00\";\n$step=1;\n$unset=\"\";\n\ +$scoreT1=$scoreT2=$nseqT=$dp_limit=$unset;\n@tl=()\ +;\nchomp($tc_version=`t_coffee -version`);$tc_vers\ +ion=~s/PROGRAM: //;\n\n\nprint STDERR \"\\n*******\ +**************************************************\ +********\";\nprint STDERR \"\\n* HIGH LE\ +VEL PROGRAM: T-COFFEE_DPA Version $VersionTag\";\n\ +print STDERR \"\\n* LOW LEVEL PROGRAM: \ +$tc_version \";\nprint STDERR \"\\n***************\ +**************************************************\ +\";\n\nif (!@ARGV)\n {\n print \"t_coffee_dpa \ +accepts every t_coffee_flag.\\nType t_coffee to ob\ +tain a list\\n\";\n print \"Requires $TC_VERSIO\ +N\\n\";\n print \"Requires \";\n print \"t_c\ +offee_dpa specific flags:\\n\";\n print \"\\t-d\ +pa_master_aln....................Master alignment:\ + provided OR computed\\n\";\n print \"\\t-dpa_m\ +aster_aln....................By default, Computed \ +with t_coffee -very_fast\\n\";\n print \"\\t-dp\ +a_master_aln=.............Use file, (must be\ + an aln in Fasta or ClustalW\\n\";\n print \"\\\ +t-dpa_master_aln=..........Compute aln wi\ +th pg -in seq -out aln`\\n\";\n print \"\\t-dpa\ +_maxnseq.......................Maximum number of s\ +equences in subgroups\\n\";\n print \"\\t-dpa_m\ +in_score1....................Minimum Id for two se\ +quences to be grouped in ref_aln\\n\";\n print \ +\"\\t-dpa_min_score2....................Minimum Id\ + within a subgroup\\n\";\n print \"\\t-dpa_debu\ +g.........................Keep Tmp File (for debug\ + purpose)\\n\\n\";\n \n exit (0);\n }\nfore\ +ach $arg (@ARGV)\n {\n $arg_list.=\" $arg\";\n\ + }\n$arg_list=~s/[=,;]/ /g;\n\n\n($seq0, $arg_lis\ +t)=&extract_val_from_arg_list(\"^\",$arg_list, \"S\ +PLICE\",\"unset\");\n($seq1, $arg_list)=&extract_v\ +al_from_arg_list(\"-seq\",$arg_list, \"SPLICE\",\"\ +unset\");\n($seq2, $arg_list)=&extract_val_from_ar\ +g_list(\"-in\",$arg_list, \"KEEP\",\"unset\");\n($\ +seq3, $arg_list)=&extract_val_from_arg_list(\"-inf\ +ile\",$arg_list, \"SPLICE\",\"unset\");\n($prf, $\ +arg_list)=&extract_val_from_arg_list(\"-profile\",\ +$arg_list, \"SPLICE\",\"unset\");\n\n$gl{'Seq'}=$s\ +eq=&vtmpnam();#file containing all the sequences\n\ +\n #1-remove sequences from -in\nif ( $arg_list \ +=~/\\-in\\b/)\n {\n my $save, $name;\n whil\ +e($arg_list=~/\\-in\\b[^-]+(\\bS[\\w.]+)/)\n \ +{\n $name=$1;$name=~s/^.//;\n if ( !-e $name){$sav\ +e.=\" S$name \";}\n\n $arg_list=~s/S$name/ /;\n \ + }\n $arg_list=~s/\\-in\\b/\\-in $save /;\n \ +}\n #2-prepare \n\nif (!($arg_list=~/\\-outorder\ +/))\n {\n \n $output_cl .=\" -outorder=$seq\ +\";\n }\n@output_flag=(\"-output\",\"-outfile\", \ +\"-run_name\", \"-outorder\"); \nforeach $v1 (@out\ +put_flag)\n {\n ($v2, $arg_list)=&extract_val_\ +from_arg_list($v1,$arg_list, \"SPLICE\",\"unset\")\ +;\n if ($v2 ne \"\")\n {\n\n if ($v1 eq \"\ +-run_name\"){$run_name=$v2;$output_cl .=\" $v1 $v2\ + \";}\n elsif ( $v1 eq \"-outorder\")\n {\n \ +if ( $v2 eq \"input\"){$v2=$seq;}\n $outorder=\ +$v2;$output_cl .=\" $v1 $v2 \";\n }\n else\n {\ +\n $output_cl .=\" $v1 $v2 \";\n }\n }\\ +n }\n\n\n($dpa_master_aln, $arg_list) =&extract_v\ +al_from_arg_list(\"-dpa_master_aln\",$arg_list, \"\ +SPLICE\", \"t_coffee\");\n$dpa_master_aln=~s/\\s//\ +g;\n($nseqT, $arg_list) =&extract_val_fr\ +om_arg_list(\"-dpa_maxnseq\",$arg_list, \"SPLICE\"\ +, 30);\n($scoreT1, $arg_list) =&extract_va\ +l_from_arg_list(\"-dpa_min_score1\",$arg_list, \"S\ +PLICE\", 80);\n($scoreT2, $arg_list) =&ext\ +ract_val_from_arg_list(\"-dpa_min_score2\" ,$ar\ +g_list, \"SPLICE\", 30);\n($dpa_limit, $arg_list) \ + =&extract_val_from_arg_list(\"-dpa_limit\" \ + ,$arg_list, \"SPLICE\", 0);\n($dpa_delta_id,\ + $arg_list) =&extract_val_from_arg_list(\"-dpa_\ +delta_id\" ,$arg_list, \"SPLICE\", 1);\n($d\ +pa_debug, $arg_list) =&extract_val_from_arg_\ +list(\"-dpa_debug\" ,$arg_list, \"SPLICE\ +\", 0);\n\n\n$in_seq=$seq0.\" \".$seq1.\" \".$seq2\ +.\" \".$seq3;\n$in_prf=(($prf ne $unset)?\"$prf \"\ +:\"\");\n&exit_dpa (($in_seq eq \"\" && $in_prf eq\ + \"\")?1:0, \"ERROR: You did not Provide any seque\ +nces. Use the -seq flag [FATAL: t_coffee_dpa]\\n\"\ +, EXIT_FAILURE);\n\n\nprint STDERR \"\\nSTART DPA \ +COMPUTATION\";\n\n\n\nif ($in_seq=~/\\S+/)\n {\n \ + \n print STDERR \"\\n Step $step: Gather all\ + the sequences into the tmp file: [$seq]\";$step++\ +; \n &my_system (\"t_coffee $in_seq -convert -q\ +uiet -output fasta_seq -outfile=$seq -maxnseq 0\")\ +;\n }\n\nif ( !-e $seq){$seq=\"\";}\n\nif ($in_pr\ +f=~/\\S+/)\n {\n $seq_in_type=\"profile\"; \n \ + $seq.= $in_prf; \n }\nif ($seq eq \"\"){ &exit\ +_dpa (1, \"\\nERROR: No Sequence FOund. Provide Se\ +quences with the -seq flag [FATAL: t_coffee_dpa]\"\ +, EXIT_FAILURE);}\n\n \n\nif ( $run_name)\n {\n \ + $suffix=$run_name;\n }\nelsif ($in_seq=~/\\b(S[\ +\\w.]+\\b)/)\n {\n my $suffix1, $sufffix2;\n \ + $suffix1=$suffix2=$1;\n $suffix2=~s/^S//;\n \ + if ( -e $suffix1){$suffix=$suffix1;}\n elsif \ +( -e $suffix2){$suffix=$suffix2;}\n else\n \ + {\n $suffix=&vtmpnam(); \n }\n $suffix=~s\ +/\\.\\w+//;\n }\n\nelse\n {\n $suffix=&vtmpna\ +m();\n }\n\n\nif (!$run_name){$output_cl.=\" -run\ +_name $suffix \";}\n\n\n$gl{'Tree'}=&seq2dpa_tree \ +($seq, \"$suffix.dpadnd\");\n\nprint STDERR \"\\n \ +Step $step: Prepare guide tree: $gl{'Tree'}\";$ste\ +p++;\n\nprint STDERR \"\\n Step $step: Identify an\ +d Align Closely Related Groups\";$step++;\n%gl=&ma\ +ke_one_pass (0, $scoreT1,\"Align\",%gl);\n\nprint \ +STDERR \"\\n Step $step: Make Multiple Group Align\ +ment\";$step++;\nwhile (!%gl ||$gl{'Ng'}>$nseqT)\n\ + {\n %gl=&make_one_pass ($nseqT, $scoreT2,\"t_\ +coffee\",%gl);\n if ( $gl{'Newgroups'}==0){$sco\ +reT2--;} \n }\nprint STDERR \"\\n Step $step: \ +Make The Final Alignment\";$step++;\n\n\n$arg_list\ + .=$output_cl;\n\n\n%gl=&tree2group (0,0, %gl);\n$\ +gl{$gl{'0'}{'File'}}{'Output'}=\"\";\n$a=0;\n&alig\ +n_groups (\"t_coffee\",'0', $arg_list, \" \", %gl)\ +;\n\n\n\nif ( !$dpa_keep_tmpfile){&clean_tmp_file \ +(@tl);}\n\n\n\nsub seq2dpa_tree \n {\n my $seq\ +=@_[0];\n my $newtree=@_[1];\n my $aln=&vtmp\ +nam ();\n\n &my_system (\"t_coffee -special_mod\ +e quickaln -in $seq -outfile $aln -quiet\");\n \ +&my_system (\"$seq_reformat -in $aln -action +aln2\ +tree +tree2dpatree -output newick >$newtree\");\n \ + return $newtree;\n } \nsub seq2dpa_tree_old \n\ + {\n my $aln=@_[0];\n my $newtree=@_[1];\n \ + \n \n &my_system(\"$seq_reformat -in $aln\ + -action +seq2dpatree -output newick > $newtree\")\ +;\n return $newtree;\n }\nsub aln2dpa_tree \n \ + {\n my $aln=@_[0];\n my $newtree=&vtmpnam()\ +;\n \n &my_system(\"$seq_reformat -in $aln -\ +action +aln2tree +tree2dpatree -output newick > $n\ +ewtree\");\n return $newtree;\n }\nsub group_f\ +ile2ngroups\n {\n my $file=@_[0];\n my $n;\\ +n \n open ( F, $file);\n while ()\n \ + {\n $n+=/\\>/;\n }\n close (F);\n re\ +turn $n;\n }\n\nsub make_one_pass\n {\n my ($\ +N, $ID,$pg, %gl)=@_;\n my $a;\n\n %gl=&tree2\ +group ($N,$ID,%gl);\n if (!$gl{'Newgroups'}){re\ +turn %gl;}\n else\n {\n for ( $a=0; $a< $n\ +g; $a++)\n {\n if ($gl{$gl{$a}{'File'}}{'Ng'\ +}>1){&display_group($a, %gl);}\n &align_groups\ + ($pg, $a, $arg_list, \" -quiet=quiet \", %gl);\n \ + }\n return %gl;\n }\n }\n\nsub tree2group \ +\n {\n my ($N, $ID, %gl)=@_;\n my $prefix=&\ +vtmpnam();\n my $group_file=&vtmpnam();\n my\ + $file;\n my $oldtree=&vtmpnam();\n my $n;\n\ + my $tree;\n\n\n if ( $gl{'Ng'}==1){return %\ +gl;}\n $tree=$gl{'Tree'}; \n \n #1 extrac\ +t the groups\n &my_system (\"$seq_reformat -in \ +$tree -action +tree2group $N $ID $prefix > $group_\ +file\");\n $n=group_file2ngroups($group_file);\\ +n \n \n $gl{'Newgroups'}=1;\n if ( $n=\ +=$gl{'Ng'})\n {\n $gl{'Newgroups'}=0;\n retur\ +n %gl;\n }\n $gl{'Iteration'}++;\n $gl{\ +'MaxNseq'}=$N;$gl{'MinID'}=$ID;\n $gl{'GroupFil\ +e'}=$group_file;$gl{'Ng'}=$ng=0;\n #2 Process t\ +he group list into the hash\n open (F, $group_f\ +ile);\n while ()\n {\n $gl{'File'}.=$_;\ +\n if (/\\>/)\n {\n $line=$_;\n $line=~s\ +/\\>//;\n @list=($line=~/(\\S+)/g);\n $fil\ +e=$gl{$ng}{'File'}=shift @list;\n $gl{$file}{'\ +Output'}=$file;\n \n $gl{$file}{'Ng'}=$#li\ +st+1;\n if ($gl{$file}{'Ng'}>1){ $gl{$file}{'T\ +list'}=$gl{$file}{'Alist'}=\"(\";}\n foreach $\ +l (@list)\n {\n \n $gl{$file}{'List'}.=\" $\ +l \";\n \n if (!$gl{$l}{'Tlist'})\n {\n \ +$gl{$l}{'Tlist'}=\"$l\";\n $gl{$l}{'Alist'}=\\ +"$l\";\n $gl{$l}{'Nseq'}=1;\n $gl{$l}{'N\ +g'}=1;\n }\n $gl{$file}{'Tlist'}.=\"$gl{$l}{'T\ +list'},\";\n $gl{$file}{'Alist'}.=\"$gl{$l}{'Tlis\ +t'}|\";\n $gl{$file}{'Nseq'}+=$gl{$l}{'Nseq'};\n \ + }\n \n\n chop($gl{$file}{'Tlist'});c\ +hop($gl{$file}{'Alist'});\n if ($gl{$file}{'Ng\ +'}>1){$gl{$file}{'Tlist'}.=\")\"; $gl{$file}{'Alis\ +t'}.=\");\";}\n $ng++;\n } \n }\n $g\ +l{'Ng'}=$ng;\n close (F);\n \n #3 Update \ +the old tree with the new groups\n $gl{'Tree'}=\ +&vtmpnam();\n &my_system (\"$seq_reformat -in $\ +tree -action +collapse_tree $group_file -output ne\ +wick > $gl{'Tree'}\");\n \n return %gl;\n }\ +\n\nsub display_group \n {\n my ($g,%gl)=@_;\n\ + my $f;\n \n if ( $g==-1)\n {\n prin\ +t STDERR \"\\nIteration $gl{'Iteration'} [MaxN=$gl\ +{'MaxNseq'}][MinID=$gl{'MinID'}]\";\n }\n \ +else\n {\n\n $f=$gl{$g}{'File'};\n $action=($\ +gl{$f}{'Ng'}==1 || $gl{'Iteration'}==1)?\"KEEP \"\ +:\"ALIGN \";\n print STDERR \"\\n\\t[$actio\ +n][MaxN=$gl{'MaxNseq'}][MinID=$gl{'MinID'}][File $\ +f][Nseq=$gl{$f}{'Nseq'}][Ngroups=$gl{$f}{'Ng'}][$g\ +l{$f}{'Alist'}]\";\n }\n }\n \n\n\nsub \ +align_groups\n {\n my ($pg, $g, $arg, $extra_a\ +rg,%gl)=@_;\n my $f;\n my $Output,$Outflag;\\ +n \n \n $f=$gl{$g}{'File'};\n $Output=\ +($gl{$f}{'Output'});\n \n if ( $pg eq \"Alig\ +n\")\n {\n if ( !-e $f)\n {\n $command=\ +\"$seq_reformat -in $gl{'Seq'} -action +extract_a\ +ln $gl{'GroupFile'}\";\n if ($gl{$f}{'Ng'}>1)\\ +n {\n &my_system ($command);\n $command=\"\ +t_coffee -special_mode quick_aln S$f -outfile=$Ou\ +tput -quiet\";\n }\n }\n else \n {$comma\ +nd=\"\";}\n }\n elsif ( -e $f)\n { \n\ + $Outflag=($Output)?\"-outfile=$Output\":\"\";\n $\ +command=\"$pg -infile $f $Outflag -quiet stdout $a\ +rg $extra_arg -maxnseq 0 -convert -quiet stdout\";\ +\n }\n elsif ( $gl{$f}{'Ng'}==1)\n {\\ +n $action=($dpa_debug)?\"cp\":\"mv\";\n $command=\\ +"$action $gl{$f}{'List'} $Output\";\n }\n \ +else\n {\n $Outflag=($Output)?\"-outfile=$Out\ +put\":\"\";\n $command=\"$pg -profile $gl{$f}{'Lis\ +t'} $Outflag $arg $extra_arg -maxnseq 0\";\n \ +}\n \n &my_system ($command);\n return $o\ +utfile;\n }\n \nsub my_system \n {\n my $c\ +ommand=@_[0];\n my $force=@_[1];\n my $statu\ +s;\n\n if ( $dpa_debug) {print STDERR \"\\nCOMM\ +AND: $command\";}\n $status=system ($command);\\ +n\n if (!$force)\n {\n &exit_dpa (($stat\ +us==1), \"Failed in Command:\\n$command\\n[FATAL: \ +t_coffee_dpa]\\n\", EXIT_FAILURE);\n }\n \ +\n return $status;\n }\n\nsub vtmpnam\n {\n \ + my $prefix=@_[0];\n my $tmp_file_name;\n\n \ + $tmp_prefix=($prefix)?$prefix:\"dpa_tmp_file_$$\"\ +;\n \n $tmp_count++;\n $tmp_file_name=\"$t\ +mp_prefix\".\"$tmp_count\";\n $tl[$#tl+1]=$tmp_\ +file_name;\n return $tmp_file_name;\n }\n\nsub\ + clean_tmp_file\n {\n\n my $list;\n my $fil\ +e;\n \n if ($dpa_debug){return;}\n $list=\ +vtmpnam();\n `ls -1 | grep $tmp_prefix>$list`;\\ +n \n open (F,$list);\n while ( )\n \ + {\n $file=$_;\n chop $file;\n if ( -e $file){unl\ +ink $file;}\n }\n close (F);\n unlink $\ +list;\n }\n\n\nsub exit_dpa\n {\n my $condition\ +=@_[0];\n my $error_msg=@_[1];\n my $exit_value=\ +@_[2];\n if ( $condition)\n {\n print \"$\ +error_msg\\n\";\n exit ($exit_value);\n }\\ +n else\n {\n return;\n }\n \n}\nsub e\ +xtract_val_from_arg_list\n {\n my $arg=@_[0];\\ +n my $arg_list=@_[1];\n my $keep_flag=@_[2];\ +\n my $default_value=@_[3];\n my $val=\"\";\\ +n \n #protect\n $arg_list=~s/\\s-/ \\@/g;\ +\n $arg=~s/-/\\@/g;\n \n #search\n if \ +($arg eq \"^\")\n {\n $arg_list=~/^([^@]*)/;\\ +n $val=$1;\n }\n else\n {$arg_list=~/\ +$arg ([^@]*)/;$val=$1;}\n \n #remove trailin\ +g spaces\n $val=~s/\\s*$//;\n \n #remove \ +the parsed sequence if needed\n if (($val ne \"\ +\") && $keep_flag ne \"KEEP\")\n {\n if ( $ar\ +g eq \"^\"){$arg_list=~s/$val/ /;}\n else {$arg_li\ +st=~s/($arg [^@]*)/ /;}\n }\n \n #unprotec\ +t\n $arg_list=~s/\\@/-/g;\n $arg=~s/\\@/-/g;\ +\n \n if (($val eq \"\") && $default_value n\ +e \"unset\"){$val=$default_value;}\n \n retu\ +rn $val, $arg_list;\n }\n$program=\"T-COFFEE (r25\ +3)\";\n\n","\n$DEBUG=1;\n$dpa_nseq=10;\n$dpa_sim=0\ +;\nif (!@ARGV)\n {\n `t_coffee`;\n exit (0)\ +;\n }\nforeach $arg (@ARGV)\n {\n $arg_list.=\ +\" $arg\";\n }\n$max_nseq=10;\n($seq0, $arg_list)\ +=&extract_val_from_arg_list(\"^\",$arg_list);\n($s\ +eq1, $arg_list)=&extract_val_from_arg_list(\"-seq\\ +",$arg_list);\n($seq2, $arg_list)=&extract_val_fro\ +m_arg_list(\"-in\",$arg_list, \"KEEP\");\n($seq3, \ +$arg_list)=&extract_val_from_arg_list(\"-infile\",\ +$arg_list);\n$in_seq=$seq0.\" \".$seq1.\" \".$seq2\ +.\" \".$seq3;\n\n$seq=vtmpnam();\n`t_coffee $in_se\ +q -convert -output fasta_seq -outfile=$seq`;\n\n\n\ +($dpa_nseq, $arg_list)=&extract_val_from_arg_list(\ +\"-dpa_nseq\",$arg_list);\n($master_aln, $arg_list\ +)=&extract_val_from_arg_list(\"-master_aln\",$arg_\ +list);\n($sim_matrix, $arg_list)=&extract_val_from\ +_arg_list(\"-sim_matrix\",$arg_list);\n($core_seq,\ + $arg_list)=&extract_val_from_arg_list(\"-core_seq\ +\",$arg_list);\n($dpa_sim, $arg_list)=&extract_val\ +_from_arg_list(\"-dpa_sim\",$arg_list);\n($run_nam\ +e, $arg_list)=&extract_val_from_arg_list(\"-run_na\ +me\",$arg_list);\n($output, $arg_list)=&extract_va\ +l_from_arg_list(\"-output\",$arg_list);\n\n\n\nif \ +(!$sim_mat && !$master_aln)#Compute the fast align\ +ment\n {\n $ref_aln=vtmpnam();\n `t_coffee \ +-seq=$seq -very_fast -outfile=$ref_aln -quiet`;\n \ + \n }\n\nif (!$sim_mat)\n {\n $sim_mat=vtmp\ +nam();\n `seq_reformat -in $ref_aln -output sim\ + > $sim_mat`;\n }\n\nif ( !$core_seq)\n {\n $\ +core_seq=vtmpnam();\n `seq_reformat -in $ref_al\ +n -action +trimTC N$max_nseq -output fasta_seq > $\ +core_seq`;\n }\n@core_name=`seq_reformat -in $cor\ +e_seq -output name `; \n\n@tot_name=`seq_reformat \ +-in $seq -output name `;\n\nforeach $s (@core_name\ +){$s=~s/\\s//g;$hcore{$s}=1;}\nforeach $s (@tot_na\ +me){$s=~s/\\s//g;}\nprint STDERR \"T-Coffee_dpa:\\\ +n\";\nprint STDERR \"\\tTOTAL SEQ: @tot_name\\n\"\ +;\nprint STDERR \"\\tCHOSEN SEQ: @core_name\\n\";\\ +n\n\n\nopen (F, $sim_mat);\nwhile ( )\n {\n \ + @l=($_=~/(\\b[\\S]+\\b)/g);\n if (($l[0] eq \"\ +TOP\" || $l[0] eq \"BOT\"))\n {\n $s1=$l[1];$\ +s2=$l[2];$v=$l[3];\n if ($hcore{$s1} && !$hcore{$s\ +2})\n {\n if (!$hseq{$s2}{\"sim\"} || $v>$hs\ +eq{$s2}{\"sim\"})\n {\n $hseq{$s2}{\"sim\"}\ +=$v;$hseq{$s2}{\"seq\"}=$s1;\n }\n }\n \ + }\n }\nclose (F);\nforeach $s (@tot_name)\n {\\ +n\n if ( !$hseq{$s}{\"seq\"}){;}\n else\n \ + {\n $s2=$hseq{$s}{\"seq\"};\n $v=$hseq{$s}{\"si\ +m\"};\n \n if ($v>$dpa_sim)\n {\n $hseq{$s}\ +{'used'}=1;\n $seq_list{$s2}{$seq_list{$s2}{'n\ +seq'}++}=$s;\n }\n }\n }\nforeach $s (@cor\ +e_name){$seq_list{$s}{$seq_list{$s}{'nseq'}++}=$s;\ +$hseq{$s}{'used'}=1;}\nforeach $s (@tot_name){if (\ +!$hseq{$s}{'used'}){$seq_list{'unused'}{$seq_list{\ +'unused'}{'nseq'}++}=$s;}}\n\n\n$n=0;\nforeach $s \ +(@core_name)\n {\n $ng++;\n $n=$seq_list{$s\ +}{'nseq'};\n for (@g_list=(), $a=0; $a<$n; $a++\ +){@g_list=(@g_list,$seq_list{$s}{$a});}\n\n $g_\ +seq=vtmpnam();\n $g_aln=vtmpnam();\n \n p\ +rint STDERR \"Group $ng: $#g_list Seq: @g_list: \"\ +;\n \n \n `seq_reformat -in $seq -action \ ++lower +keep_name +extract_seq @g_list -output fa\ +sta_seq > $g_seq`;\n \n \n if ( $#g_list=\ +=0)\n {\n print STDERR \"[No aln]\\n\";\n $g_\ +aln=$g_seq;\n }\n elsif ($#g_list<$max_nse\ +q) \n {\n print STDERR \"[t_coffee]\\n\";\n `\ +t_coffee $g_seq -outfile=$g_aln -quiet $arg_list`;\ +\n }\n else\n {\n print STDERR \"[t_c\ +offee_dpa]\\n\";\n `t_coffee_dpa2 $g_seq -outfile=\ +$g_aln $arg_list -sim_matrix $sim_matrix -dpa_nseq\ + $dpa_nseq`;\n }\n @profile_list=(@profile\ +_list, $g_aln);\n }\n\n\nprint \"UNUSED $seq_list\ +{'unused'}{'nseq'}\";\n\nif ($seq_list{'unused'}{'\ +nseq'})\n {\n $prf=vtmpnam();\n \n \ + `t_coffee -profile @profile_list $arg_list -out\ +file=$prf -quiet`;\n $n=$seq_list{\"unused\"}\ +{'nseq'};\n $new_seq=vtmpnam();\n $new_p\ +rf=vtmpnam();\n for ($a=0; $a<$n-1; $a++)\n {\ +\n $s=$seq_list{\"unused\"}{$a};\n print STDER\ +R \"\\nADD Sequence $s\";\n \n `seq_reformat -\ +in $seq -action +lower +keep_name +extract_seq $s \ + -output fasta_seq > $new_seq`;\n `t_coffee -pro\ +file $prf $new_seq $arg_list -outfile=$new_prf`;\n\ + `cp $new_prf $prf`;\n }\n $s=$seq_list{\"u\ +nused\"}{$a};\n `seq_reformat -in $seq -actio\ +n +lower +keep_name +extract_seq $s -output fasta\ +_seq > $new_seq`;\n @profile_list=($prf, $new\ +_seq);\n }\n \n \nif ($run_name){$arg_l\ +ist.=\" -run_name $run_name\";}\nelse \n {\n $\ +in_seq=~/([\\w-]+)/;\n $arg_list.=\" -run_name \ +$1\";\n }\nif ( $output){$arg_list.=\" -output $o\ +utput \";}\n\n`t_coffee -profile @profile_list $ar\ +g_list`;\n\n\n&clean (@tmp_file_list);\n\n\nsub vt\ +mpnam\n {\n my $tmp_file_name;\n $tmp_name_\ +counter++;\n $tmp_file_name=\"tmp_file_$tmp_nam\ +e_counter\\_Pid$$\";\n $tmp_file_list[$ntmp_fil\ +e++]=$tmp_file_name;\n return $tmp_file_name;\n\ + }\nsub clean\n {\n my @fl=@_;\n my $file;\n \ +return;\n\n foreach $file ( @fl)\n {\n if\ + ( -e $file){unlink($file);}\n }\n}\nsub extrac\ +t_val_from_arg_list\n {\n my $arg=@_[0];\n \ +my $arg_list=@_[1];\n my $keep_flag=@_[2];\n \ + #protect\n $arg_list=~s/\\s-/ \\@/g;\n $arg\ +=~s/-/\\@/g;\n \n #search\n if ($arg eq \\ +"^\")\n {\n $arg_list=~/^([^@]*)/;\n $val=$1;\ +\n }\n else\n {$arg_list=~/$arg ([^@]\ +*)/;$val=$1;}\n \n #remove the parsed sequen\ +ce if needed\n if ($val && $keep_flag ne \"KEEP\ +\")\n {\n if ( $arg eq \"^\"){$arg_list=~s/$v\ +al/ /;}\n else {$arg_list=~s/($arg [^@]*)/ /;}\n \ + }\n \n #unprotect\n $arg_list=~s/\\@/-/g\ +;\n $arg=~s/\\@/-/g;\n \n return $val, $a\ +rg_list;\n }\n\n","use Env;\nuse FileHandle;\nuse\ + Cwd;\nuse File::Path;\nuse Sys::Hostname;\n\nour \ +$PIDCHILD;\nour $ERROR_DONE;\nour @TMPFILE_LIST;\n\ +our $EXIT_FAILURE=1;\nour $EXIT_SUCCESS=0;\n\nour \ +$REFDIR=getcwd;\nour $EXIT_SUCCESS=0;\nour $EXIT_F\ +AILURE=1;\n\nour $PROGRAM=\"tc_generic_method.pl\"\ +;\nour $CL=$PROGRAM;\n\nour $CLEAN_EXIT_STARTED;\n\ +our $debug_lock=$ENV{\"DEBUG_LOCK\"};\nour $debug_\ +cmd_exec=$ENV{\"DEBUG_CMD_EXEC\"};\nour $LOCKDIR=$\ +ENV{\"LOCKDIR_4_TCOFFEE\"};\nif (!$LOCKDIR){$LOCKD\ +IR=getcwd();}\nour $ERRORDIR=$ENV{\"ERRORDIR_4_TCO\ +FFEE\"};\nour $ERRORFILE=$ENV{\"ERRORFILE_4_TCOFFE\ +E\"};\n&set_lock ($$);\nif (isshellpid(getppid()))\ +{lock4tc(getppid(), \"LLOCK\", \"LSET\", \"$$\\n\"\ +);}\n \n\n\n\n\nour $BLAST_MAX_NRUNS=2;\nour \ +$COMMAND;\nour $PIDCHILD;\n\n$REF_EMAIL=\"\";\n$tm\ +p_dir=\"\";\n$init_dir=\"\";\n\n\n$test=0;\nif ($t\ +est==1)\n {\n $SERVER=\"NCBI\";\n $query=$A\ +RGV[0];\n $hitf=$ARGV[1];\n %s=read_fasta_se\ +q($query);\n @sl=keys(%s);\n &blast_xml2prof\ +ile (\"xx\", $s{$sl[0]}{seq},$maxid,$minid,$mincov\ +, $hitf);\n myexit ($EXIT_FAILURE);\n }\n\nfor\ +each $v(@ARGV){$cl.=\"$v \";}\n$COMMAND=$cl;\n($mo\ +de)=&my_get_opt ( $cl, \"-mode=\",1,0);\n\n($A)=(&\ +my_get_opt ( $cl, \"-name1=\",0,0));\n($B)=(&my_ge\ +t_opt ( $cl, \"-name2=\",0,0));\n($TMPDIR)=(&my_ge\ +t_opt ( $cl, \"-tmpdir=\",0,0));\n($CACHE)=(&my_ge\ +t_opt ( $cl, \"-cache=\",0,0));\n($SERVER)=((&my_g\ +et_opt ( $cl, \"-server=\",0,0)));\n($EMAIL)=((&my\ +_get_opt ( $cl, \"-email=\",0,0)));\n\nif (!$A){$A\ +=\"A\";}\nif (!$B){$B=\"B\";}\n\n\nif (!$TMPDIR)\n\ + {\n $HOME=$ENV{HOME};\n if ($ENV{TMP_4_TCO\ +FFEE}){$TMPDIR=$ENV{TMP_4_TCOFFEE};}\n else{$TM\ +PDIR=\"$HOME/.t_coffee/tmp/\";}\n }\nif ( ! -d $T\ +MPDIR)\n {\n mkdir $TMPDIR;\n }\nif ( ! -d $T\ +MPDIR)\n {\n print \"ERROR: Could not create t\ +emporary dir: $TMPDIR\\n\";\n myexit ($EXIT_FAI\ +LURE);\n }\n\n$EMAIL=~s/XEMAILX/\\@/g;\nif (!$EMA\ +IL)\n {\n if ($ENV{EMAIL_4_TCOFFEE}){$EMAIL=$E\ +NV{EMAIL_4_TCOFFEE};}\n elsif ($ENV{EMAIL}){$EM\ +AIL=$ENV{EMAIL};}\n else {$EMAIL=$REF_EMAIL;}\n\ + }\n\n($maxid,$minid,$mincov)=(&my_get_opt ( $cl,\ + \"-maxid=\",0,0, \"-minid=\",0,0,\"-mincov=\",0,0\ +));\nif (!$cl=~/\\-maxid\\=/){$maxid=95;}\nif (!$c\ +l=~/\\-minid\\=/){$minid=35;}\nif (!$cl=~/\\-minco\ +v\\=/){$mincov=80;}\n\n\n\n\nif ($mode eq \"seq_ms\ +a\")\n {\n &seq2msa($mode,&my_get_opt ( $cl, \\ +"-infile=\",1,1, \"-method=\",1,2, \"-param=\",0,0\ +,\"-outfile=\",1,0, \"-database=\",0,0));\n }\nel\ +sif ( $mode eq \"tblastx_msa\")\n {\n &seq2tbl\ +astx_lib ($mode,&my_get_opt ( $cl, \"-infile=\",1,\ +1, \"-outfile=\",1,0));\n }\nelsif ( $mode eq \"t\ +blastpx_msa\")\n {\n &seq2tblastpx_lib ($mode,\ +&my_get_opt ( $cl, \"-infile=\",1,1, \"-outfile=\"\ +,1,0));\n }\nelsif ( $mode eq \"thread_pair\")\n \ + {\n &seq2thread_pair($mode,&my_get_opt ( $cl, \ +\"-infile=\",1,1, \"-pdbfile1=\",1,1, \"-method=\"\ +,1,2,\"-param=\",0,0, \"-outfile=\",1,0, ));\n }\\ +nelsif ( $mode eq \"pdbid_pair\")\n {\n &seq2p\ +dbid_pair($mode,&my_get_opt ( $cl, \"-pdbfile1=\",\ +1,0, \"-pdbfile2=\",1,0, \"-method=\",1,2,\"-param\ +=\",0,0, \"-outfile=\",1,0, ));\n }\nelsif ( $mod\ +e eq \"pdb_pair\")\n {\n &seq2pdb_pair($mode,&\ +my_get_opt ( $cl, \"-pdbfile1=\",1,1, \"-pdbfile2=\ +\",1,1, \"-method=\",1,2,\"-param=\",0,0, \"-outfi\ +le=\",1,0, ));\n }\nelsif ( $mode eq \"profile_pa\ +ir\")\n {\n &seq2profile_pair($mode,&my_get_o\ +pt ( $cl, \"-profile1=\",1,1, \"-profile2=\",1,1, \ +\"-method=\",1,2,\"-param=\",0,0, \"-outfile=\",1,\ +0 ));\n }\nelsif ($mode eq \"pdb_template_test\")\ +\n {\n &blast2pdb_template_test ($mode,&my_get\ +_opt ( $cl, \"-infile=\",1,1));\n\n }\nelsif ($mo\ +de eq \"psi_template_test\")\n {\n &psiblast2p\ +rofile_template_test ($mode,&my_get_opt ( $cl, \"-\ +seq=\",1,1,\"-blast=\",1,1));\n\n }\n\nelsif ( $m\ +ode eq \"pdb_template\")\n {\n &blast2pdb_temp\ +late ($mode,&my_get_opt ( $cl, \"-infile=\",1,1, \\ +"-database=\",1,0, \"-method=\",1,0, \"-outfile=\"\ +,1,0,\"-pdb_type=\",1,0));\n }\n\nelsif ( $mode e\ +q \"profile_template\")\n {\n \n &psiblast2\ +profile_template ($mode,&my_get_opt ( $cl, \"-infi\ +le=\",1,1, \"-database=\",1,0, \"-method=\",1,0, \\ +"-outfile=\",1,0));\n }\nelsif ( $mode eq \"psipr\ +ofile_template\")\n {\n &psiblast2profile_temp\ +late ($mode,&my_get_opt ( $cl, \"-infile=\",1,1, \\ +"-database=\",1,0, \"-method=\",1,0, \"-outfile=\"\ +,1,0));\n }\nelsif ( $mode eq \"RNA_template\")\n\ + {\n &seq2RNA_template ($mode,&my_get_opt ( $c\ +l, \"-infile=\",1,1, \"-outfile=\",1,0));\n }\nel\ +sif ( $mode eq \"tm_template\")\n {\n &seq2tm_\ +template ($mode, \"\", &my_get_opt ( $cl, \"-infil\ +e=\",1,1,\"-arch=\",1,1,\"-psv=\",1,1, \"-outfile=\ +\",1,0,));\n }\nelsif ( $mode eq \"psitm_template\ +\")\n {\n &seq2tm_template ($mode,&my_get_opt \ +( $cl, \"-database=\",1,0, \"-infile=\",1,1, \"-ar\ +ch=\",1,1,\"-psv=\",1,1, \"-outfile=\",1,0,));\n \ +}\nelsif ( $mode eq \"ssp_template\")\n {\n &s\ +eq2ssp_template ($mode,&my_get_opt ( $cl, \"-infil\ +e=\",1,1,\"-seq=\",1,1,\"-obs=\",1,1, \"-outfile=\\ +",1,0));\n }\nelsif ( $mode eq \"psissp_template\\ +")\n {\n &seq2ssp_template ($mode,&my_get_opt \ +( $cl, \"-infile=\",1,1,\"-seq=\",1,1,\"-obs=\",1,\ +1, \"-outfile=\",1,0));\n }\n\nelsif ( $mode eq \\ +"rna_pair\")\n{\n &seq2rna_pair($mode,&my_get_o\ +pt ( $cl, \"-pdbfile1=\",1,1, \"-pdbfile2=\",1,1, \ +\"-method=\",1,2,\"-param=\",0,0, \"-outfile=\",1,\ +0, ));\n}\nelsif ( $mode eq \"calc_rna_template\")\ +\n{\n &calc_rna_template($mode,&my_get_opt ( $c\ +l, \"-infile=\",1,1,\"-pdbfile=\",1,1, \"-outfile=\ +\",1,0));\n}\nelse\n {\n myexit(flush_error( \\ +"$mode is an unknown mode of tc_generic_method.pl\\ +"));\n }\nmyexit ($EXIT_SUCCESS);\n\n\nsub seq2ss\ +p_template\n {\n my ($mode, $infile,$gor_seq,$go\ +r_obs,$outfile)=@_;\n my %s, %h;\n my $result;\n\ + my (@profiles);\n &set_temporary_dir (\"set\",$\ +infile,\"seq.pep\");\n %s=read_fasta_seq (\"seq.p\ +ep\");\n\n \n open (R, \">result.aln\");\n \n \ +#print stdout \"\\n\";\n foreach $seq (keys(%s))\\ +n {\n \n open (F, \">seqfile\");\n \ + $s{$seq}{seq}=uc$s{$seq}{seq};\n print (F \ +\">$s{$seq}{name}\\n$s{$seq}{seq}\\n\");\n cl\ +ose (F);\n $lib_name=\"$s{$seq}{name}.ssp\";\\ +n $lib_name=&clean_file_name ($lib_name);\n \ + \n if ($mode eq \"ssp_template\"){&seq2go\ +r_prediction ($s{$seq}{name},$s{$seq}{seq}, \"seqf\ +ile\", $lib_name,$gor_seq, $gor_obs);}\n elsi\ +f ($mode eq \"psissp_template\")\n {\n &seq2msa_\ +gor_prediction ($s{$seq}{name},$s{$seq}{seq},\"seq\ +file\", $lib_name,$gor_seq, $gor_obs);\n }\n \n\ + if ( !-e $lib_name)\n {\n myexit(flush_err\ +or(\"GORIV failed to compute the secondary structu\ +re of $s{$seq}{name}\"));\n myexit ($EXIT_FAILUR\ +E);\n }\n else\n {\n print stdout \"\\tProc\ +ess: >$s{$seq}{name} _E_ $lib_name \\n\";\n prin\ +t R \">$s{$seq}{name} _E_ $lib_name\\n\";\n }\n \ + unshift (@profiles, $lib_name);\n }\n close\ + (R);\n &set_temporary_dir (\"unset\",$mode, $met\ +hod,\"result.aln\",$outfile, @profiles);\n}\n\nsub\ + seq2tm_template\n {\n my ($mode, $db, $infile,$\ +arch,$psv,$outfile)=@_;\n my %s, %h;\n my $resul\ +t;\n my (@profiles);\n &set_temporary_dir (\"set\ +\",$infile,\"seq.pep\");\n %s=read_fasta_seq (\"s\ +eq.pep\");\n\n \n open (R, \">result.aln\");\n \ +\n #print stdout \"\\n\";\n foreach $seq (keys(%\ +s))\n {\n open (F, \">seqfile\");\n p\ +rint (F \">$s{$seq}{name}\\n$s{$seq}{seq}\\n\");\n\ + close (F);\n $lib_name=\"$s{$seq}{name}\ +.tmp\";\n $lib_name=&clean_file_name ($lib_na\ +me);\n\n if ($mode eq \"tm_template\")\n {\n \ + &safe_system (\"t_coffee -other_pg fasta_seq2hmm\ +top_fasta.pl -in=seqfile -out=$lib_name -arch=$arc\ +h -psv=$psv\");\n }\n elsif ( $mode eq \"psit\ +m_template\")\n {\n &seq2msa_tm_prediction ($s{$\ +seq}{name},$s{$seq}{seq}, $db, \"seqfile\", $lib_n\ +ame,$arch, $psv);\n }\n if ( !-e $lib_name)\n\ + {\n myexit(flush_error(\"RNAplfold failed to co\ +mpute the secondary structure of $s{$seq}{name}\")\ +);\n myexit ($EXIT_FAILURE);\n }\n else\n {\ +\n print stdout \"\\tProcess: >$s{$seq}{name} _T\ +_ $lib_name\\n\";\n print R \">$s{$seq}{name} _T\ +_ $lib_name\\n\";\n }\n unshift (@profiles, $\ +lib_name);\n }\n close (R);\n &set_temporary_\ +dir (\"unset\",$mode, $method,\"result.aln\",$outf\ +ile, @profiles);\n}\n\nsub seq2RNA_template\n {\n\ + my ($mode, $infile,$outfile)=@_;\n my %s, %h, ;\ +\n my $result;\n my (@profiles);\n &set_tempora\ +ry_dir (\"set\",$infile,\"seq.pep\");\n %s=read_f\ +asta_seq (\"seq.pep\");\n\n \n open (R, \">resul\ +t.aln\");\n \n #print stdout \"\\n\";\n foreach\ + $seq (keys(%s))\n {\n open (F, \">seqfile\ +\");\n print (F \">$s{$seq}{name}\\n$s{$seq}{\ +seq}\\n\");\n close (F);\n $lib_name=\"$\ +s{$seq}{name}.rfold\";\n $lib_name=&clean_fil\ +e_name ($lib_name);\n &safe_system (\"t_coffe\ +e -other_pg RNAplfold2tclib.pl -in=seqfile -out=$l\ +ib_name\");\n \n if ( !-e $lib_name)\n {\ +\n myexit(flush_error(\"RNAplfold failed to compu\ +te the secondary structure of $s{$seq}{name}\"));\\ +n myexit ($EXIT_FAILURE);\n }\n else\n {\n \ + print stdout \"\\tProcess: >$s{$seq}{name} _F_ $\ +lib_name\\n\";\n print R \">$s{$seq}{name} _F_ $\ +lib_name\\n\";\n }\n unshift (@profiles, $lib\ +_name);\n }\n close (R);\n &set_temporary_dir\ + (\"unset\",$mode, $method,\"result.aln\",$outfile\ +, @profiles);\n}\nsub psiblast2profile_template_te\ +st\n {\n my ($mode, $seq,$blast)=@_;\n my %s, %\ +h, ;\n my ($result,$psiblast_output,$profile_name\ +,@profiles);\n my $trim=0;\n my $maxid=100;\n m\ +y $minid=0;\n my $mincov=0;\n my $maxcov=100;\n \ + \n %s=read_fasta_seq ($seq);\n open (R, \">resu\ +lt.aln\");\n \n #print stdout \"\\n\";\n foreac\ +h $seq (keys(%s))\n {\n \n open (F, \\ +">seqfile\");\n print (F \">$A\\n$s{$seq}{seq\ +}\\n\");\n close (F);\n $psiblast_output\ +=$blast;\n if ( -e $psiblast_output)\n {\n \ +%profile=blast_xml2profile($s{$seq}{name}, $s{$seq\ +}{seq},$maxid, $minid,$mincov,$psiblast_output);\n\ +\n\n \n $profile_name=\"$s{$seq}{name}.prf\";\\ +n $profile_name=&clean_file_name ($profile_name)\ +;\n unshift (@profiles, $profile_name);\n outp\ +ut_profile ($profile_name, \\%profile, $trim);\n \ + print stdout \"\\tProcess: >$s{$seq}{name} _R_ $p\ +rofile_name [$profile{n} Seq.] [$SERVER/blast/$db]\ +[$CACHE_STATUS]\\n\";\n print R \">$s{$seq}{name\ +} _R_ $profile_name\\n\";\n }\n }\n close (R);\ +\n \n die;\n}\nsub psiblast2profile_template \n \ + {\n my ($mode, $infile, $db, $method, $outfile)=\ +@_;\n my %s, %h, ;\n my ($result,$psiblast_outpu\ +t,$profile_name,@profiles);\n my $trim=0;\n &set\ +_temporary_dir (\"set\",$infile,\"seq.pep\");\n %\ +s=read_fasta_seq (\"seq.pep\");\n open (R, \">res\ +ult.aln\");\n \n #print stdout \"\\n\";\n forea\ +ch $seq (keys(%s))\n {\n open (F, \">seqfi\ +le\");\n print (F \">$A\\n$s{$seq}{seq}\\n\")\ +;\n close (F);\n $psiblast_output=&run_b\ +last ($s{$seq}{name},$method, $db, \"seqfile\",\"o\ +utfile\");\n \nif ( -e $psiblast_output)\n {\\ +n %profile=blast_xml2profile($s{$seq}{name}, $s{\ +$seq}{seq},$maxid, $minid,$mincov,$psiblast_output\ +);\n unlink ($psiblast_output);\n \n $profil\ +e_name=\"$s{$seq}{name}.prf\";\n $profile_name=&\ +clean_file_name ($profile_name);\n unshift (@pro\ +files, $profile_name);\n output_profile ($profil\ +e_name, \\%profile, $trim);\n print stdout \"\\t\ +Process: >$s{$seq}{name} _R_ $profile_name [$profi\ +le{n} Seq.] [$SERVER/blast/$db][$CACHE_STATUS]\\n\\ +";\n print R \">$s{$seq}{name} _R_ $profile_name\ +\\n\";\n }\n }\n close (R);\n &set_temporary_\ +dir (\"unset\",$mode, $method,\"result.aln\",$outf\ +ile, @profiles);\n}\nsub blast2pdb_template_test\n\ + {\n my ($mode,$infile)=@_;\n my ($ma\ +xid,$minid,$mincov);\n $maxid=100;\n $mi\ +nid=0;\n $mincov=0;\n \n print \"$i\ +nfile\\n\";\n \n %p=blast_xml2profile($s\ +{$seq}{name}, $s{$seq}{seq},$maxid, $minid,$mincov\ +,$infile);\n $c=1;\n print stdout \"\\tP\ +rocess: >$s{$seq}{name} [$SERVER/blast/$db][$CACHE\ +_STATUS]\\n\";\n while (!$found && $c<$p{n})\\ +n {\n $pdbid=&id2pdbid($p{$c}{identifyer});\n \ +if ( length ($pdbid)>5){$pdbid=id2pdbid($p{$c}{def\ +inition});}\n \n if ( length ($pdbid)>5)\n \ + {\n myexit(add_error (EXIT_FAILURE,$$,$$,ge\ +tppid(), \"BLAST_FAILURE::Could Not Parse PDBID ($\ +p{$c}{identifyer},$p{$c}{definition})\"));\n }\ +\n \n \n if (!&pdb_is_released($pdbid))\n \ + {\n print stdout \"\\t\\t**$pdbid [PDB NOT\ + RELEASED or WITHDRAWN]\\n\";\n $c++;\n \ +}\n elsif (!&pdb_has_right_type ($pdbid,$type))\\ +n {\n my $ptype=&pdb2type ($pdbid);\n \ + my $etype=&type2etype($type);\n \n \ + print stdout \"\\t\\t**$pdbid [$ptype cannot be u\ +sed (expected: $etype)]\\n\";\n $c++;\n \ +}\n else\n {\n $found=1;\n }\n }\n\ +\n if ($found)\n {\n print stdout \"\\t\\t \ +>$s{$seq}{name} _P_ $pdbid\\n\";\n }\n else\n\ + {\n print stdout \"\\t\\t >$s{$seq}{name} No Te\ +mplate Selected\\n\";\n }\n die;\n }\nsub \ +blast2pdb_template \n {\n my ($mode, $infile, $d\ +b, $method, $outfile,$type)=@_;\n my %s, %h, ;\n \ + my ($result,$blast_output);\n &set_temporary_dir\ + (\"set\",$infile,\"seq.pep\");\n %s=read_fasta_s\ +eq (\"seq.pep\");\n open (R, \">result.aln\");\n \ + \n \n #print stdout \"\\n\";\n foreach $seq (ke\ +ys(%s))\n {\n my $c;\n my $found;\n \ + \n open (F, \">seqfile\");\n print (\ +F \">$A\\n$s{$seq}{seq}\\n\");\n close (F);\n\ + \n $blast_output=&run_blast ($s{$seq}{na\ +me},$method, $db, \"seqfile\",\"outfile\");\n \ +\n %p=blast_xml2profile($s{$seq}{name}, $s{$s\ +eq}{seq},$maxid, $minid,$mincov,$blast_output);\n \ + unlink ($blast_output);\n \n $c=1;\\ +n print stdout \"\\tProcess: >$s{$seq}{name} \ +[$SERVER/blast/$db][$CACHE_STATUS]\\n\";\n wh\ +ile (!$found && $c<$p{n})\n {\n $pdbid=&id2pdbid\ +($p{$c}{identifyer});\n if ( length ($pdbid)>5){\ +$pdbid=id2pdbid($p{$c}{definition});}\n\n if ( l\ +ength ($pdbid)>5)\n {\n myexit(add_error\ + (EXIT_FAILURE,$$,$$,getppid(), \"BLAST_FAILURE::C\ +ould Not Parse PDBID ($p{$c}{identifyer},$p{$c}{de\ +finition})\"));\n }\n \n\n if (!&pdb_is_re\ +leased($pdbid))\n {\n print stdout \"\\t\ +\\t**$pdbid [PDB NOT RELEASED or WITHDRAWN]\\n\";\\ +n $c++;\n }\n elsif (!&pdb_has_right_t\ +ype ($pdbid,$type))\n {\n my $ptype=&pdb\ +2type ($pdbid);\n my $etype=&type2etype($typ\ +e);\n \n print stdout \"\\t\\t**$pdbid\ + [$ptype cannot be used (expected: $etype)]\\n\";\\ +n $c++;\n }\n else\n {\n $fo\ +und=1;\n }\n }\n\n if ($found)\n {\n pr\ +int R \">$s{$seq}{name} _P_ $pdbid\\n\";\n print\ + stdout \"\\t\\t >$s{$seq}{name} _P_ $pdbid\\n\";\\ +n }\n else\n {\n print R \">$s{$seq}{name}\\ +\n\";\n print stdout \"\\t\\t >$s{$seq}{name} No\ + Template Selected\\n\";\n }\n }\n close (R);\\ +n &set_temporary_dir (\"unset\",$mode, $method,\"\ +result.aln\",$outfile);\n}\nsub type2etype\n {\n \ + my $type=shift;\n my $etype;\n \n if (\ + $type=~/n/){$etype.=\"NMR \";}\n if ( $type=~/\ +d/){$etype.=\"diffraction \";}\n if ( $type=~/m\ +/){$etype.=\"model \";}\n return $etype;\n }\n\ +sub pdb2type\n {\n my $pdb=shift;\n my $f\ +=vtmpnam();\n \n my $value= &safe_system (\ +\"t_coffee -other_pg extract_from_pdb -model_type \ +$pdb > $f\");\n my $r=&file2string ($f);\n \ + chomp($r);\n return $r;\n }\nsub pdb_has_ri\ +ght_type\n {\n my $pdb=shift;\n my $type=sh\ +ift;\n \n my $f=vtmpnam();\n \n my $va\ +lue= &safe_system (\"t_coffee -other_pg extract_fr\ +om_pdb -model_type $pdb > $f\");\n my $r=&file2\ +string ($f);\n chomp($r);\n\n \n if (\ + $r eq \"NMR\" && $type=~/n/){return 1;}\n elsi\ +f ( $r eq \"diffraction\" && $type=~/d/){return 1;\ +}\n elsif ( $r eq \"model\" && $type=~/m/){retu\ +rn 1;}\n else {return 0;}\n }\nsub pdb_is_rele\ +ased\n {\n my $pdb=shift;\n my $f=vtmpnam()\ +;\n \n $value= &safe_system (\"t_coffee -oth\ +er_pg extract_from_pdb -is_released_pdb_name $pdb \ +> $f\");\n my $r=&file2string ($f);\n chomp(\ +$r);\n return $r;\n }\nsub blast_msa\n {\n \ + my ($infile,$db,$outfile)=@_;\n my ($a, %seq);\ +\n my $seqfile;\n my $SEQ=new FileHandle;\n \ + my $seqfile=\"seqfile\";\n my @txt;\n \n \ + \n %s1=&read_fasta_seq ($db);\n \n for\ +each $s (keys (%s1))\n {\n $i=$s1{$s}{order};\ +\n $s{$i}{name}=$s;\n $s{$i}{seq}=$s1{$s}{seq};\n \ +$s{$i}{len}=length( $s{$i}{seq});\n $s{n}++;\n \ + }\n \n &safe_system (\"formatdb -i $db\");\ +\n &safe_system (\"blastall -i $infile -d $db \ +-m7 -p blastp -o io\");\n &set_blast_type (\"io\ +\");\n \n %FB=&xml2tag_list (\"io\", \"Itera\ +tion\");\n open (F, \">$outfile\");\n print \ +F \"! TC_LIB_FORMAT_01\\n\";\n print F \"$s{n}\\ +\n\";\n for ( $a=0; $a<$s{n}; $a++)\n {\n \ +print F \"$s{$a}{name} $s{$a}{len} $s{$a}{seq}\\n\\ +";\n }\n\n\n for ( $a=0; $a<$FB{n}; $a++)\\ +n {\n %p=blast_xml2profile ($s{$a}{name}, $s{\ +$a}{seq},100, 0, 0, $FB{$a}{body});\n my $query=$p\ +{0}{name};\n my $i= $s1{$query}{order}+1;\n for ($\ +b=1; $b<$p{n}; $b++)\n {\n my $l=length ($p{\ +$b}{Qseq});\n my $hit=$p{$b}{definition};\n \ + my $Qstart=$p{$b}{Qstart};\n my $Hstart=$p{$\ +b}{Hstart};\n my $identity=$p{$b}{identity};\n\ + my @lrQ=split (//,$p{$b}{Qseq});\n my @lr\ +H=split (//,$p{$b}{Hseq});\n \n my $j= $s1\ +{$hit}{order}+1;\n #if ( $j==$i){next;}\n \ +printf F \"# %d %d\\n\", $i, $j;\n # print F\ + \"\\n$p{$b}{Qseq} ($Qstart)\\n$p{$b}{Hseq} ($Hsta\ +rt)\";\n for ($c=0; $c<$l; $c++)\n {\n \ +my $rQ=$lrQ[$c];\n my $rH=$lrH[$c];\n my $n=0;\n\ + \n if ($rQ ne \"-\"){$n++, $Qstart++;}\n if ($\ +rH ne \"-\"){$n++; $Hstart++;}\n \n if ( $n==2)\\ +n {\n printf F \"\\t%d %d %d\\n\", $Qstart\ +-1, $Hstart-1,$identity;\n }\n }\n }\n \ + }\n print F \"! SEQ_1_TO_N\\n\";\n clos\ +e (F);\n return $output;\n \n }\n\nsub blast_\ +msa_old\n {\n my ($infile,$outfile)=@_;\n m\ +y ($a, %seq);\n %s1=&read_fasta_seq ($infile);\\ +n foreach $s (keys (%s1))\n {\n $i=$s1{$s}\ +{order};\n $s{$i}{name}=$s;\n $s{$i}{seq}=$s1{$s}{\ +seq};\n $s{$i}{len}=length( $s{$i}{seq});\n $s{n}+\ ++;\n }\n &safe_system (\"formatdb -i $infi\ +le\");\n &safe_system (\"blastall -i $infile -d\ + $infile -m7 -o io\");\n &set_blast_type (\"io\\ +");\n \n %FB=&xml2tag_list (\"io\", \"Iterat\ +ion\");\n \n open (F, \">$outfile\");\n p\ +rint F \"! TC_LIB_FORMAT_01\\n\";\n print F \"$\ +s{n}\\n\";\n for ( $a=0; $a<$s{n}; $a++)\n \ + {\n print F \"$s{$a}{name} $s{$a}{len} $s{$a}{seq\ +}\\n\";\n }\n for ( $a=0; $a<$FB{n}; $a++)\ +\n {\n %p=blast_xml2profile ($s{$a}{name}, $s\ +{$a}{seq},100, 0, 0, $FB{$a}{body});\n for ($b=1; \ +$b<$p{n}; $b++)\n {\n my $l=length ($p{$b}{Q\ +seq});\n my $hit=$p{$b}{definition};\n my \ +$Qstart=$p{$b}{Qstart};\n my $Hstart=$p{$b}{Hs\ +tart};\n my $identity=$p{$b}{identity};\n \ +my @lrQ=split (//,$p{$b}{Qseq});\n my @lrH=spl\ +it (//,$p{$b}{Hseq});\n my $i= $s1{$s{$a}{name\ +}}{order}+1;\n my $j= $s1{$hit}{order}+1;\n \ + #if ( $j==$i){next;}\n printf F \"# %d %d\\n\ +\", $i, $j;\n # print F \"\\n$p{$b}{Qseq} ($\ +Qstart)\\n$p{$b}{Hseq} ($Hstart)\";\n for ($c=\ +0; $c<$l; $c++)\n {\n my $rQ=$lrQ[$c];\n m\ +y $rH=$lrH[$c];\n my $n=0;\n \n if ($rQ ne \"-\\ +"){$n++, $Qstart++;}\n if ($rH ne \"-\"){$n++; $H\ +start++;}\n \n if ( $n==2)\n {\n printf \ +F \"\\t%d %d %d\\n\", $Qstart-1, $Hstart-1,$identi\ +ty;\n }\n }\n }\n }\n print F \\ +"! SEQ_1_TO_N\\n\";\n close (F);\n return $o\ +utput;\n \n }\n\nsub seq2msa\n {\n my ($mode\ +, $infile, $method, $param, $outfile,$database)=@_\ +;\n &set_temporary_dir (\"set\",$infile,\"seq.p\ +ep\", $database, \"db.pep\");\n $param.=\" >/de\ +v/null 2>&1 \";\n \n \n #make sure test.p\ +ep is in FASTA\n &safe_system (\"t_coffee -othe\ +r_pg seq_reformat -in seq.pep -output fasta_seq > \ +x\");\n `mv x seq.pep`;\n \n if ( $method\ + eq \"blastp\")\n {\n &blast_msa (\"seq.pep\"\ +, \"db.pep\",\"result.aln\");\n }\n elsif \ +( $method eq \"muscle\")\n {\n `muscle -in se\ +q.pep -out result.aln $param`;\n }\n elsif\ + ( $method eq \"probcons\")\n {\n `probcons s\ +eq.pep >result.aln 2>/dev/null`;\n }\n els\ +if ( $method eq \"mafft\")\n {\n `mafft --qui\ +et --localpair --maxiterate 1000 seq.pep> result.a\ +ln 2>/dev/null`\n }\n elsif ( $method=~/p\ +rank/)\n {\n `$method -d=seq.pep -o=result.al\ +n -quiet 2>/dev/null`;\n `mv result.aln.1.fas resu\ +lt.aln`;\n }\n else\n {\n `$method -i\ +nfile=seq.pep -outfile=result.aln`;\n }\n \ +\n &set_temporary_dir (\"unset\",$mode, $method\ +,\"result.aln\",$outfile);\n myexit ($EXIT_SUCC\ +ESS);\n }\n\nsub seq2thread_pair\n {\n my ($m\ +ode, $infile, $pdbfile1, $method, $param, $outfile\ +)=@_;\n &set_temporary_dir (\"set\",$infile,\"s\ +eq.pep\",$pdbfile1,\"struc.pdb\");\n if ($metho\ +d eq \"fugueali\")\n {\n #Env Variable that n\ +eed to be defined for Fugue\n if (!$ENV{FUGUE_LIB_\ +LIST}){$ENV{FUGUE_LIB_LIST}=\"DUMMY\";}\n if (!$EN\ +V{HOMSTRAD_PATH}) {$ENV{HOMSTRAD_PATH}=\"DUMMY\";\ +}\n if (!$ENV{HOMS_PATH}){$ENV{HOMS_PATH}=\"DUMMY\\ +";}\n \n `joy struc.pdb >x 2>x`;\n &check_file(\"s\ +truc.tem\", \"Joy failed [FATAL:$PROGRAM/$method]\\ +");\n `melody -t struc.tem >x 2>x`;\n &check_file(\ +\"struc.tem\", \"Melody failed [FATAL:$PROGRAM/$me\ +thod]\");\n `fugueali -seq seq.pep -prf struc.fug \ +-print > tmp_result.aln`;\n \n &check_file(\"tmp_r\ +esult.aln\", \"Fugue failed [FATAL:$PROGRAM/$metho\ +d]\");\n &safe_system (\"t_coffee -other_pg seq_re\ +format -in tmp_result.aln -output fasta_aln >resul\ +t.aln\");\n }\n elsif ( $method eq \"t_cof\ +fee\")\n {\n &safe_system (\"t_coffee -in Pst\ +ruc.pdb Sseq.pep Mslow_pair -outfile result.aln -q\ +uiet\");\n }\n else\n {\n &safe_syste\ +m (\"$method -infile=seq.pep -pdbfile1=struc.pdb -\ +outfile=result.aln $param>x 2>x\");\n }\n \ +&set_temporary_dir (\"unset\",$mode,$method,\"resu\ +lt.aln\",$outfile);\n myexit ($EXIT_SUCCESS);\n\ + }\nsub seq2pdbid_pair\n {\n my ($mode, $pdbf\ +ile1, $pdbfile2, $method, $param, $outfile)=@_;\n \ + my ($name);\n\n \n &set_temporary_dir (\"\ +set\");\n $name=$pdbfile1.\" \".$pdbfile2;\n\n \ + if ( &cache_file(\"GET\",\"\",\"$name\",\"$m\ +ethod\",\"dali\",$outfile,\"EBI\"))\n {return\ + $outfile;}\n else\n {\n if ($method eq \"\ +daliweb\")\n {\n $pdbfile1=~/(....)(.)/;\n \ + $id1=$1; $c1=$2;\n \n $pdbfile2=~/(....\ +)(.)/;\n $id2=$1; $c2=$2;\n \n $comman\ +d=\"t_coffee -other_pg dalilite.pl --pdb1 $id1 --c\ +hainid1 $c1 --pdb2 $id2 --chainid2 $c2 --email=$EM\ +AIL >dali_stderr 2>dali_stderr\";\n $dali=`$c\ +ommand`;\n \n open (F, \"dali_stderr\");\n\ + while ()\n {\n if ( /JobId: dalilit\ +e-(\\S+)/)\n {\n $jobid=$1;\n }\n }\n \ + close (F);\n unlink (\"dali_stderr\");\n \ + \n $output1=\"dalilite-$jobid.txt\";\n i\ +f ( -e $output1)\n {\n unlink ($output1);\n\ + &url2file (\"http://www.ebi.ac.uk/Tools/es/cgi-b\ +in/jobresults.cgi/dalilite/dalilite-$jobid/aln.htm\ +l\", \"output2\");\n \n if ( -e \"output2\")\n \ + {\n my ($seq1, $seq2);\n $seq1=$seq2=\\ +"\";\n \n open (F, \"output2\");\n \ +while ()\n {\n $l=$_;\n if ( $l=~/Qu\ +ery\\s+(\\S+)/)\n {\n $seq1.=$1;\n }\ +\n elsif ( $l=~/Sbjct\\s+(\\S+)/)\n {\n \ + $seq2.=$1;\n }\n }\n close (F);\\ +n unlink (\"output2\");\n if ($seq1 ne \\ +"\" && $seq2 ne \"\")\n {\n $output3=\">$\ +A\\n$seq1\\n>$B\\n$seq2\\n\";\n $output3=~s/\\./\ +-/g;\n open (F, \">result.aln\");\n print F \"\ +$output3\";\n close (F);\n }\n }\n \ + }\n }\n }\n &cache_file(\"SET\",\"\",\ +\"$name\",\"$method\",\"dali\",\"result.aln\",\"EB\ +I\");\n &set_temporary_dir (\"unset\",$mode, $m\ +ethod, \"result.aln\",$outfile);\n myexit ($EXI\ +T_SUCCESS);\n }\nsub seq2pdb_pair\n {\n my ($\ +mode, $pdbfile1, $pdbfile2, $method, $param, $outf\ +ile)=@_;\n \n &set_temporary_dir (\"set\",$p\ +dbfile1,\"pdb1.pdb\",$pdbfile2,\"pdb2.pdb\");\n \ + if ($method eq \"t_coffee\")\n {\n &safe_sys\ +tem (\"t_coffee -in Ppdb1.pdb Ppdb2.pdb -quiet -ou\ +tfile=result.aln\");\n }\n elsif ( $method\ + eq \"DaliLite\")\n {\n if ( &safe_system (\"\ +DaliLite -pairwise pdb1.pdb pdb2.pdb >tmp1\")==$EX\ +IT_SUCCESS)\n {\n my ($seq1, $seq2);\n \ + $seq1=$seq2=\"\";\n \n open (F, \"tmp1\\ +");\n while ()\n {\n $l=$_;\n i\ +f ( $l=~/Query\\s+(\\S+)/)\n {\n $seq1.=\ +$1;\n }\n elsif ( $l=~/Sbjct\\s+(\\S+)/)\n \ + {\n $seq2.=$1;\n }\n }\n \ +close (F);\n unlink (\"tmp1\");\n if ($s\ +eq1 ne \"\" && $seq2 ne \"\")\n {\n my $o\ +utput3=\">$A\\n$seq1\\n>$B\\n$seq2\\n\";\n $outp\ +ut3=~s/\\./-/g;\n open (F, \">result.aln\");\n \ + print F \"$output3\";\n close (F);\n }\n\ + }\n else\n {\n print \"ERROR: DalLite fa\ +iled to align the considered structures[tc_generic\ +_method.pl]\\n\";\n } \n }\n elsif ( \ +$method eq \"TMalign\")\n {\n if ( &safe_syst\ +em (\"TMalign pdb1.pdb pdb2.pdb >tmp1\")==$EXIT_SU\ +CCESS)\n {\n `tail -4 tmp1 > tmp2`;\n \n\ + open (F, \"tmp2\");\n while ()\n \ + {\n unshift(@l, $_);\n }\n close (F);\\ +n open (F, \">result.aln\");\n $l[3]=~s/[^\ +a-zA-Z0-9-]/\\-/g;\n $l[1]=~s/[^a-zA-Z0-9-]/\\\ +-/g;\n print F \">$A\\n$l[3]\\n>$B\\n$l[1]\\n\\ +";\n close (F);\n }\n else\n {\n print\ + \"ERROR: TMalign failed to align the considered s\ +tructures[tc_generic_method.pl]\\n\";\n `rm re\ +sult.aln >/dev/null 2>/dev/null`;\n }\n }\n\ + elsif ( $method eq \"mustang\")\n {\n if \ +( &safe_system (\"mustang -i pdb1.pdb pdb2.pdb -F \ +fasta >/dev/null 2>/dev/null\")==$EXIT_SUCCESS)\n \ + {\n `mv results.afasta result.aln`;\n }\n \ +else\n {\n print \"ERROR: mustang failed to \ +align the considered structures[tc_generic_method.\ +pl]\\n\";\n `rm result.aln >/dev/null 2>/dev/n\ +ull`;\n }\n }\n else\n {\n if ( &sa\ +fe_system (\"$method -pdbfile1=pdb1.pep -pdbfile2=\ +pdb2.pdb -outfile=result.aln $param>x 2>x\")==$EXI\ +T_SUCCESS)\n {\n `mv results.afasta result.a\ +ln`;\n }\n else\n {\n print \"ERROR: $meth\ +od failed to align the considered structures[tc_ge\ +neric_method.pl]\\n\";\n `rm result.aln >/dev/\ +null 2>/dev/null`;\n }\n }\n &set_tempor\ +ary_dir (\"unset\",$mode, $method, \"result.aln\",\ +$outfile);\n myexit ($EXIT_SUCCESS);\n }\n\nsu\ +b seq2profile_pair\n {\n my ($mode, $profile1,\ + $profile2, $method, $param, $outfile)=@_;\n \n\ + \n if ($method eq \"clustalw\")\n {\n \ +&set_temporary_dir (\"set\",$profile1,\"prf1.aln\"\ +,$profile2,\"prf2.aln\");\n `clustalw -profile1=pr\ +f1.aln -profile2=prf2.aln -outfile=result.aln`;\n \ +&set_temporary_dir (\"unset\",$mode, $method, \"re\ +sult.aln\",$outfile);\n }\n elsif ( $metho\ +d eq \"hhalign\")\n {\n hhalign ( $profile1,$\ +profile2,$outfile,$param);\n }\n else\n \ + {\n \n `$method -profile1=prf1.aln -profile2=pr\ +f2.aln -outfile=result.aln $param>x 2>x`;\n }\ +\n \n myexit ($EXIT_SUCCESS);\n }\n\nsub pg_\ +is_installed\n {\n my @ml=@_;\n my ($r, $p,\ + $m);\n my $supported=0;\n \n my $p=shift\ + (@ml);\n if ($p=~/::/)\n {\n if (safe_sys\ +tem (\"perl -M$p -e 1\")==$EXIT_SUCCESS){return 1;\ +}\n else {return 0;}\n }\n else\n {\n\ + $r=`which $p 2>/dev/null`;\n if ($r eq \"\"){$r=0\ +;}\n else {$r=1;}\n \n if ($r==0 && is_blast_packa\ +ge ($p)){return pg_is_installed (\"legacy_blast.pl\ +\");}\n else {return $r;}\n }\n }\n\nsub is_\ +blast_package\n {\n my $p=shift;\n if ( $p=\ +~/blastp/){return 1;}\n elsif ($p=~/blastall/){\ +return 1;}\n elsif ($p=~/blastn/){return 1;}\n \ + elsif ($p=~/blastx/){return 1;}\n elsif ($p=\ +~/formatdb/){return 1;}\n else {return 0;}\n }\ +\n \nsub check_internet_connection\n {\n my\ + $internet;\n my $tmp;\n &check_configuratio\ +n ( \"wget\"); \n \n $tmp=&vtmpnam ();\n \ +\n if (&pg_is_installed (\"wget\")){`wge\ +t www.google.com -O$tmp >/dev/null 2>/dev/null`;}\\ +n elsif (&pg_is_installed (\"curl\")){`curl\ + www.google.com -o$tmp >/dev/null 2>/dev/null`;}\n\ + \n if ( !-e $tmp || -s $tmp < 10){$internet\ +=0;}\n else {$internet=1;}\n if (-e $tmp){un\ +link $tmp;}\n\n return $internet;\n }\nsub che\ +ck_pg_is_installed\n {\n my @ml=@_;\n my $r\ +=&pg_is_installed (@ml);\n if (!$r && $p=~/::/)\ +\n {\n print STDERR \"\\nYou Must Install the\ + perl package $p on your system.\\nRUN:\\n\\tsudo \ +perl -MCPAN -e 'install $pg'\\n\";\n }\n e\ +lsif (!$r)\n {\n myexit(flush_error(\"\\nProg\ +ram $p Supported but Not Installed on your system\\ +"));\n }\n else\n {\n return 1;\n \ + }\n }\nsub set_temporary_dir\n {\n my @list\ +=@_;\n my $dir_mode, $a, $mode, $method;\n \n \ + $dir_mode=shift (@list);\n\n \n if ( $dir\ +_mode eq \"set\")\n {\n $initial_dir=cwd();\n\ + if ( !$tmp_dir)\n {\n $rand=rand (100000);\\ +n $tmp_dir=\"$TMPDIR/tmp4tcoffee_profile_pair_\ +dir_$$\\_P_$rand\";\n }\n if ( !-d $tmp_dir)\n \ + {\n push (@TMPDIR_LIST, $tmp_dir);\n `mkd\ +ir $tmp_dir`;\n }\n \n for ( $a=0; $a<=$#list; $\ +a+=2)\n {\n if (-e $list[$a]){ `cp $list[$a\ +] $tmp_dir/$list[$a+1]`;}\n }\n chdir $tmp_d\ +ir;\n }\n elsif ( $dir_mode eq \"unset\")\\ +n {\n $mode=shift (@list);\n $method=shift (@\ +list);\n \n if (!-e $list[0])\n {\n myexit(fl\ +ush_error(\"Program $method failed to produce $lis\ +t[1]\" ));\n myexit ($EXIT_FAILURE);\n }\n e\ +lse\n {\n chdir $initial_dir;\n # `t_cof\ +fee -other_pg seq_reformat -in $tmp_dir/$list[0] -\ +output fasta_aln -out $tmp_dir/result2.aln`;\n \ + `cp $tmp_dir/$list[0] $tmp_dir/result2.aln`;\n \ + if ( $list[1] eq \"stdout\")\n {\n open (\ +F, \"$tmp_dir/result2.aln\");\n while (){print\ + $_;}close(F);\n }\n else\n {\n `\ +mv $tmp_dir/result2.aln $list[1]`;\n }\n \ + shift (@list); shift (@list);\n foreach $f (@\ +list)\n {\n if (-e (\"$tmp_dir/$f\")){`mv $\ +tmp_dir/$f .`;}\n }\n }\n }\n }\n\n\\ +n\n\nsub my_get_opt\n {\n my @list=@_;\n my\ + $cl, $a, $argv, @argl;\n \n @argl=();\n \ +$cl=shift @list;\n for ( $a=0; $a<=$#list; $a+=\ +3)\n {\n $option=$list[$a];\n $optional=$list\ +[$a+1];\n $status=$list[$a+2];\n $argv=\"\";\n if \ +($cl=~/$option(\\S+)/){$argv=$1;}\n @argl=(@argl,$\ +argv);\n \n \n #$optional:0=>optional\n #$optional\ +:1=>must be set\n #$status: 0=>no requirement\n #$\ +status: 1=>must be an existing file\n #$status: 2=\ +>must be an installed package\n \n\n if ($optional\ +==0){;}\n elsif ( $optional==1 && $argv eq \"\")\n\ + {\n myexit(flush_error( \"ERROR: Option $op\ +tion must be set\"));\n myexit ($EXIT_FAILURE)\ +;\n }\n if ($status==0){;}\n elsif ($status ==1 \ +&& $argv ne \"\" && !-e $argv)\n {\n myexit(\ +flush_error( \"File $argv must exist\"));\n my\ +exit ($EXIT_FAILURE);\n }\n elsif ( $status==2 &\ +& $argv ne \"\" && &check_pg_is_installed ($argv)=\ +=0)\n {\n myexit(flush_error( \" $argv is no\ +t installed\"));\n myexit ($EXIT_FAILURE);\n \ + }\n }\n\n return @argl;\n }\n\nsub che\ +ck_file \n {\n my ($file, $msg)=@_;\n\n if \ +( !-e $file)\n {\n myexit(flush_error(\"$msg\\ +"));\n }\n }\nsub hhalign\n {\n my ($a\ +ln1, $aln2, $outfile, $param)=@_;\n my $h1, $h2\ +;\n \n $h{0}{index}=0;\n $h{1}{index}=1;\\ +n \n $h{0}{aln}=$aln1;\n $h{1}{aln}=$aln2\ +;\n\n \n\n %{$h{0}}=aln2psi_profile (%{$h{0}}\ +);\n %{$h{1}}=aln2psi_profile (%{$h{1}});\n\n \ + $param=~s/#S/ /g;\n $param=~s/#M/\\-/g;\n \ +$param=~s/#E/\\=/g;\n \n\n \n $command=\"\ +hhalign -i $h{0}{a3m} -t $h{1}{a3m} -tc $outfile.t\ +mp -rank 1 -mapt 0 $param\";\n `$command`;\n \ + \n # `hhalign -i $h{0}{a3m} -t $h{1}{a3m} -tc $\ +outfile.tmp -rank 1 -mapt 0 -gapf 0.8 -gapg 0.8`;\\ +n \n\n # To run global use the following\n \ + \n open (I, \"$outfile.tmp\");\n open (O, \ +\">$outfile\");\n $h{0}{cons}=s/\\./x/g;\n $\ +h{1}{cons}=s/\\./x/g;\n\n print O \"! TC_LIB_FO\ +RMAT_01\\n2\\n$h{0}{name} $h{0}{len} $h{0}{seq}\\n\ +$h{1}{name} $h{1}{len} $h{1}{seq}\\n#1 2\\n\";\n \ + \n while ()\n {\n if (/(\\d+)\\s+(\\d\ ++)\\s+(\\d+)/)\n {\n print O \"\\t$h{0}{$1}\\ +\t$h{1}{$2}\\t$3\\n\";\n }\n }\n print O\ + \"! SEQ_1_TO_N\\n\";\n\n close (O);\n close\ + (I);\n }\n\nsub aln2psi_profile\n {\n my (%h\ +)=@_;\n my ($aln,$i,$hv, $a, @c, $n);\n \n \ + $i=$h{index};\n $aln=$h{aln};\n\n `cp $aln \ +$$.hhh_aln`;\n $command=\"t_coffee -other_pg se\ +q_reformat -in $aln -output hasch\";\n $hv=`$co\ +mmand`;chomp ($hv);\n \n $h{a2m}=\"$tmp/$hv.\ +tmp4hhpred.a2m\";\n $h{a3m}=\"$tmp/$hv.tmp4hhpr\ +ed.a3m\";\n if ( -e $h{a3m}){;}\n else\n \ + {\n `hhconsensus -M 50 -i $h{aln} -oa2m $h{a2m}\ +`;\n if (!-e $h{a2m})\n {\n print STDERR \"P\ +rogram tc_generic_method.pl FAILED to run:\\n\\thh\ +consensus -M 50 -i $h{aln} -oa2m $h{a2m}\";\n \ + myexit ($EXIT_FAILURE);\n }\n \n `hhconsensus \ +-M 50 -i $h{aln} -oa3m $h{a3m}`;\n if (!-e $h{a3m}\ +)\n {\n print STDERR \"Program tc_generic_me\ +thod.pl FAILED to run:\\n\\thhconsensus -M 50 -i \ +$h{aln} -oa3m $h{a3m}\";\n myexit ($EXIT_FAILU\ +RE);\n }\n `buildali.pl $h{a3m} -n 1`;\n \ + }\n \n \n $h{a2m_seq}=`head -n 2 $h{a\ +2m} | grep -v \">\"`;chomp ($h{a2m_seq});\n $h{\ +a3m_seq}=`head -n 2 $h{a3m} | grep -v \">\"`;chomp\ + ($h{a3m_seq});\n $h{cons}=$h{a2m_seq};\n $h\ +{seq}=`head -n 2 $h{aln} | grep -v \">\"`;chomp ($\ +h{seq});\n \n \n\n @c=split (//, $h{cons}\ +);\n $h{len}=$#c+1;\n for ($n=0,$a=0, $b=0; \ +$a<$h{len};$a++)\n {\n if ( $c[$a]=~/[A-Z]/)\\ +n {\n $h{++$n}=++$b;\n\n }\n elsif ( $c[$a\ +]=~/[a-z\\.]/)\n {\n ++$b;\n }\n }\n \ + \n $name=`head -n 2 $h{aln} | grep \">\"`;\n\ + $name=~/\\>(\\S+)/;\n $h{name}=$1;\n \n \ + `cp $h{a2m} $i.a2m`;\n `cp $h{a3m} $i.a3m`;\\ +n `cp $h{aln} $i.hh_aln`;\n \n return %h;\ +\n }\n\nsub read_fasta_seq \n {\n my $f=@_[0]\ +;\n my %hseq;\n my (@seq, @com, @name);\n \ + my ($a, $s,$nseq);\n\n open (F, $f);\n whil\ +e ()\n {\n $s.=$_;\n }\n close (F)\ +;\n\n \n @name=($s=~/>(\\S*).*\\n[^>]*/g);\n\ + \n @seq =($s=~/>.*.*\\n([^>]*)/g);\n @co\ +m =($s=~/>\\S*(.*)\\n([^>]*)/g);\n\n \n $nse\ +q=$#name+1;\n \n for ($a=0; $a<$nseq; $a++)\\ +n {\n my $s;\n my $n=$name[$a];\n $hseq{$n}{n\ +ame}=$n;\n $seq[$a]=~s/[^A-Za-z]//g;\n $hseq{$n}{o\ +rder}=$a;\n $hseq{$n}{seq}=$seq[$a];\n $hseq{$n}{c\ +om}=$com[$a];\n \n }\n return %hseq;\n }\\ +n\nsub file_contains \n {\n my ($file, $tag, $\ +max)=(@_);\n my ($n);\n $n=0;\n \n if \ +( !-e $file && ($file =~/$tag/)) {return 1;}\n \ +elsif ( !-e $file){return 0;}\n else \n {\\ +n open (FC, \"$file\");\n while ( )\n {\n \ + if ( ($_=~/$tag/))\n {\n close (FC);\n r\ +eturn 1;\n }\n elsif ($max && $n>$max)\n\ + {\n close (FC);\n return 0;\n }\n \ + $n++;\n }\n }\n close (FC);\n retu\ +rn 0;\n }\n \n \nsub file2string\n {\n \ +my $f=@_[0];\n my $string, $l;\n open (F,\"$\ +f\");\n while ()\n {\n\n $l=$_;\n #chom\ +p ($l);\n $string.=$l;\n }\n close (F);\n \ + $string=~s/\\r\\n//g;\n $string=~s/\\n//g;\n\ + return $string;\n }\n\n\nsub my_get_opt\n {\\ +n my @list=@_;\n my $cl, $a, $argv, @argl;\n\ + \n @argl=();\n $cl=shift @list;\n for\ + ( $a=0; $a<=$#list; $a+=3)\n {\n $option=$li\ +st[$a];\n $optional=$list[$a+1];\n $status=$list[$\ +a+2];\n $argv=\"\";\n if ($cl=~/$option(\\S+)/){$a\ +rgv=$1;}\n @argl=(@argl,$argv);\n \n \n #$optional\ +:0=>optional\n #$optional:1=>must be set\n #$statu\ +s: 0=>no requirement\n #$status: 1=>must be an exi\ +sting file\n #$status: 2=>must be an installed pac\ +kage\n \n\n if ($optional==0){;}\n elsif ( $option\ +al==1 && $argv eq \"\")\n {\n\n myexit(flush\ +_error(\"Option $option must be set\"));\n \n \ + }\n if ($status==0){;}\n elsif ($status ==1 && $a\ +rgv ne \"\" && !-e $argv)\n {\n myexit(flus\ +h_error(\"File $argv must exist\"));\n \n }\n\ + elsif ( $status==2 && $argv ne \"\" && &check_pg_\ +is_installed ($argv)==0)\n {\n myexit(flush_\ +error(\"$argv is not installed\"));\n \n }\n \ + }\n\n return @argl;\n }\n\nsub tag2valu\ +e \n {\n \n my $tag=(@_[0]);\n my $word=\ +(@_[1]);\n my $return;\n \n $tag=~/$word=\ +\"([^\"]+)\"/;\n $return=$1;\n return $retur\ +n;\n }\n \nsub hit_tag2pdbid\n {\n my $t\ +ag=(@_[0]);\n my $pdbid;\n \n $tag=~/i\ +d=\"(\\S+)\"/;\n $pdbid=$1;\n $pdbid=~s/_//;\ +\n return $pdbid;\n }\nsub id2pdbid\n {\n \ +my $in=@_[0];\n my $id;\n \n $in=~/(\\S+)\ +/;\n $id=$in;\n $id=~s/PDB/pdb/g;\n \n \ + if ($id =~/pdb(.*)/){$id=$1;}\n elsif ( $id=~/\ +(\\S+)\\s+mol:protein/){$id=$1;}\n $id=~s/[:|ï¿\ +½ï¿½_]//g;\n return $id;\n }\nsub set_blast_ty\ +pe \n {\n my $file =@_[0];\n if (&file_cont\ +ains ($file,\"EBIApplicationResult\",100)){$BLAST_\ +TYPE=\"EBI\";}\n elsif (&file_contains ($file,\\ +"NCBI_BlastOutput\",100)) {$BLAST_TYPE=\"NCBI\";}\\ +n else\n {\n $BLAST_TYPE=\"\";\n }\n \ + return $BLAST_TYPE;\n }\nsub is_valid_blast_xm\ +l\n {\n my $file=shift;\n my $line;\n\ + \n \n if ( !-e $file) {return 0;}\\ +n $line=&file2tail ($file,100);\n if ( $\ +line=~/<\\/EBIApplicationResult/ || $line=~/<\\/NC\ +BI_BlastOutput/ || $line=~/<\\/BlastOutput/ ){retu\ +rn 1;}\n return 0;\n }\nsub file2blast_fla\ +vor\n {\n my $file=shift;\n if (&file_contain\ +s ($file,\"EBIApplicationResult\",100)){return \"E\ +BI\";}\n elsif (&file_contains ($file,\"NCBI_Blast\ +Output\",100)){return \"NCBI\";}\n else {return \"\ +UNKNOWN\";}\n }\nsub blast_xml2profile \n {\\ +n my ($name,$seq,$maxid, $minid, $mincov, $file\ +)=(@_);\n my (%p, $a, $string, $n);\n \n \ +\n\n if ($BLAST_TYPE eq \"EBI\" || &file_contai\ +ns ($file,\"EBIApplicationResult\",100)){%p=ebi_bl\ +ast_xml2profile(@_);}\n elsif ($BLAST_TYPE eq \\ +"NCBI\" || &file_contains ($file,\"NCBI_BlastOutpu\ +t\",100)){%p=ncbi_blast_xml2profile(@_);}\n els\ +e \n {\n myexit(add_error ( $$,$$,getppid(), \ +\"BLAST_FAILURE::unkown XML\",$CL));\n }\n \ + for ($a=0; $a<$p{n}; $a++)\n {\n my $name=$p\ +{$a}{name};\n $p{$name}{seq}=$p{$a}{seq};\n $p{$na\ +me}{index}=$a;\n }\n return %p;\n }\nsub \ +ncbi_tblastx_xml2lib_file \n {\n my ($outlib,\ +$string)=(@_);\n my ($L,$l, $a,$b,$c,$d,$i,$nhi\ +ts,@identifyerL);\n my (%ITERATION);\n \n \ + open (F, \">>$outlib\");\n \n $seq=~s/[^a\ +-zA-Z]//g;\n $L=length ($seq);\n \n %ITER\ +ATION=xml2tag_list ($string, \"Iteration\");\n \ +for ($i=0; $i<$ITERATION{n};$i++)\n {\n my ($\ +qindex, $qlen, %hit, $string);\n $string=$ITERATIO\ +N{$i}{body};\n\n $qindex=xmltag2value($string,\"It\ +eration_iter-num\");\n $qlen =xmltag2value($strin\ +g,\"Iteration_query-len\");\n %hit=&xml2tag_list \ +($string, \"Hit\");\n\n for ($a=0; $a<$hit{n}; $a+\ ++)\n {\n my ($string);\n $string=$hit{$a\ +}{body};\n \n $hindex=xmltag2value($string,\"\ +Hit_accession\")+1;\n if ($hindex<=$qindex){ne\ +xt;}\n else {print F \"# $qindex $hindex\\n\\ +";}\n \n \n $hlen=xmltag2value ($strin\ +g,\"Hit_len\");\n %HSP=&xml2tag_list ($string\ +, \"Hsp\");\n \n for ($b=0; $b<$HSP{n}; $b+\ ++)\n {\n my ($string, $qs,$qe,$qf,$hs,$he,$\ +hf,$s, $d, $e);\n $string=$HSP{$b}{body};\n \n $\ +qs=xmltag2value ($string,\"Hsp_query-from\");\n \ +$qe=xmltag2value ($string,\"Hsp_query-to\");\n $\ +qf=xmltag2value ($string,\"Hsp_query-frame\");\n\\ +n $hs=xmltag2value ($string,\"Hsp_hit-from\");\n\ + $he=xmltag2value ($string,\"Hsp_hit-to\");\n $\ +hf=xmltag2value ($string,\"Hsp_hit-frame\");\n \\ +n $s=xmltag2value ($string,\"Hsp_identity\");\n \ + $l=xmltag2value ($string,\"Hsp_align-len\");\n \ +$s=int(($s*100)/$l);\n \n if ($qf>0)\n {$rqs=\ +$qs; $rqe=$qe;}\n else\n {\n $rqe=($qlen-\ +$qs)+1;\n $rqs=($qlen-$qe)+1;\n }\n \n i\ +f ($hf>0)\n {$rhs=$hs; $rhe=$he;}\n else\n \ +{\n $rhe=($hlen-$hs)+1;\n $rhs=($hlen-$h\ +e)+1;\n }\n for ($d=0,$e=$rqs; $e<$rqe; $e++,$\ +d++)\n {\n my ($r1,$r2);\n $r1=$e;\n \ + $r2=$rhs+$d;\n print F \" $r1 $r2 $s 0\\\ +n\";\n }\n }\n }\n }\n print F \ +\"! SEQ_1_TO_N\\n\";\n \n close (F);\n re\ +turn %lib;\n }\n\nsub ncbi_tblastpx_xml2lib_file \ +\n {\n my ($outlib,$string,%s)=(@_);\n my \ +($L,$l, $a,$b,$c,$d,$i,$nhits,@identifyerL);\n \ +my (%ITERATION,%hdes, %qdes);\n \n open (F\ +, \">>$outlib\");\n \n $seq=~s/[^a-zA-Z]//g;\ +\n $L=length ($seq);\n \n %ITERATION=xml2\ +tag_list ($string, \"Iteration\");\n for ($i=0;\ + $i<$ITERATION{n};$i++)\n {\n my ($qindex, $q\ +len, %hit, $string);\n $string=$ITERATION{$i}{body\ +};\n\n $qdef=xmltag2value($string,\"Iteration_quer\ +y-def\");\n %qdes=&tblastpx_name2description($qdef\ +,%s);\n $qlen =xmltag2value($string,\"Iteration_q\ +uery-len\");\n %hit=&xml2tag_list ($string, \"Hit\ +\");\n\n for ($a=0; $a<$hit{n}; $a++)\n {\n \ +my ($string);\n $string=$hit{$a}{body};\n \ +$hdef=xmltag2value($string,\"Hit_def\");\n %hd\ +es=&tblastpx_name2description($hdef,%s);\n if \ +($hdes{index}<=$qdes{index}){next;}\n else {p\ +rint F \"# $qdes{index} $hdes{index}\\n\";}\n \ + \n \n $hlen=xmltag2value ($string,\"Hit_l\ +en\");\n %HSP=&xml2tag_list ($string, \"Hsp\"\ +);\n \n for ($b=0; $b<$HSP{n}; $b++)\n \ + {\n my ($string, $l,$qs,$qe,$qf,$hs,$he,$hf,$s,\ + $d, $e, @s1, @s2);\n $string=$HSP{$b}{body};\n \\ +n $qs=xmltag2value ($string,\"Hsp_query-from\");\ +\n $qe=xmltag2value ($string,\"Hsp_query-to\");\\ +n $qf=$qdes{frame};\n $qseq=xmltag2value ($stri\ +ng,\"Hsp_qseq\");\n \n $hs=xmltag2value ($strin\ +g,\"Hsp_hit-from\");\n $he=xmltag2value ($string\ +,\"Hsp_hit-to\");\n $hf=$hdes{frame};\n $hseq=xm\ +ltag2value ($string,\"Hsp_hseq\");\n \n $s=xmlt\ +ag2value ($string,\"Hsp_identity\");\n $l=xmltag\ +2value ($string,\"Hsp_align-len\");\n $s=int(($s\ +*100)/$l);\n @s1=tblastpx_hsp2coordinates($qseq,$\ +qs,$qe,%qdes);\n @s2=tblastpx_hsp2coordinates($hs\ +eq,$hs,$he,%hdes);\n \n \n for ($f=0; $f<=$#s1;\ + $f++)\n {\n if ($s1[$f]==-1 || $s2[$f]==-\ +1){next;}\n else \n {\n print F \" $\ +s1[$f] $s2[$f] $s 0\\n\";\n }\n }\n \ + }\n }\n }\n print F \"! SEQ_1_TO_N\\n\\ +";\n \n close (F);\n return %lib;\n }\ns\ +ub tblastpx_hsp2coordinates\n {\n my ($seq, $s\ +, $e, %des)=@_;\n my @list;\n my @sa;\n m\ +y @gap=(-1,-1,-1);\n \n $s=$des{start}+3*($s\ +-1);\n \n if ($des{strand} eq \"d\"){;}\n e\ +lse {$s=($des{length}-$s)+1;}\n \n foreach $\ +c (split (//,$seq))\n {\n if ( $c eq '-'){pus\ +h (@list,@gap);}\n elsif ($des{strand} eq \"d\")\n\ + {\n push(@list,$s++,$s++,$s++);\n }\n els\ +e\n {\n push(@list, $s--,$s--,$s--);\n }\n\ + }\n return @list;\n }\n\nsub tblastpx_na\ +me2description\n {\n my ($name, %s)=@_;\n m\ +y @at=split(\"__\", $name);\n my %des;\n\n $\ +des{name}=$at[0];\n $des{strand}=$at[1];\n \\ +n $des{start}=$at[2];\n $des{end}=$at[3];\n \ + $des{length}=$at[4];\n $des{index}=$s{$at[0]\ +}{order}+1;\n return %des;\n } \nsub ncbi_bla\ +st_xml2profile \n {\n my ($name,$seq,$maxid, $\ +minid, $mincov, $string)=(@_);\n my ($L,$l, $a,\ +$b,$c,$d,$nhits,@identifyerL);\n \n \n $s\ +eq=~s/[^a-zA-Z]//g;\n $L=length ($seq);\n \n \ + #This is causing the NCBI parser to fail when I\ +teration_query-def is missing \n #%query=&xml2t\ +ag_list ($string, \"Iteration_query-def\");\n #\ +$name=$query{0}{body};\n \n %hit=&xml2tag_li\ +st ($string, \"Hit\");\n \n \n for ($nhit\ +s=0,$a=0; $a<$hit{n}; $a++)\n {\n my ($ldb,$i\ +d, $identity, $expectation, $start, $end, $coverag\ +e, $r);\n my (%ID,%DE,%HSP);\n \n $ldb=\"\";\n\n %\ +ID=&xml2tag_list ($hit{$a}{body}, \"Hit_id\");\n $\ +identifyer=$ID{0}{body};\n \n %DE=&xml2tag_list ($\ +hit{$a}{body}, \"Hit_def\");\n $definition=$DE{0}{\ +body};\n \n %HSP=&xml2tag_list ($hit{$a}{body}, \"\ +Hsp\");\n for ($b=0; $b<$HSP{n}; $b++)\n {\n \ + my (%START,%END,%E,%I,%Q,%M);\n\n \n %START=\ +&xml2tag_list ($HSP{$b}{body}, \"Hsp_query-from\")\ +;\n %HSTART=&xml2tag_list ($HSP{$b}{body}, \"H\ +sp_hit-from\");\n \n %LEN= &xml2tag_list \ +($HSP{$b}{body}, \"Hsp_align-len\");\n %END= \ +&xml2tag_list ($HSP{$b}{body}, \"Hsp_query-to\");\\ +n %HEND= &xml2tag_list ($HSP{$b}{body}, \"Hsp\ +_hit-to\");\n %E=&xml2tag_list ($HSP{$b}{b\ +ody}, \"Hsp_evalue\");\n %I=&xml2tag_list \ +($HSP{$b}{body}, \"Hsp_identity\");\n %Q=&xml2\ +tag_list ($HSP{$b}{body}, \"Hsp_qseq\");\n \ + %M=&xml2tag_list ($HSP{$b}{body}, \"Hsp_hseq\\ +");\n \n for ($e=0; $e<$Q{n}; $e++)\n\n \ + {\n $qs=$Q{$e}{body};\n $ms=$M{$e}{body};\n \ + \n $expectation=$E{$e}{body};\n $identity=($LEN\ +{$e}{body}==0)?0:$I{$e}{body}/$LEN{$e}{body}*100;\\ +n $start=$START{$e}{body};\n $end=$END{$e}{body}\ +;\n $Hstart=$HSTART{$e}{body};\n $Hend=$HEND{$e}\ +{body};\n \n $coverage=($L)?(($end-$start)*100)/$\ +L:0;\n \n if ($identity>$maxid || $identity<$mini\ +d || $coverage<$mincov){next;}\n @lr1=(split (//,\ +$qs));\n @lr2=(split (//,$ms));\n $l=$#lr1+1;\n \ + for ($c=0;$c<$L;$c++){$p[$nhits][$c]=\"-\";}\n f\ +or ($d=0,$c=0; $c<$l; $c++)\n {\n $r=$lr1[\ +$c];\n if ( $r=~/[A-Za-z]/)\n {\n \n\ + $p[$nhits][$d + $start-1]=$lr2[$c];\n $d++;\n\ + }\n }\n $Qseq[$nhits]=$qs;\n $Hseq[$n\ +hits]=$ms;\n $QstartL[$nhits]=$start;\n $HstartL\ +[$nhits]=$Hstart;\n $identityL[$nhits]=$identity;\ +\n $endL[$nhits]=$end;\n $definitionL[$nhits]=$d\ +efinition;\n $identifyerL[$nhits]=$identifyer;\n \ + $comment[$nhits]=\"$ldb|$identifyer [Eval=$expect\ +ation][id=$identity%][start=$Hstart end=$Hend]\";\\ +n $nhits++;\n }\n }\n }\n \n \\ +n $profile{n}=0;\n $profile{$profile{n}}{nam\ +e}=$name;\n $profile{$profile{n}}{seq}=$seq;\n \ + $profile {n}++;\n \n for ($a=0; $a<$nhits\ +; $a++)\n {\n $n=$a+1;\n \n $profile{$n}{name\ +}=\"$name\\_$a\";\n $profile{$n}{seq}=\"\";\n $pro\ +file{$n}{Qseq}=$Qseq[$a];\n $profile{$n}{Hseq}=$Hs\ +eq[$a];\n $profile{$n}{Qstart}=$QstartL[$a];\n $pr\ +ofile{$n}{Hstart}=$HstartL[$a];\n $profile{$n}{ide\ +ntity}=$identityL[$a];\n $profile{$n}{definition}=\ +$definitionL[$a];\n $profile{$n}{identifyer}=$iden\ +tifyerL[$a];\n $profile{$n}{comment}=$comment[$a];\ +\n\n for ($b=0; $b<$L; $b++)\n {\n if ($p[$a\ +][$b])\n {\n $profile{$n}{seq}.=$p[$a][$b];\ +\n }\n else\n {\n $profile{$n}{se\ +q}.=\"-\";\n }\n }\n }\n \n $pr\ +ofile{n}=$nhits+1;\n return %profile;\n }\nsub\ + ebi_blast_xml2profile \n {\n my ($name,$seq,$\ +maxid, $minid, $mincov, $string)=(@_);\n my ($L\ +,$l, $a,$b,$c,$d,$nhits,@identifyerL,$identifyer);\ +\n \n\n \n $seq=~s/[^a-zA-Z]//g;\n $L=\ +length ($seq);\n %hit=&xml2tag_list ($string, \\ +"hit\");\n \n for ($nhits=0,$a=0; $a<$hit{n}\ +; $a++)\n {\n my ($ldb,$id, $identity, $expec\ +tation, $start, $end, $coverage, $r);\n my (%Q,%M,\ +%E,%I);\n \n $ldb=&tag2value ($hit{$a}{open}, \"da\ +tabase\");\n $identifyer=&tag2value ($hit{$a}{open\ +}, \"id\");\n\n $description=&tag2value ($hit{$a}{\ +open}, \"description\");\n \n %Q=&xml2tag_list ($h\ +it{$a}{body}, \"querySeq\");\n %M=&xml2tag_list ($\ +hit{$a}{body}, \"matchSeq\");\n %E=&xml2tag_list (\ +$hit{$a}{body}, \"expectation\");\n %I=&xml2tag_li\ +st ($hit{$a}{body}, \"identity\");\n \n\n for ($b=\ +0; $b<$Q{n}; $b++)\n {\n\n $qs=$Q{$b}{body};\ +\n $ms=$M{$b}{body};\n \n $expectation\ +=$E{$b}{body};\n $identity=$I{$b}{body};\n \ + \n \n $start=&tag2value ($Q{$b}{open\ +}, \"start\");\n $end=&tag2value ($Q{$b}{open}\ +, \"end\");\n $startM=&tag2value ($M{$b}{open}\ +, \"start\");\n $endM=&tag2value ($M{$b}{open}\ +, \"end\");\n $coverage=(($end-$start)*100)/$L\ +;\n \n # print \"$id: ID: $identity COV: $c\ +overage [$start $end]\\n\";\n \n if ($iden\ +tity>$maxid || $identity<$minid || $coverage<$minc\ +ov){next;}\n # print \"KEEP\\n\";\n\n \n \ + @lr1=(split (//,$qs));\n @lr2=(split (//,$m\ +s));\n $l=$#lr1+1;\n for ($c=0;$c<$L;$c++)\ +{$p[$nhits][$c]=\"-\";}\n for ($d=0,$c=0; $c<$\ +l; $c++)\n {\n $r=$lr1[$c];\n if ( $r=~/[A\ +-Za-z]/)\n {\n \n $p[$nhits][$d + $st\ +art-1]=$lr2[$c];\n $d++;\n }\n }\n \ + \n $Qseq[$nhits]=$qs;\n $Hseq[$nhits]=$ms\ +;\n $QstartL[$nhits]=$start;\n $HstartL[$n\ +hits]=$Hstart;\n $identityL[$nhits]=$identity;\ +\n $endL[$nhits]=$end;\n $definitionL[$nhi\ +ts]=$definition;\n $identifyerL[$nhits]=$ident\ +ifyer;\n $comment[$nhits]=\"$ldb|$identifyer [\ +Eval=$expectation][id=$identity%][start=$startM en\ +d=$endM]\";\n $nhits++;\n }\n }\n \n\ + $profile{n}=0;\n $profile{$profile{n}}{name\ +}=$name;\n $profile{$profile{n}}{seq}=$seq;\n \ + $profile {n}++;\n \n for ($a=0; $a<$nhits;\ + $a++)\n {\n $n=$a+1;\n $profile{$n}{name}=\"\ +$name\\_$a\";\n $profile{$n}{seq}=\"\";\n $profile\ +{$n}{Qseq}=$Qseq[$a];\n $profile{$n}{Hseq}=$Hseq[$\ +a];\n $profile{$n}{Qstart}=$QstartL[$a];\n $profil\ +e{$n}{Hstart}=$HstartL[$a];\n $profile{$n}{identit\ +y}=$identityL[$a];\n $profile{$n}{definition}=$def\ +initionL[$a]; \n $profile{$n}{identifyer}=$identif\ +yerL[$a];\n $profile{$n}{comment}=$comment[$a];\n\\ +n for ($b=0; $b<$L; $b++)\n {\n if ($p[$a][$\ +b])\n {\n $profile{$n}{seq}.=$p[$a][$b];\n \ + }\n else\n {\n $profile{$n}{seq}.\ +=\"-\";\n }\n }\n }\n $profile{n}=\ +$nhits+1;\n \n return %profile;\n }\nsub ou\ +tput_profile\n {\n my ($outfile,$profileR, $tr\ +im)=(@_);\n my ($a);\n my %profile=%$profile\ +R;\n my $P= new FileHandle;\n my $tmp=vtmpna\ +m();\n \n open ($P, \">$tmp\");\n for ($a\ +=0; $a<$profile{n}; $a++)\n {\n print $P \">$\ +profile{$a}{name} $profile{$a}{comment}\\n$profile\ +{$a}{seq}\\n\";\n }\n close ($P);\n\n i\ +f ( $trim)\n {\n &safe_system (\"t_coffee -ot\ +her_pg seq_reformat -in $tmp -action +trim _aln_%%\ +$trim\\_K1 -output fasta_aln -out $outfile\");\n \ + }\n else\n {\n &safe_system (\"mv $tmp\ + $outfile\");\n }\n return;\n }\nsub blas\ +t_xml2hit_list\n {\n my $string=(@_[0]);\n \ +return &xml2tag_list ($string, \"hit\");\n }\nsub\ + xmltag2value\n {\n my ($string_in, $tag)=@_;\\ +n my %TAG;\n %TAG=xml2tag_list ($string_in, \ +$tag);\n return $TAG{0}{body};\n }\n \nsu\ +b xml2tag_list \n {\n my ($string_in,$tag)=@_\ +;\n my $tag_in, $tag_out;\n my %tag;\n \n\ + if (-e $string_in)\n {\n $string=&file2st\ +ring ($string_in);\n }\n else\n {\n $\ +string=$string_in;\n }\n $tag_in1=\"<$tag \ +\";\n $tag_in2=\"<$tag>\";\n $tag_out=\"/$ta\ +g>\";\n $string=~s/>/>##1/g;\n $string=~s//g;\n @l=($string=~/(\\<[^>]+\\>)/g);\n \ + $tag{n}=0;\n $in=0;$n=-1;\n \n \n\n forea\ +ch $t (@l)\n {\n\n $t=~s/<#//;\n $t=~s/#>//;\\ +n \n if ( $t=~/$tag_in1/ || $t=~/$tag_in2/)\n {\\ +n \n $in=1;\n $tag{$tag{n}}{open}=$t;\n \ + $n++;\n \n }\n elsif ($t=~/$tag_out/)\n \ + {\n \n\n $tag{$tag{n}}{close}=$t;\n $\ +tag{n}++;\n $in=0;\n }\n elsif ($in)\n {\n\ + \n $tag{$tag{n}}{body}.=$t;\n }\n }\ +\n \n return %tag;\n }\n\n\nsub seq2gor_predi\ +ction \n {\n my ($name, $seq,$infile, $outfile\ +, $gor_seq, $gor_obs)=(@_);\n my ($l);\n \n \ + `gorIV -prd $infile -seq $gor_seq -obs $gor_obs\ + > gor_tmp`;\n open (GR, \">$outfile\");\n o\ +pen (OG, \"gor_tmp\");\n\n while ()\n \ +{\n \n $l=$_;\n if ($l=~/\\>/){print GR \"$l\";}\n\ + elsif ( $l=~/Predicted Sec. Struct./)\n {\n \ + $l=~s/Predicted Sec. Struct\\.//;\n print GR \ +\"$l\";\n }\n }\n close (GR);\n close\ + (OG);\n return;\n }\nsub seq2msa_tm_predictio\ +n \n {\n my ($name, $seq, $db, $infile, $outfi\ +le, $arch, $psv)=(@_);\n my (%p,%gseq,%R, $blas\ +t_output, %s, $l);\n my $R2=new FileHandle;\n \ + my $db=\"uniprot\";\n my $method=\"psitm\";\n\ + my $SERVER=\"EBI\";\n \n $blast_output=&\ +run_blast ($name,\"blastp\", $db, $infile, \"outfi\ +le\");\n \n if (&cache_file(\"GET\",$infile,\ +$name,$method,$db,$outfile,$SERVER))\n {\n pr\ +int \"\\tPSITM: USE Cache\\n\";\n return $outfile;\ +\n }\n else\n {\n $CACHE_STATUS=\"COM\ +PUTE CACHE\";\n %p=blast_xml2profile($name,$seq,$m\ +axid, $minid,$mincov,$blast_output);\n \n \n open \ +(F, \">tm_input\");\n for (my $a=0; $a<$p{n}; $a++\ +)\n {\n my $s;\n \n $s=$p{$a}{seq};\\ +n $s=uc($s);\n print F \">$p{$a}{name}\\n$\ +s\\n\";\n #print stdout \">$p{$a}{name}\\n$s\\\ +n\";\n }\n close (F);\n print \"\\tPSITM: kept \ +$p{n} Homologues for Sequence $p{0}{name}\\n\";\n \ +&safe_system (\"t_coffee -other_pg fasta_seq2hmmto\ +p_fasta.pl -in=tm_input -out=$outfile -output=cons\ + -cov=70 -trim=95 -arch=$arch -psv=$psv\");\n unli\ +nk (\"tm_input\");\n &cache_file(\"SET\",$infile,$\ +name,$method,$db,$outfile,$SERVER);\n return;\n \ + }\n }\n\n\nsub seq2msa_gor_prediction \n {\n \ + my ($name, $seq,$infile, $outfile, $gor_seq, $g\ +or_obs)=(@_);\n my (%p,%gseq,%R, $blast_output,\ + %s, $l);\n my $R2=new FileHandle;\n my $db=\ +\"uniprot\";\n my $method=\"psigor\";\n my $\ +SERVER=\"EBI\";\n \n $blast_output=&run_blas\ +t ($name,\"blastp\", \"uniprot\", $infile, \"outfi\ +le\");\n \n if (&cache_file(\"GET\",$infile,\ +$name,$method,$db,$outfile,$SERVER))\n {\n pr\ +int \"\\tPSIGOR: USE Cache\\n\";\n return $outfile\ +;\n }\n else\n {\n $CACHE_STATUS=\"CO\ +MPUTE CACHE\";\n %p=blast_xml2profile($name,$seq,$\ +maxid, $minid,$mincov,$blast_output);\n \n \n open\ + (F, \">gor_input\");\n for (my $a=0; $a<$p{n}; $a\ +++)\n {\n my $s;\n \n $s=$p{$a}{seq}\ +;\n $s=uc($s);\n print F \">$p{$a}{name}\\\ +n$s\\n\";\n #print stdout \">$p{$a}{name}\\n$s\ +\\n\";\n }\n close (F);\n print \"\\tGORTM: kept\ + $p{n} Homologues for Sequence $p{0}{name}\\n\";\\ +n &safe_system (\"t_coffee -other_pg fasta_seq2hmm\ +top_fasta.pl -in=gor_input -out=$outfile -output=c\ +ons -cov=70 -trim=95 -gor_seq=$gor_seq -gor_obs=$g\ +or_obs -mode=gor\");\n unlink (\"tm_input\");\n &c\ +ache_file(\"SET\",$infile,$name,$method,$db,$outfi\ +le,$SERVER);\n return;\n }\n }\n\n\n\nsub ru\ +n_blast\n {\n my ($name, $method, $db, $infile\ +, $outfile, $run)=(@_);\n if (!$run){$run=1;}\n\ + \n \n if (&cache_file(\"GET\",$infile,$n\ +ame,$method,$db,$outfile,$SERVER) && is_valid_blas\ +t_xml ($outfile))\n {return $outfile;}\n e\ +lse\n {\n $CACHE_STATUS=\"COMPUTE CACHE\";\n \ +if ( $SERVER eq \"EBI_SOAP\")\n {\n &check_c\ +onfiguration (\"EMAIL\",\"SOAP::Light\",\"INTERNET\ +\");\n \n $cl_method=$method;\n if ($c\ +l_method =~/wu/)\n {\n $cl_method=~s/wu//;\\ +n if ( $cl_method eq \"psiblast\")\n {\n \ +add_warning($$,$$,\"PSI BLAST cannot be used with \ +the wuBLAST Client. Use server=EBI Or server=LOCAL\ +. blastp will be used instead\");\n $cl_metho\ +d=\"blastp\";\n }\n \n $command=\"t_coffee -o\ +ther_pg wublast.pl --email $EMAIL $infile -D $db -\ +p $cl_method --outfile $outfile -o xml>/dev/null 2\ +>/dev/null\";\n &safe_system ( $command);\n if (\ +-e \"$outfile.xml\") {`mv $outfile.xml $outfile`;}\ +\n }\n else\n {\n if ($cl_method \ +eq \"psiblast\"){$cl_method =\"blastp -j5\";}\n \\ +n $command=\"t_coffee -other_pg blastpgp.pl --ema\ +il $EMAIL $infile -d $db --outfile $outfile -p $cl\ +_method --mode PSI-Blast>/dev/null 2>/dev/null\";\\ +n &safe_system ( $command);\n \n if (-e \"$outf\ +ile.xml\") {`mv $outfile.xml $outfile`;}\n }\ +\n }\n elsif ($SERVER eq \"EBI_REST\" || $SERVER\ + eq \"EBI\")\n {\n \n $cl_method=$method;\ +\n &check_configuration(\"EMAIL\",\"XML::Simpl\ +e\", \"INTERNET\");\n if ($db eq \"uniprot\"){\ +$db1=\"uniprotkb\";}\n else {$db1=$db;}\n \ +\n\n if ($cl_method =~/wu/)\n {\n $cl_m\ +ethod=~s/wu//;\n if ( $cl_method eq \"psiblast\")\ +{$cl_method=\"blastp\";}\n \n $command=\"t_coffe\ +e -other_pg wublast_lwp.pl --email $EMAIL -D $db1 \ +-p $cl_method --outfile $outfile --align 7 --stype\ + protein $infile>/dev/null 2>/dev/null\";\n \n \ + }\n else\n {\n if ( $cl_method =~/p\ +siblast/){$cl_method =\"blastp -j5\";}\n $command\ +=\"t_coffee -other_pg ncbiblast_lwp.pl --email $EM\ +AIL -D $db1 -p $cl_method --outfile $outfile --ali\ +gn 7 --stype protein $infile>/dev/null 2>/dev/null\ +\";\n }\n &safe_system ( $command,5);\n \ + if (-e \"$outfile.out.xml\") {`mv $outfile.out\ +.xml $outfile`;}\n elsif (-e \"$outfile.xml.xm\ +l\"){`mv $outfile.xml.xml $outfile`;}\n elsif \ +(-e \"$outfile.out..xml\") {`mv $outfile.out..xml \ +$outfile`;}\n elsif (-e \"$outfile.xml..xml\")\ +{`mv $outfile.xml..xml $outfile`;}\n }\n elsif (\ +$SERVER eq \"NCBI\")\n {\n &check_configurat\ +ion (\"blastcl3\",\"INTERNET\");\n if ($db eq \ +\"uniprot\"){$cl_db=\"nr\";}\n else {$cl_db=$d\ +b;}\n \n if ( $method eq \"psiblast\")\n \ + {\n add_warning($$,$$,\"PSI BLAST cannot be \ +used with the NCBI BLAST Client. Use server=EBI Or\ + server=LOCAL. blastp will be used instead\");\n \ +$cl_method=\"blastp\";\n }\n else\n \ + {\n $cl_method=$method;\n }\n $comman\ +d=\"blastcl3 -p $cl_method -d $cl_db -i $infile -o\ + $outfile -m 7\";\n &safe_system ($command);\n\ + }\n elsif ($SERVER =~/CLIENT_(.*)/)\n {\n \ + my $client=$1;\n $command=\"$client -p $metho\ +d -d $db -i $infile -o $outfile -m 7\";\n &saf\ +e_system ($command);\n }\n elsif ( $SERVER eq \"\ +LOCAL_blastall\")\n {\n &check_configuration\ + (\"blastall\");\n if ($method eq \"blastp\")\\ +n {\n $command=\"blastall -d $db -i $infile\ + -o $outfile -m7 -p blastp\";\n }\n &saf\ +e_system ($command);\n }\n elsif ( $SERVER eq \"\ +LOCAL\")\n {\n \n if ($ENV{\"BLAST_DB_DI\ +R\"})\n {\n $x=$ENV{\"BLAST_DB_DIR\"};\n $\ +cl_db=\"$x$db\";\n }\n else\n {\n \ + $cl_db=$db;\n }\n \n if ($method eq\ + \"blastp\")\n {\n &check_configuration(\"b\ +lastpgp\");\n $command=\"blastpgp -d $cl_db -i $i\ +nfile -o $outfile -m7 -j1\";\n }\n elsif\ + ($method eq \"psiblast\")\n {\n &check_con\ +figuration(\"blastpgp\");\n $command=\"blastpgp -\ +d $cl_db -i $infile -o $outfile -m7 -j5\";\n \ + }\n elsif ($method eq \"blastn\")\n {\n\ + &check_configuration(\"blastall\");\n $command=\ +\"blastall -p blastn -d $cl_db -i $infile -o $outf\ +ile -m7 -W6\";\n } \n &safe_system ($com\ +mand);\n }\n else\n {\n \n myexit(add_\ +error (EXIT_FAILURE,$$,$$,getppid(), \"BLAST_FAILU\ +RE::UnknownServer\",$CL));\n }\n \n if ( !-e $ou\ +tfile || !&is_valid_blast_xml($outfile))\n {\n \ + \n if ( -e $outfile)\n {\n add_warni\ +ng ($$,$$,\"Corrupted Blast Output (Run $run)\");\\ +n unlink($outfile);\n }\n \n if ( $\ +run==$BLAST_MAX_NRUNS)\n {\n \n myexit(add_\ +error (EXIT_FAILURE,$$,$$,getppid(), \"BLAST_FAILU\ +RE::UnknownReason\", \"$command\"));\n }\n \ + else\n {\n my $out;\n if ($SERVER eq \"\ +NCBI\") {$SERVER=\"EBI\"; }\n elsif ($SERVER eq \\ +"EBI\"){$SERVER=\"NCBI\";}\n add_warning ($$,$$,\\ +"Blast for $name failed (Run: $run out of $BLAST_M\ +AX_NRUNS. Use $SERVER)\");\n $out=&run_blast ($na\ +me, $method, $db,$infile, $outfile, $run+1);\n if\ + ($SERVER eq \"NCBI\") {$SERVER=\"EBI\"; }\n elsi\ +f ($SERVER eq \"EBI\"){$SERVER=\"NCBI\";}\n retur\ +n $out;\n }\n }\n \n &cache_file(\"SET\",$\ +infile,$name,$method,$db,$outfile,$SERVER);\n #sys\ +tem (\"cp $outfile ~/Dropbox/tmp/cedric.out\");\n \ +#die;\n return $outfile;\n }\n }\n\nsub cach\ +e_file\n {\n my ($cache_mode,$infile,$name,$me\ +thod,$db, $outfile,$server)=(@_);\n my $cache_f\ +ile;\n #Protect names so that they can be turne\ +d into legal filenames\n $name=&clean_file_name\ + ($name);\n\n if ($db=~/\\//)\n {\n $db=~/\ +([^\\/]+)$/;\n $db=$1;\n }\n $cache_file_s\ +h=\"$name.$method.$db.$server.tmp\";\n $cache_f\ +ile=\"$CACHE/$name.$method.$db.$server.tmp\";\n \ + \n if ($infile ne \"\")\n {\n $cache_file\ +_infile_sh=\"$name.$method.$db.$server.infile.tmp\\ +";\n $cache_file_infile=\"$CACHE/$name.$method.$db\ +.$server.infile.tmp\";\n }\n \n if ($ca\ +che_mode eq \"GET\")\n {\n if ($CACHE eq \"\"\ + || $CACHE eq \"no\" || $CACHE eq \"ignore\" || $\ +CACHE eq \"local\" || $CACHE eq \"update\"){return\ + 0;}\n elsif ( !-d $CACHE)\n {\n print STDER\ +R \"ERROR: Cache Dir: $CACHE Does not Exist\";\n \ + return 0;\n }\n else\n {\n if ( -e $cac\ +he_file && &fasta_file1_eq_fasta_file2($infile,$ca\ +che_file_infile)==1)\n {\n `cp $cache_file \ +$outfile`;\n $CACHE_STATUS=\"READ CACHE\";\n ret\ +urn 1;\n }\n }\n }\n elsif ($cache\ +_mode eq \"SET\")\n {\n if ($CACHE eq \"\" ||\ + $CACHE eq \"no\" || $CACHE eq \"ignore\" || $CAC\ +HE eq \"local\" || $CACHE eq \"update\"){return 0;\ +}\n elsif ( !-d $CACHE)\n {\n print STDERR \\ +"ERROR: Cache Dir: $CACHE Does not Exist\";\n \ +return 0;\n }\n elsif (-e $outfile)\n {\n \ +`cp $outfile $cache_file`;\n if ($cache_file_i\ +nfile ne \"\"){ `cp $infile $cache_file_infile`;}\\ +n\n #functions for updating the cache\n #`\ +t_coffee -other_pg clean_cache.pl -file $cache_fil\ +e_sh -dir $CACHE`;\n #`t_coffee -other_pg clea\ +n_cache.pl -file $cache_file_infile_sh -dir $CACHE\ +`;\n return 1;\n }\n }\n $CACHE_STAT\ +US=\"COMPUTE CACHE\";\n return 0;\n }\nsub fil\ +e1_eq_file2\n {\n my ($f1, $f2)=@_;\n if ( \ +$f1 eq \"\"){return 1;}\n elsif ( $f2 eq \"\"){\ +return 1;}\n elsif ( !-e $f1){return 0;}\n e\ +lsif ( !-e $f2){return 0;}\n elsif ($f1 eq \"\"\ + || $f2 eq \"\" || `diff $f1 $f2` eq \"\"){return \ +1;}\n \n return 0;\n }\nsub clean_file_name\ + \n {\n my $name=@_[0];\n \n $name=~s/[^\ +A-Za-z1-9.-]/_/g;\n return $name;\n }\nsub url\ +2file\n {\n my ($address, $out)=(@_);\n \n \ + if (&pg_is_installed (\"wget\"))\n {\n return\ + &safe_system (\"wget $address -O$out >/dev/null 2\ +>/dev/null\");\n }\n elsif (&pg_is_installed (\\ +"curl\"))\n {\n return &safe_system (\"curl $\ +address -o$out >/dev/null 2>/dev/null\");\n }\ +\n else\n {\n myexit(flus_error(\"neither \ +curl nor wget are installed. Imnpossible to fectch\ + remote file\"));\n exit ($EXIT_FAILURE);\n }\ +\n }\nsub fasta_file1_eq_fasta_file2\n {\n my\ + ($f1, $f2)=@_;\n my (%s1, %s2);\n my @names\ +;\n %s1=read_fasta_seq ($f1);\n %s2=read_fas\ +ta_seq ($f2);\n\n @names=(keys (%s1));\n \n \ + foreach $n (keys(%s1))\n {\n if ($s1{$n}{s\ +eq} ne $s2{$n}{seq}){return 0;}\n } \n \n \ + foreach $n (keys(%s2))\n {\n if ($s1{$n}{s\ +eq} ne $s2{$n}{seq}){return 0;}\n }\n retu\ +rn 1;\n }\n \n\n\nsub read_template_file\n{\n my \ +$pdb_templates = @_[0];\n open (TEMP, \"<$pdb_temp\ +lates\");\n my %temp_h;\n while ()\n{\n $li\ +ne = $_;\n $line =~/(\\S+)\\s(\\S+)/;\n $temp_\ +h{$1}= $2;\n}\n close(TEMP);\n return %temp_h;\n}\\ +n\nsub calc_rna_template\n{\n my ($mode, $infile, \ +$pdbfile, $outfile)=@_;\n my %s, %h ;\n my $result\ +;\n my (@profiles);\n &set_temporary_dir (\"set\",\ +$infile,\"seq.pep\");\n %s=read_fasta_seq (\"seq.p\ +ep\");\n \n %pdb_template_h = &read_template_file(\ +$pdbfile);\n my $pdb_chain;\n open (R, \">result.a\ +ln\");\n\n\n #print stdout \"\\n\";\n foreach $seq\ + (keys(%s))\n {\n if ($pdb_template_h{$seq} eq \"\ +\")\n {\n next;\n }\n open (F, \">seqfile\");\ +\n print (F \">$s{$seq}{name}\\n$s{$seq}{seq}\\n\\ +");\n close (F);\n $pdb_chain = $pdb_template_h{\ +$seq};\n $lib_name=\"$s{$seq}{name}.rfold\";\n $\ +lib_name=&clean_file_name ($lib_name);\n \n saf\ +e_system (\"secondary_struc.py seqfile $CACHE$pdb_\ +chain $lib_name\");\n \n if ( !-e $lib_name)\n \ + {\n myexit(flush_error(\"RNAplfold failed to com\ +pute the secondary structure of $s{$seq}{name}\"))\ +;\n myexit ($EXIT_FAILURE);\n }\n else\n {\n \ + print stdout \"\\tProcess: >$s{$seq}{name} _F_ $\ +lib_name\\n\";\n print R \">$s{$seq}{name} _F_ $\ +lib_name\\n\";\n }\n unshift (@profiles, $lib_na\ +me);\n }\n close (R);\n &set_temporary_dir (\"unse\ +t\",$mode, $method,\"result.aln\",$outfile, @profi\ +les);\n}\n\n\n\nsub seq2rna_pair{\n my ($mode, $pd\ +bfile1, $pdbfile2, $method, $param, $outfile)=@_;\\ +n \n if ($method eq \"runsara.py\")\n {\n open(TM\ +P,\"<$pdbfile1\");\n my $count = 0;\n my $line;\\ +n while ()\n {\n $line = $_;\n if ($cou\ +nt ==1)\n {\n last;\n }\n $count += 1;\n \ + }\n\n \n $chain1 = substr($line,length($line)-3\ +,1);\n\n close TMP;\n open(TMP,\"<$pdbfile2\");\\ +n my $count = 0;\n while ()\n {\n $line \ += $_;\n if ($count ==1)\n {\n last;\n }\n\ + $count += 1;\n }\n $chain2 = substr($line,len\ +gth($line)-3,1);\n close TMP;\n\n $tmp_file=&vtm\ +pnam();\n \n safe_system(\"runsara.py $pdbfile1 $\ +chain1 $pdbfile2 $chain2 -s -o $tmp_file --limitat\ +ion 5000 > /dev/null 2> /dev/null\") == 0 or die \\ +"sara did not work $!\\n\";\n open(TMP,\"<$tmp_fi\ +le\") or die \"cannot open the sara tmp file:$!\\n\ +\";\n open(OUT,\">$outfile\") or die \"cannot ope\ +n the $outfile file:$!\\n\";\n\n my $switch = 0;\\ +n my $seqNum = 0;\n foreach my $line ()\n \ +{\n next unless ($line=~/SARAALI/);\n if ($lin\ +e=~/>/)\n {\n $switch =0;\n print OUT \">s\ +eq$seqNum\\n\";\n $seqNum++; \n }\n if (\ +$switch < 2){\n $switch++;\n next;\n }\n \\ +n if ($line =~/REMARK\\s+SARAALI\\s+([^\\*]+)\\*\ +/)\n {\n my $string = $1;\n print OUT \"$s\ +tring\\n\";\n }\n }\n close TMP; \n close OUT\ +;\n unlink($tmp_file);\n }\n}\n\nsub seq2tblastx_\ +lib\n {\n my ($mode, $infile, $outfile)=@_;\n \ + my (%s, $method,$nseq);\n\n $method=$mode;\n\ + &set_temporary_dir (\"set\",$infile,\"infile\"\ +);\n %s=read_fasta_seq(\"infile\");\n \n \ +\n foreach $seq (keys(%s))\n {\n $slist[$s\ +{$seq}{order}]=$s{$seq}{seq};\n $sname[$s{$seq}{or\ +der}]=$s{$seq}{name};\n $slen[$s{$seq}{order}]=len\ +gth ($s{$seq}{seq});\n }\n $nseq=$#sname+1\ +;\n open (F, \">outfile\");\n print F \"! TC\ +_LIB_FORMAT_01\\n\";\n print F \"$nseq\\n\";\n \ + for ($a=0; $a<$nseq;$a++)\n {\n print F \"\ +$sname[$a] $slen[$a] $slist[$a]\\n\"\n }\n \ + close (F);\n &safe_system (\"formatdb -i infi\ +le -p F\");\n &safe_system (\"blastall -p tblas\ +tx -i infile -d infile -m 7 -S1>blast.output\");\n\ + \n ncbi_tblastx_xml2lib_file (\"outfile\", \ +file2string (\"blast.output\"));\n &set_tempora\ +ry_dir (\"unset\",$mode, $method, \"outfile\",$out\ +file);\n myexit ($EXIT_SUCCESS);\n }\nsub se\ +q2tblastpx_lib\n {\n my ($mode, $infile, $outf\ +ile)=@_;\n my (%s, $method,$nseq);\n $method\ +=$mode;\n &set_temporary_dir (\"set\",$infile,\\ +"infile\");\n %s=read_fasta_seq(\"infile\");\n \ + \n foreach $seq (keys(%s))\n {\n $slist\ +[$s{$seq}{order}]=$s{$seq}{seq};\n $sname[$s{$seq}\ +{order}]=$s{$seq}{name};\n $slen[$s{$seq}{order}]=\ +length ($s{$seq}{seq});\n }\n $nseq=$#snam\ +e+1;\n open (F, \">outfile\");\n print F \"!\ + TC_LIB_FORMAT_01\\n\";\n print F \"$nseq\\n\";\ +\n for ($a=0; $a<$nseq;$a++)\n {\n print F\ + \"$sname[$a] $slen[$a] $slist[$a]\\n\"\n }\\ +n close (F);\n &safe_system(\"t_coffee -othe\ +r_pg seq_reformat -in infile -output tblastx_db1 >\ + tblastxdb\");\n &safe_system (\"formatdb -i tb\ +lastxdb -p T\");\n &safe_system (\"blastall -p \ +blastp -i tblastxdb -d tblastxdb -m7 >blast.output\ +\");\n ncbi_tblastpx_xml2lib_file (\"outfile\",\ + file2string (\"blast.output\"), %s);\n &set_te\ +mporary_dir (\"unset\",$mode, $method, \"outfile\"\ +,$outfile);\n myexit ($EXIT_SUCCESS);\n }\n\\ +n\n \n\n\n\nsub file2head\n {\n my $file =\ + shift;\n my $size = shift;\n my $f= new FileHandl\ +e;\n my $line;\n open ($f,$file);\n read ($f,$line\ +, $size);\n close ($f);\n return $line;\n }\n\ +sub file2tail\n {\n my $file = shift;\n my $s\ +ize = shift;\n my $f= new FileHandle;\n my $line;\\ +n \n open ($f,$file);\n seek ($f,$size*-1, 2);\n r\ +ead ($f,$line, $size);\n close ($f);\n return $lin\ +e;\n }\n\n\nsub vtmpnam\n {\n my $r=rand\ +(100000);\n my $f=\"file.$r.$$\";\n while (-e $f)\\ +n {\n $f=vtmpnam();\n }\n push (@TMPFILE_L\ +IST, $f);\n return $f;\n }\n\nsub myexit\n {\ +\n my $code=@_[0];\n if ($CLEAN_EXIT_STARTED\ +==1){return;}\n else {$CLEAN_EXIT_STARTED=1;}\n\ + ### ONLY BARE EXIT\n exit ($code);\n }\nsu\ +b set_error_lock\n {\n my $name = shift;\n\ + my $pid=$$;\n\n \n &lock4tc ($$,\"\ +LERROR\", \"LSET\", \"$$ -- ERROR: $name $PROGRAM\\ +\n\");\n return;\n }\nsub set_lock\n {\n \ + my $pid=shift;\n my $msg= shift;\n my $p=\ +getppid();\n &lock4tc ($pid,\"LLOCK\",\"LRESET\\ +",\"$p$msg\\n\");\n }\nsub unset_lock\n {\n \ + \n my $pid=shift;\n &lock4tc ($pid,\"LLOCK\\ +",\"LRELEASE\",\"\");\n }\nsub shift_lock\n {\n \ + my $from=shift;\n my $to=shift;\n my $fro\ +m_type=shift;\n my $to_type=shift;\n my $act\ +ion=shift;\n my $msg;\n \n if (!&lock4tc(\ +$from, $from_type, \"LCHECK\", \"\")){return 0;}\n\ + $msg=&lock4tc ($from, $from_type, \"LREAD\", \\ +"\");\n &lock4tc ($from, $from_type,\"LRELEASE\\ +", $msg);\n &lock4tc ($to, $to_type, $action, $\ +msg);\n return;\n }\nsub isshellpid\n {\n \ +my $p=shift;\n if (!lock4tc ($p, \"LLOCK\", \"L\ +CHECK\")){return 0;}\n else\n {\n my $c=lo\ +ck4tc($p, \"LLOCK\", \"LREAD\");\n if ( $c=~/-SHEL\ +L-/){return 1;}\n }\n return 0;\n }\nsub \ +isrootpid\n {\n if(lock4tc (getppid(), \"LLOCK\ +\", \"LCHECK\")){return 0;}\n else {return 1;}\\ +n }\nsub lock4tc\n {\n my ($pid,$type,$action,$\ +value)=@_;\n my $fname;\n my $host=hostname;\n\ + \n if ($type eq \"LLOCK\"){$fname=\"$LOCKDIR/\ +.$pid.$host.lock4tcoffee\";}\n elsif ( $type eq \ +\"LERROR\"){ $fname=\"$LOCKDIR/.$pid.$host.error4t\ +coffee\";}\n elsif ( $type eq \"LWARNING\"){ $fn\ +ame=\"$LOCKDIR/.$pid.$host.warning4tcoffee\";}\n \ + \n if ($debug_lock)\n {\n print STDER\ +R \"\\n\\t---lock4tc(tcg): $action => $fname =>$va\ +lue (RD: $LOCKDIR)\\n\";\n }\n\n if ($act\ +ion eq \"LCHECK\") {return -e $fname;}\n elsif (\ +$action eq \"LREAD\"){return file2string($fname);}\ +\n elsif ($action eq \"LSET\") {return string2fi\ +le ($value, $fname, \">>\");}\n elsif ($action e\ +q \"LRESET\") {return string2file ($value, $fname,\ + \">\");}\n elsif ($action eq \"LRELEASE\") \n \ + {\n if ( $debug_lock)\n {\n my $g=new\ + FileHandle;\n open ($g, \">>$fname\");\n pr\ +int $g \"\\nDestroyed by $$\\n\";\n close ($g);\ +\n safe_system (\"mv $fname $fname.old\");\n }\ +\n else\n {\n unlink ($fname);\n }\n \ + }\n return \"\";\n }\n \nsub file2string\n {\n\ + my $file=@_[0];\n my $f=new FileHandle;\n m\ +y $r;\n open ($f, \"$file\");\n while (<$f>){$\ +r.=$_;}\n close ($f);\n return $r;\n }\nsub st\ +ring2file \n {\n my ($s,$file,$mode)=@_;\n \ + my $f=new FileHandle;\n \n open ($f, \"$mo\ +de$file\");\n print $f \"$s\";\n close ($f)\ +;\n }\n\nBEGIN\n {\n srand;\n \n \ +$SIG{'SIGUP'}='signal_cleanup';\n $SIG{'SIGIN\ +T'}='signal_cleanup';\n $SIG{'SIGQUIT'}='sign\ +al_cleanup';\n $SIG{'SIGILL'}='signal_cleanup\ +';\n $SIG{'SIGTRAP'}='signal_cleanup';\n \ + $SIG{'SIGABRT'}='signal_cleanup';\n $SIG{'SI\ +GEMT'}='signal_cleanup';\n $SIG{'SIGFPE'}='si\ +gnal_cleanup';\n \n $SIG{'SIGKILL'}='sig\ +nal_cleanup';\n $SIG{'SIGPIPE'}='signal_clean\ +up';\n $SIG{'SIGSTOP'}='signal_cleanup';\n \ + $SIG{'SIGTTIN'}='signal_cleanup';\n $SIG{'\ +SIGXFSZ'}='signal_cleanup';\n $SIG{'SIGINFO'}\ +='signal_cleanup';\n \n $SIG{'SIGBUS'}='\ +signal_cleanup';\n $SIG{'SIGALRM'}='signal_cl\ +eanup';\n $SIG{'SIGTSTP'}='signal_cleanup';\n\ + $SIG{'SIGTTOU'}='signal_cleanup';\n $SI\ +G{'SIGVTALRM'}='signal_cleanup';\n $SIG{'SIGU\ +SR1'}='signal_cleanup';\n\n\n $SIG{'SIGSEGV'}\ +='signal_cleanup';\n $SIG{'SIGTERM'}='signal_\ +cleanup';\n $SIG{'SIGCONT'}='signal_cleanup';\ +\n $SIG{'SIGIO'}='signal_cleanup';\n $SI\ +G{'SIGPROF'}='signal_cleanup';\n $SIG{'SIGUSR\ +2'}='signal_cleanup';\n\n $SIG{'SIGSYS'}='sig\ +nal_cleanup';\n $SIG{'SIGURG'}='signal_cleanu\ +p';\n $SIG{'SIGCHLD'}='signal_cleanup';\n \ + $SIG{'SIGXCPU'}='signal_cleanup';\n $SIG{'S\ +IGWINCH'}='signal_cleanup';\n \n $SIG{'I\ +NT'}='signal_cleanup';\n $SIG{'TERM'}='signal\ +_cleanup';\n $SIG{'KILL'}='signal_cleanup';\n\ + $SIG{'QUIT'}='signal_cleanup';\n \n \ + our $debug_lock=$ENV{\"DEBUG_LOCK\"};\n \n \ + \n \n \n foreach my $a (@ARGV)\ +{$CL.=\" $a\";}\n if ( $debug_lock ){print ST\ +DERR \"\\n\\n\\n********** START PG: $PROGRAM ****\ +*********\\n\";}\n if ( $debug_lock ){print S\ +TDERR \"\\n\\n\\n**********(tcg) LOCKDIR: $LOCKDIR\ + $$ *************\\n\";}\n if ( $debug_lock )\ +{print STDERR \"\\n --- $$ -- $CL\\n\";}\n \n\ + \n \n \n }\nsub flush_error\n \ +{\n my $msg=shift;\n return add_error ($EXIT\ +_FAILURE,$$, $$,getppid(), $msg, $CL);\n }\nsub a\ +dd_error \n {\n my $code=shift;\n my $rpid=\ +shift;\n my $pid=shift;\n my $ppid=shift;\n \ + my $type=shift;\n my $com=shift;\n \n \ +$ERROR_DONE=1;\n lock4tc ($rpid, \"LERROR\",\"L\ +SET\",\"$pid -- ERROR: $type\\n\");\n lock4tc (\ +$$, \"LERROR\",\"LSET\", \"$pid -- COM: $com\\n\")\ +;\n lock4tc ($$, \"LERROR\",\"LSET\", \"$pid --\ + STACK: $ppid -> $pid\\n\");\n \n return $cod\ +e;\n }\nsub add_warning \n {\n my $rpid=shift\ +;\n my $pid =shift;\n my $command=shift;\n \ + my $msg=\"$$ -- WARNING: $command\\n\";\n pri\ +nt STDERR \"$msg\";\n lock4tc ($$, \"LWARNING\"\ +, \"LSET\", $msg);\n }\n\nsub signal_cleanup\n {\ +\n print dtderr \"\\n**** $$ (tcg) was killed\\\ +n\";\n &cleanup;\n exit ($EXIT_FAILURE);\n \ +}\nsub clean_dir\n {\n my $dir=@_[0];\n if \ +( !-d $dir){return ;}\n elsif (!($dir=~/tmp/)){\ +return ;}#safety check 1\n elsif (($dir=~/\\*/)\ +){return ;}#safety check 2\n else\n {\n `r\ +m -rf $dir`;\n }\n return;\n }\nsub clean\ +up\n {\n #print stderr \"\\n----tc: $$ Kills $\ +PIDCHILD\\n\";\n #kill (SIGTERM,$PIDCHILD);\n \ + my $p=getppid();\n $CLEAN_EXIT_STARTED=1;\n \ + \n \n \n if (&lock4tc($$,\"LERROR\", \"\ +LCHECK\", \"\"))\n {\n my $ppid=getppid();\n \ +if (!$ERROR_DONE) \n {\n &lock4tc($$,\"LERRO\ +R\", \"LSET\", \"$$ -- STACK: $p -> $$\\n\");\n \ + &lock4tc($$,\"LERROR\", \"LSET\", \"$$ -- COM: $\ +CL\\n\");\n }\n }\n my $warning=&lock4tc\ +($$, \"LWARNING\", \"LREAD\", \"\");\n my $erro\ +r=&lock4tc($$, \"LERROR\", \"LREAD\", \"\");\n \ + #release error and warning lock if root\n \n \ + if (isrootpid() && ($warning || $error) )\n \ + {\n \n print STDERR \"**************** Summary **\ +***********\\n$error\\n$warning\\n\";\n\n &lock4tc\ +($$,\"LERROR\",\"RELEASE\",\"\");\n &lock4tc($$,\"\ +LWARNING\",\"RELEASE\",\"\");\n } \n \n \ + \n foreach my $f (@TMPFILE_LIST)\n {\n if\ + (-e $f){unlink ($f);} \n }\n foreach my $\ +d (@TMPDIR_LIST)\n {\n clean_dir ($d);\n \ + }\n #No More Lock Release\n #&lock4tc($$,\"\ +LLOCK\",\"LRELEASE\",\"\"); #release lock \n\n \ +if ( $debug_lock ){print STDERR \"\\n\\n\\n*******\ +*** END PG: $PROGRAM ($$) *************\\n\";}\n \ + if ( $debug_lock ){print STDERR \"\\n\\n\\n*****\ +*****(tcg) LOCKDIR: $LOCKDIR $$ *************\\n\"\ +;}\n }\nEND \n {\n \n &cleanup();\n }\n \ + \nsub blast_com2new_blast_com\n {\n my $c\ +om=shift;\n if ($ENV{\"NCBI_BLAST_4_TCOFFEE\"\ +} eq \"OLD\"){return $com;}\n elsif (!&pg_is_\ +installed(\"legacy_blast.pl\")){return $com;}\n \ + else \n {\n if ($com=~/formatdb/)\n {\n \ + $com=~s/formatdb/makeblastdb/;\n $com=~\ +s/\\-i/\\-in/;\n if ($com =~/pF/){$com=~s/\\\ +-pF/\\-dbtype nucl/;}\n if ($com =~/p F/){$c\ +om=~s/\\-p F/\\-dbtype nucl/;}\n $com=\"$com\ + -logfile /dev/null\";\n return $com;\n \ +}\n elsif (&is_blast_package($com))\n {\n \ + my $path;\n \n if ( $ENV{\"NCBI_BI\ +N_4_TCOFFEE\"}){$path=$ENV{\"NCBI_BLAST_4_TCOFFEE\\ +"};}\n else\n {\n $path=`which legacy_bl\ +ast.pl`;\n $path=~s/\\/legacy_blast\\.pl//;\n \ + chomp ($path);\n }\n $path=\"--path $path\ +\";\n if ( $com=~/\\>\\>/){$com=~s/\\>\\>/ $\ +path \\>\\>/;}\n elsif ( $com=~/\\>/){$com=~\ +s/\\>/ $path \\>/;}\n else {$com.=\" $path\"\ +;}\n $com=\"legacy_blast.pl $com\";\n \ +\n return $com;\n }\n }\n }\nsub safe\ +_system \n{\n my $com=shift;\n my $ntry=shift;\n\ + my $ctry=shift;\n my $pid;\n my $status;\n my\ + $ppid=getppid();\n if ($com eq \"\"){return 1;}\\ +n \n if ( ($com=~/^blast/) ||($com=~/^formatdb/)\ +){$com=&blast_com2new_blast_com($com);} \n\n if (\ +($pid = fork ()) < 0){return (-1);}\n if ($pid ==\ + 0)\n {\n set_lock($$, \" -SHELL- $com (tc\ +g)\");\n if( $debug_cmd_exec ) { printf \"exe\ +c: %s\\n\", $com; } \n exec ($com);\n }\n \ + else\n {\n lock4tc ($$, \"LLOCK\", \"LSET\ +\", \"$pid\\n\");#update parent\n $PIDCHILD=$\ +pid;\n }\n if ($debug_lock){printf STDERR \"\\\ +n\\t .... safe_system (fasta_seq2hmm) p: $$ c: $p\ +id COM: $com\\n\";}\n\n waitpid ($pid,WTERMSIG);\\ +n\n shift_lock ($pid,$$, \"LWARNING\",\"LWARNING\\ +", \"LSET\");\n\n if ($? == $EXIT_FAILURE || lock\ +4tc($pid, \"LERROR\", \"LCHECK\", \"\"))\n {\n \ + if ($ntry && $ctry <$ntry)\n {\n\n add_warn\ +ing ($$,$$,\"$com failed [retry: $ctry out of $ntr\ +y]\");\n lock4tc ($pid, \"LRELEASE\", \"LERROR\"\ +, \"\");\n #if ($com=~/EBI/){$com=~s/EBI/NCBI/;}\ +\n #elsif ($com=~/NCBI/){$com=~s/NCBI/EBI/;}\n \ + \n return safe_system ($com, $ntry, ++$ctry);\n\ + }\n elsif ($ntry == -1)\n {\n if (!shift_l\ +ock ($pid, $$, \"LERROR\", \"LWARNING\", \"LSET\")\ +)\n {\n add_warning ($$,$$,\"$com failed\ +\");\n }\n else\n {\n lock4tc ($pi\ +d, \"LRELEASE\", \"LERROR\", \"\");\n }\n re\ +turn $?;}\n else\n {\n if (!shift_lock ($pi\ +d,$$, \"LERROR\",\"LERROR\", \"LSET\"))\n {\n \ + myexit(add_error ($EXIT_FAILURE,$$,$pid,getp\ +pid(), \"UNSPECIFIED system\", $com));\n }\n }\ +\n }\n return $?;\n}\n\nsub check_configuratio\ +n \n {\n my @l=@_;\n my $v;\n fo\ +reach my $p (@l)\n {\n \n if ( $p eq \"EMAIL\ +\")\n { \n if ( !($EMAIL=~/@/))\n {\n \ +add_warning($$,$$,\"Could Not Use EMAIL\");\n mye\ +xit(add_error ($EXIT_FAILURE,$$,$$,getppid(),\"EMA\ +IL\",\"$CL\"));\n }\n }\n elsif( $p eq\ + \"INTERNET\")\n {\n if ( !&check_intern\ +et_connection())\n {\n myexit(add_error ($EXIT\ +_FAILURE,$$,$$,getppid(),\"INTERNET\",\"$CL\"));\n\ + }\n }\n elsif( $p eq \"wget\")\n {\n \ + if (!&pg_is_installed (\"wget\") && !&pg_is_i\ +nstalled (\"curl\"))\n {\n myexit(add_error ($\ +EXIT_FAILURE,$$,$$,getppid(),\"PG_NOT_INSTALLED:wg\ +et\",\"$CL\"));\n }\n }\n elsif( !(&pg_is_i\ +nstalled ($p)))\n {\n myexit(add_error (\ +$EXIT_FAILURE,$$,$$,getppid(),\"PG_NOT_INSTALLED:$\ +p\",\"$CL\"));\n }\n }\n return 1;\n }\ +\n\n$program=\"T-COFFEE (r550)\";\n\n","*TC_METHOD\ +_FORMAT_01\n******************generic_method.tc_me\ +thod*************\n*\n* Incorporating new me\ +thods in T-Coffee\n* Cedric Notredame 26/08/\ +08\n*\n*******************************************\ +************\n*This file is a method file\n*Copy i\ +t and adapt it to your need so that the method \n*\ +you want to use can be incorporated within T-Coffe\ +e\n***********************************************\ +********\n* USAGE \ + *\n*********************************\ +**********************\n*This file is passed to t_\ +coffee via -in:\n*\n* t_coffee -in Mgeneric_method\ +.method\n*\n* The method is passed to the shell us\ +ing the following\n*call:\n*\n*\n*Conventions:\n* \ +\n*: no_name <=> Replaced with a space\n*<\ +VALUE>:   <=> Replaced with a space\n*\n******\ +*************************************************\\ +n* ALN_MODE \ + *\n******************************************\ +*************\n*pairwise ->all Vs all (no self )\ +[(n2-n)/2aln]\n*m_pairwise ->all Vs all (no self)[\ +n^2-n]^2\n*s_pairwise ->all Vs all (self): [n^2-n]\ +/2 + n\n*multiple ->All the sequences in one go\\ +n*\nALN_MODE pairwise\n*\n***********************\ +********************************\n* \ + OUT_MODE *\n*********\ +**********************************************\n* \ +mode for the output:\n*External methods: \n* aln -\ +> alignmnent File (Fasta or ClustalW Format)\n* li\ +b-> Lib file (TC_LIB_FORMAT_01)\n*Internal Methods\ +:\n* fL -> Internal Function returning a List (Lib\ +rairie)\n* fA -> Internal Function returning an Al\ +ignmnent\n*\nOUT_MODE aln\n**********************\ +*********************************\n* \ + SEQ_TYPE *\n********\ +***********************************************\n*\ +G: Genomic, S: Sequence, P: PDB, R: Profile\n*Exam\ +ples:\n*SEQTYPE S sequences against sequences (def\ +ault)\n*SEQTYPE S_P sequence against structure\n*S\ +EQTYPE P_P structure against structure\n*SEQTYPE P\ +S mix of sequences and structure \n*\nSEQ_TYPE S\n\ +*\n\n*********************************************\ +**********\n* COMMAND LINE \ + *\n*EXECUTABLE PARAM1 IN_FLAG OUT_\ +FLAG PARAM *\n************************\ +*******************************\n*****************\ +**************************************\n* \ + EXECUTABLE *\n***\ +**************************************************\ +**\n*name of the executable\n*passed to the shell:\ + executable\n* \nEXECUTABLE tc_generic_method.pl\n\ +*\n***********************************************\ +********\n* IN_FLAG \ + *\n********************************\ +***********************\n*IN_FLAG\n*flag indicatin\ +g the name of the in coming sequences\n*IN_FLAG S \ +no_name ->no flag\n*IN_FLAG S &bnsp-in&bnsp -> \" \ +-in \"\n*\nIN_FLAG -infile=\n*\n*****************\ +**************************************\n* \ + OUT_FLAG *\n***\ +**************************************************\ +**\n*OUT_FLAG\n*flag indicating the name of the ou\ +t-coming data\n*same conventions as IN_FLAG\n*OUT_\ +FLAG S no_name ->no flag\n*if you want to redirect\ +, pass the parameters via PARAM1\n*set OUT_FLAG to\ + >\n*\nOUT_FLAG -outfile=\n*\n*******************\ +************************************\n* \ + PARAM_1 *\n***\ +**************************************************\ +**\n*\n*Parameters sent to \ +the EXECUTABLE and specified *before* IN_FLAG \n*I\ +f there is more than 1 PARAM line, the lines are\n\ +*concatenated\n*Command_line: @EP@PARAM@-gapopen%e\ +10%s-gapext%e20\n* %s white space\n* %e equal sign\ +\n*\n*PARAM1 \n*\n*\n*\n**************************\ +*****************************\n* \ +PARAM_2 *\n**********\ +*********************************************\n*\n*Parameters sent to the EXE\ +CUTABLE and specified \n*after* IN_FLAG and *befor\ +e* OUT_FLAG\n*If there is more than 1 PARAM line, \ +the lines are\n*concatenated\n*\n*PARAM1 \n*\n*\n*\ +**************************************************\ +****\n* PARAM \ + *\n*************************************\ +******************\n*\ +\n*Par\ +ameters sent to the EXECUTABLE and specified *afte\ +r* OUT_FLAG\n*If there is more than 1 PARAM line, \ +the lines are\n*concatenated\n*\nPARAM -mode=seq_m\ +sa -method=clustalw\nPARAM -OUTORDER=INPUT -NEWT\ +REE=core -align -gapopen=-15\n*\n*****************\ +**************************************\n* \ + END *\n***\ +**************************************************\ +**\n","*TC_METHOD_FORMAT_01\n***************clusta\ +lw_method.tc_method*********\nEXECUTABLE clustalw\\ +nALN_MODE pairwise\nIN_FLAG -INFILE=\nOUT_FLAG \ +-OUTFILE=\nOUT_MODE aln\nPARAM -gapopen=-10\nSEQ\ +_TYPE S\n****************************************\ +*********\n","$VersionTag = \ + \ + \ + 2.43;\nuse Env;\nuse FileHandle;\nuse Cwd;\ +\nuse File::Path;\nuse Sys::Hostname;\nour $PIDCHI\ +LD;\nour $ERROR_DONE;\nour @TMPFILE_LIST;\nour $EX\ +IT_FAILURE=1;\nour $EXIT_SUCCESS=0;\n\nour $REFDIR\ +=getcwd;\nour $EXIT_SUCCESS=0;\nour $EXIT_FAILURE=\ +1;\n\nour $PROGRAM=\"extract_from_pdb\";\nour $CL=\ +$PROGRAM;\n\nour $CLEAN_EXIT_STARTED;\nour $debug_\ +lock=$ENV{\"DEBUG_LOCK\"};\nour $LOCKDIR=$ENV{\"LO\ +CKDIR_4_TCOFFEE\"};\nif (!$LOCKDIR){$LOCKDIR=getcw\ +d();}\nour $ERRORDIR=$ENV{\"ERRORDIR_4_TCOFFEE\"};\ +\nour $ERRORFILE=$ENV{\"ERRORFILE_4_TCOFFEE\"};\n&\ +set_lock ($$);\nif (isshellpid(getppid())){lock4tc\ +(getppid(), \"LLOCK\", \"LSET\", \"$$\\n\");}\n \ + \nour $SILENT=\" >/dev/null 2>/dev/null\";\nour\ + $INTERNET=-1;\n\n\n\n\n\n\n\nour $BLAST_MAX_NRUNS\ +=2;\nour $EXIT_SUCCESS=0;\nour $EXIT_FAILURE=1;\no\ +ur $CONFIGURATION=-1;\nour $REF_EMAIL=\"\";\nour $\ +PROGRAM=\"extract_from_pdb\";\n\n\nmy %onelett_pro\ +t=&fill_onelett_prot();\nmy %threelett_prot=&fill_\ +threelett_prot();\nmy %onelett_RNA=&fill_onelett_R\ +NA();\nmy %threelett_RNA=&fill_threelett_RNA();\nm\ +y %onelett_DNA=&fill_onelett_DNA();\nmy %threelett\ +_DNA=&fill_threelett_DNA();\n\n\n\n\n\nmy %onelett\ + = (\n'P' => \\%onelett_prot,\n'D' => \\%onelett_D\ +NA,\n'R' => \\%onelett_RNA\n);\n\n\nmy %threelett \ += (\n'P' => \\%threelett_prot,\n'D' => \\%threelet\ +t_DNA,\n'R' => \\%threelett_RNA\n);\n\n\n\n\n\n\n\\ +nif($ARGV[0]=~/help/ ||$ARGV[0]=~/man/ || $ARGV[0]\ +=~/HELP/ || $ARGV[0]=~/Man/ || $ARGV[0] eq \"-h\" \ + || $ARGV[0] eq \"-H\" )\n{die \"SYNTAX: extract_\ +from_pdb Version $VersionTag \n Minimum: \ + [extract_from_pdb file] \n OR \n [.\ +.. | extract_from_pdb]\n Flags (Default setting o\ +n the first line)\n -version...................\ +[Returns the Version Number]\n -force...\ +..................[Forces the file to be treated l\ +ike a PDB file]\n \ + [Regenerates the header and SEQRES fields]\n \ + -force_name................[Forces the f\ +ile to be named after name]]\n -infile..\ +...file...........[Flag can be omited]\n \ + [File must be pdb or fro pgm]\n \ + [File can also be compre\ +ssed Z or gz]\n \ + [In the case of a compressed file, you can omit\ + the gz|Z extension]\n -netfile.........\ +..........[File will be fetch from the net using w\ +get]\n [wget \ +or curl must be installed]\n \ + [ftp://ftp.gnu.org/pub/gnu/wget/]\\ +n [http://cur\ +l.haxx.se/]\n \ + [Must also be used to retrieve the file from a lo\ +cal pdb copy (cf netaddress)]\n -netaddr\ +ess................[Address used for the retrievin\ +g the netfile]\n \ + [http://www.rcsb.org/pdb/cgi/export.cgi/%%.pdb\ +.gz?format=PDB&pdbId=%%&compression=gz]\n \ + [http://www.expasy.ch\ +/cgi-bin/get-pdb-entry.pl?%%]\n \ + [local -> will get the file fro\ +m pdb_dir (see pdb_dir)]\n -netcompressi\ +on............[Extension if the netfile comes comp\ +ressed]\n [gz\ +]\n -pdb_dir...................[address \ +of the repertory where the pdb is installed]\n \ + [Supports standa\ +rd ftp style installation OR every stru in DIR]\n \ + [Give the ...\ +./pdb/structure/ dir]\n \ + [If value omitted, the pg gets it from \ +the env variable PDB_DIR]\n -netcompress\ +ion_pg.........[gunzip]\n -is_pdb_name..\ +........name.[Returns 1 if the name is a PDB ID, 0\ + otherwise]\n -model_type...........name\ +.[Returns the model type if valid PDB name]\n \ + -is_released_pdb_name name.[Returns 1 if the\ + name corresponds to a released PDB file]\n \ + -get_pdb_chains.....name...[Returns the list o\ +f chains corresponding to the entry]\n -\ +get_pdb_id.........name...[Returns the PDB id with\ +in the provided pdb file]\n -get_fugue_n\ +ame.....name...[Turns a name into a name valid for\ + fugue]\n [Us\ +es the netaddress to do so]\n -chain......FIRST\ +..........[Extract the first chain only]\n \ + A B C..........[Extract Several chains if needed]\ +\n ALL............[Extract all the chains]\ + \n -ligand.....ALL............[Extract \ +the ligands in the chain (HETATM)]\n \ + ,[Extract All the named lig\ +nds]\n -ligand_only...............[Extract only\ + the ligands]\n -ligand_list............\ +...[Extract the list of ligands]\n -coor.......\ +...[Coordinates of the fragment to ext\ +ract]\n [Omit end to include the C\ +ter]\n -num........absolute.......[absol\ +ute: relative to the seq] \n \ + file...........[file: relative to file]\n \ + -num_out....new............[new: start 1->L]\n \ + old............[old: keep th\ +e file coordinates]\n -delete........[Delete from residue start to residue end\ +]\n -atom.......CA.............[Atoms to includ\ +e, ALL for all of them]\n CA O N.........[\ +Indicate several atoms if needed]\n -code......\ +.3..............[Use the 1 letter code or the 3 le\ +tters code]\n -mode.......raw............[Outpu\ +t original pdb file]\n pdb..\ +..........[Output something that looks like pdb]\n\ + fasta..........[Output the sequences in f\ +asta format]\n simple.........[Output a fo\ +rmat easy to parse in C ]\n -seq_field.\ +.ATOM...........[Field used to extract the sequenc\ +e]\n SEQRES.........[Use the complete sequ\ +ence]\n -seq.......................[Equivalent \ +to -mode fasta]\n -model......1..............[\ +Chosen Model in an NMR file]\n -nodiagno\ +stic..............[Switches Error Messages off]\n \ + -debug.....................[Sets the DEB\ +UG ON]\n -no_remote_pdb_dir.........[Do \ +not look for a remote file]\n -cache_pdb\ +.................[Cache Value, default is $HOME/.t\ +_coffee/cache, other values: NO<=> No cache]\n\n \ + Environement Variables\n These varia\ +bles can be set from the environement\n \ +Command line values with the corresponding flag su\ +perseed evironement value\n NO_REMOTE_PD\ +B_DIR..........[Prevents the program from searchin\ +g remote file: faster]\n PDB_DIR........\ +............[Indicates where PDB file must be fetc\ +hed (localy)]\n\n PROBLEMS: please contact cedric\ +.notredame\\@europe.com\\n\";\n exit ($EXIT_SUCCE\ +SS);\n}\n\n$np=0;\n$n_para=$#ARGV;\n$model=1;\n$pd\ +b_dir=$ENV{'PDB_DIR'};if ($pdb_dir){$pdb_dir.=\"/\\ +";}\n$debug=$ENV{'DEBUG_EXTRACT_FROM_PDB'};\n\n$no\ +_remote_pdb_dir=$ENV{NO_REMOTE_PDB_DIR};\n$HOME=$E\ +NV{'HOME'};\nif ( $ENV{CACHE_4_TCOFFEE})\n{$cache=\ +$ENV{CACHE_4_TCOFFEE};}\nelse\n{\n $cache=\"$HO\ +ME/.t_coffee/cache/\";\n}\n\n \n$netaddress=\"ht\ +tp://www.rcsb.org/pdb/files/%%.pdb.gz\";\n$netcomp\ +ression_pg=\"gunzip\";\n$netcompression=\"gz\";\n\\ +nforeach ($np=0; $np<=$n_para; $np++)\n { \ +\n $value=$ARGV[$np];\n \n if ($np==0 && \ +!($value=~/^-.*/))\n { \n $pdb_file= $ARGV[$n\ +p];\n }\n elsif ( !($value=~/^-.*/))\n \ + {\n print \"@ARGV\";\n die;\n } \n \n \ + elsif ($value eq \"-nodiagnostic\"){$nodiagnostic\ +=1;}\n elsif ($value eq \"-force\")\n {\n \ +$force_pdb=1;\n }\n elsif ($value eq \"-fo\ +rce_name\")\n {\n $force_name=$ARGV[++$np];\n\ + $force_pdb=1;\n }\n \n elsif ($value e\ +q \"-is_pdb_name\")\n {\n $pdb_file= $ARGV[++\ +$np]; \n $is_pdb_name=1; \n } \n elsif ($v\ +alue eq \"-is_released_pdb_name\")\n {\n $pdb\ +_file= $ARGV[++$np]; \n $is_released_pdb_name=1;\n\ + }\n elsif ($value eq \"-model_type\")\n \ + {\n $pdb_file= $ARGV[++$np]; \n $model_type=1;\ +\n }\n elsif ($value eq \"-debug\")\n{\n $\ +debug=1;\n}\n elsif ($value eq \"-get_pdb_chain\ +s\")\n{\n $pdb_file= $ARGV[++$np];\n $get_pdb_chai\ +ns=1;\n}\n elsif ($value eq \"-get_pdb_ligands\\ +")\n{\n $get_pdb_ligands=1;\n}\n \n elsif ($\ +value eq \"-get_pdb_id\")\n{\n $pdb_file= $ARGV[++\ +$np];\n $get_pdb_id=1;\n \n}\n \n elsif ( $v\ +alue eq \"-get_fugue_name\")\n{\n $pdb_file= $ARGV\ +[++$np];\n $get_fugue_name=1;\n}\n elsif ( $val\ +ue eq \"-infile\")\n{\n $pdb_file= $ARGV[++$\ +np];\n} \n elsif ($value eq \"-netfile\")\n{\n \ +$netfile=1;\n if ( !($ARGV[$np+1]=~/^-.*/)){$pdb_f\ +ile= $ARGV[++$np];}\n}\n elsif ( $value eq \"-\ +num\")\n{\n $numbering= $ARGV[++$np];\n}\n \ + elsif ( $value eq \"-num_out\")\n{\n $num\ +bering_out= $ARGV[++$np];\n}\n elsif ( $value e\ +q \"-netaddress\")\n{\n $netadress=$ARGV[++$np];\n\ +}\n \n elsif ( $value eq \"-netcompression\\ +")\n{\n $netcompression=$ARGV[++$np];\n}\n els\ +if ( $value eq \"-pdb_dir\")\n{\n if ( !($ARGV[$n\ +p+1]=~/^-.*/)){$pdb_dir= \"$ARGV[++$np]/\";}\n}\n \ + elsif ( $value eq \"-no_remote_pdb_dir\")\n{\n\ + $no_remote_pdb_dir=1;\n if ( !($ARGV[$np+1]=~/^-.\ +*/)){$pdb_dir= \"$ARGV[++$np]/\";}\n}\n elsif (\ + $value eq \"-cache\")\n{\n $cache=$ARGV[++$np];\n\ +}\n \n elsif ($value eq \"-netcompression_pg\ +\")\n{\n $netcompression_pg=$ARGV[++$np];\n}\n \ + elsif ($value eq \"-mode\")\n{\n $MODE=$A\ +RGV[++$np];\n}\n\n elsif ( $value eq \"-model\"\ +)\n{\n $model= $ARGV[++$np];\n}\n elsif (\ +$value eq \"-seq_field\" )\n{\n $seq_field= \ +$ARGV[++$np];\n} \n elsif ($value eq \"-coor\\ +" )\n{\n $start= $ARGV[++$np];\n \n i\ +f (($ARGV[$np+1] eq \"\") ||($ARGV[$np+1]=~/^-.*/)\ +){$end=\"*\";} \n else {$end= $ARGV[++$np]\ +;} \n $coor_set=1;\n}\n elsif ($value\ + eq \"-delete\" )\n{\n $delete_start= $ARGV[\ +++$np];\n $delete_end= $ARGV[++$np];\n \ + $delete_set=1;\n}\n elsif ($value eq \"-code\\ +")\n{\n $code= $ARGV[++$np];\n}\n elsif \ +($value eq \"-no_hetatm\")\n{\n $no_hetatm=1\ +;\n}\n elsif ($value eq \"-chain\")\n{\n \ +while (!($ARGV[$np+1] eq \"\") &&!($ARGV[$np+1]=~/\ +^-.*/))\n{\n ++$np;\n @c_chain=(@chain\ +, $ARGV[$np]);\n $hc_chain{$ARGV[$np]}=$#c_\ +chain+1;\n} \n}\n elsif ($value eq \"\ +-atom\")\n{\n\n while (!($ARGV[$np+1] eq \"\\ +") && !($ARGV[$np+1]=~/^-.*/))\n{\n ++$np;\n\ + $atom[$n_atom++]= $ARGV[$np];\n $ato\ +m_list{$ARGV[$np]}=1; \n} \n \n}\n \ +elsif ( $value eq \"-unfold\")\n{\n $unfold=1;\n}\\ +n elsif ($value eq \"-seq\" ||$value eq \"-fast\ +a\" )\n{\n $MODE=\"fasta\";\n}\n elsif ( \ +$value eq \"-version\")\n{\n print STDERR \"\\nex\ +tract_from_pdb: Version $VersionTag\\n\";\n &myexi\ +t ($EXIT_SUCCESS);\n}\n elsif ( $value eq \"-li\ +gand\")\n{\n while (!($ARGV[$np+1] eq \"\") && !($\ +ARGV[$np+1]=~/^-.*/))\n{\n ++$np;\n $ligan\ +d=1;\n $ligand_list{$ARGV[$np]}=1; \n} \\ +n $hc_chain{'LIGAND'}=1;\n}\n elsif ( $value eq\ + \"-ligand_only\")\n{\n $ligand_only=1;\n}\n}\nif \ +( $debug)\n{\n print STDERR \"\\n[DEBUG:extract\ +_from_pdb] NO_REMOTE_PDB_DIR: $no_remote_pdb_dir\\\ +n\";\n print STDERR \"\\n[DEBUG:extract_from_pd\ +b] PDB_DIR: $pdb_dir\\n\";\n}\n\n\nif ( $is_pdb_na\ +me)\n {\n if (&remote_is_pdb_name($pdb_file))\\ +n {\n print \"1\";\n }\n else\n \ +{\n print \"0\";\n }\n exit ($EXIT_SUCCESS\ +);\n }\n\nif ( $is_released_pdb_name)\n {\n \\ +n if (&is_released($pdb_file))\n {\n print\ + \"1\";\n }\n else\n {\n print \"0\";\ +\n }\n exit ($EXIT_SUCCESS);\n }\nif ($mo\ +del_type)\n {\n \n printf \"%s\", &pdb2model\ +_type($pdb_file);\n exit ($EXIT_SUCCESS);\n \ +\n }\n \n\nif (!$force_name)\n{\n $pdb_file\ +=~/([^\\/]*)$/;\n $force_name=$1;\n}\n\n$local_\ +pdb_file=$pdb_file;\n\nif ( $debug){print STDERR \\ +"\\n[DEBUG: extract_from_pdb] Scan For $local_pdb_\ +file\\n\";}\n\n$mem=$no_remote_pdb_dir;\n$no_remot\ +e_pdb_dir=1;\n$tmp_pdb_file=get_pdb_file ($local_p\ +db_file);\n\nif ( !-e $tmp_pdb_file || $tmp_pdb_fi\ +le eq \"\")\n {\n $local_pdb_file=$pdb_file;\n\ + ($local_pdb_file, $suffix_chain)=&pdb_name2nam\ +e_and_chain($local_pdb_file);\n\n if ($local_pd\ +b_file)\n {\n if ( $debug){print STDERR \"\\n\ +Split $pdb_file into $local_pdb_file and $suffix_c\ +hain \\n\";}\n $tmp_pdb_file=get_pdb_file ($local_\ +pdb_file);\n if ( $tmp_pdb_file ne \"\")\n {\n \ + @c_chain=();\n @c_chain=($suffix_chain);\n \ + %hc_chain=();\n $hc_chain{$suffix_chain}=1\ +;\n }\n }\n }\n\n$no_remote_pdb_dir=$mem;\\ +nif ($no_remote_pdb_dir==0)\n {\n \n if ( !\ +-e $tmp_pdb_file || $tmp_pdb_file eq \"\")\n \ +{\n \n $local_pdb_file=$pdb_file;\n ($local_pdb_fi\ +le, $suffix_chain)=&pdb_name2name_and_chain($local\ +_pdb_file);\n if ($local_pdb_file)\n {\n \n \ + if ( $debug){print STDERR \"\\nSplit $pdb_file\ + into $local_pdb_file and $suffix_chain \\n\";}\n \ + \n $tmp_pdb_file=get_pdb_file ($local_pdb_\ +file); \n \n if ( $tmp_pdb_file ne \"\"\ +)\n {\n @c_chain=();\n @c_chain=($suffix_c\ +hain);\n %hc_chain=();\n $hc_chain{$suffix_chain\ +}=1;\n }\n }\n }\n }\n\nif ( $debug)\ +{print STDERR \"\\n$pdb_file copied into ##$tmp_pd\ +b_file##\\n\";}\n\nif ( !-e $tmp_pdb_file || $tmp_\ +pdb_file eq \"\")\n{\n if ($is_pdb_name)\n{\n \ +print \"0\\n\"; exit ($EXIT_SUCCESS);\n}\n else\n{\ +\n \n print \"\\nEXTRACT_FROM_PDB: NO RESULT \ +for $pdb_file\\n\";\n &myexit ($EXIT_SUCCESS);\ + \n}\n}\n\n\n\n\n%molecule_type=&pdbfile2chaintype\ +($tmp_pdb_file);\nif ( $debug){print STDERR \"\\n\\ +\tSequence Type determined\\n\";}\n\n$pdb_id=&get_\ +pdb_id ($tmp_pdb_file);\nif ( $debug){print STDERR\ + \"\\n\\tID: $pdb_id (for $tmp_pdb_file)\\n\";}\n\\ +nif ( $pdb_id eq \"\"){$pdb_id=$force_name;}\n\n@f\ +_chain=&get_chain_list ($tmp_pdb_file);\nif ( $deb\ +ug){print STDERR \"\\n\\tChain_list:@f_chain\\n\";\ +}\n\nif ( $get_pdb_chains)\n{\n print \"@f_chai\ +n\\n\";\n &myexit ($EXIT_SUCCESS);\n}\nif ( $ge\ +t_pdb_ligands)\n{\n %complete_ligand_list=&get_\ +ligand_list ($tmp_pdb_file);\n print $complete_\ +ligand_list{\"result\"};\n &myexit ($EXIT_SUCCE\ +SS);\n}\n\nelsif ( $get_pdb_id ||$get_fugue_name )\ +\n{\n if (@c_chain && $c_chain[0] eq \"FIRST\ +\"){$pdb_id=$pdb_id.$f_chain[0];}\n elsif (@c_c\ +hain && $c_chain[0] ne \" \"){$pdb_id=$pdb_id.$c_c\ +hain[0];}\n \n print \"$pdb_id\\n\";\n &m\ +yexit ($EXIT_SUCCESS);\n \n}\nelsif ( $is_pdb_n\ +ame)\n{\n printf \"1\\n\";\n &myexit ($EXIT_\ +SUCCESS);\n}\n\n\n\n$structure_file=vtmpnam();\n\n\ +if ( $debug){print STDERR \"\\n\\tCheck_point #1: \ +$tmp_pdb_file $structure_file\\n\";}\n\n$INFILE=v\ +fopen (\"$tmp_pdb_file\", \"r\"); \n$TMP=vfopen (\\ +"$structure_file\", \"w\");\n\n$print_model=1;\n$i\ +n_model=0;\n\nif ( $debug){print STDERR \"\\n\\tCh\ +eck_point #2\\n\";}\nwhile ( <$INFILE>)\n{\n my $\ +first_model=0;\n $line=$_;\n\n if ( !$first_mode\ +l && ($line =~/^MODEL\\s*(\\d*)/))\n {\n $\ +first_model=$1;\n if ($model==1){$model=$firs\ +t_model;}\n }\n \n if (($line =~/^MODEL\\s*(\\ +\d*)/))\n {\n if ($1==$model)\n {\n $in_\ +model=1;\n $print_model=1;\n $is_nmr=1;\n }\n \ + elsif ( $in_model==0)\n {\n $print_model=0;\ +\n }\n elsif ( $in_model==1)\n {\n last;\n \ +}\n }\n if ($print_model){print $TMP $line;} \ +\n}\nclose ($TMP);\nclose ($INFILE);\n\nif ( $debu\ +g){print STDERR \"\\n\\tCheck_point #3\\n\";} \n\n\ + if ($numbering eq \"\"){$numbering=\"absolute\";\ +}\n if ($numbering_out eq \"\"){$numbering_out=\"\ +new\";}\n\n if ( $delete_set && $coor_set) {die \\ +"-delete and -coor are mutually exclusive, sorry\\\ +n\";}\n if ( $n_atom==0){$atom_list[$n_atom++]=\"\ +ALL\";$atom_list{$atom_list[0]}=1;}\n if ( $seq_f\ +ield eq \"\"){$seq_field=\"ATOM\";}\n \n if ( $M\ +ODE eq \"\"){$MODE=\"pdb\";}\n elsif ( $MODE eq \\ +"simple\" && $code==0){$code=1;}\n\n if ( $code==\ +0){$code=3;}\n\n\nif ($f_chain[0] eq \" \"){$hc_ch\ +ain{' '}=1;$c_chain[0]=\" \";}\nelsif (!@c_chain){\ +$hc_chain{FIRST}=1;$c_chain[0]=\"FIRST\";}#make su\ +re the first chain is taken by default\n\nif ($\ +hc_chain{ALL}) \n{\n @c_chain=@f_chain;\n \ + foreach $e (@c_chain){$hc_chain{$e}=1;}\n}\nelsi\ +f($hc_chain{FIRST})\n{\n @c_chain=($f_chain[0]);\n\ + $hc_chain{$f_chain[0]}=1;\n}\n\n\n$MAIN_HOM_CODE=\ +&get_main_hom_code ($structure_file);\n$INFILE=vfo\ +pen ($structure_file, \"r\");\n\n\nif ( $MODE eq \\ +"raw_pdb\" || $MODE eq \"raw\")\n{\n while (<$I\ +NFILE>)\n{ print \"$_\";}\n close ( $INFILE);\n\ + &myexit($EXIT_SUCCESS);\n} \nif ( $MODE eq \ +\"raw4fugue\" )\n{\n while (<$INFILE>)\n{ \n $l\ +=$_;\n if ($l=~/^SEQRES/)\n{\n \n $c= subs\ +tr($l,11,1);\n if ($hc_chain {$c}){print \"$l\\ +";}\n}\n elsif ( $l=~/^ATOM/)\n{\n $c=substr($\ +l,21,1);\n if ($hc_chain {$c}){print \"$l\";}\\ +n}\n}\n close ( $INFILE);\n &myexit($EXIT_SU\ +CCESS);\n} \n\nif ( $MODE eq \"pdb\")\n{\n\n \ + $read_header=0;\n while (<$INFILE>) \n{\n \ +$line=$_;\n if ($line =~ /^HEADER/){print \\ +"$line\";$read_header=1;}\n}\n close ($INFILE);\ +\n\n if (!$read_header)\n{\n print \"HEADER \ +UNKNOWN 00-JAN-00 \ + $force_name\\n\";\n}\n\n $INFILE=vfopen ($str\ +ucture_file, \"r\");\n \n print \"COMPND 1\ + CHAIN:\";\n $last=pop(@c_chain);\n foreach \ +$c ( @c_chain){ print \" $c,\";}\n if ( $last e\ +q \" \"){print \" NULL;\\n\";}\n else \n{\n \ + print \" $last;\\n\";\n}\n @c_chain=(@c_chain\ +, $last);\n \n print \"REMARK Output of the \ +program extract_from_pdb (Version $VersionTag)\\n\\ +";\n print \"REMARK Legal PDB format not Guaran\ +teed\\n\";\n print \"REMARK This format is not \ +meant to be used in place of the PDB format\\n\";\\ +n print \"REMARK The header refers to the origi\ +nal entry\\n\";\n print \"REMARK The sequence f\ +rom the original file has been taken in the field:\ + $seq_field\\n\";\n print \"REMARK extract_from\ +_pdb, 2001, 2002, 2003, 2004, 2005 2006 (c) CNRS a\ +nd Cedric Notredame\\n\"; \n if ( $coor_set)\\ +n{\n print \"REMARK Partial chain: Start $st\ +art End $end\\n\";\n}\n if ( $is_nmr)\n{\n \ + print \"REMARK NMR structure: MODEL $model\\n\";\ +\n}\n \n if ( $n_atom!=0)\n{\n print \"\ +REMARK Contains Coordinates of: \";\n foreac\ +h $a (@atom){print \"$a \";}\n print \"\\n\"\ +;\n} \n}\n\n\n\n\nmy $residue_index = -999;\nmy $\ +old_c = \"TemporaryChain\";\n\nwhile (<$INFILE>) \\ +n{\n $line=$_;\n\n\n if ($line =~ /^SEQRES/)\n{\n\\ +n @field=/(\\S*)\\s*/g;\n\n $c= substr($_,11,1);\ +\n\n \n $l=$#field;\n for ($a=4; $a<$#field ;)\\ +n{\n if (!$onelett{$molecule_type{$c}}->{$field[\ +$a]})\n{\n splice @field, $a, 1;\n}\n else \n\ +{\n $a++;\n}\n}\n \n if ( $c ne $in_chain)\n{\\ +n $pdb_chain_list[$n_pdb_chains]=$c;\n $pdb_ch\ +ain_len [$n_pdb_chains]=$len;\n $in_chain=$c;\n \ + $n_pdb_chains++;\n}\n \n for ( $a=4; $a<$#field\ +;$a++)\n{\n @{$complete_seq{$c}}->[$complete_seq\ +_len{$c}++]=$field[$a];\n}\n}\n elsif ( $line=~\ +/^ATOM/ || ($line=~/^HETATM/ && &is_aa(substr($lin\ +e,17,3),substr($line,21,1)) && !$no_hetatm))\n{\n\\ +n \n $RAW_AT_ID=$AT_ID=substr($line,12,4);\n $\ +RES_ID=&is_aa(substr($line,17,3),substr($line,21,1\ +));\n $CHAIN=substr($line,21,1);\n\n $RES_NO=su\ +bstr($line,22,4);\n $HOM_CODE=substr ($line, 26, 1\ +);\n $TEMP=substr($line,60,6);\n \n $TEMP=~s/\\s//\ +g;\n $AT_ID=~s/\\s//g;\n $RES_ID=~s/\\s//g;\ +\n $RES_NO=~s/\\s//g;\n \n if ( $HOM_CODE \ +ne $MAIN_HOM_CODE){next;}\n elsif ( $already_read2\ +{$CHAIN}{$RES_ID}{$AT_ID}{$RES_NO}){next;}\n else{\ +$already_read2{$CHAIN}{$RES_ID}{$AT_ID}{$RES_NO}=1\ +;}\n \n \n if ($coor_set && $numbering eq \"file\"\ + && $residue_index ne $RES_NO)\n{\n \n if \ +( $RES_NO<=$start){$real_start{$CHAIN}++;}\n i\ +f ( $RES_NO<=$end){$real_end{$CHAIN}++;}\n}\n elsi\ +f ($numbering eq \"absolute\")\n{\n $real_star\ +t{$CHAIN}=$start;\n $real_end{$CHAIN}=$end;\n}\ +\n\n $KEY=\"ALL\";\n if ( $CHAIN ne \ +$in_atom_chain)\n{\n \n $pdb_atom_chain_list\ +[$n_pdb_atom_chains]=$c;\n $pdb_atom_chain_len [\ +$n_pdb_atom_chains]=$len;\n $in_atom_chain=$c;\n\ + $n_pdb_atom_chains++;\n}\n \n if ( $residue_ind\ +ex ne $RES_NO)\n{\n $residue_index = $RES_NO;\ +\n @{$atom_seq{$CHAIN}}->[$atom_seq_len{$CHAI\ +N}++]=$RES_ID;;\n}\n}\n\n}\nclose ($INFILE);\n\n\n\ +\n\n\n\n$INFILE=vfopen ($structure_file, \"r\");\n\ +foreach $c (@c_chain)\n{\n\n if ( $seq_field eq\ + \"SEQRES\"){@pdb_seq=@{$complete_seq{$c}};}\n els\ +if ( $seq_field eq \"ATOM\") {@pdb_seq=@{$atom_se\ +q{$c}};}\n \n\n $full_length=$l=$#pdb_seq+1;\n \n\ + if ( $real_end{$c}==\"*\"){$real_end{$c}=$full_le\ +ngth;}\n if ( $coor_set)\n{ \n\n if ( $real_\ +end{$c} < $l){splice @pdb_seq, $real_end{$c}, $l;}\ +\n if ( $real_start{$c} < $l){splice @pdb_seq, \ +0, $real_start{$c}-1;} \n $l=$#pdb_seq;\n\ +}\n\n elsif ( $delete_set)\n{\n splice @pdb_seq\ +, $delete_start, $delete_end-$delete_start+1;\n \ + $l=$#pdb_seq;\n}\n \n $new_fasta_name=\"$pdb_id$c\ +\";\n if ( $coor_set)\n{\n if ( $n_pdb_chains==\ +0){$new_fasta_name=\"$new_fasta_name$c\";}\n $n\ +ew_fasta_name= $new_fasta_name.\"\\_$start\\_$end\\ +";\n}\n \n if ( $MODE eq \"pdb\")\n{\n $nl=1\ +;\n $n=0;\n \n foreach $res ( @pdb_seq)\n\ + {\n if ( !$n)\n {\n \n printf \"SEQRES %3d \ +%1s %4d \", $nl,$c, $l;\n $nl++;\n }\n $re\ +s=~s/\\s//g;\n \n if ($code==1){ printf \ +\"%3s \",$onelett{$molecule_type{$c}}->{$res};}\n \ + elsif ($code==3){ printf \"%3s \",$res};\n \ + \n $n++; \n if ( $n==13){$n=0;pri\ +nt \"\\n\";}\n}\n if ( $n!=0){print \"\\n\"; $n=\ +0;}\n}\n elsif ( $MODE eq \"simple\")\n{\n print\ + \"# SIMPLE_PDB_FORMAT\\n\";\n if ( $new_fasta_n\ +ame eq \" \"){$new_fasta_name=\"dummy_name\";}\n \ + print \">$new_fasta_name\\n\";\n\n foreach $res\ + ( @pdb_seq)\n{\n print \"$onelett{$molecule\ +_type{$c}}->{$res}\";\n}\n print \"\\n\";\n}\n e\ +lsif ( $MODE eq \"fasta\")\n{\n $n=0;\n print \ +\">$new_fasta_name\\n\";\n \n foreach $res ( @\ +pdb_seq)\n{\n\n print \"$onelett{$molecule_t\ +ype{$c}}->{$res}\";\n $n++;\n i\ +f ( $n==60){print \"\\n\"; $n=0;}\n}\n print \"\\ +\n\"; \n}\n}\n\nif ( $MODE eq \"fasta\")\n{\n \ +&myexit($EXIT_SUCCESS);\n \n}\n\n \n $charcount\ +=0;\n $inchain=\"BEGIN\";\n $n=0;\n while (<$IN\ +FILE>) \n{\n $line=$_;\n \n if ($line =~\ +/^ATOM/ || ($line=~/^HETATM/))\n{\n $line_header\ +=\"UNKNWN\";\n $RES_ID=substr($line,17,3);\n $chai\ +n = substr($line,21,1);\n\n if ($line =~/^ATOM/)\n\ +{\n $line_header=\"ATOM\";\n $RES_ID=(&is_\ +aa($RES_ID,$chain))?&is_aa($RES_ID,$chain):$RES_ID\ +;\n}\n elsif ($line=~/^HETATM/ && ($ligand_list {$\ +RES_ID} ||$ligand_list {'ALL'} || !&is_aa($RES_ID,\ +$chain)))\n{\n $line_header=\"HETATM\";\n}\n e\ +lsif ($line=~/^HETATM/ && (&is_aa($RES_ID,$chain) \ +&& !$no_hetatm))\n{\n $line_header=\"ATOM\";\n\ + $RES_ID=&is_aa($RES_ID,$chain);\n}\n else\n{\\ +n next;\n}\n\n \n\n $X=substr($line,30,8); \ + \n $Y=substr($line,38,8);\n $Z=substr($line,46,8)\ +;\n $TEMP=substr($line,60,6);\n \n $RAW_AT_ID=$AT_\ +ID=substr($line,12,4);\n $CHAIN=substr($line,21,1)\ +;\n $RES_NO=substr($line,22,4);\n $HOM_CODE=substr\ + ($line, 26, 1);\n \n $X=~s/\\s//g;\n $Y=~s/\\s//g\ +;\n $Z=~s/\\s//g;\n $TEMP=~s/\\s//g;\n \n $AT_ID=~\ +s/\\s//g;\n $RES_ID=~s/\\s//g;\n $RES_NO=~s/\\s//g\ +;\n\n \n if ( $HOM_CODE ne $MAIN_HOM_CODE){next;}\\ +n elsif ( $already_read{$CHAIN}{$RES_ID}{$AT_ID}{$\ +RES_NO}){next;}\n else{$already_read{$CHAIN}{$RES_\ +ID}{$AT_ID}{$RES_NO}=1;}\n \n $KEY=\"ALL\";\n\n \ + if ( $RES_NO ==0){$start_at_zero=1;}\n\n $RES_\ +NO+=$start_at_zero; \n \n if ( $current_chain n\ +e $CHAIN)\n{\n $current_chain=$CHAIN;\n $p\ +os=$current_residue=0;\n $offset=($coor_set)?(\ +$real_start{$CHAIN}-1):0;\n if ( $seq_field\ + eq \"SEQRES\"){@ref_seq=@{$complete_seq{$CHAIN}};\ +}\n elsif ( $seq_field eq \"ATOM\") {@ref_seq\ +=@{$atom_seq{$CHAIN}};}\n}\n \n if ($current_resid\ +ue != $RES_NO)\n{\n $current_residue=$RES_NO;\\ +n if ( $seq_field eq \"SEQRES\"){$pos=$curr\ +ent_residue;}\n elsif ( $seq_field eq \"ATOM\"\ +){$pos++;}\n}\n \n \n if ($n_atom==0 || $atom_list\ +{$AT_ID}==1 || $atom_list{$KEY}==1)\n{ \n \n \ + $do_it=(!@c_chain || $hc_chain{$CHAIN} ||$hc_c\ +hain{'LIGAND'} );\n \n $do_it= ($do_it==1)\ + && ($coor_set==0 ||($pos>=$real_start{$CHAIN} && \ +$pos<=$real_end{$CHAIN}));\n $do_it= ($do_it==\ +1) && ($delete_set==0 || $pos<$delete_start ||$pos\ +>$delete_end );\n if ($ligand==0 && $line_head\ +er eq \"HETATM\" ){$do_it=0;}\n if ($ligand_on\ +ly==1 && $line_header eq \"ATOM\" ){$do_it=0;}\n \ + if ($ligand==1 && $line_header eq \"HETATM\" &&\ + $ligand_list{$RES_ID}==0 && $ligand_list{\"ALL\"}\ +==0){$do_it=0;} \n \n \n if ( $do_it)\\ +n{\n $n++;\n $out_pos=$pos;\n \n if ( $d\ +elete_set)\n{\n if ( $out_pos< $delete_start){;\ +}\n else {$offset=$delete_end-$delete_start;}\n\ +} \n \n if ( $numbering_out eq\ + \"new\"){$out_pos-=$offset;}\n elsif ( $nu\ +mbering_out eq \"old\"){$out_pos=$RES_NO;}\n \ + \n \n \n if ( $code==1){$RES\ +_ID=$onelett{$molecule_type{$c}}->{$RES_ID};}\n \ + \n if ($unfold)\n{\n $unfolded_x+=5;\\ +n $X=$unfolded_x;\n $Y=0;\n $Z=0;\n \ + $float=1;\n}\n else\n{\n $float=3;\n}\ +\n\n if ( $MODE eq \"pdb\")\n{\n printf\ + \"%-6s%5d %-4s %3s %s%4d %8.3f%8.3f%8.3f 1.00\ + %5.2f\\n\",$line_header, $n, $RAW_AT_ID,$RES_ID,$\ +CHAIN,$out_pos, $X, $Y, $Z,$TEMP; \n}\n \ +elsif ( $MODE eq \"simple\")\n{\n if ( $RES_I\ +D eq \"\"){$RES_ID=\"X\";}\n printf \"%-6s %5s \ +%s %2s %4d %8.3f %8.3f %8.3f\\n\",$line_header,\ + $AT_ID, $RES_ID,($CHAIN eq\"\" || $CHAIN eq \" \"\ +)?\"A\":$CHAIN,$out_pos, $X, $Y, $Z,$TEMP;\n}\n\n}\ +\n}\n}\n}\nprint \"\\n\";\nclose($INFILE);\n\n\nif\ + ( $error ne \"\") \n{$error=$error.\"\\nDiagnosti\ +c: SEQRES and the residues in ATOM are probably\ + Incompatible\\n\";\n $error=$error. \"Recomen\ +dation: Rerun with '-fix 1' in order to ignore the\ + SEQRES sequences\\n\";\n}\nif (!$nodiagnostic){pr\ +int STDERR $error;}\n&myexit ( $EXIT_SUCCESS);\n\n\ +sub is_released \n {\n my ($r);\n my $in=@_\ +[0];\n my $name=&remote_is_pdb_name ($in);\n \ + my $hold=&remote_is_on_hold($in);\n \n $r=(\ +$name && !$hold)?1:0;\n return $r;\n }\nsub re\ +mote_is_pdb_name \n{\n my $in=@_[0];\n my ($\ +ref_file, $pdb);\n my ($value,$value1,$value2);\ +\n\n if ( $in=~/[^\\w\\d\\:\\_]/){return 0;}\n \ + $ref_file=\"$cache/pdb_entry_type.txt\";\n \\ +n if ( !-e $ref_file || (-M $ref_file)>2 || -z \ +$ref_file)\n {\n &url2file(\"ftp://ftp.wwpdb.\ +org/pub/pdb/derived_data/pdb_entry_type.txt\", $re\ +f_file);\n }\n $pdb=substr ($in,0, 4);\n \ + chomp(($value1=`grep -c $pdb $ref_file`));\n \ +$pdb=lc($pdb);\n chomp(($value2=`grep -c $pdb $\ +ref_file`));\n $value=($value1 || $value2)?1:0;\ +\n $value=($value>0)?1:0;\n \n return $va\ +lue;\n }\n\nsub pdb2model_type\n{\n my $in=@_[\ +0];\n my ($ref_file, $pdb);\n my ($value, $r\ +et);\n\n if ( $in=~/[^\\w\\d\\:\\_]/){return 0;\ +}\n $ref_file=\"$cache/pdb_entry_type.txt\";\n \ + \n if ( !-e $ref_file || (-M $ref_file)>2 ||\ + -z $ref_file)\n {\n &url2file(\"ftp://ftp.ww\ +pdb.org/pub/pdb/derived_data/pdb_entry_type.txt\",\ + $ref_file);\n }\n $pdb=substr ($in,0, 4);\ +\n $pdb=lc($pdb);\n \n chomp(($value=`gre\ +p $pdb $ref_file`));\n \n $value=~/^\\S+\\s+\ +\\S+\\s+(\\S+)/;\n $ret=$1;\n if ( $ret eq\"\ +\"){return \"UNKNOWN\";}\n \n return $ret;\n\ + }\nsub remote_is_on_hold\n {\n my $in=@_[0];\ +\n my ($ref_file, $pdb);\n my ($value1, $val\ +ue2,$value);\n \n if ( $in=~/[^\\w\\d\\:\\_]\ +/){return 0;}\n $ref_file=\"$cache/unreleased.x\ +ml\";\n \n if ( !-e $ref_file || (-M $ref_fi\ +le)>2 || -z $ref_file)\n {\n &url2file(\"http\ +://www.rcsb.org/pdb/rest/getUnreleased\",$ref_file\ +);\n }\n \n $pdb=substr ($in,0, 4);\n \ + chomp(($value1=`grep -c $pdb $ref_file`));\n \ +$pdb=lc($pdb);\n chomp(($value2=`grep -c $pdb $\ +ref_file`));\n $value=($value1 || $value2)?1:0;\ +\n $value=($value>0)?1:0;\n return $value;\n\ + }\nsub is_pdb_file\n{\n my @arg=@_;\n\n if\ + ( !-e $arg[0]){return 0;}\n \n $F=vfopen ($\ +arg[0], \"r\");\n while ( <$F>)\n{\n if (/^HEAD\ +ER/)\n{\n close $F;\n return 1;\n}\n elsif\ + ( /^SEQRES/)\n{\n close $F;\n return 1;\n\ +}\n elsif ( /^ATOM/)\n{\n close $F;\n retu\ +rn 1;\n}\n}\n return 0;\n}\nsub get_pdb_id\n{\n\ + my $header_file=@_[0];\n my $id;\n my $F\ += new FileHandle;\n \n \n $F=vfopen (\"$h\ +eader_file\", \"r\");\n\n while ( <$F>)\n \ +{\n if ( /HEADER/)\n {\n if ($debug){print \\ +"$_\";}\n $id=substr($_,62,4 );\n return $\ +id;\n }\n }\n close ($F);\n \n ret\ +urn \"\";\n}\n\nsub get_ligand_list\n{\n my $pd\ +b_file=@_[0];\n my $chain;\n my $ligand;\n \ + my %complete_ligand_list;\n \n\n $F=vfopen\ + ($pdb_file, \"r\");\n while ( <$F>)\n{\n if ( \ +/^HETATM/)\n{\n $line=$_;\n $chain=substr(\ +$line,21,1);\n $ligand=substr($line,17,3);\n \ + \n if (!$complete_ligand_list{$chain}{$liga\ +nd})\n{\n \n $complete_ligand_list{\"result\"}.=\ +\"CHAIN $chain LIGAND $ligand\\n\";\n $complete_l\ +igand_list{$chain}{$ligand}=1;\n}\n}\n}\n close\ + ($F);\n return %complete_ligand_list;\n}\n\nsu\ +b get_chain_list \n{\n my $header_file;\n my\ + @chain_list;\n my @list;\n my $n_chains;\n \ + my %chain_hasch;\n my $pdb_file=@_[0];\n \ +my $c;\n my %hasch;\n my $chain;\n \n \n\ + $F=vfopen ($pdb_file, \"r\");\n while ( <$F\ +>)\n{\n\n\n if (/SEQRES\\s+\\d+\\s+(\\S+)/)\n {\\ +n $chain = substr($_,11,1);$chain=~s/\\s//g;if\ + ( $chain eq \"\"){$chain=\" \";}\n if (!$hasc\ +h{$chain}){$hasch{$chain}=1;push @chain_list, $cha\ +in;}\n }\n if (/^ATOM/ || /^HETATM/)\n {\n \ + $chain = substr($_,21,1); $chain=~s/\\s//g;if ( $\ +chain eq \"\"){$chain=\" \";}\n if (!$hasch{$c\ +hain}){$hasch{$chain}=1;push @chain_list, $chain;}\ +\n }\n }\n\n\nclose ($F);\nif (!@chain_list\ +)\n {\n @chain_list=(\"A\");\n }\n\n\nreturn \ +@chain_list;\n}\n\nsub token_is_in_list\n{\n\n \ +my @list=@_;\n my $a;\n \n for ($a=1; $a<\ +=$#list; $a++)\n{\n if ( $list[$a] eq $list[0]){re\ +turn $a;}\n}\n}\n\nsub pdb_name2name_and_chain \n{\ +\n my $pdb_file=@_[0];\n my $pdb_file_in;\n \ + my @array;\n my $chain;\n my $c;\n\n $\ +pdb_file_in=$pdb_file;\n\n $pdb_file=~/^(.{4})/\ +;$pdb_id=$1;\n @array=($pdb_file=~/([\\w])/g);\\ +n \n \n $chain=uc ($array[4]);\n $chain=($\ +chain eq \"\")?\"FIRST\":$chain;\n \n return\ + ( $pdb_id, $chain);\n\n if ( $#array==3){retur\ +n ($pdb_id, \"FIRST\");}\n elsif ( $#array<4){ \ +return ($pdb_id, \"\");}\n else {return ( $pdb_\ +id, $chain);}\n \n \n \n}\nsub get_main\ +_hom_code \n{\n my $pdb_file=@_[0];\n my %ho\ +m, $n, $best, $best_h;\n open (F, $pdb_file);\n\ + while ()\n{\n if ( $_=~/^ATOM/)\n{\n $h\ +=substr ($_,26, 1);\n $n=++$hom{$h};\n if \ +($n>$best)\n{\n $best=$n;\n $best_h=$h;\n}\n}\n}\ +\n close (F);\n return $best_h;\n}\n\n\nsub \ +get_pdb_file \n{\n my ($pdb_file_in)=(@_);\n \ + my $result;\n my @letter;\n my @chain;\n \ + my $v;\n my $pdb_file=$pdb_file_in;\n\n $pd\ +b_file=($pdb_file_in=~/\\S+_S_(\\S+)/)?$1:$pdb_fil\ +e_in;\n \n if ($no_remote_pdb_dir==0)\n \ + {\n $no_remote_pdb_dir=1;\n $result=get_pdb_file3\ + ($pdb_file);\n $no_remote_pdb_dir=0;\n if ( $resu\ +lt){return $result;}\n else\n {\n \n lc \ +($pdb_file);\n $result=get_pdb_file3($pdb_file\ +);\n return $result;\n }\n }\n else\ +\n {\n return get_pdb_file3 ($pdb_file);\n \ + }\n \n }\n\nsub get_pdb_file3 \n{\n my $\ +pdb_file_in=@_[0];\n my $result;\n my @lette\ +r;\n my @chain;\n my $lcfile;\n my $ucfil\ +e;\n my $pdb_file=$pdb_file_in;\n \n $lcf\ +ile=lc $pdb_file;\n $ucfile=uc $pdb_file;\n\n \ + if ( ($result=get_pdb_file2 ($pdb_file))){return\ + $result;}\n \n\n if ($lcfile ne $pdb_file &\ +& ($result=get_pdb_file2 ($lcfile))){return $resul\ +t;}\n if ($ucfile ne $pdb_file && ($result=get_\ +pdb_file2 ($ucfile))){return $result;}\n \n \\ +n \n return \"\";\n}\nsub get_pdb_file2\n{\n\ + my $pdb_file=@_[0];\n my $return_value;\n \ + \n $return_value=\"\";\n \n if ( ($resu\ +lt=get_pdb_file1 ($pdb_file))){$return_value=$resu\ +lt;}\n elsif ( !($pdb_file=~/\\.pdb/) && !($pdb\ +_file=~/\\.PDB/))\n{\n if ( ($result=get_pdb_file1\ + (\"$pdb_file.pdb\"))){$return_value=$result;}\n e\ +lsif ( ($result=get_pdb_file1 (\"$pdb_file.PDB\"))\ +){$return_value=$result;}\n\n elsif ( ($result=get\ +_pdb_file1 (\"pdb$pdb_file.pdb\"))){$return_value=\ +$result;} \n elsif ( ($result=get_pdb_file1 (\"pdb\ +$pdb_file.PDB\"))){$return_value=$result;}\n elsif\ + ( ($result=get_pdb_file1 (\"PDB$pdb_file.PDB\")))\ +{$return_value=$result;}\n elsif ( ($result=get_pd\ +b_file1 (\"PDB$pdb_file.pdb\"))){$return_value=$re\ +sult;}\n \n \n elsif ( ($result=get_pdb_file1 (\"$\ +pdb_file.ent\"))){$return_value=$result;}\n elsif \ +( ($result=get_pdb_file1 (\"pdb$pdb_file.ent\"))){\ +$return_value=$result;}\n elsif ( ($result=get_pdb\ +_file1 (\"PDB$pdb_file.ent\"))){$return_value=$res\ +ult;}\n\n elsif ( ($result=get_pdb_file1 (\"$pdb_f\ +ile.ENT\"))){$return_value=$result;}\n elsif ( ($r\ +esult=get_pdb_file1 (\"pdb$pdb_file.ENT\"))){$retu\ +rn_value=$result;}\n elsif ( ($result=get_pdb_file\ +1 (\"PDB$pdb_file.ENT\"))){$return_value=$result;}\ +\n \n \n \n}\n return $return_value;\n}\n \n\ +sub get_pdb_file1\n{\n my ($pdb_file)=(@_);\n \ + my $return_value;\n \n\n $return_value=\"\\ +";\n if ( ($result=get_pdb_file0 ($pdb_file))){\ +$return_value=$result;}\n elsif ( ($result=get_\ +pdb_file0 (\"$pdb_file.Z\"))){$return_value=$resul\ +t;}\n elsif ( ($result=get_pdb_file0 (\"$pdb_fi\ +le.gz\"))){$return_value=$result;}\n elsif ( ($\ +result=get_pdb_file0 (\"$pdb_file.GZ\"))){$return_\ +value=$result;}\n return $return_value;\n}\nsub\ + get_pdb_file0 \n{ \n my ($pdb_file, $attempt)=\ +(@_);\n my $pdb_file=@_[0];\n my $tmp_pdb_fi\ +le; \n my $return_value;\n\n if ( !$attem\ +pt){$attempt=1;}\n \n $local_pdb_file=\"$pdb\ +_file\";\n if ( $local_pdb_file eq \"\")\n{\n $\ +tmp_pdb_file=vtmpnam();\n open F, \">$tmp_pdb_file\ +\";\n \n while (){print F \"$_\";}\n close \ +(F);\n \n if (-e $tmp_pdb_file && &is_pdb_file ( $\ +local_pdb_file))\n{return $tmp_pdb_file;}\n}\n\n \ + $local_pdb_file=\"$pdb_file\";\n &debug_print\ + (\"\\nTry access local file: $local_pdb_file\");\\ +n \n $local_pdb_file=&check_pdb_file4compres\ +sion ($local_pdb_file);\n if ( -e $local_pdb_fi\ +le && (&is_pdb_file ($local_pdb_file) || $force_pd\ +b))\n{\n &debug_print ( \"\\n\\tIs in Current Dir\\ +");\n $tmp_pdb_file=vtmpnam();\n `cp $local_pdb_fi\ +le $tmp_pdb_file`;\n return $tmp_pdb_file;\n}\n \ + else\n{\n &debug_print (\"\\n\\tFile Not in Curre\ +nt Dir\");\n}\n\n if ($pdb_file=~/^pdb/||$pdb_f\ +ile=~/^PDB/){$pdb_div=substr ($pdb_file, 4, 2);}\n\ + else\n{\n $pdb_div=substr ($pdb_file, 1, 2);\ +\n}\n $local_pdb_file=\"$pdb_dir/$pdb_div/$pdb_\ +file\";\n $local_pdb_file=&check_pdb_file4compr\ +ession ( $local_pdb_file);\n &debug_print (\"\\\ +nTry access file From PDB_DIR: $local_pdb_file\");\ +\n if ($pdb_dir && -e $local_pdb_file && &is_pd\ +b_file ($local_pdb_file))\n{\n &debug_print ( \"\\\ +n\\tIs in Local PDB DIR\");\n $tmp_pdb_file=vtmpna\ +m();\n `cp $local_pdb_file $tmp_pdb_file`;\n retur\ +n $tmp_pdb_file;\n}\n\n $local_pdb_file=\"$pdb_\ +dir/$pdb_file\";\n $local_pdb_file=&check_pdb_f\ +ile4compression ( $local_pdb_file);\n &debug_pr\ +int (\"\\nTry access file From PDB_DIR: local_pdb_\ +file\");\n if ($pdb_dir && -e $local_pdb_file &\ +& &is_pdb_file ($local_pdb_file))\n{\n &debug_prin\ +t ( \"\\n\\tIs in Local PDB DIR\");\n $tmp_pdb_fil\ +e=vtmpnam();\n `cp $local_pdb_file $tmp_pdb_file`;\ +\n return $tmp_pdb_file;\n}\n\n $local_pdb_file\ +=\"$pdb_dir$pdb_file\";\n $local_pdb_file=&chec\ +k_pdb_file4compression ( $local_pdb_file);\n &d\ +ebug_print (\"\\nTry access file From PDB_DIR: $lo\ +cal_pdb_file\");\n if ($pdb_dir && -e $local_pd\ +b_file && &is_pdb_file ($local_pdb_file))\n{\n &de\ +bug_print ( \"\\n\\tIs in Local PDB DIR\");\n $tmp\ +_pdb_file=vtmpnam();\n `cp $local_pdb_file $tmp_pd\ +b_file`;\n return $tmp_pdb_file;\n}\n else\n{&d\ +ebug_print ( \"\\n\\tNot In Local Pdb Dir\");}\n\n\ + if ($cache ne \"NO\" && $cache ne \"no\")\n{\n\ +\n $local_pdb_file=\"$cache/$pdb_file\";\n $local_\ +pdb_file=&check_pdb_file4compression ( $local_pdb_\ +file);\n &debug_print(\"\\nTry access file From Ca\ +che: $local_pdb_file\");\n if (-e $local_pdb_file \ +&& &is_pdb_file ($local_pdb_file))\n{\n &debug\ +_print ( \"\\n\\tIs in T-Coffee Cache\");\n $t\ +mp_pdb_file=vtmpnam();\n `cp $local_pdb_file $\ +tmp_pdb_file`;\n return $tmp_pdb_file;\n}\n el\ +se{&debug_print ( \"\\n\\tNot in Cache Dir\");}\n}\ +\n\nif (!$no_remote_pdb_dir) \n {\n my $value=\ +&is_released ($pdb_file);\n my $return_value=\"\ +\";\n if ($value==1)\n {\n \n &debug_print\ + (\"\\n*******************************************\ +**********\\nTry Remote Access for $pdb_file\");\n\ + $tmp_pdb_file=vtmpnam();\n $netcommand=$netaddres\ +s;\n $netcommand=~s/%%/$pdb_file/g;\n &url2file(\"\ +$netcommand\", \"$tmp_pdb_file.$netcompression\");\ +\n &debug_print(\"\\nREMOTE: $netcommand\\n\");\n \ +\n $compressed_tmp_file_name=\"$tmp_pdb_file.$netc\ +ompression\";\n \n if ($netcompression && -B $comp\ +ressed_tmp_file_name)\n {\n my $r;\n &de\ +bug_print (\"\\n\\tFile Found Remotely\");\n i\ +f (($r=safe_system ( \"$netcompression_pg $compres\ +sed_tmp_file_name\")!=$EXIT_SUCCESS) && $attempts<\ +5)\n {\n &debug_print (\"\\n\\tProper Downl\ +oad Failed Try again\");\n unlink $compressed_tmp\ +_file_name;\n print \"\\nFailed to Download $comp\ +ressed_tmp_file_name. New Attempt $attempt/5\\n\";\ +\n return &get_pdb_file0($pdb_file, $attempt+1);\\ +n }\n elsif ($r== $EXIT_SUCCESS)\n \ + {\n &debug_print (\"\\n\\tProper Download Succee\ +ded \");\n $return_value=$tmp_pdb_file;\n }\ +\n else\n {\n &debug_print (\"\\n\\tPro\ +per Download Failed \");\n &debug_print (\"\\nFil\ +e Not Found Remotely\");\n unlink $compressed_tmp\ +_file_name;\n }\n }\n else\n {\n\n &\ +debug_print (\"\\nFile Not Found Remotely\");\n \ + unlink $compressed_tmp_file_name;\n }\n #Updat\ +e cache if required\n if ($cache ne \"no\" && $cac\ +he ne \"update\" && -e $return_value)\n {\n \ +`cp $return_value $cache/$pdb_file.pdb`;\n #`t\ +_coffee -other_pg clean_cache.pl -file $pdb_file.p\ +db -dir $cache`;\n }\n }\n &debug_print \ +(\"\\nRemote Download Finished\");\n return $re\ +turn_value;\n }\nreturn \"\";\n}\n\nsub check_pdb\ +_file4compression \n{\n my $file=@_[0];\n my\ + $tmp;\n my $r;\n \n $tmp=&vtmpnam();\n \ + if (-e $tmp){unlink $tmp;}\n \n $file=~s/\\ +\/\\//\\//g;\n if (-B $file && ($file=~/\\.Z\ +/)) {`cp $file $tmp.Z`;`rm $tmp`;`gunzip $tmp.Z $S\ +ILENT`;$r=$tmp;}\n elsif (-B $file && ($file=~/\ +\\.gz/)){`cp $file $tmp.gz`;`gunzip $tmp.gz $SILEN\ +T`;return $r=$tmp;}\n elsif (-B $file ){`cp $fi\ +le $tmp.gz`;`gunzip $tmp.gz $SILENT`;$r=$tmp;}\n \ + elsif ( -e $file ) {$r= $file;}\n elsif ( -e \ +\"$file.gz\" ){ `cp $file.gz $tmp.gz`;`gunzip \ +$tmp.gz $SILENT`;$r=$tmp;} \n elsif ( -e \"$\ +file.Z\") {`cp $file.Z $tmp.Z`; `gunzip $tmp.Z $S\ +ILENT`;$r=$tmp;}\n else {$r= $file;}\n\n if\ + ( -e \"$tmp.Z\"){unlink \"$tmp.Z\";}\n if ( -e\ + \"$tmp.gz\"){unlink \"$tmp.gz\";}\n \n retu\ +rn $r;\n \n}\n\n\n\n\n\n \n\n\n\n\n\n\n\nsub\ + vfopen \n{\n my $file=@_[0];\n my $mode=@_[\ +1];\n my $tmp;\n my $F = new FileHandle;\n \ + \n \n $tmp=$file;\n \n \n if ( $mode\ + eq \"r\" && !-e $file){ myexit(flush_error (\"Can\ +not open file $file\"));}\n elsif ($mode eq \"w\ +\"){$tmp=\">$file\";}\n elsif ($mode eq \"a\"){\ +$tmp=\">>$file\";}\n \n \n open ($F,$tmp)\ +;\n return $F;\n}\nsub debug_print\n{\n my $\ +message =@_[0];\n if ($debug){print STDERR \"NO\ +_REMOTE_PDB_DIR: $no_remote_pdb_dir - $message [DE\ +BUG:extract_from_pdb]\";}\n return;\n}\nsub is_\ +aa \n{\n my ($aa, $chain) =@_;\n\n my $one;\\ +n my $trhee;\n \n if ( $onelett{$molecule\ +_type{$chain}}->{$aa} eq 'X' || !$onelett{$molecul\ +e_type{$chain}}->{$aa} ){return '';}\n else\n \ + {\n $one=$onelett{$molecule_type{$chain}}->{$a\ +a};\n\n $three=$threelett{$molecule_type{$chain}}-\ +>{$one};\n \n\n return $three;\n }\n }\n\n\n\ +\n\n\nsub url2file\n{\n my ($address, $out, $wg\ +et_arg, $curl_arg)=(@_);\n my ($pg, $flag, $r, \ +$arg, $count);\n \n if (!$CONFIGURATION){&ch\ +eck_configuration (\"wget\", \"INTERNET\", \"gzip\\ +");$CONFIGURATION=1;}\n \n if (&pg_is_instal\ +led (\"wget\")) {$pg=\"wget\"; $flag=\"-O\";$arg\ +=$wget_arg;}\n elsif (&pg_is_installed (\"curl\\ +")){$pg=\"curl\"; $flag=\"-o\";$arg=$curl_arg;}\n \ + return safe_system (\"$pg $flag$out $address >/\ +dev/null 2>/dev/null\");\n\n}\n\n\n\n\nsub pdbfile\ +2chaintype\n {\n my $file=@_[0];\n my %ct;\\ +n my $F;\n \n $F=vfopen ($file, \"r\");\n\ + while (<$F>)\n {\n my $line=$_;\n if ($li\ +ne =~/^ATOM/)\n {\n my $C=substr($line,21,1)\ +;\n if (!$ct{$C})\n { \n my $r=substr($\ +line,17,3);\n $r=~s/\\s+//;\n if (length ($r)==1\ +){$ct{$C}=\"R\";}\n elsif (length ($r)==2){$ct{$C\ +}=\"D\";}\n elsif (length ($r)==3){$ct{$C}=\"P\";\ +}\n else \n {\n myexit(flush_error(\"ERRO\ +R: Could not read RES_ID field in file $file\"));\\ +n }\n }\n }\n }\n close ($F);\n\ + return %ct;\n }\n \n \n\n\n\nsub fill_th\ +reelett_RNA\n{\n\n my %threelett=(\n 'A', ' A',\n\ + 'T', ' T',\n 'U', ' U',\n 'C', ' C',\n 'G', ' \ + G',\n 'I', ' I', #Inosine\n );\n \n return %thre\ +elett;\n\n}\n\n\nsub fill_onelett_RNA\n{\n my %o\ +nelett=(\n ' A' => 'A',\n ' T' => 'T',\n ' U' =\ +> 'U',\n ' C' => 'C',\n ' G' => 'G',\n 'CSL' => \ +'X',\n 'UMS' => 'X',\n ' I' => 'I',\n 'A' => 'A',\ +\n 'T' => 'T',\n 'U' => 'U',\n 'C' => 'C',\n 'G' =\ +> 'G',\n 'I' => 'I',\n );\n\n return %onelett;\n\n\ +}\n\n\nsub fill_onelett_DNA\n{\n my %onelett=(\n\ + ' DA', 'A',\n ' DT', 'T',\n ' DC', 'C',\n ' DG', \ +'G',\n 'DA', 'A',\n 'DT', 'T',\n 'DC', 'C',\n 'DG'\ +, 'G',\n );\n\n return %onelett;\n\n}\n\nsub fill_\ +threelett_DNA\n{\n\n my %threelett=(\n 'A', ' DA',\ +\n 'T', ' DT',\n 'C', ' DC',\n 'G', ' DG',\n );\n\\ +n return %threelett;\n\n}\n\n\n\n\nsub fill_threel\ +ett_prot\n{ \n my %threelett;\n\n %threelett=(\\ +n'A', 'ALA',\n'C', 'CYS',\n'D', 'ASP',\n'E', 'GLU'\ +,\n'F', 'PHE',\n'G', 'GLY',\n'H', 'HIS',\n'I', 'IL\ +E',\n'K', 'LYS',\n'L', 'LEU',\n'N', 'ASN',\n'M', '\ +MET',\n'P', 'PRO',\n'Q', 'GLN',\n'R', 'ARG',\n'S',\ + 'SER',\n'T', 'THR',\n'V', 'VAL',\n'W', 'TRP',\n'Y\ +', 'TYR',\n);\n\nreturn %threelett;\n\n\n}\n\nsub \ +fill_onelett_prot\n{\n my %onelett;\n \n \ +%onelett=(\n\n'10A', 'X',\n'11O', 'X',\n'12A', 'X'\ +,\n'13P', 'X',\n'13R', 'X',\n'13S', 'X',\n'14W', '\ +X',\n'15P', 'X',\n'16A', 'X',\n'16G', 'X',\n'1AN',\ + 'X',\n'1AP', 'X',\n'1AR', 'X',\n'1BH', 'X',\n'1BO\ +', 'X',\n'1C5', 'X',\n'1CU', 'X',\n'1DA', 'X',\n'1\ +GL', 'X',\n'1GN', 'X',\n'1IN', 'X',\n'1LU', 'L',\n\ +'1MA', 'X',\n'1MC', 'X',\n'1MG', 'X',\n'1MZ', 'X',\ +\n'1NA', 'X',\n'1NB', 'X',\n'1NI', 'X',\n'1PA', 'A\ +',\n'1PC', 'X',\n'1PE', 'X',\n'1PG', 'X',\n'1PI', \ +'A',\n'1PM', 'X',\n'1PN', 'X',\n'1PU', 'X',\n'1PY'\ +, 'X',\n'1UN', 'X',\n'24T', 'X',\n'25T', 'X',\n'26\ +P', 'X',\n'2AB', 'X',\n'2AM', 'X',\n'2AN', 'X',\n'\ +2AP', 'X',\n'2AR', 'X',\n'2AS', 'D',\n'2BL', 'X',\\ +n'2BM', 'X',\n'2CP', 'X',\n'2DA', 'X',\n'2DG', 'X'\ +,\n'2DP', 'X',\n'2DT', 'X',\n'2EP', 'X',\n'2EZ', '\ +X',\n'2FG', 'X',\n'2FL', 'X',\n'2FP', 'X',\n'2FU',\ + 'X',\n'2GL', 'X',\n'2GP', 'X',\n'2HP', 'X',\n'2IB\ +', 'X',\n'2IP', 'X',\n'2LU', 'L',\n'2MA', 'X',\n'2\ +MD', 'X',\n'2ME', 'X',\n'2MG', 'X',\n'2ML', 'L',\n\ +'2MO', 'X',\n'2MR', 'R',\n'2MU', 'X',\n'2MZ', 'X',\ +\n'2NO', 'X',\n'2NP', 'X',\n'2OG', 'X',\n'2PA', 'X\ +',\n'2PC', 'X',\n'2PE', 'X',\n'2PG', 'X',\n'2PH', \ +'X',\n'2PI', 'X',\n'2PL', 'X',\n'2PP', 'X',\n'2PU'\ +, 'X',\n'2SI', 'X',\n'2TB', 'X',\n'34C', 'X',\n'35\ +G', 'X',\n'3AA', 'X',\n'3AD', 'X',\n'3AH', 'H',\n'\ +3AN', 'X',\n'3AP', 'X',\n'3AT', 'X',\n'3BT', 'X',\\ +n'3CH', 'X',\n'3CN', 'X',\n'3CO', 'X',\n'3CP', 'X'\ +,\n'3DR', 'X',\n'3EP', 'X',\n'3FM', 'X',\n'3GA', '\ +X',\n'3GP', 'X',\n'3HB', 'X',\n'3HC', 'X',\n'3HP',\ + 'X',\n'3IB', 'X',\n'3ID', 'X',\n'3IN', 'X',\n'3MA\ +', 'X',\n'3MB', 'X',\n'3MC', 'X',\n'3MD', 'D',\n'3\ +MF', 'X',\n'3MP', 'X',\n'3MT', 'X',\n'3OL', 'X',\n\ +'3PA', 'X',\n'3PG', 'X',\n'3PO', 'X',\n'3PP', 'X',\ +\n'3PY', 'X',\n'49A', 'X',\n'4AB', 'X',\n'4AM', 'X\ +',\n'4AN', 'X',\n'4AP', 'X',\n'4BA', 'X',\n'4BT', \ +'X',\n'4CA', 'X',\n'4CO', 'X',\n'4HP', 'X',\n'4IP'\ +, 'X',\n'4MO', 'X',\n'4MV', 'X',\n'4MZ', 'X',\n'4N\ +C', 'X',\n'4NP', 'X',\n'4OX', 'X',\n'4PB', 'X',\n'\ +4PN', 'X',\n'4PP', 'X',\n'4SC', 'X',\n'4SU', 'X',\\ +n'4TB', 'X',\n'55C', 'X',\n'5AD', 'X',\n'5AN', 'X'\ +,\n'5AT', 'X',\n'5CM', 'X',\n'5GP', 'X',\n'5HP', '\ +E',\n'5HT', 'X',\n'5IT', 'X',\n'5IU', 'X',\n'5MB',\ + 'X',\n'5MC', 'X',\n'5MD', 'X',\n'5MP', 'X',\n'5MU\ +', 'X',\n'5NC', 'X',\n'5OB', 'X',\n'5PA', 'X',\n'5\ +PV', 'X',\n'6AB', 'X',\n'6CT', 'X',\n'6HA', 'X',\n\ +'6HC', 'X',\n'6HG', 'X',\n'6HT', 'X',\n'6IN', 'X',\ +\n'6MO', 'X',\n'6MP', 'X',\n'6PG', 'X',\n'6WO', 'X\ +',\n'70U', 'X',\n'7DG', 'X',\n'7HP', 'X',\n'7I2', \ +'X',\n'7MG', 'X',\n'7MQ', 'X',\n'7NI', 'X',\n'87Y'\ +, 'X',\n'8AD', 'X',\n'8BR', 'X',\n'8IG', 'X',\n'8I\ +N', 'X',\n'8OG', 'X',\n'95A', 'X',\n'9AD', 'X',\n'\ +9AM', 'X',\n'9AP', 'X',\n'9DG', 'X',\n'9DI', 'X',\\ +n'9HX', 'X',\n'9OH', 'X',\n'9TA', 'X',\n'A12', 'X'\ +,\n'A15', 'X',\n'A23', 'X',\n'A24', 'X',\n'A26', '\ +X',\n'A2G', 'X',\n'A2P', 'X',\n'A32', 'X',\n'A3P',\ + 'X',\n'A4P', 'X',\n'A5P', 'X',\n'A70', 'X',\n'A76\ +', 'X',\n'A77', 'X',\n'A78', 'X',\n'A79', 'X',\n'A\ +80', 'X',\n'A85', 'X',\n'A88', 'X',\n'A9A', 'X',\n\ +'AA3', 'X',\n'AA4', 'X',\n'AA6', 'X',\n'AAA', 'X',\ +\n'AAB', 'X',\n'AAC', 'X',\n'AAE', 'X',\n'AAG', 'R\ +',\n'AAH', 'X',\n'AAM', 'X',\n'AAN', 'X',\n'AAP', \ +'X',\n'AAR', 'R',\n'AAS', 'X',\n'AAT', 'X',\n'ABA'\ +, 'X',\n'ABC', 'X',\n'ABD', 'X',\n'ABE', 'X',\n'AB\ +H', 'X',\n'ABI', 'X',\n'ABK', 'X',\n'ABM', 'X',\n'\ +ABN', 'X',\n'ABP', 'X',\n'ABR', 'X',\n'ABS', 'X',\\ +n'ABU', 'X',\n'AC1', 'X',\n'AC2', 'X',\n'ACA', 'X'\ +,\n'ACB', 'D',\n'ACC', 'C',\n'ACD', 'X',\n'ACE', '\ +X',\n'ACH', 'X',\n'ACI', 'X',\n'ACL', 'R',\n'ACM',\ + 'X',\n'ACN', 'X',\n'ACO', 'X',\n'ACP', 'X',\n'ACQ\ +', 'X',\n'ACR', 'X',\n'ACS', 'X',\n'ACT', 'X',\n'A\ +CV', 'V',\n'ACX', 'X',\n'ACY', 'X',\n'AD2', 'X',\n\ +'AD3', 'X',\n'ADC', 'X',\n'ADD', 'X',\n'ADE', 'X',\ +\n'ADH', 'X',\n'ADI', 'X',\n'ADM', 'X',\n'ADN', 'X\ +',\n'ADP', 'X',\n'ADQ', 'X',\n'ADR', 'X',\n'ADS', \ +'X',\n'ADT', 'X',\n'ADU', 'X',\n'ADW', 'X',\n'ADX'\ +, 'X',\n'AE2', 'X',\n'AEA', 'X',\n'AEB', 'X',\n'AE\ +I', 'D',\n'AEN', 'X',\n'AET', 'T',\n'AF1', 'X',\n'\ +AF3', 'X',\n'AFA', 'D',\n'AFP', 'X',\n'AG7', 'X',\\ +n'AGB', 'X',\n'AGF', 'X',\n'AGL', 'X',\n'AGM', 'R'\ +,\n'AGN', 'X',\n'AGP', 'X',\n'AGS', 'X',\n'AGU', '\ +X',\n'AH0', 'X',\n'AH1', 'X',\n'AHA', 'X',\n'AHB',\ + 'D',\n'AHC', 'X',\n'AHF', 'X',\n'AHG', 'X',\n'AHH\ +', 'X',\n'AHM', 'X',\n'AHO', 'X',\n'AHP', 'X',\n'A\ +HS', 'X',\n'AHT', 'Y',\n'AHU', 'X',\n'AHX', 'X',\n\ +'AI1', 'X',\n'AI2', 'X',\n'AIB', 'X',\n'AIC', 'X',\ +\n'AIM', 'X',\n'AIP', 'X',\n'AIQ', 'X',\n'AIR', 'X\ +',\n'AJ3', 'X',\n'AKB', 'X',\n'AKG', 'X',\n'AKR', \ +'X',\n'AL1', 'X',\n'AL2', 'X',\n'AL3', 'X',\n'AL4'\ +, 'X',\n'AL5', 'X',\n'AL6', 'X',\n'AL7', 'X',\n'AL\ +8', 'X',\n'AL9', 'X',\n'ALA', 'A',\n'ALB', 'X',\n'\ +ALC', 'X',\n'ALD', 'L',\n'ALE', 'X',\n'ALF', 'X',\\ +n'ALG', 'X',\n'ALL', 'X',\n'ALM', 'A',\n'ALN', 'A'\ +,\n'ALO', 'T',\n'ALP', 'X',\n'ALQ', 'X',\n'ALR', '\ +X',\n'ALS', 'X',\n'ALT', 'A',\n'ALY', 'K',\n'ALZ',\ + 'X',\n'AMA', 'X',\n'AMB', 'X',\n'AMC', 'X',\n'AMD\ +', 'X',\n'AMG', 'X',\n'AMH', 'X',\n'AMI', 'X',\n'A\ +ML', 'X',\n'AMN', 'X',\n'AMO', 'X',\n'AMP', 'X',\n\ +'AMQ', 'X',\n'AMR', 'X',\n'AMS', 'X',\n'AMT', 'X',\ +\n'AMU', 'X',\n'AMW', 'X',\n'AMX', 'X',\n'AMY', 'X\ +',\n'ANA', 'X',\n'ANB', 'X',\n'ANC', 'X',\n'AND', \ +'X',\n'ANE', 'X',\n'ANI', 'X',\n'ANL', 'X',\n'ANO'\ +, 'X',\n'ANP', 'X',\n'ANS', 'X',\n'ANT', 'X',\n'AO\ +E', 'X',\n'AOP', 'X',\n'AP1', 'X',\n'AP2', 'X',\n'\ +AP3', 'X',\n'AP4', 'X',\n'AP5', 'X',\n'AP6', 'X',\\ +n'APA', 'X',\n'APB', 'X',\n'APC', 'X',\n'APE', 'F'\ +,\n'APF', 'X',\n'APG', 'X',\n'APH', 'A',\n'API', '\ +X',\n'APL', 'X',\n'APM', 'X',\n'APN', 'G',\n'APP',\ + 'X',\n'APQ', 'X',\n'APR', 'X',\n'APS', 'X',\n'APT\ +', 'X',\n'APU', 'X',\n'APX', 'X',\n'APY', 'X',\n'A\ +PZ', 'X',\n'AQS', 'X',\n'AR1', 'X',\n'AR2', 'X',\n\ +'ARA', 'X',\n'ARB', 'X',\n'ARC', 'X',\n'ARD', 'X',\ +\n'ARG', 'R',\n'ARH', 'X',\n'ARI', 'X',\n'ARM', 'R\ +',\n'ARN', 'X',\n'ARO', 'R',\n'ARP', 'X',\n'ARQ', \ +'X',\n'ARS', 'X',\n'AS1', 'R',\n'AS2', 'X',\n'ASA'\ +, 'D',\n'ASB', 'D',\n'ASC', 'X',\n'ASD', 'X',\n'AS\ +E', 'X',\n'ASF', 'X',\n'ASI', 'X',\n'ASK', 'D',\n'\ +ASL', 'X',\n'ASM', 'N',\n'ASO', 'X',\n'ASP', 'D',\\ +n'ASQ', 'X',\n'ASU', 'X',\n'ATA', 'X',\n'ATC', 'X'\ +,\n'ATD', 'X',\n'ATF', 'X',\n'ATG', 'X',\n'ATH', '\ +X',\n'ATM', 'X',\n'ATO', 'X',\n'ATP', 'X',\n'ATQ',\ + 'X',\n'ATR', 'X',\n'ATT', 'X',\n'ATY', 'X',\n'ATZ\ +', 'X',\n'AUC', 'X',\n'AUR', 'X',\n'AVG', 'X',\n'A\ +XP', 'X',\n'AYA', 'A',\n'AZ2', 'X',\n'AZA', 'X',\n\ +'AZC', 'X',\n'AZD', 'X',\n'AZE', 'X',\n'AZI', 'X',\ +\n'AZL', 'X',\n'AZM', 'X',\n'AZR', 'X',\n'AZT', 'X\ +',\n'B12', 'X',\n'B1F', 'F',\n'B2A', 'A',\n'B2F', \ +'F',\n'B2I', 'I',\n'B2V', 'V',\n'B3I', 'X',\n'B3P'\ +, 'X',\n'B7G', 'X',\n'B96', 'X',\n'B9A', 'X',\n'BA\ +1', 'X',\n'BAA', 'X',\n'BAB', 'X',\n'BAC', 'X',\n'\ +BAF', 'X',\n'BAH', 'X',\n'BAI', 'X',\n'BAK', 'X',\\ +n'BAL', 'A',\n'BAM', 'X',\n'BAO', 'X',\n'BAP', 'X'\ +,\n'BAR', 'X',\n'BAS', 'X',\n'BAT', 'F',\n'BAY', '\ +X',\n'BAZ', 'X',\n'BB1', 'X',\n'BB2', 'X',\n'BBA',\ + 'X',\n'BBH', 'X',\n'BBS', 'X',\n'BBT', 'X',\n'BBZ\ +', 'X',\n'BCA', 'X',\n'BCB', 'X',\n'BCC', 'X',\n'B\ +CD', 'X',\n'BCL', 'X',\n'BCN', 'X',\n'BCR', 'X',\n\ +'BCS', 'C',\n'BCT', 'X',\n'BCY', 'X',\n'BCZ', 'X',\ +\n'BDA', 'X',\n'BDG', 'X',\n'BDK', 'X',\n'BDM', 'X\ +',\n'BDN', 'X',\n'BDS', 'X',\n'BE1', 'X',\n'BE2', \ +'X',\n'BEA', 'X',\n'BEF', 'X',\n'BEN', 'X',\n'BEO'\ +, 'X',\n'BEP', 'X',\n'BER', 'X',\n'BES', 'X',\n'BE\ +T', 'X',\n'BEZ', 'X',\n'BF2', 'X',\n'BFA', 'X',\n'\ +BFD', 'X',\n'BFP', 'X',\n'BFS', 'X',\n'BFU', 'X',\\ +n'BG6', 'X',\n'BGF', 'X',\n'BGG', 'X',\n'BGL', 'X'\ +,\n'BGN', 'X',\n'BGP', 'X',\n'BGX', 'X',\n'BH4', '\ +X',\n'BHA', 'X',\n'BHC', 'X',\n'BHD', 'D',\n'BHO',\ + 'X',\n'BHS', 'X',\n'BIC', 'X',\n'BIN', 'X',\n'BIO\ +', 'X',\n'BIP', 'X',\n'BIS', 'X',\n'BIZ', 'X',\n'B\ +JH', 'X',\n'BJI', 'X',\n'BJP', 'X',\n'BLA', 'X',\n\ +'BLB', 'X',\n'BLE', 'L',\n'BLG', 'P',\n'BLI', 'X',\ +\n'BLM', 'X',\n'BLV', 'X',\n'BLY', 'K',\n'BM1', 'X\ +',\n'BM2', 'X',\n'BM5', 'X',\n'BM9', 'X',\n'BMA', \ +'X',\n'BMD', 'X',\n'BME', 'X',\n'BMP', 'X',\n'BMQ'\ +, 'X',\n'BMS', 'X',\n'BMT', 'T',\n'BMU', 'X',\n'BM\ +Y', 'X',\n'BMZ', 'X',\n'BNA', 'X',\n'BNG', 'X',\n'\ +BNI', 'X',\n'BNN', 'F',\n'BNO', 'L',\n'BNS', 'X',\\ +n'BNZ', 'X',\n'BO3', 'X',\n'BO4', 'X',\n'BOC', 'X'\ +,\n'BOG', 'X',\n'BOM', 'X',\n'BOT', 'X',\n'BOX', '\ +X',\n'BOZ', 'X',\n'BPA', 'X',\n'BPB', 'X',\n'BPD',\ + 'X',\n'BPG', 'X',\n'BPH', 'X',\n'BPI', 'X',\n'BPJ\ +', 'X',\n'BPM', 'X',\n'BPN', 'X',\n'BPO', 'X',\n'B\ +PP', 'X',\n'BPT', 'X',\n'BPY', 'X',\n'BRB', 'X',\n\ +'BRC', 'X',\n'BRE', 'X',\n'BRI', 'X',\n'BRL', 'X',\ +\n'BRM', 'X',\n'BRN', 'X',\n'BRO', 'X',\n'BRS', 'X\ +',\n'BRU', 'X',\n'BRZ', 'X',\n'BSB', 'X',\n'BSI', \ +'X',\n'BSP', 'X',\n'BT1', 'X',\n'BT2', 'X',\n'BT3'\ +, 'X',\n'BTA', 'L',\n'BTB', 'X',\n'BTC', 'C',\n'BT\ +D', 'X',\n'BTN', 'X',\n'BTP', 'X',\n'BTR', 'W',\n'\ +BU1', 'X',\n'BUA', 'X',\n'BUB', 'X',\n'BUC', 'X',\\ +n'BUG', 'X',\n'BUL', 'X',\n'BUM', 'X',\n'BUQ', 'X'\ +,\n'BUT', 'X',\n'BVD', 'X',\n'BX3', 'X',\n'BYS', '\ +X',\n'BZ1', 'X',\n'BZA', 'X',\n'BZB', 'X',\n'BZC',\ + 'X',\n'BZD', 'X',\n'BZF', 'X',\n'BZI', 'X',\n'BZM\ +', 'X',\n'BZO', 'X',\n'BZP', 'X',\n'BZQ', 'X',\n'B\ +ZS', 'X',\n'BZT', 'X',\n'C02', 'X',\n'C11', 'X',\n\ +'C1O', 'X',\n'C20', 'X',\n'C24', 'X',\n'C2F', 'X',\ +\n'C2O', 'X',\n'C2P', 'X',\n'C3M', 'X',\n'C3P', 'X\ +',\n'C3X', 'X',\n'C48', 'X',\n'C4M', 'X',\n'C4X', \ +'X',\n'C5C', 'X',\n'C5M', 'X',\n'C5P', 'X',\n'C5X'\ +, 'X',\n'C60', 'X',\n'C6C', 'X',\n'C6M', 'X',\n'C7\ +8', 'X',\n'C8E', 'X',\n'CA3', 'X',\n'CA5', 'X',\n'\ +CAA', 'X',\n'CAB', 'X',\n'CAC', 'X',\n'CAD', 'X',\\ +n'CAF', 'C',\n'CAG', 'X',\n'CAH', 'X',\n'CAL', 'X'\ +,\n'CAM', 'X',\n'CAN', 'X',\n'CAO', 'X',\n'CAP', '\ +X',\n'CAQ', 'X',\n'CAR', 'X',\n'CAS', 'C',\n'CAT',\ + 'X',\n'CAV', 'X',\n'CAY', 'C',\n'CAZ', 'X',\n'CB3\ +', 'X',\n'CB4', 'X',\n'CBA', 'X',\n'CBD', 'X',\n'C\ +BG', 'X',\n'CBI', 'X',\n'CBL', 'X',\n'CBM', 'X',\n\ +'CBN', 'X',\n'CBO', 'X',\n'CBP', 'X',\n'CBS', 'X',\ +\n'CBX', 'X',\n'CBZ', 'X',\n'CC0', 'X',\n'CC1', 'X\ +',\n'CCC', 'X',\n'CCH', 'X',\n'CCI', 'X',\n'CCM', \ +'X',\n'CCN', 'X',\n'CCO', 'X',\n'CCP', 'X',\n'CCR'\ +, 'X',\n'CCS', 'C',\n'CCV', 'X',\n'CCY', 'X',\n'CD\ +1', 'X',\n'CDC', 'X',\n'CDE', 'X',\n'CDF', 'X',\n'\ +CDI', 'X',\n'CDL', 'X',\n'CDM', 'X',\n'CDP', 'X',\\ +n'CDR', 'X',\n'CDU', 'X',\n'CE1', 'X',\n'CEA', 'C'\ +,\n'CEB', 'X',\n'CEC', 'X',\n'CED', 'X',\n'CEF', '\ +X',\n'CEH', 'X',\n'CEM', 'X',\n'CEO', 'X',\n'CEP',\ + 'X',\n'CEQ', 'X',\n'CER', 'X',\n'CES', 'G',\n'CET\ +', 'X',\n'CFC', 'X',\n'CFF', 'X',\n'CFM', 'X',\n'C\ +FO', 'X',\n'CFP', 'X',\n'CFS', 'X',\n'CFX', 'X',\n\ +'CGN', 'X',\n'CGP', 'X',\n'CGS', 'X',\n'CGU', 'E',\ +\n'CH2', 'X',\n'CH3', 'X',\n'CHA', 'X',\n'CHB', 'X\ +',\n'CHD', 'X',\n'CHF', 'X',\n'CHG', 'G',\n'CHI', \ +'X',\n'CHN', 'X',\n'CHO', 'X',\n'CHP', 'G',\n'CHR'\ +, 'X',\n'CHS', 'F',\n'CHT', 'X',\n'CHX', 'X',\n'CI\ +C', 'X',\n'CIN', 'X',\n'CIP', 'X',\n'CIR', 'X',\n'\ +CIT', 'X',\n'CIU', 'X',\n'CKI', 'X',\n'CL1', 'X',\\ +n'CL2', 'X',\n'CLA', 'X',\n'CLB', 'A',\n'CLC', 'S'\ +,\n'CLD', 'A',\n'CLE', 'L',\n'CLF', 'X',\n'CLK', '\ +S',\n'CLL', 'X',\n'CLM', 'X',\n'CLN', 'X',\n'CLO',\ + 'X',\n'CLP', 'X',\n'CLQ', 'X',\n'CLR', 'X',\n'CLS\ +', 'X',\n'CLT', 'X',\n'CLX', 'X',\n'CLY', 'X',\n'C\ +MA', 'R',\n'CMC', 'X',\n'CMD', 'X',\n'CME', 'C',\n\ +'CMG', 'X',\n'CMK', 'X',\n'CMN', 'X',\n'CMO', 'X',\ +\n'CMP', 'X',\n'CMR', 'X',\n'CMS', 'X',\n'CMT', 'C\ +',\n'CMX', 'X',\n'CNA', 'X',\n'CNC', 'X',\n'CND', \ +'X',\n'CNH', 'X',\n'CNM', 'X',\n'CNN', 'X',\n'CNO'\ +, 'X',\n'CNP', 'X',\n'CO2', 'X',\n'CO3', 'X',\n'CO\ +5', 'X',\n'CO8', 'X',\n'COA', 'X',\n'COB', 'X',\n'\ +COC', 'X',\n'COD', 'X',\n'COE', 'X',\n'COF', 'X',\\ +n'COH', 'X',\n'COI', 'X',\n'COJ', 'X',\n'COL', 'X'\ +,\n'COM', 'X',\n'CON', 'X',\n'COP', 'X',\n'COR', '\ +X',\n'COS', 'X',\n'COT', 'X',\n'COY', 'X',\n'CP1',\ + 'G',\n'CP2', 'X',\n'CP4', 'X',\n'CPA', 'X',\n'CPB\ +', 'X',\n'CPC', 'X',\n'CPD', 'X',\n'CPG', 'X',\n'C\ +PH', 'X',\n'CPI', 'X',\n'CPM', 'X',\n'CPN', 'G',\n\ +'CPO', 'X',\n'CPP', 'X',\n'CPQ', 'X',\n'CPR', 'X',\ +\n'CPS', 'X',\n'CPT', 'X',\n'CPU', 'X',\n'CPV', 'X\ +',\n'CPY', 'X',\n'CR1', 'X',\n'CR6', 'X',\n'CRA', \ +'X',\n'CRB', 'X',\n'CRC', 'X',\n'CRG', 'X',\n'CRH'\ +, 'X',\n'CRO', 'T',\n'CRP', 'X',\n'CRQ', 'X',\n'CR\ +S', 'X',\n'CRT', 'X',\n'CRY', 'X',\n'CSA', 'C',\n'\ +CSB', 'X',\n'CSD', 'C',\n'CSE', 'C',\n'CSH', 'X',\\ +n'CSI', 'X',\n'CSN', 'X',\n'CSO', 'C',\n'CSP', 'C'\ +,\n'CSR', 'C',\n'CSS', 'C',\n'CST', 'X',\n'CSW', '\ +C',\n'CSX', 'C',\n'CSY', 'X',\n'CSZ', 'C',\n'CT3',\ + 'X',\n'CTA', 'X',\n'CTB', 'X',\n'CTC', 'X',\n'CTD\ +', 'X',\n'CTH', 'T',\n'CTO', 'X',\n'CTP', 'X',\n'C\ +TR', 'X',\n'CTS', 'X',\n'CTT', 'X',\n'CTY', 'X',\n\ +'CTZ', 'X',\n'CU1', 'X',\n'CUA', 'X',\n'CUC', 'X',\ +\n'CUL', 'X',\n'CUO', 'X',\n'CUZ', 'X',\n'CVI', 'X\ +',\n'CXF', 'X',\n'CXL', 'X',\n'CXM', 'M',\n'CXN', \ +'X',\n'CXP', 'X',\n'CXS', 'X',\n'CY1', 'C',\n'CY3'\ +, 'X',\n'CYB', 'X',\n'CYC', 'X',\n'CYF', 'C',\n'CY\ +G', 'C',\n'CYH', 'X',\n'CYL', 'X',\n'CYM', 'C',\n'\ +CYN', 'X',\n'CYO', 'X',\n'CYP', 'X',\n'CYQ', 'C',\\ +n'CYS', 'C',\n'CYU', 'X',\n'CYY', 'X',\n'CYZ', 'X'\ +,\n'CZH', 'X',\n'CZZ', 'C',\n'D12', 'X',\n'D13', '\ +X',\n'D16', 'X',\n'D18', 'X',\n'D19', 'X',\n'D1P',\ + 'X',\n'D24', 'X',\n'D34', 'X',\n'D35', 'X',\n'D4D\ +', 'X',\n'D4T', 'X',\n'D6G', 'X',\n'DA2', 'R',\n'D\ +A3', 'X',\n'DA6', 'X',\n'DA7', 'X',\n'DAA', 'X',\n\ +'DAB', 'X',\n'DAC', 'X',\n'DAD', 'X',\n'DAE', 'X',\ +\n'DAF', 'X',\n'DAG', 'X',\n'DAH', 'A',\n'DAJ', 'X\ +',\n'DAK', 'X',\n'DAL', 'A',\n'DAM', 'A',\n'DAN', \ +'X',\n'DAO', 'X',\n'DAP', 'X',\n'DAQ', 'X',\n'DAR'\ +, 'R',\n'DAS', 'D',\n'DAT', 'X',\n'DAU', 'X',\n'DA\ +V', 'X',\n'DBA', 'X',\n'DBD', 'X',\n'DBF', 'X',\n'\ +DBG', 'X',\n'DBI', 'X',\n'DBV', 'X',\n'DBY', 'Y',\\ +n'DCA', 'X',\n'DCB', 'X',\n'DCE', 'X',\n'DCF', 'X'\ +,\n'DCG', 'X',\n'DCH', 'X',\n'DCI', 'I',\n'DCL', '\ +X',\n'DCM', 'X',\n'DCP', 'X',\n'DCS', 'X',\n'DCT',\ + 'X',\n'DCY', 'C',\n'DCZ', 'X',\n'DDA', 'X',\n'DDB\ +', 'X',\n'DDC', 'X',\n'DDF', 'X',\n'DDG', 'X',\n'D\ +DH', 'X',\n'DDL', 'X',\n'DDM', 'X',\n'DDO', 'L',\n\ +'DDP', 'X',\n'DDQ', 'X',\n'DDT', 'Y',\n'DDU', 'X',\ +\n'DEA', 'X',\n'DEB', 'X',\n'DEC', 'X',\n'DEF', 'X\ +',\n'DEL', 'X',\n'DEM', 'X',\n'DEN', 'X',\n'DEP', \ +'X',\n'DEQ', 'X',\n'DES', 'X',\n'DET', 'X',\n'DFC'\ +, 'X',\n'DFG', 'X',\n'DFI', 'X',\n'DFL', 'X',\n'DF\ +O', 'X',\n'DFP', 'X',\n'DFR', 'X',\n'DFT', 'X',\n'\ +DFV', 'X',\n'DFX', 'X',\n'DG2', 'X',\n'DG3', 'X',\\ +n'DG6', 'X',\n'DGA', 'X',\n'DGD', 'X',\n'DGG', 'X'\ +,\n'DGL', 'E',\n'DGN', 'Q',\n'DGP', 'X',\n'DGT', '\ +X',\n'DGX', 'X',\n'DH2', 'X',\n'DHA', 'A',\n'DHB',\ + 'X',\n'DHC', 'X',\n'DHD', 'X',\n'DHE', 'X',\n'DHF\ +', 'X',\n'DHG', 'X',\n'DHI', 'H',\n'DHL', 'X',\n'D\ +HM', 'X',\n'DHN', 'V',\n'DHP', 'X',\n'DHQ', 'X',\n\ +'DHR', 'X',\n'DHS', 'X',\n'DHT', 'X',\n'DHU', 'X',\ +\n'DHY', 'X',\n'DHZ', 'X',\n'DI2', 'X',\n'DI3', 'G\ +',\n'DI4', 'X',\n'DI5', 'X',\n'DIA', 'X',\n'DIC', \ +'X',\n'DIF', 'X',\n'DIG', 'X',\n'DII', 'X',\n'DIL'\ +, 'I',\n'DIM', 'X',\n'DIO', 'X',\n'DIP', 'X',\n'DI\ +Q', 'X',\n'DIS', 'X',\n'DIT', 'X',\n'DIV', 'V',\n'\ +DIX', 'X',\n'DIY', 'X',\n'DKA', 'X',\n'DLA', 'X',\\ +n'DLE', 'L',\n'DLF', 'X',\n'DLS', 'K',\n'DLY', 'K'\ +,\n'DM1', 'X',\n'DM2', 'X',\n'DM3', 'X',\n'DM4', '\ +X',\n'DM5', 'X',\n'DM6', 'X',\n'DM7', 'X',\n'DM8',\ + 'X',\n'DM9', 'X',\n'DMA', 'X',\n'DMB', 'X',\n'DMC\ +', 'X',\n'DMD', 'X',\n'DME', 'X',\n'DMF', 'X',\n'D\ +MG', 'G',\n'DMH', 'N',\n'DMI', 'X',\n'DMJ', 'X',\n\ +'DML', 'X',\n'DMM', 'X',\n'DMN', 'X',\n'DMO', 'X',\ +\n'DMP', 'X',\n'DMQ', 'X',\n'DMR', 'X',\n'DMS', 'X\ +',\n'DMT', 'X',\n'DMV', 'X',\n'DMY', 'X',\n'DNC', \ +'X',\n'DND', 'X',\n'DNH', 'X',\n'DNJ', 'X',\n'DNN'\ +, 'X',\n'DNP', 'X',\n'DNQ', 'X',\n'DNR', 'X',\n'DO\ +2', 'X',\n'DO3', 'X',\n'DOA', 'X',\n'DOB', 'X',\n'\ +DOC', 'X',\n'DOH', 'D',\n'DOM', 'X',\n'DOS', 'X',\\ +n'DOX', 'X',\n'DP5', 'X',\n'DP7', 'X',\n'DPA', 'X'\ +,\n'DPC', 'X',\n'DPD', 'X',\n'DPE', 'X',\n'DPG', '\ +X',\n'DPH', 'F',\n'DPM', 'X',\n'DPN', 'F',\n'DPO',\ + 'X',\n'DPP', 'X',\n'DPR', 'P',\n'DPS', 'X',\n'DPT\ +', 'X',\n'DPX', 'X',\n'DPY', 'X',\n'DPZ', 'X',\n'D\ +QH', 'X',\n'DQN', 'X',\n'DR1', 'X',\n'DRB', 'X',\n\ +'DRC', 'X',\n'DRI', 'X',\n'DRP', 'X',\n'DRT', 'X',\ +\n'DRU', 'X',\n'DSA', 'X',\n'DSB', 'X',\n'DSC', 'X\ +',\n'DSD', 'X',\n'DSE', 'S',\n'DSI', 'X',\n'DSN', \ +'S',\n'DSP', 'D',\n'DSR', 'X',\n'DSS', 'X',\n'DSX'\ +, 'X',\n'DSY', 'X',\n'DTB', 'X',\n'DTD', 'X',\n'DT\ +H', 'T',\n'DTN', 'X',\n'DTO', 'X',\n'DTP', 'X',\n'\ +DTQ', 'X',\n'DTR', 'W',\n'DTT', 'X',\n'DTY', 'Y',\\ +n'DUD', 'X',\n'DUO', 'X',\n'DUR', 'X',\n'DUT', 'X'\ +,\n'DVA', 'V',\n'DVR', 'X',\n'DX9', 'X',\n'DXA', '\ +X',\n'DXB', 'X',\n'DXC', 'X',\n'DXG', 'X',\n'DXX',\ + 'X',\n'DZF', 'X',\n'E09', 'X',\n'E20', 'X',\n'E2P\ +', 'X',\n'E3G', 'X',\n'E4N', 'X',\n'E4P', 'X',\n'E\ +64', 'X',\n'E6C', 'X',\n'E96', 'X',\n'E97', 'X',\n\ +'EA2', 'X',\n'EAA', 'X',\n'EAP', 'X',\n'EBP', 'X',\ +\n'EBW', 'X',\n'ECO', 'X',\n'EDA', 'X',\n'EDC', 'X\ +',\n'EDE', 'X',\n'EDO', 'X',\n'EDR', 'X',\n'EEB', \ +'X',\n'EEE', 'X',\n'EFC', 'X',\n'EFZ', 'X',\n'EG1'\ +, 'X',\n'EG2', 'X',\n'EG3', 'X',\n'EGC', 'X',\n'EG\ +L', 'X',\n'EHP', 'A',\n'EIC', 'X',\n'EJT', 'X',\n'\ +ELA', 'X',\n'EMB', 'X',\n'EMC', 'X',\n'EMD', 'X',\\ +n'EMM', 'X',\n'EMO', 'X',\n'EMP', 'X',\n'EMR', 'X'\ +,\n'ENA', 'X',\n'ENC', 'X',\n'ENH', 'X',\n'ENO', '\ +X',\n'ENP', 'X',\n'EOA', 'X',\n'EOH', 'X',\n'EOT',\ + 'X',\n'EOX', 'X',\n'EPA', 'X',\n'EPE', 'X',\n'EPH\ +', 'X',\n'EPI', 'X',\n'EPN', 'X',\n'EPO', 'X',\n'E\ +PT', 'X',\n'EPU', 'X',\n'EPX', 'X',\n'EPY', 'X',\n\ +'EQI', 'X',\n'EQP', 'X',\n'EQU', 'X',\n'ERG', 'X',\ +\n'ERI', 'X',\n'ERY', 'X',\n'ESC', 'X',\n'ESD', 'X\ +',\n'ESI', 'X',\n'ESO', 'X',\n'ESP', 'X',\n'EST', \ +'X',\n'ESX', 'X',\n'ETA', 'X',\n'ETC', 'X',\n'ETD'\ +, 'X',\n'ETF', 'X',\n'ETH', 'X',\n'ETI', 'X',\n'ET\ +N', 'X',\n'ETO', 'X',\n'ETP', 'X',\n'ETR', 'X',\n'\ +ETS', 'X',\n'ETY', 'X',\n'EU3', 'X',\n'EUG', 'X',\\ +n'EYS', 'C',\n'F09', 'X',\n'F2B', 'X',\n'F3S', 'X'\ +,\n'F42', 'X',\n'F43', 'X',\n'F4S', 'X',\n'F6B', '\ +X',\n'F6P', 'X',\n'F89', 'X',\n'FA1', 'X',\n'FA5',\ + 'F',\n'FAA', 'X',\n'FAB', 'X',\n'FAC', 'X',\n'FAD\ +', 'X',\n'FAF', 'X',\n'FAG', 'X',\n'FAM', 'X',\n'F\ +AR', 'X',\n'FAS', 'X',\n'FAT', 'X',\n'FBA', 'X',\n\ +'FBE', 'X',\n'FBI', 'X',\n'FBP', 'X',\n'FBQ', 'X',\ +\n'FBS', 'X',\n'FBT', 'X',\n'FBU', 'X',\n'FCA', 'X\ +',\n'FCB', 'X',\n'FCI', 'X',\n'FCN', 'X',\n'FCO', \ +'X',\n'FCR', 'X',\n'FCT', 'X',\n'FCX', 'X',\n'FCY'\ +, 'C',\n'FD1', 'F',\n'FD2', 'F',\n'FD3', 'F',\n'FD\ +4', 'F',\n'FDA', 'X',\n'FDC', 'X',\n'FDI', 'X',\n'\ +FDP', 'X',\n'FDS', 'X',\n'FE2', 'X',\n'FEA', 'X',\\ +n'FEL', 'X',\n'FEM', 'X',\n'FEN', 'X',\n'FEO', 'X'\ +,\n'FEP', 'X',\n'FER', 'X',\n'FES', 'X',\n'FFB', '\ +X',\n'FFC', 'X',\n'FFF', 'X',\n'FFO', 'X',\n'FGL',\ + 'G',\n'FHB', 'X',\n'FHC', 'X',\n'FHP', 'X',\n'FHU\ +', 'X',\n'FID', 'X',\n'FII', 'X',\n'FIP', 'X',\n'F\ +K5', 'X',\n'FKA', 'X',\n'FKI', 'X',\n'FKP', 'X',\n\ +'FL2', 'X',\n'FL9', 'X',\n'FLA', 'A',\n'FLC', 'X',\ +\n'FLD', 'X',\n'FLE', 'L',\n'FLF', 'X',\n'FLO', 'X\ +',\n'FLP', 'X',\n'FLT', 'Y',\n'FLU', 'X',\n'FLX', \ +'X',\n'FM1', 'X',\n'FM2', 'X',\n'FMA', 'X',\n'FMB'\ +, 'X',\n'FMC', 'X',\n'FME', 'M',\n'FMN', 'X',\n'FM\ +P', 'X',\n'FMR', 'X',\n'FMS', 'X',\n'FMT', 'X',\n'\ +FNE', 'X',\n'FNP', 'X',\n'FNS', 'X',\n'FOC', 'X',\\ +n'FOE', 'X',\n'FOG', 'F',\n'FOH', 'X',\n'FOK', 'X'\ +,\n'FOL', 'X',\n'FON', 'X',\n'FOP', 'X',\n'FOR', '\ +X',\n'FOS', 'X',\n'FPA', 'X',\n'FPC', 'X',\n'FPI',\ + 'X',\n'FPO', 'X',\n'FPP', 'X',\n'FPT', 'X',\n'FQP\ +', 'X',\n'FRA', 'X',\n'FRD', 'F',\n'FRU', 'X',\n'F\ +S3', 'X',\n'FS4', 'X',\n'FSB', 'X',\n'FSO', 'X',\n\ +'FSX', 'X',\n'FTC', 'X',\n'FTP', 'X',\n'FTR', 'W',\ +\n'FTT', 'X',\n'FTY', 'Y',\n'FUA', 'X',\n'FUC', 'X\ +',\n'FUM', 'X',\n'FUP', 'X',\n'FVF', 'X',\n'FXP', \ +'X',\n'FXV', 'X',\n'FYA', 'F',\n'G16', 'X',\n'G1P'\ +, 'X',\n'G20', 'X',\n'G21', 'X',\n'G23', 'X',\n'G2\ +6', 'X',\n'G28', 'X',\n'G2F', 'X',\n'G37', 'X',\n'\ +G39', 'X',\n'G3H', 'X',\n'G3P', 'X',\n'G4D', 'X',\\ +n'G6D', 'X',\n'G6P', 'X',\n'G6Q', 'X',\n'G7M', 'X'\ +,\n'GA2', 'X',\n'GAA', 'X',\n'GAB', 'X',\n'GAC', '\ +X',\n'GAI', 'X',\n'GAL', 'X',\n'GAM', 'X',\n'GAN',\ + 'X',\n'GAO', 'X',\n'GAP', 'X',\n'GAR', 'G',\n'GAS\ +', 'X',\n'GAT', 'X',\n'GBC', 'X',\n'GBI', 'X',\n'G\ +BP', 'X',\n'GBS', 'X',\n'GBX', 'X',\n'GC4', 'X',\n\ +'GCA', 'X',\n'GCD', 'X',\n'GCG', 'G',\n'GCH', 'G',\ +\n'GCK', 'X',\n'GCL', 'X',\n'GCM', 'X',\n'GCN', 'X\ +',\n'GCO', 'X',\n'GCP', 'X',\n'GCR', 'X',\n'GCS', \ +'X',\n'GCU', 'X',\n'GD3', 'X',\n'GDB', 'X',\n'GDM'\ +, 'X',\n'GDN', 'X',\n'GDP', 'X',\n'GDS', 'X',\n'GD\ +U', 'X',\n'GE1', 'X',\n'GE2', 'X',\n'GE3', 'X',\n'\ +GEA', 'X',\n'GEL', 'X',\n'GEM', 'X',\n'GEN', 'X',\\ +n'GEP', 'X',\n'GER', 'X',\n'GFP', 'X',\n'GGB', 'X'\ +,\n'GGL', 'E',\n'GGP', 'X',\n'GHP', 'G',\n'GIP', '\ +X',\n'GIS', 'X',\n'GKR', 'X',\n'GL2', 'X',\n'GL3',\ + 'G',\n'GL4', 'X',\n'GL5', 'X',\n'GL7', 'X',\n'GL9\ +', 'X',\n'GLA', 'X',\n'GLB', 'X',\n'GLC', 'X',\n'G\ +LD', 'X',\n'GLE', 'X',\n'GLF', 'X',\n'GLG', 'X',\n\ +'GLH', 'Q',\n'GLI', 'X',\n'GLL', 'X',\n'GLM', 'G',\ +\n'GLN', 'Q',\n'GLO', 'X',\n'GLP', 'X',\n'GLR', 'X\ +',\n'GLS', 'X',\n'GLT', 'X',\n'GLU', 'E',\n'GLV', \ +'X',\n'GLW', 'X',\n'GLY', 'G',\n'GLZ', 'X',\n'GM1'\ +, 'X',\n'GMA', 'X',\n'GMC', 'X',\n'GMH', 'X',\n'GM\ +P', 'X',\n'GMY', 'X',\n'GN7', 'X',\n'GNA', 'X',\n'\ +GNB', 'X',\n'GNH', 'X',\n'GNP', 'X',\n'GNT', 'X',\\ +n'GOA', 'X',\n'GOL', 'X',\n'GOX', 'X',\n'GP1', 'X'\ +,\n'GP3', 'X',\n'GP4', 'X',\n'GP6', 'X',\n'GP8', '\ +X',\n'GPB', 'E',\n'GPC', 'X',\n'GPE', 'X',\n'GPG',\ + 'X',\n'GPI', 'X',\n'GPJ', 'X',\n'GPL', 'K',\n'GPM\ +', 'X',\n'GPN', 'G',\n'GPP', 'X',\n'GPR', 'X',\n'G\ +PS', 'X',\n'GPX', 'X',\n'GR1', 'X',\n'GR3', 'X',\n\ +'GR4', 'X',\n'GSA', 'X',\n'GSB', 'X',\n'GSC', 'G',\ +\n'GSE', 'S',\n'GSH', 'X',\n'GSP', 'X',\n'GSR', 'X\ +',\n'GSS', 'X',\n'GT9', 'C',\n'GTA', 'X',\n'GTB', \ +'X',\n'GTD', 'X',\n'GTE', 'X',\n'GTH', 'T',\n'GTN'\ +, 'X',\n'GTO', 'X',\n'GTP', 'X',\n'GTR', 'X',\n'GT\ +S', 'X',\n'GTT', 'X',\n'GTX', 'X',\n'GTZ', 'X',\n'\ +GU7', 'X',\n'GUA', 'X',\n'GUD', 'X',\n'GUM', 'X',\\ +n'GUN', 'X',\n'GUP', 'X',\n'GUR', 'X',\n'GW3', 'X'\ +,\n'GZZ', 'X',\n'H2B', 'X',\n'H2P', 'H',\n'H2S', '\ +X',\n'H2U', 'X',\n'H4B', 'X',\n'H5M', 'P',\n'H5P',\ + 'X',\n'HAA', 'X',\n'HAB', 'X',\n'HAC', 'A',\n'HAD\ +', 'X',\n'HAE', 'X',\n'HAG', 'X',\n'HAI', 'X',\n'H\ +AM', 'X',\n'HAP', 'X',\n'HAQ', 'X',\n'HAR', 'R',\n\ +'HAS', 'X',\n'HAV', 'V',\n'HAX', 'X',\n'HAZ', 'X',\ +\n'HBA', 'X',\n'HBC', 'X',\n'HBD', 'X',\n'HBI', 'X\ +',\n'HBO', 'X',\n'HBU', 'X',\n'HBY', 'X',\n'HC0', \ +'X',\n'HC1', 'X',\n'HC4', 'X',\n'HCA', 'X',\n'HCC'\ +, 'X',\n'HCI', 'X',\n'HCS', 'X',\n'HDA', 'X',\n'HD\ +D', 'X',\n'HDF', 'X',\n'HDN', 'X',\n'HDS', 'X',\n'\ +HDZ', 'X',\n'HE1', 'X',\n'HE6', 'X',\n'HEA', 'X',\\ +n'HEB', 'X',\n'HEC', 'X',\n'HED', 'X',\n'HEE', 'X'\ +,\n'HEF', 'X',\n'HEG', 'X',\n'HEM', 'X',\n'HEN', '\ +X',\n'HEO', 'X',\n'HEP', 'X',\n'HEU', 'X',\n'HEV',\ + 'X',\n'HEX', 'X',\n'HEZ', 'X',\n'HF1', 'X',\n'HFA\ +', 'X',\n'HFP', 'X',\n'HGA', 'Q',\n'HGB', 'X',\n'H\ +GC', 'X',\n'HGI', 'X',\n'HGU', 'X',\n'HHO', 'X',\n\ +'HHP', 'X',\n'HIB', 'X',\n'HIC', 'H',\n'HII', 'X',\ +\n'HIN', 'X',\n'HIO', 'X',\n'HIP', 'H',\n'HIS', 'H\ +',\n'HLE', 'X',\n'HLT', 'X',\n'HMA', 'A',\n'HMB', \ +'X',\n'HMC', 'X',\n'HMD', 'X',\n'HMF', 'A',\n'HMG'\ +, 'X',\n'HMH', 'X',\n'HMI', 'L',\n'HMM', 'X',\n'HM\ +N', 'X',\n'HMO', 'X',\n'HMP', 'X',\n'HMR', 'R',\n'\ +HNI', 'X',\n'HNP', 'X',\n'HOA', 'X',\n'HOE', 'X',\\ +n'HOH', 'X',\n'HOM', 'X',\n'HOP', 'X',\n'HOQ', 'X'\ +,\n'HP1', 'A',\n'HP2', 'A',\n'HP3', 'X',\n'HPA', '\ +X',\n'HPB', 'X',\n'HPC', 'X',\n'HPD', 'X',\n'HPE',\ + 'A',\n'HPG', 'X',\n'HPH', 'F',\n'HPP', 'X',\n'HPQ\ +', 'F',\n'HPR', 'X',\n'HPT', 'X',\n'HPY', 'X',\n'H\ +QO', 'X',\n'HQQ', 'X',\n'HQU', 'X',\n'HRG', 'R',\n\ +'HRI', 'X',\n'HSA', 'X',\n'HSE', 'S',\n'HSF', 'X',\ +\n'HSM', 'X',\n'HSO', 'H',\n'HSP', 'X',\n'HT1', 'X\ +',\n'HT2', 'X',\n'HTA', 'X',\n'HTL', 'X',\n'HTO', \ +'X',\n'HTP', 'X',\n'HTR', 'W',\n'HUP', 'X',\n'HUX'\ +, 'X',\n'HV5', 'A',\n'HV7', 'X',\n'HV8', 'X',\n'HX\ +A', 'X',\n'HXC', 'X',\n'HXP', 'X',\n'HY1', 'X',\n'\ +HYA', 'X',\n'HYB', 'X',\n'HYD', 'X',\n'HYG', 'X',\\ +n'HYP', 'P',\n'I06', 'X',\n'I10', 'X',\n'I11', 'X'\ +,\n'I17', 'X',\n'I2P', 'X',\n'I3N', 'X',\n'I3P', '\ +X',\n'I40', 'X',\n'I48', 'X',\n'I4B', 'X',\n'I52',\ + 'X',\n'I5P', 'X',\n'I84', 'G',\n'IAG', 'G',\n'IAS\ +', 'X',\n'IB2', 'X',\n'IBB', 'X',\n'IBP', 'X',\n'I\ +BR', 'X',\n'IBS', 'X',\n'IBZ', 'X',\n'IC1', 'X',\n\ +'ICA', 'X',\n'ICI', 'X',\n'ICL', 'X',\n'ICP', 'X',\ +\n'ICT', 'X',\n'ICU', 'X',\n'ID2', 'X',\n'IDC', 'X\ +',\n'IDG', 'X',\n'IDH', 'X',\n'IDM', 'X',\n'IDO', \ +'X',\n'IDP', 'X',\n'IDR', 'X',\n'IDS', 'X',\n'IDT'\ +, 'X',\n'IDU', 'X',\n'IFG', 'X',\n'IFP', 'X',\n'IG\ +L', 'X',\n'IGN', 'X',\n'IGP', 'X',\n'IGU', 'X',\n'\ +IH1', 'X',\n'IH2', 'X',\n'IH3', 'X',\n'IHB', 'X',\\ +n'IHN', 'X',\n'IHP', 'X',\n'IIC', 'X',\n'IIL', 'I'\ +,\n'IIP', 'X',\n'IK2', 'X',\n'IKT', 'X',\n'ILA', '\ +I',\n'ILE', 'I',\n'ILG', 'X',\n'ILO', 'X',\n'ILX',\ + 'I',\n'IM1', 'X',\n'IM2', 'X',\n'IMC', 'X',\n'IMD\ +', 'X',\n'IME', 'X',\n'IMF', 'X',\n'IMG', 'X',\n'I\ +MH', 'X',\n'IMI', 'X',\n'IML', 'I',\n'IMM', 'X',\n\ +'IMN', 'X',\n'IMO', 'X',\n'IMP', 'X',\n'IMR', 'X',\ +\n'IMU', 'X',\n'IN0', 'D',\n'IN1', 'R',\n'IN2', 'K\ +',\n'IN3', 'L',\n'IN4', 'X',\n'IN5', 'A',\n'IN6', \ +'L',\n'IN7', 'X',\n'IN8', 'X',\n'IN9', 'X',\n'INA'\ +, 'L',\n'INB', 'X',\n'INC', 'X',\n'IND', 'X',\n'IN\ +E', 'X',\n'INF', 'F',\n'ING', 'F',\n'INH', 'R',\n'\ +INI', 'X',\n'INJ', 'X',\n'INK', 'X',\n'INL', 'X',\\ +n'INM', 'X',\n'INN', 'A',\n'INO', 'X',\n'INP', 'X'\ +,\n'INQ', 'X',\n'INR', 'X',\n'INS', 'X',\n'INT', '\ +V',\n'INU', 'X',\n'INV', 'X',\n'INW', 'X',\n'INX',\ + 'X',\n'INY', 'X',\n'INZ', 'X',\n'IOA', 'X',\n'IOB\ +', 'X',\n'IOC', 'X',\n'IOD', 'X',\n'IOE', 'X',\n'I\ +OF', 'X',\n'IOH', 'X',\n'IOL', 'X',\n'IOP', 'X',\n\ +'IP1', 'X',\n'IP2', 'X',\n'IP3', 'X',\n'IP4', 'X',\ +\n'IPA', 'X',\n'IPB', 'X',\n'IPD', 'X',\n'IPG', 'G\ +',\n'IPH', 'X',\n'IPL', 'X',\n'IPM', 'X',\n'IPN', \ +'X',\n'IPO', 'F',\n'IPP', 'X',\n'IPS', 'X',\n'IPT'\ +, 'X',\n'IPU', 'X',\n'IPY', 'A',\n'IQB', 'X',\n'IQ\ +P', 'X',\n'IQS', 'X',\n'IR3', 'X',\n'IRI', 'X',\n'\ +IRP', 'X',\n'ISA', 'X',\n'ISF', 'X',\n'ISO', 'X',\\ +n'ISP', 'X',\n'ISQ', 'X',\n'ISU', 'X',\n'ITM', 'X'\ +,\n'ITP', 'X',\n'ITR', 'W',\n'ITS', 'X',\n'ITU', '\ +X',\n'IU5', 'X',\n'IUM', 'X',\n'IUR', 'X',\n'IVA',\ + 'X',\n'IYG', 'G',\n'IYR', 'Y',\n'J77', 'X',\n'J78\ +', 'X',\n'J80', 'X',\n'JE2', 'X',\n'JEN', 'X',\n'J\ +ST', 'X',\n'K21', 'X',\n'KAH', 'X',\n'KAI', 'X',\n\ +'KAM', 'X',\n'KAN', 'X',\n'KAP', 'X',\n'KCP', 'X',\ +\n'KCX', 'K',\n'KDO', 'X',\n'KEF', 'X',\n'KET', 'X\ +',\n'KGR', 'X',\n'KH1', 'X',\n'KIF', 'X',\n'KIV', \ +'V',\n'KNI', 'X',\n'KPH', 'K',\n'KTH', 'X',\n'KTN'\ +, 'X',\n'KTP', 'X',\n'KWT', 'X',\n'L04', 'X',\n'L1\ +P', 'X',\n'L24', 'E',\n'L2P', 'X',\n'L34', 'E',\n'\ +L37', 'E',\n'L3P', 'X',\n'L4P', 'X',\n'L75', 'X',\\ +n'LAC', 'X',\n'LAD', 'X',\n'LAK', 'X',\n'LAM', 'X'\ +,\n'LAR', 'X',\n'LAT', 'X',\n'LAX', 'X',\n'LCO', '\ +X',\n'LCP', 'X',\n'LCS', 'X',\n'LDA', 'X',\n'LDO',\ + 'L',\n'LDP', 'X',\n'LEA', 'X',\n'LEO', 'X',\n'LEU\ +', 'L',\n'LG2', 'X',\n'LG6', 'X',\n'LGC', 'X',\n'L\ +GP', 'X',\n'LHG', 'X',\n'LHY', 'F',\n'LI1', 'X',\n\ +'LIG', 'X',\n'LIL', 'X',\n'LIM', 'X',\n'LIN', 'X',\ +\n'LIO', 'X',\n'LIP', 'X',\n'LLA', 'X',\n'LLP', 'K\ +',\n'LLY', 'K',\n'LMG', 'X',\n'LML', 'X',\n'LMT', \ +'X',\n'LMU', 'X',\n'LMZ', 'X',\n'LNK', 'X',\n'LNL'\ +, 'X',\n'LNO', 'X',\n'LOF', 'X',\n'LOL', 'L',\n'LO\ +M', 'X',\n'LOR', 'X',\n'LOS', 'X',\n'LOV', 'L',\n'\ +LOX', 'X',\n'LP1', 'X',\n'LP2', 'R',\n'LPA', 'X',\\ +n'LPC', 'X',\n'LPF', 'X',\n'LPL', 'X',\n'LPM', 'X'\ +,\n'LPP', 'X',\n'LRB', 'X',\n'LRU', 'X',\n'LS1', '\ +X',\n'LS2', 'X',\n'LS3', 'X',\n'LS4', 'X',\n'LS5',\ + 'X',\n'LTA', 'X',\n'LTL', 'X',\n'LTR', 'W',\n'LUM\ +', 'X',\n'LVS', 'L',\n'LXC', 'X',\n'LY2', 'X',\n'L\ +Y3', 'X',\n'LYA', 'X',\n'LYB', 'X',\n'LYC', 'X',\n\ +'LYD', 'X',\n'LYM', 'K',\n'LYN', 'X',\n'LYS', 'K',\ +\n'LYT', 'X',\n'LYW', 'X',\n'LYZ', 'K',\n'M1A', 'X\ +',\n'M1G', 'X',\n'M2G', 'X',\n'M3L', 'K',\n'M6P', \ +'X',\n'M6T', 'X',\n'M7G', 'X',\n'MA1', 'X',\n'MA2'\ +, 'X',\n'MA3', 'X',\n'MA4', 'X',\n'MA6', 'X',\n'MA\ +A', 'A',\n'MAB', 'X',\n'MAC', 'X',\n'MAE', 'X',\n'\ +MAG', 'X',\n'MAH', 'X',\n'MAI', 'R',\n'MAK', 'X',\\ +n'MAL', 'X',\n'MAM', 'X',\n'MAN', 'X',\n'MAO', 'X'\ +,\n'MAP', 'X',\n'MAR', 'X',\n'MAS', 'X',\n'MAT', '\ +X',\n'MAU', 'X',\n'MAZ', 'X',\n'MBA', 'X',\n'MBD',\ + 'X',\n'MBG', 'X',\n'MBH', 'X',\n'MBN', 'X',\n'MBO\ +', 'X',\n'MBR', 'X',\n'MBS', 'X',\n'MBV', 'X',\n'M\ +BZ', 'X',\n'MCA', 'X',\n'MCD', 'X',\n'MCE', 'X',\n\ +'MCG', 'G',\n'MCI', 'X',\n'MCN', 'X',\n'MCP', 'X',\ +\n'MCT', 'X',\n'MCY', 'X',\n'MD2', 'X',\n'MDA', 'X\ +',\n'MDC', 'X',\n'MDG', 'X',\n'MDH', 'X',\n'MDL', \ +'X',\n'MDM', 'X',\n'MDN', 'X',\n'MDP', 'X',\n'ME6'\ +, 'X',\n'MEB', 'X',\n'MEC', 'X',\n'MEL', 'X',\n'ME\ +N', 'N',\n'MEP', 'X',\n'MER', 'X',\n'MES', 'X',\n'\ +MET', 'M',\n'MEV', 'X',\n'MF2', 'X',\n'MF3', 'M',\\ +n'MFB', 'X',\n'MFD', 'X',\n'MFU', 'X',\n'MG7', 'X'\ +,\n'MGA', 'X',\n'MGB', 'X',\n'MGD', 'X',\n'MGG', '\ +R',\n'MGL', 'X',\n'MGN', 'Q',\n'MGO', 'X',\n'MGP',\ + 'X',\n'MGR', 'X',\n'MGS', 'X',\n'MGT', 'X',\n'MGU\ +', 'X',\n'MGY', 'G',\n'MHB', 'X',\n'MHF', 'X',\n'M\ +HL', 'L',\n'MHM', 'X',\n'MHO', 'M',\n'MHS', 'H',\n\ +'MHZ', 'X',\n'MIA', 'X',\n'MIC', 'X',\n'MID', 'X',\ +\n'MIL', 'X',\n'MIM', 'X',\n'MIN', 'G',\n'MIP', 'X\ +',\n'MIS', 'S',\n'MIT', 'X',\n'MJI', 'X',\n'MK1', \ +'X',\n'MKC', 'X',\n'MLA', 'X',\n'MLC', 'X',\n'MLE'\ +, 'L',\n'MLN', 'X',\n'MLT', 'X',\n'MLY', 'K',\n'ML\ +Z', 'K',\n'MM3', 'X',\n'MM4', 'X',\n'MMA', 'X',\n'\ +MMC', 'X',\n'MME', 'M',\n'MMO', 'R',\n'MMP', 'X',\\ +n'MMQ', 'X',\n'MMT', 'X',\n'MN1', 'X',\n'MN2', 'X'\ +,\n'MN3', 'X',\n'MN5', 'X',\n'MN7', 'X',\n'MN8', '\ +X',\n'MNA', 'X',\n'MNB', 'X',\n'MNC', 'X',\n'MNG',\ + 'X',\n'MNL', 'L',\n'MNO', 'X',\n'MNP', 'X',\n'MNQ\ +', 'X',\n'MNS', 'X',\n'MNT', 'X',\n'MNV', 'V',\n'M\ +O1', 'X',\n'MO2', 'X',\n'MO3', 'X',\n'MO4', 'X',\n\ +'MO5', 'X',\n'MO6', 'X',\n'MOA', 'X',\n'MOB', 'X',\ +\n'MOC', 'X',\n'MOE', 'X',\n'MOG', 'X',\n'MOH', 'X\ +',\n'MOL', 'X',\n'MOO', 'X',\n'MOP', 'X',\n'MOR', \ +'X',\n'MOS', 'X',\n'MOT', 'X',\n'MOX', 'X',\n'MP1'\ +, 'X',\n'MP3', 'X',\n'MPA', 'X',\n'MPB', 'X',\n'MP\ +C', 'X',\n'MPD', 'X',\n'MPG', 'X',\n'MPH', 'M',\n'\ +MPI', 'X',\n'MPJ', 'M',\n'MPL', 'X',\n'MPN', 'X',\\ +n'MPO', 'X',\n'MPP', 'X',\n'MPQ', 'G',\n'MPR', 'X'\ +,\n'MPS', 'X',\n'MQ0', 'X',\n'MQ7', 'X',\n'MQ8', '\ +X',\n'MQ9', 'X',\n'MQI', 'X',\n'MR2', 'X',\n'MRC',\ + 'X',\n'MRM', 'X',\n'MRP', 'X',\n'MS2', 'X',\n'MSA\ +', 'X',\n'MSB', 'X',\n'MSD', 'X',\n'MSE', 'M',\n'M\ +SF', 'X',\n'MSI', 'X',\n'MSO', 'M',\n'MSQ', 'X',\n\ +'MST', 'X',\n'MSU', 'X',\n'MTA', 'X',\n'MTB', 'X',\ +\n'MTC', 'X',\n'MTD', 'X',\n'MTE', 'X',\n'MTF', 'X\ +',\n'MTG', 'X',\n'MTO', 'X',\n'MTS', 'X',\n'MTT', \ +'X',\n'MTX', 'X',\n'MTY', 'Y',\n'MUG', 'X',\n'MUP'\ +, 'X',\n'MUR', 'X',\n'MVA', 'V',\n'MW1', 'X',\n'MW\ +2', 'X',\n'MXA', 'X',\n'MXY', 'X',\n'MYA', 'X',\n'\ +MYC', 'X',\n'MYG', 'X',\n'MYR', 'X',\n'MYS', 'X',\\ +n'MYT', 'X',\n'MZM', 'X',\n'N1T', 'X',\n'N25', 'X'\ +,\n'N2B', 'X',\n'N3T', 'X',\n'N4B', 'X',\n'NA2', '\ +X',\n'NA5', 'X',\n'NA6', 'X',\n'NAA', 'X',\n'NAB',\ + 'X',\n'NAC', 'X',\n'NAD', 'X',\n'NAE', 'X',\n'NAF\ +', 'X',\n'NAG', 'X',\n'NAH', 'X',\n'NAI', 'X',\n'N\ +AL', 'A',\n'NAM', 'A',\n'NAN', 'X',\n'NAO', 'X',\n\ +'NAP', 'X',\n'NAQ', 'X',\n'NAR', 'X',\n'NAS', 'X',\ +\n'NAU', 'X',\n'NAV', 'X',\n'NAW', 'X',\n'NAX', 'X\ +',\n'NAY', 'X',\n'NBA', 'X',\n'NBD', 'X',\n'NBE', \ +'X',\n'NBG', 'X',\n'NBN', 'X',\n'NBP', 'X',\n'NBS'\ +, 'X',\n'NBU', 'X',\n'NCA', 'X',\n'NCB', 'A',\n'NC\ +D', 'X',\n'NCH', 'X',\n'NCM', 'X',\n'NCN', 'X',\n'\ +NCO', 'X',\n'NCR', 'X',\n'NCS', 'X',\n'ND4', 'X',\\ +n'NDA', 'X',\n'NDC', 'X',\n'NDD', 'X',\n'NDO', 'X'\ +,\n'NDP', 'X',\n'NDT', 'X',\n'NEA', 'X',\n'NEB', '\ +X',\n'NED', 'X',\n'NEM', 'H',\n'NEN', 'X',\n'NEO',\ + 'X',\n'NEP', 'H',\n'NEQ', 'X',\n'NES', 'X',\n'NET\ +', 'X',\n'NEV', 'X',\n'NFA', 'F',\n'NFE', 'X',\n'N\ +FG', 'X',\n'NFP', 'X',\n'NFS', 'X',\n'NG6', 'X',\n\ +'NGA', 'X',\n'NGL', 'X',\n'NGM', 'X',\n'NGO', 'X',\ +\n'NGP', 'X',\n'NGT', 'X',\n'NGU', 'X',\n'NH2', 'X\ +',\n'NH3', 'X',\n'NH4', 'X',\n'NHD', 'X',\n'NHE', \ +'X',\n'NHM', 'X',\n'NHP', 'X',\n'NHR', 'X',\n'NHS'\ +, 'X',\n'NI1', 'X',\n'NI2', 'X',\n'NIC', 'X',\n'NI\ +D', 'X',\n'NIK', 'X',\n'NIO', 'X',\n'NIP', 'X',\n'\ +NIT', 'X',\n'NIU', 'X',\n'NIY', 'Y',\n'NLA', 'X',\\ +n'NLE', 'L',\n'NLG', 'X',\n'NLN', 'L',\n'NLP', 'L'\ +,\n'NM1', 'X',\n'NMA', 'A',\n'NMB', 'X',\n'NMC', '\ +G',\n'NMD', 'X',\n'NME', 'X',\n'NMN', 'X',\n'NMO',\ + 'X',\n'NMQ', 'X',\n'NMX', 'X',\n'NMY', 'X',\n'NNH\ +', 'R',\n'NNO', 'X',\n'NO2', 'X',\n'NO3', 'X',\n'N\ +OA', 'X',\n'NOD', 'X',\n'NOJ', 'X',\n'NON', 'X',\n\ +'NOP', 'X',\n'NOR', 'X',\n'NOS', 'X',\n'NOV', 'X',\ +\n'NOX', 'X',\n'NP3', 'X',\n'NPA', 'X',\n'NPC', 'X\ +',\n'NPD', 'X',\n'NPE', 'X',\n'NPF', 'X',\n'NPH', \ +'C',\n'NPI', 'X',\n'NPL', 'X',\n'NPN', 'X',\n'NPO'\ +, 'X',\n'NPP', 'X',\n'NPT', 'X',\n'NPY', 'X',\n'NR\ +G', 'R',\n'NRI', 'X',\n'NS1', 'X',\n'NS5', 'X',\n'\ +NSP', 'X',\n'NTA', 'X',\n'NTB', 'X',\n'NTC', 'X',\\ +n'NTH', 'X',\n'NTM', 'X',\n'NTP', 'X',\n'NTS', 'X'\ +,\n'NTU', 'X',\n'NTZ', 'X',\n'NU1', 'X',\n'NVA', '\ +V',\n'NVI', 'X',\n'NVP', 'X',\n'NW1', 'X',\n'NYP',\ + 'X',\n'O4M', 'X',\n'OAA', 'X',\n'OAI', 'X',\n'OAP\ +', 'X',\n'OAR', 'X',\n'OAS', 'S',\n'OBA', 'X',\n'O\ +BN', 'X',\n'OC1', 'X',\n'OC2', 'X',\n'OC3', 'X',\n\ +'OC4', 'X',\n'OC5', 'X',\n'OC6', 'X',\n'OC7', 'X',\ +\n'OCL', 'X',\n'OCM', 'X',\n'OCN', 'X',\n'OCO', 'X\ +',\n'OCP', 'X',\n'OCS', 'C',\n'OCT', 'X',\n'OCV', \ +'K',\n'OCY', 'C',\n'ODA', 'X',\n'ODS', 'X',\n'OES'\ +, 'X',\n'OET', 'X',\n'OF1', 'X',\n'OF2', 'X',\n'OF\ +3', 'X',\n'OFL', 'X',\n'OFO', 'X',\n'OHE', 'X',\n'\ +OHO', 'X',\n'OHT', 'X',\n'OIC', 'X',\n'OIP', 'X',\\ +n'OKA', 'X',\n'OLA', 'X',\n'OLE', 'X',\n'OLI', 'X'\ +,\n'OLO', 'X',\n'OMB', 'X',\n'OMC', 'X',\n'OMD', '\ +X',\n'OME', 'X',\n'OMG', 'X',\n'OMP', 'X',\n'OMT',\ + 'M',\n'OMU', 'X',\n'ONE', 'X',\n'ONL', 'L',\n'ONP\ +', 'X',\n'OPA', 'X',\n'OPD', 'X',\n'OPE', 'X',\n'O\ +PG', 'X',\n'OPH', 'X',\n'OPN', 'X',\n'OPP', 'X',\n\ +'OPR', 'R',\n'ORN', 'X',\n'ORO', 'X',\n'ORP', 'X',\ +\n'OSB', 'X',\n'OSS', 'X',\n'OTA', 'X',\n'OTB', 'X\ +',\n'OTE', 'X',\n'OTG', 'X',\n'OUT', 'X',\n'OVA', \ +'X',\n'OWQ', 'X',\n'OXA', 'X',\n'OXE', 'X',\n'OXI'\ +, 'X',\n'OXL', 'X',\n'OXM', 'X',\n'OXN', 'X',\n'OX\ +O', 'X',\n'OXP', 'X',\n'OXS', 'X',\n'OXY', 'X',\n'\ +P11', 'A',\n'P24', 'X',\n'P28', 'X',\n'P2P', 'X',\\ +n'P2U', 'X',\n'P3M', 'X',\n'P4C', 'X',\n'P4P', 'X'\ +,\n'P5P', 'X',\n'P6G', 'X',\n'PA1', 'X',\n'PA2', '\ +X',\n'PA3', 'X',\n'PA4', 'X',\n'PA5', 'X',\n'PAA',\ + 'X',\n'PAB', 'X',\n'PAC', 'X',\n'PAD', 'X',\n'PAE\ +', 'X',\n'PAG', 'X',\n'PAH', 'X',\n'PAI', 'X',\n'P\ +AL', 'D',\n'PAM', 'X',\n'PAN', 'X',\n'PAO', 'X',\n\ +'PAP', 'A',\n'PAQ', 'F',\n'PAR', 'X',\n'PAS', 'X',\ +\n'PAT', 'W',\n'PBA', 'X',\n'PBB', 'X',\n'PBC', 'X\ +',\n'PBF', 'F',\n'PBG', 'X',\n'PBI', 'X',\n'PBM', \ +'X',\n'PBN', 'X',\n'PBP', 'X',\n'PBR', 'X',\n'PBZ'\ +, 'X',\n'PC2', 'X',\n'PCA', 'E',\n'PCB', 'X',\n'PC\ +D', 'X',\n'PCE', 'X',\n'PCG', 'X',\n'PCH', 'X',\n'\ +PCL', 'X',\n'PCM', 'X',\n'PCP', 'X',\n'PCR', 'X',\\ +n'PCS', 'X',\n'PCU', 'X',\n'PCV', 'X',\n'PCY', 'X'\ +,\n'PD1', 'X',\n'PDA', 'X',\n'PDC', 'X',\n'PDD', '\ +A',\n'PDE', 'A',\n'PDI', 'X',\n'PDL', 'A',\n'PDN',\ + 'X',\n'PDO', 'X',\n'PDP', 'X',\n'PDT', 'X',\n'PDU\ +', 'X',\n'PE2', 'X',\n'PE6', 'X',\n'PEA', 'X',\n'P\ +EB', 'X',\n'PEC', 'X',\n'PED', 'X',\n'PEE', 'X',\n\ +'PEF', 'X',\n'PEG', 'X',\n'PEL', 'X',\n'PEO', 'X',\ +\n'PEP', 'X',\n'PEQ', 'X',\n'PER', 'X',\n'PET', 'X\ +',\n'PFB', 'X',\n'PFC', 'X',\n'PFG', 'X',\n'PFL', \ +'X',\n'PFM', 'X',\n'PFZ', 'X',\n'PG4', 'X',\n'PG5'\ +, 'X',\n'PG6', 'X',\n'PGA', 'X',\n'PGC', 'X',\n'PG\ +D', 'X',\n'PGE', 'X',\n'PGG', 'G',\n'PGH', 'X',\n'\ +PGL', 'X',\n'PGO', 'X',\n'PGP', 'X',\n'PGQ', 'X',\\ +n'PGR', 'X',\n'PGS', 'X',\n'PGU', 'X',\n'PGX', 'X'\ +,\n'PGY', 'G',\n'PH1', 'X',\n'PH2', 'X',\n'PH3', '\ +X',\n'PHA', 'F',\n'PHB', 'X',\n'PHC', 'X',\n'PHD',\ + 'X',\n'PHE', 'F',\n'PHG', 'X',\n'PHH', 'X',\n'PHI\ +', 'F',\n'PHL', 'F',\n'PHM', 'X',\n'PHN', 'X',\n'P\ +HO', 'X',\n'PHP', 'X',\n'PHQ', 'X',\n'PHS', 'H',\n\ +'PHT', 'X',\n'PHW', 'P',\n'PHY', 'X',\n'PI1', 'X',\ +\n'PI2', 'X',\n'PI3', 'X',\n'PI4', 'X',\n'PI5', 'X\ +',\n'PI6', 'X',\n'PI7', 'X',\n'PI8', 'X',\n'PI9', \ +'X',\n'PIA', 'X',\n'PIB', 'X',\n'PIC', 'X',\n'PID'\ +, 'X',\n'PIG', 'X',\n'PIH', 'X',\n'PIM', 'X',\n'PI\ +N', 'X',\n'PIO', 'X',\n'PIP', 'X',\n'PIQ', 'X',\n'\ +PIR', 'X',\n'PIV', 'X',\n'PKF', 'X',\n'PL1', 'X',\\ +n'PL9', 'X',\n'PLA', 'D',\n'PLC', 'X',\n'PLE', 'L'\ +,\n'PLG', 'G',\n'PLH', 'X',\n'PLM', 'X',\n'PLP', '\ +X',\n'PLS', 'S',\n'PLT', 'W',\n'PLU', 'L',\n'PLY',\ + 'X',\n'PMA', 'X',\n'PMB', 'X',\n'PMC', 'X',\n'PME\ +', 'F',\n'PML', 'X',\n'PMM', 'X',\n'PMO', 'X',\n'P\ +MP', 'X',\n'PMS', 'X',\n'PMY', 'X',\n'PN2', 'X',\n\ +'PNA', 'X',\n'PNB', 'X',\n'PNC', 'G',\n'PND', 'X',\ +\n'PNE', 'A',\n'PNF', 'X',\n'PNG', 'X',\n'PNI', 'X\ +',\n'PNL', 'X',\n'PNM', 'X',\n'PNN', 'X',\n'PNO', \ +'X',\n'PNP', 'X',\n'PNQ', 'X',\n'PNS', 'X',\n'PNT'\ +, 'X',\n'PNU', 'X',\n'PO2', 'X',\n'PO4', 'X',\n'PO\ +B', 'X',\n'POC', 'X',\n'POL', 'X',\n'POM', 'P',\n'\ +PON', 'X',\n'POP', 'X',\n'POR', 'X',\n'POS', 'X',\\ +n'PP1', 'X',\n'PP2', 'X',\n'PP3', 'A',\n'PP4', 'X'\ +,\n'PP5', 'X',\n'PP6', 'X',\n'PP7', 'X',\n'PP8', '\ +N',\n'PP9', 'X',\n'PPB', 'X',\n'PPC', 'X',\n'PPD',\ + 'X',\n'PPE', 'E',\n'PPG', 'X',\n'PPH', 'F',\n'PPI\ +', 'X',\n'PPJ', 'V',\n'PPL', 'X',\n'PPM', 'X',\n'P\ +PN', 'A',\n'PPO', 'X',\n'PPP', 'X',\n'PPQ', 'X',\n\ +'PPR', 'X',\n'PPS', 'X',\n'PPT', 'X',\n'PPU', 'X',\ +\n'PPX', 'F',\n'PPY', 'X',\n'PPZ', 'X',\n'PQ0', 'X\ +',\n'PQN', 'X',\n'PQQ', 'X',\n'PR1', 'X',\n'PR2', \ +'X',\n'PR3', 'X',\n'PRA', 'X',\n'PRB', 'X',\n'PRC'\ +, 'X',\n'PRD', 'X',\n'PRE', 'X',\n'PRF', 'X',\n'PR\ +H', 'X',\n'PRI', 'P',\n'PRL', 'X',\n'PRN', 'X',\n'\ +PRO', 'P',\n'PRP', 'X',\n'PRR', 'A',\n'PRS', 'P',\\ +n'PRZ', 'X',\n'PS0', 'X',\n'PSA', 'X',\n'PSD', 'X'\ +,\n'PSE', 'X',\n'PSF', 'S',\n'PSG', 'X',\n'PSI', '\ +X',\n'PSO', 'X',\n'PSQ', 'X',\n'PSS', 'X',\n'PST',\ + 'X',\n'PSU', 'X',\n'PT1', 'X',\n'PT3', 'X',\n'PTA\ +', 'X',\n'PTC', 'X',\n'PTD', 'X',\n'PTE', 'X',\n'P\ +TH', 'Y',\n'PTL', 'X',\n'PTM', 'Y',\n'PTN', 'X',\n\ +'PTO', 'X',\n'PTP', 'X',\n'PTR', 'Y',\n'PTS', 'X',\ +\n'PTT', 'X',\n'PTU', 'X',\n'PTY', 'X',\n'PUA', 'X\ +',\n'PUB', 'X',\n'PUR', 'X',\n'PUT', 'X',\n'PVA', \ +'X',\n'PVB', 'X',\n'PVH', 'H',\n'PVL', 'X',\n'PXA'\ +, 'X',\n'PXF', 'X',\n'PXG', 'X',\n'PXP', 'X',\n'PX\ +Y', 'X',\n'PXZ', 'X',\n'PY2', 'X',\n'PY4', 'X',\n'\ +PY5', 'X',\n'PY6', 'X',\n'PYA', 'A',\n'PYC', 'X',\\ +n'PYD', 'X',\n'PYE', 'X',\n'PYL', 'X',\n'PYM', 'X'\ +,\n'PYO', 'X',\n'PYP', 'X',\n'PYQ', 'X',\n'PYR', '\ +X',\n'PYS', 'X',\n'PYT', 'X',\n'PYX', 'X',\n'PYY',\ + 'X',\n'PYZ', 'X',\n'PZQ', 'X',\n'Q82', 'X',\n'QNC\ +', 'X',\n'QND', 'X',\n'QSI', 'Q',\n'QTR', 'X',\n'Q\ +UA', 'X',\n'QUE', 'X',\n'QUI', 'X',\n'QUO', 'X',\n\ +'R11', 'X',\n'R12', 'X',\n'R13', 'X',\n'R18', 'X',\ +\n'R1P', 'X',\n'R56', 'X',\n'R5P', 'X',\n'RA2', 'X\ +',\n'RAD', 'X',\n'RAI', 'X',\n'RAL', 'X',\n'RAM', \ +'X',\n'RAN', 'X',\n'RAP', 'X',\n'RBF', 'X',\n'RBU'\ +, 'X',\n'RCA', 'X',\n'RCL', 'X',\n'RCO', 'X',\n'RD\ +C', 'X',\n'RDF', 'W',\n'RE9', 'X',\n'REA', 'X',\n'\ +RED', 'K',\n'REO', 'X',\n'REP', 'X',\n'RET', 'X',\\ +n'RFA', 'X',\n'RFB', 'X',\n'RFL', 'X',\n'RFP', 'X'\ +,\n'RG1', 'X',\n'RGS', 'X',\n'RH1', 'X',\n'RHA', '\ +X',\n'RHC', 'X',\n'RHD', 'X',\n'RHM', 'X',\n'RHO',\ + 'X',\n'RHQ', 'X',\n'RHS', 'X',\n'RIA', 'X',\n'RIB\ +', 'X',\n'RIC', 'X',\n'RIF', 'X',\n'RIN', 'X',\n'R\ +IP', 'X',\n'RIT', 'X',\n'RMB', 'X',\n'RMN', 'X',\n\ +'RMP', 'X',\n'RNG', 'X',\n'RNS', 'X',\n'RNT', 'X',\ +\n'RO2', 'X',\n'RO4', 'X',\n'ROC', 'N',\n'ROI', 'X\ +',\n'ROM', 'X',\n'RON', 'V',\n'ROP', 'X',\n'ROS', \ +'X',\n'ROX', 'X',\n'RPA', 'X',\n'RPD', 'X',\n'RPH'\ +, 'X',\n'RPL', 'X',\n'RPP', 'X',\n'RPR', 'X',\n'RP\ +X', 'X',\n'RQ3', 'X',\n'RR1', 'X',\n'RR6', 'X',\n'\ +RRS', 'X',\n'RS1', 'X',\n'RS2', 'X',\n'RS7', 'X',\\ +n'RSS', 'X',\n'RTA', 'X',\n'RTB', 'X',\n'RTC', 'X'\ +,\n'RTL', 'X',\n'RUB', 'X',\n'RUN', 'X',\n'RWJ', '\ +X',\n'RXP', 'X',\n'S02', 'X',\n'S11', 'X',\n'S1H',\ + 'S',\n'S27', 'X',\n'S2C', 'C',\n'S3P', 'X',\n'S4U\ +', 'X',\n'S57', 'X',\n'S58', 'X',\n'S5H', 'X',\n'S\ +6G', 'X',\n'S80', 'X',\n'SAA', 'X',\n'SAB', 'X',\n\ +'SAC', 'S',\n'SAD', 'X',\n'SAE', 'X',\n'SAF', 'X',\ +\n'SAH', 'C',\n'SAI', 'C',\n'SAL', 'X',\n'SAM', 'M\ +',\n'SAN', 'X',\n'SAP', 'X',\n'SAR', 'X',\n'SAS', \ +'X',\n'SB1', 'X',\n'SB2', 'X',\n'SB3', 'X',\n'SB4'\ +, 'X',\n'SB5', 'X',\n'SB6', 'X',\n'SBA', 'L',\n'SB\ +B', 'X',\n'SBD', 'A',\n'SBI', 'X',\n'SBL', 'A',\n'\ +SBN', 'X',\n'SBO', 'X',\n'SBR', 'X',\n'SBS', 'X',\\ +n'SBT', 'X',\n'SBU', 'X',\n'SBX', 'X',\n'SC4', 'X'\ +,\n'SCA', 'X',\n'SCC', 'X',\n'SCD', 'X',\n'SCH', '\ +C',\n'SCI', 'X',\n'SCL', 'X',\n'SCM', 'X',\n'SCN',\ + 'X',\n'SCO', 'X',\n'SCP', 'S',\n'SCR', 'X',\n'SCS\ +', 'X',\n'SCV', 'C',\n'SCY', 'C',\n'SD8', 'X',\n'S\ +DK', 'X',\n'SDZ', 'X',\n'SE4', 'X',\n'SEA', 'X',\n\ +'SEB', 'S',\n'SEC', 'X',\n'SEG', 'A',\n'SEI', 'X',\ +\n'SEL', 'S',\n'SEM', 'X',\n'SEO', 'X',\n'SEP', 'S\ +',\n'SER', 'S',\n'SES', 'X',\n'SET', 'S',\n'SEU', \ +'X',\n'SF4', 'X',\n'SFG', 'X',\n'SFN', 'X',\n'SFO'\ +, 'X',\n'SGA', 'X',\n'SGC', 'X',\n'SGL', 'X',\n'SG\ +M', 'X',\n'SGN', 'X',\n'SGP', 'X',\n'SHA', 'X',\n'\ +SHC', 'X',\n'SHF', 'X',\n'SHH', 'X',\n'SHP', 'G',\\ +n'SHR', 'E',\n'SHT', 'T',\n'SHU', 'X',\n'SI2', 'X'\ +,\n'SIA', 'X',\n'SIF', 'X',\n'SIG', 'X',\n'SIH', '\ +X',\n'SIM', 'X',\n'SIN', 'X',\n'SKD', 'X',\n'SKF',\ + 'X',\n'SLB', 'X',\n'SLE', 'X',\n'SLZ', 'K',\n'SMA\ +', 'X',\n'SMC', 'C',\n'SME', 'M',\n'SML', 'X',\n'S\ +MM', 'M',\n'SMN', 'X',\n'SMP', 'X',\n'SMS', 'X',\n\ +'SN1', 'X',\n'SN6', 'X',\n'SN7', 'X',\n'SNC', 'C',\ +\n'SNN', 'X',\n'SNP', 'X',\n'SO1', 'X',\n'SO2', 'X\ +',\n'SO3', 'X',\n'SO4', 'X',\n'SOA', 'X',\n'SOC', \ +'C',\n'SOM', 'X',\n'SOR', 'X',\n'SOT', 'X',\n'SOX'\ +, 'X',\n'SPA', 'X',\n'SPB', 'X',\n'SPC', 'X',\n'SP\ +D', 'X',\n'SPE', 'X',\n'SPG', 'X',\n'SPH', 'X',\n'\ +SPI', 'X',\n'SPK', 'X',\n'SPM', 'X',\n'SPN', 'X',\\ +n'SPO', 'X',\n'SPP', 'X',\n'SPS', 'X',\n'SPY', 'X'\ +,\n'SQU', 'X',\n'SRA', 'X',\n'SRB', 'X',\n'SRD', '\ +X',\n'SRL', 'X',\n'SRM', 'X',\n'SRS', 'X',\n'SRY',\ + 'X',\n'SSA', 'X',\n'SSB', 'X',\n'SSG', 'X',\n'SSP\ +', 'X',\n'ST1', 'X',\n'ST2', 'X',\n'ST3', 'X',\n'S\ +T4', 'X',\n'ST5', 'X',\n'ST6', 'X',\n'STA', 'X',\n\ +'STB', 'X',\n'STE', 'X',\n'STG', 'X',\n'STI', 'X',\ +\n'STL', 'X',\n'STN', 'X',\n'STO', 'X',\n'STP', 'X\ +',\n'STR', 'X',\n'STU', 'X',\n'STY', 'Y',\n'SU1', \ +'X',\n'SU2', 'X',\n'SUC', 'X',\n'SUI', 'X',\n'SUL'\ +, 'X',\n'SUR', 'X',\n'SVA', 'S',\n'SWA', 'X',\n'T1\ +6', 'X',\n'T19', 'X',\n'T23', 'X',\n'T29', 'X',\n'\ +T33', 'X',\n'T3P', 'X',\n'T42', 'A',\n'T44', 'X',\\ +n'T5A', 'X',\n'T6A', 'T',\n'T6P', 'X',\n'T80', 'X'\ +,\n'T87', 'X',\n'TA1', 'X',\n'TAA', 'X',\n'TAB', '\ +X',\n'TAC', 'X',\n'TAD', 'X',\n'TAF', 'X',\n'TAM',\ + 'X',\n'TAP', 'X',\n'TAR', 'X',\n'TAS', 'X',\n'TAU\ +', 'X',\n'TAX', 'X',\n'TAZ', 'X',\n'TB9', 'X',\n'T\ +BA', 'X',\n'TBD', 'X',\n'TBG', 'G',\n'TBH', 'X',\n\ +'TBM', 'T',\n'TBO', 'X',\n'TBP', 'X',\n'TBR', 'X',\ +\n'TBS', 'X',\n'TBT', 'X',\n'TBU', 'X',\n'TBZ', 'X\ +',\n'TC4', 'X',\n'TCA', 'X',\n'TCB', 'X',\n'TCH', \ +'X',\n'TCK', 'X',\n'TCL', 'X',\n'TCM', 'X',\n'TCN'\ +, 'X',\n'TCP', 'X',\n'TCR', 'W',\n'TCS', 'X',\n'TC\ +Z', 'X',\n'TDA', 'X',\n'TDB', 'X',\n'TDG', 'X',\n'\ +TDP', 'X',\n'TDR', 'X',\n'TDX', 'X',\n'TEA', 'X',\\ +n'TEM', 'X',\n'TEN', 'X',\n'TEO', 'X',\n'TEP', 'X'\ +,\n'TER', 'X',\n'TES', 'X',\n'TET', 'X',\n'TFA', '\ +X',\n'TFB', 'X',\n'TFH', 'X',\n'TFI', 'X',\n'TFK',\ + 'X',\n'TFP', 'X',\n'THA', 'X',\n'THB', 'X',\n'THC\ +', 'T',\n'THD', 'X',\n'THE', 'X',\n'THF', 'X',\n'T\ +HJ', 'X',\n'THK', 'X',\n'THM', 'X',\n'THN', 'X',\n\ +'THO', 'T',\n'THP', 'X',\n'THQ', 'X',\n'THR', 'T',\ +\n'THS', 'X',\n'THT', 'X',\n'THU', 'X',\n'THX', 'X\ +',\n'THZ', 'X',\n'TI1', 'X',\n'TI2', 'X',\n'TI3', \ +'P',\n'TIA', 'X',\n'TIH', 'A',\n'TK4', 'X',\n'TLA'\ +, 'X',\n'TLC', 'X',\n'TLM', 'X',\n'TLN', 'X',\n'TL\ +X', 'X',\n'TM5', 'X',\n'TM6', 'X',\n'TMA', 'X',\n'\ +TMB', 'T',\n'TMC', 'X',\n'TMD', 'T',\n'TME', 'X',\\ +n'TMF', 'X',\n'TML', 'K',\n'TMM', 'X',\n'TMN', 'X'\ +,\n'TMP', 'X',\n'TMQ', 'X',\n'TMR', 'X',\n'TMT', '\ +X',\n'TMZ', 'X',\n'TNB', 'C',\n'TND', 'X',\n'TNK',\ + 'X',\n'TNP', 'X',\n'TNT', 'X',\n'TOA', 'X',\n'TOB\ +', 'X',\n'TOC', 'X',\n'TOL', 'X',\n'TOP', 'X',\n'T\ +OS', 'X',\n'TOT', 'X',\n'TP1', 'G',\n'TP2', 'P',\n\ +'TP3', 'E',\n'TP4', 'E',\n'TP7', 'T',\n'TPA', 'X',\ +\n'TPE', 'X',\n'TPF', 'X',\n'TPI', 'X',\n'TPL', 'W\ +',\n'TPM', 'X',\n'TPN', 'G',\n'TPO', 'T',\n'TPP', \ +'X',\n'TPQ', 'A',\n'TPR', 'P',\n'TPS', 'X',\n'TPT'\ +, 'X',\n'TPV', 'X',\n'TPX', 'X',\n'TPY', 'X',\n'TQ\ +3', 'X',\n'TQ4', 'X',\n'TQ5', 'X',\n'TQ6', 'X',\n'\ +TR1', 'X',\n'TRA', 'X',\n'TRB', 'X',\n'TRC', 'X',\\ +n'TRD', 'X',\n'TRE', 'X',\n'TRF', 'W',\n'TRG', 'K'\ +,\n'TRH', 'X',\n'TRI', 'X',\n'TRJ', 'X',\n'TRM', '\ +X',\n'TRN', 'W',\n'TRO', 'W',\n'TRP', 'W',\n'TRQ',\ + 'X',\n'TRS', 'X',\n'TRX', 'W',\n'TRZ', 'X',\n'TS2\ +', 'X',\n'TS3', 'X',\n'TS4', 'X',\n'TS5', 'X',\n'T\ +SA', 'X',\n'TSB', 'X',\n'TSI', 'X',\n'TSM', 'X',\n\ +'TSN', 'X',\n'TSP', 'X',\n'TSU', 'X',\n'TTA', 'X',\ +\n'TTE', 'X',\n'TTN', 'X',\n'TTO', 'X',\n'TTP', 'X\ +',\n'TTX', 'X',\n'TXL', 'X',\n'TYA', 'Y',\n'TYB', \ +'Y',\n'TYD', 'X',\n'TYI', 'Y',\n'TYL', 'X',\n'TYM'\ +, 'W',\n'TYN', 'Y',\n'TYQ', 'Y',\n'TYR', 'Y',\n'TY\ +S', 'Y',\n'TYV', 'X',\n'TYY', 'A',\n'TZB', 'X',\n'\ +TZC', 'X',\n'TZE', 'X',\n'TZL', 'X',\n'TZO', 'X',\\ +n'TZP', 'X',\n'U01', 'X',\n'U02', 'X',\n'U03', 'X'\ +,\n'U04', 'X',\n'U05', 'X',\n'U0E', 'X',\n'U10', '\ +X',\n'U18', 'X',\n'U2G', 'X',\n'U3P', 'X',\n'U49',\ + 'X',\n'U55', 'X',\n'U5P', 'X',\n'U66', 'X',\n'U89\ +', 'X',\n'U8U', 'X',\n'UAA', 'X',\n'UAG', 'A',\n'U\ +AP', 'X',\n'UAR', 'X',\n'UC1', 'X',\n'UC2', 'X',\n\ +'UC3', 'X',\n'UC4', 'X',\n'UD1', 'X',\n'UD2', 'X',\ +\n'UDP', 'X',\n'UDX', 'X',\n'UFG', 'X',\n'UFM', 'X\ +',\n'UFP', 'X',\n'UGA', 'X',\n'UIN', 'X',\n'UKP', \ +'A',\n'UM3', 'X',\n'UMA', 'A',\n'UMG', 'X',\n'UMP'\ +, 'X',\n'UNA', 'X',\n'UND', 'X',\n'UNI', 'X',\n'UN\ +K', 'X',\n'UNN', 'X',\n'UNX', 'X',\n'UP5', 'X',\n'\ +UP6', 'X',\n'UPA', 'X',\n'UPF', 'X',\n'UPG', 'X',\\ +n'UPP', 'X',\n'UQ1', 'X',\n'UQ2', 'X',\n'UQ6', 'X'\ +,\n'UR2', 'X',\n'URA', 'X',\n'URE', 'X',\n'URF', '\ +X',\n'URI', 'X',\n'URS', 'X',\n'UTP', 'X',\n'UVC',\ + 'X',\n'UVW', 'X',\n'V35', 'X',\n'V36', 'X',\n'V4O\ +', 'X',\n'V7O', 'X',\n'VAA', 'V',\n'VAC', 'X',\n'V\ +AD', 'V',\n'VAF', 'V',\n'VAG', 'X',\n'VAL', 'V',\n\ +'VAN', 'X',\n'VAS', 'X',\n'VAX', 'X',\n'VDX', 'X',\ +\n'VDY', 'X',\n'VG1', 'X',\n'VIB', 'X',\n'VIR', 'X\ +',\n'VIT', 'X',\n'VK3', 'X',\n'VO3', 'X',\n'VO4', \ +'X',\n'VS1', 'F',\n'VS2', 'F',\n'VS3', 'F',\n'VS4'\ +, 'F',\n'VXA', 'X',\n'W01', 'X',\n'W02', 'X',\n'W0\ +3', 'X',\n'W11', 'X',\n'W33', 'X',\n'W35', 'X',\n'\ +W42', 'X',\n'W43', 'X',\n'W54', 'X',\n'W56', 'X',\\ +n'W59', 'X',\n'W71', 'X',\n'W84', 'X',\n'W8R', 'X'\ +,\n'W91', 'X',\n'WAY', 'X',\n'WCC', 'X',\n'WO2', '\ +X',\n'WO4', 'X',\n'WRB', 'X',\n'WRR', 'X',\n'WRS',\ + 'X',\n'WW7', 'X',\n'X2F', 'X',\n'X7O', 'X',\n'XAA\ +', 'X',\n'XAN', 'X',\n'XAO', 'X',\n'XBB', 'X',\n'X\ +BP', 'X',\n'XDN', 'X',\n'XDP', 'X',\n'XIF', 'X',\n\ +'XIM', 'X',\n'XK2', 'X',\n'XL1', 'X',\n'XLS', 'X',\ +\n'XMP', 'X',\n'XN1', 'X',\n'XN2', 'X',\n'XN3', 'X\ +',\n'XUL', 'X',\n'XV6', 'X',\n'XYD', 'X',\n'XYH', \ +'X',\n'XYL', 'X',\n'XYP', 'X',\n'XYS', 'X',\n'YOF'\ +, 'Y',\n'YRR', 'X',\n'YT3', 'X',\n'YZ9', 'X',\n'Z3\ +4', 'G',\n'Z5A', 'X',\n'ZAF', 'X',\n'ZAP', 'X',\n'\ +ZEB', 'X',\n'ZEN', 'X',\n'ZES', 'X',\n'ZID', 'X',\\ +n'ZMR', 'X',\n'ZN3', 'X',\n'ZNH', 'X',\n'ZNO', 'X'\ +,\n'ZO3', 'X',\n'ZPR', 'P',\n'ZRA', 'A',\n'ZST', '\ +X',\n'ZYA', 'A',\n\n\n'ASN','N');\n} \n\n\nsub fil\ +e2head\n {\n my $file = shift;\n my $size = s\ +hift;\n my $f= new FileHandle;\n my $line;\n open \ +($f,$file);\n read ($f,$line, $size);\n close ($f)\ +;\n return $line;\n }\nsub file2tail\n {\ +\n my $file = shift;\n my $size = shift;\n my $f= \ +new FileHandle;\n my $line;\n \n open ($f,$file);\\ +n seek ($f,$size*-1, 2);\n read ($f,$line, $size);\ +\n close ($f);\n return $line;\n }\n\n\nsub v\ +tmpnam\n {\n my $r=rand(100000);\n my $f=\"fi\ +le.$r.$$\";\n while (-e $f)\n {\n $f=vtmpnam\ +();\n }\n push (@TMPFILE_LIST, $f);\n return $f;\ +\n }\n\nsub myexit\n {\n my $code=@_[0];\\ +n if ($CLEAN_EXIT_STARTED==1){return;}\n els\ +e {$CLEAN_EXIT_STARTED=1;}\n ### ONLY BARE EXIT\ +\n exit ($code);\n }\nsub set_error_lock\n \ +{\n my $name = shift;\n my $pid=$$;\n\n \ + \n &lock4tc ($$,\"LERROR\", \"LSET\", \"\ +$$ -- ERROR: $name $PROGRAM\\n\");\n return;\\ +n }\nsub set_lock\n {\n my $pid=shift;\n \ + my $msg= shift;\n my $p=getppid();\n &lock4\ +tc ($pid,\"LLOCK\",\"LRESET\",\"$p$msg\\n\");\n }\ +\nsub unset_lock\n {\n \n my $pid=shift;\\ +n &lock4tc ($pid,\"LLOCK\",\"LRELEASE\",\"\");\\ +n }\nsub shift_lock\n {\n my $from=shift;\n \ + my $to=shift;\n my $from_type=shift;\n my \ +$to_type=shift;\n my $action=shift;\n my $ms\ +g;\n \n if (!&lock4tc($from, $from_type, \"L\ +CHECK\", \"\")){return 0;}\n $msg=&lock4tc ($fr\ +om, $from_type, \"LREAD\", \"\");\n &lock4tc ($\ +from, $from_type,\"LRELEASE\", $msg);\n &lock4t\ +c ($to, $to_type, $action, $msg);\n return;\n \ +}\nsub isshellpid\n {\n my $p=shift;\n if (\ +!lock4tc ($p, \"LLOCK\", \"LCHECK\")){return 0;}\n\ + else\n {\n my $c=lock4tc($p, \"LLOCK\", \\ +"LREAD\");\n if ( $c=~/-SHELL-/){return 1;}\n \ + }\n return 0;\n }\nsub isrootpid\n {\n if\ +(lock4tc (getppid(), \"LLOCK\", \"LCHECK\")){retur\ +n 0;}\n else {return 1;}\n }\nsub lock4tc\n {\\ +n my ($pid,$type,$action,$value)=@_;\n my $fna\ +me;\n my $host=hostname;\n \n if ($type eq \\ +"LLOCK\"){$fname=\"$LOCKDIR/.$pid.$host.lock4tcoff\ +ee\";}\n elsif ( $type eq \"LERROR\"){ $fname=\"\ +$LOCKDIR/.$pid.$host.error4tcoffee\";}\n elsif (\ + $type eq \"LWARNING\"){ $fname=\"$LOCKDIR/.$pid.$\ +host.warning4tcoffee\";}\n \n if ($debug_lock)\ +\n {\n print STDERR \"\\n\\t---lock4tc(t\ +cg): $action => $fname =>$value (RD: $LOCKDIR)\\n\\ +";\n }\n\n if ($action eq \"LCHECK\") {re\ +turn -e $fname;}\n elsif ($action eq \"LREAD\"){\ +return file2string($fname);}\n elsif ($action eq\ + \"LSET\") {return string2file ($value, $fname, \"\ +>>\");}\n elsif ($action eq \"LRESET\") {return \ +string2file ($value, $fname, \">\");}\n elsif ($\ +action eq \"LRELEASE\") \n {\n if ( $deb\ +ug_lock)\n {\n my $g=new FileHandle;\n open\ + ($g, \">>$fname\");\n print $g \"\\nDestroyed \ +by $$\\n\";\n close ($g);\n safe_system (\"m\ +v $fname $fname.old\");\n }\n else\n {\n \ + unlink ($fname);\n }\n }\n return \"\";\n\ + }\n \nsub file2string\n {\n my $file=@_[0];\n \ + my $f=new FileHandle;\n my $r;\n open ($f, \"\ +$file\");\n while (<$f>){$r.=$_;}\n close ($f)\ +;\n return $r;\n }\nsub string2file \n {\n \ + my ($s,$file,$mode)=@_;\n my $f=new FileHandle\ +;\n \n open ($f, \"$mode$file\");\n print\ + $f \"$s\";\n close ($f);\n }\n\nBEGIN\n {\ +\n srand;\n \n $SIG{'SIGUP'}='signal_\ +cleanup';\n $SIG{'SIGINT'}='signal_cleanup';\\ +n $SIG{'SIGQUIT'}='signal_cleanup';\n $S\ +IG{'SIGILL'}='signal_cleanup';\n $SIG{'SIGTRA\ +P'}='signal_cleanup';\n $SIG{'SIGABRT'}='sign\ +al_cleanup';\n $SIG{'SIGEMT'}='signal_cleanup\ +';\n $SIG{'SIGFPE'}='signal_cleanup';\n \ +\n $SIG{'SIGKILL'}='signal_cleanup';\n $\ +SIG{'SIGPIPE'}='signal_cleanup';\n $SIG{'SIGS\ +TOP'}='signal_cleanup';\n $SIG{'SIGTTIN'}='si\ +gnal_cleanup';\n $SIG{'SIGXFSZ'}='signal_clea\ +nup';\n $SIG{'SIGINFO'}='signal_cleanup';\n \ + \n $SIG{'SIGBUS'}='signal_cleanup';\n \ + $SIG{'SIGALRM'}='signal_cleanup';\n $SIG{'S\ +IGTSTP'}='signal_cleanup';\n $SIG{'SIGTTOU'}=\ +'signal_cleanup';\n $SIG{'SIGVTALRM'}='signal\ +_cleanup';\n $SIG{'SIGUSR1'}='signal_cleanup'\ +;\n\n\n $SIG{'SIGSEGV'}='signal_cleanup';\n \ + $SIG{'SIGTERM'}='signal_cleanup';\n $SIG{\ +'SIGCONT'}='signal_cleanup';\n $SIG{'SIGIO'}=\ +'signal_cleanup';\n $SIG{'SIGPROF'}='signal_c\ +leanup';\n $SIG{'SIGUSR2'}='signal_cleanup';\\ +n\n $SIG{'SIGSYS'}='signal_cleanup';\n $\ +SIG{'SIGURG'}='signal_cleanup';\n $SIG{'SIGCH\ +LD'}='signal_cleanup';\n $SIG{'SIGXCPU'}='sig\ +nal_cleanup';\n $SIG{'SIGWINCH'}='signal_clea\ +nup';\n \n $SIG{'INT'}='signal_cleanup';\ +\n $SIG{'TERM'}='signal_cleanup';\n $SIG\ +{'KILL'}='signal_cleanup';\n $SIG{'QUIT'}='si\ +gnal_cleanup';\n \n our $debug_lock=$ENV\ +{\"DEBUG_LOCK\"};\n \n \n \n \\ +n foreach my $a (@ARGV){$CL.=\" $a\";}\n \ + if ( $debug_lock ){print STDERR \"\\n\\n\\n******\ +**** START PG: $PROGRAM *************\\n\";}\n \ + if ( $debug_lock ){print STDERR \"\\n\\n\\n*****\ +*****(tcg) LOCKDIR: $LOCKDIR $$ *************\\n\"\ +;}\n if ( $debug_lock ){print STDERR \"\\n --\ +- $$ -- $CL\\n\";}\n \n \n \n \ +\n }\nsub flush_error\n {\n my $msg=shift;\\ +n return add_error ($EXIT_FAILURE,$$, $$,getppi\ +d(), $msg, $CL);\n }\nsub add_error \n {\n my\ + $code=shift;\n my $rpid=shift;\n my $pid=sh\ +ift;\n my $ppid=shift;\n my $type=shift;\n \ + my $com=shift;\n \n $ERROR_DONE=1;\n lo\ +ck4tc ($rpid, \"LERROR\",\"LSET\",\"$pid -- ERROR:\ + $type\\n\");\n lock4tc ($$, \"LERROR\",\"LSET\\ +", \"$pid -- COM: $com\\n\");\n lock4tc ($$, \"\ +LERROR\",\"LSET\", \"$pid -- STACK: $ppid -> $pid\\ +\n\");\n \n return $code;\n }\nsub add_warni\ +ng \n {\n my $rpid=shift;\n my $pid =shift;\ +\n my $command=shift;\n my $msg=\"$$ -- WARN\ +ING: $command\\n\";\n print STDERR \"$msg\";\n \ + lock4tc ($$, \"LWARNING\", \"LSET\", $msg);\n \ +}\n\nsub signal_cleanup\n {\n print dtderr \"\\ +\n**** $$ (tcg) was killed\\n\";\n &cleanup;\n \ + exit ($EXIT_FAILURE);\n }\nsub clean_dir\n {\\ +n my $dir=@_[0];\n if ( !-d $dir){return ;}\\ +n elsif (!($dir=~/tmp/)){return ;}#safety check\ + 1\n elsif (($dir=~/\\*/)){return ;}#safety che\ +ck 2\n else\n {\n `rm -rf $dir`;\n }\\ +n return;\n }\nsub cleanup\n {\n #print st\ +derr \"\\n----tc: $$ Kills $PIDCHILD\\n\";\n #k\ +ill (SIGTERM,$PIDCHILD);\n my $p=getppid();\n \ + $CLEAN_EXIT_STARTED=1;\n \n \n \n if\ + (&lock4tc($$,\"LERROR\", \"LCHECK\", \"\"))\n \ + {\n my $ppid=getppid();\n if (!$ERROR_DONE) \n \ + {\n &lock4tc($$,\"LERROR\", \"LSET\", \"$$ --\ + STACK: $p -> $$\\n\");\n &lock4tc($$,\"LERROR\ +\", \"LSET\", \"$$ -- COM: $CL\\n\");\n }\n \ + }\n my $warning=&lock4tc($$, \"LWARNING\", \"L\ +READ\", \"\");\n my $error=&lock4tc($$, \"LERR\ +OR\", \"LREAD\", \"\");\n #release error and wa\ +rning lock if root\n \n if (isrootpid() && (\ +$warning || $error) )\n {\n \n print STDERR \\ +"**************** Summary *************\\n$error\\\ +n$warning\\n\";\n\n &lock4tc($$,\"LERROR\",\"RELEA\ +SE\",\"\");\n &lock4tc($$,\"LWARNING\",\"RELEASE\"\ +,\"\");\n } \n \n \n foreach my $f (\ +@TMPFILE_LIST)\n {\n if (-e $f){unlink ($f);}\ + \n }\n foreach my $d (@TMPDIR_LIST)\n \ + {\n clean_dir ($d);\n }\n #No More Lock \ +Release\n #&lock4tc($$,\"LLOCK\",\"LRELEASE\",\\ +"\"); #release lock \n\n if ( $debug_lock ){pri\ +nt STDERR \"\\n\\n\\n********** END PG: $PROGRAM (\ +$$) *************\\n\";}\n if ( $debug_lock ){p\ +rint STDERR \"\\n\\n\\n**********(tcg) LOCKDIR: $L\ +OCKDIR $$ *************\\n\";}\n }\nEND \n {\n \ + \n &cleanup();\n }\n \n\nsub safe_system \\ +n{\n my $com=shift;\n my $ntry=shift;\n my $ctr\ +y=shift;\n my $pid;\n my $status;\n my $ppid=ge\ +tppid();\n if ($com eq \"\"){return 1;}\n \n \n\ +\n if (($pid = fork ()) < 0){return (-1);}\n if \ +($pid == 0)\n {\n set_lock($$, \" -SHELL- \ +$com (tcg)\");\n exec ($com);\n }\n else\\ +n {\n lock4tc ($$, \"LLOCK\", \"LSET\", \"\ +$pid\\n\");#update parent\n $PIDCHILD=$pid;\n\ + }\n if ($debug_lock){printf STDERR \"\\n\\t .\ +... safe_system (fasta_seq2hmm) p: $$ c: $pid COM\ +: $com\\n\";}\n\n waitpid ($pid,WTERMSIG);\n\n s\ +hift_lock ($pid,$$, \"LWARNING\",\"LWARNING\", \"L\ +SET\");\n\n if ($? == $EXIT_FAILURE || lock4tc($p\ +id, \"LERROR\", \"LCHECK\", \"\"))\n {\n i\ +f ($ntry && $ctry <$ntry)\n {\n add_warning ($$,\ +$$,\"$com failed [retry: $ctry]\");\n lock4tc ($\ +pid, \"LRELEASE\", \"LERROR\", \"\");\n return s\ +afe_system ($com, $ntry, ++$ctry);\n }\n elsi\ +f ($ntry == -1)\n {\n if (!shift_lock ($pid, $$,\ + \"LERROR\", \"LWARNING\", \"LSET\"))\n {\n \ + add_warning ($$,$$,\"$com failed\");\n }\n\ + else\n {\n lock4tc ($pid, \"LRELEASE\\ +", \"LERROR\", \"\");\n }\n return $?;}\n \ + else\n {\n if (!shift_lock ($pid,$$, \"LERROR\ +\",\"LERROR\", \"LSET\"))\n {\n myexit(a\ +dd_error ($EXIT_FAILURE,$$,$pid,getppid(), \"UNSPE\ +CIFIED system\", $com));\n }\n }\n }\n ret\ +urn $?;\n}\n\nsub check_configuration \n {\n \ + my @l=@_;\n my $v;\n foreach my $p (@\ +l)\n {\n \n if ( $p eq \"EMAIL\")\n { \n\ + if ( !($EMAIL=~/@/))\n {\n add_warning($$\ +,$$,\"Could Not Use EMAIL\");\n myexit(add_error \ +($EXIT_FAILURE,$$,$$,getppid(),\"EMAIL\",\"$CL\"))\ +;\n }\n }\n elsif( $p eq \"INTERNET\")\ +\n {\n if ( !&check_internet_connection(\ +))\n {\n myexit(add_error ($EXIT_FAILURE,$$,$$\ +,getppid(),\"INTERNET\",\"$CL\"));\n }\n }\n \ + elsif( $p eq \"wget\")\n {\n if (!&pg_\ +is_installed (\"wget\") && !&pg_is_installed (\"cu\ +rl\"))\n {\n myexit(add_error ($EXIT_FAILURE,$\ +$,$$,getppid(),\"PG_NOT_INSTALLED:wget\",\"$CL\"))\ +;\n }\n }\n elsif( !(&pg_is_installed ($p))\ +)\n {\n myexit(add_error ($EXIT_FAILURE,\ +$$,$$,getppid(),\"PG_NOT_INSTALLED:$p\",\"$CL\"));\ +\n }\n }\n return 1;\n }\nsub pg_is_in\ +stalled\n {\n my @ml=@_;\n my $r, $p, $m;\n\ + my $supported=0;\n \n my $p=shift (@ml);\ +\n if ($p=~/::/)\n {\n if (safe_system (\"\ +perl -M$p -e 1\")==$EXIT_SUCCESS){return 1;}\n els\ +e {return 0;}\n }\n else\n {\n $r=`wh\ +ich $p 2>/dev/null`;\n if ($r eq \"\"){return 0;}\\ +n else {return 1;}\n }\n }\n\n\n\nsub check_\ +internet_connection\n {\n my $internet;\n m\ +y $tmp;\n &check_configuration ( \"wget\"); \n \ + \n $tmp=&vtmpnam ();\n \n if (&pg_\ +is_installed (\"wget\")){`wget www.google.com -\ +O$tmp >/dev/null 2>/dev/null`;}\n elsif (&pg_i\ +s_installed (\"curl\")){`curl www.google.com -o\ +$tmp >/dev/null 2>/dev/null`;}\n \n if ( !-e\ + $tmp || -s $tmp < 10){$internet=0;}\n else {$i\ +nternet=1;}\n if (-e $tmp){unlink $tmp;}\n\n \ + return $internet;\n }\nsub check_pg_is_installed\ +\n {\n my @ml=@_;\n my $r=&pg_is_installed \ +(@ml);\n if (!$r && $p=~/::/)\n {\n print \ +STDERR \"\\nYou Must Install the perl package $p o\ +n your system.\\nRUN:\\n\\tsudo perl -MCPAN -e 'in\ +stall $pg'\\n\";\n }\n elsif (!$r)\n \ +{\n myexit(flush_error(\"\\nProgram $p Supported b\ +ut Not Installed on your system\"));\n }\n \ + else\n {\n return 1;\n }\n }\n\n\n","u\ +se Cwd;\nuse Env;\nuse File::Path;\nuse FileHandle\ +;\nuse strict;\n\n\nour (%MODE, %PG, %ENV_SET, %SU\ +PPORTED_OS);\n\n\nour $EXIT_SUCCESS=0;\nour $EXIT_\ +FAILURE=1;\nour $INTERNET=0;\n\nour $CP=\"cp \"; #\ +was causing a crash on MacOSX\nour $SILENT=\">/dev\ +/null 2>/dev/null\";\nour $WEB_BASE=\"http://www.t\ +coffee.org\";\nour $TCLINKDB_ADDRESS=\"$WEB_BASE/R\ +esources/tclinkdb.txt\";\nour $OS=get_os();\nour $\ +ROOT=&get_root();\nour $CD=cwd();\nour $CDIR=$CD;\\ +nour $HOME=$ENV{'HOME'};\n\nour $OSNAME=$ENV{'OSNA\ +ME'};\nour $OSARCH=$ENV{'OSARCH'};\nour $REPO_ROOT\ +=\"\";\n\nour $TCDIR;\nour $TCCACHE;\nour $TCTMP;\\ +nour $TCM;\nour $TCMETHODS;\nour $TCPLUGINS;\nour \ +$PLUGINS_DIR=\"\";\nour $INSTALL_DIR=\"\";\n\nour \ +$CXX=\"g++\";\nour $CXXFLAGS=\"\";\n\nour $CPP=\"g\ +++\";\nour $CPPFLAGS=\"\";\n\nour $CC=\"gcc\";\nou\ +r $CFLAGS=\"\";\n\nour $FC=\"f77\";\nour $FFLAGS=\\ +"\";\n\nmy $install=\"all\";\nmy $default_update_a\ +ction=\"no_update\";\nmy @required_applications=(\\ +"wget_OR_curl\");\nmy @smode=(\"all\", \"clean\", \ +\"install\");\n\n&initialize_PG();\n\nmy $cl=join(\ + \" \", @ARGV);\nif ($#ARGV==-1 || ($cl=~/-h/) ||(\ +$cl=~/-H/) )\n {\n print \"\\n!!!!!!! ./insta\ +ll t_coffee --> installs t_coffee onl\ +y\";\n print \"\\n!!!!!!! ./install all \ + --> installs all the modes [mcoffee, e\ +xpresso, psicoffee,rcoffee..]\";\n print \"\\n\ +!!!!!!! ./install [mcoffee|rcoffee|..] --> instal\ +ls the specified mode\";\n print \"\\n!!!!!!! \ +./install -h --> print usage\\n\ +\\n\";\n if ( $#ARGV==-1){exit ($EXIT_FAILURE)\ +;}\n }\n \nif (($cl=~/-h/) ||($cl=~/-H/) )\n\ + {\n my $m;\n print \"\\n\\n!!!!!!! advance\ +d mode\\n\";\n foreach $m ((keys (%MODE)),@smod\ +e)\n {\n print \"!!!!!!! ./install $m\\\ +n\";\n }\n \n print \"!!!!!!! ./install\ + [target:package|mode|] [-update|-force|-exec=dir|\ +-dis=dir|-root|-tclinkdb=file|-] [CC=|FCC=|CXX=|CF\ +LAGS=|CXXFLAGS=]\\n\";\n print \"!!!!!!! ./inst\ +all clean [removes all executables]\\n\";\n \ +print \"!!!!!!! ./install [optional:target] -updat\ +e [updates package already installed\ +]\\n\";\n print \"!!!!!!! ./install [optional:t\ +arget] -force [Forces recompilation\ + over everything]\\n\";\n \n print \"!!!!!!!\ + ./install [optional:target] -root \ + [You are running as root]\\n\";\n print \"!!!!\ +!!! ./install [optional:target] -exec=/foo/bar/ \ + [address for the T-Coffee executable]\\n\";\n \ + print \"!!!!!!! ./install [optional:target] -di\ +s=/foo/bar/ [Address where distributions sh\ +ould be stored]\\n\";\n print \"!!!!!!! ./insta\ +ll [optional:target] -tclinkdb=foo|update [file c\ +ontaining all the packages to be installed]\\n\";\\ +n print \"!!!!!!! ./install [optional:target] -\ +clean [clean everything]\\n\";\n \ + print \"!!!!!!! ./install [optional:target] -plug\ +ins [plugins directory]\\n\";\n pr\ +int \"!!!!!!! ./install [optional:target] -tcdir=/\ +foor/bar [base path where T-Coffee will be in\ +stalled]\\n\";\n print \"!!!!!!! ./install [opt\ +ional:target] -repo=/path/to/repo [binaries repo\ +sitory root directory]\\n\";\n print \"!!!!!!! \ +mode:\";\n foreach $m (keys(%MODE)){print \"$m \ +\";}\n print \"\\n\";\n print \"!!!!!!! Pack\ +ages:\";\n foreach $m (keys (%PG)){print \"$m \\ +";}\n print \"\\n\";\n \n print \"\\n\\n\\ +";\n exit ($EXIT_FAILURE);\n }\n\n\n\nmy (@arg\ +l)=($cl=~/(\\S+=[^=]+)\\s\\w+=/g);\npush (@argl, (\ +$cl=~/(\\S+=[^=]+\\S)\\s*$/g));\n\nforeach $a (@ar\ +gl)\n {\n if ( ($cl=~/CXX=(.*)/)){$CXX=$1;}\n \ + if ( ($cl=~/-CC=(.*)/ )){$CC=$1;}\n if ( \ +($cl=~/-FC=(.*)/ )){$FC=$1;}\n if ( ($cl=~/-\ +CFLAGS=(.*)/)){$CFLAGS=$1;}\n if ( ($cl=~/-CXXF\ +LAGS=(.*)/)){$CXXFLAGS=$1;}\n }\nour ($ROOT_INSTA\ +LL, $NO_QUESTION, $default_update_action,$BINARIES\ +_ONLY,$force, $default_update_action, $INSTALL_DIR\ +, $PLUGINS_DIR, $DISTRIBUTIONS,$tclinkdb, $proxy, \ +$clean);\nif ( ($cl=~/-root/)){$ROOT_INSTALL=1;}\n\ +if ( ($cl=~/-no_question/)){$NO_QUESTION=1;}\nif (\ + ($cl=~/-update/)){$default_update_action=\"update\ +\";}\nif ( ($cl=~/-binaries/)){$BINARIES_ONLY=1;}\\ +nif ( ($cl=~/-force/)){$force=1;$default_update_ac\ +tion=\"update\"}\nif ( ($cl=~/-exec=\\s*(\\S+)/)){\ +$INSTALL_DIR=$1;}\nif ( ($cl=~/-plugins=\\s*(\\S+)\ +/)){$PLUGINS_DIR=$1;}\nif ( ($cl=~/-dis=\\s*(\\S+)\ +/)){$DISTRIBUTIONS=$1;}\n\nif ( ($cl=~/-tclinkdb=\\ +\s*(\\S+)/)){$tclinkdb=$1;}\nif ( ($cl=~/-proxy=\\\ +s*(\\S+)/)){$proxy=$1;}\nif ( ($cl=~/-clean/)){$cl\ +ean=1;}\nif ( ($cl=~/-repo=\\s*(\\S+)/)){ $REPO_RO\ +OT=$1; }\nif ( ($cl=~/-tcdir=\\s*(\\S+)/)){ $TCDIR\ +=$1; }\nif ($tclinkdb){&update_tclinkdb ($tclinkdb\ +);}\n\n\nif( $REPO_ROOT ne \"\" ) {\n if( $OSNAME \ +eq \"\" ) { print \"You have specified the reposit\ +ory folder but the required \\\"OSNAME\\\" envirom\ +ent variable is missing. \\n\"; exit 1; } \n if( $\ +OSARCH eq \"\" ) { print \"You have specified the \ +repository folder but the required \\\"OSARCH\\\" \ +enviroment variable is missing. \\n\"; exit 1; } \\ +n}\n\n\nif(!$TCDIR) { $TCDIR=\"$HOME/.t_coffee\"; \ +}\n&add_dir ($TCDIR);\n&add_dir ($TCCACHE=\"$TCDIR\ +/cache\");\n&add_dir ($TCTMP=\"$CDIR/tmp\");\n&add\ +_dir ($TCM=\"$TCDIR/mcoffee\");\n&add_dir ($TCMETH\ +ODS=\"$TCDIR/methods\");\n&add_dir ($TCPLUGINS=\"$\ +TCDIR/plugins/$OS\");\n\n\nour $BASE=\"$CD/bin\";\\ +nour $BIN=\"$BASE/binaries/$OS\";\nour $DOWNLOAD_D\ +IR=\"$BASE/download\";\nour $DOWNLOAD_FILE=\"$DOWN\ +LOAD_DIR/files\";\nour $TMP=\"$BASE/tmp\";\n\n&add\ +_dir($BASE);\n&add_dir($BIN);\n&add_dir($DOWNLOAD_\ +DIR);\n&add_dir($DOWNLOAD_FILE);\nif (!$DISTRIBUTI\ +ONS){$DISTRIBUTIONS=\"$DOWNLOAD_DIR/distributions\\ +";}\n&add_dir ($DISTRIBUTIONS);\n&add_dir ($TMP);\\ +n\n\nif (!$PLUGINS_DIR && !$ROOT_INSTALL){$PLUG\ +INS_DIR=$TCPLUGINS;}\nelsif (!$PLUGINS_DIR && $RO\ +OT_INSTALL){$PLUGINS_DIR=\"/usr/local/bin/\";}\n\n\ +if (!$INSTALL_DIR && !$ROOT_INSTALL){$INSTALL_D\ +IR=\"$HOME/bin/\";mkpath ($INSTALL_DIR);}\nelsif (\ +!$INSTALL_DIR && $ROOT_INSTALL){$INSTALL_DIR=\"/u\ +sr/local/bin/\";}\n\nif (-d \"mcoffee\"){`cp mcoff\ +ee/* $TCM`;}\n\n\nour $ENV_FILE=\"$TCDIR/t_coffee_\ +env\";\n&env_file2putenv ($ENV_FILE);\n&set_proxy(\ +$proxy);\nmy ($target, $p, $r);\n$target=$p;\n\nfo\ +reach $p ( ((keys (%PG)),(keys(%MODE)),(@smode)) \ +)\n {\n if ($ARGV[0] eq $p && $target eq \"\")\ +{$target=$p;}\n }\nif ($target eq \"\"){exit ($EX\ +IT_FAILURE);}\n\n\nforeach $r (@required_applicati\ +ons)\n {\n my @app_list;\n my $i;\n $i=0\ +;\n \n @app_list=split (/_OR_/, $r);\n fo\ +reach my $pg (@app_list)\n {\n $i+=&pg_is_ins\ +talled ($pg);\n }\n if ($i==0)\n {\n \ + print \"One of the following packages must be\ + installed to proceed: \";\n foreach my $pg (\ +@app_list)\n {\n print (\"$pg \");\n }\n di\ +e;\n }\n }\n\n\n\n\n\n\n&sign_license_ni();\n\\ +n\n$PG{C}{compiler}=get_C_compiler($CC);\n$PG{Fort\ +ran}{compiler}=get_F_compiler($FC);\n$PG{CXX}{comp\ +iler}=$PG{CPP}{compiler}=$PG{GPP}{compiler}=get_CX\ +X_compiler($CXX);\nif ($CXXFLAGS){$PG{CPP}{options\ +}=$PG{GPP}{options}=$PG{CXX}{options}=$CXXFLAGS;}\\ +nif ($CFLAGS){$PG{C}{options}=$CFLAGS;}\nforeach m\ +y $c (keys(%PG))\n {\n my $arguments;\n if \ +($PG{$c}{compiler})\n {\n $arguments=\"$PG{$c\ +}{compiler_flag}=$PG{$c}{compiler} \";\n if ($PG{$\ +c}{options})\n {\n $arguments.=\"$PG{$c}{opt\ +ions_flag}=$PG{$c}{options} \";\n }\n $PG{$c}{ar\ +guments}=$arguments;\n }\n }\n\nif ($PG{$tar\ +get}){$PG{$target}{install}=1;}\nelse\n {\n fo\ +reach my $pg (keys(%PG))\n {\n if ( $target e\ +q \"all\" || ($PG{$pg}{mode}=~/$target/))\n {\n \ + $PG{$pg} {install}=1;\n }\n }\n }\n\nf\ +oreach my $pg (keys(%PG))\n {\n if (!$PG{$pg}{\ +update_action}){$PG{$pg}{update_action}=$default_u\ +pdate_action;}\n elsif ($PG{$pg}{update_action}\ + eq \"never\"){$PG{$pg}{install}=0;}\n if ( $fo\ +rce && $PG{$pg}{install})\n {\n `rm $BIN/$pg \ +$BIN/$pg.exe $SILENT`;\n }\n if ($PG{$pg}{\ +update_action} eq \"update\" && $PG{$pg}{install})\ +{$PG{$pg}{update}=1;}\n }\n\nif (($target=~/clean\ +/))\n {\n print \"------- cleaning executables\ + -----\\n\";\n `rm bin/* $SILENT`;\n exit ($\ +EXIT_SUCCESS);\n }\n\nif ( !$PG{$target}){print \\ +"------- Installing T-Coffee Modes\\n\";}\n\nforea\ +ch my $m (keys(%MODE))\n {\n if ( $target eq \\ +"all\" || $target eq $m)\n {\n print \"\\n---\ +---- The installer will now install the $m compone\ +nts $MODE{$m}{description}\\n\";\n foreach my $pg \ +(keys(%PG))\n {\n if ( $PG{$pg}{mode} =~/$m/\ + && $PG{$pg}{install})\n {\n if ($PG{$pg}{t\ +ouched}){print \"------- $PG{$pg}{dname}: already \ +processed\\n\";}\n else {$PG{$pg}{success}=&insta\ +ll_pg($pg);$PG{$pg}{touched}=1;}\n }\n }\n\ + }\n }\n\nif ( $PG{$target}){print \"-------\ + Installing Individual Package\\n\";}\nforeach my \ +$pg (keys (%PG))\n {\n \n if ( $PG{$pg}{ins\ +tall} && !$PG{$pg}{touched})\n {\n print \"\\\ +n------- Install $pg\\n\";\n $PG{$pg}{success}=&in\ +stall_pg($pg);$PG{$pg}{touched}=1;\n }\n }\n\ +print \"------- Finishing The installation\\n\";\n\ +my $final_report=&install ($INSTALL_DIR);\n\nprint\ + \"\\n\";\nprint \"*******************************\ +**************************************\\n\";\nprin\ +t \"******** INSTALLATION SUMMARY \ + *****************\\n\";\nprint \"***********\ +**************************************************\ +********\\n\";\nprint \"------- SUMMARY package In\ +stallation:\\n\";\nprint \"------- Executable In\ +stalled in: $PLUGINS_DIR\\n\";\n\nforeach my $pg (\ +keys(%PG))\n {\n if ( $PG{$pg}{install})\n \ + {\n my $bin_status=($PG{$pg}{from_binary} && $PG\ +{$pg}{success})?\"[from binary]\":\"\";\n if (\ + $PG{$pg}{new} && !$PG{$pg}{old}) \ + {print \"*------ $PG{$pg}{dname}: insta\ +lled $bin_status\\n\"; $PG{$pg}{status}=1;}\n elsi\ +f ( $PG{$pg}{new} && $PG{$pg}{old}) \ + {print \"*------ $PG{$pg}{dname}: u\ +pdated $bin_status\\n\" ; $PG{$pg}{status}=1;} \n\ + elsif (!$PG{$pg}{new} && $PG{$pg}{old} && !$PG{\ +$pg}{update}){print \"*------ $PG{$pg}{dnam\ +e}: previous\\n\" ; $PG{$pg}{status}=1;}\n elsif \ +(!$PG{$pg}{new} && $PG{$pg}{old} && $PG{$pg}{upd\ +ate}){print \"*------ $PG{$pg}{dname}: fail\ +ed update (previous installation available)\\n\";$\ +PG{$pg}{status}=0;}\n else \ + {print \"*------\ + $PG{$pg}{dname}: failed installation\\n\";\ +$PG{$pg}{status}=0;}\n }\n }\nmy $failure;\n\ +\nif ( !$PG{$target}){print \"*------ SUMMARY mode\ + Installation:\\n\";}\nforeach my $m (keys(%MODE))\ +\n {\n \n if ( $target eq \"all\" || $target \ +eq $m)\n {\n my $succesful=1;\n foreach my $p\ +g (keys(%PG))\n {\n if (($PG{$pg}{mode}=~/$m\ +/) && $PG{$pg}{install} && $PG{$pg}{status}==0)\n \ + {\n $succesful=0;\n print \"*!!!!!! \ +$PG{$pg}{dname}: Missing\\n\";\n }\n }\n i\ +f ( $succesful)\n {\n $MODE{$m}{status}=1;\n\ + print \"*------ MODE $MODE{$m}{dname} S\ +UCCESSFULLY installed\\n\";\n }\n else\n {\n \ + $failure++;\n $MODE{$m}{status}=0;\n pr\ +int \"*!!!!!! MODE $MODE{$m}{dname} UNSUCCES\ +SFULLY installed\\n\";\n }\n }\n }\n\n \ +\n \nif ($clean==1 && ($BASE=~/install4tcoffe\ +e/) ){print \"*------ Clean Installation Directory\ +: $BASE\\n\";`rm -rf $BASE`;}\nforeach my $pg (key\ +s(%PG)){if ($PG{$pg}{install} && $PG{$pg}{status}=\ +=0){exit ($EXIT_FAILURE);}}\n\nif ($failure)\n {\\ +n print \"*************************************\ +********************************\\n\";\n print \ +\"******** SOME PACKAGES FAILED TO INSTALL \ + *****************\\n\";\n print \"*********\ +**************************************************\ +**********\\n\";\n print \"\\nSome of the repor\ +ted failures may be due to connectivity problems\"\ +;\n print \"\\nRerun the installation and the i\ +nstaller will specifically try to install the miss\ +ing packages\";\n print \"\\nIf this Fails, go \ +to the original website and install the package ma\ +nually\";\n }\n\nprint \"************************\ +*********************************************\\n\"\ +;\nprint \"******** FINALIZE YOUR INS\ +TALLATION *****************\\n\";\nprint \"****\ +**************************************************\ +***************\\n\";\nprint \"------- Your execut\ +ables are in:\\n\"; \nprint \"------- $PLUGI\ +NS_DIR:\\n\";\nprint \"------- Add this directory \ +to your path with the following command:\\n\";\npr\ +int \"------- export PATH=$PLUGINS_DIR:\\$PA\ +TH\\n\";\nprint \"------- Make this permanent by a\ +dding this line to the file:\\n\";\nprint \"------\ +- $HOME/.bashrc\\n\";\nexit ($EXIT_SUCCESS);\ + \n \nsub get_CXX_compiler\n {\n my $c=@_[0]\ +;\n my (@clist)=(\"g++\");\n \n return ge\ +t_compil ($c, @clist);\n }\nsub get_C_compiler\n \ +{\n my $c=@_[0];\n my (@clist)=(\"gcc\", \"c\ +c\", \"icc\");\n \n return get_compil ($c, @\ +clist);\n }\n\nsub get_F_compiler\n {\n my ($c\ +)=@_[0];\n my @clist=(\"f77\", \"g77\",\"g95\",\ + \"gfortran\", \"ifort\");\n return get_compil \ +($c, @clist);\n } \n \nsub get_compil\n {\\ +n my ($fav,@clist)=(@_);\n \n #return the\ + first compiler found installed in the system. Che\ +ck first the favorite\n foreach my $c ($fav,@cl\ +ist)\n {\n if (&pg_is_installed ($c)){return\ + $c;}\n }\n return \"\";\n }\nsub exit_if\ +_pg_not_installed\n {\n my (@arg)=(@_);\n \\ +n foreach my $p (@arg)\n {\n if ( !&pg_is_\ +installed ($p))\n {\n print \"!!!!!!!! The $\ +p utility must be installed for this installation \ +to proceed [FATAL]\\n\";\n die;\n }\n }\ +\n return 1;\n }\nsub set_proxy\n {\n my (\ +$proxy)=(@_);\n my (@list,$p);\n \n @list\ += (\"HTTP_proxy\", \"http_proxy\", \"HTTP_PROXY\",\ + \"ALL_proxy\", \"all_proxy\",\"HTTP_proxy_4_TCOFF\ +EE\",\"http_proxy_4_TCOFFEE\");\n \n if (!$p\ +roxy)\n {\n foreach my $p (@list)\n {\n \ + if ( ($ENV_SET{$p}) || $ENV{$p}){$proxy=$ENV{$p};\ +}\n }\n }\n foreach my $p(@list){$ENV{$p\ +}=$proxy;}\n }\n \nsub check_internet_connection\\ +n {\n my $internet;\n \n if ( -e \"x\"){\ +unlink (\"x\");}\n if (&pg_is_installed \ +(\"wget\")){`wget www.google.com -Ox >/dev/null 2>\ +/dev/null`;}\n elsif (&pg_is_installed (\"c\ +url\")){`curl www.google.com -ox >/dev/null 2>/dev\ +/null`;}\n else\n {\n printf stderr \"\\nE\ +RROR: No pg for remote file fetching [wget or curl\ +][FATAL]\\n\";\n exit ($EXIT_FAILURE);\n }\n \ + \n if ( !-e \"x\" || -s \"x\" < 10){$interne\ +t=0;}\n else {$internet=1;}\n if (-e \"x\"){\ +unlink \"x\";}\n return $internet;\n }\nsub ur\ +l2file\n {\n my ($cmd, $file,$wget_arg, $curl_\ +arg)=(@_);\n my ($exit,$flag, $pg, $arg);\n \ +\n if ($INTERNET || check_internet_connection (\ +)){$INTERNET=1;}\n else\n {\n print STDERR\ + \"ERROR: No Internet Connection [FATAL:install.pl\ +]\\n\";\n exit ($EXIT_FAILURE);\n }\n \n \ + if (&pg_is_installed (\"wget\")){$pg=\"wg\ +et\"; $flag=\"-O\";$arg=\"--tries=2 --connect-time\ +out=10 $wget_arg\";}\n elsif (&pg_is_installed\ + (\"curl\")){$pg=\"curl\"; $flag=\"-o\";$arg=$c\ +url_arg;}\n else\n {\n printf stderr \"\\n\ +ERROR: No pg for remote file fetching [wget or cur\ +l][FATAL]\\n\";\n exit ($EXIT_FAILURE);\n }\n\ + \n \n if (-e $file){unlink($file);}\n \ + $exit=system \"$pg $cmd $flag$file $arg\";\n r\ +eturn $exit;\n }\n\nsub pg_is_installed\n {\n \ + my ($p, $dir)=(@_);\n my ($r,$m, $ret);\n m\ +y ($supported, $language, $compil);\n \n \n \ + if ( $PG{$p})\n {\n $language=$PG{$p}{langua\ +ge2};\n $compil=$PG{$language}{compiler};\n }\ +\n \n if ( $compil eq \"CPAN\")\n {\n i\ +f ( system (\"perl -M$p -e 1\")==$EXIT_SUCCESS){$r\ +et=1;}\n else {$ret=0;}\n }\n elsif ($dir)\ +\n {\n if (-e \"$dir/$p\" || -e \"$dir/$p\\.e\ +xe\"){$ret=1;}\n else {$ret=0;}\n }\n elsi\ +f (-e \"$PLUGINS_DIR/$p\" || -e \"$PLUGINS_DIR/$p.\ +exe\"){$ret=1;}\n else\n {\n $r=`which $p \ +2>/dev/null`;\n if ($r eq \"\"){$ret=0;}\n else {$\ +ret=1;}\n }\n \n return $ret;\n }\nsub \ +install\n {\n my ($new_bin)=(@_);\n my ($co\ +pied, $report);\n\n \n if (!$ROOT_INSTALL)\n\ + {\n \n if (-e \"$BIN/t_coffee\"){`$CP $BIN/t\ +_coffee $INSTALL_DIR`};\n `cp $BIN/* $PLUGINS_DIR`\ +;\n $copied=1;\n }\n else\n {\n $copi\ +ed=&root_run (\"You must be root to finalize the i\ +nstallation\", \"$CP $BIN/* $INSTALL_DIR $SILENT\"\ +);\n }\n \n \n if ( !$copied)\n {\\ +n $report=\"*!!!!!! Installation unsuccesful.\ + The executables have been left in $BASE/bin\\n\";\ +\n }\n elsif ( $copied && $ROOT)\n {\n \ + $report=\"*------ Installation succesful. Your ex\ +ecutables have been copied in $new_bin and are on \ +your PATH\\n\";\n }\n elsif ( $copied && !$ROO\ +T)\n {\n $report= \"*!!!!!! T-Coffee and a\ +ssociated packages have been copied in: $new_bin\\\ +n\";\n $report.=\"*!!!!!! This address is NOT\ + in your PATH sytem variable\\n\";\n $report.\ +=\"*!!!!!! You can do so by adding the following l\ +ine in your ~/.bashrc file:\\n\";\n $report.=\ +\"*!!!!!! export PATH=$new_bin:\\$PATH\\n\";\n \ +}\n return $report;\n}\n\nsub sign_license_ni\n \ +{\n my $F=new FileHandle;\n open ($F, \"lice\ +nse.txt\");\n while (<$F>)\n {\n print \"$\ +_\";\n }\n close ($F);\n \n return;\\ +n }\n\nsub install_pg\n {\n my ($pg)=(@_);\n \ + my ($report, $previous, $language, $compiler, $\ +return);\n \n if (!$PG{$pg}{install}){return\ + 1;}\n \n $previous=&pg_is_installed ($pg);\\ +n \n if ($PG{$pg}{update_action} eq \"no_upd\ +ate\" && $previous)\n {\n $PG{$pg}{old}=1;\n \ +$PG{$pg}{new}=0;\n $return=1;\n }\n else\n\ + {\n $PG{$pg}{old}=$previous;\n \n if ($PG{$p\ +g} {language2} eq \"Perl\"){&install_perl_package \ +($pg);}\n elsif ($BINARIES_ONLY && &install_binary\ +_package ($pg)){$PG{$pg}{from_binary}=1;}\n elsif \ +(&install_source_package ($pg)){;}\n else \n {\n\ + \n if (!&supported_os($OS))\n {\n \ +print \"!!!!!!!! $pg compilation failed, binary un\ +supported for $OS\\n\"; \n }\n elsif (!(\ +$PG{$pg}{from_binary}=&install_binary_package ($pg\ +)))\n {\n print \"!!!!!!!! $pg compilation \ +and binary installation failed\\n\";\n }\n \ + }\n $PG{$pg}{new}=$return=&pg_is_installed ($pg,\ +$BIN);\n }\n\n \n return $return;\n }\\ +nsub install_perl_package\n {\n my ($pg)=(@_);\ +\n my ($report, $language, $compiler);\n \n \ + $language=$PG{$pg} {language2};\n $compiler=\ +$PG{$language}{compiler};\n \n if (!&pg_is_i\ +nstalled ($pg))\n {\n if ( $OS eq \"windows\"\ +){`perl -M$compiler -e 'install $pg'`;}\n elsif ( \ +$ROOT eq \"sudo\"){system (\"sudo perl -M$compiler\ + -e 'install $pg'\");}\n else {system (\"su root -\ +c perl -M$compiler -e 'install $pg'\");}\n }\\ +n return &pg_is_installed ($pg);\n }\n\n\n\nsu\ +b install_source_package\n {\n my ($pg)=(@_);\\ +n my ($report, $download, $arguments, $language\ +, $address, $name, $ext, $main_dir, $distrib);\n \ + my $wget_tmp=\"$TMP/wget.tmp\";\n my (@fl);\n\ + if ( -e \"$BIN/$pg\" || -e \"$BIN/$pg.exe\"){r\ +eturn 1;}\n \n #\n # check if the module \ +exists in the repository cache \n #\n if( repo_\ +load($pg) ) {\n return 1;\n }\n \n if ($pg \ +eq \"t_coffee\") {return &install_t_coffee ($pg\ +);}\n elsif ($pg eq \"TMalign\"){return &inst\ +all_TMalign ($pg);}\n \n chdir $DISTRIBUTION\ +S;\n \n $download=$PG{$pg}{source};\n \n \ + if (($download =~/tgz/))\n {\n ($address,$\ +name,$ext)=($download=~/(.+\\/)([^\\/]+)(\\.tgz).*\ +/);\n }\n elsif (($download=~/tar\\.gz/))\\ +n {\n ($address,$name,$ext)=($download=~/(.+\\ +\/)([^\\/]+)(\\.tar\\.gz).*/);\n }\n elsif\ + (($download=~/tar/))\n {\n ($address,$name,$\ +ext)=($download=~/(.+\\/)([^\\/]+)(\\.tar).*/);\n \ + }\n else\n {\n ($address,$name)=($dow\ +nload=~/(.+\\/)([^\\/]+)/);\n $ext=\"\";\n }\\ +n $distrib=\"$name$ext\";\n \n if ( !-d $\ +pg){mkdir $pg;}\n chdir $pg;\n \n #get the\ + distribution if available\n if ( -e \"$DOWNLOA\ +D_DIR/$distrib\")\n {\n `$CP $DOWNLOAD_DIR/$d\ +istrib .`;\n }\n #UNTAR and Prepare everyt\ +hing\n if (!-e \"$name.tar\" && !-e \"$name\")\\ +n {\n &check_rm ($wget_tmp);\n print \"\\n---\ +---- Downloading/Installing $pg\\n\";\n \n if (!-e\ + $distrib && &url2file (\"$download\", \"$wget_tmp\ +\")==$EXIT_SUCCESS)\n {\n \n `mv $wget_t\ +mp $distrib`;\n `$CP $distrib $DOWNLOAD_DIR/`;\ +\n }\n\n if (!-e $distrib)\n {\n print \"!\ +!!!!!! Download of $pg distribution failed\\n\";\n\ + print \"!!!!!!! Check Address: $PG{$pg}{sourc\ +e}\\n\";\n return 0;\n }\n print \"\\n------\ +- unzipping/untaring $name\\n\";\n if (($ext =~/z/\ +))\n { \n &flush_command (\"gunzip $name$ext\ +\");\n \n }\n if (($ext =~/tar/) || ($ext =~\ +/tgz/))\n {\n &flush_command(\"tar -xvf $nam\ +e.tar\");\n }\n }\n #Guess and enter the\ + distribution directory\n @fl=ls($p);\n fore\ +ach my $f (@fl)\n {\n if (-d $f)\n {\n \ +$main_dir=$f;\n }\n }\n if (-d $main_dir\ +)\n \n {\n chdir $main_dir;}\n else\n \ + {\n print \"Error: $main_dir does not exist\";\\ +n }\n print \"\\n------- Compiling/Install\ +ing $pg\\n\";\n `make clean $SILENT`;\n \n \ + \n #\n # SAP module\n #\n if ($pg eq\ + \"sap\")\n {\n if (-e \"./configure\")\n {\ +\n #new sap distribution\n if ($OS eq \"ma\ +cosx\")\n {\n &replace_line_in_file (\"./sr\ +c/galloc.h\", \"malloc.h\", \"\");\n &replace_li\ +ne_in_file (\"./src/pdbprot.h\", \"malloc.h\", \"\\ +");\n &replace_line_in_file (\"./src/pdbprot.c\",\ + \"malloc.h\", \"\");\n }\n \n &flus\ +h_command (\"./configure\");\n &flush_command \ +(\"make clean\");\n &flush_command (\"make\");\ +\n &check_cp (\"./src/$pg\", \"$BIN\");\n \ +repo_store(\"./src/$pg\");\n }\n else\n {\n \ + #old style distribution\n `rm *.o sap sap.e\ +xe ./util/aa/*.o ./util/wt/.o $SILENT`;\n &fl\ +ush_command (\"make $arguments sap\");\n &chec\ +k_cp ($pg, \"$BIN\");\n repo_store($pg);\n }\ +\n }\n \n #\n # CLUSTALW2 module\n \ + #\n elsif ($pg eq \"clustalw2\")\n {\n &\ +flush_command(\"./configure\");\n &flush_command(\\ +"make $arguments\");\n &check_cp (\"./src/$pg\", \\ +"$BIN\");\n repo_store(\"./src/$pg\");\n }\n \ + \n #\n # FSA module\n # \n elsif ($\ +pg eq \"fsa\")\n {\n &flush_command(\"./confi\ +gure --prefix=$BIN\");\n &flush_command(\"make $ar\ +guments\");\n &flush_command (\"make install\");\n\ +\n repo_store(\"fsa\", \"$BIN/bin\");\n `mv $BIN/b\ +in/* $BIN`;\n `rmdir $BIN/bin`;\n }\n \n \ + #\n # CLUSTALW module\n #\n elsif ($pg \ +eq \"clustalw\")\n {\n &flush_command(\"make \ +$arguments clustalw\");\n `$CP $pg $BIN $SILENT`;\\ +n repo_store($pg);\n }\n \n #\n # MA\ +FFT module\n #\n elsif ($pg eq \"mafft\")\n \ + {\n my $base=cwd();\n my $c;\n \n #compile co\ +re\n mkpath (\"./mafft/bin\");\n mkpath (\"./mafft\ +/lib\");\n chdir \"$base/core\";\n `make clean $SI\ +LENT`;\n &flush_command (\"make $arguments\");\n &\ +flush_command (\"make install LIBDIR=../mafft/lib \ +BINDIR=../mafft/bin\");\n \n #compile extension\n \ +chdir \"$base/extensions\";\n `make clean $SILENT`\ +;\n &flush_command (\"make $arguments\");\n &flush\ +_command (\"make install LIBDIR=../mafft/lib BINDI\ +R=../mafft/bin\");\n \n #put everything in mafft a\ +nd copy the compiled stuff in bin\n chdir \"$base\\ +";\n if ($ROOT_INSTALL)\n {\n &root_run (\"Y\ +ou Must be Root to Install MAFFT\\n\", \"mkdir /us\ +r/local/mafft/;$CP mafft/lib/* /usr/local/mafft;$C\ +P mafft/lib/mafft* /usr/local/bin ;$CP mafft/bin/m\ +afft /usr/local/bin/; \");\n }\n else\n {\n \ + `$CP mafft/lib/* $BIN`;\n `$CP mafft/bin/ma\ +fft $BIN`;\n }\n `tar -cvf mafft.tar mafft`;\n \ +`gzip mafft.tar`;\n `mv mafft.tar.gz $BIN`;\n \n r\ +epo_store(\"mafft/bin/mafft\", \"mafft/lib/\", \"$\ +BIN/mafft.tar.gz\");\n }\n \n #\n \ +# DIALIGN-TX module\n #\n elsif ( $pg eq \"d\ +ialign-tx\" )\n {\n my $f;\n my $base=cwd();\\ +n\n chdir \"./source\";\n if ($OS eq \"macosx\"){&\ +flush_command (\"cp makefile.MAC_OS makefile\");}\\ +n\n &flush_command (\" make CPPFLAGS='-O3 -funroll\ +-loops' all\");\n \n chdir \"..\";\n &check_cp (\"\ +./source/$pg\", \"$BIN\");\n repo_store(\"./source\ +/$pg\");\n }\n \n #\n # DIALIGN-T \ +module \n # (is the same as dialign-tx, but it \ +is mantained for backward name compatibility with \ +tcoffee)\n #\n elsif ( $pg eq \"dialign-t\" \ +)\n {\n my $f;\n my $base=cwd();\n\n chdir \"\ +./source\";\n if ($OS eq \"macosx\"){&flush_comman\ +d (\"cp makefile.MAC_OS makefile\");}\n\n &flush_c\ +ommand (\" make CPPFLAGS='-O3 -funroll-loops' all\\ +");\n \n chdir \"..\";\n &check_cp (\"./source/dia\ +lign-tx\", \"$BIN/dialign-t\");\n repo_store(\"$BI\ +N/dialign-t\"); \n } \n \n #\n \ + # POA module\n #\n elsif ($pg eq \"poa\")\\ +n {\n &flush_command (\"make $arguments poa\"\ +);\n &check_cp (\"$pg\", \"$BIN\");\n repo_store(\\ +"$pg\");\n }\n \n \n #\n # PROB\ +CONS module\n #\n elsif ( $pg eq \"probcons\\ +")\n {\n &add_C_libraries(\"./ProbabilisticMo\ +del.h\", \"list\", \"cstring\");\n \n `rm *.exe $S\ +ILENT`;\n &flush_command (\"make $arguments probco\ +ns\");\n &check_cp(\"$pg\", \"$BIN/$pg\");\n repo_\ +store(\"$pg\");\n }\n \n #\n # PRO\ +BCONS RNA module\n #\n elsif ( $pg eq \"prob\ +consRNA\")\n {\n &add_C_libraries(\"./Probabi\ +listicModel.h\", \"list\", \"cstring\");\n &add_C_\ +libraries(\"./Main.cc\", \"iomanip\", \"cstring\",\ +\"climits\");\n `rm *.exe $SILENT`;\n &flush_comma\ +nd (\"make $arguments probcons\");\n &check_cp(\"p\ +robcons\", \"$BIN/$pg\");\n repo_store(\"$BIN/$pg\\ +");\n }\n\n #\n # MUSCLE module\n #\n elsi\ +f ( $pg eq \"muscle\")\n { \n `rm *.o muscle\ + muscle.exe $SILENT`;\n if ($OS eq \"macosx\" || $\ +OS eq \"linux\")\n {\n &replace_line_in_file\ + (\"./Makefile\", \"LDLIBS = -lm -static\", \"LDL\ +IBS = -lm\");\n }\n elsif ($OS eq \"windows\")\n\ + {\n &replace_line_in_file (\"./intmath.cpp\\ +", \"double log2e\", \"double cedric_log\");\ +\n &replace_line_in_file (\"./intmath.cpp\", \ +\"double log2\", \"double log_notuse\");\n \ + &replace_line_in_file (\"./intmath.cpp\", \"do\ +uble cedric_log\", \"double log2e\");\n }\n &flu\ +sh_command (\"make $arguments all\");\n &check_cp(\ +\"$pg\", \"$BIN\");\n repo_store(\"$pg\"); \n \ + }\n \n #\n # MUS4 module\n #\n \ + elsif ( $pg eq \"mus4\")\n {\n `rm *.o mu\ +scle muscle.exe $SILENT`;\n &flush_command (\"./mk\ +\");\n &check_cp(\"$pg\", \"$BIN\");\n repo_store(\ +\"$pg\"); \n }\n \n #\n # PCMA mod\ +ule\n #\n elsif ( $pg eq \"pcma\")\n {\\ +n if ($OS eq \"macosx\")\n {\n &replace_line\ +_in_file (\"./alcomp2.c\", \"malloc.h\", \"\");\n\ + }\n &flush_command (\"make $arguments pcma\");\\ +n &check_cp(\"$pg\", \"$BIN\");\n repo_store(\"$pg\ +\"); \n }\n \n #\n # KALIGN module\ +\n #\n elsif ($pg eq \"kalign\")\n {\n \ +&flush_command (\"./configure\");\n &flush_command\ +(\"make $arguments\");\n &check_cp (\"$pg\",$BIN);\ +\n repo_store(\"$pg\"); \n }\n \n #\n\ + # AMAP module\n #\n elsif ( $pg eq \"ama\ +p\")\n {\n &add_C_libraries(\"./Amap.cc\", \"\ +iomanip\", \"cstring\",\"climits\"); \n `make clea\ +n $SILENT`;\n &flush_command (\"make $arguments al\ +l\");\n &check_cp (\"$pg\", $BIN);\n repo_store(\"\ +$pg\"); \n }\n \n #\n # PRODA modu\ +le\n #\n elsif ( $pg eq \"proda\")\n {\\ +n &add_C_libraries(\"AlignedFragment.h\", \"vector\ +\", \"iostream\", \"cstring\",\"cstdlib\");\n &add\ +_C_libraries(\"Main.cc\", \"vector\", \"climits\")\ +; \n &add_C_libraries(\"Sequence.cc\", \"stdlib.h\\ +", \"cstdio\"); \n &flush_command (\"make $argumen\ +ts all\");\n &check_cp (\"$pg\", $BIN);\n repo_sto\ +re(\"$pg\"); \n }\n \n #\n # PRANK\ + module\n #\n elsif ( $pg eq \"prank\")\n \ + {\n &flush_command (\"make $arguments all\");\n\ + &check_cp (\"$pg\", $BIN);\n repo_store(\"$pg\");\ + \n }\n \n #\n # !!!! MUSTANG modu\ +le\n #\n elsif ( $pg eq \"mustang\")\n \ + {\n &flush_command (\"rm ./bin/*\");\n &flush_com\ +mand (\"make $arguments all\");\n\n if ( $OS=~/win\ +dows/){&flush_command(\"cp ./bin/* $BIN/mustang.ex\ +e\");}\n else {&flush_command(\"cp ./bin/* $BIN/mu\ +stang\");}\n \n repo_store(\"$BIN/mustang\");\n \ + }\n\n #\n # RNAplfold module\n #\n elsif ( $\ +pg eq \"RNAplfold\")\n {\n &flush_command(\".\ +/configure\");\n &flush_command (\"make $arguments\ + all\");\n &check_cp(\"./Progs/RNAplfold\", \"$BIN\ +\");\n &check_cp(\"./Progs/RNAalifold\", \"$BIN\")\ +;\n &check_cp(\"./Progs/RNAfold\", \"$BIN\");\n \n\ + repo_store(\"./Progs/RNAplfold\", \"./Progs/RNAal\ +ifold\", \"./Progs/RNAfold\");\n }\n \n \ + #\n # !!! RETREE module\n #\n elsif ( \ +$pg eq \"retree\")\n {\n chdir \"src\";\n &fl\ +ush_command (\"make $arguments all\");\n &flush_co\ +mmand (\"make put\");\n system \"cp ../exe/* $BIN\\ +";\n \n repo_store(\"retree\", \"../exe\");\n \ + }\n \n chdir $CDIR;\n return &pg_is_install\ +ed ($pg, $BIN);\n }\n\nsub install_t_coffee\n {\\ +n my ($pg)=(@_);\n my ($report,$cflags, $arg\ +uments, $language, $compiler) ;\n #1-Install T-\ +Coffee\n chdir \"t_coffee_source\";\n &flush\ +_command (\"make clean\");\n print \"\\n-------\ + Compiling T-Coffee\\n\";\n $language=$PG{$pg} \ +{language2};\n $arguments=$PG{$language}{argume\ +nts};\n if (!($arguments =~/CFLAGS/)){$argument\ +s .= \" CFLAGS=-O2 \";}\n\n if ( $CC ne \"\"){&\ +flush_command (\"make -i $arguments t_coffee\");}\\ +n &check_cp ($pg, $BIN);\n \n chdir $CDIR\ +;\n return &pg_is_installed ($pg, $BIN);\n }\n\ +sub install_TMalign\n {\n my ($pg)=(@_);\n \ +my $report;\n chdir \"t_coffee_source\";\n p\ +rint \"\\n------- Compiling TMalign\\n\";\n `rm\ + TMalign TMalign.exe $SILENT`;\n if ( $FC ne \"\ +\"){&flush_command (\"make -i $PG{Fortran}{argumen\ +ts} TMalign\");}\n &check_cp ($pg, $BIN);\n \ +repo_store($pg);\n\n if ( !-e \"$BIN/$pg\" && p\ +g_has_binary_distrib ($pg))\n {\n print \"!!!\ +!!!! Compilation of $pg impossible. Will try to in\ +stall from binary\\n\";\n return &install_binary_p\ +ackage ($pg);\n }\n chdir $CDIR;\n retu\ +rn &pg_is_installed ($pg, $BIN);\n }\n\nsub pg_ha\ +s_binary_distrib\n {\n my ($pg)=(@_);\n if \ +($PG{$pg}{windows}){return 1;}\n elsif ($PG{$pg\ +}{osx}){return 1;}\n elsif ($PG{$pg}{linux}){re\ +turn 1;}\n return 0;\n }\nsub install_binary_p\ +ackage\n {\n my ($pg)=(@_);\n my ($base,$re\ +port,$name, $download, $arguments, $language, $dir\ +);\n my $isdir;\n &input_os();\n \n if\ + (!&supported_os($OS)){return 0;}\n if ( $PG{$p\ +g}{binary}){$name=$PG{$pg}{binary};}\n else \n \ + {\n $name=$pg;\n if ( $OS eq \"windows\"){$na\ +me.=\".exe\";}\n }\n \n $download=\"$WE\ +B_BASE/Packages/Binaries/$OS/$name\";\n \n $\ +base=cwd();\n chdir $TMP;\n \n if (!-e $n\ +ame)\n {\n `rm x $SILENT`;\n if ( url2file(\"\ +$download\",\"x\")==$EXIT_SUCCESS)\n {\n `mv\ + x $name`;\n }\n }\n \n if (!-e $name\ +)\n {\n print \"!!!!!!! $PG{$pg}{dname}: Down\ +load of $pg binary failed\\n\";\n print \"!!!!!!! \ +$PG{$pg}{dname}: Check Address: $download\\n\";\n \ +return 0;\n }\n print \"\\n------- Install\ +ing $pg\\n\";\n \n if ($name =~/tar\\.gz/)\n\ + {\n `gunzip $name`;\n `tar -xvf $pg.tar`;\n\ + chdir $pg;\n if ( $pg eq \"mafft\")\n {\n i\ +f ($ROOT_INSTALL)\n {\n &root_run (\"You Mu\ +st be Roor to Install MAFFT\\n\", \"$CP mafft/bin/\ +* /usr/local/mafft;mkdir /usr/local/mafft/; $CP ma\ +fft/lib/* /usr/local/bin/\");\n }\n else\ +\n {\n `$CP $TMP/$pg/bin/* $BIN $SILENT`;\n\ + `$CP $TMP/$pg/lib/* $BIN $SILENT`;\n }\n \ + }\n else\n {\n if (-e \"$TMP/$pg/data\"){`$\ +CP $TMP/$pg/data/* $TCM $SILENT`;}\n if (!($pg\ +=~/\\*/)){`rm -rf $pg`;}\n }\n }\n else\\ +n {\n &check_cp (\"$pg\", \"$BIN\");\n `chmod\ + u+x $BIN/$pg`; \n unlink ($pg);\n }\n chd\ +ir $base;\n $PG{$pg}{from_binary}=1;\n retur\ +n &pg_is_installed ($pg, $BIN);\n }\n\nsub add_di\ +r \n {\n my $dir=@_[0];\n \n if (!-e $di\ +r && !-d $dir)\n {\n my @l;\n umask (0000);\n\ + @l=mkpath ($dir,{mode => 0777});\n \n }\n \ + else\n {\n return 0;\n }\n }\nsub chec\ +k_rm \n {\n my ($file)=(@_);\n \n if ( -\ +e $file)\n {\n return unlink($file);\n }\ +\n return 0;\n }\nsub check_cp\n {\n my ($\ +from, $to)=(@_);\n if ( !-e $from && -e \"$from\ +\\.exe\"){$from=\"$from\\.exe\";}\n if ( !-e $f\ +rom){return 0;}\n \n `$CP $from $to`;\n \ + return 1;\n }\n\nsub repo_store \n{\n # chec\ +k that all required data are available\n if( $RE\ +PO_ROOT eq \"\" ) { return; }\n\n\n # extract t\ +he package name from the specified path\n my $p\ +g =`basename $_[0]`;\n chomp($pg);\n \n my $\ +VER = $PG{$pg}{version};\n my $CACHE = \"$REPO_\ +ROOT/$pg/$VER/$OSNAME-$OSARCH\"; \n \n print\ + \"-------- Storing package: \\\"$pg\\\" to path: \ +$CACHE\\n\";\n \n # clean the cache path if \ +exists and create it again\n `rm -rf $CACHE`;\n\ + `mkdir -p $CACHE`;\n \n for my $path (@_) \ +{\n\n # check if it is a single file \n if( \ +-f $path ) {\n `cp $path $CACHE`;\n }\n # .\ +. or a directory, in this case copy all the conten\ +t \n elsif( -d $path ) {\n opendir(IMD, $path);\ +\n my @thefiles= readdir(IMD);\n closedir(IMD)\ +;\n \n for my $_file (@thefiles) {\n if( $_\ +file ne \".\" && $_file ne \"..\") {\n `cp \ +$path/$_file $CACHE`;\n }\n }\n } \n } \n\ + \n \n} \n\nsub repo_load \n{\n my ($pg)=(\ +@_);\n\n # check that all required data are ava\ +ilable\n if( $REPO_ROOT eq \"\" ) { return 0; }\ +\n\n my $VER = $PG{$pg}{version};\n my $CACH\ +E = \"$REPO_ROOT/$pg/$VER/$OSNAME-$OSARCH\"; \n \ + if( !-e \"$CACHE/$pg\" ) {\n print \"-------\ +- Module \\\"$pg\\\" NOT found on repository cache\ +.\\n\";\n return 0;\n }\n \n print \"\ +-------- Module \\\"$pg\\\" found on repository ca\ +che. Using copy on path: $CACHE\\n\";\n `cp $CA\ +CHE/* $BIN`;\n return 1;\n}\n\nsub check_file_l\ +ist_exists \n {\n my ($base, @flist)=(@_);\n \ + my $f;\n\n foreach $f (@flist)\n {\n if \ +( !-e \"$base/$f\"){return 0;}\n }\n retur\ +n 1;\n }\nsub ls\n {\n my $f=@_[0];\n my @\ +fl;\n chomp(@fl=`ls -1 $f`);\n return @fl;\n\ + }\nsub flush_command\n {\n my $command=@_[0]\ +;\n my $F=new FileHandle;\n open ($F, \"$com\ +mand|\");\n while (<$F>){print \" --- $_\";}\ +\n close ($F);\n } \n\nsub input_installati\ +on_directory\n {\n my $dir=@_[0];\n my $new\ +;\n \n print \"------- The current installat\ +ion directory is: [$dir]\\n\";\n print \"??????\ +? Return to keep the default or new value:\";\n \ +\n if ($NO_QUESTION==0)\n {\n chomp ($new=\ +);\n while ( $new ne \"\" && !input_yes (\"\ +You have entered $new. Is this correct? ([y]/n):\"\ +))\n {\n print \"???????New installation dir\ +ectory:\";\n chomp ($new=);\n }\n $di\ +r=($new eq \"\")?$dir:$new;\n $dir=~s/\\/$//;\n \ + }\n \n if ( -d $dir){return $dir;}\n e\ +lsif (&root_run (\"You must be root to create $dir\ +\",\"mkdir $dir\")==$EXIT_SUCCESS){return $dir;}\n\ + else\n {\n print \"!!!!!!! $dir could not\ + be created\\n\";\n if ( $NO_QUESTION)\n {\n \ + return \"\";\n }\n elsif ( &input_yes (\"??????\ +? Do you want to provide a new directory([y]/n)?:\\ +"))\n {\n return input_installation_director\ +y ($dir);\n }\n else\n {\n return \"\";\n \ + }\n }\n \n }\nsub input_yes\n {\n m\ +y $question =@_[0];\n my $answer;\n\n if ($N\ +O_QUESTION==1){return 1;}\n \n if ($question\ + eq \"\"){$question=\"??????? Do you wish to proce\ +ed ([y]/n)?:\";}\n print $question;\n chomp(\ +$answer=lc());\n if (($answer=~/^y/) || \ +$answer eq \"\"){return 1;}\n elsif ( ($answer=\ +~/^n/)){return 0;}\n else\n {\n return inp\ +ut_yes($question);\n }\n }\nsub root_run\n \ +{\n my ($txt, $cmd)=(@_);\n \n if ( syste\ +m ($cmd)==$EXIT_SUCCESS){return $EXIT_SUCCESS;}\n \ + else \n {\n print \"------- $txt\\n\";\n i\ +f ( $ROOT eq \"sudo\"){return system (\"sudo $cmd\\ +");}\n else {return system (\"su root -c \\\"$cmd\\ +\\"\");}\n }\n }\nsub get_root\n {\n if \ +(&pg_is_installed (\"sudo\")){return \"sudo\";}\n \ + else {return \"su\";}\n }\n\nsub get_os\n {\n\ + my $raw_os=`uname`;\n my $os;\n\n $raw_o\ +s=lc ($raw_os);\n \n if ($raw_os =~/cygwin/)\ +{$os=\"windows\";}\n elsif ($raw_os =~/linux/){\ +$os=\"linux\";}\n elsif ($raw_os =~/osx/){$os=\\ +"macosx\";}\n elsif ($raw_os =~/darwin/){$os=\"\ +macosx\";}\n else\n {\n $os=$raw_os;\n \ + }\n return $os;\n }\nsub input_os\n {\n \ +my $answer;\n if ($OS) {return $OS;}\n \n \ + print \"??????? which os do you use: [w]indows, [\ +l]inux, [m]acosx:?\";\n $answer=lc();\n\\ +n if (($answer=~/^m/)){$OS=\"macosx\";}\n el\ +sif ( ($answer=~/^w/)){$OS=\"windows\";}\n elsi\ +f ( ($answer=~/^linux/)){$OS=\"linux\";}\n \n \ + else\n {\n return &input_os();\n }\n \ + return $OS;\n }\n\nsub supported_os\n {\n m\ +y ($os)=(@_[0]);\n return $SUPPORTED_OS{$os};\n\ + }\n \n \n\n\nsub update_tclinkdb \n {\n \ + my $file =@_[0];\n my $name;\n my $F=new F\ +ileHandle;\n my ($download, $address, $name, $l\ +, $db);\n \n if ( $file eq \"update\"){$file\ +=$TCLINKDB_ADDRESS;}\n \n if ( $file =~/http\ +:\\/\\// || $file =~/ftp:\\/\\//)\n {\n ($add\ +ress, $name)=($download=~/(.*)\\/([^\\/]+)$/);\n `\ +rm x $SILENT`;\n if (&url2file ($file,\"x\")==$EXI\ +T_SUCCESS)\n {\n print \"------- Susscessful\ + upload of $name\";\n `mv x $name`;\n $fil\ +e=$name;\n }\n }\n open ($F, \"$file\");\ +\n while (<$F>)\n {\n my $l=$_;\n if (($l \ +=~/^\\/\\//) || ($db=~/^#/)){;}\n elsif ( !($l =~/\ +\\w/)){;}\n else\n {\n my @v=split (/\\s+/, \ +$l);\n if ( $l=~/^MODE/)\n {\n $MODE{$v\ +[1]}{$v[2]}=$v[3];\n }\n elsif ($l=~/^PG\ +/)\n {\n $PG{$v[1]}{$v[2]}=$v[3];\n }\ +\n }\n }\n close ($F);\n &post_proces\ +s_PG();\n return;\n }\n\n\n\nsub initialize_PG\ +\n {\n\n$PG{\"t_coffee\"}{\"4_TCOFFEE\"}=\"TCOFFE\ +E\";\n$PG{\"t_coffee\"}{\"type\"}=\"sequence_multi\ +ple_aligner\";\n$PG{\"t_coffee\"}{\"ADDRESS\"}=\"h\ +ttp://www.tcoffee.org\";\n$PG{\"t_coffee\"}{\"lang\ +uage\"}=\"C\";\n$PG{\"t_coffee\"}{\"language2\"}=\\ +"C\";\n$PG{\"t_coffee\"}{\"source\"}=\"http://www.\ +tcoffee.org/Packages/T-COFFEE_distribution.tar.gz\\ +";\n$PG{\"t_coffee\"}{\"update_action\"}=\"always\\ +";\n$PG{\"t_coffee\"}{\"mode\"}=\"tcoffee,mcoffee,\ +rcoffee,expresso,3dcoffee\";\n$PG{\"clustalw2\"}{\\ +"4_TCOFFEE\"}=\"CLUSTALW2\";\n$PG{\"clustalw2\"}{\\ +"type\"}=\"sequence_multiple_aligner\";\n$PG{\"clu\ +stalw2\"}{\"ADDRESS\"}=\"http://www.clustal.org\";\ +\n$PG{\"clustalw2\"}{\"language\"}=\"C++\";\n$PG{\\ +"clustalw2\"}{\"language2\"}=\"CXX\";\n$PG{\"clust\ +alw2\"}{\"source\"}=\"http://www.clustal.org/downl\ +oad/2.0.10/clustalw-2.0.10-src.tar.gz\";\n$PG{\"cl\ +ustalw2\"}{\"mode\"}=\"mcoffee,rcoffee\";\n$PG{\"c\ +lustalw2\"}{\"version\"}=\"2.0.10\";\n$PG{\"clusta\ +lw\"}{\"4_TCOFFEE\"}=\"CLUSTALW\";\n$PG{\"clustalw\ +\"}{\"type\"}=\"sequence_multiple_aligner\";\n$PG{\ +\"clustalw\"}{\"ADDRESS\"}=\"http://www.clustal.or\ +g\";\n$PG{\"clustalw\"}{\"language\"}=\"C\";\n$PG{\ +\"clustalw\"}{\"language2\"}=\"C\";\n$PG{\"clustal\ +w\"}{\"source\"}=\"http://www.clustal.org/download\ +/1.X/ftp-igbmc.u-strasbg.fr/pub/ClustalW/clustalw1\ +.82.UNIX.tar.gz\";\n$PG{\"clustalw\"}{\"mode\"}=\"\ +mcoffee,rcoffee\";\n$PG{\"clustalw\"}{\"version\"}\ +=\"1.82\";\n$PG{\"dialign-t\"}{\"4_TCOFFEE\"}=\"DI\ +ALIGNT\";\n$PG{\"dialign-t\"}{\"type\"}=\"sequence\ +_multiple_aligner\";\n$PG{\"dialign-t\"}{\"ADDRESS\ +\"}=\"http://dialign-tx.gobics.de/\";\n$PG{\"diali\ +gn-t\"}{\"DIR\"}=\"/usr/share/dialign-tx/\";\n$PG{\ +\"dialign-t\"}{\"language\"}=\"C\";\n$PG{\"dialign\ +-t\"}{\"language2\"}=\"C\";\n$PG{\"dialign-t\"}{\"\ +source\"}=\"http://dialign-tx.gobics.de/DIALIGN-TX\ +_1.0.2.tar.gz\";\n$PG{\"dialign-t\"}{\"mode\"}=\"m\ +coffee\";\n$PG{\"dialign-t\"}{\"binary\"}=\"dialig\ +n-t\";\n$PG{\"dialign-t\"}{\"version\"}=\"1.0.2\";\ +\n$PG{\"dialign-tx\"}{\"4_TCOFFEE\"}=\"DIALIGNTX\"\ +;\n$PG{\"dialign-tx\"}{\"type\"}=\"sequence_multip\ +le_aligner\";\n$PG{\"dialign-tx\"}{\"ADDRESS\"}=\"\ +http://dialign-tx.gobics.de/\";\n$PG{\"dialign-tx\\ +"}{\"DIR\"}=\"/usr/share/dialign-tx/\";\n$PG{\"dia\ +lign-tx\"}{\"language\"}=\"C\";\n$PG{\"dialign-tx\\ +"}{\"language2\"}=\"C\";\n$PG{\"dialign-tx\"}{\"so\ +urce\"}=\"http://dialign-tx.gobics.de/DIALIGN-TX_1\ +.0.2.tar.gz\";\n$PG{\"dialign-tx\"}{\"mode\"}=\"mc\ +offee\";\n$PG{\"dialign-tx\"}{\"binary\"}=\"dialig\ +n-tx\";\n$PG{\"dialign-tx\"}{\"version\"}=\"1.0.2\\ +";\n$PG{\"poa\"}{\"4_TCOFFEE\"}=\"POA\";\n$PG{\"po\ +a\"}{\"type\"}=\"sequence_multiple_aligner\";\n$PG\ +{\"poa\"}{\"ADDRESS\"}=\"http://www.bioinformatics\ +.ucla.edu/poa/\";\n$PG{\"poa\"}{\"language\"}=\"C\\ +";\n$PG{\"poa\"}{\"language2\"}=\"C\";\n$PG{\"poa\\ +"}{\"source\"}=\"http://downloads.sourceforge.net/\ +poamsa/poaV2.tar.gz\";\n$PG{\"poa\"}{\"DIR\"}=\"/u\ +sr/share/\";\n$PG{\"poa\"}{\"FILE1\"}=\"blosum80.m\ +at\";\n$PG{\"poa\"}{\"mode\"}=\"mcoffee\";\n$PG{\"\ +poa\"}{\"binary\"}=\"poa\";\n$PG{\"poa\"}{\"versio\ +n\"}=\"2.0\";\n$PG{\"probcons\"}{\"4_TCOFFEE\"}=\"\ +PROBCONS\";\n$PG{\"probcons\"}{\"type\"}=\"sequenc\ +e_multiple_aligner\";\n$PG{\"probcons\"}{\"ADDRESS\ +\"}=\"http://probcons.stanford.edu/\";\n$PG{\"prob\ +cons\"}{\"language2\"}=\"CXX\";\n$PG{\"probcons\"}\ +{\"language\"}=\"C++\";\n$PG{\"probcons\"}{\"sourc\ +e\"}=\"http://probcons.stanford.edu/probcons_v1_12\ +.tar.gz\";\n$PG{\"probcons\"}{\"mode\"}=\"mcoffee\\ +";\n$PG{\"probcons\"}{\"binary\"}=\"probcons\";\n$\ +PG{\"probcons\"}{\"version\"}=\"1.12\";\n$PG{\"maf\ +ft\"}{\"4_TCOFFEE\"}=\"MAFFT\";\n$PG{\"mafft\"}{\"\ +type\"}=\"sequence_multiple_aligner\";\n$PG{\"maff\ +t\"}{\"ADDRESS\"}=\"http://align.bmr.kyushu-u.ac.j\ +p/mafft/online/server/\";\n$PG{\"mafft\"}{\"langua\ +ge\"}=\"C\";\n$PG{\"mafft\"}{\"language\"}=\"C\";\\ +n$PG{\"mafft\"}{\"source\"}=\"http://align.bmr.kyu\ +shu-u.ac.jp/mafft/software/mafft-6.603-with-extens\ +ions-src.tgz\";\n$PG{\"mafft\"}{\"windows\"}=\"htt\ +p://align.bmr.kyushu-u.ac.jp/mafft/software/mafft-\ +6.603-mingw.tar\";\n$PG{\"mafft\"}{\"mode\"}=\"mco\ +ffee,rcoffee\";\n$PG{\"mafft\"}{\"binary\"}=\"maff\ +t.tar.gz\";\n$PG{\"mafft\"}{\"version\"}=\"6.603\"\ +;\n$PG{\"muscle\"}{\"4_TCOFFEE\"}=\"MUSCLE\";\n$PG\ +{\"muscle\"}{\"type\"}=\"sequence_multiple_aligner\ +\";\n$PG{\"muscle\"}{\"ADDRESS\"}=\"http://www.dri\ +ve5.com/muscle/\";\n$PG{\"muscle\"}{\"language\"}=\ +\"C++\";\n$PG{\"muscle\"}{\"language2\"}=\"GPP\";\\ +n$PG{\"muscle\"}{\"source\"}=\"http://www.drive5.c\ +om/muscle/downloads3.7/muscle3.7_src.tar.gz\";\n$P\ +G{\"muscle\"}{\"windows\"}=\"http://www.drive5.com\ +/muscle/downloads3.7/muscle3.7_win32.zip\";\n$PG{\\ +"muscle\"}{\"linux\"}=\"http://www.drive5.com/musc\ +le/downloads3.7/muscle3.7_linux_ia32.tar.gz\";\n$P\ +G{\"muscle\"}{\"mode\"}=\"mcoffee,rcoffee\";\n$PG{\ +\"muscle\"}{\"version\"}=\"3.7\";\n$PG{\"mus4\"}{\\ +"4_TCOFFEE\"}=\"MUS4\";\n$PG{\"mus4\"}{\"type\"}=\\ +"sequence_multiple_aligner\";\n$PG{\"mus4\"}{\"ADD\ +RESS\"}=\"http://www.drive5.com/muscle/\";\n$PG{\"\ +mus4\"}{\"language\"}=\"C++\";\n$PG{\"mus4\"}{\"la\ +nguage2\"}=\"GPP\";\n$PG{\"mus4\"}{\"source\"}=\"h\ +ttp://www.drive5.com/muscle/muscle4.0_src.tar.gz\"\ +;\n$PG{\"mus4\"}{\"mode\"}=\"mcoffee,rcoffee\";\n$\ +PG{\"mus4\"}{\"version\"}=\"4.0\";\n$PG{\"pcma\"}{\ +\"4_TCOFFEE\"}=\"PCMA\";\n$PG{\"pcma\"}{\"type\"}=\ +\"sequence_multiple_aligner\";\n$PG{\"pcma\"}{\"AD\ +DRESS\"}=\"ftp://iole.swmed.edu/pub/PCMA/\";\n$PG{\ +\"pcma\"}{\"language\"}=\"C\";\n$PG{\"pcma\"}{\"la\ +nguage2\"}=\"C\";\n$PG{\"pcma\"}{\"source\"}=\"ftp\ +://iole.swmed.edu/pub/PCMA/pcma.tar.gz\";\n$PG{\"p\ +cma\"}{\"mode\"}=\"mcoffee\";\n$PG{\"pcma\"}{\"ver\ +sion\"}=\"1.0\";\n$PG{\"kalign\"}{\"4_TCOFFEE\"}=\\ +"KALIGN\";\n$PG{\"kalign\"}{\"type\"}=\"sequence_m\ +ultiple_aligner\";\n$PG{\"kalign\"}{\"ADDRESS\"}=\\ +"http://msa.cgb.ki.se\";\n$PG{\"kalign\"}{\"langua\ +ge\"}=\"C\";\n$PG{\"kalign\"}{\"language2\"}=\"C\"\ +;\n$PG{\"kalign\"}{\"source\"}=\"http://msa.cgb.ki\ +.se/downloads/kalign/current.tar.gz\";\n$PG{\"kali\ +gn\"}{\"mode\"}=\"mcoffee\";\n$PG{\"kalign\"}{\"ve\ +rsion\"}=\"1.0\";\n$PG{\"amap\"}{\"4_TCOFFEE\"}=\"\ +AMAP\";\n$PG{\"amap\"}{\"type\"}=\"sequence_multip\ +le_aligner\";\n$PG{\"amap\"}{\"ADDRESS\"}=\"http:/\ +/bio.math.berkeley.edu/amap/\";\n$PG{\"amap\"}{\"l\ +anguage\"}=\"C++\";\n$PG{\"amap\"}{\"language2\"}=\ +\"CXX\";\n$PG{\"amap\"}{\"source\"}=\"http://amap-\ +align.googlecode.com/files/amap.2.0.tar.gz\";\n$PG\ +{\"amap\"}{\"mode\"}=\"mcoffee\";\n$PG{\"amap\"}{\\ +"version\"}=\"2.0\";\n$PG{\"proda\"}{\"4_TCOFFEE\"\ +}=\"PRODA\";\n$PG{\"proda\"}{\"type\"}=\"sequence_\ +multiple_aligner\";\n$PG{\"proda\"}{\"ADDRESS\"}=\\ +"http://proda.stanford.edu\";\n$PG{\"proda\"}{\"la\ +nguage\"}=\"C++\";\n$PG{\"proda\"}{\"language2\"}=\ +\"CXX\";\n$PG{\"proda\"}{\"source\"}=\"http://prod\ +a.stanford.edu/proda_1_0.tar.gz\";\n$PG{\"proda\"}\ +{\"mode\"}=\"mcoffee\";\n$PG{\"proda\"}{\"version\\ +"}=\"1.0\";\n$PG{\"fsa\"}{\"4_TCOFFEE\"}=\"FSA\";\\ +n$PG{\"fsa\"}{\"type\"}=\"sequence_multiple_aligne\ +r\";\n$PG{\"fsa\"}{\"ADDRESS\"}=\"http://fsa.sourc\ +eforge.net/\";\n$PG{\"fsa\"}{\"language\"}=\"C++\"\ +;\n$PG{\"fsa\"}{\"language2\"}=\"CXX\";\n$PG{\"fsa\ +\"}{\"source\"}=\"http://sourceforge.net/projects/\ +fsa/files/fsa-1.15.3.tar.gz/download/\";\n$PG{\"fs\ +a\"}{\"mode\"}=\"mcoffee\";\n$PG{\"fsa\"}{\"versio\ +n\"}=\"1.15.3\";\n$PG{\"prank\"}{\"4_TCOFFEE\"}=\"\ +PRANK\";\n$PG{\"prank\"}{\"type\"}=\"sequence_mult\ +iple_aligner\";\n$PG{\"prank\"}{\"ADDRESS\"}=\"htt\ +p://www.ebi.ac.uk/goldman-srv/prank/\";\n$PG{\"pra\ +nk\"}{\"language\"}=\"C++\";\n$PG{\"prank\"}{\"lan\ +guage2\"}=\"CXX\";\n$PG{\"prank\"}{\"source\"}=\"h\ +ttp://www.ebi.ac.uk/goldman-srv/prank/src/prank/pr\ +ank.src.100303.tgz\";\n$PG{\"prank\"}{\"mode\"}=\"\ +mcoffee\";\n$PG{\"prank\"}{\"version\"}=\"100303\"\ +;\n$PG{\"sap\"}{\"4_TCOFFEE\"}=\"SAP\";\n$PG{\"sap\ +\"}{\"type\"}=\"structure_pairwise_aligner\";\n$PG\ +{\"sap\"}{\"ADDRESS\"}=\"http://mathbio.nimr.mrc.a\ +c.uk/wiki/Software\";\n$PG{\"sap\"}{\"language\"}=\ +\"C\";\n$PG{\"sap\"}{\"language2\"}=\"C\";\n$PG{\"\ +sap\"}{\"source\"}=\"http://mathbio.nimr.mrc.ac.uk\ +/download/sap-1.1.1.tar.gz\";\n$PG{\"sap\"}{\"mode\ +\"}=\"expresso,3dcoffee\";\n$PG{\"sap\"}{\"version\ +\"}=\"1.1.1\";\n$PG{\"TMalign\"}{\"4_TCOFFEE\"}=\"\ +TMALIGN\";\n$PG{\"TMalign\"}{\"type\"}=\"structure\ +_pairwise_aligner\";\n$PG{\"TMalign\"}{\"ADDRESS\"\ +}=\"http://zhang.bioinformatics.ku.edu/TM-align/TM\ +align.f\";\n$PG{\"TMalign\"}{\"language\"}=\"Fortr\ +an\";\n$PG{\"TMalign\"}{\"language2\"}=\"Fortran\"\ +;\n$PG{\"TMalign\"}{\"source\"}=\"http://zhang.bio\ +informatics.ku.edu/TM-align/TMalign.f\";\n$PG{\"TM\ +align\"}{\"linux\"}=\"http://zhang.bioinformatics.\ +ku.edu/TM-align/TMalign_32.gz\";\n$PG{\"TMalign\"}\ +{\"mode\"}=\"expresso,3dcoffee\";\n$PG{\"TMalign\"\ +}{\"version\"}=\"1.0\";\n$PG{\"mustang\"}{\"4_TCOF\ +FEE\"}=\"MUSTANG\";\n$PG{\"mustang\"}{\"type\"}=\"\ +structure_pairwise_aligner\";\n$PG{\"mustang\"}{\"\ +ADDRESS\"}=\"http://www.cs.mu.oz.au/~arun/mustang\\ +";\n$PG{\"mustang\"}{\"language\"}=\"C++\";\n$PG{\\ +"mustang\"}{\"language2\"}=\"CXX\";\n$PG{\"mustang\ +\"}{\"source\"}=\"http://ww2.cs.mu.oz.au/~arun/mus\ +tang/mustang_v3.2.1.tgz\";\n$PG{\"mustang\"}{\"mod\ +e\"}=\"expresso,3dcoffee\";\n$PG{\"mustang\"}{\"ve\ +rsion\"}=\"3.2.1\";\n$PG{\"lsqman\"}{\"4_TCOFFEE\"\ +}=\"LSQMAN\";\n$PG{\"lsqman\"}{\"type\"}=\"structu\ +re_pairwise_aligner\";\n$PG{\"lsqman\"}{\"ADDRESS\\ +"}=\"empty\";\n$PG{\"lsqman\"}{\"language\"}=\"emp\ +ty\";\n$PG{\"lsqman\"}{\"language2\"}=\"empty\";\n\ +$PG{\"lsqman\"}{\"source\"}=\"empty\";\n$PG{\"lsqm\ +an\"}{\"update_action\"}=\"never\";\n$PG{\"lsqman\\ +"}{\"mode\"}=\"expresso,3dcoffee\";\n$PG{\"align_p\ +db\"}{\"4_TCOFFEE\"}=\"ALIGN_PDB\";\n$PG{\"align_p\ +db\"}{\"type\"}=\"structure_pairwise_aligner\";\n$\ +PG{\"align_pdb\"}{\"ADDRESS\"}=\"empty\";\n$PG{\"a\ +lign_pdb\"}{\"language\"}=\"empty\";\n$PG{\"align_\ +pdb\"}{\"language2\"}=\"empty\";\n$PG{\"align_pdb\\ +"}{\"source\"}=\"empty\";\n$PG{\"align_pdb\"}{\"up\ +date_action\"}=\"never\";\n$PG{\"align_pdb\"}{\"mo\ +de\"}=\"expresso,3dcoffee\";\n$PG{\"fugueali\"}{\"\ +4_TCOFFEE\"}=\"FUGUE\";\n$PG{\"fugueali\"}{\"type\\ +"}=\"structure_pairwise_aligner\";\n$PG{\"fugueali\ +\"}{\"ADDRESS\"}=\"http://www-cryst.bioc.cam.ac.uk\ +/fugue/download.html\";\n$PG{\"fugueali\"}{\"langu\ +age\"}=\"empty\";\n$PG{\"fugueali\"}{\"language2\"\ +}=\"empty\";\n$PG{\"fugueali\"}{\"source\"}=\"empt\ +y\";\n$PG{\"fugueali\"}{\"update_action\"}=\"never\ +\";\n$PG{\"fugueali\"}{\"mode\"}=\"expresso,3dcoff\ +ee\";\n$PG{\"dalilite.pl\"}{\"4_TCOFFEE\"}=\"DALIL\ +ITEc\";\n$PG{\"dalilite.pl\"}{\"type\"}=\"structur\ +e_pairwise_aligner\";\n$PG{\"dalilite.pl\"}{\"ADDR\ +ESS\"}=\"built_in\";\n$PG{\"dalilite.pl\"}{\"ADDRE\ +SS2\"}=\"http://www.ebi.ac.uk/Tools/webservices/se\ +rvices/dalilite\";\n$PG{\"dalilite.pl\"}{\"languag\ +e\"}=\"Perl\";\n$PG{\"dalilite.pl\"}{\"language2\"\ +}=\"Perl\";\n$PG{\"dalilite.pl\"}{\"source\"}=\"em\ +pty\";\n$PG{\"dalilite.pl\"}{\"update_action\"}=\"\ +never\";\n$PG{\"dalilite.pl\"}{\"mode\"}=\"express\ +o,3dcoffee\";\n$PG{\"probconsRNA\"}{\"4_TCOFFEE\"}\ +=\"PROBCONSRNA\";\n$PG{\"probconsRNA\"}{\"type\"}=\ +\"RNA_multiple_aligner\";\n$PG{\"probconsRNA\"}{\"\ +ADDRESS\"}=\"http://probcons.stanford.edu/\";\n$PG\ +{\"probconsRNA\"}{\"language\"}=\"C++\";\n$PG{\"pr\ +obconsRNA\"}{\"language2\"}=\"CXX\";\n$PG{\"probco\ +nsRNA\"}{\"source\"}=\"http://probcons.stanford.ed\ +u/probconsRNA.tar.gz\";\n$PG{\"probconsRNA\"}{\"mo\ +de\"}=\"mcoffee,rcoffee\";\n$PG{\"probconsRNA\"}{\\ +"version\"}=\"1.0\";\n$PG{\"sfold\"}{\"4_TCOFFEE\"\ +}=\"CONSAN\";\n$PG{\"sfold\"}{\"type\"}=\"RNA_pair\ +wise_aligner\";\n$PG{\"sfold\"}{\"ADDRESS\"}=\"htt\ +p://selab.janelia.org/software/consan/\";\n$PG{\"s\ +fold\"}{\"language\"}=\"empty\";\n$PG{\"sfold\"}{\\ +"language2\"}=\"empty\";\n$PG{\"sfold\"}{\"source\\ +"}=\"empty\";\n$PG{\"sfold\"}{\"update_action\"}=\\ +"never\";\n$PG{\"sfold\"}{\"mode\"}=\"rcoffee\";\n\ +$PG{\"RNAplfold\"}{\"4_TCOFFEE\"}=\"RNAPLFOLD\";\n\ +$PG{\"RNAplfold\"}{\"type\"}=\"RNA_secondarystruct\ +ure_predictor\";\n$PG{\"RNAplfold\"}{\"ADDRESS\"}=\ +\"http://www.tbi.univie.ac.at/~ivo/RNA/\";\n$PG{\"\ +RNAplfold\"}{\"language\"}=\"C\";\n$PG{\"RNAplfold\ +\"}{\"language2\"}=\"C\";\n$PG{\"RNAplfold\"}{\"so\ +urce\"}=\"http://www.tbi.univie.ac.at/~ivo/RNA/Vie\ +nnaRNA-1.7.2.tar.gz\";\n$PG{\"RNAplfold\"}{\"mode\\ +"}=\"rcoffee,\";\n$PG{\"RNAplfold\"}{\"version\"}=\ +\"1.7.2\";\n$PG{\"retree\"}{\"4_TCOFFEE\"}=\"PHYLI\ +P\";\n$PG{\"retree\"}{\"type\"}=\"RNA_secondarystr\ +ucture_predictor\";\n$PG{\"retree\"}{\"ADDRESS\"}=\ +\"http://evolution.gs.washington.edu/phylip/\";\n$\ +PG{\"retree\"}{\"language\"}=\"C\";\n$PG{\"retree\\ +"}{\"language2\"}=\"C\";\n$PG{\"retree\"}{\"source\ +\"}=\"http://evolution.gs.washington.edu/phylip/do\ +wnload/phylip-3.69.tar.gz\";\n$PG{\"retree\"}{\"mo\ +de\"}=\"trmsd,\";\n$PG{\"retree\"}{\"version\"}=\"\ +3.69\";\n$PG{\"hmmtop\"}{\"4_TCOFFEE\"}=\"HMMTOP\"\ +;\n$PG{\"hmmtop\"}{\"type\"}=\"protein_secondaryst\ +ructure_predictor\";\n$PG{\"hmmtop\"}{\"ADDRESS\"}\ +=\"www.enzim.hu/hmmtop/\";\n$PG{\"hmmtop\"}{\"lang\ +uage\"}=\"C\";\n$PG{\"hmmtop\"}{\"language2\"}=\"C\ +\";\n$PG{\"hmmtop\"}{\"source\"}=\"empty\";\n$PG{\\ +"hmmtop\"}{\"update_action\"}=\"never\";\n$PG{\"hm\ +mtop\"}{\"mode\"}=\"tcoffee\";\n$PG{\"gorIV\"}{\"4\ +_TCOFFEE\"}=\"GOR4\";\n$PG{\"gorIV\"}{\"type\"}=\"\ +protein_secondarystructure_predictor\";\n$PG{\"gor\ +IV\"}{\"ADDRESS\"}=\"http://mig.jouy.inra.fr/logic\ +iels/gorIV/\";\n$PG{\"gorIV\"}{\"language\"}=\"C\"\ +;\n$PG{\"gorIV\"}{\"language2\"}=\"C\";\n$PG{\"gor\ +IV\"}{\"source\"}=\"http://mig.jouy.inra.fr/logici\ +els/gorIV/GOR_IV.tar.gz\";\n$PG{\"gorIV\"}{\"updat\ +e_action\"}=\"never\";\n$PG{\"gorIV\"}{\"mode\"}=\\ +"tcoffee\";\n$PG{\"wublast.pl\"}{\"4_TCOFFEE\"}=\"\ +EBIWUBLASTc\";\n$PG{\"wublast.pl\"}{\"type\"}=\"pr\ +otein_homology_predictor\";\n$PG{\"wublast.pl\"}{\\ +"ADDRESS\"}=\"built_in\";\n$PG{\"wublast.pl\"}{\"A\ +DDRESS2\"}=\"http://www.ebi.ac.uk/Tools/webservice\ +s/services/wublast\";\n$PG{\"wublast.pl\"}{\"langu\ +age\"}=\"Perl\";\n$PG{\"wublast.pl\"}{\"language2\\ +"}=\"Perl\";\n$PG{\"wublast.pl\"}{\"source\"}=\"em\ +pty\";\n$PG{\"wublast.pl\"}{\"update_action\"}=\"n\ +ever\";\n$PG{\"wublast.pl\"}{\"mode\"}=\"psicoffee\ +,expresso,accurate\";\n$PG{\"blastpgp.pl\"}{\"4_TC\ +OFFEE\"}=\"EBIBLASTPGPc\";\n$PG{\"blastpgp.pl\"}{\\ +"type\"}=\"protein_homology_predictor\";\n$PG{\"bl\ +astpgp.pl\"}{\"ADDRESS\"}=\"built_in\";\n$PG{\"bla\ +stpgp.pl\"}{\"ADDRESS2\"}=\"http://www.ebi.ac.uk/T\ +ools/webservices/services/blastpgp\";\n$PG{\"blast\ +pgp.pl\"}{\"language\"}=\"Perl\";\n$PG{\"blastpgp.\ +pl\"}{\"language2\"}=\"Perl\";\n$PG{\"blastpgp.pl\\ +"}{\"source\"}=\"empty\";\n$PG{\"blastpgp.pl\"}{\"\ +update_action\"}=\"never\";\n$PG{\"blastpgp.pl\"}{\ +\"mode\"}=\"psicoffee,expresso,accurate\";\n$PG{\"\ +blastcl3\"}{\"4_TCOFFEE\"}=\"NCBIWEBBLAST\";\n$PG{\ +\"blastcl3\"}{\"type\"}=\"protein_homology_predict\ +or\";\n$PG{\"blastcl3\"}{\"ADDRESS\"}=\"ftp://ftp.\ +ncbi.nih.gov/blast/executables/LATEST\";\n$PG{\"bl\ +astcl3\"}{\"language\"}=\"C\";\n$PG{\"blastcl3\"}{\ +\"language2\"}=\"C\";\n$PG{\"blastcl3\"}{\"source\\ +"}=\"empty\";\n$PG{\"blastcl3\"}{\"update_action\"\ +}=\"never\";\n$PG{\"blastcl3\"}{\"mode\"}=\"psicof\ +fee,expresso,3dcoffee\";\n$PG{\"blastpgp\"}{\"4_TC\ +OFFEE\"}=\"NCBIBLAST\";\n$PG{\"blastpgp\"}{\"type\\ +"}=\"protein_homology_predictor\";\n$PG{\"blastpgp\ +\"}{\"ADDRESS\"}=\"ftp://ftp.ncbi.nih.gov/blast/ex\ +ecutables/LATEST\";\n$PG{\"blastpgp\"}{\"language\\ +"}=\"C\";\n$PG{\"blastpgp\"}{\"language2\"}=\"C\";\ +\n$PG{\"blastpgp\"}{\"source\"}=\"empty\";\n$PG{\"\ +blastpgp\"}{\"update_action\"}=\"never\";\n$PG{\"b\ +lastpgp\"}{\"mode\"}=\"psicoffee,expresso,3dcoffee\ +\";\n$PG{\"SOAP::Lite\"}{\"4_TCOFFEE\"}=\"SOAPLITE\ +\";\n$PG{\"SOAP::Lite\"}{\"type\"}=\"library\";\n$\ +PG{\"SOAP::Lite\"}{\"ADDRESS\"}=\"http://cpansearc\ +h.perl.org/src/MKUTTER/SOAP-Lite-0.710.08/Makefile\ +.PL\";\n$PG{\"SOAP::Lite\"}{\"language\"}=\"Perl\"\ +;\n$PG{\"SOAP::Lite\"}{\"language2\"}=\"Perl\";\n$\ +PG{\"SOAP::Lite\"}{\"source\"}=\"empty\";\n$PG{\"b\ +lastpgp\"}{\"update_action\"}=\"never\";\n$PG{\"SO\ +AP::Lite\"}{\"mode\"}=\"none\";\n$PG{\"XML::Simple\ +\"}{\"4_TCOFFEE\"}=\"XMLSIMPLE\";\n$PG{\"XML::Simp\ +le\"}{\"type\"}=\"library\";\n$PG{\"XML::Simple\"}\ +{\"ADDRESS\"}=\"http://search.cpan.org/~grantm/XML\ +-Simple-2.18/lib/XML/Simple.pm\";\n$PG{\"XML::Simp\ +le\"}{\"language\"}=\"Perl\";\n$PG{\"XML::Simple\"\ +}{\"language2\"}=\"Perl\";\n$PG{\"XML::Simple\"}{\\ +"source\"}=\"empty\";\n$PG{\"XML::Simple\"}{\"mode\ +\"}=\"psicoffee,expresso,accurate\";\n$MODE{\"tcof\ +fee\"}{\"name\"}=\"tcoffee\";\n$MODE{\"rcoffee\"}{\ +\"name\"}=\"rcoffee\";\n$MODE{\"3dcoffee\"}{\"name\ +\"}=\"3dcoffee\";\n$MODE{\"mcoffee\"}{\"name\"}=\"\ +mcoffee\";\n$MODE{\"expresso\"}{\"name\"}=\"expres\ +so\";\n$MODE{\"trmsd\"}{\"name\"}=\"trmsd\";\n$MOD\ +E{\"accurate\"}{\"name\"}=\"accurate\";\n$MODE{\"s\ +eq_reformat\"}{\"name\"}=\"seq_reformat\";\n\n\n$P\ +G{C}{compiler}=\"gcc\";\n$PG{C}{compiler_flag}=\"C\ +C\";\n$PG{C}{options}=\"\";\n$PG{C}{options_flag}=\ +\"CFLAGS\";\n$PG{C}{type}=\"compiler\";\n\n$PG{\"C\ +XX\"}{compiler}=\"g++\";\n$PG{\"CXX\"}{compiler_fl\ +ag}=\"CXX\";\n$PG{\"CXX\"}{options}=\"\";\n$PG{\"C\ +XX\"}{options_flag}=\"CXXFLAGS\";\n$PG{CXX}{type}=\ +\"compiler\";\n\n$PG{\"CPP\"}{compiler}=\"g++\";\n\ +$PG{\"CPP\"}{compiler_flag}=\"CPP\";\n$PG{\"CPP\"}\ +{options}=\"\";\n$PG{\"CPP\"}{options_flag}=\"CPPF\ +LAGS\";\n$PG{CPP}{type}=\"compiler\";\n\n$PG{\"GPP\ +\"}{compiler}=\"g++\";\n$PG{\"GPP\"}{compiler_flag\ +}=\"GPP\";\n$PG{\"GPP\"}{options}=\"\";\n$PG{\"GPP\ +\"}{options_flag}=\"CFLAGS\";\n$PG{GPP}{type}=\"co\ +mpiler\";\n\n$PG{Fortran}{compiler}=\"g77\";\n$PG{\ +Fortran}{compiler_flag}=\"FCC\";\n$PG{Fortran}{typ\ +e}=\"compiler\";\n\n$PG{Perl}{compiler}=\"CPAN\";\\ +n$PG{Perl}{type}=\"compiler\";\n\n$SUPPORTED_OS{ma\ +cox}=\"Macintosh\";\n$SUPPORTED_OS{linux}=\"Linux\\ +";\n$SUPPORTED_OS{windows}=\"Cygwin\";\n\n\n\n$MOD\ +E{t_coffee}{description}=\" for regular multiple s\ +equence alignments\";\n$MODE{rcoffee} {description\ +}=\" for RNA multiple sequence alignments\";\n\n$M\ +ODE{psicoffee} {description}=\" for Homology Exten\ +ded multiple sequence alignments\";\n$MODE{express\ +o}{description}=\" for very accurate structure bas\ +ed multiple sequence alignments\";\n$MODE{\"3dcoff\ +ee\"}{description}=\" for multiple structure align\ +ments\";\n$MODE{mcoffee} {description}=\" for comb\ +ining alternative multiple sequence alignment pack\ +ages\\n------- into a unique meta-package. The ins\ +taller will upload several MSA packages and compil\ +e them\\n\n\";\n\n\n&post_process_PG();\nreturn;\n\ +}\n\nsub post_process_PG\n {\n my $p;\n \n \ + %PG=&name2dname (%PG);\n %MODE=&name2dname(%\ +MODE);\n foreach $p (keys(%PG)){if ( $PG{$p}{ty\ +pe} eq \"compiler\"){$PG{$p}{update_action}=\"neve\ +r\";}}\n \n }\n\nsub name2dname\n {\n my (\ +%L)=(@_);\n my ($l, $ml);\n \n foreach my\ + $pg (keys(%L))\n {\n $l=length ($pg);\n if (\ + $l>$ml){$ml=$l;}\n }\n $ml+=1;\n forea\ +ch my $pg (keys(%L))\n {\n my $name;\n $l=$ml\ +-length ($pg);\n $name=$pg;\n for ( $b=0; $b<$l; $\ +b++)\n {\n $name .=\" \";\n }\n $L{$pg}{dn\ +ame}=$name;\n }\n return %L;\n }\n\nsub e\ +nv_file2putenv\n {\n my $f=@_[0];\n my $F=n\ +ew FileHandle;\n my $n;\n \n open ($F, \"\ +$f\");\n while (<$F>)\n {\n my $line=$_;\n\ + my($var, $value)=($_=~/(\\S+)\\=(\\S*)/);\n $ENV{\ +$var}=$value;\n $ENV_SET{$var}=1;\n $n++;\n }\ +\n close ($F);\n return $n;\n }\n\nsub repl\ +ace_line_in_file\n {\n my ($file, $wordin, $wo\ +rdout)=@_;\n my $O=new FileHandle;\n my $I=n\ +ew FileHandle;\n my $l;\n if (!-e $file){ret\ +urn;}\n \n system (\"mv $file $file.old\");\\ +n open ($O, \">$file\");\n open ($I, \"$file\ +.old\");\n while (<$I>)\n {\n $l=$_;\n if \ +(!($l=~/$wordin/)){print $O \"$l\";}\n elsif ( $wo\ +rdout ne \"\"){$l=~s/$wordin/$wordout/g;print $O \\ +"$l\";}\n }\n close ($O);\n close ($I);\ +\n return;\n }\n\nsub add_C_libraries\n {\n \ + my ($file,$first,@list)=@_;\n \n my $O=new F\ +ileHandle;\n my $I=new FileHandle;\n my ($l,\ +$anchor);\n if (!-e $file){return;}\n \n $\ +anchor=\"#include <$first>\";\n \n system (\"m\ +v $file $file.old\");\n open ($O, \">$file\");\\ +n open ($I, \"$file.old\");\n while (<$I>)\n\ + {\n $l=$_;\n print $O \"$l\";\n if (!($l=~/$\ +anchor/))\n {\n \n foreach my $lib (@li\ +st)\n {\n print $O \"#incl\ +ude <$lib>\\n\";\n }\n }\n }\ +\n close ($O);\n close ($I);\n return;\n \ + }\n","use Env;\nuse Cwd;\n@suffix=(\"tmp\", \"t\ +emp\", \"cache\", \"t_coffee\", \"core\", \"tcoffe\ +e\");\n\nif ($#ARGV==-1)\n {\n print \"clean_c\ +ache.pl -file -dir=
    -si\ +ze=\\n0: unlimited -1 always.\\nWill \ +only clean directories matching:[\";\n foreach \ +$k(@suffix){print \"*$k* \";}\n print \"]\\n\";\ +\n exit (EXIT_FAILURE);\n }\n\n$cl=join (\" \"\ +,@ARGV);\nif (($cl=~/\\-no_action/))\n {\n exi\ +t (EXIT_SUCCESS);\n }\n\nif (($cl=~/\\-debug/))\n\ + {\n $DEBUG=1;\n }\nelse\n {\n $DEBUG=0;\\ +n }\n\nif (($cl=~/\\-dir=(\\S+)/))\n {\n $dir\ +=$1;\n }\nelse\n {\n $dir=\"./\";\n }\n\nif \ +($cl=~/\\-file=(\\S+)/)\n {\n $file=$1;\n }\n\ +else\n {\n $file=0;\n }\n\nif ($cl=~/\\-size=\ +(\\S+)/)\n {\n $max_size=$1;\n }\nelse\n {\n\ + $max_size=0;#unlimited\n }\nif ($cl=~/\\-forc\ +e/)\n {\n $force=1;\n }\nelse\n {\n $forc\ +e=0;\n }\n\nif ($cl=~/\\-age=(\\S+)/)\n {\n $\ +max_age=$1;\n }\nelse\n {\n $max_age=0;#unlim\ +ited\n }\n\n$max_size*=1000000;\nif ( ! -d $dir)\\ +n {\n print STDERR \"\\nCannot process $dir: d\ +oes not exist \\n\";\n exit (EXIT_FAILURE);\n \ +}\n\nif ( !($dir=~/^\\//))\n {\n $base=cwd();\\ +n $dir=\"$base/$dir\";\n }\n\n$proceed=0;\nfor\ +each $s (@suffix)\n {\n \n if (($dir=~/$s/)\ +){$proceed=1;}\n $s=uc ($s);\n if (($dir=~/$\ +s/)){$proceed=1;}\n }\nif ( $proceed==0)\n {\n \ + print STDERR \"Clean_cache.pl can only clean dir\ +ectories whose absolute path name contains the fol\ +lowing strings:\";\n foreach $w (@suffix) {prin\ +t STDERR \"$w \";$w=lc($w); print STDERR \"$w \";}\ +\n print STDERR \"\\nCannot process $dir\\n\";\\ +n exit (EXIT_FAILURE);\n }\n\n$name_file=\"$di\ +r/name_file.txt\";\n$size_file=\"$dir/size_file.tx\ +t\";\nif ( $force){&create_ref_file ($dir,$name_fi\ +le,$size_file);}\nif ($file){&add_file ($dir, $nam\ +e_file, $size_file, $file);}\n&clean_dir ($dir, $n\ +ame_file, $size_file, $max_size,$max_age);\nexit (\ +EXIT_SUCCESS);\n\nsub clean_dir \n {\n my ($di\ +r, $name_file, $size_file, $max_size, $max_age)=@_\ +;\n my ($tot_size, $size, $f, $s);\n\n \n $\ +tot_size=&get_tot_size ($dir, $name_file, $size_fi\ +le);\n\n if ( $tot_size<=$max_size){return ;}\n\ + else {$max_size/=2;}\n \n #recreate the \ +name file in case some temprary files have not bee\ +n properly registered\n &create_ref_file ($dir,\ + $name_file, $size_file, $max_age);\n \n $new_\ +name_file=&vtmpnam();\n open (R, \"$name_file\"\ +);\n open (W, \">$new_name_file\");\n while \ +()\n {\n my $line=$_;\n \n ($f, $s)=($line\ +=~/(\\S+) (\\S+)/);\n if ( !($f=~/\\S/)){next;}\n \ +\n elsif ($max_size && $tot_size>=$max_size && !($\ +f=~/name_file/))\n {\n remove ( \"$dir/$f\")\ +;\n $tot_size-=$s;\n }\n elsif ( $max_age &&\ + -M(\"$dir/$f\")>=$max_age)\n {\n remove ( \\ +"$dir/$f\");\n $tot_size-=$s;\n }\n else\n \ + {\n print W \"$f $s\\n\";\n }\n }\n \ + close (R);\n close (W);\n open (F, \">$size\ +_file\");\n print F \"$tot_size\";\n if ( -e\ + $new_name_file){`mv $new_name_file $name_file`;}\\ +n close (F);\n }\nsub get_tot_size\n {\n m\ +y ($dir, $name_file, $size_file)=@_;\n my $size\ +;\n \n if ( !-d $dir){return 0;}\n if ( !\ +-e $name_file)\n {\n \n &create_ref_file ($di\ +r, $name_file, $size_file);\n }\n open (F,\ + \"$size_file\");\n $size=;\n close (F);\\ +n chomp ($size);\n return $size;\n }\nsub s\ +ize \n {\n my $f=@_[0];\n\n if ( !-d $f){re\ +turn -s($f);}\n else {return &dir2size($f);}\n \ + }\nsub dir2size\n {\n my $d=@_[0];\n my ($\ +s, $f);\n \n if ( !-d $d) {return 0;}\n \\ +n foreach $f (&dir2list ($d))\n {\n if ( -\ +d $f){$s+=&dir2size (\"$d/$f\");}\n else {$s+= -s \ +\"$dir/$f\";}\n }\n return $s;\n }\n\nsub\ + remove \n {\n my $file=@_[0];\n my ($f);\n\ + \n debug_print( \"--- $file ---\\n\");\n \ + if (($file eq \".\") || ($file eq \"..\") || ($fi\ +le=~/\\*/)){return EXIT_FAILURE;}\n elsif ( !-d\ + $file)\n {\n debug_print (\"unlink $file\\n\\ +");\n if (-e $file){unlink ($file);}\n }\n \ + elsif ( -d $file)\n {\n debug_print (\"+++++\ ++++ $file +++++++\\n\");\n foreach $f (&dir2list($\ +file))\n {\n &remove (\"$file/$f\");\n }\n\ + debug_print (\"rmdir $file\\n\");\n rmdir $file;\\ +n }\n else\n {\n debug_print (\"?????\ +???? $file ????????\\n\");\n }\n return EX\ +IT_SUCCESS;\n }\n\nsub dir2list\n {\n my $dir\ +=@_[0];\n my (@list1, @list2,@list3, $l);\n\n \ + opendir (DIR,$dir);\n @list1=readdir (DIR);\n\ + closedir (DIR);\n \n foreach $l (@list1)\ +\n {\n if ( $l ne \".\" && $l ne \"..\"){@lis\ +t2=(@list2, $l);}\n }\n @list3 = sort { (-\ +M \"$dir/$list2[$b]\") <=> (-M \"$dir/$list2[$a]\"\ +)} @list2;\n return @list3;\n \n }\n\nsub d\ +ebug_print\n {\n \n if ($DEBUG==1){print @_\ +;}\n \n }\nsub create_ref_file\n {\n my ($\ +dir,$name_file,$size_file)=@_;\n my ($f, $s, $t\ +ot_size, @l);\n \n if ( !-d $dir){return;}\n\ + \n @l=&dir2list ($dir);\n open (F, \">$n\ +ame_file\");\n foreach $f (@l)\n {\n $s=&s\ +ize(\"$dir/$f\");\n $tot_size+=$s;\n print F \"$f \ +$s\\n\";\n }\n &myecho ($tot_size, \">$siz\ +e_file\");\n close (F);\n }\nsub add_file \n \ +{\n my ($dir,$name_file,$size_file,$file)=@_;\n\ + my ($s, $tot_size);\n \n if ( !-d $dir) \ + {return;}\n if ( !-e \"$dir/$file\" ) {return\ +;}\n if ( !-e $name_file){&create_ref_file ($di\ +r,$name_file,$size_file);}\n \n $s=&siz\ +e(\"$dir/$file\");\n open (F, \">>$name_file\")\ +;\n print F \"$file\\n\";\n close (F);\n\n \ + $tot_size=&get_tot_size ($dir,$name_file,$size_f\ +ile);\n $tot_size+=$s;\n &myecho ($tot_size,\ + \">$size_file\");\n \n }\n \nsub myecho\n {\\ +n my ($string, $file)=@_;\n open (ECHO, $fil\ +e) || die;\n print ECHO \"$string\";\n close\ + (ECHO);\n }\n \n \n \nsub vtmpnam\n {\n \ +my $tmp_file_name;\n $tmp_name_counter++;\n \ +$tmp_file_name=\"tmp_file_for_clean_cache_pdb$$.$t\ +mp_name_counter\";\n $tmp_file_list[$ntmp_file+\ ++]=$tmp_file_name;\n if ( -e $tmp_file_name) {r\ +eturn &vtmpnam ();}\n else {return $tmp_file_na\ +me;}\n }\n","\nmy $address=\"http://www.tcoffee.o\ +rg/Projects/Datasets/NatureMethodsDataset.tar.gz\"\ +;\nmy $out=\"NatureMethodsDataset.tar.gz\";\n&url2\ +file ($address,$out);\n\nif ( -e $out)\n {\n \\ +n system (\"gunzip NatureMethodsDataset.tar.gz\\ +");\n system (\"tar -xvf NatureMethodsDataset.t\ +ar\");\n \n print \"Your Data Set is in the \ +Folder NatureMethodsDataset\\n\";\n }\nelse \n {\ +\n print \"Could not Download Dataset --- Web s\ +ite may be down -- Try again later\\n\";\n }\n\n\\ +n\n\nsub url2file\n{\n my ($address, $out, $wge\ +t_arg, $curl_arg)=(@_);\n my ($pg, $flag, $r, $\ +arg, $count);\n \n if (!$CONFIGURATION){&che\ +ck_configuration (\"wget\", \"INTERNET\", \"gzip\"\ +);$CONFIGURATION=1;}\n \n if (&pg_is_install\ +ed (\"wget\")) {$pg=\"wget\"; $flag=\"-O\";$arg=\ +$wget_arg;}\n elsif (&pg_is_installed (\"curl\"\ +)){$pg=\"curl\"; $flag=\"-o\";$arg=$curl_arg;}\n \ + return system (\"$pg $address $flag $out>/dev/nu\ +ll 2>/dev/null\");\n\n}\n\nsub pg_is_installed\n \ +{\n my @ml=@_;\n my $r, $p, $m;\n my $sup\ +ported=0;\n \n my $p=shift (@ml);\n if ($\ +p=~/::/)\n {\n if (system (\"perl -M$p -e 1\"\ +)==$EXIT_SUCCESS){return 1;}\n else {return 0;}\n \ + }\n else\n {\n $r=`which $p 2>/dev/nu\ +ll`;\n if ($r eq \"\"){return 0;}\n else {return 1\ +;}\n }\n }\nsub check_configuration \n {\\ +n my @l=@_;\n my $v;\n foreach my $\ +p (@l)\n {\n \n if ( $p eq \"EMAIL\")\n \ +{ \n if ( !($EMAIL=~/@/))\n {\n exit (EX\ +IT_FAILURE);\n }\n }\n elsif( $p eq \"INTER\ +NET\")\n {\n if ( !&check_internet_conne\ +ction())\n {\n exit (EXIT_FAILURE);\n }\n \ + }\n elsif( $p eq \"wget\")\n {\n if (\ +!&pg_is_installed (\"wget\") && !&pg_is_installed \ +(\"curl\"))\n {\n exit (EXIT_FAILURE);\n }\n \ + }\n elsif( !(&pg_is_installed ($p)))\n {\ +\n exit (EXIT_FAILURE);\n }\n }\n r\ +eturn 1;\n }\nsub check_internet_connection\n \ +{\n my $internet;\n my $tmp;\n &check_con\ +figuration ( \"wget\"); \n \n $tmp=&vtmpnam \ +();\n \n if (&pg_is_installed (\"wget\ +\")){`wget www.google.com -O$tmp >/dev/null 2>/dev\ +/null`;}\n elsif (&pg_is_installed (\"curl\\ +")){`curl www.google.com -o$tmp >/dev/null 2>/dev/\ +null`;}\n \n if ( !-e $tmp || -s $tmp < 10){\ +$internet=0;}\n else {$internet=1;}\n if (-e\ + $tmp){unlink $tmp;}\n\n return $internet;\n }\ +\n\nsub vtmpnam\n {\n my $r=rand(100000);\n m\ +y $f=\"file.$r.$$\";\n while (-e $f)\n {\n $\ +f=vtmpnam();\n }\n push (@TMPFILE_LIST, $f);\n r\ +eturn $f;\n }\n\n","\n$t_coffee=\"t_coffee\";\ +\n\nforeach $value ( @ARGV)\n {\n $seq_file=$s\ +eq_file.\" \".$value;\n }\n\n$name=$ARGV[0];\n$na\ +me=~s/\\.[^\\.]*$//;\n$lib_name=\"$name.mocca_lib\\ +";\n$type=`t_coffee $seq_file -get_type -quiet`;\n\ +chop ($type);\n\nif ( $type eq \"PROTEIN\"){$lib_m\ +ode=\"lalign_rs_s_pair -lalign_n_top 20\";}\nelsif\ + ( $type eq\"DNA\"){$lib_mode=\"lalign_rs_s_dna_pa\ +ir -lalign_n_top 40\";}\n\nif ( !(-e $lib_name))\n\ + {\n \n $command=\"$t_coffee -mocca -seq_weigh\ +t=no -cosmetic_penalty=0 -mocca_interactive -in $l\ +ib_mode -out_lib $lib_name -infile $seq_file\";\n \ + \n }\nelsif ( (-e $lib_name))\n {\n $command=\\ +"$t_coffee -mocca -seq_weight=no -cosmetic_penalty\ +=0 -mocca_interactive -in $lib_name -infile $seq_f\ +ile\";\n \n }\n\nsystem ($command);\n\nexit;\n\n\ +","my $WSDL = 'http://www.ebi.ac.uk/Tools/webservi\ +ces/wsdl/WSDaliLite.wsdl';\n\nuse SOAP::Lite;\nuse\ + Data::Dumper;\nuse Getopt::Long qw(:config no_ign\ +ore_case bundling);\nuse File::Basename;\n\nmy $ch\ +eckInterval = 5;\n\nmy %params=(\n 'async' => \ +'1', # Use async mode and simulate sync mode in cl\ +ient\n );\nGetOptions(\n 'pdb1=s' => \\\ +$params{'sequence1'},\n 'chainid1=s' => \\$para\ +ms{'chainid1'},\n 'pdb2=s' => \\$params{'se\ +quence2'},\n 'chainid2=s' => \\$params{'chainid\ +2'},\n \"help|h\" => \\$help, # Usage info\n \ + \"async|a\" => \\$async, # Asynchronous submiss\ +ion\n \"polljob\" => \\$polljob, # Get results\ +\n \"status\" => \\$status, # Get status\n \ +\"jobid|j=s\" => \\$jobid, # JobId\n \"email|S\ +=s\" => \\$params{email}, # E-mail address\n \\ +"trace\" => \\$trace, # SOAP messages\n \"\ +sequence=s\" => \\$sequence, # Input PDB\n );\n\ +\nmy $scriptName = basename($0, ());\nif($help) {\\ +n &usage();\n exit(0);\n}\n\nif($trace) {\n \ + print \"Tracing active\\n\";\n SOAP::Lite->i\ +mport(+trace => 'debug');\n}\n\nmy $soap = SOAP::L\ +ite\n ->service($WSDL)\n ->on_fault(sub {\n \ + my $soap = shift;\n my $res = shift;\ +\n # Throw an exception for all faults\n \ + if(ref($res) eq '') {\n die($res);\ +\n } else {\n die($res->faultstr\ +ing);\n }\n return new SOAP::SOM;\n \ + }\n );\n\nif( !($polljob || $stat\ +us) &&\n !( defined($params{'sequence1'}) && de\ +fined($params{'sequence2'}) )\n ) {\n print \ +STDERR 'Error: bad option combination', \"\\n\";\n\ + &usage();\n exit(1);\n}\nelsif($polljob && \ +defined($jobid)) {\n print \"Getting results fo\ +r job $jobid\\n\";\n getResults($jobid);\n}\nel\ +sif($status && defined($jobid)) {\n print STDER\ +R \"Getting status for job $jobid\\n\";\n my $r\ +esult = $soap->checkStatus($jobid);\n print STD\ +OUT \"$result\", \"\\n\";\n if($result eq 'DONE\ +') {\n print STDERR \"To get results: $scriptName \ +--polljob --jobid $jobid\\n\";\n }\n}\nelse {\n\ + if(-f $params{'sequence1'}) {\n $params{'seque\ +nce1'} = read_file($params{'sequence1'});\n }\n\ + if(-f $params{'sequence2'}) {\n $params{'seque\ +nce2'} = read_file($params{'sequence2'});\n }\n\ +\n my $jobid;\n my $paramsData = SOAP::Data-\ +>name('params')->type(map=>\\%params);\n # For \ +SOAP::Lite 0.60 and earlier parameters are passed \ +directly\n if($SOAP::Lite::VERSION eq '0.60' ||\ + $SOAP::Lite::VERSION =~ /0\\.[1-5]/) {\n $\ +jobid = $soap->runDaliLite($paramsData);\n }\n \ + # For SOAP::Lite 0.69 and later parameter handl\ +ing is different, so pass\n # undef's for templ\ +ated params, and then pass the formatted args.\n \ + else {\n $jobid = $soap->runDaliLite(unde\ +f,\n $paramsData);\n }\n\n if (defin\ +ed($async)) {\n print STDOUT $jobid, \"\\n\";\n \ + print STDERR \"To check status: $scriptName -\ +-status --jobid $jobid\\n\";\n } else { # Synch\ +ronous mode\n print STDERR \"JobId: $jobid\\ +\n\";\n sleep 1;\n getResults($jobid\ +);\n }\n}\n\nsub clientPoll($) {\n my $jobid\ + = shift;\n my $result = 'PENDING';\n # Chec\ +k status and wait if not finished\n #print STDE\ +RR \"Checking status: $jobid\\n\";\n while($res\ +ult eq 'RUNNING' || $result eq 'PENDING') {\n \ + $result = $soap->checkStatus($jobid);\n \ +print STDERR \"$result\\n\";\n if($result e\ +q 'RUNNING' || $result eq 'PENDING') {\n \ + # Wait before polling again.\n sleep \ +$checkInterval;\n }\n }\n}\n\nsub getRes\ +ults($) {\n $jobid = shift;\n # Check status\ +, and wait if not finished\n clientPoll($jobid)\ +;\n # Use JobId if output file name is not defi\ +ned\n unless(defined($outfile)) {\n $out\ +file=$jobid;\n }\n # Get list of data types\\ +n my $resultTypes = $soap->getResults($jobid);\\ +n # Get the data and write it to a file\n if\ +(defined($outformat)) { # Specified data type\n \ + my $selResultType;\n foreach my $resul\ +tType (@$resultTypes) {\n if($resultTyp\ +e->{type} eq $outformat) {\n $selRe\ +sultType = $resultType;\n }\n }\\ +n $res=$soap->poll($jobid, $selResultType->\ +{type});\n write_file($outfile.'.'.$selResu\ +ltType->{ext}, $res);\n } else { # Data types a\ +vailable\n # Write a file for each output t\ +ype\n for my $resultType (@$resultTypes){\n\ + #print \"Getting $resultType->{type}\\\ +n\";\n $res=$soap->poll($jobid, $result\ +Type->{type});\n write_file($outfile.'.\ +'.$resultType->{ext}, $res);\n }\n }\n}\\ +n\nsub read_file($) {\n my $filename = shift;\n\ + open(FILE, $filename);\n my $content;\n \ +my $buffer;\n while(sysread(FILE, $buffer, 1024\ +)) {\n $content.= $buffer;\n }\n close(FILE)\ +;\n return $content;\n}\n\nsub write_file($$) {\ +\n my ($tmp,$entity) = @_;\n print STDERR \"\ +Creating result file: \".$tmp.\"\\n\";\n unless\ +(open (FILE, \">$tmp\")) {\n return 0;\n }\n \ + syswrite(FILE, $entity);\n close (FILE);\n \ +return 1;\n}\n\nsub usage {\n print STDERR < [opt\ +ions] pdbFile [--outfile string]\n Returns: saves\ + the results to disk\n\nAsynchronous job:\n\n Use\ + this if you want to retrieve the results at a lat\ +er time. The results \n are stored for up to 24 h\ +ours. \n The asynchronous submission mode is reco\ +mmended when users are submitting \n batch jobs o\ +r large database searches \n Usage: $scriptName -\ +-email --async [options] pdbFile\n \ + Returns: jobid\n\n Use the jobid to query for th\ +e status of the job. \n Usage: $scriptName --stat\ +us --jobid \n Returns: string indicating t\ +he status of the job:\n DONE - job has finished\ +\n RUNNING - job is running\n NOT_FOUND - jo\ +b cannot be found\n ERROR - the jobs has encoun\ +tered an error\n\n When done, use the jobid to re\ +trieve the status of the job. \n Usage: $scriptNa\ +me --polljob --jobid [--outfile string]\n\\ +n[Help]\n\n For more detailed help information re\ +fer to\n http://www.ebi.ac.uk/DaliLite/\nEOF\n;\n\ +}\n","my $WSDL = 'http://www.ebi.ac.uk/Tools/webse\ +rvices/wsdl/WSWUBlast.wsdl';\n\nuse strict;\nuse S\ +OAP::Lite;\nuse Getopt::Long qw(:config no_ignore_\ +case bundling);\nuse File::Basename;\n\nmy $checkI\ +nterval = 15;\n\nmy $numOpts = scalar(@ARGV);\nmy \ +($outfile, $outformat, $help, $async, $polljob, $s\ +tatus, $ids, $jobid, $trace, $sequence);\nmy %para\ +ms= ( # Defaults\n 'async' => 1, # Force int\ +o async mode\n 'exp' => 10.0, # E-value thre\ +shold\n 'numal' => 50, # Maximum number of a\ +lignments\n 'scores' => 100, # Maximum numbe\ +r of scores\n );\nGetOptions( # Map the\ + options into variables\n \"program|p=s\" =\ +> \\$params{program}, # BLAST program\n \"datab\ +ase|D=s\" => \\$params{database}, # Search data\ +base\n \"matrix|m=s\" => \\$params{matrix}\ +, # Scoring matrix\n \"exp|E=f\" => \\$\ +params{exp}, # E-value threshold\n \"echofilter\ +|e\" => \\$params{echofilter}, # Display filter\ +ed sequence\n \"filter|f=s\" => \\$params{\ +filter}, # Low complexity filter name\n \"align\ +ments|b=i\" => \\$params{numal}, # Number of alig\ +nments\n \"scores|s=i\" => \\$params{score\ +s}, # Number of scores\n \"sensitivity|S=s\" =>\ + \\$params{sensitivity}, # Search sensitivity\n \ + \"sort|t=s\" => \\$params{sort}, # Sort hit\ +s by...\n \"stats|T=s\" => \\$params{stat\ +s}, # Scoring statistic to use\n \"strand|d=s\"\ + => \\$params{strand}, # Strand to use in DNA\ + vs. DNA search\n \"topcombon|c=i\" => \\$par\ +ams{topcombon}, # Consistent sets of HSPs\n \"o\ +utfile=s\" => \\$outfile, # Output file\n \ + \"outformat|o=s\" => \\$outformat, # Output for\ +mat\n \"help|h\" => \\$help, # Usage info\ +\n \"async|a\" => \\$async, # Asynchronou\ +s mode\n \"polljob\" => \\$polljob, # Get\ + results\n \"status\" => \\$status, # Get\ + job status\n \"ids\" => \\$ids, # \ +Get ids from result\n \"jobid|j=s\" => \\\ +$jobid, # JobId\n \"email=s\" => \\$par\ +ams{email}, # E-mail address\n \"trace\" \ + => \\$trace, # SOAP trace\n \"sequence=s\" \ + => \\$sequence, # Query sequence\n );\n\nm\ +y $scriptName = basename($0, ());\nif($help || $nu\ +mOpts == 0) {\n &usage();\n exit(0);\n}\n\ni\ +f($trace){\n print STDERR \"Tracing active\\n\"\ +;\n SOAP::Lite->import(+trace => 'debug');\n}\n\ +\nmy $soap = SOAP::Lite\n ->service($WSDL)\n \ + ->proxy('http://localhost/',\n #proxy => ['htt\ +p' => 'http://your.proxy.server/'], # HTTP proxy\n\ + timeout => 600, # HTTP connection timeout\n \ + )\n ->on_fault(sub { # SOAP fault handler\n \ + my $soap = shift;\n my $res = shift;\n\ + # Throw an exception for all faults\n \ + if(ref($res) eq '') {\n die($res);\n\ + } else {\n die($res->faultstrin\ +g);\n }\n return new SOAP::SOM;\n \ + }\n );\n\nif( !($polljob || $status\ + || $ids) &&\n !( defined($ARGV[0]) || defined(\ +$sequence) )\n ) {\n print STDERR 'Error: ba\ +d option combination', \"\\n\";\n &usage();\n \ + exit(1);\n}\nelsif($polljob && defined($jobid)) \ +{\n print \"Getting results for job $jobid\\n\"\ +;\n getResults($jobid);\n}\nelsif($status && de\ +fined($jobid)) {\n print STDERR \"Getting statu\ +s for job $jobid\\n\";\n my $result = $soap->ch\ +eckStatus($jobid);\n print STDOUT \"$result\\n\\ +";\n if($result eq 'DONE') {\n print STDERR \"T\ +o get results: $scriptName --polljob --jobid $jobi\ +d\\n\";\n }\n} \nelsif($ids && defined($jobid)\ +) {\n print STDERR \"Getting ids from job $jobi\ +d\\n\";\n getIds($jobid);\n}\nelse {\n # Pre\ +pare input data\n my $content;\n my (@conten\ +ts) = ();\n if(-f $ARGV[0] || $ARGV[0] eq '-') \ +{ \n $content={type=>'sequence',content=>read_file\ +($ARGV[0])}; \n }\n if($sequence) { \n if(-f\ + $sequence || $sequence eq '-') { \n $content=\ +{type=>'sequence',content=>read_file($ARGV[0])}; \\ +n } else {\n $content={type=>'sequence',conten\ +t=>$sequence};\n }\n }\n push @contents, $co\ +ntent;\n\n # Submit the job\n my $paramsData\ + = SOAP::Data->name('params')->type(map=>\\%params\ +);\n my $contentData = SOAP::Data->name('conten\ +t')->value(\\@contents);\n # For SOAP::Lite 0.6\ +0 and earlier parameters are passed directly\n \ +if($SOAP::Lite::VERSION eq '0.60' || $SOAP::Lite::\ +VERSION =~ /0\\.[1-5]/) {\n $jobid = $soap-\ +>runWUBlast($paramsData, $contentData);\n }\n \ + # For SOAP::Lite 0.69 and later parameter handli\ +ng is different, so pass\n # undef's for templa\ +ted params, and then pass the formatted args.\n \ + else {\n $jobid = $soap->runWUBlast(undef,\ + undef,\n $paramsData, $contentData);\n }\ +\n\n # Asynchronous mode: output jobid and exit\ +.\n if (defined($async)) {\n print STDOUT $jobi\ +d, \"\\n\";\n print STDERR \"To check statu\ +s: $scriptName --status --jobid $jobid\\n\";\n \ +}\n # Synchronous mode: try to get results\n \ + else {\n print STDERR \"JobId: $jobid\\n\"\ +;\n sleep 1;\n getResults($jobid);\n\ + }\n}\n\nsub getIds($) {\n my $jobid = shift\ +;\n my $results = $soap->getIds($jobid);\n f\ +or my $result (@$results){\n print \"$result\\n\";\ +\n }\n}\n\nsub clientPoll($) {\n my $jobid =\ + shift;\n my $result = 'PENDING';\n # Check \ +status and wait if not finished\n while($result\ + eq 'RUNNING' || $result eq 'PENDING') {\n \ +$result = $soap->checkStatus($jobid);\n pri\ +nt STDERR \"$result\\n\";\n if($result eq '\ +RUNNING' || $result eq 'PENDING') {\n #\ + Wait before polling again.\n sleep $ch\ +eckInterval;\n }\n }\n}\n\nsub getResult\ +s($) {\n my $jobid = shift;\n my $res;\n \ +# Check status, and wait if not finished\n clie\ +ntPoll($jobid);\n # Use JobId if output file na\ +me is not defined\n unless(defined($outfile)) {\ +\n $outfile=$jobid;\n }\n # Get list \ +of data types\n my $resultTypes = $soap->getRes\ +ults($jobid);\n # Get the data and write it to \ +a file\n if(defined($outformat)) { # Specified \ +data type\n if($outformat eq 'xml') {$outformat = \ +'toolxml';}\n if($outformat eq 'txt') {$outformat \ += 'tooloutput';}\n my $selResultType;\n \ + foreach my $resultType (@$resultTypes) {\n \ + if($resultType->{type} eq $outformat) {\n \ + $selResultType = $resultType;\n \ + }\n }\n $res=$soap->poll($jo\ +bid, $selResultType->{type});\n if($outfile eq '-'\ +) {\n write_file($outfile, $res);\n } else {\\ +n write_file($outfile.'.'.$selResultType->{ext\ +}, $res);\n }\n } else { # Data types available\ +\n # Write a file for each output type\n \ + for my $resultType (@$resultTypes){\n \ + #print STDERR \"Getting $resultType->{type}\\n\ +\";\n $res=$soap->poll($jobid, $resultT\ +ype->{type});\n if($outfile eq '-') {\n write\ +_file($outfile, $res);\n } else {\n write_fil\ +e($outfile.'.'.$resultType->{ext}, $res);\n }\\ +n }\n }\n}\n\nsub read_file($) {\n my\ + $filename = shift;\n my ($content, $buffer);\n\ + if($filename eq '-') {\n while(sysread(STDIN, \ +$buffer, 1024)) {\n $content .= $buffer;\n }\n\ + }\n else { # File\n open(FILE, $filename) o\ +r die \"Error: unable to open input file\";\n whil\ +e(sysread(FILE, $buffer, 1024)) {\n $content .\ += $buffer;\n }\n close(FILE);\n }\n return $\ +content;\n}\n\nsub write_file($$) {\n my ($file\ +name, $data) = @_;\n print STDERR 'Creating res\ +ult file: ' . $filename . \"\\n\";\n if($filena\ +me eq '-') {\n print STDOUT $data;\n }\n els\ +e {\n open(FILE, \">$filename\") or die \"Error: u\ +nable to open output file\";\n syswrite(FILE, $dat\ +a);\n close(FILE);\n }\n}\n\nsub usage {\n p\ +rint STDERR < [options...] seqFile\n Returns: saves the re\ +sults to disk\n\nAsynchronous job:\n\n Use this i\ +f you want to retrieve the results at a later time\ +. The results \n are stored for up to 24 hours. \\ +n The asynchronous submission mode is recommended\ + when users are submitting \n batch jobs or large\ + database searches \n Usage: $scriptName --async \ +--email [options...] seqFile\n Ret\ +urns : jobid\n\n Use the jobid to query for the s\ +tatus of the job. \n Usage: $scriptName --status \ +--jobid \n Returns : string indicating the\ + status of the job:\n DONE - job has finished\n\ + RUNNING - job is running\n NOT_FOUND - job \ +cannot be found\n ERROR - the jobs has encounte\ +red an error\n\n When done, use the jobid to retr\ +ieve the status of the job. \n Usage: $scriptName\ + --polljob --jobid [--outfile string]\n R\ +eturns: saves the results to disk\n\n[Help]\n\nFor\ + more detailed help information refer to \nhttp://\ +www.ebi.ac.uk/blast2/WU-Blast2_Help_frame.html\n \\ +nEOF\n;\n}\n","\nmy $WSDL = 'http://www.ebi.ac.uk/\ +Tools/webservices/wsdl/WSBlastpgp.wsdl';\n\nuse SO\ +AP::Lite;\nuse Getopt::Long qw(:config no_ignore_c\ +ase bundling);\nuse File::Basename;\n\nmy $checkIn\ +terval = 15;\n\nmy %params=(\n 'async' => '1',\ + # Use async mode and simulate sync mode in client\ +\n );\nGetOptions(\n \"mode=s\" =\ +> \\$params{mode}, # Search mode: PSI-Blast or PHI\ +-Blast\n \"database|d=s\" => \\$params{data\ +base}, # Database to search\n \"matrix|M=s\" \ + => \\$params{matrix},# Scoring maxtrix\n \"\ +exp|e=f\" => \\$params{exp}, # E-value\n \ + \"expmulti|h=f\" => \\$params{expmulti}, # \ +E-value\n \"filter|F=s\" => \\$params{fil\ +ter}, # Low complexity filter\n \"dropoff|X=i\"\ + => \\$params{dropoff}, # Dropoff score\n \ +\"finaldropoff|Z=i\" => \\$params{finaldropoff}, #\ + Final dropoff score\n \"scores|v=i\" => \ +\\$params{scores}, # Max number of scores\n \"a\ +lign=i\" => \\$params{align}, # Alignment\ + view\n \"startregion|S=i\" => \\$params{start\ +region}, # Start of region in query\n \"endregi\ +on|H=i\" => \\$params{endregion}, # End of regi\ +on in query\n \"maxpasses|j=i\" => \\$params\ +{maxpasses}, # Number of PSI iterations\n \"ope\ +ngap|G=i\" => \\$params{opengap}, # Gap open \ +penalty\n \"extendgap|E=i\" => \\$params{ext\ +endgap}, # Gap extension penalty\n \"pattern=s\\ +" => \\$params{pattern}, # PHI-BLAST patter\ +n\n \"usagemode|p=s\" => \\$params{usagemode\ +}, # PHI-BLAST program\n \"appxml=s\" =\ +> \\$params{appxml}, # Application XML\n \"sequ\ +ence=s\" => \\$sequence, # Query sequence\n \ + \"help\" => \\$help, # Usage info\n \\ +"polljob\" => \\$polljob, # Get results\n \ + \"status\" => \\$status, # Get status\n \ + \"ids\" => \\$ids, # Get ids from r\ +esult\n \"jobid=s\" => \\$jobid, # Job\ +Id\n \"outfile=s\" => \\$outfile, # Outp\ +ut filename\n \"outformat|o=s\" => \\$outfor\ +mat, # Output file format\n \"async|a\" \ +=> \\$async, # Async submission\n \"email=s\" \ + => \\$params{email}, # User e-mail address\ +\n \"trace\" => \\$trace, # Show SOA\ +P messages\n );\n\nmy $scriptName = basename($0\ +, ());\nif($help) {\n &usage();\n exit(0);\n\ +}\n\nif ($trace){\n print \"Tracing active\\n\"\ +;\n SOAP::Lite->import(+trace => 'debug');\n}\n\ +\nmy $soap = SOAP::Lite\n ->service($WSDL)\n \ + ->on_fault(sub {\n my $soap = shift;\n \ + my $res = shift;\n # Throw an exception\ + for all faults\n if(ref($res) eq '') {\n \ + die($res);\n } else {\n \ + die($res->faultstring);\n }\n retu\ +rn new SOAP::SOM;\n }\n );\n\nif(\ + !($polljob || $status || $ids) &&\n !( (define\ +d($ARGV[0]) && -f $ARGV[0]) || defined($sequence) \ +)\n ) {\n print STDERR 'Error: bad option co\ +mbination', \"\\n\";\n &usage();\n exit(1);\\ +n}\nelsif($polljob && defined($jobid)) {\n prin\ +t \"Getting results for job $jobid\\n\";\n getR\ +esults($jobid);\n}\nelsif($status && defined($jobi\ +d)) {\n print STDERR \"Getting status for job $\ +jobid\\n\";\n my $result = $soap->checkStatus($\ +jobid);\n print STDOUT $result, \"\\n\";\n i\ +f($result eq 'DONE') {\n print STDERR \"To get res\ +ults: $scriptName --polljob --jobid $jobid\\n\";\n\ + }\n} \nelsif($ids && defined($jobid)) {\n \ +print STDERR \"Getting ids from job $jobid\\n\";\n\ + getIds($jobid);\n}\nelse {\n if(-f $ARGV[0]\ +) { \n $content={type=>'sequence', content=>read_f\ +ile($ARGV[0])}; \n }\n if($sequence) { \n if\ +(-f $sequence) {\n $content={type=>'sequence',\ + content=>read_file($sequence)}; \n } else {\n \ + $content={type=>'sequence', content=>$sequence};\\ +n }\n }\n push @content, $content;\n\n my\ + $jobid;\n my $paramsData = SOAP::Data->name('p\ +arams')->type(map=>\\%params);\n my $contentDat\ +a = SOAP::Data->name('content')->value(\\@content)\ +;\n # For SOAP::Lite 0.60 and earlier parameter\ +s are passed directly\n if($SOAP::Lite::VERSION\ + eq '0.60' || $SOAP::Lite::VERSION =~ /0\\.[1-5]/)\ + {\n $jobid = $soap->runBlastpgp($paramsDat\ +a, $contentData);\n }\n # For SOAP::Lite 0.6\ +9 and later parameter handling is different, so pa\ +ss\n # undef's for templated params, and then p\ +ass the formatted args.\n else {\n $jobi\ +d = $soap->runBlastpgp(undef, undef,\n $par\ +amsData, $contentData);\n }\n\n if (defined(\ +$async)) {\n print STDOUT $jobid, \"\\n\";\n \ + print STDERR \"To check status: $scriptName --st\ +atus --jobid $jobid\\n\";\n } else { # Synchron\ +ous mode\n print STDERR \"JobId: $jobid\\n\\ +";\n sleep 1;\n getResults($jobid);\\ +n }\n}\n\nsub getIds($) {\n $jobid = shift;\\ +n my $results = $soap->getIds($jobid);\n for\ + $result (@$results){\n print \"$result\\n\";\n \ + }\n}\n\nsub clientPoll($) {\n my $jobid = shif\ +t;\n my $result = 'PENDING';\n # Check statu\ +s and wait if not finished\n #print STDERR \"Ch\ +ecking status: $jobid\\n\";\n while($result eq \ +'RUNNING' || $result eq 'PENDING') {\n $res\ +ult = $soap->checkStatus($jobid);\n print S\ +TDERR \"$result\\n\";\n if($result eq 'RUNN\ +ING' || $result eq 'PENDING') {\n # Wai\ +t before polling again.\n sleep $checkI\ +nterval;\n }\n }\n}\n\nsub getResults($)\ + {\n $jobid = shift;\n # Check status, and w\ +ait if not finished\n clientPoll($jobid);\n \ +# Use JobId if output file name is not defined\n \ + unless(defined($outfile)) {\n $outfile=$j\ +obid;\n }\n # Get list of data types\n my\ + $resultTypes = $soap->getResults($jobid);\n # \ +Get the data and write it to a file\n if(define\ +d($outformat)) { # Specified data type\n my\ + $selResultType;\n foreach my $resultType (\ +@$resultTypes) {\n if($resultType->{typ\ +e} eq $outformat) {\n $selResultTyp\ +e = $resultType;\n }\n }\n \ + $res=$soap->poll($jobid, $selResultType->{type})\ +;\n write_file($outfile.'.'.$selResultType-\ +>{ext}, $res);\n } else { # Data types availabl\ +e\n # Write a file for each output type\n \ + for my $resultType (@$resultTypes){\n \ + #print \"Getting $resultType->{type}\\n\";\n \ + $res=$soap->poll($jobid, $resultType->{\ +type});\n write_file($outfile.'.'.$resu\ +ltType->{ext}, $res);\n }\n }\n}\n\nsub \ +read_file($) {\n my $filename = shift;\n ope\ +n(FILE, $filename);\n my $content;\n my $buf\ +fer;\n while(sysread(FILE, $buffer, 1024)) {\n \ +$content.= $buffer;\n }\n close(FILE); \n \ + return $content;\n}\n\nsub write_file($$) {\n \ + my ($tmp,$entity) = @_;\n print STDERR \"Creat\ +ing result file: \".$tmp.\"\\n\";\n unless(open\ + (FILE, \">$tmp\")) {\n return 0;\n }\n sysw\ +rite(FILE, $entity);\n close (FILE);\n retur\ +n 1;\n}\n\nsub usage {\n print STDERR < [options...] \ +seqfile\n Returns: saves the results to disk\n\nA\ +synchronous job:\n\n Use this if you want to retr\ +ieve the results at a later time. The results\n a\ +re stored for up to 24 hours.\n The asynchronous \ +submission mode is recommended when users are subm\ +itting\n batch jobs or large database searches\n \ + Usage: blastpgp.pl --email --async [\ +options...] seqFile\n Returns: jobid\n\n Use the\ + jobid to query for the status of the job.\n Usag\ +e: blastpgp.pl --status --jobid \n Returns\ +: string indicating the status of the job\n DON\ +E - job has finished\n RUNNING - job is running\ +\n NOT_FOUND - job cannot be found\n ERROR -\ + the jobs has encountered an error\n\n When done,\ + use the jobid to retrieve the results of the job.\ +\n Usage: blastpgp.pl --polljob --jobid [\ +--outfile ]\n Returns: saves the result\ +s to disk\nEOF\n;\n}\n","\n=head1 NAME\n\nncbiblas\ +t_lwp.pl\n\n=head1 DESCRIPTION\n\nNCBI BLAST REST \ +web service Perl client using L.\n\nTested wi\ +th:\n\n=over\n\n=item *\nL 5.79, L 2.12 and Perl 5.8.3\n\n=item *\nL 5.805, L\ + 2.14 and Perl 5.8.7\n\n=item *\nL 5.820, L 2.18 and Perl 5.10.0 (Ubu\ +ntu 9.04)\n\n=back\n\nFor further information see:\ +\n\n=over\n\n=item *\nL\n\n=ite\ +m *\nL\n\n=back\n\n=head1 VERSION\n\n$Id: ncb\ +iblast_lwp.pl 1317 2009-09-03 15:44:11Z hpm $\n\n=\ +cut\n\nuse strict;\nuse warnings;\n\nuse English;\\ +nuse LWP;\nuse XML::Simple;\nuse Getopt::Long qw(:\ +config no_ignore_case bundling);\nuse File::Basena\ +me;\nuse Data::Dumper;\n\nmy $baseUrl = 'http://ww\ +w.ebi.ac.uk/Tools/services/rest/ncbiblast';\n\nmy \ +$checkInterval = 3;\n\nmy $outputLevel = 1;\n\nmy \ +$numOpts = scalar(@ARGV);\nmy %params = ( 'debugLe\ +vel' => 0 );\n\nmy %tool_params = ();\nGetOptions(\ +\n\n # Tool specific options\n 'program|p=s' => \\ +\$tool_params{'program'}, # blastp, blastn, blas\ +tx, etc.\n 'database|D=s' => \\$params{'database'}\ +, # Database(s) to search\n 'matrix|m=s' =\ +> \\$tool_params{'matrix'}, # Scoring martix to\ + use\n 'exp|E=f' => \\$tool_params{'exp'}, \ + # E-value threshold\n 'filter|f=s' => \\$too\ +l_params{'filter'}, # Low complexity filter\n '\ +align|A=i' => \\$tool_params{'align'}, # Pa\ +irwise alignment format\n 'scores|s=i' => \\$too\ +l_params{'scores'}, # Number of scores\n 'align\ +ments|n=i' => \\$tool_params{'alignments'}, # Nu\ +mber of alignments\n 'dropoff|d=i' => \\$tool_p\ +arams{'dropoff'}, # Dropoff score\n 'match_sc\ +ores=s' => \\$tool_params{'match_scores'}, # Match\ +/missmatch scores\n 'match|u=i' => \\$params{\ +'match'}, # Match score\n 'mismatch|v=\ +i' => \\$params{'mismatch'}, # Mismatch\ + score\n 'gapopen|o=i' => \\$tool_params{'gapop\ +en'}, # Open gap penalty\n 'gapext|x=i' =\ +> \\$tool_params{'gapext'}, # Gap extension \ +penality\n 'gapalign|g' => \\$tool_params{'gap\ +align'}, # Optimise gap alignments\n 'stype=s'\ + => \\$tool_params{'stype'}, # Sequence type\n \ +'seqrange=s' => \\$tool_params{'seqrange'}, # Q\ +uery subsequence\n 'sequence=s' => \\$params{'sequ\ +ence'}, # Query sequence\n 'multifasta' =>\ + \\$params{'multifasta'}, # Multiple fasta i\ +nput\n\n # Compatability options, old command-line\ +\n 'numal|n=i' => \\$params{'numal'}, #\ + Number of alignments\n 'opengap|o=i' => \\$para\ +ms{'opengap'}, # Open gap penalty\n 'extendga\ +p|x=i' => \\$params{'extendgap'}, # Gap extensi\ +on penality\n \n # Generic options\n 'email=s' \ + => \\$params{'email'}, # User e-mail a\ +ddress\n 'title=s' => \\$params{'title'}, \ + # Job title\n 'outfile=s' => \\$params{\ +'outfile'}, # Output file name\n 'outformat\ +=s' => \\$params{'outformat'}, # Output fil\ +e type\n 'jobid=s' => \\$params{'jobid'}, \ + # JobId\n 'help|h' => \\$params{'hel\ +p'}, # Usage help\n 'async' => \\ +\$params{'async'}, # Asynchronous submiss\ +ion\n 'polljob' => \\$params{'polljob'}, \ + # Get results\n 'resultTypes' => \\$params{'\ +resultTypes'}, # Get result types\n 'status' \ + => \\$params{'status'}, # Get status\\ +n 'params' => \\$params{'params'}, \ +# List input parameters\n 'paramDetail=s' => \\$pa\ +rams{'paramDetail'}, # Get details for paramete\ +r\n 'quiet' => \\$params{'quiet'}, \ + # Decrease output level\n 'verbose' => \\$\ +params{'verbose'}, # Increase output level\\ +n 'debugLevel=i' => \\$params{'debugLevel'}, \ +# Debug output level\n 'baseUrl=s' => \\$baseU\ +rl, # Base URL for service.\n);\n\ +if ( $params{'verbose'} ) { $outputLevel++ }\nif (\ + $params{'$quiet'} ) { $outputLevel-- }\n\n&print\ +_debug_message( 'MAIN', 'LWP::VERSION: ' . $LWP::V\ +ERSION,\n 1 );\n\n&print_debug_message( 'MAIN', \"\ +params:\\n\" . Dumper( \\%params ), 11 )\ +;\n&print_debug_message( 'MAIN', \"tool_params:\\n\ +\" . Dumper( \\%tool_params ), 11 );\n\nmy $script\ +Name = basename( $0, () );\n\nif ( $params{'help'}\ + || $numOpts == 0 ) {\n &usage();\n exit(0);\n}\n\\ +n&print_debug_message( 'MAIN', 'baseUrl: ' . $base\ +Url, 1 );\n\nif (\n !(\n $params{'polljob'}\n \ + || $params{'resultTypes'}\n || $params{'status'}\ +\n || $params{'params'}\n || $params{'paramDetai\ +l'}\n )\n && !( defined( $ARGV[0] ) || defined( $p\ +arams{'sequence'} ) )\n )\n{\n\n # Bad argument c\ +ombination, so print error message and usage\n pri\ +nt STDERR 'Error: bad option combination', \"\\n\"\ +;\n &usage();\n exit(1);\n}\n\nelsif ( $params{'pa\ +rams'} ) {\n &print_tool_params();\n}\n\nelsif ( $\ +params{'paramDetail'} ) {\n &print_param_details( \ +$params{'paramDetail'} );\n}\n\nelsif ( $params{'s\ +tatus'} && defined( $params{'jobid'} ) ) {\n &prin\ +t_job_status( $params{'jobid'} );\n}\n\nelsif ( $p\ +arams{'resultTypes'} && defined( $params{'jobid'} \ +) ) {\n &print_result_types( $params{'jobid'} );\n\ +}\n\nelsif ( $params{'polljob'} && defined( $param\ +s{'jobid'} ) ) {\n &get_results( $params{'jobid'} \ +);\n}\n\nelse {\n\n # Multiple input sequence mode\ +, assume fasta format.\n if ( $params{'multifasta'\ +} ) {\n &multi_submit_job();\n }\n\n # Entry iden\ +tifier list file.\n elsif (( defined( $params{'seq\ +uence'} ) && $params{'sequence'} =~ m/^\\@/ )\n |\ +| ( defined( $ARGV[0] ) && $ARGV[0] =~ m/^\\@/ ) )\ +\n {\n my $list_filename = $params{'sequence'} ||\ + $ARGV[0];\n $list_filename =~ s/^\\@//;\n &list\ +_file_submit_job($list_filename);\n }\n\n # Defaul\ +t: single sequence/identifier.\n else {\n\n # Loa\ +d the sequence data and submit.\n &submit_job( &l\ +oad_data() );\n }\n}\n\n=head1 FUNCTIONS\n\n=cut\n\ +\n\n=head2 rest_request()\n\nPerform a REST reques\ +t.\n\n my $response_str = &rest_request($url);\n\\ +n=cut\n\nsub rest_request {\n print_debug_message(\ + 'rest_request', 'Begin', 11 );\n my $requestUrl =\ + shift;\n print_debug_message( 'rest_request', 'UR\ +L: ' . $requestUrl, 11 );\n\n # Create a user agen\ +t\n my $ua = LWP::UserAgent->new();\n '$Revision: \ +1317 $' =~ m/(\\d+)/;\n $ua->agent(\"EBI-Sample-Cl\ +ient/$1 ($scriptName; $OSNAME) \" . $ua->agent());\ +\n $ua->env_proxy;\n\n # Perform the request\n my \ +$response = $ua->get($requestUrl);\n print_debug_m\ +essage( 'rest_request', 'HTTP status: ' . $respons\ +e->code,\n 11 );\n\n # Check for HTTP error codes\ +\n if ( $response->is_error ) {\n $response->cont\ +ent() =~ m/

    ([^<]+)<\\/h1>/;\n die 'http statu\ +s: ' . $response->code . ' ' . $response->message \ +. ' ' . $1;\n }\n print_debug_message( 'rest_requ\ +est', 'End', 11 );\n\n # Return the response data\\ +n return $response->content();\n}\n\n=head2 rest_g\ +et_parameters()\n\nGet list of tool parameter name\ +s.\n\n my (@param_list) = &rest_get_parameters();\ +\n\n=cut\n\nsub rest_get_parameters {\n print_debu\ +g_message( 'rest_get_parameters', 'Begin', 1 );\n \ +my $url = $baseUrl . '/parameters/'\ +;\n my $param_list_xml_str = rest_request($url);\n\ + my $param_list_xml = XMLin($param_list_xml_st\ +r);\n my (@param_list) = @{ $param_list_xml-\ +>{'id'} };\n print_debug_message( 'rest_get_parame\ +ters', 'End', 1 );\n return (@param_list);\n}\n\n=\ +head2 rest_get_parameter_details()\n\nGet details \ +of a tool parameter.\n\n my $paramDetail = &rest_\ +get_parameter_details($param_name);\n\n=cut\n\nsub\ + rest_get_parameter_details {\n print_debug_messag\ +e( 'rest_get_parameter_details', 'Begin', 1 );\n m\ +y $parameterId = shift;\n print_debug_message( 're\ +st_get_parameter_details',\n 'parameterId: ' . $p\ +arameterId, 1 );\n my $url = $bas\ +eUrl . '/parameterdetails/' . $parameterId;\n my $\ +param_detail_xml_str = rest_request($url);\n my $p\ +aram_detail_xml = XMLin($param_detail_xml_str)\ +;\n print_debug_message( 'rest_get_parameter_detai\ +ls', 'End', 1 );\n return ($param_detail_xml);\n}\\ +n\n=head2 rest_run()\n\nSubmit a job.\n\n my $job\ +_id = &rest_run($email, $title, \\%params );\n\n=c\ +ut\n\nsub rest_run {\n print_debug_message( 'rest_\ +run', 'Begin', 1 );\n my $email = shift;\n my $ti\ +tle = shift;\n my $params = shift;\n print_debug_\ +message( 'rest_run', 'email: ' . $email, 1 );\n if\ + ( defined($title) ) {\n print_debug_message( 're\ +st_run', 'title: ' . $title, 1 );\n }\n print_debu\ +g_message( 'rest_run', 'params: ' . Dumper($params\ +), 1 );\n\n # User agent to perform http requests\\ +n my $ua = LWP::UserAgent->new();\n $ua->env_proxy\ +;\n\n # Clean up parameters\n my (%tmp_params) = %\ +{$params};\n $tmp_params{'email'} = $email;\n $tmp\ +_params{'title'} = $title;\n foreach my $param_nam\ +e ( keys(%tmp_params) ) {\n if ( !defined( $tmp_p\ +arams{$param_name} ) ) {\n delete $tmp_params{$p\ +aram_name};\n }\n }\n\n # Submit the job as a POS\ +T\n my $url = $baseUrl . '/run';\n my $response = \ +$ua->post( $url, \\%tmp_params );\n print_debug_me\ +ssage( 'rest_run', 'HTTP status: ' . $response->co\ +de, 11 );\n print_debug_message( 'rest_run',\n 'r\ +equest: ' . $response->request()->content(), 11 );\ +\n\n # Check for HTTP error codes\n if ( $response\ +->is_error ) {\n $response->content() =~ m/

    ([\ +^<]+)<\\/h1>/;\n die 'http status: ' . $response-\ +>code . ' ' . $response->message . ' ' . $1;\n }\\ +n\n # The job id is returned\n my $job_id = $respo\ +nse->content();\n print_debug_message( 'rest_run',\ + 'End', 1 );\n return $job_id;\n}\n\n=head2 rest_g\ +et_status()\n\nCheck the status of a job.\n\n my \ +$status = &rest_get_status($job_id);\n\n=cut\n\nsu\ +b rest_get_status {\n print_debug_message( 'rest_g\ +et_status', 'Begin', 1 );\n my $job_id = shift;\n \ +print_debug_message( 'rest_get_status', 'jobid: ' \ +. $job_id, 2 );\n my $status_str = 'UNKNOWN';\n my\ + $url = $baseUrl . '/status/' . $job_id;\n \ +$status_str = &rest_request($url);\n print_debug_m\ +essage( 'rest_get_status', 'status_str: ' . $statu\ +s_str, 2 );\n print_debug_message( 'rest_get_statu\ +s', 'End', 1 );\n return $status_str;\n}\n\n=head2\ + rest_get_result_types()\n\nGet list of result typ\ +es for finished job.\n\n my (@result_types) = &re\ +st_get_result_types($job_id);\n\n=cut\n\nsub rest_\ +get_result_types {\n print_debug_message( 'rest_ge\ +t_result_types', 'Begin', 1 );\n my $job_id = shif\ +t;\n print_debug_message( 'rest_get_result_types',\ + 'jobid: ' . $job_id, 2 );\n my (@resultTypes);\n \ +my $url = $baseUrl . '/result\ +types/' . $job_id;\n my $result_type_list_xml_str \ += &rest_request($url);\n my $result_type_list_xml \ + = XMLin($result_type_list_xml_str);\n (@result\ +Types) = @{ $result_type_list_xml->{'type'} };\n p\ +rint_debug_message( 'rest_get_result_types',\n sc\ +alar(@resultTypes) . ' result types', 2 );\n print\ +_debug_message( 'rest_get_result_types', 'End', 1 \ +);\n return (@resultTypes);\n}\n\n=head2 rest_get_\ +result()\n\nGet result data of a specified type fo\ +r a finished job.\n\n my $result = rest_get_resul\ +t($job_id, $result_type);\n\n=cut\n\nsub rest_get_\ +result {\n print_debug_message( 'rest_get_result',\ + 'Begin', 1 );\n my $job_id = shift;\n my $type \ += shift;\n print_debug_message( 'rest_get_result',\ + 'jobid: ' . $job_id, 1 );\n print_debug_message( \ +'rest_get_result', 'type: ' . $type, 1 );\n my \ +$url = $baseUrl . '/result/' . $job_id . '/' . \ +$type;\n my $result = &rest_request($url);\n print\ +_debug_message( 'rest_get_result', length($result)\ + . ' characters',\n 1 );\n print_debug_message( '\ +rest_get_result', 'End', 1 );\n return $result;\n}\ +\n\n\n=head2 print_debug_message()\n\nPrint debug \ +message at specified debug level.\n\n &print_debu\ +g_message($method_name, $message, $level);\n\n=cut\ +\n\nsub print_debug_message {\n my $function_name \ += shift;\n my $message = shift;\n my $level \ + = shift;\n if ( $level <= $params{'debugLe\ +vel'} ) {\n print STDERR '[', $function_name, '()\ +] ', $message, \"\\n\";\n }\n}\n\n=head2 print_too\ +l_params()\n\nPrint list of tool parameters.\n\n \ +&print_tool_params();\n\n=cut\n\nsub print_tool_pa\ +rams {\n print_debug_message( 'print_tool_params',\ + 'Begin', 1 );\n my (@param_list) = &rest_get_para\ +meters();\n foreach my $param ( sort(@param_list) \ +) {\n print $param, \"\\n\";\n }\n print_debug_me\ +ssage( 'print_tool_params', 'End', 1 );\n}\n\n=hea\ +d2 print_param_details()\n\nPrint details of a too\ +l parameter.\n\n &print_param_details($param_name\ +);\n\n=cut\n\nsub print_param_details {\n print_de\ +bug_message( 'print_param_details', 'Begin', 1 );\\ +n my $paramName = shift;\n print_debug_message( 'p\ +rint_param_details', 'paramName: ' . $paramName, 2\ + );\n my $paramDetail = &rest_get_parameter_detail\ +s($paramName);\n print $paramDetail->{'name'}, \"\\ +\t\", $paramDetail->{'type'}, \"\\n\";\n print $pa\ +ramDetail->{'description'}, \"\\n\";\n foreach my \ +$value ( @{ $paramDetail->{'values'}->{'value'} } \ +) {\n print $value->{'value'};\n if ( $value->{'\ +defaultValue'} eq 'true' ) {\n print \"\\t\", 'd\ +efault';\n }\n print \"\\n\";\n print \"\\t\", \ +$value->{'label'}, \"\\n\";\n }\n print_debug_mess\ +age( 'print_param_details', 'End', 1 );\n}\n\n=hea\ +d2 print_job_status()\n\nPrint status of a job.\n\\ +n &print_job_status($job_id);\n\n=cut\n\nsub prin\ +t_job_status {\n print_debug_message( 'print_job_s\ +tatus', 'Begin', 1 );\n my $jobid = shift;\n print\ +_debug_message( 'print_job_status', 'jobid: ' . $j\ +obid, 1 );\n if ( $outputLevel > 0 ) {\n print ST\ +DERR 'Getting status for job ', $jobid, \"\\n\";\n\ + }\n my $result = &rest_get_status($jobid);\n prin\ +t \"$result\\n\";\n if ( $result eq 'FINISHED' && \ +$outputLevel > 0 ) {\n print STDERR \"To get resu\ +lts: $scriptName --polljob --jobid \" . $jobid\n \ + . \"\\n\";\n }\n print_debug_message( 'print_job\ +_status', 'End', 1 );\n}\n\n=head2 print_result_ty\ +pes()\n\nPrint available result types for a job.\n\ +\n &print_result_types($job_id);\n\n=cut\n\nsub p\ +rint_result_types {\n print_debug_message( 'result\ +_types', 'Begin', 1 );\n my $jobid = shift;\n prin\ +t_debug_message( 'result_types', 'jobid: ' . $jobi\ +d, 1 );\n if ( $outputLevel > 0 ) {\n print STDER\ +R 'Getting result types for job ', $jobid, \"\\n\"\ +;\n }\n my $status = &rest_get_status($jobid);\n i\ +f ( $status eq 'PENDING' || $status eq 'RUNNING' )\ + {\n print STDERR 'Error: Job status is ', $statu\ +s,\n '. To get result types the job must be fin\ +ished.', \"\\n\";\n }\n else {\n my (@resultTypes\ +) = &rest_get_result_types($jobid);\n if ( $outpu\ +tLevel > 0 ) {\n print STDOUT 'Available result \ +types:', \"\\n\";\n }\n foreach my $resultType (\ +@resultTypes) {\n print STDOUT $resultType->{'id\ +entifier'}, \"\\n\";\n if ( defined( $resultType\ +->{'label'} ) ) {\n print STDOUT \"\\t\", $resu\ +ltType->{'label'}, \"\\n\";\n }\n if ( defined\ +( $resultType->{'description'} ) ) {\n print ST\ +DOUT \"\\t\", $resultType->{'description'}, \"\\n\\ +";\n }\n if ( defined( $resultType->{'mediaTyp\ +e'} ) ) {\n print STDOUT \"\\t\", $resultType->\ +{'mediaType'}, \"\\n\";\n }\n if ( defined( $r\ +esultType->{'fileSuffix'} ) ) {\n print STDOUT \ +\"\\t\", $resultType->{'fileSuffix'}, \"\\n\";\n \ + }\n }\n if ( $status eq 'FINISHED' && $outputLe\ +vel > 0 ) {\n print STDERR \"\\n\", 'To get resu\ +lts:', \"\\n\",\n \" $scriptName --polljob --\ +jobid \" . $params{'jobid'} . \"\\n\",\n \" $\ +scriptName --polljob --outformat --jobid \"\ +\n . $params{'jobid'} . \"\\n\";\n }\n }\n pr\ +int_debug_message( 'result_types', 'End', 1 );\n}\\ +n\n=head2 submit_job()\n\nSubmit a job to the serv\ +ice.\n\n &submit_job($seq);\n\n=cut\n\nsub submit\ +_job {\n print_debug_message( 'submit_job', 'Begin\ +', 1 );\n\n # Set input sequence\n $tool_params{'s\ +equence'} = shift;\n\n # Load parameters\n &load_p\ +arams();\n\n # Submit the job\n my $jobid = &rest_\ +run( $params{'email'}, $params{'title'}, \\%tool_p\ +arams );\n\n # Simulate sync/async mode\n if ( def\ +ined( $params{'async'} ) ) {\n print STDOUT $jobi\ +d, \"\\n\";\n if ( $outputLevel > 0 ) {\n print\ + STDERR\n \"To check status: $scriptName --sta\ +tus --jobid $jobid\\n\";\n }\n }\n else {\n if (\ + $outputLevel > 0 ) {\n print STDERR \"JobId: $j\ +obid\\n\";\n }\n sleep 1;\n &get_results($jobid\ +);\n }\n print_debug_message( 'submit_job', 'End',\ + 1 );\n}\n\n=head2 multi_submit_job()\n\nSubmit mu\ +ltiple jobs assuming input is a collection of fast\ +a formatted sequences.\n\n &multi_submit_job();\n\ +\n=cut\n\nsub multi_submit_job {\n print_debug_mes\ +sage( 'multi_submit_job', 'Begin', 1 );\n my $jobI\ +dForFilename = 1;\n $jobIdForFilename = 0 if ( def\ +ined( $params{'outfile'} ) );\n my (@filename_list\ +) = ();\n\n # Query sequence\n if ( defined( $ARGV\ +[0] ) ) { # Bare option\n if ( -f $ARGV[0] || \ +$ARGV[0] eq '-' ) { # File\n push( @filename_\ +list, $ARGV[0] );\n }\n }\n if ( $params{'sequenc\ +e'} ) { # Via --sequence\n if (\ + -f $params{'sequence'} || $params{'sequence'} eq \ +'-' ) { # File\n push( @filename_list, $param\ +s{'sequence'} );\n }\n }\n\n $/ = '>';\n foreach \ +my $filename (@filename_list) {\n open( my $INFIL\ +E, '<', $filename )\n or die \"Error: unable to\ + open file $filename ($!)\";\n while (<$INFILE>) \ +{\n my $seq = $_;\n $seq =~ s/>$//;\n if ( $\ +seq =~ m/(\\S+)/ ) {\n print STDERR \"Submittin\ +g job for: $1\\n\"\n if ( $outputLevel > 0 );\ +\n $seq = '>' . $seq;\n &print_debug_message\ +( 'multi_submit_job', $seq, 11 );\n &submit_job\ +($seq);\n $params{'outfile'} = undef if ( $jobI\ +dForFilename == 1 );\n }\n }\n close $INFILE;\\ +n }\n print_debug_message( 'multi_submit_job', 'En\ +d', 1 );\n}\n\n=head2 list_file_submit_job()\n\nSu\ +bmit multiple jobs using a file containing a list \ +of entry identifiers as \ninput.\n\n &list_file_s\ +ubmit_job($list_filename)\n\n=cut\n\nsub list_file\ +_submit_job {\n my $filename = shift;\n my\ + $jobIdForFilename = 1;\n $jobIdForFilename = 0 if\ + ( defined( $params{'outfile'} ) );\n\n # Iterate \ +over identifiers, submitting each job\n open( my $\ +LISTFILE, '<', $filename )\n or die 'Error: unab\ +le to open file ' . $filename . ' (' . $! . ')';\n\ + while (<$LISTFILE>) {\n my $line = $_;\n chomp(\ +$line);\n if ( $line ne '' ) {\n &print_debug_m\ +essage( 'list_file_submit_job', 'line: ' . $line, \ +2 );\n if ( $line =~ m/\\w:\\w/ ) { # Check t\ +his is an identifier\n print STDERR \"Submittin\ +g job for: $line\\n\"\n if ( $outputLevel > 0\ + );\n &submit_job($line);\n }\n else {\n \ + print STDERR\n\"Warning: line \\\"$line\\\" is no\ +t recognised as an identifier\\n\";\n }\n }\n \ +$params{'outfile'} = undef if ( $jobIdForFilename \ +== 1 );\n }\n close $LISTFILE;\n}\n\n=head2 load_d\ +ata()\n\nLoad sequence data from file or option sp\ +ecified on the command-line.\n\n &load_data();\n\\ +n=cut\n\nsub load_data {\n print_debug_message( 'l\ +oad_data', 'Begin', 1 );\n my $retSeq;\n\n # Query\ + sequence\n if ( defined( $ARGV[0] ) ) { # Bare\ + option\n if ( -f $ARGV[0] || $ARGV[0] eq '-' ) {\ + # File\n $retSeq = &read_file( $ARGV[0] );\n\ + }\n else { \ +# DB:ID or sequence\n $retSeq = $ARGV[0];\n }\n\ + }\n if ( $params{'sequence'} ) { \ + # Via --sequence\n if ( -f $params{'sequence'} \ +|| $params{'sequence'} eq '-' ) { # File\n $r\ +etSeq = &read_file( $params{'sequence'} );\n }\n \ + else { # DB:ID or sequence\n $retSeq = $para\ +ms{'sequence'};\n }\n }\n print_debug_message( 'l\ +oad_data', 'End', 1 );\n return $retSeq;\n}\n\n=he\ +ad2 load_params()\n\nLoad job parameters from comm\ +and-line options.\n\n &load_params();\n\n=cut\n\n\ +sub load_params {\n print_debug_message( 'load_par\ +ams', 'Begin', 1 );\n\n # Database(s) to search\n \ +my (@dbList) = split /[ ,]/, $params{'database'};\\ +n $tool_params{'database'} = \\@dbList;\n\n # Matc\ +h/missmatch\n if ( $params{'match'} && $params{'mi\ +ssmatch'} ) {\n $tool_params{'match_scores'} =\n \ + $params{'match'} . ',' . $params{'missmatch'};\\ +n }\n \n # Compatability options, old command-line\ +\n if(!$tool_params{'alignments'} && $params{'numa\ +l'}) {\n $tool_params{'alignments'} = $params{'nu\ +mal'};\n }\n if(!$tool_params{'gapopen'} && $param\ +s{'opengap'}) {\n $tool_params{'gapopen'} = $para\ +ms{'opengap'};\n }\n if(!$tool_params{'gapext'} &&\ + $params{'extendgap'}) {\n $tool_params{'gapext'}\ + = $params{'extendgap'};\n }\n\n print_debug_messa\ +ge( 'load_params', 'End', 1 );\n}\n\n=head2 client\ +_poll()\n\nClient-side job polling.\n\n &client_p\ +oll($job_id);\n\n=cut\n\nsub client_poll {\n print\ +_debug_message( 'client_poll', 'Begin', 1 );\n my \ +$jobid = shift;\n my $status = 'PENDING';\n\n my \ +$errorCount = 0;\n while ($status eq 'RUNNING'\n \ +|| $status eq 'PENDING'\n || ( $status eq 'ERROR'\ + && $errorCount < 2 ) )\n {\n $status = rest_get_\ +status($jobid);\n print STDERR \"$status\\n\" if \ +( $outputLevel > 0 );\n if ( $status eq 'ERROR' )\ + {\n $errorCount++;\n }\n elsif ( $errorCount \ +> 0 ) {\n $errorCount--;\n }\n if ( $status \ +eq 'RUNNING'\n || $status eq 'PENDING'\n || $s\ +tatus eq 'ERROR' )\n {\n\n # Wait before pollin\ +g again.\n sleep $checkInterval;\n }\n }\n prin\ +t_debug_message( 'client_poll', 'End', 1 );\n retu\ +rn $status;\n}\n\n=head2 get_results()\n\nGet the \ +results for a job identifier.\n\n &get_results($j\ +ob_id);\n\n=cut\n\nsub get_results {\n print_debug\ +_message( 'get_results', 'Begin', 1 );\n my $jobid\ + = shift;\n print_debug_message( 'get_results', 'j\ +obid: ' . $jobid, 1 );\n\n # Verbose\n if ( $outpu\ +tLevel > 1 ) {\n print 'Getting results for job '\ +, $jobid, \"\\n\";\n }\n\n # Check status, and wai\ +t if not finished\n client_poll($jobid);\n\n # Use\ + JobId if output file name is not defined\n unless\ + ( defined( $params{'outfile'} ) ) {\n $params{'o\ +utfile'} = $jobid;\n }\n\n # Get list of data type\ +s\n my (@resultTypes) = rest_get_result_types($job\ +id);\n\n # Get the data and write it to a file\n i\ +f ( defined( $params{'outformat'} ) ) { # Speci\ +fied data type\n my $selResultType;\n foreach my\ + $resultType (@resultTypes) {\n if ( $resultType\ +->{'identifier'} eq $params{'outformat'} ) {\n \ +$selResultType = $resultType;\n }\n }\n if ( d\ +efined($selResultType) ) {\n my $result =\n \ +rest_get_result( $jobid, $selResultType->{'identif\ +ier'} );\n if ( $params{'outfile'} eq '-' ) {\n \ + write_file( $params{'outfile'}, $result );\n \ +}\n else {\n write_file(\n $params{'outfi\ +le'} . '.'\n . $selResultType->{'identifier'\ +} . '.'\n . $selResultType->{'fileSuffix'},\\ +n $result\n );\n }\n }\n else {\n die\ + 'Error: unknown result format \"' . $params{'outf\ +ormat'} . '\"';\n }\n }\n else { # Data types \ +available\n # Write a file for each output \ +type\n for my $resultType (@resultTypes) {\n if\ + ( $outputLevel > 1 ) {\n print STDERR 'Getting\ + ', $resultType->{'identifier'}, \"\\n\";\n }\n \ + my $result = rest_get_result( $jobid, $resultTyp\ +e->{'identifier'} );\n if ( $params{'outfile'} e\ +q '-' ) {\n write_file( $params{'outfile'}, $re\ +sult );\n }\n else {\n write_file(\n $p\ +arams{'outfile'} . '.'\n . $resultType->{'id\ +entifier'} . '.'\n . $resultType->{'fileSuff\ +ix'},\n $result\n );\n }\n }\n }\n print\ +_debug_message( 'get_results', 'End', 1 );\n}\n\n=\ +head2 read_file()\n\nRead a file into a scalar. Th\ +e special filename '-' can be used to read from \n\ +standard input (STDIN).\n\n my $data = &read_file\ +($filename);\n\n=cut\n\nsub read_file {\n print_de\ +bug_message( 'read_file', 'Begin', 1 );\n my $file\ +name = shift;\n print_debug_message( 'read_file', \ +'filename: ' . $filename, 2 );\n my ( $content, $b\ +uffer );\n if ( $filename eq '-' ) {\n while ( sy\ +sread( STDIN, $buffer, 1024 ) ) {\n $content .= \ +$buffer;\n }\n }\n else { # File\n open( my $\ +FILE, '<', $filename )\n or die \"Error: unable\ + to open input file $filename ($!)\";\n while ( s\ +ysread( $FILE, $buffer, 1024 ) ) {\n $content .=\ + $buffer;\n }\n close($FILE);\n }\n print_debug_\ +message( 'read_file', 'End', 1 );\n return $conten\ +t;\n}\n\n=head2 write_file()\n\nWrite data to a fi\ +le. The special filename '-' can be used to write \ +to \nstandard output (STDOUT).\n\n &write_file($f\ +ilename, $data);\n\n=cut\n\nsub write_file {\n pri\ +nt_debug_message( 'write_file', 'Begin', 1 );\n my\ + ( $filename, $data ) = @_;\n print_debug_message(\ + 'write_file', 'filename: ' . $filename, 2 );\n if\ + ( $outputLevel > 0 ) {\n print STDERR 'Creating \ +result file: ' . $filename . \"\\n\";\n }\n if ( $\ +filename eq '-' ) {\n print STDOUT $data;\n }\n e\ +lse {\n open( my $FILE, '>', $filename )\n or \ +die \"Error: unable to open output file $filename \ +($!)\";\n syswrite( $FILE, $data );\n close($FIL\ +E);\n }\n print_debug_message( 'write_file', 'End'\ +, 1 );\n}\n\n=head2 usage()\n\nPrint program usage\ + message.\n\n &usage();\n\n=cut\n\nsub usage {\n \ +print STDERR < [options...] seqFile\n Returns: r\ +esults as an attachment\n\nAsynchronous job:\n\n \ +Use this if you want to retrieve the results at a \ +later time. The results \n are stored for up to 2\ +4 hours. \n Usage: $scriptName --async --email <\ +your\\@email> [options...] seqFile\n Returns: job\ +id\n\n Use the jobid to query for the status of t\ +he job. If the job is finished, \n it also return\ +s the results/errors.\n Usage: $scriptName --poll\ +job --jobid [--outfile string]\n Returns:\ + string indicating the status of the job and if ap\ +plicable, results \n as an attachment.\n\nFurther\ + information:\n\n http://www.ebi.ac.uk/Tools/webs\ +ervices/services/sss/ncbi_blast_rest\n http://www\ +.ebi.ac.uk/Tools/webservices/tutorials/perl\n\nSup\ +port/Feedback:\n\n http://www.ebi.ac.uk/support/\\ +nEOF\n}\n\n=head1 FEEDBACK/SUPPORT\n\nPlease conta\ +ct us at L if you h\ +ave any \nfeedback, suggestions or issues with the\ + service or this client.\n\n=cut\n","\n=head1 NAME\ +\n\nwublast_lwp.pl\n\n=head1 DESCRIPTION\n\nWU-BLA\ +ST REST web service Perl client using L.\n\nT\ +ested with:\n\n=over\n\n=item *\nL 5.79, L 2.12 and Perl 5.8.3\n\n=item *\nL \ +5.805, L 2.14 and Perl 5.8.7\n\n=item\ + *\nL 5.820, L 2.18 and Perl 5.1\ +0.0 (Ubuntu 9.04)\n\n=back\n\nFor further informat\ +ion see:\n\n=over\n\n=item *\nL\n\ +\n=item *\nL\n\n=back\n\n=head1 VERSION\n\n$I\ +d: wublast_lwp.pl 1317 2009-09-03 15:44:11Z hpm $\\ +n\n=cut\n\nuse strict;\nuse warnings;\n\nuse Engli\ +sh;\nuse LWP;\nuse XML::Simple;\nuse Getopt::Long \ +qw(:config no_ignore_case bundling);\nuse File::Ba\ +sename;\nuse Data::Dumper;\n\nmy $baseUrl = 'http:\ +//www.ebi.ac.uk/Tools/services/rest/wublast';\n\nm\ +y $checkInterval = 3;\n\nmy $outputLevel = 1;\n\nm\ +y $numOpts = scalar(@ARGV);\nmy %params = ( 'debug\ +Level' => 0 );\n\nmy %tool_params = ();\nGetOption\ +s(\n\n # Tool specific options\n 'program|p=s' \ + => \\$tool_params{'program'}, # BLAST progra\ +m\n 'database|D=s' => \\$params{'database'}, \ + # Search database\n 'matrix|m=s' => \\$tool\ +_params{'matrix'}, # Scoring matrix\n 'exp|E\ +=f' => \\$tool_params{'exp'}, # E\ +-value threshold\n 'viewfilter|e' => \\$tool_pa\ +rams{'viewfilter'}, # Display filtered sequence\\ +n 'filter|f=s' => \\$tool_params{'filter'}, \ + # Low complexity filter name\n 'alignments|n=\ +i' => \\$tool_params{'alignments'}, # Number of\ + alignments\n 'scores|s=i' => \\$tool_params{\ +'scores'}, # Number of scores\n 'sensitivity\ +|S=s' => \\$tool_params{'sensitivity'}, # Search \ +sensitivity\n 'sort|t=s' => \\$tool_params{\ +'sort'}, # Sort hits by...\n 'stats|T=s' \ + => \\$tool_params{'stats'}, # Scoring \ +statistic to use\n 'strand|d=s' => \\$tool_pa\ +rams{'strand'}, # Strand to use\n 'topcombon\ +|c=i' => \\$tool_params{'topcombon'}, # Consi\ +stent sets of HSPs\n 'align|A=i' => \\$tool_\ +params{'align'}, # Pairwise alignment format\n '\ +stype=s' => \\$tool_params{'stype'}, # Sequence\ + type 'protein' or 'dna'\n 'sequence=s' => \\$para\ +ms{'sequence'}, # Query sequence file or D\ +B:ID\n 'multifasta' => \\$params{'multifasta'}, \ + # Multiple fasta input\n\n # Compatability opt\ +ions, old command-line.\n 'echofilter|e' => \\$\ +params{'echofilter'}, # Display filtered sequenc\ +e\n 'b=i' => \\$params{'numal'}, # Number \ +of alignments\n 'appxml=s' => \\$params{'ap\ +pxml'}, # Application XML\n\n # Generic opti\ +ons\n 'email=s' => \\$params{'email'}, \ + # User e-mail address\n 'title=s' => \\$\ +params{'title'}, # Job title\n 'outfile=s\ +' => \\$params{'outfile'}, # Output fil\ +e name\n 'outformat=s' => \\$params{'outformat'}\ +, # Output file type\n 'jobid=s' => \\$\ +params{'jobid'}, # JobId\n 'help|h' \ + => \\$params{'help'}, # Usage help\n '\ +async' => \\$params{'async'}, # A\ +synchronous submission\n 'polljob' => \\$par\ +ams{'polljob'}, # Get results\n 'resultType\ +s' => \\$params{'resultTypes'}, # Get result \ +types\n 'status' => \\$params{'status'}, \ + # Get status\n 'params' => \\$params{\ +'params'}, # List input parameters\n 'para\ +mDetail=s' => \\$params{'paramDetail'}, # Get d\ +etails for parameter\n 'quiet' => \\$param\ +s{'quiet'}, # Decrease output level\n 've\ +rbose' => \\$params{'verbose'}, # Inc\ +rease output level\n 'debugLevel=i' => \\$params{\ +'debugLevel'}, # Debug output level\n 'baseUrl\ +=s' => \\$baseUrl, # Base URL\ + for service.\n);\nif ( $params{'verbose'} ) { $ou\ +tputLevel++ }\nif ( $params{'$quiet'} ) { $output\ +Level-- }\n\n&print_debug_message( 'MAIN', 'LWP::V\ +ERSION: ' . $LWP::VERSION,\n 1 );\n\n&print_debug_\ +message( 'MAIN', \"params:\\n\" . Dumper( \\%param\ +s ), 11 );\n&print_debug_message( 'MAIN'\ +, \"tool_params:\\n\" . Dumper( \\%tool_params ), \ +11 );\n\nmy $scriptName = basename( $0, () );\n\ni\ +f ( $params{'help'} || $numOpts == 0 ) {\n &usage(\ +);\n exit(0);\n}\n\n&print_debug_message( 'MAIN', \ +'baseUrl: ' . $baseUrl, 1 );\n\nif (\n !(\n $p\ +arams{'polljob'}\n || $params{'resultTypes'}\n |\ +| $params{'status'}\n || $params{'params'}\n || \ +$params{'paramDetail'}\n )\n && !( defined( $ARGV[\ +0] ) || defined( $params{'sequence'} ) )\n )\n{\n\ +\n # Bad argument combination, so print error mess\ +age and usage\n print STDERR 'Error: bad option co\ +mbination', \"\\n\";\n &usage();\n exit(1);\n}\n\n\ +elsif ( $params{'params'} ) {\n &print_tool_params\ +();\n}\n\nelsif ( $params{'paramDetail'} ) {\n &pr\ +int_param_details( $params{'paramDetail'} );\n}\n\\ +nelsif ( $params{'status'} && defined( $params{'jo\ +bid'} ) ) {\n &print_job_status( $params{'jobid'} \ +);\n}\n\nelsif ( $params{'resultTypes'} && defined\ +( $params{'jobid'} ) ) {\n &print_result_types( $p\ +arams{'jobid'} );\n}\n\nelsif ( $params{'polljob'}\ + && defined( $params{'jobid'} ) ) {\n &get_results\ +( $params{'jobid'} );\n}\n\nelse {\n\n # Multiple \ +input sequence mode, assume fasta format.\n if ( $\ +params{'multifasta'} ) {\n &multi_submit_job();\n\ + }\n\n # Entry identifier list file.\n elsif (( de\ +fined( $params{'sequence'} ) && $params{'sequence'\ +} =~ m/^\\@/ )\n || ( defined( $ARGV[0] ) && $ARG\ +V[0] =~ m/^\\@/ ) )\n {\n my $list_filename = $pa\ +rams{'sequence'} || $ARGV[0];\n $list_filename =~\ + s/^\\@//;\n &list_file_submit_job($list_filename\ +);\n }\n\n # Default: single sequence/identifier.\\ +n else {\n\n # Load the sequence data and submit.\ +\n &submit_job( &load_data() );\n }\n}\n\n=head1 \ +FUNCTIONS\n\n=cut\n\n\n=head2 rest_request()\n\nPe\ +rform a REST request.\n\n my $response_str = &res\ +t_request($url);\n\n=cut\n\nsub rest_request {\n p\ +rint_debug_message( 'rest_request', 'Begin', 11 );\ +\n my $requestUrl = shift;\n print_debug_message( \ +'rest_request', 'URL: ' . $requestUrl, 11 );\n\n #\ + Create a user agent\n my $ua = LWP::UserAgent->ne\ +w();\n '$Revision: 1317 $' =~ m/(\\d+)/;\n $ua->ag\ +ent(\"EBI-Sample-Client/$1 ($scriptName; $OSNAME) \ +\" . $ua->agent());\n $ua->env_proxy;\n\n # Perfor\ +m the request\n my $response = $ua->get($requestUr\ +l);\n print_debug_message( 'rest_request', 'HTTP s\ +tatus: ' . $response->code,\n 11 );\n\n # Check f\ +or HTTP error codes\n if ( $response->is_error ) {\ +\n $response->content() =~ m/

    ([^<]+)<\\/h1>/;\ +\n die 'http status: ' . $response->code . ' ' . \ +$response->message . ' ' . $1;\n }\n print_debug_\ +message( 'rest_request', 'End', 11 );\n\n # Return\ + the response data\n return $response->content();\\ +n}\n\n=head2 rest_get_parameters()\n\nGet list of \ +tool parameter names.\n\n my (@param_list) = &res\ +t_get_parameters();\n\n=cut\n\nsub rest_get_parame\ +ters {\n print_debug_message( 'rest_get_parameters\ +', 'Begin', 1 );\n my $url = $baseU\ +rl . '/parameters/';\n my $param_list_xml_str = re\ +st_request($url);\n my $param_list_xml = XMLin\ +($param_list_xml_str);\n my (@param_list) = \ +@{ $param_list_xml->{'id'} };\n print_debug_messag\ +e( 'rest_get_parameters', 'End', 1 );\n return (@p\ +aram_list);\n}\n\n=head2 rest_get_parameter_detail\ +s()\n\nGet details of a tool parameter.\n\n my $p\ +aramDetail = &rest_get_parameter_details($param_na\ +me);\n\n=cut\n\nsub rest_get_parameter_details {\n\ + print_debug_message( 'rest_get_parameter_details'\ +, 'Begin', 1 );\n my $parameterId = shift;\n print\ +_debug_message( 'rest_get_parameter_details',\n '\ +parameterId: ' . $parameterId, 1 );\n my $url \ + = $baseUrl . '/parameterdetails/' . $\ +parameterId;\n my $param_detail_xml_str = rest_req\ +uest($url);\n my $param_detail_xml = XMLin($pa\ +ram_detail_xml_str);\n print_debug_message( 'rest_\ +get_parameter_details', 'End', 1 );\n return ($par\ +am_detail_xml);\n}\n\n=head2 rest_run()\n\nSubmit \ +a job.\n\n my $job_id = &rest_run($email, $title,\ + \\%params );\n\n=cut\n\nsub rest_run {\n print_de\ +bug_message( 'rest_run', 'Begin', 1 );\n my $email\ + = shift;\n my $title = shift;\n my $params = sh\ +ift;\n print_debug_message( 'rest_run', 'email: ' \ +. $email, 1 );\n if ( defined($title) ) {\n print\ +_debug_message( 'rest_run', 'title: ' . $title, 1 \ +);\n }\n print_debug_message( 'rest_run', 'params:\ + ' . Dumper($params), 1 );\n\n # User agent to per\ +form http requests\n my $ua = LWP::UserAgent->new(\ +);\n $ua->env_proxy;\n\n # Clean up parameters\n m\ +y (%tmp_params) = %{$params};\n $tmp_params{'email\ +'} = $email;\n $tmp_params{'title'} = $title;\n fo\ +reach my $param_name ( keys(%tmp_params) ) {\n if\ + ( !defined( $tmp_params{$param_name} ) ) {\n de\ +lete $tmp_params{$param_name};\n }\n }\n\n # Subm\ +it the job as a POST\n my $url = $baseUrl . '/run'\ +;\n my $response = $ua->post( $url, \\%tmp_params \ +);\n print_debug_message( 'rest_run', 'HTTP status\ +: ' . $response->code, 11 );\n print_debug_message\ +( 'rest_run',\n 'request: ' . $response->request(\ +)->content(), 11 );\n\n # Check for HTTP error cod\ +es\n if ( $response->is_error ) {\n $response->co\ +ntent() =~ m/

    ([^<]+)<\\/h1>/;\n die 'http sta\ +tus: ' . $response->code . ' ' . $response->messag\ +e . ' ' . $1;\n }\n\n # The job id is returned\n \ +my $job_id = $response->content();\n print_debug_m\ +essage( 'rest_run', 'End', 1 );\n return $job_id;\\ +n}\n\n=head2 rest_get_status()\n\nCheck the status\ + of a job.\n\n my $status = &rest_get_status($job\ +_id);\n\n=cut\n\nsub rest_get_status {\n print_deb\ +ug_message( 'rest_get_status', 'Begin', 1 );\n my \ +$job_id = shift;\n print_debug_message( 'rest_get_\ +status', 'jobid: ' . $job_id, 2 );\n my $status_st\ +r = 'UNKNOWN';\n my $url = $baseUrl . '/sta\ +tus/' . $job_id;\n $status_str = &rest_request($ur\ +l);\n print_debug_message( 'rest_get_status', 'sta\ +tus_str: ' . $status_str, 2 );\n print_debug_messa\ +ge( 'rest_get_status', 'End', 1 );\n return $statu\ +s_str;\n}\n\n=head2 rest_get_result_types()\n\nGet\ + list of result types for finished job.\n\n my (@\ +result_types) = &rest_get_result_types($job_id);\n\ +\n=cut\n\nsub rest_get_result_types {\n print_debu\ +g_message( 'rest_get_result_types', 'Begin', 1 );\\ +n my $job_id = shift;\n print_debug_message( 'rest\ +_get_result_types', 'jobid: ' . $job_id, 2 );\n my\ + (@resultTypes);\n my $url = \ +$baseUrl . '/resulttypes/' . $job_id;\n my $result\ +_type_list_xml_str = &rest_request($url);\n my $re\ +sult_type_list_xml = XMLin($result_type_list_x\ +ml_str);\n (@resultTypes) = @{ $result_type_list_x\ +ml->{'type'} };\n print_debug_message( 'rest_get_r\ +esult_types',\n scalar(@resultTypes) . ' result t\ +ypes', 2 );\n print_debug_message( 'rest_get_resul\ +t_types', 'End', 1 );\n return (@resultTypes);\n}\\ +n\n=head2 rest_get_result()\n\nGet result data of \ +a specified type for a finished job.\n\n my $resu\ +lt = rest_get_result($job_id, $result_type);\n\n=c\ +ut\n\nsub rest_get_result {\n print_debug_message(\ + 'rest_get_result', 'Begin', 1 );\n my $job_id = s\ +hift;\n my $type = shift;\n print_debug_message(\ + 'rest_get_result', 'jobid: ' . $job_id, 1 );\n pr\ +int_debug_message( 'rest_get_result', 'type: ' . $\ +type, 1 );\n my $url = $baseUrl . '/result/'\ + . $job_id . '/' . $type;\n my $result = &rest_req\ +uest($url);\n print_debug_message( 'rest_get_resul\ +t', length($result) . ' characters',\n 1 );\n pri\ +nt_debug_message( 'rest_get_result', 'End', 1 );\n\ + return $result;\n}\n\n\n=head2 print_debug_messag\ +e()\n\nPrint debug message at specified debug leve\ +l.\n\n &print_debug_message($method_name, $messag\ +e, $level);\n\n=cut\n\nsub print_debug_message {\n\ + my $function_name = shift;\n my $message = \ +shift;\n my $level = shift;\n if ( $level \ +<= $params{'debugLevel'} ) {\n print STDERR '[', \ +$function_name, '()] ', $message, \"\\n\";\n }\n}\\ +n\n=head2 print_tool_params()\n\nPrint list of too\ +l parameters.\n\n &print_tool_params();\n\n=cut\n\ +\nsub print_tool_params {\n print_debug_message( '\ +print_tool_params', 'Begin', 1 );\n my (@param_lis\ +t) = &rest_get_parameters();\n foreach my $param (\ + sort(@param_list) ) {\n print $param, \"\\n\";\n\ + }\n print_debug_message( 'print_tool_params', 'En\ +d', 1 );\n}\n\n=head2 print_param_details()\n\nPri\ +nt details of a tool parameter.\n\n &print_param_\ +details($param_name);\n\n=cut\n\nsub print_param_d\ +etails {\n print_debug_message( 'print_param_detai\ +ls', 'Begin', 1 );\n my $paramName = shift;\n prin\ +t_debug_message( 'print_param_details', 'paramName\ +: ' . $paramName, 2 );\n my $paramDetail = &rest_g\ +et_parameter_details($paramName);\n print $paramDe\ +tail->{'name'}, \"\\t\", $paramDetail->{'type'}, \\ +"\\n\";\n print $paramDetail->{'description'}, \"\\ +\n\";\n foreach my $value ( @{ $paramDetail->{'val\ +ues'}->{'value'} } ) {\n print $value->{'value'};\ +\n if ( $value->{'defaultValue'} eq 'true' ) {\n \ + print \"\\t\", 'default';\n }\n print \"\\n\";\ +\n print \"\\t\", $value->{'label'}, \"\\n\";\n }\ +\n print_debug_message( 'print_param_details', 'En\ +d', 1 );\n}\n\n=head2 print_job_status()\n\nPrint \ +status of a job.\n\n &print_job_status($job_id);\\ +n\n=cut\n\nsub print_job_status {\n print_debug_me\ +ssage( 'print_job_status', 'Begin', 1 );\n my $job\ +id = shift;\n print_debug_message( 'print_job_stat\ +us', 'jobid: ' . $jobid, 1 );\n if ( $outputLevel \ +> 0 ) {\n print STDERR 'Getting status for job ',\ + $jobid, \"\\n\";\n }\n my $result = &rest_get_sta\ +tus($jobid);\n print \"$result\\n\";\n if ( $resul\ +t eq 'FINISHED' && $outputLevel > 0 ) {\n print S\ +TDERR \"To get results: $scriptName --polljob --jo\ +bid \" . $jobid\n . \"\\n\";\n }\n print_debug_\ +message( 'print_job_status', 'End', 1 );\n}\n\n=he\ +ad2 print_result_types()\n\nPrint available result\ + types for a job.\n\n &print_result_types($job_id\ +);\n\n=cut\n\nsub print_result_types {\n print_deb\ +ug_message( 'result_types', 'Begin', 1 );\n my $jo\ +bid = shift;\n print_debug_message( 'result_types'\ +, 'jobid: ' . $jobid, 1 );\n if ( $outputLevel > 0\ + ) {\n print STDERR 'Getting result types for job\ + ', $jobid, \"\\n\";\n }\n my $status = &rest_get_\ +status($jobid);\n if ( $status eq 'PENDING' || $st\ +atus eq 'RUNNING' ) {\n print STDERR 'Error: Job \ +status is ', $status,\n '. To get result types \ +the job must be finished.', \"\\n\";\n }\n else {\\ +n my (@resultTypes) = &rest_get_result_types($job\ +id);\n if ( $outputLevel > 0 ) {\n print STDOUT\ + 'Available result types:', \"\\n\";\n }\n forea\ +ch my $resultType (@resultTypes) {\n print STDOU\ +T $resultType->{'identifier'}, \"\\n\";\n if ( d\ +efined( $resultType->{'label'} ) ) {\n print ST\ +DOUT \"\\t\", $resultType->{'label'}, \"\\n\";\n \ + }\n if ( defined( $resultType->{'description'} \ +) ) {\n print STDOUT \"\\t\", $resultType->{'de\ +scription'}, \"\\n\";\n }\n if ( defined( $res\ +ultType->{'mediaType'} ) ) {\n print STDOUT \"\\ +\t\", $resultType->{'mediaType'}, \"\\n\";\n }\n\ + if ( defined( $resultType->{'fileSuffix'} ) ) {\ +\n print STDOUT \"\\t\", $resultType->{'fileSuf\ +fix'}, \"\\n\";\n }\n }\n if ( $status eq 'FIN\ +ISHED' && $outputLevel > 0 ) {\n print STDERR \"\ +\\n\", 'To get results:', \"\\n\",\n \" $scri\ +ptName --polljob --jobid \" . $params{'jobid'} . \\ +"\\n\",\n \" $scriptName --polljob --outforma\ +t --jobid \"\n . $params{'jobid'} . \"\\ +\n\";\n }\n }\n print_debug_message( 'result_type\ +s', 'End', 1 );\n}\n\n=head2 submit_job()\n\nSubmi\ +t a job to the service.\n\n &submit_job($seq);\n\\ +n=cut\n\nsub submit_job {\n print_debug_message( '\ +submit_job', 'Begin', 1 );\n\n # Set input sequenc\ +e\n $tool_params{'sequence'} = shift;\n\n # Load p\ +arameters\n &load_params();\n\n # Submit the job\n\ + my $jobid = &rest_run( $params{'email'}, $params{\ +'title'}, \\%tool_params );\n\n # Simulate sync/as\ +ync mode\n if ( defined( $params{'async'} ) ) {\n \ + print STDOUT $jobid, \"\\n\";\n if ( $outputLeve\ +l > 0 ) {\n print STDERR\n \"To check status\ +: $scriptName --status --jobid $jobid\\n\";\n }\n\ + }\n else {\n if ( $outputLevel > 0 ) {\n print\ + STDERR \"JobId: $jobid\\n\";\n }\n sleep 1;\n \ +&get_results($jobid);\n }\n print_debug_message( '\ +submit_job', 'End', 1 );\n}\n\n=head2 multi_submit\ +_job()\n\nSubmit multiple jobs assuming input is a\ + collection of fasta formatted sequences.\n\n &mu\ +lti_submit_job();\n\n=cut\n\nsub multi_submit_job \ +{\n print_debug_message( 'multi_submit_job', 'Begi\ +n', 1 );\n my $jobIdForFilename = 1;\n $jobIdForFi\ +lename = 0 if ( defined( $params{'outfile'} ) );\n\ + my (@filename_list) = ();\n\n # Query sequence\n \ +if ( defined( $ARGV[0] ) ) { # Bare option\n i\ +f ( -f $ARGV[0] || $ARGV[0] eq '-' ) { # File\n\ + push( @filename_list, $ARGV[0] );\n }\n }\n if\ + ( $params{'sequence'} ) { # Via\ + --sequence\n if ( -f $params{'sequence'} || $par\ +ams{'sequence'} eq '-' ) { # File\n push( @fi\ +lename_list, $params{'sequence'} );\n }\n }\n\n $\ +/ = '>';\n foreach my $filename (@filename_list) {\ +\n open( my $INFILE, '<', $filename )\n or die\ + \"Error: unable to open file $filename ($!)\";\n \ + while (<$INFILE>) {\n my $seq = $_;\n $seq =~\ + s/>$//;\n if ( $seq =~ m/(\\S+)/ ) {\n print\ + STDERR \"Submitting job for: $1\\n\"\n if ( \ +$outputLevel > 0 );\n $seq = '>' . $seq;\n &\ +print_debug_message( 'multi_submit_job', $seq, 11 \ +);\n &submit_job($seq);\n $params{'outfile'}\ + = undef if ( $jobIdForFilename == 1 );\n }\n }\ +\n close $INFILE;\n }\n print_debug_message( 'mul\ +ti_submit_job', 'End', 1 );\n}\n\n=head2 list_file\ +_submit_job()\n\nSubmit multiple jobs using a file\ + containing a list of entry identifiers as \ninput\ +.\n\n &list_file_submit_job($list_filename)\n\n=c\ +ut\n\nsub list_file_submit_job {\n my $filename \ + = shift;\n my $jobIdForFilename = 1;\n $jobI\ +dForFilename = 0 if ( defined( $params{'outfile'} \ +) );\n\n # Iterate over identifiers, submitting ea\ +ch job\n open( my $LISTFILE, '<', $filename )\n \ +or die 'Error: unable to open file ' . $filename .\ + ' (' . $! . ')';\n while (<$LISTFILE>) {\n my $l\ +ine = $_;\n chomp($line);\n if ( $line ne '' ) {\ +\n &print_debug_message( 'list_file_submit_job',\ + 'line: ' . $line, 2 );\n if ( $line =~ m/\\w:\\\ +w/ ) { # Check this is an identifier\n print\ + STDERR \"Submitting job for: $line\\n\"\n if\ + ( $outputLevel > 0 );\n &submit_job($line);\n \ + }\n else {\n print STDERR\n\"Warning: line \ +\\\"$line\\\" is not recognised as an identifier\\\ +n\";\n }\n }\n $params{'outfile'} = undef if (\ + $jobIdForFilename == 1 );\n }\n close $LISTFILE;\\ +n}\n\n=head2 load_data()\n\nLoad sequence data fro\ +m file or option specified on the command-line.\n\\ +n &load_data();\n\n=cut\n\nsub load_data {\n prin\ +t_debug_message( 'load_data', 'Begin', 1 );\n my $\ +retSeq;\n\n # Query sequence\n if ( defined( $ARGV\ +[0] ) ) { # Bare option\n if ( -f $ARGV[0] || \ +$ARGV[0] eq '-' ) { # File\n $retSeq = &read_\ +file( $ARGV[0] );\n }\n else { \ + # DB:ID or sequence\n $retSeq\ + = $ARGV[0];\n }\n }\n if ( $params{'sequence'} )\ + { # Via --sequence\n if ( -f $\ +params{'sequence'} || $params{'sequence'} eq '-' )\ + { # File\n $retSeq = &read_file( $params{'se\ +quence'} );\n }\n else { # DB:ID or sequence\\ +n $retSeq = $params{'sequence'};\n }\n }\n prin\ +t_debug_message( 'load_data', 'End', 1 );\n return\ + $retSeq;\n}\n\n=head2 load_params()\n\nLoad job p\ +arameters from command-line options.\n\n &load_pa\ +rams();\n\n=cut\n\nsub load_params {\n print_debug\ +_message( 'load_params', 'Begin', 1 );\n\n # Datab\ +ase(s) to search\n my (@dbList) = split /[ ,]/, $p\ +arams{'database'};\n $tool_params{'database'} = \\\ +@dbList;\n\n # Compatability options, old command-\ +line.\n if(!$tool_params{'viewfilter'} && $params{\ +'echofilter'}) {\n $tool_params{'viewfilter'} = '\ +true';\n }\n if(!$tool_params{'alignments'} && $pa\ +rams{'numal'}) {\n $tool_params{'alignments'} = $\ +params{'numal'};\n }\n # TODO: set alignment forma\ +t option to get NCBI BLAST XML.\n if($params{'appx\ +ml'}) {\n $tool_params{'align'} = '';\n }\n\n pri\ +nt_debug_message( 'load_params', 'End', 1 );\n}\n\\ +n=head2 client_poll()\n\nClient-side job polling.\\ +n\n &client_poll($job_id);\n\n=cut\n\nsub client_\ +poll {\n print_debug_message( 'client_poll', 'Begi\ +n', 1 );\n my $jobid = shift;\n my $status = 'PEN\ +DING';\n\n my $errorCount = 0;\n while ($status eq\ + 'RUNNING'\n || $status eq 'PENDING'\n || ( $sta\ +tus eq 'ERROR' && $errorCount < 2 ) )\n {\n $stat\ +us = rest_get_status($jobid);\n print STDERR \"$s\ +tatus\\n\" if ( $outputLevel > 0 );\n if ( $statu\ +s eq 'ERROR' ) {\n $errorCount++;\n }\n elsif \ +( $errorCount > 0 ) {\n $errorCount--;\n }\n i\ +f ( $status eq 'RUNNING'\n || $status eq 'PEND\ +ING'\n || $status eq 'ERROR' )\n {\n\n # Wait\ + before polling again.\n sleep $checkInterval;\n\ + }\n }\n print_debug_message( 'client_poll', 'End\ +', 1 );\n return $status;\n}\n\n=head2 get_results\ +()\n\nGet the results for a job identifier.\n\n &\ +get_results($job_id);\n\n=cut\n\nsub get_results {\ +\n print_debug_message( 'get_results', 'Begin', 1 \ +);\n my $jobid = shift;\n print_debug_message( 'ge\ +t_results', 'jobid: ' . $jobid, 1 );\n\n # Verbose\ +\n if ( $outputLevel > 1 ) {\n print 'Getting res\ +ults for job ', $jobid, \"\\n\";\n }\n\n # Check s\ +tatus, and wait if not finished\n client_poll($job\ +id);\n\n # Use JobId if output file name is not de\ +fined\n unless ( defined( $params{'outfile'} ) ) {\ +\n $params{'outfile'} = $jobid;\n }\n\n # Get lis\ +t of data types\n my (@resultTypes) = rest_get_res\ +ult_types($jobid);\n\n # Get the data and write it\ + to a file\n if ( defined( $params{'outformat'} ) \ +) { # Specified data type\n my $selResultType;\ +\n foreach my $resultType (@resultTypes) {\n if\ + ( $resultType->{'identifier'} eq $params{'outform\ +at'} ) {\n $selResultType = $resultType;\n }\\ +n }\n if ( defined($selResultType) ) {\n my $r\ +esult =\n rest_get_result( $jobid, $selResultT\ +ype->{'identifier'} );\n if ( $params{'outfile'}\ + eq '-' ) {\n write_file( $params{'outfile'}, $\ +result );\n }\n else {\n write_file(\n \ +$params{'outfile'} . '.'\n . $selResultType-\ +>{'identifier'} . '.'\n . $selResultType->{'\ +fileSuffix'},\n $result\n );\n }\n }\n \ +else {\n die 'Error: unknown result format \"' .\ + $params{'outformat'} . '\"';\n }\n }\n else { \ + # Data types available\n # Write a file fo\ +r each output type\n for my $resultType (@resultT\ +ypes) {\n if ( $outputLevel > 1 ) {\n print S\ +TDERR 'Getting ', $resultType->{'identifier'}, \"\\ +\n\";\n }\n my $result = rest_get_result( $job\ +id, $resultType->{'identifier'} );\n if ( $param\ +s{'outfile'} eq '-' ) {\n write_file( $params{'\ +outfile'}, $result );\n }\n else {\n write_\ +file(\n $params{'outfile'} . '.'\n . $re\ +sultType->{'identifier'} . '.'\n . $resultTy\ +pe->{'fileSuffix'},\n $result\n );\n }\n \ + }\n }\n print_debug_message( 'get_results', 'End'\ +, 1 );\n}\n\n=head2 read_file()\n\nRead a file int\ +o a scalar. The special filename '-' can be used t\ +o read from \nstandard input (STDIN).\n\n my $dat\ +a = &read_file($filename);\n\n=cut\n\nsub read_fil\ +e {\n print_debug_message( 'read_file', 'Begin', 1\ + );\n my $filename = shift;\n print_debug_message(\ + 'read_file', 'filename: ' . $filename, 2 );\n my \ +( $content, $buffer );\n if ( $filename eq '-' ) {\ +\n while ( sysread( STDIN, $buffer, 1024 ) ) {\n \ + $content .= $buffer;\n }\n }\n else { # File\ +\n open( my $FILE, '<', $filename )\n or die \\ +"Error: unable to open input file $filename ($!)\"\ +;\n while ( sysread( $FILE, $buffer, 1024 ) ) {\n\ + $content .= $buffer;\n }\n close($FILE);\n }\\ +n print_debug_message( 'read_file', 'End', 1 );\n \ +return $content;\n}\n\n=head2 write_file()\n\nWrit\ +e data to a file. The special filename '-' can be \ +used to write to \nstandard output (STDOUT).\n\n \ +&write_file($filename, $data);\n\n=cut\n\nsub writ\ +e_file {\n print_debug_message( 'write_file', 'Beg\ +in', 1 );\n my ( $filename, $data ) = @_;\n print_\ +debug_message( 'write_file', 'filename: ' . $filen\ +ame, 2 );\n if ( $outputLevel > 0 ) {\n print STD\ +ERR 'Creating result file: ' . $filename . \"\\n\"\ +;\n }\n if ( $filename eq '-' ) {\n print STDOUT \ +$data;\n }\n else {\n open( my $FILE, '>', $filen\ +ame )\n or die \"Error: unable to open output f\ +ile $filename ($!)\";\n syswrite( $FILE, $data );\ +\n close($FILE);\n }\n print_debug_message( 'writ\ +e_file', 'End', 1 );\n}\n\n=head2 usage()\n\nPrint\ + program usage message.\n\n &usage();\n\n=cut\n\n\ +sub usage {\n print STDERR < [opti\ +ons...] seqFile\n Returns: results as an attachme\ +nt\n\nAsynchronous job:\n\n Use this if you want \ +to retrieve the results at a later time. The resul\ +ts \n are stored for up to 24 hours. \n Usage: \ +$scriptName --async --email [option\ +s...] seqFile\n Returns: jobid\n\n Use the jobid\ + to query for the status of the job. If the job is\ + finished, \n it also returns the results/errors.\ +\n Usage: $scriptName --polljob --jobid [\ +--outfile string]\n Returns: string indicating th\ +e status of the job and if applicable, results \n \ + as an attachment.\n\nFurther information:\n\n ht\ +tp://www.ebi.ac.uk/Tools/webservices/services/sss/\ +wu_blast_rest\n http://www.ebi.ac.uk/Tools/webser\ +vices/tutorials/perl\n\nSupport/Feedback:\n\n htt\ +p://www.ebi.ac.uk/support/\nEOF\n}\n\n=head1 FEEDB\ +ACK/SUPPORT\n\nPlease contact us at L if you have any \nfeedback, sug\ +gestions or issues with the service or this client\ +.\n\n=cut\n","\n\n\nmy $PROBTRESH = 0.3;# base pai\ +rs below this prob threshold will be ignored\nmy $\ +WEIGHT = 100.0; # float!!\nmy $NUCALPH = \"ACGTUNR\ +YMKSWHBVD\";\nuse vars qw($NUCALPH $WEIGHT);\n\nmy\ + $myname = basename($0);\n\nuse strict;\nuse warni\ +ngs;\n\nuse File::Basename;\nuse Getopt::Long;\nus\ +e File::Glob ':glob';\nuse File::Spec;\nuse File::\ +Temp qw/ tempfile tempdir /;\n\n\n\n\nsub tcoffeel\ +ib_header($;$)\n{\n my ($nseq, $fd) = @_;\n \ +if (! defined($fd)) {\n $fd = *STDOUT;\n \ + }\n printf $fd \"! TC_LIB_FORMAT_01\\n\";\n \ + printf $fd \"%d\\n\", $nseq;\n}\n\n\nsub tcoffeel\ +ib_header_addseq($$;$)\n{\n my ($id, $seq, $fd)\ + = @_;\n if (! defined($fd)) {\n $fd = *\ +STDOUT;\n }\n printf $fd \"%s %d %s\\n\", $i\ +d, length($seq), $seq;\n}\n\n\nsub tcoffeelib_comm\ +ent($;$)\n{\n my ($comment, $fd) = @_;\n if \ +(! defined($fd)) {\n $fd = *STDOUT;\n }\\ +n printf $fd \"!\" . $comment . \"\\n\";\n}\n\n\ +\nsub tcoffeelib_struct($$$;$)\n{\n my ($nseq, \ +$len, $bpm, $fd) = @_;\n\n if (! defined($fd)) \ +{\n $fd = *STDOUT;\n }\n\n # output b\ +asepair indices with fixed weight\n printf $fd \ +\"#%d %d\\n\", $nseq, $nseq;\n # output basepai\ +rs (only once) and with unit-offset\n for (my $\ +i=0; $i<$len; $i++) {\n for (my $j=$i+1; $j\ +<$len; $j++) {\n if (! defined($bpm->[$\ +i][$j])) {\n print STDERR \"ERROR: \ +\\$bpm->[$i][$j] undefined\\n\";\n }\n \ + if ($bpm->[$i][$j]>0) {\n \ + print $fd $i+1;\n print $fd \" \"\ +;\n print $fd $j+1;\n \ + print $fd \" \" . $bpm->[$i][$j] . \"\\n\";\n \ + }\n }\n }\n}\n\n\nsub tcoffeeli\ +b_footer(;$)\n{\n my ($fd) = @_;\n if (! def\ +ined($fd)) {\n $fd = *STDOUT;\n }\n p\ +rint $fd \"! SEQ_1_TO_N\\n\";\n}\n\n\n \nsub pl\ +fold($$$)\n{ \n my ($id, $seq, $probtresh) =\ + @_;\n my (@struct);# return\n my ($templ, $\ +fhtmp, $fnametmp, $cmd, $ctr, $window_size);\n \ +our $ntemp++;\n \n $templ = $myname . \".pid\ +-\" . $$ .$ntemp .\".XXXXXX\";\n ($fhtmp, $fnam\ +etmp) = tempfile($templ, UNLINK => 1); \n print\ + $fhtmp \">$id\\n$seq\\n\";\n\n # --- init base\ +pair array\n #\n for (my $i=0; $i/dev/null\";\n system($\ +cmd);\n \n if ($? != 0) {\n printf ST\ +DERR \"ERROR: RNAplfold ($cmd) exited with error s\ +tatus %d\\n\", $? >> 8;\n return;\n }\n \ + #unlink($fnametmp);\n my $fps = sprintf(\"%s\ +_dp.ps\", $id); # check long name\n \n if (!\ + -s $fps) {\n {\n\n $fps = sprintf(\"%s_dp.ps\ +\", substr($id,0,12)); # check short name\n if (!\ + -s $fps)\n {\n die(\"couldn't find expected\ + file $fps\\n\");\n return;\n }\n }\n \ + }\n\n \n # --- read base pairs from create\ +d postscript\n #\n open(FH, $fps);\n whil\ +e (my $line = ) {\n my ($nti, $ntj, $pr\ +ob);\n chomp($line); \n # lin\ +e: bp bp sqrt-prob ubox\n my @match = ($lin\ +e =~ m/^([0-9]+) +([0-9]+) +([0-9\\.]+) +ubox$/);\\ +n if (scalar(@match)) {\n $nti=$\ +1;\n $ntj=$2;\n $prob=$3*$3;\ +# prob stored as square root\n\n if ($p\ +rob>$probtresh) {\n #printf STDERR \ +\"\\$struct[$nti][$ntj] sqrtprob=$3 prob=$prob > $\ +probtresh\\n\";\n $struct[$nti-1][$\ +ntj-1] = $WEIGHT\n }\n # sto\ +re with zero-offset\n }\n }\n close(F\ +H);\n\n # remove or gzi postscript\n #\n \ +unlink($fps);\n #\n # or gzip\n #$cmd = \\ +"gzip -qf $fps\";\n #system($cmd);\n #if ($?\ + != 0) {\n # printf STDERR \"ERROR: gzip ($c\ +md) exited with error status %d\\n\", $? >> 8;\n \ + #}\n\n return \\@struct;\n}\n\n\n\n\n\nsub rn\ +aseqfmt($)\n{\n my ($seq) = @_;\n # remove g\ +aps\n $seq =~ s/-//g;\n # uppercase RNA\n \ + $seq = uc($seq);\n # T -> U\n $seq =~ s/T/U\ +/g;\n # check for invalid charaters\n $_ = $\ +seq;\n s/[^$NUCALPH]//g;\n return $_;\n}\n\n\ +\n\n\nsub usage(;$)\n{ \n my ($errmsg) = @_;\ +\n if ($errmsg) {\n print STDERR \"ERROR\ +: $errmsg\\n\";\n }\n print STDERR << \"EOF\\ +";\n$myname:\n Creates a T-Coffee RNA structure li\ +brary from RNAplfold prediction.\n See FIXME:citat\ +ion\nUsage:\n $myname -in seq_file -out tcoffee_li\ +b\nEOF\n exit(1);\n}\n\nsub read_fasta_seq \n \ +{\n my $f=$_[0];\n my %hseq;\n my (@seq, \ +@com, @name);\n my ($a, $s,$nseq);\n\n open \ +(F, $f);\n while ()\n {\n $s.=$_;\n \ + }\n close (F);\n\n \n @name=($s=~/>(\\S\ +*).*\\n[^>]*/g);\n \n @seq =($s=~/>.*.*\\n([\ +^>]*)/g);\n @com =($s=~/>(\\S*)(.*)\\n([^>]*)/g\ +);\n\n\n $nseq=$#name+1;\n \n for ($a=0; $a\ +<$nseq; $a++)\n {\n my $n=$name[$a];\n my $s;\ +\n $hseq{$n}{name}=$n;\n $s=$seq[$a];$s=~s/\\s//g;\ +\n \n $hseq{$n}{seq}=$s;\n $hseq{$n}{com}=$com[$a]\ +;\n }\n return %hseq;\n }\n\n\n\n\n\n\n\n\ +my $fmsq = \"\";\nmy $flib = \"\";\nmy %OPTS;\nmy \ +%seq;\nmy ($id, $nseq, $i);\nmy @nl;\n\nGetOptions\ +(\"in=s\" => \\$fmsq, \"out=s\" => \\$flib);\n\nif\ + (! -s $fmsq) {\n usage(\"empty or non-existant\ + file \\\"$fmsq\\\"\")\n}\nif (length($flib)==0) {\ +\n usage(\"empty out-filename\")\n}\n\n\n\n\n\n\ +\n%seq=read_fasta_seq($fmsq);\n\n\n@nl=keys(%seq);\ +\n\n$nseq=$#nl+1;\nopen FD_LIB, \">$flib\" or die \ +\"can't open $flib!\";\ntcoffeelib_header($nseq, *\ +FD_LIB);\nforeach $id (keys (%seq))\n {\n my (\ +$seq, $fmtseq);\n \n $seq = $seq{$id}{seq};\\ +n \n $fmtseq = rnaseqfmt($seq);# check here,\ + formatting for folding important later\n if (l\ +ength($seq)!=length($fmtseq)) {\n print STD\ +ERR \"ERROR: invalid sequence $id is not an RNA se\ +quence. read seq is: $seq\\n\";\n exit\n \ + }\n \n tcoffeelib_header_addseq($id, uc($s\ +eq), *FD_LIB);\n }\ntcoffeelib_comment(\"generate\ +d by $myname on \" . localtime(), *FD_LIB);\n\n\n\\ +n$i=0;\nforeach $id (keys (%seq))\n {\n my ($c\ +leanid, $seq, $bpm);\n $seq=$seq{$id}{seq};\n \ + $cleanid = $id;\n $cleanid =~ s,[/ ],_,g;# ne\ +eded for rnaplfold\n $seq = rnaseqfmt($seq);\n \ + \n $bpm = plfold($cleanid, rnaseqfmt($seq), \ +$PROBTRESH); \n \n tcoffeelib_struct($\ +i+1, length($seq), $bpm, *FD_LIB);\n $i++;\n}\n\ +\n\ntcoffeelib_footer(*FD_LIB);\nclose FD_LIB;\nex\ +it (0);\n\n","\n\n\n\n\n$cmd=join ' ', @ARGV;\nif \ +($cmd=~/-infile=(\\S+)/){ $seqfile=$1;}\nif ($cmd=\ +~/-outfile=(\\S+)/){ $libfile=$1;}\n\n\n\n%s=read_\ +fasta_seq ($seqfile);\n\nopen (F, \">$libfile\");\\ +nforeach $name (keys (%s))\n {\n my $tclib=\"$\ +name.RNAplfold_tclib\";\n print (F \">$name _F_\ + $tclib\\n\");\n seq2RNAplfold2tclib ($name, $s\ +{$name}{seq}, $tclib);\n }\nclose (F);\nexit (EXI\ +T_SUCCESS);\n\nsub seq2RNAplfold2tclib\n {\n m\ +y ($name, $seq, $tclib)=@_;\n my ($tmp);\n $\ +n++;\n $tmp=\"tmp4seq2RNAplfold_tclib.$$.$n.pep\ +\";\n open (RF, \">$tmp\");\n print (RF \">$\ +name\\n$seq\\n\");\n close (RF);\n \n sys\ +tem \"t_coffee -other_pg RNAplfold2tclib.pl -in=$t\ +mp -out=$tclib\";\n \n unlink ($tmp);\n r\ +eturn $tclib;\n }\n \n \nsub read_fasta_seq\ + \n {\n my $f=@_[0];\n my %hseq;\n my (@\ +seq, @com, @name);\n my ($a, $s,$nseq);\n\n \ +open (F, $f);\n while ()\n {\n $s.=$_;\\ +n }\n close (F);\n\n \n @name=($s=~/\ +>(\\S*).*\\n[^>]*/g);\n \n @seq =($s=~/>.*.*\ +\\n([^>]*)/g);\n @com =($s=~/>\\S*(.*)\\n([^>]*\ +)/g);\n\n \n $nseq=$#name+1;\n \n for \ +($a=0; $a<$nseq; $a++)\n {\n my $n=$name[$a];\ +\n $hseq{$n}{name}=$n;\n $hseq{$n}{seq}=$seq[$a];\\ +n $hseq{$n}{com}=$com[$a];\n }\n return %h\ +seq;\n }\n","use Getopt::Long;\nuse File::Path;\n\ +use Env;\nuse FileHandle;\nuse Cwd;\nuse Sys::Host\ +name;\nour $PIDCHILD;\nour $ERROR_DONE;\nour @TMPF\ +ILE_LIST;\nour $EXIT_FAILURE=1;\nour $EXIT_SUCCESS\ +=0;\n\nour $REFDIR=getcwd;\nour $EXIT_SUCCESS=0;\n\ +our $EXIT_FAILURE=1;\n\nour $PROGRAM=\"tc_generic_\ +method.pl\";\nour $CL=$PROGRAM;\n\nour $CLEAN_EXIT\ +_STARTED;\nour $debug_lock=$ENV{\"DEBUG_LOCK\"};\n\ +our $LOCKDIR=$ENV{\"LOCKDIR_4_TCOFFEE\"};\nif (!$L\ +OCKDIR){$LOCKDIR=getcwd();}\nour $ERRORDIR=$ENV{\"\ +ERRORDIR_4_TCOFFEE\"};\nour $ERRORFILE=$ENV{\"ERRO\ +RFILE_4_TCOFFEE\"};\n&set_lock ($$);\nif (isshellp\ +id(getppid())){lock4tc(getppid(), \"LLOCK\", \"LSE\ +T\", \"$$\\n\");}\n \nour $print;\nmy ($fmsq1\ +, $fmsq2, $output, $outfile, $arch, $psv, $hmmtop_\ +home, $trim, $cov, $sample, $mode, $gor_home, $gor\ +_seq, $gor_obs);\n\nGetOptions(\"-in=s\" => \\$fms\ +q1,\"-output=s\" =>\\$output ,\"-out=s\" => \\$out\ +file, \"-arch=s\" => \\$arch,\"-psv=s\" => \\$psv,\ + \"-hmmtop_home=s\", \\$hmmtop_home,\"-trim=s\" =>\ +\\$trim ,\"-print=s\" =>\\$print,\"-cov=s\" =>\\$c\ +ov , \"-sample=s\" =>\\$sample, \"-mode=s\" =>\\$m\ +ode, \"-gor_home=s\"=>\\$gor_home, \"-gor_seq=s\"=\ +>\\$gor_seq,\"-gor_obs=s\"=>\\$gor_obs);\n\n\nif (\ +!$mode){$mode = \"hmmtop\"}\nelsif ($mode eq \"hmm\ +top\"){;}\nelsif ($mode eq \"gor\"){;}\nelse {myex\ +it(flush_error (\"-mode=$mode is unknown\"));}\n\n\ +\nour $HOME=$ENV{\"HOME\"};\nour $MCOFFEE=($ENV{\"\ +MCOFFEE_4_TCOFFEE\"})?$ENV{\"MCOFFEE_4_TCOFFEE\"}:\ +\"$HOME/.t_coffee/mcoffee\";\n\nif ($mode eq \"hmm\ +top\")\n {\n check_configuration (\"hmmtop\");\ +\n if (-e $arch){$ENV{'HMMTOP_ARCH'}=$arch;}\n \ + elsif (-e $ENV{HMMTOP_ARCH}){$arch=$ENV{HMMTOP_\ +ARCH};}\n elsif (-e \"$MCOFFEE/hmmtop.arch\"){$\ +arch=$ENV{'HMMTOP_ARCH'}=\"$MCOFFEE/hmmtop.arch\";\ +}\n elsif (-e \"$hmmtop_home/hmmtop.arc\"){$arc\ +h=$ENV{'HMMTOP_ARCH'}=\"$hmmtop_home/hmmtop.arc\";\ +}\n else {myexit(flush_error ( \"Could not find\ + ARCH file for hmmtop\"));}\n \n \n if (-\ +e $psv){$ENV{'HMMTOP_PSV'}=$psv;}\n elsif (-e $\ +ENV{HMMTOP_PSV}){$psv=$ENV{HMMTOP_PSV};}\n elsi\ +f (-e \"$MCOFFEE/hmmtop.psv\"){$psv=$ENV{'HMMTOP_P\ +SV'}=\"$MCOFFEE/hmmtop.psv\";}\n elsif (-e \"$h\ +mmtop_home/hmmtop.psv\"){$psv=$ENV{'HMMTOP_PSV'}=\\ +"$hmmtop_home/hmmtop.psv\";}\n else {myexit(flu\ +sh_error ( \"Could not find PSV file for hmmtop\")\ +);}\n }\nelsif ($mode eq \"gor\")\n {\n our $\ +GOR_SEQ;\n our $GOR_OBS;\n \n check_confi\ +guration (\"gorIV\");\n if (-e $gor_seq){$GOR_S\ +EQ=$gor_seq;}\n elsif (-e $ENV{GOR_SEQ}){$GOR_S\ +EQ=$ENV{GOR_SEQ};}\n elsif (-e \"$MCOFFEE/New_K\ +S.267.seq\"){$GOR_SEQ=\"$MCOFFEE/New_KS.267.seq\";\ +}\n elsif (-e \"$gor_home/New_KS.267.seq\"){$GO\ +R_SEQ=\"$gor_home/New_KS.267.seq\";}\n else {my\ +exit(flush_error ( \"Could not find SEQ file for g\ +or\"));}\n\n if (-e $gor_obs){$GOR_OBS=$gor_obs\ +;}\n elsif (-e $ENV{GOR_OBS}){$GOR_OBS=$ENV{GOR\ +_OBS};}\n elsif (-e \"$MCOFFEE/New_KS.267.obs\"\ +){$GOR_OBS=\"$MCOFFEE/New_KS.267.obs\";}\n elsi\ +f (-e \"$gor_home/New_KS.267.obs\"){$GOR_OBS=\"$go\ +r_home/New_KS.267.obs\";}\n else {myexit(flush_\ +error ( \"Could not find OBS file for gor\"));}\n \ + }\n\n\nif ( ! -e $fmsq1){myexit(flush_error (\"Co\ +uld Not Read Input file $fmsq1\"));}\n\n\nmy $fmsq\ +2=vtmpnam();\nmy $fmsq3=vtmpnam();\nmy $tmpfile=vt\ +mpnam();\nmy $predfile=vtmpnam();\n\nif ($trim){$t\ +rim_action=\" +trim _aln_%%$trim\\_K1 \";}\nif ($c\ +ov) {$cov_action= \" +sim_filter _aln_c$cov \";}\n\ +&safe_system(\"t_coffee -other_pg seq_reformat -in\ + $fmsq1 -action +convert 'BOUJXZ-' $cov_action $tr\ +im_action -output fasta_aln -out $fmsq2\");\nmy (%\ +pred, %seq, %predA);\n\n\n%seq=read_fasta_seq($fms\ +q2);\n%seq=fasta2sample(\\%seq, $sample);\n\nif (1\ +==2 && $mode eq \"hmmtop\" && $output eq \"cons\")\ +\n {\n fasta2hmmtop_cons($outfile,\\%seq);\n \ +}\nelse\n {\n %pred=fasta2pred(\\%seq, $mode);\ +\n %predA=pred2aln (\\%pred, \\%seq);\n \n \ + \n if (!$output || $output eq \"prediction\")\ +{output_fasta_seq (\\%predA, $outfile);}\n elsi\ +f ($output eq \"color_html\"){pred2color (\\%pred,\ +\\%seq, $outfile);}\n elsif ($output eq \"cons\\ +"){pred2cons($outfile,\\%predA);}\n else {flush\ +_error (\"$output is an unknown output mode\");}\n\ + }\n\nsub fasta2sample\n {\n my $SR=shift;\n \ + my $it=shift;\n my %S=%$SR;\n \n my $s\ +eq=index2seq_name (\\%S, 1);\n my $l=length($S{\ +$seq}{seq});\n my @sl=keys(%S);\n my $nseq=$\ +#sl+1;\n my $index=$nseq;\n \n if (!$sample\ +) {return %S;}\n for (my $a=0; $a<$it; $a++)\n \ + {\n my $newseq=\"\";\n my $nname=\"$seq\\_sam\ +pled_$index\";\n for (my $p=0; $p<$l; $p++)\n {\\ +n my $i=int(rand($nseq));\n \n my $nam\ +e = $sl[$i];\n my $seq=$S{$name}{seq};\n m\ +y $r=substr ($seq, $p, 1);\n $newseq.=$r;\n \ +}\n $S{$nname}{name}=$nname;\n $S{$nname}{seq}=$ne\ +wseq;\n $S{$nname}{com}=\"sampled\";\n $S{$nname}{\ +index}=++$index;\n }\n return %S;\n }\n \ + \nsub fasta2pred\n {\n my $s=shift;\n \ +my $mode=shift;\n\n if ( $mode eq \"hmmtop\"){r\ +eturn fasta2hmmtop_pred($s);}\n elsif ($mode eq\ + \"gor\"){return fasta2gor_pred ($s);}\n }\nsub f\ +asta2hmmtop_cons\n {\n my $outfile=shift;\n \ + my $SR=shift;\n \n my $o = new FileHandle;\\ +n my $i = new FileHandle;\n my $tmp_in =vtmp\ +nam();\n my $tmp_out=vtmpnam();\n my %seq=%$\ +SR;\n my %pred;\n my $N=keys(%seq);\n \n \ + output_fasta_seq (\\%seq,$tmp_in, \"seq\");\n \ + `hmmtop -pi=mpred -if=$tmp_in -sf=FAS -pl 2>/dev\ +/null >$tmp_out`;\n open ($o, \">$outfile\");\n\ + open ($i, \"$tmp_out\");\n while (<$i>)\n \ + {\n my $l=$_;\n if (($l=~/>HP\\:\\s+(\\d+)\\s+\ +(.*)/)){my $line=\">$2 NSEQ: $N\\n\";print $o \"$l\ +ine\";}\n elsif ( ($l=~/.*pred(.*)/)) {my $line=\\ +"$1\\n\";print $o \"$line\";}\n }\n close \ +($o);\n close ($i);\n return read_fasta_seq(\ +$tmp);\n }\nsub fasta2hmmtop_pred\n {\n my $S\ +R=shift;\n my $o = new FileHandle;\n my $i =\ + new FileHandle;\n my $tmp =vtmpnam();\n \ +my $tmp_in =vtmpnam();\n my $tmp_out=vtmpnam();\ +\n my %seq=%$SR;\n my %pred;\n \n\n ou\ +tput_fasta_seq (\\%seq,$tmp_in, \"seq\");\n `hm\ +mtop -if=$tmp_in -sf=FAS -pl 2>/dev/null >$tmp_out\ +`;\n open ($o, \">$tmp\");\n open ($i, \"$tm\ +p_out\");\n while (<$i>)\n {\n my $l=$_;\n\ + if (($l=~/>HP\\:\\s+(\\d+)\\s+(.*)/)){my $line=\"\ +>$2\\n\";print $o \"$line\";}\n elsif ( ($l=~/.*pr\ +ed(.*)/)) {my $line=\"$1\\n\";print $o \"$line\";\ +}\n }\n close ($o);\n close ($i);\n \ +return read_fasta_seq($tmp);\n }\n \n \n \n \ + \n \n \n\n \nsub fasta2gor_pred\n {\n my $SR\ +=shift;\n my $o = new FileHandle;\n my $i = \ +new FileHandle;\n my $tmp =vtmpnam();\n m\ +y $tmp_in =vtmpnam();\n my $tmp_out=vtmpnam();\\ +n my %seq=%$SR;\n my %pred;\n \n\n out\ +put_fasta_seq (\\%seq,$tmp_in, \"seq\");\n `gor\ +IV -prd $tmp_in -seq $GOR_SEQ -obs $GOR_OBS >$tmp_\ +out`;\n open ($o, \">$tmp\");\n open ($i, \"\ +$tmp_out\");\n while (<$i>)\n {\n my $l=$_\ +;\n\n \n if ( $l=~/>/){print $o \"$l\";}\n elsif (\ + $l=~/Predicted Sec. Struct./){$l=~s/Predicted Sec\ +. Struct\\.//;print $o \"$l\";}\n }\n clos\ +e ($o);\n close ($i);\n return read_fasta_se\ +q($tmp);\n }\n \n \nsub index2seq_name\n\ + {\n \n my $SR=shift;\n my $index=shift;\ +\n \n \n my %S=%$SR;\n \n foreach m\ +y $s (%S)\n {\n if ( $S{$s}{index}==$index){r\ +eturn $s;}\n }\n return \"\";\n }\n\nsub \ +pred2cons\n {\n my $outfile=shift;\n my $pr\ +edR=shift;\n my $seq=shift;\n my %P=%$predR;\ +\n my %C;\n my ($s,@r,$nseq);\n my $f= ne\ +w FileHandle;\n\n open ($f, \">$outfile\");\n\n\ + if (!$seq){$seq=index2seq_name(\\%P,1);}\n \ +foreach my $s (keys(%P))\n {\n $nseq++;\n $st\ +ring= $P{$s}{seq};\n $string = uc $string;\n my @r\ +=split (//,$string);\n for (my $a=0; $a<=$#r; $a++\ +)\n {\n if (($r[$a]=~/[OHICE]/)){$C{$a}{$r[$\ +a]}++;}\n }\n }\n @l=keys(%C);\n \n \ + \n $s=$P{$seq}{seq};\n print $f \">$seq pr\ +ed based on $nseq\\n\";\n @r=split (//,$s);\n \ + \n for (my $x=0; $x<=$#r; $x++)\n {\n if\ + ($r[$x] ne \"-\")\n {\n my $h=$C{$x}{H};\n \ + my $i=$C{$x}{I};\n my $o=$C{$x}{O};\n \ +my $c=$C{$x}{C};\n my $e=$C{$x}{E};\n my $\ +l=$i+$o;\n \n if ($h>=$i && $h>=$o && $h>=\ +$c && $h>=$e){$r[$x]='H';}\n elsif ($i>=$o && \ +$i>=$c && $i>=$e){$r[$x]='I';}\n elsif ($o>=$c\ + && $o>=$e){$r[$x]='O';}\n elsif ($c>=$e){$r[$\ +x]='C';}\n else {$r[$x]='E';}\n }\n }\n\ + $j=join ('', @r);\n print $f \"$j\\n\";\n \ + close ($f);\n return $j;\n }\n\nsub pred2aln\ +\n {\n my $PR=shift;\n my $AR=shift;\n \\ +n my $f=new FileHandle;\n my %P=%$PR;\n m\ +y %A=%$AR;\n my %PA;\n my $tmp=vtmpnam();\n \ + my $f= new FileHandle;\n \n open ($f, \">\ +$tmp\");\n foreach my $s (sort{$A{$a}{index}<=>\ +$A{$b}{index}}(keys (%A)))\n {\n my (@list, $\ +seq, @plist, @pseq, $L, $PL, $c, $w);\n my $seq;\n\ + my $seq=$A{$s}{seq};\n my $pred=$P{$s}{seq};\n $s\ +eq=pred2alnS($P{$s}{seq},$A{$s}{seq});\n print $f \ +\">$s\\n$seq\\n\";\n }\n close ($f);\n \ +return read_fasta_seq ($tmp);\n }\nsub pred2alnS\\ +n {\n my $pred=shift;\n my $aln= shift;\n \ + my ($j,$a,$b);\n my @P=split (//, $pred);\n \ + my @A=split (//, $aln);\n for ($a=$b=0;$a<=$#\ +A; $a++)\n {\n if ($A[$a] ne \"-\"){$A[$a]=$P\ +[$b++];}\n }\n if ($b!= ($#P+1)){add_warni\ +ng (\"Could not thread sequence: $b $#P\");}\n \ +\n $j= join ('', @A);\n return $j;\n }\nsub\ + pred2color\n {\n my $predP=shift;\n my $al\ +nP=shift;\n my $out=shift;\n my $F=new FileH\ +andle;\n my $struc=vtmpnam();\n my $aln=vtmp\ +nam();\n \n\n output_fasta_seq ($alnP, $aln)\ +;\n my %p=%$predP;\n \n open ($F, \">$str\ +uc\");\n \n \n foreach my $s (keys(%p))\n\ + {\n \n print $F \">$s\\n\";\n my $s=uc($p{$s\ +}{seq});\n \n $s=~s/[Oo]/0/g;\n $s=~s/[Ee]/0/g;\n \ +\n $s=~s/[Ii]/5/g;\n $s=~s/[Cc]/5/g;\n \n $s=~s/[H\ +h]/9/g;\n \n print $F \"$s\\n\";\n }\n clo\ +se ($F);\n \n \n \n safe_system ( \"t_\ +coffee -other_pg seq_reformat -in $aln -struc_in $\ +struc -struc_in_f number_fasta -output color_html \ +-out $out\");\n return;\n }\n \n \nsub di\ +splay_fasta_seq\n {\n my $SR=shift;\n my %S\ +=%$SR;\n \n foreach my $s (sort{$S{$a}{index\ +}<=>$S{$b}{index}}(keys (%S)))\n {\n print ST\ +DERR \">$s\\n$S{$s}{seq}\\n\";\n }\n close\ + ($f);\n }\nsub output_fasta_seq\n {\n my $SR\ +=shift;\n my $outfile=shift;\n my $mode =shi\ +ft;\n my $f= new FileHandle;\n my %S=%$SR;\n\ + \n \n open ($f, \">$outfile\");\n for\ +each my $s (sort{$S{$a}{index}<=>$S{$b}{index}}(ke\ +ys (%S)))\n {\n my $seq=$S{$s}{seq};\n if ( $\ +mode eq \"seq\"){$seq=~s/\\-//g;}\n print $f \">$s\ +\\n$seq\\n\";\n }\n close ($f);\n }\n \ + \nsub read_fasta_seq \n {\n my $f=$_[0];\n \ + my %hseq;\n my (@seq, @com, @name);\n my (\ +$a, $s,$nseq);\n my $index;\n open (F, $f);\\ +n while ()\n {\n $s.=$_;\n }\n \ +close (F);\n\n \n @name=($s=~/>(\\S*).*\\n[^\ +>]*/g);\n \n @seq =($s=~/>.*.*\\n([^>]*)/g);\ +\n @com =($s=~/>.*(.*)\\n([^>]*)/g);\n\n\n $\ +nseq=$#name+1;\n \n \n for ($a=0; $a<$nseq;\ + $a++)\n {\n my $n=$name[$a];\n my $s;\n $hse\ +q{$n}{name}=$n;\n $s=$seq[$a];$s=~s/\\s//g;\n $hse\ +q{$n}{index}=++$index;\n $hseq{$n}{seq}=$s;\n $hse\ +q{$n}{com}=$com[$a];\n }\n return %hseq;\n\ + }\n\n\nsub file2head\n {\n my $file = shift\ +;\n my $size = shift;\n my $f= new FileHandle;\n m\ +y $line;\n open ($f,$file);\n read ($f,$line, $siz\ +e);\n close ($f);\n return $line;\n }\nsub fi\ +le2tail\n {\n my $file = shift;\n my $size = \ +shift;\n my $f= new FileHandle;\n my $line;\n \n o\ +pen ($f,$file);\n seek ($f,$size*-1, 2);\n read ($\ +f,$line, $size);\n close ($f);\n return $line;\n \ + }\n\n\nsub vtmpnam\n {\n my $r=rand(10000\ +0);\n my $f=\"file.$r.$$\";\n while (-e $f)\n {\\ +n $f=vtmpnam();\n }\n push (@TMPFILE_LIST, $\ +f);\n return $f;\n }\n\nsub myexit\n {\n \ +my $code=@_[0];\n if ($CLEAN_EXIT_STARTED==1){r\ +eturn;}\n else {$CLEAN_EXIT_STARTED=1;}\n ##\ +# ONLY BARE EXIT\n exit ($code);\n }\nsub set_\ +error_lock\n {\n my $name = shift;\n \ +my $pid=$$;\n\n \n &lock4tc ($$,\"LERROR\ +\", \"LSET\", \"$$ -- ERROR: $name $PROGRAM\\n\");\ +\n return;\n }\nsub set_lock\n {\n my \ +$pid=shift;\n my $msg= shift;\n my $p=getppi\ +d();\n &lock4tc ($pid,\"LLOCK\",\"LRESET\",\"$p\ +$msg\\n\");\n }\nsub unset_lock\n {\n \n \ + my $pid=shift;\n &lock4tc ($pid,\"LLOCK\",\"LR\ +ELEASE\",\"\");\n }\nsub shift_lock\n {\n my \ +$from=shift;\n my $to=shift;\n my $from_type\ +=shift;\n my $to_type=shift;\n my $action=sh\ +ift;\n my $msg;\n \n if (!&lock4tc($from,\ + $from_type, \"LCHECK\", \"\")){return 0;}\n $m\ +sg=&lock4tc ($from, $from_type, \"LREAD\", \"\");\\ +n &lock4tc ($from, $from_type,\"LRELEASE\", $ms\ +g);\n &lock4tc ($to, $to_type, $action, $msg);\\ +n return;\n }\nsub isshellpid\n {\n my $p=\ +shift;\n if (!lock4tc ($p, \"LLOCK\", \"LCHECK\\ +")){return 0;}\n else\n {\n my $c=lock4tc(\ +$p, \"LLOCK\", \"LREAD\");\n if ( $c=~/-SHELL-/){r\ +eturn 1;}\n }\n return 0;\n }\nsub isroot\ +pid\n {\n if(lock4tc (getppid(), \"LLOCK\", \"\ +LCHECK\")){return 0;}\n else {return 1;}\n }\n\ +sub lock4tc\n {\n my ($pid,$type,$action,$value)\ +=@_;\n my $fname;\n my $host=hostname;\n \n \ + if ($type eq \"LLOCK\"){$fname=\"$LOCKDIR/.$pid.\ +$host.lock4tcoffee\";}\n elsif ( $type eq \"LERR\ +OR\"){ $fname=\"$LOCKDIR/.$pid.$host.error4tcoffee\ +\";}\n elsif ( $type eq \"LWARNING\"){ $fname=\"\ +$LOCKDIR/.$pid.$host.warning4tcoffee\";}\n \n \ +if ($debug_lock)\n {\n print STDERR \"\\\ +n\\t---lock4tc(tcg): $action => $fname =>$value (R\ +D: $LOCKDIR)\\n\";\n }\n\n if ($action eq\ + \"LCHECK\") {return -e $fname;}\n elsif ($actio\ +n eq \"LREAD\"){return file2string($fname);}\n e\ +lsif ($action eq \"LSET\") {return string2file ($v\ +alue, $fname, \">>\");}\n elsif ($action eq \"LR\ +ESET\") {return string2file ($value, $fname, \">\"\ +);}\n elsif ($action eq \"LRELEASE\") \n {\n\ + if ( $debug_lock)\n {\n my $g=new FileH\ +andle;\n open ($g, \">>$fname\");\n print $g\ + \"\\nDestroyed by $$\\n\";\n close ($g);\n \ +safe_system (\"mv $fname $fname.old\");\n }\n \ + else\n {\n unlink ($fname);\n }\n }\n \ + return \"\";\n }\n \nsub file2string\n {\n my \ +$file=@_[0];\n my $f=new FileHandle;\n my $r;\\ +n open ($f, \"$file\");\n while (<$f>){$r.=$_;\ +}\n close ($f);\n return $r;\n }\nsub string2f\ +ile \n {\n my ($s,$file,$mode)=@_;\n my $\ +f=new FileHandle;\n \n open ($f, \"$mode$fil\ +e\");\n print $f \"$s\";\n close ($f);\n }\ +\n\nBEGIN\n {\n srand;\n \n $SIG{'\ +SIGUP'}='signal_cleanup';\n $SIG{'SIGINT'}='s\ +ignal_cleanup';\n $SIG{'SIGQUIT'}='signal_cle\ +anup';\n $SIG{'SIGILL'}='signal_cleanup';\n \ + $SIG{'SIGTRAP'}='signal_cleanup';\n $SIG{\ +'SIGABRT'}='signal_cleanup';\n $SIG{'SIGEMT'}\ +='signal_cleanup';\n $SIG{'SIGFPE'}='signal_c\ +leanup';\n \n $SIG{'SIGKILL'}='signal_cl\ +eanup';\n $SIG{'SIGPIPE'}='signal_cleanup';\n\ + $SIG{'SIGSTOP'}='signal_cleanup';\n $SI\ +G{'SIGTTIN'}='signal_cleanup';\n $SIG{'SIGXFS\ +Z'}='signal_cleanup';\n $SIG{'SIGINFO'}='sign\ +al_cleanup';\n \n $SIG{'SIGBUS'}='signal\ +_cleanup';\n $SIG{'SIGALRM'}='signal_cleanup'\ +;\n $SIG{'SIGTSTP'}='signal_cleanup';\n \ +$SIG{'SIGTTOU'}='signal_cleanup';\n $SIG{'SIG\ +VTALRM'}='signal_cleanup';\n $SIG{'SIGUSR1'}=\ +'signal_cleanup';\n\n\n $SIG{'SIGSEGV'}='sign\ +al_cleanup';\n $SIG{'SIGTERM'}='signal_cleanu\ +p';\n $SIG{'SIGCONT'}='signal_cleanup';\n \ + $SIG{'SIGIO'}='signal_cleanup';\n $SIG{'SIG\ +PROF'}='signal_cleanup';\n $SIG{'SIGUSR2'}='s\ +ignal_cleanup';\n\n $SIG{'SIGSYS'}='signal_cl\ +eanup';\n $SIG{'SIGURG'}='signal_cleanup';\n \ + $SIG{'SIGCHLD'}='signal_cleanup';\n $SIG\ +{'SIGXCPU'}='signal_cleanup';\n $SIG{'SIGWINC\ +H'}='signal_cleanup';\n \n $SIG{'INT'}='\ +signal_cleanup';\n $SIG{'TERM'}='signal_clean\ +up';\n $SIG{'KILL'}='signal_cleanup';\n \ +$SIG{'QUIT'}='signal_cleanup';\n \n our \ +$debug_lock=$ENV{\"DEBUG_LOCK\"};\n \n \\ +n \n \n foreach my $a (@ARGV){$CL.=\ +\" $a\";}\n if ( $debug_lock ){print STDERR \\ +"\\n\\n\\n********** START PG: $PROGRAM **********\ +***\\n\";}\n if ( $debug_lock ){print STDERR \ +\"\\n\\n\\n**********(tcg) LOCKDIR: $LOCKDIR $$ **\ +***********\\n\";}\n if ( $debug_lock ){print\ + STDERR \"\\n --- $$ -- $CL\\n\";}\n \n \ +\n \n \n }\nsub flush_error\n {\n \ + my $msg=shift;\n return add_error ($EXIT_FAILU\ +RE,$$, $$,getppid(), $msg, $CL);\n }\nsub add_err\ +or \n {\n my $code=shift;\n my $rpid=shift;\ +\n my $pid=shift;\n my $ppid=shift;\n my \ +$type=shift;\n my $com=shift;\n \n $ERROR\ +_DONE=1;\n lock4tc ($rpid, \"LERROR\",\"LSET\",\ +\"$pid -- ERROR: $type\\n\");\n lock4tc ($$, \"\ +LERROR\",\"LSET\", \"$pid -- COM: $com\\n\");\n \ + lock4tc ($$, \"LERROR\",\"LSET\", \"$pid -- STACK\ +: $ppid -> $pid\\n\");\n \n return $code;\n \ +}\nsub add_warning \n {\n my $rpid=shift;\n \ + my $pid =shift;\n my $command=shift;\n my $\ +msg=\"$$ -- WARNING: $command\\n\";\n print STD\ +ERR \"$msg\";\n lock4tc ($$, \"LWARNING\", \"LS\ +ET\", $msg);\n }\n\nsub signal_cleanup\n {\n \ +print dtderr \"\\n**** $$ (tcg) was killed\\n\";\n\ + &cleanup;\n exit ($EXIT_FAILURE);\n }\nsub\ + clean_dir\n {\n my $dir=@_[0];\n if ( !-d \ +$dir){return ;}\n elsif (!($dir=~/tmp/)){return\ + ;}#safety check 1\n elsif (($dir=~/\\*/)){retu\ +rn ;}#safety check 2\n else\n {\n `rm -rf \ +$dir`;\n }\n return;\n }\nsub cleanup\n \ +{\n #print stderr \"\\n----tc: $$ Kills $PIDCHI\ +LD\\n\";\n #kill (SIGTERM,$PIDCHILD);\n my $\ +p=getppid();\n $CLEAN_EXIT_STARTED=1;\n \n \ + \n \n if (&lock4tc($$,\"LERROR\", \"LCHECK\ +\", \"\"))\n {\n my $ppid=getppid();\n if (!$\ +ERROR_DONE) \n {\n &lock4tc($$,\"LERROR\", \\ +"LSET\", \"$$ -- STACK: $p -> $$\\n\");\n &loc\ +k4tc($$,\"LERROR\", \"LSET\", \"$$ -- COM: $CL\\n\\ +");\n }\n }\n my $warning=&lock4tc($$, \\ +"LWARNING\", \"LREAD\", \"\");\n my $error=&loc\ +k4tc($$, \"LERROR\", \"LREAD\", \"\");\n #rele\ +ase error and warning lock if root\n \n if (\ +isrootpid() && ($warning || $error) )\n {\n \\ +n print STDERR \"**************** Summary ********\ +*****\\n$error\\n$warning\\n\";\n\n &lock4tc($$,\"\ +LERROR\",\"RELEASE\",\"\");\n &lock4tc($$,\"LWARNI\ +NG\",\"RELEASE\",\"\");\n } \n \n \n \ + foreach my $f (@TMPFILE_LIST)\n {\n if (-e $\ +f){unlink ($f);} \n }\n foreach my $d (@TM\ +PDIR_LIST)\n {\n clean_dir ($d);\n }\n \ + #No More Lock Release\n #&lock4tc($$,\"LLOCK\\ +",\"LRELEASE\",\"\"); #release lock \n\n if ( $\ +debug_lock ){print STDERR \"\\n\\n\\n********** EN\ +D PG: $PROGRAM ($$) *************\\n\";}\n if (\ + $debug_lock ){print STDERR \"\\n\\n\\n**********(\ +tcg) LOCKDIR: $LOCKDIR $$ *************\\n\";}\n \ +}\nEND \n {\n \n &cleanup();\n }\n \n\ns\ +ub safe_system \n{\n my $com=shift;\n my $ntry=s\ +hift;\n my $ctry=shift;\n my $pid;\n my $status\ +;\n my $ppid=getppid();\n if ($com eq \"\"){retu\ +rn 1;}\n \n \n\n if (($pid = fork ()) < 0){retu\ +rn (-1);}\n if ($pid == 0)\n {\n set_lock\ +($$, \" -SHELL- $com (tcg)\");\n exec ($com);\ +\n }\n else\n {\n lock4tc ($$, \"LLOCK\ +\", \"LSET\", \"$pid\\n\");#update parent\n $\ +PIDCHILD=$pid;\n }\n if ($debug_lock){printf S\ +TDERR \"\\n\\t .... safe_system (fasta_seq2hmm) p\ +: $$ c: $pid COM: $com\\n\";}\n\n waitpid ($pid,W\ +TERMSIG);\n\n shift_lock ($pid,$$, \"LWARNING\",\\ +"LWARNING\", \"LSET\");\n\n if ($? == $EXIT_FAILU\ +RE || lock4tc($pid, \"LERROR\", \"LCHECK\", \"\"))\ +\n {\n if ($ntry && $ctry <$ntry)\n {\n \ +add_warning ($$,$$,\"$com failed [retry: $ctry]\")\ +;\n lock4tc ($pid, \"LRELEASE\", \"LERROR\", \"\\ +");\n return safe_system ($com, $ntry, ++$ctry);\ +\n }\n elsif ($ntry == -1)\n {\n if (!shift\ +_lock ($pid, $$, \"LERROR\", \"LWARNING\", \"LSET\\ +"))\n {\n add_warning ($$,$$,\"$com fail\ +ed\");\n }\n else\n {\n lock4tc ($\ +pid, \"LRELEASE\", \"LERROR\", \"\");\n }\n \ +return $?;}\n else\n {\n if (!shift_lock ($\ +pid,$$, \"LERROR\",\"LERROR\", \"LSET\"))\n {\\ +n myexit(add_error ($EXIT_FAILURE,$$,$pid,ge\ +tppid(), \"UNSPECIFIED system\", $com));\n }\n\ + }\n }\n return $?;\n}\n\nsub check_configurat\ +ion \n {\n my @l=@_;\n my $v;\n \ +foreach my $p (@l)\n {\n \n if ( $p eq \"EMA\ +IL\")\n { \n if ( !($EMAIL=~/@/))\n {\n\ + add_warning($$,$$,\"Could Not Use EMAIL\");\n m\ +yexit(add_error ($EXIT_FAILURE,$$,$$,getppid(),\"E\ +MAIL\",\"$CL\"));\n }\n }\n elsif( $p \ +eq \"INTERNET\")\n {\n if ( !&check_inte\ +rnet_connection())\n {\n myexit(add_error ($EX\ +IT_FAILURE,$$,$$,getppid(),\"INTERNET\",\"$CL\"));\ +\n }\n }\n elsif( $p eq \"wget\")\n {\n\ + if (!&pg_is_installed (\"wget\") && !&pg_is\ +_installed (\"curl\"))\n {\n myexit(add_error \ +($EXIT_FAILURE,$$,$$,getppid(),\"PG_NOT_INSTALLED:\ +wget\",\"$CL\"));\n }\n }\n elsif( !(&pg_is\ +_installed ($p)))\n {\n myexit(add_error\ + ($EXIT_FAILURE,$$,$$,getppid(),\"PG_NOT_INSTALLED\ +:$p\",\"$CL\"));\n }\n }\n return 1;\n \ + }\nsub pg_is_installed\n {\n my @ml=@_;\n \ +my $r, $p, $m;\n my $supported=0;\n \n my\ + $p=shift (@ml);\n if ($p=~/::/)\n {\n if \ +(safe_system (\"perl -M$p -e 1\")==$EXIT_SUCCESS){\ +return 1;}\n else {return 0;}\n }\n else\n\ + {\n $r=`which $p 2>/dev/null`;\n if ($r eq \\ +"\"){return 0;}\n else {return 1;}\n }\n }\n\ +\n\n\nsub check_internet_connection\n {\n my $\ +internet;\n my $tmp;\n &check_configuration \ +( \"wget\"); \n \n $tmp=&vtmpnam ();\n \n\ + if (&pg_is_installed (\"wget\")){`wget \ +www.google.com -O$tmp >/dev/null 2>/dev/null`;}\n \ + elsif (&pg_is_installed (\"curl\")){`curl w\ +ww.google.com -o$tmp >/dev/null 2>/dev/null`;}\n \ + \n if ( !-e $tmp || -s $tmp < 10){$internet=0\ +;}\n else {$internet=1;}\n if (-e $tmp){unli\ +nk $tmp;}\n\n return $internet;\n }\nsub check\ +_pg_is_installed\n {\n my @ml=@_;\n my $r=&\ +pg_is_installed (@ml);\n if (!$r && $p=~/::/)\n\ + {\n print STDERR \"\\nYou Must Install the p\ +erl package $p on your system.\\nRUN:\\n\\tsudo pe\ +rl -MCPAN -e 'install $pg'\\n\";\n }\n els\ +if (!$r)\n {\n myexit(flush_error(\"\\nProgra\ +m $p Supported but Not Installed on your system\")\ +);\n }\n else\n {\n return 1;\n \ +}\n }\n\n\n\n","\n\n\n\n\nmy $FMODEL =\"\"; \nmy \ +$TMPDIR = \"/tmp\";\n\n\n\n\nmy $NUCALPH = \"ACGTU\ +NRYMKSWHBVD\";\nmy $PRIMNUCALPH = \"ACGTUN\";\nuse\ + vars qw($NUCALPH $PRIMNUCALPH $TMPDIR);\n\n\nmy $\ +errmsg;\nuse vars qw($errmsg);\n\n\n\nuse Getopt::\ +Long;\nuse Cwd;\nuse File::Basename;\nuse File::Te\ +mp qw/ tempfile tempdir /;\nuse File::Copy;\nuse F\ +ile::Path;\n\n\n\nsub usage(;$)\n{\n my ($errms\ +g) = @_;\n my $myname = basename($0);\n\n if\ + ($errmsg) {\n print STDERR \"ERROR: $errms\ +g\\n\";\n }\n\n print STDERR << \"EOF\";\n \ + \n$myname: align two sequences by means of consa\ +n\\'s sfold\nUsage:\n $myname -i file -o file -d p\ +ath\nOptions:\n -i|--in : pairwise input sequence \ +file\n -o|--out: output alignment\n -d|--directory\ + containing data\n\nEOF\n}\n\nsub read_stk_aln \n \ + {\n my $f=$_[0];\n my ($seq, $id);\n \n \ + my %hseq;\n\n open (STK, \"$f\");\n while\ + ()\n {\n if ( /^#/ || /^\\/\\// || /^\\\ +s*$/){;}\n else\n {\n ($id,$seq)=/(\\S+)\\s+\ +(\\S+)/;\n $hseq{$id}{'seq'}.=$seq;\n }\n \ + }\n close (STK);\n return %hseq;\n }\nsu\ +b read_fasta_seq \n {\n my $f=$_[0];\n my %\ +hseq;\n my (@seq, @com, @name);\n my ($a, $s\ +,$nseq);\n\n open (F, $f);\n while ()\n \ + {\n $s.=$_;\n }\n close (F);\n\n \n\ + @name=($s=~/>(.*).*\\n[^>]*/g);\n \n @se\ +q =($s=~/>.*.*\\n([^>]*)/g);\n @com =($s=~/>.*(\ +.*)\\n([^>]*)/g);\n\n \n $nseq=$#name+1;\n \ + \n for ($a=0; $a<$nseq; $a++)\n {\n my $\ +n=$name[$a];\n $hseq{$n}{name}=$n;\n $hseq{$n}{seq\ +}=$seq[$a];\n $hseq{$n}{com}=$com[$a];\n }\n \ + return %hseq;\n }\n\n\n\nsub sfold_parseoutput\ +($$)\n{\n my ($frawout, $foutfa) = @_;\n my \ +%haln;\n my ($fstk, $cmd, $id);\n open FOUTF\ +A, \">$foutfa\";\n \n $fstk = $frawout . \".\ +stk\";\n \n # first line of raw out contains\ + info\n # remaining stuff is stockholm formatte\ +d\n $cmd = \"sed -e '1d' $frawout\";\n syste\ +m(\"$cmd > $fstk\");\n if ($? != 0) {\n \ +$errmsg = \"command failed with exit status $?.\";\ +\n $errmsg .= \"Command was \\\"$cmd\\\"\"\ +;\n return -1;\n }\n\n # this gives a\ +n error message. just ignore it...\n %haln=read\ +_stk_aln ( $fstk);\n foreach $i (keys (%haln))\\ +n {\n my $s;\n $s=$haln{$i}{'seq'};\n $s =~ s\ +/\\./-/g;\n print FOUTFA \">$i\\n$s\\n\";\n }\ +\n close FOUTFA;\n return 0;\n}\n\n\n\n\nsub\ + sfold_wrapper($$$$)\n{\n \n my ($fs1, $fs2,\ + $fmodel, $foutfa) = @_;\n \n\n my ($cmd, $f\ +rawout, $ferrlog, $freadme, $ftimelog, $fstk);\n\n\ + # add basename($fmsqin) (unknown here!)\n \ +$frawout = \"sfold.log\";\n $ferrlog = \"sfold.\ +err\";\n $ftimelog = \"sfold.time\";\n $frea\ +dme = \"sfold.README\";\n $fstk = \"sfold.stk\\ +";\n \n # prepare execution...\n #\n #\ + ./tmp is essential for dswpalign\n # otherwise\ + you'll get a segfault\n mkdir \"./tmp\";\n \ +\n $cmd = \"sfold -m $fmodel $fs1 $fs2\";\n \ +open(FREADME,\">$freadme\");\n print FREADME \"\ +$cmd\\n\"; \n close(FREADME);\n\n # and go\n\ + #\n system(\"/usr/bin/time -p -o $ftimelog \ +$cmd >$frawout 2>$ferrlog\");\n if ($? != 0) {\\ +n $errmsg = \"command failed with exit stat\ +us $?\";\n $errmsg .= \"command was \\\"$cm\ +d\\\". See \" . getcwd . \"\\n\";\n return \ +-1;\n }\n\n return sfold_parseoutput($frawou\ +t, $foutfa);\n}\n\n\n\n\n\n\n\nmy ($help, $fmsqin,\ + $fmsaout);\nGetOptions(\"help\" => \\$help,\n \ + \"in=s\" => \\$fmsqin,\n \"out=s\ +\" => \\$fmsaout,\n \"data=s\" => \\$ref_dir);\\ +n\n\n\nif ($help) {\n usage();\n exit(0);\n}\ +\nif (! defined($fmsqin)) {\n usage('missing in\ +put filename');\n exit(1);\n}\nif (! defined($f\ +msaout)) {\n usage('missing output filename');\\ +n exit(1);\n\n}\nif (scalar(@ARGV)) {\n usag\ +e('Unknown remaining args');\n exit(1);\n}\n\n$\ +FMODEL = \"$ref_dir/mix80.mod\";\nif (! -e \"$FMOD\ +EL\") {\n die(\"couldn't find sfold grammar mod\ +el file. Expected $FMODEL\\n\");\n}\n\n\nmy %hseq=\ +read_fasta_seq ($fmsqin);\nmy $id;\n\nforeach $id \ +(keys(%hseq))\n {\n push(@seq_array, $hseq{$id\ +});\n }\n\nif ( scalar(@seq_array) != 2 ) {\n \ +die(\"Need *exactly* two sequences as input (pairw\ +ise alignment!).\")\n}\n\n\n\nmy ($sec, $min, $hou\ +r, $mday, $mon, $year, $wday, $yday, $isdst) = loc\ +altime(time);\nmy $datei = sprintf(\"%4d-%02d-%02d\ +\", $year+1900, $mon+1, $mday);\nmy $templ = basen\ +ame($0) . \".\" . $datei . \".pid-\" . $$ . \".XXX\ +XXX\";\nmy $wd = tempdir ( $templ, DIR => $TMPDIR)\ +;\n\ncopy($fmsqin, \"$wd/\" . basename($fmsqin) . \ +\".org\"); # for reproduction\ncopy($FMODEL, \"$wd\ +\");\nmy $fmodel = basename($FMODEL);\nmy $orgwd =\ + getcwd;\nchdir $wd;\n\n\n\nmy @sepseqfiles;\nfore\ +ach $id (keys(%hseq)) {\n my ($seq, $orgseq, $f\ +name, $sout);\n $seq=$hseq{$id}{'seq'};\n \n\ + $fname = basename($fmsqin) . \"_$id.fa\";\n \ + # replace funnies in file/id name (e.g. \"/\" \" \ +\" etc)\n $fname =~ s,[/ ],_,g;\n open (PF, \ +\">$fname\");\n print (PF \">$id\\n$seq\\n\");\\ +n close (PF);\n\n push(@sepseqfiles, $fname)\ +;\n}\n\nmy ($f1, $f2, $fout);\n$f1 = $sepseqfiles[\ +0];\n$f2 = $sepseqfiles[1];\n$fout = $wd . basenam\ +e($fmsqin) . \".out.fa\";\nif (sfold_wrapper($f1, \ +$f2, $fmodel, \"$fout\") != 0) {\n printf STDER\ +R \"ERROR: See logs in $wd\\n\";\n exit(1);\n} \ +else {\n chdir $orgwd;\n copy($fout, $fmsaou\ +t);\n rmtree($wd);\n exit(0);\n}\n","\nuse En\ +v qw(HOST);\nuse Env qw(HOME);\nuse Env qw(USER);\\ +n\n\n$tmp=clean_cr ($ARGV[0]);\nopen (F, $tmp);\n\\ +nwhile ( )\n {\n my $l=$_;\n if ( $l=~/^\ +# STOCKHOLM/){$stockholm=1;}\n elsif ( $stockho\ +lm && $l=~/^#/)\n {\n $l=~/^#(\\S+)\\s+(\\S+)\ +\\s+(\\S*)/g;\n $l=\"_stockholmhasch_$1\\_stockhol\ +mspace_$2 $3\\n\";\n }\n $file.=$l;\n }\n\ +close (F);\nunlink($tmp);\n$file1=$file;\n\n$file=\ +~s/\\#/_hash_symbol_/g;\n$file=~s/\\@/_arobase_sym\ +bol_/g;\n\n\n$file=~s/\\n[\\.:*\\s]+\\n/\\n\\n/g;\\ +n\n$file=~s/\\n[ \\t\\r\\f]+(\\b)/\\n\\1/g;\n\n\n$\ +file=~s/(\\n\\S+)(\\s+)(\\S)/\\1_blank_\\3/g;\n\n$\ +file=~s/[ ]//g;\n$file=~s/_blank_/ /g;\n\n\n\n$fil\ +e =~s/\\n\\s*\\n/#/g;\n\n$file.=\"#\";\n$file =~s/\ +\\n/@/g;\n\n\n\n\n@blocks=split /\\#/, $file;\nshi\ +ft (@blocks);\n@s=split /\\@/, $blocks[0];\n$nseq=\ +$#s+1;\n\n\n\n$file=join '@', @blocks;\n@lines=spl\ +it /\\@/,$file;\n\n$c=0;\n\nforeach $l (@lines)\n \ + {\n if (!($l=~/\\S/)){next;}\n elsif ($stoc\ +kholm && ($l=~/^\\/\\// || $l=~/STOCKHOLM/)){next;\ +}#get read of STOCHOLM Terminator\n \n $l=~/(\ +\\S+)\\s+(\\S*)/g;\n $n=$1; $s=$2;\n \n $\ +seq[$c].=$s;\n $name[$c]=$n;\n $c++;\n \n\ + if ( $c==$nseq){$c=0;}\n \n } \n\nif ( $c!\ +=0)\n {\n print STDERR \"ERROR: $ARGV[0] is N\ +OT an MSA in Clustalw format: make sure there is n\ +o blank line within a block [ERROR]\\n\";\n exit (\ +EXIT_FAILURE);\n }\n\nfor ($a=0; $a< $nseq; $\ +a++)\n {\n $name[$a]=cleanstring ($name[$a]);\\ +n $seq[$a]=cleanstring ($seq[$a]);\n $seq[$a\ +]=breakstring($seq[$a], 60);\n \n $line=\">$\ +name[$a]\\n$seq[$a]\\n\";\n \n print \"$line\ +\";\n }\nexit (EXIT_SUCCESS);\n\nsub cleanstring\\ +n {\n my $s=@_[0];\n $s=~s/_hash_symbol_/\\\ +#/g;\n $s=~s/_arobase_symbol_/\\@/g;\n $s=~s\ +/[ \\t]//g;\n return $s;\n }\nsub breakstring\\ +n {\n my $s=@_[0];\n my $size=@_[1];\n m\ +y @list;\n my $n,$ns, $symbol;\n \n @list\ +=split //,$s;\n $n=0;$ns=\"\";\n foreach $sy\ +mbol (@list)\n {\n if ( $n==$size)\n {\n \ + $ns.=\"\\n\";\n $n=0;\n }\n $ns.=$symbol;\\ +n $n++;\n }\n return $ns;\n }\n\nsub cl\ +ean_cr\n {\n my $f=@_[0];\n my $file;\n \ +\n $tmp=\"f$.$$\";\n \n \n open (IN, $\ +f);\n open (OUT, \">$tmp\");\n \n while (\ + )\n {\n $file=$_;\n $file=~s/\\r\\n/\\n/\ +g;\n $file=~s/\\n\\r/\\n/g;\n $file=~s/\\r\\r/\\n/\ +g;\n $file=~s/\\r/\\n/g;\n print OUT \"$file\";\n \ + }\n \n close (IN);\n close (OUT);\n \ + return $tmp;\n }\n","use Env qw(HOST);\nuse En\ +v qw(HOME);\nuse Env qw(USER);\n\n\n$query_start=-\ +1;\n$query_end=-1;\n\nwhile (<>)\n {\n if ( /\\ +\/\\//){$in_aln=1;}\n elsif ( $in_aln && /(\\S+\ +)\\s+(.*)/)\n {\n\n\n $name=$1;\n \n\n $seq=$\ +2;\n $seq=~s/\\s//g;\n $seq=~s/\\~/\\-/g;\n\ + $seq=~s/\\./\\-/g;\n if ( $list{$n}{'name'} && $l\ +ist{$n}{'name'} ne $name)\n {\n print \"$lis\ +t{$n}{'name'} Vs $name\";\n \n exit (EXIT_\ +FAILURE);\n }\n else\n {\n $list{$n}{'name\ +'}= $name;\n }\n\n $list{$n}{'seq'}=$list{$n}{'s\ +eq'}.$seq;\n \n $nseq=++$n;\n \n }\n else\\ +n {$n=0;}\n }\n\n\nfor ($a=0; $a<$nseq; $a++\ +)\n {\n print \">$list{$a}{'name'}\\n$list{$a}\ +{'seq'}\\n\";\n }\n \n","\nuse Env qw(HOST);\ +\nuse Env qw(HOME);\nuse Env qw(USER);\n\n \ + \n\ +use strict; \ + \nuse warnings;\nuse diagnostics;\n\nmy $in_\ +hit_list, my $in_aln=0, my(%name_list)=(),my (%lis\ +t)=(),my $n_seq=0; my $test=0;\nmy($j)=0, my $n=0,\ + my $nom, my $lg_query, my %vu=();\n\nopen (F, \">\ +tmp\");\n\n$/=\"\\n\";\nwhile (<>)\n{\n print F\ + $_;\n if($_ =~ /Query=\\s*(.+?)\\s/i) { $nom=$\ +1;}\n\n if ( /Sequences producing significant a\ +lignments/){$in_hit_list=1;}\n \n if ($_=~ /\ +^pdb\\|/i) { $_=~ s/pdb\\|//g; }\n if ($_=~ /^(\ +1_\\d+)\\s+\\d+/) { $_=~ s/$1/QUERY/;}\n \n \ + if ( /^(\\S+).+?\\s+[\\d.]+\\s+([\\de.-]+)\\s+$/\ + && $in_hit_list) \n {\n my($id)=$1; # \n $id=~\ + s/\\|/_/g; #\n if ($id =~ /.+_$/) { chop($id) }; \ +#\n $name_list{$n_seq++}=$id;\n $name_list{$n_seq-\ +1}=~ s/.*\\|//g; \n }\n \n if (/query/i\ +) {$in_aln=1;}\n if ( /^(\\S+)\\s+(\\d+)\\s+([a\ +-zA-Z-]+)\\s+(\\d+)/ || /^(\\S+)(\\s+)(\\-+)(\\s+)\ +/ && ($in_aln == 1))\n {\n my $name=$1;\n my $s\ +tart=$2;\n my $seq=$3;\n my $end=$4;\n \n if ($na\ +me =~ /QUERY/i) { $lg_query=length($seq); }\n\n un\ +less ($test > $n) #m\n {\n my(@seqq)= split(''\ +,$seq);\n my($gap_missing)= scalar(@seqq);\n \ + \n while ($gap_missing != $lg_query) { uns\ +hift (@seqq,\"-\"); $gap_missing= scalar(@seqq); }\ +\n $seq=join('',@seqq); #m\n }\n \n if ($name\ + =~ /QUERY/i)\n {\n $n=0; %vu=(); $j=0;\n \ +$list{$n}{'real_name'}=\"$nom\";\n } \n else\n {\n\ + unless (exists $vu{$name}) { ++$j;} \n $l\ +ist{$n}{'real_name'}=$name_list{$j-1};\n }\n \n $\ +list{$n}{'name'}=$name;\n\n $seq=~tr/a-z/A-Z/;\n $\ +list{$n}{'seq'}=$list{$n}{'seq'};\n $list{$n}{'seq\ +'}.=$seq;\n\n $n++;\n $vu{$name}++;\n $test++;\n \ + } \n \n}\n\nmy @numero=();\n\nfor (my $a=0; $a\ +<$n; $a++) #m\n{\n my $long=length($list{0}{'se\ +q'}); \n my $long1= length($list{$a}{'seq'});\\ +n \n while ($long1 ne $long)\n {\n $list{$a\ +}{'seq'}.=\"-\";\n $long1= length ($list{$a}{'seq'\ +});\n } \n \n push (@numero,\"$list{$a}{'nam\ +e'} $list{$a}{'real_name'}\\n\");\n}\n\nmy %dejavu\ +=();\n\n\nfor (my $i=0; $i<=$#numero; $i++)\n{\n \ + my $s=\">$list{$i}{'real_name'}\\n$list{$i}{'seq\ +'}\\n\";\n my $k=0;\n \n if (exists $deja\ +vu{$numero[$i]}) {next;}\n else\n { \n for (\ +$j=0; $j<$n ; $j++)\n {\n if (\"$numero[$i]\" \ +eq \"$numero[$j]\" && $j != $i )\n {\n ++$k;\\ +n $s .=\">$list{$j}{'real_name'}\\n$list{$j}{'seq\ +'}\\n\";\n }\n } \n }\n \n if ($k>0) \ +\n {\n my $cons;\n open (SOR,\">tempo_aln2cons\\ +"); print SOR $s; close SOR ;\n open (COM,\"t_cof\ +fee -other_pg seq_reformat -in tempo_aln2cons -act\ +ion +aln2cons +upper |\") ; \n while ()\\ +n { \n if (/^>/) { $cons =\">$list{$i}{'real_n\ +ame'}\\n\"; next;}\n $_=~ s/\\n//g;\n $con\ +s .=$_;\n }\n close COM; unlink (\"tempo_aln2cons\\ +");\n print $cons,\"\\n\"; print F $cons,\"\\n\";\\ +n } \n else { print $s; print F $s; }\n \ + \n $dejavu{$numero[$i]}++;\n} #m\n\nexit;\n\n\\ +n\n\n\n\n\n\n\n\n\n","use Env;\n\n\n$tmp_dir=\"\";\ +\n$init_dir=\"\";\n$program=\"tc_generic_method.pl\ +\";\n\n$blast=@ARGV[0];\n\n$name=\"query\";$seq=\"\ +\";\n%p=blast_xml2profile($name,$seq,100, 0, 0, $b\ +last);\n&output_profile (%p);\n\n\nsub output_prof\ +ile\n {\n my (%profile)=(@_);\n my ($a);\n \ + for ($a=0; $a<$profile{n}; $a++)\n {\n \n \ +print \">$profile{$a}{name} $profile{$a}{comment}\\ +\n$profile{$a}{seq}\\n\";\n }\n return;\n \ + }\nsub file_contains \n {\n my ($file, $tag, \ +$max)=(@_);\n my ($n);\n $n=0;\n \n if\ + ( !-e $file && ($file =~/$tag/)) {return 1;}\n \ + elsif ( !-e $file){return 0;}\n else \n {\ +\n open (FC, \"$file\");\n while ( )\n {\n \ + if ( ($_=~/$tag/))\n {\n close (FC);\n \ +return 1;\n }\n elsif ($max && $n>$max)\\ +n {\n close (FC);\n return 0;\n }\n \ + $n++;\n }\n }\n close (FC);\n ret\ +urn 0;\n }\n \n \nsub file2string\n {\n \ + my $f=@_[0];\n my $string, $l;\n open (F,\"\ +$f\");\n while ()\n {\n\n $l=$_;\n #cho\ +mp ($l);\n $string.=$l;\n }\n close (F);\n\ + $string=~s/\\r\\n//g;\n $string=~s/\\n//g;\\ +n return $string;\n }\n\n\n\nsub tag2value \n \ + {\n \n my $tag=(@_[0]);\n my $word=(@_[1\ +]);\n my $return;\n \n $tag=~/$word=\"([^\ +\"]+)\"/;\n $return=$1;\n return $return;\n \ + }\n \nsub hit_tag2pdbid\n {\n my $tag=(@\ +_[0]);\n my $pdbid;\n \n $tag=~/id=\"(\ +\\S+)\"/;\n $pdbid=$1;\n $pdbid=~s/_//;\n \ + return $pdbid;\n }\nsub id2pdbid \n {\n my $\ +id=@_[0];\n \n if ($id =~/pdb/)\n {\n $id\ +=~/pdb(.*)/;\n $id=$1;\n }\n $id=~s/[|¦_]/\ +/g;\n return $id;\n }\nsub set_blast_type \n \ +{\n my $file =@_[0];\n if (&file_contains ($\ +file,\"EBIApplicationResult\",100)){$BLAST_TYPE=\"\ +EBI\";}\n elsif (&file_contains ($file,\"NCBI_B\ +lastOutput\",100)) {$BLAST_TYPE=\"NCBI\";}\n el\ +se\n {\n $BLAST_TYPE=\"\";\n }\n retu\ +rn $BLAST_TYPE;\n }\nsub blast_xml2profile \n {\\ +n my ($name,$seq,$maxid, $minid, $mincov, $file\ +)=(@_);\n my (%p, $a, $string, $n);\n \n\n\n\ + if ($BLAST_TYPE eq \"EBI\" || &file_contains (\ +$file,\"EBIApplicationResult\",100)){%p=ebi_blast_\ +xml2profile(@_);}\n elsif ($BLAST_TYPE eq \"NCB\ +I\" || &file_contains ($file,\"NCBI_BlastOutput\",\ +100)){%p=ncbi_blast_xml2profile(@_);}\n else \n\ + {\n print \"************ ERROR: Blast Return\ +ed an unknown XML Format **********************\";\ +\n die;\n }\n for ($a=0; $a<$p{n}; $a++)\n\ + {\n my $name=$p{$a}{name};\n $p{$name}{seq}=\ +$p{$a}{seq};\n }\n return %p;\n }\nsub nc\ +bi_blast_xml2profile \n {\n my ($name,$seq,$ma\ +xid, $minid, $mincov, $string)=(@_);\n my ($L,$\ +l, $a,$b,$c,$d,$nhits,@identifyerL);\n \n \n\ + $seq=~s/[^a-zA-Z]//g;\n $L=length ($seq);\n\ + \n %hit=&xml2tag_list ($string, \"Hit\");\n\ + \n \n for ($nhits=0,$a=0; $a<$hit{n}; $a\ +++)\n {\n my ($ldb,$id, $identity, $expectati\ +on, $start, $end, $coverage, $r);\n my (%ID,%DE,%H\ +SP);\n \n $ldb=\"\";\n\n %ID=&xml2tag_list ($hit{$\ +a}{body}, \"Hit_id\");\n $identifyer=$ID{0}{body};\ +\n \n %DE=&xml2tag_list ($hit{$a}{body}, \"Hit_def\ +\");\n $definition=$DE{0}{body};\n \n %HSP=&xml2ta\ +g_list ($hit{$a}{body}, \"Hsp\");\n for ($b=0; $b<\ +$HSP{n}; $b++)\n {\n my (%START,%END,%E,%I,%\ +Q,%M);\n\n \n %START=&xml2tag_list ($HSP{$b}{\ +body}, \"Hsp_query-from\");\n %HSTART=&xml2tag\ +_list ($HSP{$b}{body}, \"Hsp_hit-from\");\n \n\ + %LEN= &xml2tag_list ($HSP{$b}{body}, \"Hsp_a\ +lign-len\");\n %END= &xml2tag_list ($HSP{$b}{\ +body}, \"Hsp_query-to\");\n %HEND= &xml2tag_l\ +ist ($HSP{$b}{body}, \"Hsp_hit-to\");\n %E=&xm\ +l2tag_list ($HSP{$b}{body}, \"Hsp_evalue\");\n\ + %I=&xml2tag_list ($HSP{$b}{body}, \"Hsp_i\ +dentity\");\n %Q=&xml2tag_list ($HSP{$b}{b\ +ody}, \"Hsp_qseq\");\n %M=&xml2tag_list ($\ +HSP{$b}{body}, \"Hsp_hseq\");\n \n for ($e\ +=0; $e<$Q{n}; $e++)\n\n {\n $qs=$Q{$e}{body\ +};\n $ms=$M{$e}{body};\n if ($seq eq\"\"){$seq=$\ +qs;$L=length($seq);}\n \n $expectation=$E{$e}{bo\ +dy};\n $identity=($LEN{$e}{body}==0)?0:$I{$e}{bod\ +y}/$LEN{$e}{body}*100;\n $start=$START{$e}{body};\ +\n $end=$END{$e}{body};\n $Hstart=$HSTART{$e}{bo\ +dy};\n $Hend=$HEND{$e}{body};\n \n $coverage=(($\ +end-$start)*100)/$L;\n\n \n if ($identity>$maxid \ +|| $identity<$minid || $coverage<$mincov){next;}\n\ + @lr1=(split (//,$qs));\n @lr2=(split (//,$ms));\ +\n $l=$#lr1+1;\n for ($c=0;$c<$L;$c++){$p[$nhits\ +][$c]=\"-\";}\n for ($d=0,$c=0; $c<$l; $c++)\n \ + {\n $r=$lr1[$c];\n if ( $r=~/[A-Za-z]/)\ +\n {\n \n $p[$nhits][$d + $start-1]=$lr\ +2[$c];\n $d++;\n }\n }\n $Qseq[$nhits\ +]=$qs;\n $Hseq[$nhits]=$ms;\n $QstartL[$nhits]=$\ +start;\n $HstartL[$nhits]=$Hstart;\n $identityL[\ +$nhits]=$identity;\n $endL[$nhits]=$end;\n $defi\ +nitionL[$nhits]=$definition;\n $identifyerL[$nhit\ +s]=$identifyer;\n $comment[$nhits]=\"$ldb|$identi\ +fyer [Eval=$expectation][id=$identity%][start=$Hst\ +art end=$Hend]\";\n $nhits++;\n }\n }\n \ + }\n \n $profile{n}=0;\n $profile{$pro\ +file{n}}{name}=$name;\n $profile{$profile{n}}{s\ +eq}=$seq;\n $profile {n}++;\n \n for ($a=\ +0; $a<$nhits; $a++)\n {\n $n=$a+1;\n \n $prof\ +ile{$n}{name}=\"$name\\_$a\";\n $profile{$n}{seq}=\ +\"\";\n $profile{$n}{Qseq}=$Qseq[$a];\n $profile{$\ +n}{Hseq}=$Hseq[$a];\n $profile{$n}{Qstart}=$Qstart\ +L[$a];\n $profile{$n}{Hstart}=$HstartL[$a];\n $pro\ +file{$n}{identity}=$identityL[$a];\n $profile{$n}{\ +definition}=$definitionL[$a];\n $profile{$n}{ident\ +ifyer}=$identifyerL[$a];\n $profile{$n}{comment}=$\ +comment[$a];\n for ($b=0; $b<$L; $b++)\n {\n \ + if ($p[$a][$b])\n {\n $profile{$n}{seq}.=$\ +p[$a][$b];\n }\n else\n {\n $prof\ +ile{$n}{seq}.=\"-\";\n }\n }\n }\n \ + \n $profile{n}=$nhits+1;\n return %profile;\ +\n }\nsub ebi_blast_xml2profile \n {\n my ($n\ +ame,$seq,$maxid, $minid, $mincov, $string)=(@_);\n\ + my ($L,$l, $a,$b,$c,$d,$nhits,@identifyerL,$id\ +entifyer);\n \n\n \n $seq=~s/[^a-zA-Z]//g\ +;\n $L=length ($seq);\n %hit=&xml2tag_list (\ +$string, \"hit\");\n \n for ($nhits=0,$a=0; \ +$a<$hit{n}; $a++)\n {\n my ($ldb,$id, $identi\ +ty, $expectation, $start, $end, $coverage, $r);\n \ +my (%Q,%M,%E,%I);\n \n $ldb=&tag2value ($hit{$a}{o\ +pen}, \"database\");\n $identifyer=&tag2value ($hi\ +t{$a}{open}, \"id\");\n\n $description=&tag2value \ +($hit{$a}{open}, \"description\");\n \n %Q=&xml2ta\ +g_list ($hit{$a}{body}, \"querySeq\");\n %M=&xml2t\ +ag_list ($hit{$a}{body}, \"matchSeq\");\n %E=&xml2\ +tag_list ($hit{$a}{body}, \"expectation\");\n %I=&\ +xml2tag_list ($hit{$a}{body}, \"identity\");\n \n\\ +n for ($b=0; $b<$Q{n}; $b++)\n {\n \n \n\ + $qs=$Q{$b}{body};\n $ms=$M{$b}{body};\n \ + if ($seq eq\"\"){$seq=$qs;$L=length($seq);}\n\n\ + $expectation=$E{$b}{body};\n $identity=$I\ +{$b}{body};\n \n \n $start=&tag2v\ +alue ($Q{$b}{open}, \"start\");\n $end=&tag2va\ +lue ($Q{$b}{open}, \"end\");\n $startM=&tag2va\ +lue ($M{$b}{open}, \"start\");\n $endM=&tag2va\ +lue ($M{$b}{open}, \"end\");\n $coverage=(($en\ +d-$start)*100)/$L;\n \n # print \"$id: ID: \ +$identity COV: $coverage [$start $end]\\n\";\n \ + \n \n if ($identity>$maxid || $identity<$\ +minid || $coverage<$mincov){next;}\n # print \\ +"KEEP\\n\";\n\n \n @lr1=(split (//,$qs));\\ +n @lr2=(split (//,$ms));\n $l=$#lr1+1;\n \ + for ($c=0;$c<$L;$c++){$p[$nhits][$c]=\"-\";}\n \ + for ($d=0,$c=0; $c<$l; $c++)\n {\n $r=$\ +lr1[$c];\n if ( $r=~/[A-Za-z]/)\n {\n \n \ + $p[$nhits][$d + $start-1]=$lr2[$c];\n $d\ +++;\n }\n }\n \n \n $identifyer\ +L[$nhits]=$identifyer;\n $comment[$nhits]=\"$l\ +db|$identifyer [Eval=$expectation][id=$identity%][\ +start=$startM end=$endM]\";\n $nhits++;\n }\\ +n }\n \n $profile{n}=0;\n $profile{$\ +profile{n}}{name}=$name;\n $profile{$profile{n}\ +}{seq}=$seq;\n $profile {n}++;\n \n for (\ +$a=0; $a<$nhits; $a++)\n {\n $n=$a+1;\n $prof\ +ile{$n}{name}=\"$name\\_$a\";\n $profile{$n}{seq}=\ +\"\";\n $profile{$n}{identifyer}=$identifyerL[$a];\ +\n \n $profile{$n}{comment}=$comment[$a];\n for ($\ +b=0; $b<$L; $b++)\n {\n if ($p[$a][$b])\n \ + {\n $profile{$n}{seq}.=$p[$a][$b];\n }\\ +n else\n {\n $profile{$n}{seq}.=\"-\";\\ +n }\n }\n }\n $profile{n}=$nhits+1\ +;\n \n return %profile;\n }\n\nsub blast_xm\ +l2hit_list\n {\n my $string=(@_[0]);\n retu\ +rn &xml2tag_list ($string, \"hit\");\n }\nsub xml\ +2tag_list \n {\n my ($string_in,$tag)=@_;\n \ + my $tag_in, $tag_out;\n my %tag;\n \n i\ +f (-e $string_in)\n {\n $string=&file2string \ +($string_in);\n }\n else\n {\n $strin\ +g=$string_in;\n }\n $tag_in1=\"<$tag \";\n\ + $tag_in2=\"<$tag>\";\n $tag_out=\"/$tag>\";\ +\n $string=~s/>/>##1/g;\n $string=~s//g;\n @l=($string=~/(\\<[^>]+\\>)/g);\n $ta\ +g{n}=0;\n $in=0;$n=-1;\n \n \n\n foreach $t\ + (@l)\n {\n\n $t=~s/<#//;\n $t=~s/#>//;\n \n \ +if ( $t=~/$tag_in1/ || $t=~/$tag_in2/)\n {\n \n\ + $in=1;\n $tag{$tag{n}}{open}=$t;\n $n\ +++;\n \n }\n elsif ($t=~/$tag_out/)\n {\n \ + \n\n $tag{$tag{n}}{close}=$t;\n $tag{n\ +}++;\n $in=0;\n }\n elsif ($in)\n {\n \\ +n $tag{$tag{n}}{body}.=$t;\n }\n }\n \\ +n return %tag;\n }\n\n\n\n\n","use Env qw(HOST\ +);\nuse Env qw(HOME);\nuse Env qw(USER);\nwhile (<\ +>)\n {\n if ( /^>(\\S+)/)\n {\n if ($list\ +{$1})\n {\n print \">$1_$list{$1}\\n\";\n \ + $list{$1}++;\n }\n else\n {\n print $_;\\ +n $list{$1}=1;\n }\n }\n else\n \ + {\n print $_;\n }\n }\n \n","\n\n\nuse\ + Env qw(HOST);\nuse Env qw(HOME);\nuse Env qw(USER\ +);\n\n\nopen (F,$ARGV[0]);\nwhile ( <>)\n {\n \ +@x=/([^:,;\\)\\(\\s]+):[^:,;\\)\\(]*/g;\n @list\ +=(@list,@x);\n }\n$n=$#list+1;\nforeach $n(@list)\ +{print \">$n\\nsequence\\n\";}\n\n\nclose (F);\n",\ +"\nopen (F, $ARGV[0]);\n\nwhile ( )\n {\n @\ +l=($_=~/(\\S+)/g);\n \n $name=shift @l;\n \ + \n print STDOUT \"\\n>$name\\n\";\n foreach\ + $e (@l){$e=($e eq \"0\")?\"O\":\"I\";print \"$e\"\ +;}\n }\nclose (F);\n\n \n \n","use Env\ + qw(HOST);\nuse Env qw(HOME);\nuse Env qw(USER);\n\ +\n$tmp=\"$ARGV[0].$$\";\nopen (IN, $ARGV[0]);\nope\ +n (OUT, \">$tmp\");\n\nwhile ( )\n {\n $fi\ +le=$_;\n $file=~s/\\r\\n/\\n/g;\n $file=~s/\\ +\n\\r/\\n/g;\n $file=~s/\\r\\r/\\n/g;\n $fil\ +e=~s/\\r/\\n/g;\n print OUT \"$file\";\n }\ncl\ +ose (IN);\nclose (OUT);\n\nopen (OUT, \">$ARGV[0]\\ +");\nopen (IN, \"$tmp\");\n\nwhile ( )\n{\n p\ +rint OUT \"$_\";\n}\nclose (IN);\nclose (OUT);\nun\ +link ($tmp);\n\n"}; +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/random.c b/binaries/src/tcoffee/t_coffee_source/random.c new file mode 100644 index 0000000..1baa3ee --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/random.c @@ -0,0 +1,94 @@ +/* +* +* Rand.c +* +* - linear and additive congruential random number generators +* (see R. Sedgewick, Algorithms, Chapter 35) +* +* Implementation: R. Fuchs, EMBL Data Library, 1991 +* +*/ + + + +#define m1 10000 +#define m 100000000 + +/* linear congruential method +* +* linrand() returns an unsigned long random number in the range 0 to r-1 +*/ + + + +static unsigned long mult(unsigned long p, unsigned long q) +{ + unsigned long p1,p0,q1,q0; + + p1 = p/m1; p0 = p % m1; + q1 = q/m1; q0 = q % m1; + return (unsigned long)((((p0*q1 + p1*q0) % m1) * m1 + p0*q0) % m); +} + + +/* additive congruential method +* +* addrand() returns an unsigned long random number in the range 0 to r-1 +* The random number generator is initialized by addrandinit() +*/ + +static unsigned long j; +static unsigned long a[55]; + +unsigned long addrand(unsigned long r) +{ +int x,y; +/* fprintf(stdout,"\n j = %d",j); */ + j = (j + 1) % 55; +/* fprintf(stdout,"\n j = %d",j); */ + x = (j+23)%55; + y = (j+54)%55; + a[j] = (a[x] + a[y]) % m; +/* a[j] = (a[(j+23)%55] + a[(j+54)%55]) % m; */ +/* fprintf(stdout,"\n a[j] = %d",a[j]); */ + return( ((a[j] / m1) * r) / m1 ); +} + +void addrandinit(unsigned long s) +{ + a[0] = s; + j = 0; + do { + ++j; + a[j] = (mult(31,a[j-1]) + 1) % m; + } while (j<54); +} +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/reformat.c b/binaries/src/tcoffee/t_coffee_source/reformat.c new file mode 100644 index 0000000..2eac04a --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/reformat.c @@ -0,0 +1,12795 @@ +#include +#include +#include +#include +#include +#include +#include +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "dp_lib_header.h" +#include "define_header.h" +#include "dev1_lib_header.h" //JM_STRAT + +#define ACTION(x) ((n_actions>=(x+1))?action_list[x]:NULL) +#define ACTION2(x,y) ((n_actions>=(x+1))?action_list[x]:y) +#define ATOI_ACTION(x) ((ACTION(x)!=NULL)?(atoi(ACTION(x))):0) + +/**************************************************************************************************/ +/***************************** SEQ_REFORMAT ******************************************/ +/**************************************************************************************************/ +int output_transitions(char *outfile, Alignment *A); +static int output_age_matrix ( char *outfile, int val); +int SeqGCGCheckSum(char *seq, int len); +static Sequence *seq2year ( Sequence *S, int modulo); +static Sequence* output_n_pavie_age_channel (Sequence *S, char *name, int n); +static Sequence* output_pavie_age_channel (Sequence *S, char *name, int modulo); + +static int output_seq2struc(char *outfile, Alignment *A); +void output_conservation_statistics ( char *file, Alignment *A); +/**************************************************************************************************/ +/***************************** SEQ_REFORMAT ******************************************/ +/**************************************************************************************************/ +int seq_reformat ( int argc, char **in_argv) + { + + Sequence_data_struc *D1=NULL; + Sequence_data_struc *D2=NULL; + Sequence_data_struc *D_ST=NULL; + Action_data_struc *RAD; + + + + int a, b; + + char *in_format; + char *in2_format; + char *out_format; + char *in_file; + char *in2_file; + char *out_file; + char *out2_file; + char *struc_in_format; + char *struc_out_format; + char *struc_in_file; + char *struc_out_file; + char**action_list; + char **action; + char *rename_file; + char *cache; + char ***rename_list=NULL; + int code=CODE; + char **argv; + + int n_actions=0; + int print_format=0; + /*INITIALIZATIONS*/ + + RAD=vcalloc ( 1, sizeof ( Action_data_struc)); + RAD->keep_case=1; + declare_name (cache);sprintf ( cache, "use"); + declare_name(in_file); + declare_name(in2_file); + declare_name(out_file); + declare_name(out2_file); + declare_name(struc_in_format); + declare_name(struc_out_format); + declare_name(RAD->coor_file); + + declare_name(struc_in_file); + declare_name(struc_out_file); + declare_name(in_format); + declare_name(in2_format); + declare_name(out_format); + declare_name(rename_file); + + + argv=break_list ( in_argv, &argc, "=;, \n"); + + action_list=declare_char ( 100, 100); + +/*END INITIALIZATION*/ + + addrandinit ( (unsigned long) 500); + + if ( argc==1 || strm6 ( argv[1], "h", "-h", "help", "-help", "-man", "?")) + { + + fprintf ( stdout, "\n%s (%s,%s,%s [%s])\n",PROGRAM, VERSION,AUTHOR, DATE, URL); + fprintf ( stdout, "\n*********** MINIMUM SYNTAX *****************"); + fprintf ( stdout, "\nseq_reformat -in -output "); + fprintf ( stdout, "\nSome File formats are automatically recognised"); + fprintf ( stdout, "\nSee Format section"); + fprintf ( stdout, "\n"); + fprintf ( stdout, "\n*********** MAIN FLAGS ******************"); + fprintf ( stdout, "\n-in name........Name of the file read"); + + + fprintf ( stdout, "\n-input format......Name of the format read, see Input Format Section"); + fprintf ( stdout, "\n...................Automatic detection, except for seqs of numbers"); + fprintf ( stdout, "\n...................-input number_aln | number_fasta"); + fprintf ( stdout, "\n-in2 fname......Second alignment"); + fprintf ( stdout, "\n-input2 format.....See -input"); + fprintf ( stdout, "\n-exon_boundaries obj file"); + fprintf ( stdout, "\n-out fname......Output file (defualt is STDOUT"); + fprintf ( stdout, "\n-output format.....Output Format, default is fasta_aln"); + fprintf ( stdout, "\n-struc_in name...File containing a coded aln"); + fprintf ( stdout, "\n-struc_in_f format.See -input and output format section"); + fprintf ( stdout, "\n-struc_out fname..Name of the output structure"); + fprintf ( stdout, "\n-struc_out_f symbol"); + fprintf ( stdout, "\n-keep_case=on|off..keep case, On by default"); + fprintf ( stdout, "\n-action +ac1 +ac2..See the action section"); + fprintf ( stdout, "\n-rename .....Rename the sequences following indications"); + fprintf ( stdout, "\n...................File Format: One couple /line"); + fprintf ( stdout, "\n...................Rename order into "); + fprintf ( stdout, "\n...................code file: -output code_name"); + fprintf ( stdout, "\n-code Rename file to "); + fprintf ( stdout, "\n-decode Rename file to "); + fprintf ( stdout, "\n-no_warning........Suppresses all warnings"); + fprintf ( stdout, "\n-cache.............use,ignore,update,local, DirectoryName"); + + + fprintf ( stdout, "\n"); + + fprintf ( stdout, "\n*********** REFORMAT ACTIONS *****************"); + fprintf ( stdout, "\n +Xaction.............Specifies which file undergoes the action"); + fprintf ( stdout, "\n +Xaction.............X=1: -in"); + fprintf ( stdout, "\n +Xaction.............X=2: -in2"); + fprintf ( stdout, "\n +Xaction.............X=3: -struc_in"); + fprintf ( stdout, "\n +name2unique_name....replace duplicated name with name_#"); + fprintf ( stdout, "\n +swap_header........,swapp comments: replace comments/name in 1 by in 2"); + fprintf ( stdout, "\n +swap_lib_header.F...Replace the sequences in the tc_lib (-in) with those in F"); + fprintf ( stdout, "\n .....................F is a legal FASTA file"); + + + fprintf ( stdout, "\n +translate[0-2]......Translate on Frame 0, 1, 2 "); + fprintf ( stdout, "\n +translate[3]........longuest ORF on direct strand"); + fprintf ( stdout, "\n +translate[4]........longuest ORF on direct+complementary strand"); + + + fprintf ( stdout, "\n +add_scale...addscale below aln"); + + fprintf ( stdout, "\n +rm_gap n ...........Removes col with n%% gap [n=100]"); + fprintf ( stdout, "\n +rmgap_col SEQ1:SEQ2.Removes column with a gap in SEQ [#] "); + + fprintf ( stdout, "\n +backtranslate.......Random Backtranslation"); + fprintf ( stdout, "\n +complement..........Produces the reverse complement"); + + fprintf ( stdout, "\n +reorder.............Reorders sequences of according to "); + fprintf ( stdout, "\n .........random......Random_order"); + fprintf ( stdout, "\n .........tree........Tree Order (in2)"); + fprintf ( stdout, "\n +reorder_column.....Reorders sequences of according to "); + fprintf ( stdout, "\n .........random......Random_order"); + fprintf ( stdout, "\n .........tree..mode..Tree Order (comuted with mode: sarmat, idmat, blosum62mt..."); + fprintf ( stdout, "\n +aln2random_aln SCR..Randomize the aln, S: swap sequences names"); + fprintf ( stdout, "\n .....................Swap residues within colums"); + fprintf ( stdout, "\n .....................Swap residues across the aln"); + fprintf ( stdout, "\n +aln2sample......N......"); + fprintf ( stdout, "\n +aln2bootstrap...N......"); + + + fprintf ( stdout, "\n +chain...............Identifies all the intermediate sequences from <-in>"); + fprintf ( stdout, "\n .....................needed to join every sequence pair in <-in2>"); + + fprintf ( stdout, "\n +aln2cons mat_name..Ouputs a consensus sequence"); + fprintf ( stdout, "\n .....................The consensus is determined using mat"); + fprintf ( stdout, "\n .....................By Default, mat=blosum62mt, name=Cons"); + fprintf ( stdout, "\n +aln2resindex........Prints the sequence index of each residue in -in for each -in2 sequence"); + fprintf ( stdout, "\n +collapse_aln | file name"); + fprintf ( stdout, "\n .....................Replaces a group of sequences with its consensus"); + fprintf ( stdout, "\n .....................The replacement sequence is named "); + fprintf ( stdout, "\n .....................List of sequences can be provided via a file"); + fprintf ( stdout, "\n .....................File:>new_name seq1 seq2 seq3...."); + fprintf ( stdout, "\n +original_seqnos.....Keep original seqnos [SWITCH]"); + fprintf ( stdout, "\n +seqnos..............Print Seqnos [SWITCH]"); + fprintf ( stdout, "\n +code_dna_aln........Undocumented") ; + fprintf ( stdout, "\n +grep..[NAME|SEQ|COMMENT]..[KEEP|REMOVE]..[string]......"); + fprintf ( stdout, "\n .....................Keeps or Removes Sequences matching string"); + fprintf ( stdout, "\n +extract_block | |"); + fprintf ( stdout, "\n .....................Extract column pos OR [start to end["); + fprintf ( stdout, "\n ..................... Format"); + fprintf ( stdout, "\n .......................seq start end | seq pos"); + fprintf ( stdout, "\n .......................# for comments"); + fprintf ( stdout, "\n .......................! seq offset_value (0 by default)"); + fprintf ( stdout, "\n .....................Can extract as many positions as needed"); + fprintf ( stdout, "\n .....................seq=cons: measure positions on the full aln"); + fprintf ( stdout, "\n +cat_aln.............Concatenates the alignments input via -in and -in2"); + fprintf ( stdout, "\n +cat_aln.............-if no -in2, -in is expected to be a list of alignments to concatenate"); + fprintf ( stdout, "\n +orthologous_cat..: mode=voronoi or nothing"); + fprintf ( stdout, "\n ......................-in: sequences from different species"); + fprintf ( stdout, "\n ..................... -in2: list of species in fasta"); + fprintf ( stdout, "\n ..................... sequence must be named: _"); + fprintf ( stdout, "\n ..................... all paralogues will be concatenated"); + + fprintf ( stdout, "\n +aln2replicate N name"); + fprintf ( stdout, "\n ..................... Generates N replicates in Fasta"); + fprintf ( stdout, "\n ..................... Voronoi weights can be used"); + + fprintf ( stdout, "\n +msalist2cat_pwaln.min..max"); + fprintf ( stdout, "\n .....................extract all pw projections and conctaenates those\n"); + fprintf ( stdout, "\n .....................where id>=min and id<=max\n"); + fprintf ( stdout, "\n .....................min and max can be omitted (min=0, max=100)\n"); + + fprintf ( stdout, "\n +seq2blast ..gather all possible homologues from NR (EBI BLAST)"); + fprintf ( stdout, "\n +seq2msa ....makes a standard progressive alignment using matrix"); + fprintf ( stdout, "\n +realign_block "); + fprintf ( stdout, "\n .....................Realign column c1 to c2 (non inc.) with pg)"); + fprintf ( stdout, "\n .....................pg reads fasta and outputs fasta"); + fprintf ( stdout, "\n .....................pg -infile= -outfile="); + fprintf ( stdout, "\n +extract_seq seq_name (start end seq_name start end...) | filename"); + fprintf ( stdout, "\n .....................seq_name='*': every seq"); + fprintf ( stdout, "\n .....................start='*' : real start"); + fprintf ( stdout, "\n .....................end='*' : real end"); + fprintf ( stdout, "\n .....................filename: fasta format"); + fprintf ( stdout, "\n +extract_seq_list name1 name2"); + fprintf ( stdout, "\n .....................Extracts entire sequences"); + fprintf ( stdout, "\n +remove_seq sn1 sn2..Removes sequences sn1, sn2..."); + fprintf ( stdout, "\n +remove_seq empty....Removes empty sequences (gap only)"); + fprintf ( stdout, "\n +remove_seq unique...Remove all multiple occurences except the first"); + fprintf ( stdout, "\n +thread_profile_on_msa "); + fprintf ( stdout, "\n .....................Threads a list of profiles on corresponding seq"); + fprintf ( stdout, "\n .....................File: >seqname _R_ [nlines]"); + + fprintf ( stdout, "\n +thread_dna_on_prot_aln"); + fprintf ( stdout, "\n .....................-in DNA.seq and -in2 AA.aln"); + fprintf ( stdout, "\n +thread_struc_on_aln"); + fprintf ( stdout, "\n .....................-in structure and -in2 aln"); + fprintf ( stdout, "\n +use_cons............Use the consensus for n[SWITCH]"); + fprintf ( stdout, "\n +upper.n|[n1-n2].....n omitted sets everything to upper case"); + fprintf ( stdout, "\n .....................To use n: provide a number_aln via:"); + fprintf ( stdout, "\n .....................-struc_in -struc_in_f number_aln"); + fprintf ( stdout, "\n .....................if use_cons is set n, is read on the cons"); + fprintf ( stdout, "\n .....................n: will upper every residue with a value of n in struc_in"); + fprintf ( stdout, "\n .....................[n1-n2]: upper residues between n1 and n2"); + fprintf ( stdout, "\n +lower n|[n1-n2]....See +upper"); + fprintf ( stdout, "\n +switchcase n|[n1-n2]See +upper"); + fprintf ( stdout, "\n +color_residue | file"); + fprintf ( stdout, "\n .....................File: seq_name pos color"); + fprintf ( stdout, "\n .....................color: 0-9"); + fprintf ( stdout, "\n +edit_residue | file"); + fprintf ( stdout, "\n .....................File: seq_name pos color"); + fprintf ( stdout, "\n .....................edit: upper|lower|symbol"); + + + + fprintf ( stdout, "\n +keep n|[n1-n2]....Only keep residues that have a score between n1 and n2"); + + fprintf ( stdout, "\n +invert..............Inverts the sequences: CAT => TAC"); + fprintf ( stdout, "\n +rotate name Rotate an MSA, names each sequence name_col#"); + fprintf ( stdout, "\n +convert n|[n1-n2] s1 s2 ...."); + fprintf ( stdout, "\n +merge_annotation.... "); + + fprintf ( stdout, "\n .....................Converts residues with your alignment"); + fprintf ( stdout, "\n .....................similar to upper"); + fprintf ( stdout, "\n .....................s1: ABCDe turns every ABCD into e"); + fprintf ( stdout, "\n .....................s1: #e turns any residue into e"); + fprintf ( stdout, "\n aln2short_aln L C S..Turns sequences into shorter sequences"); + fprintf ( stdout, "\n .....................L: list of residues to keep"); + fprintf ( stdout, "\n .....................S: Size of Streches replaced by symbol C"); + + + fprintf ( stdout, "\n +random n l..........Generates N random sequences of len l"); + fprintf ( stdout, "\n .....................You must provide a file with -in"); + fprintf ( stdout, "\n +count n|[n1-n2] s1 s2...."); + fprintf ( stdout, "\n .....................Counts residues with your alignment"); + fprintf ( stdout, "\n .....................similar to convert"); + fprintf ( stdout, "\n +print_format........prints the format name"); + fprintf ( stdout, "\n +keep_name...........Keep the original sequence name on extraction"); + + fprintf ( stdout, "\n +remove_aa pos Ml Ncycle Random_len"); + fprintf ( stdout, "\n .....................Randomly modifies an alignment"); + fprintf ( stdout, "\n .....................pos=0: chosen randomly"); + fprintf ( stdout, "\n .....................MaxLen of the deletions, Ncycle: number of cycles"); + fprintf ( stdout, "\n .....................Random_len: 0 sets the len to maxlen, 1 to a random value"); + fprintf ( stdout, "\n +remove_nuc.x........Remove Position 1, 2 or 3 of every codon"); + fprintf ( stdout, "\n +evaluate matrix..gop..gep"); + fprintf ( stdout, "\n .....................Make a similarity evaluation with matrix"); + fprintf ( stdout, "\n .....................use -output=score_ascii, or score_html."); + fprintf ( stdout, "\n .....................You can filter on the values"); + fprintf ( stdout, "\n +evaluate matrix..gop..gep"); + fprintf ( stdout, "\n .....................Make an SP evaluation with matrix"); + fprintf ( stdout, "\n .....................Uses Natural Gap penalties"); + fprintf ( stdout, "\n .....................gop and gep must be negative"); + fprintf ( stdout, "\n .....................use -output=color_ascii, color_html to get a color display"); + + fprintf ( stdout, "\n.....+evaluate_lat........Make a lateral evaluation with matrix"); + fprintf ( stdout, "\n +msa_weight proc.....Computes weights using the procedure"); + fprintf ( stdout, "\nRNA analysis Post Processing___________________________________________________"); + fprintf ( stdout, "\n +aln2alifold.........Turns the MSA into a consensus structure"); + fprintf ( stdout, "\n +add_alifold.........adds an alifold consensus structure"); + + fprintf ( stdout, "\n +alifold2analyze.mode..mode=stat_cache_list_aln_color_html_ps_usegap"); + fprintf ( stdout, "\n .......................stat: compile Number of compensated mutations"); + fprintf ( stdout, "\n .......................cache: ascii-code compensated mutations on aln"); + fprintf ( stdout, "\n .......................html: color-code compensated mutations on aln"); + fprintf ( stdout, "\n .......................aln: mark compensated mutations on stockholm aln"); + fprintf ( stdout, "\n .......................usegap: do not ignore positions with gaps"); + + fprintf ( stdout, "\n +RNAfold_cmp.........compares the sec struc of in1 and in2 (computes them with alifold if missing)"); + + fprintf ( stdout, "\nMSA Post Processing___________________________________________________"); + fprintf ( stdout, "\n +force_aln filename|seq1 res1 seq2 res2"); + fprintf ( stdout, "\n .....................Forces residue 1 of seq1 to be aligned with res2 of seq 2"); + fprintf ( stdout, "\n .....................In a file, there must be one pair of interaction/line"); + fprintf ( stdout, "\n +sim_filter[_aln_Ix_iy_Cz_cw "); + fprintf ( stdout, "\n ....................._, aln is assumed"); + fprintf ( stdout, "\n ....................._I max identity to seq"); + fprintf ( stdout, "\n ....................._i min identity to seq"); + fprintf ( stdout, "\n ....................._C max cov on seq"); + fprintf ( stdout, "\n ....................._c min cov on seq"); + fprintf ( stdout, "\n +trim[_aln_%%%%50_n111_N50_T_Fn_fS_pS_max_sim_P0_K0] [string2]"); + fprintf ( stdout, "\n ....................._, aln is assumed"); + fprintf ( stdout, "\n ....................._%%%%"); + fprintf ( stdout, "\n ....................._max Or _min "); + fprintf ( stdout, "\n ....................._cov Or _sim Filter according to the coverage [Def: _sim]"); + fprintf ( stdout, "\n ....................._n "); + fprintf ( stdout, "\n ....................._N"); + fprintf ( stdout, "\n ....................._T Reorder the sequences according to a tree BEFORE triming"); + fprintf ( stdout, "\n ....................._Fn Keep only sequences that have AT LEAST ONE residue aligned"); + fprintf ( stdout, "\n ......................in the n first and n last columns. "); + fprintf ( stdout, "\n ....................._O Remove outlayers that have less than min average sim with other sequences"); + fprintf ( stdout, "\n ....................._Kn Forces the n top sequences to be kept"); + fprintf ( stdout, "\n ....................._P_ Print a summary in stderr"); + + + fprintf ( stdout, "\n .....................Keeping Sequences: Sequences provided via -in2 will be kept"); + + fprintf ( stdout, "\n .....................Keeping Sequences: Sequences whose name contains in field fS will be kept"); + fprintf ( stdout, "\n ....................._f designates a field"); + fprintf ( stdout, "\n ..................... is a Perl regular expression"); + fprintf ( stdout, "\n +aln2unalign Mode Penalty Threshold"); + fprintf ( stdout, "\n .....................Identifies all the streches less conserved than than the average"); + fprintf ( stdout, "\n .....................Mode: lower|number|unalign Act on all the resiues withs score with tree <-in2>)"); + fprintf ( stdout, "\n ......................+tree_scan help to get P1 information"); + fprintf ( stdout, "\n ......................+aln2tree help to get P2 information"); + + fprintf ( stdout, "\n .....................-in and -in2 can contain different taxons"); + fprintf ( stdout, "\n +tree2node.......... Reports the node list along with the split"); + fprintf ( stdout, "\n ..................... splits can be described with the seq order "); + fprintf ( stdout, "\n ..................... provided via -in3= "); + + fprintf ( stdout, "\n +treelist2groups.N....count all topologies within a list of trees"); + fprintf ( stdout, "\n .....................-in is in fasta format with each name being a newick file"); + fprintf ( stdout, "\n .....................-in2 can be a list of sequences used to trim the trees"); + fprintf ( stdout, "\n ......................N can be used to unresolve the trees with Depth N"); + fprintf ( stdout, "\n +treelist2lti.N.C.....Reports the average stability of each sequence neighborhood"); + fprintf ( stdout, "\n ......................Species can be selected via -in2 [Fasta file with Taxon names]"); + fprintf ( stdout, "\n ......................OR the sequences observed in C%% of the files are kept [Def: C=100]"); + + + fprintf ( stdout, "\n +treelist2seq.C.......Reports the species observed in C%% of the trees"); + fprintf ( stdout, "\n +treelist2splits......List and counts all the splits in a list of trees"); + fprintf ( stdout, "\n ......................splits can be restricted to a list of sequences provided via -in2"); + fprintf ( stdout, "\n +treelist2dmat.......outputs a distance matrix for a list of trees"); + + fprintf ( stdout, "\n +tree_compute n s....Computes a tree using the MSA provided with -in"); + fprintf ( stdout, "\n ....................n:0-9, controls the way the MSA is filtered"); + fprintf ( stdout, "\n ....................s:pam250mt|blosum62mt|categories|enthropy"); + fprintf ( stdout, "\n ....................s:controls the column evaluation in MSA"); + fprintf ( stdout, "\n +change_distances.f.f:float, sets all the distances to f in the tree"); + fprintf ( stdout, "\n +change_bootstrap n..:n=0 removes all the bootstrap values"); + fprintf ( stdout, "\n .....................:n!=0 adds a the value n to every node"); + fprintf ( stdout, "\n +tree2dpatree........Replaces tree distances with the minimum %%ID in"); + fprintf ( stdout, "\n .....................the depending subgroup. The ID is measured on an"); + fprintf ( stdout, "\n .....................-in=TREE -in2=ALN"); + fprintf ( stdout, "\n +unroot..............Removes the root in the input tree"); + fprintf ( stdout, "\n +tree2group.N.I.P....Reports all the tree subgroup with at most Nseq"); + fprintf ( stdout, "\n .....................and at min I%% identity. Output format can be read by"); + fprintf ( stdout, "\n .....................collapse_tree. New groups are named P_1, P_2..."); + fprintf ( stdout, "\n +collapse_tree.F.....Collapses trees. F is either a file or a list"); + fprintf ( stdout, "\n ..................... ..."); + fprintf ( stdout, "\n +aln2tree............Computes a tree"); + fprintf ( stdout, "\n ..ktupN|aln|sarmat ktupN: match size N to estimate distances"); + fprintf ( stdout, "\n .....................aln: Measures distances on aln"); + fprintf ( stdout, "\n .....................sarmat: expects in to be a SAR matrix of O and I"); + fprintf ( stdout, "\n ..nj | cw............Runs Neighbor Joining OR Cw to compute Tree"); + fprintf ( stdout, "\n ..dpa................Turns the tree into a daptree (+tree2dpatree)"); + fprintf ( stdout, "\n +node_sort.....Sort leafs of tree n1, by node distance"); + + + fprintf ( stdout, "\nMatrix Analysis___________________________________________________"); + fprintf ( stdout, "\n +aln2mat_diaa........computes a dinucleotide matrix on a list of aln"); + fprintf ( stdout, "\n +aln2mat.............computes a log odd matrix"); + + fprintf ( stdout, "\n +seq2lat_mat.........computes a transition matrix on seq provided via -in"); + + fprintf ( stdout, "\nStructure Analysis___________________________________________________"); + fprintf ( stdout, "\n +struc2contacts.A.B D.Displays in capitals all the residues of A"); + fprintf ( stdout, "\n ......................Less than D Angs from a residue of B"); + fprintf ( stdout, "\n ......................A and B are pdb file, D is a distance in Angs"); + fprintf ( stdout, "\n +seq2contacts.A.D.....Identifies all the residues in contact with ligands"); + fprintf ( stdout, "\n ......................Ligands are in the FASTA header of struc in"); + fprintf ( stdout, "\n ......................>Name _S_ [Target Struc] [Ligand1] [Chain] ..."); + fprintf ( stdout, "\n ......................Output: number_fasta: 0=no contact, 1=ligand 1..."); + fprintf ( stdout, "\n ......................9: residues in contact with more than 1 ligand"); + fprintf ( stdout, "\n ......................Use -output=color_html/ascii to display result"); + fprintf ( stdout, "\n +struc2nb...D.........Display a list of all the residues D appart"); + fprintf ( stdout, "\n +rm_template...V......Removes _[S|G|R]_[template] to sequence names"); + fprintf ( stdout, "\n ......................V: omitted | sequences <=> Output sequences"); + fprintf ( stdout, "\n ......................V: template <=> Output templates"); + + fprintf ( stdout, "\n +add_template.F.......Add _[S|G|R]_[template] to sequence names"); + fprintf ( stdout, "\n ......................F can either be a fasta file or an executable"); + fprintf ( stdout, "\n ......................F: File: >name _S_ template"); + fprintf ( stdout, "\n ......................F: executable: pg -infile= -outfile="); + fprintf ( stdout, "\nMatrix Comparison___________________________________________________"); + fprintf ( stdout, "\n +mat2cmp...............Returns the correlation coefficient between two matrices"); + fprintf ( stdout, "\n .......................-in mat1 -input matrix, -in2 mat2 -input2 matrix"); + fprintf ( stdout, "\n*********** INPUT FORMATS: Alignments *****************"); + fprintf ( stdout, "\n AUTOMATIC RECOGNITION"); + fprintf ( stdout, "\n perl_xxx:............. runs xxx onto the input file"); + fprintf ( stdout, "\n xxxx > outfile..xxx reads any formats, outputs fasta"); + fprintf ( stdout, "\n amps_aln saga_aln "); + fprintf ( stdout, "\n clustal_aln fasta_aln msf_aln "); + fprintf ( stdout, "\n dali_aln gotoh_aln pima_aln"); + fprintf ( stdout, "\n dialign_aln matrix conc_aln"); + fprintf ( stdout, "\n NON AUTOMATIC RECOGNITION (use the -input file to specify the format"); + fprintf ( stdout, "\n number_aln newick_tree"); + fprintf ( stdout, "\n"); + fprintf ( stdout, "\n*********** INPUT FORMATS: Sequences *****************"); + fprintf ( stdout, "\n fasta_seq dali_seq pir_seq"); + fprintf ( stdout, "\n barton_list_tc amps_sd_scores EST_fasta"); + fprintf ( stdout, "\n gor_seq gor_struc number_fasta[*]"); + fprintf ( stdout, "\n swissprot tc_lib pdb_struc"); + fprintf ( stdout, "\n"); + fprintf ( stdout, "\n*********** INPUT FORMATS: Structures *****************"); + fprintf ( stdout, "\n rna_number"); + fprintf ( stdout, "\n alifold"); + fprintf ( stdout, "\n*********** OUTPUT FORMATS: Alignments ******************"); + fprintf ( stdout, "\n compressed_aln saga_aln clustal_aln"); + fprintf ( stdout, "\n phylip_aln msf_aln fasta_aln "); + fprintf ( stdout, "\n pir_aln "); + fprintf ( stdout, "\n color_html,color_ps......colored using the struc_in file "); + fprintf ( stdout, "\n color_protogene..........colors codons"); + fprintf ( stdout, "\n color_exoset.............mixes conservation (gray) and introns (RGB)"); + fprintf ( stdout, "\n color_pdf pw_lib_saga_aln tdna_aln"); + fprintf ( stdout, "\n thread_dna_on_prot_aln"); + fprintf ( stdout, "\n"); + fprintf ( stdout, "\n*********** OUTPUT FORMATS: sequence ******************"); + fprintf ( stdout, "\n fasta_seq fasta_seq1 gotoh_seq"); + fprintf ( stdout, "\n gor_seq cache_id"); + fprintf ( stdout, "\n tblastx_db1 tblastx_db2 tblastx_db3"); + fprintf ( stdout, "\n*********** OUTPUT FORMATS: weights ******************"); + fprintf ( stdout, "\n constraints saga_pw_sd_weights nseq\n"); + fprintf ( stdout, "\n"); + fprintf ( stdout, "\n*********** OUTPUT Formats: special ****************"); + fprintf ( stdout, "\n len name statistics<_hnrglNL>"); + fprintf ( stdout, "\n sim............outputs a similarity matrix based on an id comparison of -in"); + fprintf ( stdout, "\n sim_sarmat.....in is sar matrix"); + fprintf ( stdout, "\n sim_idscore....makes dp alignment of the sequences using Blosum62mt"); + fprintf ( stdout, "\n sim_idscoreDNA.makes dp alignment of the sequences using idmat"); + fprintf ( stdout, "\n sim............if -in2 is set: in1 vs in2, idscore"); + + fprintf ( stdout, "\n code_name......Outputs a compact list of names for code/decode"); + + + + fprintf ( stdout, "\n"); + + + fprintf ( stdout, "\n"); + return EXIT_SUCCESS; + } + + argv=standard_initialisation (argv, &argc); + + + for ( a=1; a< argc; a++) + { + if (a==1 && argv[1][0]!='-') + { + sprintf( in_file, "%s", argv[a]); + } + else if ( strcmp ( argv[a], "-in_f")==0 ||strm(argv[a],"-input") ) + { + if ( strcmp ( argv[a], "-in_f")==0) fprintf ( stdout,"\nWARNING: %s deprecated, use -input instead", argv[a]); + + sprintf ( in_format, "%s", argv[a+1]); + a++; + } + + else if ( strcmp ( argv[a], "-cache")==0 ) + { + sprintf (cache, "%s", argv[a+1]); + + a++; + } + + + else if ( strcmp ( argv[a], "-exon_boundaries")==0 ) + { + + set_string_variable ("exon_boundaries", argv[a+1]); + a++; + } + else if ( strcmp ( argv[a], "-overaln_threshold")==0 ) + { + + set_int_variable ("overaln_threshold", atoi(argv[a+1])); + a++; + } + else if ( strcmp ( argv[a], "-overaln_target")==0 ) + { + + set_int_variable ("overaln_target", atoi(argv[a+1])); + a++; + } + else if ( strcmp ( argv[a], "-overaln_P1")==0 ) + { + + set_int_variable ("overaln_P1", atoi(argv[a+1])); + a++; + } + else if ( strcmp ( argv[a], "-overaln_P2")==0 ) + { + + set_int_variable ("overaln_P2", atoi(argv[a+1])); + a++; + } + else if ( strcmp ( argv[a], "-overaln_P3")==0 ) + { + + set_int_variable ("overaln_P3", atoi(argv[a+1])); + a++; + } + else if ( strcmp ( argv[a], "-overaln_P4")==0 ) + { + + set_int_variable ("overaln_P4", atoi(argv[a+1])); + a++; + } + + else if ( strcmp ( argv[a], "-in2_f")==0||strm(argv[a],"-input2") ) + { + if ( strcmp ( argv[a], "-in_f")==0) fprintf ( stdout,"\nWARNING: %s deprecated, use -input2 instead", argv[a]); + + sprintf ( in2_format, "%s", argv[a+1]); + a++; + } + else if ( strcmp ( argv[a], "-seqnos")==0) + { + sprintf (action_list[n_actions++], "seqnos"); + } + + else if ( strcmp( argv[a], "-action")==0) + { + while ((a+1)keep_case=1; + else RAD->keep_case=(strm3(argv[a], "on","ON","On"))?1:0; + + } + + else if ( strcmp ( argv[a], "-conv")==0) + { + if ( strncmp ( argv[a+1],"set",3)==0)RAD->symbol_list=make_symbols (argv[++a],&(RAD->n_symbol)); + else + { + RAD->symbol_list=declare_char (STRING, STRING); + while(!NEXT_ARG_IS_FLAG) + { + sprintf ( RAD->symbol_list[RAD->n_symbol], "%s", argv[++a]); + RAD->n_symbol++; + } + } + } + else if ( strcmp ( argv[a], "-struc_in_f")==0 ||strcmp ( argv[a], "-input3")==0 ) + { + sprintf ( struc_in_format, "%s", argv[a+1]); + a++; + } + else if ( strcmp ( argv[a], "-out_f")==0 ||strm(argv[a],"-output") ) + { + if ( strcmp ( argv[a], "-out_f")==0) fprintf (stdout, "\nWARNING: %s deprecated, use -output instead", argv[a]); + sprintf ( out_format, "%s", argv[a+1]); + a++; + } + else if ( strm ( argv[a], "-struc_out_f") || strm ( argv[a], "-output_struc") ) + { + sprintf ( struc_out_format, "%s", argv[a+1]); + a++; + } + else if ( strcmp (argv[a],"-in")==0) + { + sprintf( in_file, "%s", argv[a+1]); + a++; + } + else if ( strcmp (argv[a],"-rename")==0) + { + sprintf( rename_file, "%s", argv[a+1]); + a++; + } + else if ( strcmp (argv[a],"-code")==0) + { + code=CODE; + sprintf( rename_file, "%s", argv[a+1]); + a++; + } + else if ( strcmp (argv[a],"-decode")==0) + { + code=DECODE; + sprintf( rename_file, "%s", argv[a+1]); + a++; + } + else if ( strcmp (argv[a],"-in2")==0) + { + sprintf( in2_file, "%s", argv[a+1]); + a++; + } + else if ( strcmp (argv[a],"-coor")==0) + { + sprintf( RAD->coor_file, "%s", argv[a+1]); + a++; + } + else if (strcmp (argv[a],"-out")==0) + { + sprintf (out_file, "%s", argv[a+1]); + a++; + } + else if (strcmp (argv[a],"-out2")==0) + { + sprintf (out2_file, "%s", argv[a+1]); + a++; + } + else if ( strcmp (argv[a],"-struc_in")==0 || strcmp (argv[a],"-in3")==0 ) + { + sprintf( struc_in_file, "%s", argv[a+1]); + a++; + } + else if (strcmp (argv[a],"-struc_out")==0) + { + sprintf (struc_out_file, "%s", argv[a+1]); + a++; + } + else if ( strcmp ( argv[a], "-rm_gap")==0) + { + RAD->rm_gap=1; + } + else if ( strcmp ( argv[a], "-print_format")==0) + { + print_format=1; + } + else if ( strcmp ( argv[a], "-no_warning")==0) + { + set_warning_mode (NO); + } + + else + { + fprintf ( stdout, "\nUNKNOWN OPTION: %s", argv[a]); + myexit(EXIT_FAILURE); + } + } +/****************************************************************/ +/* */ +/* Data Preparation */ +/* */ +/* */ +/****************************************************************/ + + prepare_cache (cache); +/****************************************************************/ +/* */ +/* INPUT SEQ/ALN */ +/* */ +/* */ +/****************************************************************/ + + + if ( strm (out_format, "hasch")) + { + fprintf ( stdout, "%d\n", (int)hash_file(in_file)); + return EXIT_SUCCESS; + } + + if ( rename_file[0]) + { + rename_list=read_rename_file ( rename_file,code); + } + + + if ((D1=read_data_structure (in_format, in_file,RAD))!=NULL) + { + in_format=(in_format && in_format[0])?in_format:identify_seq_format(in_file); + + if (print_format)fprintf ( stdout, "\nFILE:%s FORMAT:%s\n", in_file, in_format); + } + else if ( in_file[0]) + { + fprintf ( stdout, "\nFORMAT of file %s Not Supported[FATAL:%s]\n", in_file, PROGRAM); + myexit(EXIT_FAILURE); + } + + if ((D2=read_data_structure (in2_format, in2_file,RAD))!=NULL){if (print_format)fprintf ( stderr, "\nFILE:%s FORMAT:%s\n", in2_file, (in2_format&&in2_format[0])?in2_format:identify_seq_format(in2_file));} + + else if (!D2 && in2_file[0]) + { + fprintf ( stderr, "\nFORMAT of file %s Not Supported [FATAL:%s]\n", in2_file, PROGRAM); + myexit(EXIT_FAILURE); + } + +/*STRUCTURE INPUT*/ + + + if ((D_ST=read_data_structure (struc_in_format, struc_in_file,RAD))) + { + + if ( D_ST->CL) + { + Constraint_list *CL; + int *entry; + + CL=D_ST->CL; + + while ((entry=extract_entry (CL))) + { + if ( D_ST->S)(D_ST->S)->seq[entry[SEQ1]][entry[R1]-1]=entry[WE]; + } + thread_seq_struc2aln (D_ST->A, D_ST->S); + } + else if ( name_is_in_list ("cons", ((D_ST)->A)->name, ((D_ST)->A)->nseq, 100)); + else + { + D_ST->A=copy_aln ( D1->A, D_ST->A); + + thread_seq_struc2aln (D_ST->A, D_ST->S); + } + } + else if ((strcmp (struc_in_format, "rna_number")==0) && in_file[0]) + { + D_ST->RNA_ST=read_rna_struc_number((D1->A),struc_in_file); + } + else if ( struc_in_format[0] && struc_in_file[0]) + { + + fprintf ( stderr, "\nSTRUC %s UNKNOWN[FATAL]", struc_in_format); + myexit(EXIT_FAILURE); + } + else + { + D_ST=vcalloc ( 1, sizeof (Sequence_data_struc)); + } + + action=declare_char(100, 100); + for ( a=0; a< n_actions;) + { + if (action_list[a][0]!='+') + { + fprintf ( stderr, "\nWARNING: Action %s Unknown. Actions start with a +", action_list[a]); + myexit (EXIT_FAILURE); + } + else + { + b=0; + sprintf ( action[b++], "%s", action_list[a++]+1); + while ( aA= rename_seq_in_aln(D1->A, rename_list); + if (D2)D2->A=rename_seq_in_aln (D2->A, rename_list); + if (D_ST)D_ST->A=rename_seq_in_aln (D_ST->A,rename_list); + + if (D1)D1->T =rename_seq_in_tree (D1->T, rename_list); + if (D2)D2->T =rename_seq_in_tree (D2->T, rename_list); + if (D_ST)D_ST->T=rename_seq_in_tree (D_ST->T,rename_list); + } + + + if ( !out_format[0] && ! struc_out_format[0])sprintf ( out_format, "%s", (in_format && in_format[0])?in_format:"fasta_aln"); + main_output ( D1, D2, D_ST, out_format, out_file); + main_output ( D1, D2, D_ST, struc_out_format, struc_out_file); + return EXIT_SUCCESS; + } + + + + +/**************************************************************************************************/ +/***************************** FORMAT GUESSING ******************************************/ +/**************************************************************************************************/ +Sequence_data_struc *read_data_structure ( char *in_format, char *in_file, Action_data_struc *RAD) + + { + Sequence_data_struc *D; + char **seq_name=NULL, **sequences=NULL; + int nseq=0, a; + + + D=vcalloc ( 1, sizeof (Sequence_data_struc)); + + + if (!in_file[0])return NULL; + if (!in_format[0]) + { + in_format=identify_seq_format(in_file); + } + if (!in_format[0])return NULL; + + + + D->A=declare_Alignment(NULL); + if ( RAD->keep_case)(D->A)->residue_case=KEEP_CASE; + + D->rm_gap=RAD->rm_gap; + sprintf ( D->format, "%s", in_format); + sprintf ( D->file, "%s", in_file); + + + + + if ( strm2(in_format,"saga_aln","clustal_aln")) + { + read_aln (in_file, D->A); + D->S=aln2seq(D->A); + + } + + else if ( strm (in_format, "treefile_list")) + { + + D->S=get_tree_file_list(in_file); + D->A=seq2aln(D->S, D->A,NO_PAD); + } + else if ( strm (in_format, "file_list") || strm (in_format, "list")) + { + D->S=get_file_list(in_file); + D->A=seq2aln(D->S, D->A,KEEP_GAP); + } + else if ( strm (in_format, "fasta_tree")) + { + + D->S=get_fasta_tree (in_file, NULL); + D->A=seq2aln(D->S, D->A,NO_PAD); + + } + else if ( strm (in_format, "tree_list") || strm (in_format, "treelist")) + { + char **line; + FILE *seq; + int n=0; + char *seq_file; + FILE *fp; + + seq_file=vtmpnam(NULL); + seq=vfopen (seq_file, "w"); + line=file2lines (in_file); + fp=vfopen (seq_file, "w"); + for ( n=1; nTree_%d\n%s\n", n,line[n]); + } + vfclose (fp); + + free_char (line, -1); + return read_data_structure ( "fasta_tree",seq_file,RAD); + } + + else if (strm (in_format, "matrix")) + { + D->M=read_matrice (in_file); + } + else if (strm4 (in_format, "newick_tree", "newick", "nh", "new_hampshire")) + { + D->T=main_read_tree (in_file); + D->S=tree2seq(D->T, NULL); + D->A=seq2aln (D->S,D->A, 0); + } + else if (strm (in_format, "blast_aln")) + { + if (read_blast_aln (in_file, D->A)) + { + D->S=aln2seq(D->A); + } + else + { + return NULL; + } + } + else if ( strm( in_format,"number_aln")) + { + read_number_aln (in_file, D->A); + D->S=aln2seq(D->A); + } + else if ( strm( in_format,"stockholm_aln")) + { + read_stockholm_aln (in_file, D->A); + D->S=aln2seq(D->A); + } + else if ( strm( in_format,"gotoh_aln")) + { + read_gotoh_aln (in_file, D->A); + D->S=aln2seq(D->A); + } + + else if ( strm ( in_format, "msf_aln")) + { + read_msf_aln (in_file, D->A); + D->S=aln2seq(D->A); + } + else if ( strm ( in_format, "amps_aln")) + { + read_amps_aln (in_file, D->A); + D->S=aln2seq(D->A); + } + else if ( strm (in_format, "excel_seq")) + { + D->S=perl_reformat2fasta ("excel2fasta.pl",in_file); + (D->S)->contains_gap=0; + D->A=seq2aln(D->S, D->A,RAD->rm_gap); + } + else if ( strm (in_format, "pavie_seq")) + { + D->S=perl_reformat2fasta ("pavie2fasta.pl",in_file); + (D->S)->contains_gap=0; + D->A=seq2aln(D->S, D->A,RAD->rm_gap); + } + else if ( strncmp (in_format, "perl_",5 )==0) + { + D->S=perl_reformat2fasta (in_format+5,in_file); + (D->S)->contains_gap=0; + D->A=seq2aln(D->S, D->A,RAD->rm_gap); + } + else if ( strm (in_format, "number_fasta")) + { + D->S=get_fasta_sequence_num (in_file, NULL); + (D->S)->contains_gap=0; + D->A=seq2aln(D->S, D->A,RAD->rm_gap); + } + else if ( strm (in_format, "raw_fasta")) + { + D->S=get_fasta_sequence_raw (in_file, NULL); + (D->S)->contains_gap=0; + D->A=seq2aln(D->S, D->A,RAD->rm_gap); + } + + else if ( strm2 (in_format, "fasta_aln", "fasta_seq")) + { + + D->S=get_fasta_sequence (in_file, NULL); + if ( strcmp (in_format, "fasta_aln")==0)(D->S)->contains_gap=0; + D->A=seq2aln(D->S, D->A,RAD->rm_gap); + } + else if ( strm (in_format, "fasta_tree")) + { + + D->S=get_fasta_tree (in_file, NULL); + D->A=seq2aln(D->S, D->A, NO_PAD); + } + + else if ( strm (in_format, "pdb") || strm (in_format, "pdb_struc")) + { + D->S=get_pdb_sequence (in_file); + if ( D->S==NULL) + { + add_warning (stderr, "FAILED TO find PDB File %s", in_file); + myexit (EXIT_FAILURE); + } + D->A=seq2aln(D->S, D->A,RAD->rm_gap); + } + else if ( strm2(in_format, "pir_seq", "pir_aln")) + { + D->S=get_pir_sequence ( in_file,NULL ); + seq2aln(D->S, D->A, RAD->rm_gap); + } + else if ( strm(in_format, "gor_seq") ) + { + D->S=get_gor_sequence ( in_file,NULL ); + seq2aln(D->S, D->A, RAD->rm_gap); + } + else if ( strm2 ( in_format, "dali_aln", "dali_seq")) + { + D->S=get_sequence_dali ( in_file); + seq2aln(D->S, D->A, RAD->rm_gap); + } + else if ( strm (in_format, "barton_list_tc")) + { + get_barton_list_tc_seq ( in_file); + } + else if ( strm (in_format, "amps_sd_scores")) + { + D->W=get_amps_sd_scores ( in_file); + } + + else if ( strm ( in_format, "pima_aln")) + { + D->S=get_pima_sequence ( in_file); + seq2aln (D->S, D->A, RAD->rm_gap); + } + else if ( strm( in_format, "gor_struc")) + { + D->S=get_struc_gor ( in_file); + seq2aln(D->S, D->A, RAD->rm_gap); + } + else if ( strm( in_format, "dialign_aln")) + { + D->S=get_dialign_sequence ( in_file); + seq2aln (D->S, D->A, RAD->rm_gap); + } + else if ( strm( in_format, "tc_lib") || strm( in_format, "mocca_lib") || strm( in_format, "lib")) + { + read_seq_in_list (in_file,&nseq,&sequences,&seq_name); + D->S=fill_sequence_struc ( nseq, sequences, seq_name); + D->CL=declare_constraint_list ( D->S,NULL, NULL, 0,NULL, NULL); + D->CL=read_constraint_list_file(D->CL,in_file); + seq2aln (D->S, D->A, RAD->rm_gap); + free_char (sequences,-1); + free_char (seq_name, -1); + } + else if ( strm( in_format,"swissprot_seq")) + { + D->S=get_swissprot_sequence ( in_file,NULL); + seq2aln (D->S, D->A, RAD->rm_gap); + } + else if (strm (in_format, "alifold")) + { + D->S=read_alifold ( in_file); + seq2aln (D->S, D->A,0); + } + else + { + return NULL; + } + + if ( D->A) + { + for ( a=0; a<(D->A)->nseq; a++)sprintf ( (D->A)->file[a], "%s", in_file); + } + if ( D->S) + { + for ( a=0; a<(D->A)->nseq; a++)sprintf ( (D->S)->file[a], "%s", in_file); + } + + return D; + } +Sequence *read_sequences (char *name) +{ + return main_read_seq (name); +} +Alignment * alifold2aln (char *file) +{ + Sequence *S; + S=read_alifold(file); + sprintf ( S->seq[0],"%s", S->seq[1]); + return seq2aln (S, NULL, 0); +} +Sequence * read_alifold (char *file) +{ + Sequence *S; + char **list; + int l; + S=declare_sequence (1,count_n_char_in_file (file),2); + list=file2lines (file); + + S->seq[0]=list[1]; + S->seq[1]=list[2]; + substitute (S->seq[0], "\n", "\0"); + substitute (S->seq[0], " ", "\0"); + substitute (S->seq[0], "_", STOCKHOLM_STRING); + l=strlen (S->seq[0]); + substitute (S->seq[1], "\n", "\0"); + substitute (S->seq[1], " ", "\0"); + substitute (S->seq[1], ".", STOCKHOLM_STRING); + S->seq[1][l]='\0'; + sprintf (S->name[0], "cons"); + sprintf (S->name[1], "#=GC SS_cons"); + return S; +} + + + + + + +Sequence * main_read_seq ( char *name) + { + char *format=NULL; + Sequence *S=NULL; + Alignment *A=NULL; + int a; + + + format=identify_seq_format (name); + + + if ( getenv4debug ("DEBUG_REFORMAT"))fprintf ( stderr, "\n\nFormat %s\n", format); + + + if (format &&strm(format, "fasta_seq")) + { + S= get_fasta_sequence ( name, NULL); + } + else if (format &&strm(format, "pir_seq")) S= get_pir_sequence ( name, NULL); + else if (format &&strm(format,"swissprot_seq"))S= get_swissprot_sequence (name, NULL); + else if (format && strstr (format, "aln")) + { + A=main_read_aln ( name, NULL); + S=aln2seq(A); + ungap_seq(S); + free_aln(A); + } + else if ( format && strstr (format, "tc_lib")) + { + int nseq,b; + char **sequences=NULL, **seq_name=NULL; + + read_seq_in_list (name,&nseq,&sequences,&seq_name); + S=fill_sequence_struc ( nseq, sequences, seq_name); + for ( b=0; b< S->nseq; b++)sprintf ( S->file[b], "%s",name); + free_char (seq_name, -1);free_char (sequences, -1); + } + else + { + /*Use The ClustalW routine*/ + S=cw_read_sequences (name); + } + + for ( a=0; anseq; a++)sprintf ( S->file[a], "%s", name); + vfree(format); + ungap_seq(S); + S=clean_sequence ( S); + return S; + } + +Alignment * main_read_aln ( char *name, Alignment *A) + { + int a; + + static char *format; + Sequence *S=NULL; + Sequence *IN_SEQ; + + + if ( !name)return NULL; + else if (!check_file_exists(name)) + { + if ( !check_file_exists (name+1))return NULL; + else if ( name[0]=='A') name++; + else if ( name[0]=='S') name++;/*Line Added for the -convert flag of T-Coffee*/ + } + + + if (!A)A=declare_aln(NULL); + format=identify_seq_format (name); + + IN_SEQ=A->S; + + if ((format && strm(format, "saga_aln" )) ||strm(format, "clustal_aln")||strm(format, "t_coffee_aln" ) ) + { + + read_aln ( name, A); + + } + else if (format && strm (format, "conc_aln"))A=input_conc_aln (name,NULL); + else if (format &&strm(format, "msf_aln" ))read_msf_aln ( name, A); + else if (format &&strm(format, "blast_aln"))read_blast_aln (name, A); + else if (format &&(strm(format, "fasta_aln"))) + { + + + S=get_fasta_sequence ( name, NULL); + + S->contains_gap=0; + seq2aln (S, A, 0); + } + else if (format &&strm(format, "pir_aln")) + { + S=get_pir_sequence ( name, NULL); + S->contains_gap=0; + seq2aln (S, A, 0); + } + else if (format && strm(format, "fasta_seq") && A) + { + S=get_fasta_sequence ( name, NULL); + + for ( a=1; anseq; a++)if ( strlen (S->seq[a-1])!=strlen (S->seq[a])){free_sequence (S, S->nseq); free_aln (A); return NULL;} + S->contains_gap=0; + seq2aln (S, A, 0); + } + + else if (format && strm(format, "pir_seq") && A) + { + S=get_pir_sequence ( name, NULL); + + for ( a=1; anseq; a++)if ( strlen (S->seq[a-1])!=strlen (S->seq[a])){free_sequence (S, S->nseq); free_aln (A); return NULL;} + S->contains_gap=0; + seq2aln (S, A, 0); + } + else + { + free_aln(A); + return NULL; + } + + + if ( check_list_for_dup( A->name, A->nseq)) + { + fprintf ( stderr, "\nWARNING (main_read_aln): %s is duplicated in File %s ", check_list_for_dup( A->name, A->nseq), A->file[0]); + A=aln2unique_name_aln(A); + } + + if (IN_SEQ)A->S=IN_SEQ; + else if (!A->S){A->S=aln2seq(A);} + + A->S=ungap_seq(A->S); + A=fix_aln_seq(A, A->S); + compress_aln (A); + for ( a=0; a< A->nseq; a++) sprintf ( A->file[a], "%s", name); + + A=clean_aln (A); + return A; + } + + +char * identify_aln_format ( char *file) + { + /*This function identify known sequence and alignmnent formats*/ + return identify_seq_format (file); + } +char * identify_seq_format ( char *file) + { + char *format=NULL; + /*This function identify known sequence and alignmnent formats*/ + + if ( format==NULL)format=vcalloc ( 100, sizeof (char)); + else format[0]='\0'; + + + + if ( !check_file_exists(file)) + { + fprintf (stderr, "ERROR: %s Does Not Exist [FATAL:%s]\n",file, PROGRAM); + myexit (EXIT_FAILURE); + } + else if ( is_stockholm_aln (file))sprintf (format, "stockholm_aln"); + else if ( is_blast_file (file))sprintf ( format, "blast_aln"); + else if ( is_pdb_file(file))sprintf ( format, "pdb_struc"); + else if ( format_is_msf (file))sprintf ( format, "msf_aln"); + else if ( format_is_fasta_seq(file))sprintf ( format, "fasta_seq"); + else if ( format_is_fasta_aln(file))sprintf ( format, "fasta_aln"); + else if ( format_is_pir_aln (file))sprintf ( format, "pir_aln"); + else if ( format_is_pir_seq (file))sprintf ( format, "pir_seq"); + else if ( format_is_oligo (file))sprintf ( format, "oligo_aln"); + else if ( format_is_swissprot (file))sprintf ( format, "swissprot_seq"); + else if ( format_is_saga (file))sprintf ( format, "clustal_aln"); + else if ( format_is_conc_aln (file))sprintf ( format, "conc_aln"); + else if ( is_lib (file))sprintf ( format, "tc_lib"); + else if ( is_lib_02 (file))sprintf ( format, "tc_lib_02"); + else if ( is_newick(file))sprintf ( format, "newick_tree"); + + else + { + //add_warning ( stderr, "\nThe Format of File: %s was not recognized [SERIOUS:%s]",file, PROGRAM); + ; + } + return format; + } +char **identify_list_format ( char **list, int n) + { + int a; + char *name; + char *string; + char mode; + + + + declare_name (name); + for ( a=0; a< n; a++) + { + + sprintf (name, "%s", list[a]); + string=list[a]; + if ((mode=identify_format ( &string))!='?') + { + sprintf ( name, "%s", string); + sprintf ( list[a], "%c%s", mode,name); + } + else + { + fprintf ( stderr, "\nERROR: %s not recognised [FATAL:%s]", name, PROGRAM); + } + + } + + vfree(name); + return list; + } + +char * name2type_name ( char *name) +{ + /*turns into , ...*/ + char *new_name; + char mode; + + new_name=vcalloc ( strlen (name)+2, sizeof (char)); + sprintf ( new_name, "%s", name); + if (is_in_set (name[0], "ALSMXPRW") && !check_file_exists(name)) + { + sprintf ( new_name, "%s", name); + } + else + { + mode=identify_format (&new_name); + sprintf ( new_name, "%c%s", mode,name); + } + return new_name; +} + +char identify_format (char **fname) + { + char mode='?'; + mode=fname[0][0]; + + if ((is_in_set (mode, "ALMSPR") && check_file_exists(fname[0]+1)) ||(mode=='X' && is_matrix ( fname[0]+1)) ||(mode=='M' && is_method(fname[0]+1)) ) + { + + fname[0]++; + } + else if (mode=='W' && !check_file_exists(fname[0])){fname[0]++;} + else + { + + /*WARNING: Order matters => internal methods can be confused with files, must be checked last*/ + if (is_lib(fname[0]))mode='L'; + else if (is_pdb_file(fname[0]))mode='P'; + else if (is_seq(fname[0]))mode='S'; + else if (is_aln(fname[0]))mode='A'; + else if (is_matrix(fname[0]))mode='X'; + else if (is_method(fname[0]))mode='M'; + else mode='?'; + } + return mode; + } + + + +int is_pdb_name ( char *name) + { + char command[1000]; + int result; + char *result_file; + static char **buf_names; + static int *buf_result; + static int nbuf; + FILE *fp; + + + /*Use the look up*/ + if ( !buf_names) + { + buf_names=declare_char (1000, 100); + buf_result=vcalloc (1000, sizeof (int)); + } + if ( (result=name_is_in_list ( name, buf_names,nbuf,100))!=-1)return buf_result[result]; + + + + result_file=vtmpnam (NULL); + + sprintf ( command, "extract_from_pdb -is_pdb_name \'%s\' > %s", name, result_file); + if ( getenv4debug ("DEBUG_EXTRACT_FROM_PDB"))fprintf ( stderr, "\n[DEBUG_EXTRACT_FROM_PDB:is_pdb_name] %s\n", command); + my_system ( command); + + fp=vfopen ( result_file, "r"); + fscanf ( fp, "%d", &result); + vfclose (fp); + vremove ( result_file); + + sprintf ( buf_names[nbuf], "%s", name); + result=buf_result[nbuf++]=(result==1)?1:0; + + return result; + + } + +char* get_pdb_id ( char *file) +{ + /*receives the name of a pdb file*/ + /*reads the structure id in the header*/ + /*returns the pdb_id*/ + char *tmp_name; + char command[10000]; + char cached [1000]; + char fname[1000]; + FILE *fp; + char *id; + char buf[1000]; + + + tmp_name=vtmpnam(NULL); + + sprintf ( cached, "%s/%s", get_cache_dir(),file); + if ( check_file_exists(cached))sprintf ( fname, "%s", cached); + else sprintf ( fname, "%s", file); + + sprintf ( command, "extract_from_pdb -get_pdb_id %s > %s",fname, tmp_name); + + if ( getenv4debug ("DEBUG_EXTRACT_FROM_PDB"))fprintf ( stderr, "\n[DEBUG_EXTRACT_FROM_PDB:get_pdb_id] %s\n", command); + my_system ( command); + + buf[0]='\0'; + fp=vfopen (tmp_name, "r"); + fscanf ( fp, "\n%s\n", buf); + vfclose (fp); + + if ( getenv4debug ("DEBUG_EXTRACT_FROM_PDB"))fprintf ( stderr, "\n[DEBUG_EXTRACT_FROM_PDB:get_pdb_id]DONE\n"); + + id=vcalloc ( strlen (buf)+1, sizeof (char)); + sprintf ( id, "%s", buf); + + + + return id; +} + + +char* get_pdb_struc(char *in_name, int start, int end) + { + char *name1,*name2; + char command[LONG_STRING]; + char *name; + + + + + name=vcalloc ( STRING, sizeof (char)); + sprintf ( name, "%s", in_name); + + if ( (name1=is_pdb_struc(name))==NULL && (name[0]=='P' && ((name1=is_pdb_struc (name+1))==NULL))) + { + fprintf ( stderr, "\nERROR Could not download structure %s [FATAL:%s]\n", name, PROGRAM);crash(""); + } + else if ( (start==0) && (end==0))return name1; + else + { + declare_name(name2); + sprintf ( name2, "%s_%d_%d.pdb", name, start, end); + sprintf ( command, "extract_from_pdb -infile \'%s\' -chain FIRST -coor %d %d > %s%s",check_file_exists(name1),start, end, get_cache_dir(),name2); + if ( getenv4debug ("DEBUG_EXTRACT_FROM_PDB"))fprintf ( stderr, "\n[DEBUG_EXTRACT_FROM_PDB:get_pdb_struc] %s\n", command); + my_system (command); + + if ( is_pdb_file(name2))return name2; + else + { + fprintf ( stderr, "\nERROR Could not extract segment [%d %d] from structure %s [FATAL:%s]\n",start, end, name, PROGRAM);crash(""); + } + myexit (EXIT_FAILURE); + } + + return NULL; + } + +char* seq_is_pdb_struc ( Sequence *S, int i) +{ + + if (!S){return NULL;} + else if ( !S->T[i]){return NULL;} + else if ( !((S->T[i])->P)){return NULL;} + else return ((S->T[i])->P)->template_file; +} +char* is_pdb_struc ( char *name) + { + /*Receives a name + checks if this is the name of a local file that contains PDB data + checks if this is the name of a file from a local db + put the file in the cache + checks if this is a file from a remote db (extract_from_pdb + return NULL if everything fails + */ + + static char *file_name1; + static char *file_name2; + + static char **buf_names; + static char **buf_result; + static int nbuf, s; + + + char *r=NULL; + char command[1000]; + + + if ( !name || name[0]=='\0')return NULL; + + + /*Use the look up*/ + if ( !buf_names) + { + + buf_names=vcalloc ( 1000, sizeof (char*)); + buf_result=vcalloc ( 1000, sizeof (char*)); + file_name1=vcalloc ( 1000, sizeof (char)); + file_name2=vcalloc ( 1000, sizeof (char)); + } + if ( (s=name_is_in_list ( name, buf_names,nbuf,-1))!=-1)return buf_result[s]; + + + r=NULL; + sprintf ( file_name1, "%s", name); + sprintf ( file_name2, "%s.pdb", name); + + + if (is_pdb_file(file_name1)){r=file_name1;} + else if (is_pdb_file(file_name2)){r=file_name2;} + else if (is_pdb_name (name)) + { + printf_system ("extract_from_pdb -netfile \'%s\' > %s/%s 2>/dev/null",name, get_cache_dir(), file_name2); + if ( is_pdb_file(file_name2))r=file_name2; + else r=NULL; + + } + + + /*Fill the buffer*/ + buf_names[nbuf]=vcalloc ( strlen (name)+1, sizeof (char)); + sprintf ( buf_names[nbuf], "%s", name); + if ( r) + { + buf_result[nbuf]=vcalloc ( strlen (r)+1, sizeof (char)); + sprintf (buf_result[nbuf], "%s", r); + } + else buf_result[nbuf]=NULL; + nbuf++; + + return r; + } + +char *fix_pdb_file ( char *in) +{ + char *empty; + + empty=vcalloc(1, sizeof(char)); + + if ( !in || !check_file_exists (in))return empty; + else if ( is_pdb_file(in))return in; + else + { + char command[10000]; + char *tmp; + char *tmp2; + tmp=vtmpnam (NULL); + tmp2=vcalloc (strlen (tmp)+1, sizeof (char)); + sprintf (tmp2, "%s", tmp); + sprintf ( command, "extract_from_pdb %s > %s", check_file_exists(in), tmp2); + my_system (command); + if ( is_pdb_file (tmp))return tmp2; + else return empty; + + } +} + +int is_sap_file ( char *name) + { + FILE *fp; + if (!name); + if (!check_file_exists(name))return 0; + + if ((fp=find_token_in_file (name, NULL, "Percent"))!=NULL) + { + if ((fp=find_token_in_file (name,fp, "Percent"))!=NULL) + { + vfclose (fp); + return 1; + } + else + { + return 0; + } + } + else + { + return 0; + } + } + + +int is_blast_file ( char *name) + { + if ( !check_file_exists(name) ) return 0; + else if (token_is_in_file (name, "")) + { + return BLAST_XML; + } + else + { + if (token_is_in_file (name, "Lambda") && token_is_in_file (name, "Altschul,")) + { + return BLAST_TXT; + } + else + { + return 0; + } + } + return 0; + } +int is_simple_pdb_file ( char *name) +{ + FILE *fp; + if ((fp=find_token_in_file (name, NULL, "SIMPLE_PDB_FORMAT"))!=NULL){vfclose (fp);return 1;} + return 0; +} + + +int is_pdb_file ( char *name) + { + FILE *fp; + int ispdb=0; + + if ( name==NULL) return 0; + if (!check_file_exists (name))return 0; + + if ((fp=find_token_in_file (name, NULL, "\nHEADER"))!=NULL) + {vfclose (fp); + ispdb++; + } + if ((fp=find_token_in_file (name, NULL, "\nSEQRES"))!=NULL) + { + vfclose (fp); + ispdb++; + } + + if ((fp=find_token_in_file (name, NULL, "\nATOM"))!=NULL) + { + vfclose (fp); + ispdb++; + } + else + { + ispdb=0; + } + + + if ( ispdb>=2)return 1; + else return 0; + } +int is_seq ( char *name) + { + char *format; + + if ( !check_file_exists(name))return 0; + + format= identify_seq_format(name); + if(!format || format[0]=='\0'){vfree (format);return 0;} + else if (strstr(format, "seq")){vfree (format);return 1;} + else return 0; + } +int is_aln ( char *name) + { + char *format; + if ( !check_file_exists (name))return 0; + + format= identify_seq_format(name); + if ( !format || format[0]=='\0'){vfree (format);return 0;} + else if (strstr(format, "aln")){vfree (format); return 1;} + else return 0; + } + +int is_matrix (char *name) + { + int **m; + + if ((m=read_matrice (name))!=NULL){free_int (m, -1); return 1;} + return 0; + } +int is_newick (char *name) + { + int c; + FILE *fp; + + + fp=vfopen (name, "r"); + if ( (c=fgetc(fp))!='('){vfclose (fp); return 0;} + + + while ( (c=fgetc(fp))!=EOF) + { + if ( c==';'){vfclose (fp); return 1;} + } + vfclose (fp); + return 0; + } + +int is_clustalw_matrix ( char *name) +{ + + FILE *fp; + + + if ( (fp=find_token_in_file (name, NULL, "CLUSTALW_MATRIX"))!=NULL){vfclose(fp);return 1;} + else return 0; +} +int is_pavie_matrix ( char *name) +{ + + FILE *fp; + + + if ( (fp=find_token_in_file (name, NULL, "PAVIE_MATRIX"))!=NULL){vfclose(fp);return 1;} + else return 0; +} +int is_distance_matrix_file (char *name) +{ + FILE *fp; + if ( (fp=find_token_in_file (name, NULL, "TC_DISTANCE_MATRIX_FORMAT_01"))!=NULL){vfclose(fp);return 1;} + else return 0; +} +int is_similarity_matrix_file (char *name) +{ + FILE *fp; + if ( (fp=find_token_in_file (name, NULL, "TC_SIMILARITY_MATRIX_FORMAT_01"))!=NULL){vfclose(fp);return 1;} + else return 0; +} +int is_blast_matrix ( char *name) +{ + + FILE *fp; + + + if ( (fp=find_token_in_file (name, NULL, "BLAST_MATRIX"))!=NULL){vfclose(fp);return 1;} + else return 0; +} + +int is_single_seq_weight_file ( char *name) +{ + + + return token_is_in_file ( name, "SINGLE_SEQ_WEIGHT_FORMAT_01"); + +} +int is_stockholm_aln (char *file) +{ + FILE *fp; + + if ((fp=find_token_in_file_nlines (file, NULL, "STOCKHOLM",2))) + { + vfclose (fp); + return 1; + } + return 0; +} + +int is_lib ( char *name) +{ + return is_lib_01(name); +} + +int is_lib_02 ( char *name) +{ + + return token_is_in_file ( name, "TC_LIB_FORMAT_02"); + +} + +int is_lib_01 (char *name) + { + + + if ( token_is_in_file ( name, "TC_LIB_FORMAT_01")) return 1; + else if (token_is_in_file ( name, "T-COFFEE_LIB_FORMAT_01"))return 1; + else if (token_is_in_file (name, "SEQ_1_TO_N"))return 1; + else return 0; + } +int is_lib_list ( char *name) +{ + if ( !check_file_exists (name))return 0; + if ( token_is_in_file ( name, "TC_LIB_LIST_FORMAT_01")) return 1; + return 0; +} +int is_method ( char *file) + { + char new_file[200]; + + + sprintf ( new_file, "%s", file); + if ( (token_is_in_file(new_file, "TC_METHOD_FORMAT_01"))){return 1;} + if ( is_in_pre_set_method_list(new_file)) + { + + vremove ( new_file); + return 1; + } + else + { + + return 0; + } + } + +/*******************************************************************************************/ +/* */ +/* */ +/* SEQUENCE FORMAT IDENTIFIERS */ +/* */ +/***************************************************************************************** */ +int type_is_exon_boundaries(char **seq, int n) +{ + int a, l, b; + for (a=0; aseq[0]){free_sequence (S, S->nseq); return 1;} + l=strlen ( S->seq[0]); + for ( a=0; a< S->nseq; a++)if(strlen(S->seq[a])!=l){free_sequence (S, S->nseq);return 1;} + for ( a=0; a< S->nseq; a++) + { + l1=strlen ( S->seq[a]); + ungap (S->seq[a]); + l2=strlen ( S->seq[a]); + if ( l1!=l2) + { + free_sequence (S, S->nseq); + return 0; + } + } + free_sequence (S, S->nseq); + return 1; + } + else + { + return 0; + } + } + +int format_is_fasta ( char *file) + { + Sequence *S; + + if ( !check_file_exists(file))return 0; + + if ( get_first_non_white_char (file)!='>')return 0; + if ( !(S=get_fasta_sequence (file, NULL)))return 0; + free_sequence (S, -1); + if ( format_is_pir(file)) return 0; + return 1; + } + +int format_is_pir_aln ( char *file) + + { + if ( format_is_pir(file) && !format_is_pir_seq(file))return 1; + else return 0; + } + +int format_is_pir_seq ( char *file) + { + int a, l1, l2; + Sequence *S; + + + if ( format_is_pir (file)) + { + S=get_pir_sequence (file, NULL); + for ( a=0; a< S->nseq; a++) + { + l1=strlen ( S->seq[a]); + ungap (S->seq[a]); + l2=strlen ( S->seq[a]); + if ( l1!=l2) + { + free_sequence (S, S->nseq); + return 0; + } + } + return 1; + } + else + { + return 0; + } + } + + +int format_is_pir ( char *file) + { + Sequence *S; + int pir_name=1, star_end=1, a; + + S=get_fasta_sequence (file, NULL); + if (!S)return 0; + else if (!S->seq[0])return 0; + + pir_name=1; star_end=1; + for (a=0; a< S->nseq; a++) + { + int l; + if (!is_pir_name(S->name[a]))pir_name=0; + l=strlen (S->seq[a]); + if (!l || (l && S->seq[a][l-1]!='*')) + star_end=0; + } + free_sequence(S,-1); + if ( pir_name && star_end) return 1; + else return 0; + } +int is_pir_name (char *name) +{ + if ( strstr (name, "P1;"))return 1; + if ( strstr (name, "F1;"))return 1; + if ( strstr (name, "DL;"))return 1; + if ( strstr (name, "DC;"))return 1; + if ( strstr (name, "RL;"))return 1; + if ( strstr (name, "RC;"))return 1; + if ( strstr (name, "XX;"))return 1; + return 0; +} + + +int format_is_conc_aln (char *file) +{ + FILE *fp; + if ( (fp=find_token_in_file (file, NULL, "CONC_MSF_FORMAT_01"))){vfclose (fp); return 1;} + return 0; +} +int format_is_saga ( char *file) + { + FILE *fp; + int **list; + int n_blocks; + int n_seq; + int a, b; + + if ( (fp=find_token_in_file (file, NULL, "SAGA"))){vfclose (fp); return 1;} + else if ((fp=find_token_in_file (file, NULL, "CLUSTAL"))){vfclose (fp); return 1;} + else if ((fp=find_token_in_file (file, NULL, "ClustalW"))){vfclose (fp); return 1;} + else if ((fp=find_token_in_file (file, NULL, "clustalw"))){vfclose (fp); return 1;} + else if ((fp=find_token_in_file (file, NULL, "clustal"))){vfclose (fp); return 1;} + else if ((fp=find_token_in_file (file, NULL, "T-COFFEE_MSA"))){vfclose (fp); return 1;} + else if ((fp=find_token_in_file (file, NULL, "INTERLEAVED_MSA"))){vfclose (fp); return 1;} + + else return 0; + + if (1==1); + else if ((fp=find_token_in_file (file, NULL, "T-COFFEE"))){vfclose (fp); return 1;} + else if ((fp=find_token_in_file (file, NULL, "SAGA_FORMAT"))){vfclose (fp); return 1;} + else if ((fp=find_token_in_file (file, NULL, "GARP"))){vfclose (fp); return 1;} + else if ((fp=find_token_in_file (file, NULL, "INTERLEAVED"))){vfclose (fp); return 1;} + + else + { + list=get_file_block_pattern (file,&n_blocks,100); + if (n_blocks<=2){free_int (list, -1);return 0;} + else + { + n_seq=list[1][0]; + for ( a=1; a< n_blocks-1; a++) + { + if ( list[a][0]!=n_seq){free_int (list, -1);return 0;} + else + { + for ( b=1; b<=list[a][0]; b++) + if ( list[a][b]!=2){free_int (list, -1);return 0;} + } + } + } + return 1; + } + + return 0; + } + + +int format_is_swissprot (char *name) + { + FILE *fp; + + if ( !check_file_exists(name))return 0; + + + + + if ( (fp=find_token_in_file_nlines (name,NULL,"\nID ",10))!=NULL\ + &&(fp=find_token_in_file (name,NULL,"\nSQ "))!=NULL ) + { + + vfclose (fp);return 1; + } + else + { + return 0; + } + } + +/*******************************************************************************************/ +/* */ +/* */ +/* OUTPUT STUFF */ +/* */ +/***************************************************************************************** */ +int output_format_aln ( char *format, Alignment *inA, Alignment *inEA,char *name) + { + Sequence_data_struc *D1=NULL; + Sequence_data_struc *D2=NULL; + Alignment *A=NULL; + Alignment *EA=NULL; + + + A =copy_aln (inA, NULL); + A->CL=inA->CL; + EA=copy_aln (inEA,NULL); + A =expand_aln(A); + EA=expand_number_aln(inA,EA); + + + if (A && A->expanded_order )A=reorder_aln ( A, A->expanded_order,A->nseq); + if (EA && EA->expanded_order)EA=reorder_aln ( EA, EA->expanded_order,EA->nseq); + + + D1=vcalloc ( 1, sizeof (Sequence_data_struc)); + D1->A=A; + if (EA) + { + D2=vcalloc ( 1, sizeof (Sequence_data_struc)); + D2->A=EA; + } + + main_output ( D1, NULL,D2, format, name); + + vfree(D1); + vfree(D2); + free_aln (A); + free_aln (EA); + return 1; + } +int main_output (Sequence_data_struc *D1, Sequence_data_struc *D2, Sequence_data_struc *DST, char *out_format, char *out_file) + + { + FILE *fp; + int value; + Alignment *BUF_A; + int expanded=0; + + if ( !out_format[0])return 0; + if ( D1 && D1->rm_gap)ungap_aln ((D1->A)); + + if ( (strstr (out_format, "expanded_"))) + { + if (!D1) return 1; + out_format+=strlen ("expanded_"); + BUF_A=copy_aln (D1->A, NULL); + (D1->A)=thread_profile_files2aln ((D1->A), NULL, NULL); + expanded=1; + } + + if ( strm (out_format, ""))return 0; + else if ( ( strm (out_format, "aln2lib"))) + { + int a, b, c; + int r1,r2,s1, s2,s; + Constraint_list *CL; + FILE *fp; + Alignment *IN; + int **pos; + + if (!D1)return 1; + IN=D1->A; + CL=(D1->A)->CL; + pos=aln2pos_simple(IN, IN->nseq); + fp=vfopen (out_file, "w"); + fp=save_list_header (fp,CL); + + + for ( b=0; b< IN->nseq-1; b++) + { + for ( c=b+1; c< IN->nseq; c++) + { + s1=IN->order[b][0]; + s2=IN->order[c][0]; + fprintf ( fp, "#%d %d\n", s1+1, s2+1); + for ( a=0; a< IN->len_aln; a++) + { + r1=pos[b][a]; + r2=pos[c][a]; + + if ( s1==s2 && !CL->do_self)continue; + + if ( s1< s2)s=(CL->evaluate_residue_pair)( CL, s1, r1, s2, r2); + else s=(CL->evaluate_residue_pair)( CL, s2, r2, s1, r1); + + s=(s!=UNDEFINED)?s:0; + if ( r1>0 && r2>0) + { + fprintf (fp, "\t%5d %5d %5d \n", r1, r2, s); + } + } + } + } + vfclose (save_list_footer (fp, CL)); + } + else if ( strncmp (out_format, "score",5)==0 || strm (out_format, "html")) + { + Alignment *BUF; + + if (!D1)return 1; + if ( !DST) + { + fprintf ( stderr,"\n[You Need an evaluation File: Change the output format or use +evaluate][FATAL:%s]\n", PROGRAM); + myexit(EXIT_FAILURE); + } + if ( !strm ("html", out_format))while ( out_format[0]!='_' && out_format[0]!='\0' )out_format++; + + D1->S=aln2seq(D1->A); + BUF=copy_aln (DST->A, NULL); + DST->A=aln2number (DST->A); + + if ( strstr ( out_format, "html" ))output_reliability_html ( D1->A, DST->A, out_file); + else if( strm ( out_format, "_ps" ))output_reliability_ps ( D1->A, DST->A, out_file); + else if( strm ( out_format, "_pdf" ))output_reliability_pdf ( D1->A, DST->A, out_file); + else if( strm ( out_format, "_ascii" ))output_reliability_ascii ( D1->A, DST->A, out_file); + else if( strm ( out_format, "_seq" ))output_seq_reliability_ascii ( D1->A, DST->A, out_file); + else + { + DST->A=BUF; + main_output (DST, NULL, NULL, out_format+1, out_file); + } + } + else if (strm (out_format, "sec_html") || strm (out_format, "_E_html")) + { + Alignment *ST, *A; + Sequence *S; + + int a, b,c,i, ns=0; + char *buf; + if (!D1)return 1; + A=D1->A; + + + S=A->S; + ST=copy_aln (A, NULL); + for (a=0; anseq; a++) + { + i=name_is_in_list (ST->name[a],S->name, S->nseq, 100); + if ( i!=-1) + { + buf=seq2E_template_string(S, i); + if ( buf==NULL)continue; + else ns++; + for (c=0,b=0; blen_aln; b++) + { + int r1, s; + r1=ST->seq_al[a][b]; + if ( r1!='-') + { + s=tolower (buf[c]); + if (s=='e')r1='0'; + else if (s=='h')r1='9'; + else if (s=='c')r1='5'; + c++; + } + ST->seq_al[a][b]=r1; + } + } + } + + if (!ns) + { + add_warning ( stderr, "Cannot output tm_html:_E_ template file (sec. struc.) is required for this output ", PROGRAM); + } + output_color_html ( A, ST, out_file); + } + else if (strm (out_format, "tm_html") || strm (out_format, "_T_html")) + { + Alignment *ST, *A; + Sequence *S; + + int a, b,c,i, ns=0; + char *buf; + if (!D1)return 1; + A=D1->A; + A->output_tm = 1; + + S=A->S; + ST=copy_aln (A, NULL); + for (a=0; anseq; a++) + { + i=name_is_in_list (ST->name[a],S->name, S->nseq, 100); + if ( i!=-1) + { + buf=seq2T_template_string(S, i); + if ( buf==NULL)continue; + else ns++; + for (c=0,b=0; blen_aln; b++) + { + int r1, s; + r1=ST->seq_al[a][b]; + if ( r1!='-') + { + s=tolower (buf[c]); + if (s=='o')r1='0'; + else if (s=='h')r1='9'; + else if (s=='i')r1='5'; + c++; + } + ST->seq_al[a][b]=r1; + } + } + } + + if (!ns) + { + add_warning ( stderr, "Cannot output tm_html:_T_ template file (trans. Memb. ) is required for this output ", PROGRAM); + } + output_color_html ( A, ST, out_file); + } + + else if (strm (out_format, "color_exoset")) + { + Alignment *ST, *EX, *A; + Constraint_list *CL; + int a, b, n; + char *buf; + + if ( !DST->A) + { + printf_exit ( EXIT_FAILURE, stderr, "\nYou must provide an obj file via the -struc_in flag [FATAL:%s]", PROGRAM); + } + EX=DST->A; + A=D1->A; + + CL=declare_constraint_list ( DST->S,NULL, NULL, 0,NULL, read_matrice("pam250mt")); + + ST=copy_aln (A, NULL); + buf=vcalloc ( EX->len_aln+1, sizeof (int)); + + for ( a=0; a< A->nseq; a++) + { + int i; + + i=name_is_in_list (A->name[a],EX->name, EX->nseq, -1); + if ( i==-1)continue; + + sprintf ( buf, "%s", EX->seq_al[i]); + ungap (buf); + + for (n=0,b=0; blen_aln; b++) + { + if (!is_gap(A->seq_al[a][b])) + { + if ( buf[n]=='o') + ST->seq_al[a][b]='0'; + else if ( buf[n]=='j') + ST->seq_al[a][b]='1'; + else if ( buf[n]=='b') + ST->seq_al[a][b]='2'; + n++; + } + } + } + vfree (buf); + + output_color_html ( A, ST, out_file); + return EXIT_SUCCESS; + } + + else if (strm (out_format, "color_protogene")) + { + int n, a, b; + DST->A=copy_aln (D1->A, NULL); + for (n=1,a=0; a< (D1->A)->len_aln; a++, n++) + { + for ( b=0; b<(D1->A)->nseq; b++) + { + if (is_gap((D1->A)->seq_al[b][a])); + else if ( n<=3)(DST->A)->seq_al[b][a]=2; + else if ( n>3)(DST->A)->seq_al[b][a]=9; + } + + if ( n==6)n=0; + } + output_color_html ( D1->A, DST->A, out_file); + return EXIT_SUCCESS; + + } + else if ( strncmp (out_format, "color",5)==0) + { + Alignment *BUF; + + if (!D1)return 1; + + if ( !DST) + { + fprintf ( stderr,"\n[You Need an evaluation File: Change the output format or use +evaluate][FATAL:%s]\n", PROGRAM); + myexit(EXIT_FAILURE); + } + while ( out_format[0]!='_' && out_format[0]!='\0' )out_format++; + + BUF=copy_aln (DST->A, NULL); + + + + + if ( strm ( out_format, "_html" ))output_color_html ( D1->A, DST->A, out_file); + else if( strm ( out_format, "_ps" ))output_color_ps ( D1->A, DST->A, out_file); + else if( strm ( out_format, "_pdf" ))output_color_pdf ( D1->A, DST->A, out_file); + else if( strm ( out_format, "_ascii" ))output_color_ascii ( D1->A, DST->A, out_file); + else + { + DST->A=BUF; + return main_output (DST, NULL, NULL, out_format+1, out_file); + } + return EXIT_SUCCESS; + } + else if ( strm4 ( out_format, "tc_aln","t_coffee_aln", "t_coffee", "tcoffee")) + { + if (!D1)return 1; + vfclose (output_aln ( D1->A, vfopen (out_file, "w"))); + } + else if ( strm ( out_format, "analyse_pdb")) + { + if (!D1)return 1; + if ( !DST) + { + fprintf ( stderr,"\n[You Need an evaluation File: Change the output format][FATAL:%s]\n", PROGRAM); + myexit(EXIT_FAILURE); + } + analyse_pdb ( D1->A,DST->A, "stdout"); + (DST->A)=aln2number (DST->A); + output_reliability_ps ( D1->A, DST->A, out_file); + } + else if ( strm4 ( out_format, "lower0", "lower1", "lower2", "lower3") || strm4(out_format, "lower4", "lower5", "lower6", "lower7") || strm4 (out_format,"lower8", "lower9", "align_pdb", "malign_pdb") ) + { + if (!D1)return 1; + if ( !DST) + { + fprintf ( stderr,"\n[You Need an evaluation File: Change the output format][FATAL:%s]\n", PROGRAM); + myexit(EXIT_FAILURE); + } + + + + (DST->A)=aln2number (DST->A); + if ( strm (out_format, "align_pdb"))value=0; + else if ( strm (out_format, "malign_pdb"))value=5; + else value=atoi(out_format+5); + + D1->A=filter_aln_upper_lower (D1->A, DST->A,0, value); + output_clustal_aln ( out_file, D1->A); + } + else if ( strnm (out_format, "repeat", 6)) + { + int size; + int a, b, c; + Alignment *CONC; + + if ( !D1)return 1; + size=atoi (out_format+6); + print_aln (D1->A); + CONC=declare_aln2 ( (D1->A)->nseq, ((D1->A)->len_aln+1)*size+1); + + for ( a=0; a< (D1->A)->nseq; a++)(D1->A)->seq_al[a][(D1->A)->len_aln]='\0'; + for ( c=0,a=0; a< (D1->A)->nseq;c++) + { + + sprintf ( CONC->name[c], "%s", (D1->A)->name[a]); + for ( b=0; bseq_al[c], (D1->A)->seq_al[a]); + strcat (CONC->seq_al[c], "O"); + } + } + CONC->nseq=c;CONC->len_aln=strlen (CONC->seq_al[0]); + output_clustal_aln ( out_file, CONC); + free_aln (CONC); + } + + else if ( strnm (out_format, "upper", 5)) + { + + if (!D1)return 1; + if ( !DST) + { + fprintf ( stderr,"\n[You Need an evaluation File: Change the output format][FATAL:%s]\n", PROGRAM); + myexit(EXIT_FAILURE); + } + + + (DST->A)=aln2number (DST->A); + + value=atoi(out_format+5); + + D1->A=filter_aln_lower_upper (D1->A, DST->A,0, value); + output_clustal_aln ( out_file, D1->A); + } + + else if ( strm4 ( out_format, "filter0", "filter1", "filter2", "filter3")) + { + if (!D1)return 1; + if ( !DST) + { + fprintf ( stderr,"\n[You Need an evaluation File: Change the output format][FATAL:%s]\n", PROGRAM); + myexit(EXIT_FAILURE); + } + + (DST->A)=aln2number (DST->A); + + D1->A=filter_aln (D1->A, DST->A, atoi(out_format+6)); + output_clustal_aln ( out_file, D1->A); + } + + else if ( strm3 ( out_format, "phylip_aln", "phylip", "phy")) + { + if (!D1)return 1; + output_phylip_aln ( out_file, D1->A); + } + else if ( strm ( out_format, "mocca_aln")) + { + if (!D1)return 1; + output_mocca_aln ( out_file, D1->A, DST->A); + } + else if ( strm ( out_format, "saga_pw_sd_weights") ) + { + if (!D1)return 1; + output_pw_weights4saga ((D1->W),(D1->W)->PW_SD, out_file); + } + else if ( strm ( out_format, "saga_aln")) + { + if (!D1)return 1; + output_saga_aln (out_file, D1->A); + } + else if (strm2 ( out_format, "aln","clustal_tc")|| strm (out_format, "msa")) + { + + if (!D1)return 1; + output_clustal_aln (out_file, D1->A); + } + else if (strm5 ( out_format, "strict_clustal","clustal_aln", "clustalw","clustal", "clustalw_aln") || strm (out_format,"number_aln")) + { + if (!D1)return 1; + output_strict_clustal_aln (out_file, D1->A); + } + else if ( strm ( out_format, "conc_aln")) + { + if (!D1)return 1; + output_conc_aln (out_file, D1->A); + } + else if ( strm2 ( out_format, "lalign_aln","lalign")) + { + if (!D1)return 1; + output_lalign (out_file, D1->A); + } + else if ( strm2 ( out_format, "glalign_aln","glalign")) + { + if (!D1)return 1; + output_glalign (out_file, D1->A, DST->A); + } + + else if ( strm2 ( out_format, "fasta_aln","fasta" ) || strm (out_format, "blast_aln")) + { + if (!D1)return 1; + output_fasta_aln( out_file, D1->A); + } + else if ( strstr (out_format, "overaln")) + { + + char *s, mode[100]; + OveralnP *F; + int eb=0; + if (!D1) return 1; + F=vcalloc (1, sizeof (OveralnP)); + ungap_aln (D1->A); + string_array_upper ((D1->A)->seq_al, (D1->A)->nseq); + if ( D2 && D2->A) + { + D1->A=mark_exon_boundaries (D1->A, D2->A); + eb=1; + } + else if ( (s=get_string_variable ("exon_boundaries"))) + { + Sequence *S; + Alignment *EB; + EB=seq2aln(S=main_read_seq(s),NULL, 0); + D1->A=mark_exon_boundaries (D1->A, EB); + free_sequence (S, S->nseq); free_aln (EB); + eb=1; + } + if ( strstr (out_format, "lower")) sprintf (F->mode,"lower"); + else if (strstr (out_format, "unalign2"))sprintf (F->mode, "unalign2"); + else if (strstr (out_format, "unalign"))sprintf (F->mode, "unalign"); + else sprintf (F->mode, "%s", ((s=get_string_variable ("overaln_mode")))?s:"lower"); + if (!strm (F->mode, "lower") && !strm (F->mode, "unalign") && !strm (F->mode, "unalign2"))printf_exit (EXIT_FAILURE,stderr,"\nERROR: unknown overaln_mode in overaln output [%s] [FATAL:%s]", mode, PROGRAM); + + if (int_variable_isset ("overaln_threshold"))F->t=get_int_variable ("overaln_threshold"); + if (int_variable_isset ("overaln_target"))F->f=get_int_variable ("overaln_target"); + if (int_variable_isset ("overaln_P1"))F->p1=get_int_variable ("overaln_P1"); + if (int_variable_isset ("overaln_P2"))F->p2=get_int_variable ("overaln_P2"); + if (int_variable_isset ("overaln_P3"))F->p3=get_int_variable ("overaln_P3"); + if (int_variable_isset ("overaln_P4"))F->p4=get_int_variable ("overaln_P4"); + + if (eb)sprintf (F->model, "fsa2"); + else sprintf (F->model, "fsa1"); + D1->A=aln2clean_pw_aln (D1->A, F); + + //if (eb)D1->A=aln2clean_pw_aln (D1->A, mode,t, f,p1,p2,p3, "fsa2"); + //else D1->A=aln2clean_pw_aln (D1->A, mode,t, f,p1,p2,p3, "fsa1"); + + D1->S=aln2seq(D1->A); + output_clustal_aln (out_file, D1->A); + } + else if ( strm ( out_format, "est_prf" )) + { + if (!D1)return 1; + output_est_prf( out_file, D1->A); + } + else if ( strm ( out_format, "clean_est_fasta_seq" )) + { + if (!D1)return 1; + D1->A=clean_est(D1->A); + output_fasta_seq(out_file, D1->A); + + } + + else if ( strm3 ( out_format, "msf_aln", "gcg", "msf")) + { + if (!D1)return 1; + output_msf_aln( out_file, D1->A); + } + else if ( strm ( out_format, "rnalign")) + { + if (!D1)return 1; + output_rnalign (out_file, D1->A, DST->S); + } + else if ( strm ( out_format, "tblastx_db1")) + { + seq2tblastx_db (out_file,D1->S,1); + } + else if ( strm ( out_format, "tblastx_db") || strm (out_format, "tblastx_db3")) + { + seq2tblastx_db (out_file,D1->S,3); + } + else if ( strm ( out_format, "tblastx_db2")) + { + seq2tblastx_db (out_file,D1->S,2); + } + else if ( strm ( out_format, "fasta_seq") ||strm ( out_format, "list")||strm ( out_format, "file_list")) + { + + if (!D1)return 1; + output_fasta_seq (out_file,D1->A); + } + else if (strm (out_format, "fasta_tree") ) + { + if (!D1)return 1; + output_fasta_tree (out_file,D1->A); + } + + else if ( strm ( out_format, "gotoh_seq")) + { + if (!D1)return 1; + output_gotoh_seq (out_file,D1->A); + } + else if ( strm (out_format, "fasta_seq1")) + { + if (!D1)return 1; + output_fasta_seq1 (out_file, D1->A); + } + else if ( strm2 (out_format, "pir_aln", "pir")) + { + if (!D1)return 1; + output_pir_aln (out_file, D1->A); + } + else if ( strm (out_format, "pir_seq")) + { + if (!D1)return 1; + output_pir_seq (out_file, D1->A); + } + else if ( strm (out_format, "gor_seq")) + { + if (!D1)return 1; + output_gor_seq (out_file, D1->A); + } + else if ( strm (out_format, "pir_seq1")) + { + if (!D1)return 1; + output_pir_seq1 (out_file, D1->A); + } + else if ( strm (out_format, "pw_lib_saga_aln")) + { + if (!D1)return 1; + output_pw_lib_saga_aln (out_file, D1->A); + } + else if ( strm (out_format, "lib")) + { + if (!D1)return 1; + output_lib (out_file, D1->A); + } + else if ( strm (out_format, "pdb_constraint_list")) + { + if (!D1)return 1; + output_constraints (out_file, "pdb",D1->A); + } + else if ( strm2 (out_format, "constraint_list","tc_lib")) + { + + if (!D1)return 1; + else if (!D1->CL)output_constraints (out_file,"sim", D1->A); + else if (D1->CL) vfclose ( save_constraint_list ( D1->CL, 0, (D1->CL)->ne, out_file, NULL, "ascii",(D1->CL)->S)); + } + else if ( strm2 (out_format, "extended_lib","extended_cosmetic")) + { + if (!D1)return 1; + output_constraints (out_file,out_format, D1->A); + } + else if ( strncmp (out_format, "extended_pair", 13)==0) + { + if (!D1)return 1; + output_constraints (out_file,out_format, D1->A); + } + else if ( strm (out_format, "cache_id")) + { + if (!D1)return 1; + cache_id (D1->A); + output_saga_aln (out_file, D1->A); + } + else if ( strm (out_format, "compress_aln")) + { + if (!D1)return 1; + compress_aln (D1->A); + output_saga_aln (out_file, D1->A); + } + else if (strm (out_format, "n_seq") ||strm (out_format, "nseq") ) + { + if (!D1)return 1; + fp=vfopen ( out_file, "w"); + fprintf ( fp, "%d\n", (D1->A)->nseq); + vfclose (fp); + } + + else if ( strm ( out_format, "thread_dna_on_prot_aln")) + { + if (!D1)return 1; + D1->A=thread_dnaseq_on_prot_aln (D1->S, D2->A); + output_saga_aln ( out_file, D1->A); + } + else if ( strm ( out_format, "tdna_fasta_seq1")) + {if (!D1)return 1; + D1->A=translate_dna_aln (D1->A,0); + output_fasta_seq1 (out_file, D1->A); + } + else if (strm (out_format, "exons")) + { + Alignment *A; + //exons come in upper case + //output alternates them upper/lower + if (!D1)return 1; + A=copy_aln (D1->A, NULL); + A->seq_al=gene2exons(A->seq_al,A->nseq); + output_fasta_seq (out_file,A); + free_aln (A); + } + else if ( strm (out_format, "wexons")) + { + if (!D1)return 1; + output_wexons (out_file,D1->A); + + } + else if ( strm (out_format, "texons")) + { + Alignment *A; + Sequence *S; + //exons come in upper case + //output alternate amino acids in upper/lower case + //amino acid has the case of its first nucleotide + if (!D1)return 1; + A=copy_aln (D1->A, NULL); + A->seq_al=gene2exons(A->seq_al,A->nseq); + S=aln2seq(A); + output_fasta_seqS (out_file,S=translate_dna_seqS(S,1,'X')); + } + else if ( strm (out_format, "sexons")) + { + Alignment *A; + + //exons come in upper case + //output alternate amino acids in upper/lower case + //amino acid has the case of its first nucleotide + if (!D1)return 1; + A=copy_aln (D1->A, NULL); + output_fasta_seq ( out_file, D1->A); + } + + else if ( strm ( out_format, "tdna_aln")) + {if (!D1)return 1; + D1->A=translate_dna_aln (D1->A,0); + output_saga_aln ( out_file, D1->A); + } + else if ( strm ( out_format, "cdna_fasta_seq1")) + {if (!D1)return 1; + D1->A= gene2prot(D1->A); + output_fasta_seq1 ( out_file, D1->A); + } + else if ( strm ( out_format, "mutate_cdna_aln")) + {if (!D1)return 1; + D1->A= mutate_cdna_aln ( D1->A); + output_clustal_aln ( out_file, D1->A); + } + else if ( strm ( out_format, "tdna_sp_aln")) + { if (!D1)return 1; + if ( !DST) + { + fprintf ( stderr,"\n[You Need an evaluation File: Change the output format][FATAL:%s]\n", PROGRAM); + myexit(EXIT_FAILURE); + } + (DST->A)=aln2number (DST->A); + D1->A=translate_splice_dna_aln (D1->A, DST->A); + output_saga_aln ( out_file, D1->A); + } + else if (out_format && out_format[0] && (strcmp ( out_format,"rna_graph_fasta")==0)) + { + if (!D1)return 1; + sprintf ( (D1->A)->seq_al[0], "%s",(DST->S)->seq[0]); + (D1->A)->nseq=0; + output_fasta_seq (out_file, DST->A); + } + else if (strm ( out_format, "freq_mat")) + { + if (!D1)return 1; + output_freq_mat (out_file, D1->A); + } + else if (strm ( out_format, "maln_pval")) + {if (!D1)return 1; + output_maln_pval ( out_file, D1->A); + } + else if ( strm ( out_format, "model_aln")) + { + if (!D1)return 1; + output_model_aln ( out_file, D1->A); + } + else if (strncmp (out_format, "mult",4)==0) + { + if (!D1)return 1; + output_mult_fasta_seq ( out_file, D1->A, atoi(out_format+4)); + } + else if (strm (out_format, "conservation")) + { + output_conservation_statistics (out_file, D1->A); + } + else if (strm (out_format, "len")) + { + if (!D1)return 1; + output_statistics (out_file, D1->A, "nrl"); + } + else if ( strm (out_format, "name")) + { + if (!D1)return 1; + if ( D1->A)output_statistics (out_file, D1->A, "n"); + if ( D1->T) + { + Sequence *TS; + TS=tree2seq(D1->T, NULL);print_array_char (vfopen(out_file, "w"), TS->name, TS->nseq, "\n"); + } + } + else if ( strm (out_format, "code_name")) + { + char **nl=NULL; + int num, n=0; + Sequence *TS; + FILE *lfp; + if ( D1->A){n=(D1->A)->nseq, nl=(D1->A)->name;} + if ( D1->T){TS=tree2seq(D1->T, NULL);nl=TS->name;n=TS->nseq;} + + lfp=vfopen (out_file, "w"); + for ( num=0; numA); + } + else if ( strstr ( out_format, "pavie_age_channel")) + { + output_n_pavie_age_channel ( D1->S,out_file, atoi((out_format+strlen ("pavie_age_channel")))); + return EXIT_SUCCESS; + } + else if ( strstr ( out_format, "age_matrix")) + { + output_age_matrix (out_file, atoi((out_format+10))); + } + else if ( strm ( out_format, "transitions")) + { + output_transitions (out_file, D1->A); + } + + else if ( strncmp (out_format, "statistics",10)==0) + { + if (!D1)return 1; + + output_statistics (out_file, D1->A,out_format+10); + } + + + + + else if ( strm4 (out_format, "newick_tree","newick","binary","nh")) + { + if (!D1)return 1; + + /*D1->T=unroot_tree(D1->T);*/ + vfclose (print_tree ((D1->T), out_format, vfopen ( out_file, "w"))); + } + else if ( strncmp (out_format, "sarsim", 6)==0) + { + if (!D1)return 1; + compare_sar_sequence (D1->S, (D2 &&D2->S)?D2->S:D1->S, atoi(out_format+6)); + return EXIT_SUCCESS; + } + else if ( strncmp (out_format, "sim",3)==0) + { + if (!D1)return 1; + output_similarities (out_file, D1->A,out_format); + } + + else if ( strncmp (out_format, "cov",3)==0) + { + if (!D1)return 1; + output_similarities (out_file, D1->A,out_format); + } + else if ( strm (out_format, "stockholm_aln")) + { + output_stockholm_aln (out_file,D1->A, (D2)?D2->A:NULL); + } + else if ( strm (out_format, "pair_sim")) + { + if ( !D2) + { + fprintf ( stderr, "\n-output=pair_sim: provide aln1 via -in and aln2 via -in2 [FATAL:%s]\n", PROGRAM); + myexit (EXIT_FAILURE); + } + output_similarities_pw (out_file, D1->A,D2->A,out_format); + } + else if ( strm (out_format, "matrix") || strm (out_format, "blast_matrix")) + { + output_blast_mat (D1->M, out_file); + } + else if ( strm (out_format, "header_matrix")) + { + output_header_mat(D1->M, out_file); + } + + else + { + + fprintf ( stderr, "\n%s is an UNKNOWN OUTPUT FORMAT [FATAL:%s]\n",out_format, PROGRAM); + myexit (EXIT_FAILURE); + + } + + //Remove the expansion + if ( expanded) + { + free_aln (D1->A); + D1->A=BUF_A; + } + return 0; + } +int is_in_format_list ( char *name) + { + if ( strcmp ( name, "saga_aln")==0)return 1; + if ( strcmp ( name, "number_aln")==0)return 1; + if ( strcmp ( name, "clustal_aln")==0)return 1; + if ( strcmp ( name, "fasta_aln")==0)return 1; + if ( strcmp ( name, "number_fasta")==0)return 1; + if ( strcmp ( name, "fasta_seq")==0)return 1; + if ( strcmp ( name, "pdb")==0)return 1; + if ( strcmp ( name, "msf_aln")==0)return 1; + if ( strcmp ( name, "dali_aln")==0)return 1; + if ( strcmp ( name, "dali_seq")==0)return 1; + if ( strcmp ( name, "barton_list_tc")==0)return 1; + if ( strcmp ( name, "est_prf")==0)return 1; + + if ( strcmp ( name, "gotoh_aln")==0)return 1; + if ( strcmp ( name, "amps_aln")==0)return 1; + if ( strcmp ( name, "pir_aln")==0)return 1; + if ( strcmp ( name, "pir_seq")==0)return 1; + if ( strcmp ( name, "est_fasta")==0)return 1; + if ( strcmp ( name, "amps_sd_scores")==0)return 1; + if ( strcmp ( name, "pima_aln")==0)return 1; + if ( strcmp ( name, "dialign_aln")==0)return 1; + if ( strcmp ( name, "gor_seq")==0)return 1; + if ( strcmp ( name, "gor_struc")==0)return 1; + if ( strcmp ( name, "stockholm_aln")==0)return 1; + + return 0; + } +int is_struc_in_format_list ( char *name) + { + if ( strcmp ( name, "rna_number")==0)return 1; + if ( strcmp ( name, "fasta_seq")==0)return 1; + return 0; + } +char *format_name2aln_format_name (char *name) + { + if ( strm (name, "gcg"))sprintf (name, "msf"); + else if ( strm (name, "fasta"))sprintf (name, "fasta_aln"); + return name; + } +int is_out_format_list ( char *name) + { + return main_output (NULL, NULL, NULL, name, NULL); + } + +int is_struc_out_format_list ( char *name) + { + return main_output (NULL, NULL, NULL, name, NULL); + } + +/**************************************************************************************************/ +/*************************************REFORMAT UTIL*************************************************/ +/**************************************************************************************************/ + +/*************************************REFORMAT IN**************************************************/ +/**************************************************************************************************/ +/*******************************************************************************************/ +/* */ +/* */ +/* READ COG FILE */ +/* */ +/***************************************************************************************** */ + +/*******************************************************************************************/ +/* */ +/* */ +/* INPUT WEIGHTS */ +/* */ +/***************************************************************************************** */ + +Weights* get_amps_sd_scores ( char *fname) + { + FILE *fp; + char *buf; + char *buf2; + int nseq; + Weights *W; + int a, b,e; + int c; + float array[20]; + + buf=vcalloc ( 1001, sizeof (char)); + buf2=vcalloc ( 1001, sizeof (char)); + + fp=vfopen ( fname, "r"); + set_fp_id ( fp, "Index"); + buf=fgets ( buf, 1000, fp); + fscanf ( fp, "%s", buf2); + + nseq=0; + while ( isalnum(buf2[0]) && !isalpha(buf2[0])) + { + nseq++; + buf=fgets ( buf, 1000, fp); + fscanf ( fp, "%s", buf2); + } + vfclose ( fp); + + W=declare_weights (nseq); + + fp=vfopen ( fname, "r"); + set_fp_id ( fp, "Index"); + buf=fgets ( buf, 1000, fp); + fscanf ( fp, "%s", buf2); + + a=0; + while ( isalnum(buf2[0]) && !isalpha(buf2[0])) + { + fp=set_fp_after_char (fp, '>'); + fscanf ( fp, "%s",W->seq_name[a]); + buf=fgets ( buf, 1000, fp); + fscanf ( fp, "%s", buf2); + a++; + } + buf=fgets ( buf, 1000, fp); + c=1; + while ( c!=0) + { + for ( e=0; e< 16; e++) + { + c=fscanf ( fp, "%f", &array[e]); + } + fscanf ( fp, "\n"); + if ( c!=0) + { + + a=(int)array[0]-1; + b=(int)array[1]-1; + W->PW_ID[b][a]=W->PW_ID[a][b]=array[9]; + W->PW_SD[b][a]=W->PW_SD[a][b]=array[14]; + } + + } + vfclose ( fp); + sprintf ( W->comments, "SD WEIGHTS GENERATED WITH THE PROGRAM AMPS IN PAIRWISE MODE"); + vfree ( buf); + return W; + } + +Weights *read_seq_weight (char **name, int nseq, char* seq_weight) + { + int a, p; + Weights *W; + float w; + + FILE *fp; + char line[LONG_STRING]; + char sname[MAXNAMES]; + + + /*Read sequence weights: + * comment + name1 weight1 + ..... + + + NOTE: + weights must be between 0 and 1; + + sequences not in S do not get any weight + sequences in S but not in file get a weight of 1 + */ + if ( !is_single_seq_weight_file (seq_weight)) + { + fprintf ( stderr, "\nERROR: File %s is not in Format SINGLE_SEQ_WEIGHT_FORMAT_01 [FATA:%s]", seq_weight,PROGRAM); + myexit (EXIT_FAILURE); + return NULL; + } + else + { + W=declare_weights(nseq); + for ( a=0; a< nseq; a++) + { + sprintf ( W->seq_name[a], "%s", name[a]); + W->SEQ_W[a]=1; + } + sprintf ( W->mode, "%s", seq_weight); + fp=vfopen (seq_weight, "r"); + + + while ( fgets( line,LONG_STRING-1, fp)) + { + if ( line[0]=='*' ||line[0]=='#' || isblanc(line)); + else + { + if (sscanf(line, "%s %f", sname, &w)!=2)continue; + if ( (p=name_is_in_list ( sname, W->seq_name, nseq, MAXNAMES-1))!=-1) + { + W->SEQ_W[p]=w; + } + } + } + vfclose (fp); + return W; + } + } + + +/*******************************************************************************************/ +/* */ +/* */ +/* INPUT MISC */ +/* */ +/***************************************************************************************** */ + +char *** read_rename_file ( char *fname, int code) +{ + int n; + FILE *fp; + char ***convert=NULL; + + convert=declare_arrayN(3, sizeof (char),count_n_line_in_file(fname) +1,2,MAXNAMES+1); + fp=vfopen (fname, "r"); + n=0; + if ( code==CODE) while ( fscanf ( fp, "%s %s\n", convert[n][0], convert[n][1])==2)n++; + else if (code==DECODE)while ( fscanf ( fp, "%s %s\n", convert[n][1], convert[n][0])==2)n++; + vfclose (fp); + return convert; +} + +void get_barton_list_tc_seq ( char *in_file) + { + FILE *fp, *fp_make, *fp_length, *fp_long; + FILE *fp_small[9]; + + static char *buf; + int len_buf=10000; + char name[100]; + + char pwd[100]; + int a,c,nseq; + int k=0; + int *length; + int longest=0; + + c=0; + length=vcalloc ( 1000, sizeof(int)); + if ( buf==NULL)buf=vcalloc ( len_buf, sizeof (char)); + fp=vfopen (in_file, "r"); + fp_long=vfopen ( "barton_seq_list_large", "w"); + fp_make=vfopen ( "make_dir", "w"); + fp_length=vfopen ( "barton_length", "w"); + for ( a=0; a< 9; a++) + { + sprintf ( name, "barton_nseq%d",a); + fp_small[a]=vfopen ( name, "w"); + } + get_pwd (pwd); + + + while ( c!=EOF) + {a=0; + while ( (c=fgetc(fp))!='#'); + while ( (c=fgetc(fp))=='#'); + ungetc ( c, fp); + while ( (c=fgetc(fp))!='#')buf[a++]=c; + buf[a]='\0'; + + sprintf ( name, "%s", buf); + + while ( (c=fgetc(fp))=='#'); + + if ( c!=EOF) + { + a=0; + while ( (c=fgetc(fp))!='#' && c!=EOF) + { + buf[a++]=c; + if (a==len_buf) + { + len_buf+=10000; + buf=vrealloc ( buf, len_buf*sizeof (char)); + } + } + buf[a]='\0'; + if (c!=EOF) + { + + nseq=process_barton_entry ( buf,name); + length[nseq]++; + longest=(longest') + { + a=get_string_line (a,2, buf, buf2); + while ((c=buf[a++])!='*') + if (isalnum (c)|| c=='.' || c=='-') + clen++; + max_len_seq=(clen> max_len_seq)?clen: max_len_seq; + min_len_seq=(clen< min_len_seq)?clen: min_len_seq; + nseq++; + clen=0; + } + if ( buf[a]!='\0')a++; + } + + + LS=declare_sequence ( min_len_seq, max_len_seq, nseq); + LS->nseq=nseq; + + + for (a=0, current=0; current< nseq; current++) + { + a=get_string_line ( a, 1, buf, buf2); + sscanf ( buf2, ">P1;%s", LS->name[current]); + a=get_string_line ( a, 1, buf, buf2); + l=strlen ( buf2); + buf2[l-1]='\0'; + sprintf ( LS->seq_comment[current],"%s", buf2); + + p=0; + while ( (c=buf[a++])!='*') + { + if (isalpha (c)) + LS->seq[current][p++]=tolower (c); + else if ( isgraph(c)) + LS->seq[current][p++]=(c); + } + a++; + } + + LA=declare_Alignment(LS); + seq2aln ( LS, LA,rm_gap); + output_fasta_seq (fname,LA); + output_pir_check (com_name,LA->nseq, LA->seq_comment); + free_Alignment ( LA); + free_sequence ( LS, nseq); + + return nseq; + } + + + + +Structure *read_rna_struc_number (Alignment *A,char *fname) + { + FILE *fp; + int a; + char x,y; + float f; + Sequence *SA; + Structure *ST; + int first, last; + + SA=declare_sequence ( A->len_aln, A->len_aln, 1); + SA->len[0]=A->len[0]; + for ( a=0; a< SA->len[0]; a++) + SA->seq[0][a]='.'; + ST=declare_rna_structure_num (SA); + ST->S=SA; + + fp=vfopen ( fname, "r"); + fscanf ( fp, "%c\n%d\n",&x, &(ST)->tot_list); + for ( a=0; a<(ST)->tot_list; a++) + { + fscanf ( fp, "%d %d %d %c %c %f\n", &(ST)->list[a][0],&(ST)->list[a][1],&(ST)->list[a][2], &x, &y, &f); + (ST)->list[a][0]--; + (ST)->list[a][1]--; + (ST)->list[a][2]--; + if ( a==0) + { + (ST)->stem[0][0]=(ST)->list[a][0]; + (ST)->stem[0][1]=a; + } + else if ( (ST)->stem[(ST)->tot_stem][0]==(ST)->list[a][0]); + else if ( (ST)->stem[(ST)->tot_stem][0]!=(ST)->list[a][0]) + { + (ST)->stem[(ST)->tot_stem][2]=a-1; + (ST)->tot_stem++; + (ST)->stem[(ST)->tot_stem][0]=(ST)->list[a][0]; + (ST)->stem[(ST)->tot_stem][1]=a; + } + + SA->seq[0][(ST)->list[a][1]]='-'; + SA->seq[0][(ST)->list[a][2]]='-'; + } + (ST)->stem[(ST)->tot_stem][2]=a-1; + (ST)->tot_stem++; + for ( a=0; a< (ST)->tot_stem; a++) + { + + first=(ST)->stem[a][1]; + last=(ST)->stem[a][2]; + SA->seq[0][(ST)->list[first][1]]='>'; + SA->seq[0][(ST)->list[first][2]]='<'; + SA->seq[0][(ST)->list[last][1]]='>'; + SA->seq[0][(ST)->list[last][2]]='<'; + } + + return ST; + } + +Structure * declare_rna_structure_num (Sequence *SA) + { + Structure *ST; + ST=vcalloc ( 1, sizeof ( Structure)); + ST->list=declare_int ( SA->len[0], 3); + ST->stem=declare_int ( SA->len[0], 3); + return ST; + } +char ** read_lib_list (char *name, int *n) +{ + + char **lines; + char **list; + int a, b, l; + + lines=file2lines (name); + l=atoi (lines[0]); + + list=vcalloc (l, sizeof (char*)); + for ( n[0]=0,a=1; a .... + Groups must NOT be overlaping + list[group_index][0]="number of sequences" + list[group_index][1]="group name" + list[group_index][2...N]="sequence" + */ + + FILE *fp; + char *buf; + char ***list; + int a, c, l; + + + + l=measure_longest_line_in_file (file)+1; + buf=vcalloc (l, sizeof (char)); + list=vcalloc ( count_n_line_in_file (file )+1, sizeof (char**)); + + fp=vfopen (file, "r"); + + a=0; + while ((c=fgetc(fp))!=EOF) + { + buf=fgets (buf,l-1, fp); + if ( c=='>')list[a++]=string2list (buf); + } + vfclose (fp); + vfree (buf); + return list; +} + + +static Sequence* get_pdb_sequence_from_field (char *fname, char *field); + +Sequence* get_pdb_sequence (char *fname) +{ + Sequence *S; + + if ( (S=get_pdb_sequence_from_field(fname, "SEQRES"))!=NULL); + else if ( (S=get_pdb_sequence_from_field(fname, "ATOM"))!=NULL) + { + add_warning (stderr,"Warning: Read Sequence from ATOM field in %s [%s:WARNING]", fname, PROGRAM); + } + else + { + add_warning ( stderr, "\nWARNING: failed to extract sequence from %s [%s:WARNING]\n", fname, PROGRAM); + S=NULL; + } + return S; +} + + +static Sequence* get_pdb_sequence_from_field (char *fname, char *field) +{ + char *tp_name; + char *command; + char *pdbid; + Sequence *S; + + + command=vcalloc ( LONG_STRING, sizeof (char)); + tp_name=vtmpnam (NULL); + sprintf ( command, "extract_from_pdb -seq_field %s -chain FIRST -infile \'%s\' -mode fasta > %s", field, check_file_exists(fname), tp_name); +// printf("CO: %s\n", command); +// char *x = vcalloc ( LONG_STRING, sizeof (char)); +// sprintf(x, "cp %s ~/Desktop/erg.txt", tp_name); +// my_system(x); + if ( getenv4debug ("DEBUG_EXTRACT_FROM_PDB"))fprintf ( stderr, "\n[DEBUG_EXTRACT_FROM_PDB:get_pdb_seq] %s\n", command); + my_system ( command); + + + S=get_fasta_sequence ( tp_name, NULL); + if (S==NULL)return NULL; + + if ( (pdbid=get_pdb_id (fname))){sprintf ( S->name[0], "%s",pdbid);vfree (pdbid);} + S->nseq=1; + + sprintf ( S->file[0], "%s", fname); + S->max_len=S->min_len=S->len[0]; + if ( S->len[0]==0) + { + free_sequence (S, -1); + S=NULL; + } + + vremove ( tp_name); + vfree ( command); + + return S; +} + +char * get_pdb_file ( char *fname) + { + char *file; + int a, c; + FILE *fp; + + + a=0; + file=vcalloc ( sizeof (char),count_n_char_in_file ( fname)+1); + fp=vfopen ( fname, "r"); + while ( (c=fgetc(fp))!=EOF)file[a++]=c; + file[a]='\0'; + return file; + } + +Sequence* get_struc_gor ( char *fname) + { + int nseq, min_len, max_len; + int a, c; + int len; + char name[STRING]; + + + FILE *fp; + Sequence *S; + + min_len=max_len=-1; + fp=vfopen ( fname, "r"); + nseq=0; + while ( (c=fgetc(fp))!=EOF) + { + if ( c!='!'); + else + { + nseq++; + fscanf ( fp, "%s %d", name, &len); + if (min_len==-1)min_len=max_len=len; + else + { + min_len=(len>min_len)?min_len:len; + max_len=(len>max_len)?len:max_len; + } + } + + } + vfclose (fp); + + S=declare_sequence ( min_len, max_len+1,nseq); + S->nseq=0; + + fp=vfopen (fname,"r"); + while ( (c=fgetc(fp))!=EOF) + { + if ( c!='!'); + else + { + fscanf ( fp, "%s %d\n",S->name[S->nseq], &(S->len[S->nseq])); + + while ( (c=fgetc(fp))!='\n'); + + for ( a=0; alen[S->nseq]; a++) + fscanf ( fp, " %*c %c %*f %*f %*f\n",&(S->seq[S->nseq][a])); + + S->seq[S->nseq][a]='\0'; + while ( (c=fgetc(fp))!='!' && c!=EOF); + ungetc (c, fp); + S->nseq++; + } + + } + vfclose (fp); + return S; + } + +Sequence* get_sequence_dali (char *fname) + { + Sequence *LS; + FILE *fp; + int c; + + char name[100]; + int clen=0; + int current=0; + int p=0; + int max_len_seq=0; + int min_len_seq=999999; + int nseq=0; + + if ((fp=vfopen (fname,"r"))==NULL) + {printf ( "\nCOULDN'T OPEN %s",fname); + myexit(EXIT_FAILURE); + } + c=fgetc(fp); + while (c!=EOF) + { + if (isdigit(c)) + { + ungetc(c, fp); + fscanf (fp, "%s",name); + while (!isdigit(c=fgetc(fp)) && c!=EOF) + if (isalnum (c) || c=='.' || c=='-') + clen++; + max_len_seq=(clen> max_len_seq)?clen: max_len_seq; + min_len_seq=(clen< min_len_seq)?clen: min_len_seq; + nseq++; + clen=0; + } + else + c=fgetc (fp); + } + vfclose (fp); + + LS=declare_sequence ( min_len_seq, max_len_seq+1,nseq); + LS->nseq=nseq; + + fp=vfopen (fname,"r"); + + current=0; + c=fgetc(fp); + while (c!=EOF) + { + if (isdigit(c)) + { + ungetc(c, fp); + fscanf_seq_name (fp, LS->name[current]); + p=0; + while (!isdigit(c=fgetc(fp)) && c!=EOF) + { + if (isalpha (c)) + LS->seq[current][p++]=tolower (c); + else if ( c=='.') + LS->seq[current][p++]='-'; + else if ( c=='-') + LS->seq[current][p++]='-'; + } + LS->seq[current][p]='\0'; + LS->len[current]=strlen ( LS->seq[current]); + current++; + } + else + c=fgetc ( fp); + } + + vfclose (fp); + + + return LS; + } + +Sequence* get_dialign_sequence (char *fname) + { + Sequence *LS; + FILE *fp; + int c; + + char name[10000]; + int clen=0; + int current=0; + int p=0; + int max_len_seq=0; + int min_len_seq=999999; + int nseq=0, l=0; + char *buf; + + buf=vcalloc ( 1000, sizeof (char)); + if ((fp=vfopen (fname,"r"))==NULL) + {printf ( "\nCOULDN'T OPEN %s",fname); + myexit(EXIT_FAILURE); + } + c=fgetc(fp); + while (c!=EOF) + { + if (c=='>') + {fscanf (fp, "%s",name); + + buf=fgets ( buf, 1000, fp); + while ((c=fgetc(fp))!='>' && c!=EOF && c!=' ' && c!='\t') + if (isalnum (c)|| is_gap(c)) + clen++; + max_len_seq=(clen> max_len_seq)?clen: max_len_seq; + min_len_seq=(clen< min_len_seq)?clen: min_len_seq; + nseq++; + clen=0; + } + else + c=fgetc (fp); + } + vfclose (fp); + + LS=declare_sequence ( min_len_seq, max_len_seq, nseq); + LS->nseq=nseq; + + fp=vfopen (fname,"r"); + + current=0; + c=fgetc(fp); + while (c!=EOF) + { + if (c=='>') + { + + fscanf_seq_name (fp, LS->name[current]); + l=strlen ( LS->name[current]); + if ( LS->name[current][l-1]==','||LS->name[current][l-1]==',')LS->name[current][l-1]='\0'; + buf=fgets ( buf, 1000, fp); + p=0; + while ((c=fgetc(fp))!='>' && c!=EOF && c!=EOF && c!=' ' && c!='\t') + if (isalpha (c)) + LS->seq[current][p++]=tolower (c); + else if ( isgraph(c)) + LS->seq[current][p++]=(c); + LS->seq[current][p]='\0'; + LS->len[current]=strlen ( LS->seq[current]); + current++; + } + else + c=fgetc ( fp); + } + + vfclose (fp); + return LS; + } + +Sequence* get_pima_sequence (char *fname) + { + Sequence *LS; + + FILE *fp; + int c; + + char name[10000]; + int clen=0; + int current=0; + int p=0; + int max_len_seq=0; + int min_len_seq=999999; + int nseq=0, l=0, len=0; + char *buf, *buf2; + char prefix[1000]; + + sprintf ( prefix, "%s",fname); + + buf=strstr(prefix, "-"); + buf[0]='\0'; + len=strlen (prefix); + + + + buf=vcalloc ( 1000, sizeof (char)); + if ((fp=vfopen (fname,"r"))==NULL) + {printf ( "\nCOULDN'T OPEN %s",fname); + myexit(EXIT_FAILURE); + } + c=fgetc(fp); + while (c!=EOF) + { + if (c=='>') + { + fscanf_seq_name (fp,name); + if ( strlen(name)>=len && strncmp ( name, prefix, len)==0) + { + c=fgetc(fp); + } + else + { + + buf=fgets ( buf, 1000, fp); + while ((c=fgetc(fp))!='>' && c!=EOF) + if (isalnum (c)|| is_gap(c)) + clen++; + max_len_seq=(clen> max_len_seq)?clen: max_len_seq; + min_len_seq=(clen< min_len_seq)?clen: min_len_seq; + nseq++; + clen=0; + } + } + else + c=fgetc (fp); + } + vfclose (fp); + + LS=declare_sequence ( min_len_seq, max_len_seq, nseq); + LS->nseq=nseq; + + fp=vfopen (fname,"r"); + + current=0; + c=fgetc(fp); + while (c!=EOF) + { + if (c=='>') + { + fscanf_seq_name (fp,LS->name[current]); + if ( strlen(LS->name[current])>=len && strncmp ( LS->name[current], prefix, len)==0) + c=fgetc (fp); + else + { + buf2=strstr (LS->name[current], "."); + if ( buf2!=NULL) buf2[0]='\0'; + + l=strlen ( LS->name[current]); + if ( LS->name[current][l-1]==','||LS->name[current][l-1]==',')LS->name[current][l-1]='\0'; + buf=fgets ( buf, 1000, fp); + p=0; + while ((c=fgetc(fp))!='>' && c!=EOF) + if (isalpha (c)) + LS->seq[current][p++]=tolower (c); + else if ( isgraph(c)) + LS->seq[current][p++]=(c); + LS->seq[current][p]='\0'; + LS->len[current]=strlen ( LS->seq[current]); + current++; + } + } + else + c=fgetc ( fp); + } + + vfclose (fp); + return LS; + } + +Sequence* perl_reformat2fasta (char *perl_command, char *fname) + { + char command[1000]; + char *file; + + file=vtmpnam (NULL); + + check_program_is_installed ( perl_command,"", perl_command,EMAIL,IS_FATAL); + sprintf ( command, "%s %s > %s", perl_command, fname, file); + my_system ( command); + return get_fasta_sequence (file, NULL); + } +Sequence* get_fasta_sequence_num (char *fname, char *comment_out) + { + Sequence *LS; + char *buffer; + FILE *fp; + int a; + + int c; + char *name; + int clen=0; + int current=0; + int p=0; + int max; + int max_len_seq=0; + int min_len_seq=0; + int nseq=0, l=0; + + + + + int *sub; + + buffer=vcalloc (1000, sizeof (char)); + name=vcalloc ( 100, sizeof (char)); + + nseq=count_n_char_x_in_file(fname, '>'); + min_len_seq=max=count_n_char_in_file(fname); + sub=vcalloc (max+1, sizeof (int)); + + fp=vfopen (fname,"r"); + + + c=fgetc(fp); + while (c!=EOF) + { + if (c=='>') + { + fscanf_seq_name (fp,name); + while ((c=fgetc(fp))!='\n' && c!=EOF); + while ((c=fgetc(fp))!='>' && c!=EOF) + if (isalnum (c)|| is_gap(c)) + clen++; + max_len_seq=(clen> max_len_seq)?clen: max_len_seq; + min_len_seq=(clen< min_len_seq)?clen: min_len_seq; + clen=0; + } + else + c=fgetc (fp); + + } + + vfclose (fp); + LS=declare_sequence ( min_len_seq, max_len_seq,nseq); + + LS->nseq=nseq; + + fp=vfopen (fname,"r"); + current=0; + c=fgetc(fp); + while (c!=EOF) + { + if (c=='>') + { + + fscanf_seq_name (fp,LS->name[current]); + l=strlen ( LS->name[current]); + if ( LS->name[current][l-1]==','||LS->name[current][l-1]==';')LS->name[current][l-1]='\0'; + LS->name[current]=translate_name ( LS->name[current]); + a=0; + while ((c=fgetc(fp))!='\n' && c!=EOF && a<(COMMENT_SIZE-1))LS->seq_comment[current][a++]=c; + LS->seq_comment[current][a]='\0'; + + + p=0; + while ((c=fgetc(fp))!='>' && c!=EOF) + { + if (isalnum (c)) + LS->seq[current][p++]=c; + else if (is_gap(c)) + LS->seq[current][p++]=c; + } + LS->seq[current][p]='\0'; + LS->len[current]=strlen ( LS->seq[current]); + + current++; + } + else + c=fgetc ( fp); + } + + + vfclose (fp); + + + vfree (sub); + vfree (name); + vfree (buffer); + return LS; + } + +Sequence *get_tree_file_list ( char *fname) +{ + + char ***list; + char *tmp; + int a; + FILE *fp; + + tmp=vtmpnam (NULL); + list=file2list (fname, "\n"); + fp=vfopen (tmp, "w"); + a=0; + while (list[a] && !isspace(list[a][1][0])) + { + char *s; + s=file2string (list[a][1]); + fprintf ( fp, ">%s\n%s\n", list[a][1], (s)?s:""); + a++; + } + vfclose (fp); + free_arrayN((void ***)list, 3); + return get_fasta_tree (tmp, NULL); +} +Sequence *get_file_list ( char *fname) +{ + + char ***list; + char *tmp; + int a; + FILE *fp; + + tmp=vtmpnam (NULL); + list=file2list (fname, "\n"); + fp=vfopen (tmp, "w"); + a=0; + while (list[a] && !isspace(list[a][1][0])) + { + + fprintf ( fp, ">%s\n", list[a][1]); + a++; + } + vfclose (fp); + free_arrayN((void ***)list, 3); + return get_fasta_sequence (tmp, NULL); +} +Sequence*get_fasta_tree (char *fname, char *comment_out) +{ + Sequence *LS; + char *buffer; + FILE *fp; + int a; + + int c; + char *name; + int clen=0; + int current=0; + int p=0; + int max; + int max_len_seq=0; + int min_len_seq=0; + int nseq=0, l=0; + + + + + int *sub; + + buffer=vcalloc (1000, sizeof (char)); + name=vcalloc ( 100, sizeof (char)); + + nseq=count_n_char_x_in_file(fname, '>'); + min_len_seq=max=count_n_char_in_file(fname); + sub=vcalloc (max+1, sizeof (int)); + + fp=vfopen (fname,"r"); + + + c=fgetc(fp); + while (c!=EOF) + { + if (c=='>') + { + fscanf_seq_name (fp,name); + while ((c=fgetc(fp))!='\n' && c!=EOF); + while ((c=fgetc(fp))!='>' && c!=EOF) + if (isgraph(c)) + clen++; + max_len_seq=(clen> max_len_seq)?clen: max_len_seq; + min_len_seq=(clen< min_len_seq)?clen: min_len_seq; + clen=0; + } + else + c=fgetc (fp); + + } + + vfclose (fp); + LS=declare_sequence ( min_len_seq, max_len_seq,nseq); + + LS->nseq=nseq; + + fp=vfopen (fname,"r"); + current=0; + c=fgetc(fp); + while (c!=EOF) + { + if (c=='>') + { + + fscanf_seq_name (fp,LS->name[current]); + l=strlen ( LS->name[current]); + if ( LS->name[current][l-1]==','||LS->name[current][l-1]==';')LS->name[current][l-1]='\0'; + LS->name[current]=translate_name ( LS->name[current]); + a=0; + while ((c=fgetc(fp))!='\n' && c!=EOF && a<(COMMENT_SIZE-1))LS->seq_comment[current][a++]=c; + LS->seq_comment[current][a]='\0'; + + + p=0; + while ((c=fgetc(fp))!='>' && c!=EOF) + { + LS->seq[current][p++]=c; + } + + LS->seq[current][p]='\0'; + LS->len[current]=strlen ( LS->seq[current]); + + current++; + + } + + else + c=fgetc ( fp); + } + + + vfclose (fp); + + + vfree (sub); + vfree (name); + vfree (buffer); + + return LS; +} +Sequence* get_fasta_sequence_raw (char *fname, char *comment_out) + { + Sequence *LS; + char *buffer; + FILE *fp; + int a; + + int c; + char *name; + int clen=0; + int current=0; + int p=0; + int max; + int max_len_seq=0; + int min_len_seq=0; + int nseq=0, l=0; + + + + + int *sub; + + buffer=vcalloc (1000, sizeof (char)); + name=vcalloc ( 100, sizeof (char)); + + nseq=count_n_char_x_in_file(fname, '>'); + min_len_seq=max=count_n_char_in_file(fname); + sub=vcalloc (max+1, sizeof (int)); + + fp=vfopen (fname,"r"); + + + c=fgetc(fp); + while (c!=EOF) + { + if (c=='>') + { + fscanf_seq_name (fp,name); + while ((c=fgetc(fp))!='\n' && c!=EOF); + while ((c=fgetc(fp))!='>' && c!=EOF) + if (isgraph(c)) + clen++; + max_len_seq=(clen> max_len_seq)?clen: max_len_seq; + min_len_seq=(clen< min_len_seq)?clen: min_len_seq; + clen=0; + } + else + c=fgetc (fp); + + } + + vfclose (fp); + LS=declare_sequence ( min_len_seq, max_len_seq,nseq); + + LS->nseq=nseq; + + fp=vfopen (fname,"r"); + current=0; + c=fgetc(fp); + while (c!=EOF) + { + if (c=='>') + { + + fscanf_seq_name (fp,LS->name[current]); + l=strlen ( LS->name[current]); + if ( LS->name[current][l-1]==','||LS->name[current][l-1]==';')LS->name[current][l-1]='\0'; + LS->name[current]=translate_name ( LS->name[current]); + a=0; + while ((c=fgetc(fp))!='\n' && c!=EOF && a<(COMMENT_SIZE-1))LS->seq_comment[current][a++]=c; + LS->seq_comment[current][a]='\0'; + + + p=0; + while ((c=fgetc(fp))!='>' && c!=EOF) + { + //if (c<'A')c+='z'; + if (c!='\n')LS->seq[current][p++]=c; + } + + LS->seq[current][p]='\0'; + LS->len[current]=strlen ( LS->seq[current]); + + current++; + + } + + else + c=fgetc ( fp); + } + + + vfclose (fp); + + + vfree (sub); + vfree (name); + vfree (buffer); + return LS; + } +Sequence* get_fasta_sequence (char *fname, char *comment_out) + { + Sequence *LS; + Sequence *pdb_S; + int a; + + char *pdb_name; + + char *buffer; + FILE *fp; + + int c; + char *name; + int clen=0; + int current=0; + int p=0; + int max; + int max_len_seq=0; + int min_len_seq=0; + int nseq=0, l=0; + char *sub; + int disk=0; + int coor=0; + + + + buffer=vcalloc (1000, sizeof (char)); + name=vcalloc ( 10000, sizeof (char)); + + nseq=count_n_char_x_in_file(fname, '>'); + if (disk==1 || get_int_variable ("use_disk") || getenv ("SEQ_ON_DISK_4_TCOFFEE")){disk=1;} + if ( nseq==0) + { + vfree (buffer); vfree (name); + return NULL; + } + + min_len_seq=max=count_n_char_in_file(fname); + sub=vcalloc (max+1, sizeof (char)); + + fp=vfopen (fname,"r"); + + nseq=0; + c=fgetc(fp); + while (c!=EOF) + { + if (c=='>') + { + nseq++; + fscanf_seq_name (fp,name); + while ((c=fgetc(fp))!='\n' && c!=EOF); + while ((c=fgetc(fp))!='>' && c!=EOF) + { + if (isalnum (c)|| is_gap(c)) + sub[clen++]=c; + } + + if (strm (sub, "PDB")) + { + pdb_name=get_pdb_struc(name,0, 0); + pdb_S=get_pdb_sequence (pdb_name); + if (pdb_S) + { + clen=strlen( pdb_S->seq[0]); + free_sequence ( pdb_S,1); + } + else + clen=0; + + } + + max_len_seq=(clen> max_len_seq)?clen: max_len_seq; + min_len_seq=(clen< min_len_seq)?clen: min_len_seq; + clen=0; + } + else + c=fgetc (fp); + + } + + vfclose (fp); + + + if ( disk==0) + LS=declare_sequence ( min_len_seq, max_len_seq,nseq); + else + { + LS=declare_sequence (0,0,nseq); + for (a=0; aseq[a]=NULL; + } + LS->nseq=nseq; + + fp=vfopen (fname,"r"); + current=0; + c=fgetc(fp);coor++; + + while (c!=EOF) + { + if (c=='>') + { + coor+=fscanf_seq_name (fp, LS->name[current]); + + + l=strlen ( LS->name[current]); + if ( LS->name[current][l-1]==','||LS->name[current][l-1]==';')LS->name[current][l-1]='\0'; + LS->name[current]=translate_name ( LS->name[current]); + a=0; + while ((c=fgetc(fp))!='\n' && c!=EOF && a<(COMMENT_SIZE-1)){LS->seq_comment[current][a++]=c;coor++;} + coor++; + + LS->seq_comment[current][a]='\0'; + + p=0; + while ((c=fgetc(fp))!='>' && c!=EOF) + { + coor++; + + if (!isspace(c)) + { + if (p==0)LS->dc[current][0]=coor; + + if (disk==0)LS->seq[current][p++]=c; + else p++; + } + + LS->dc[current][1]=coor; + } + coor++; + + if ( disk==0)LS->seq[current][p]='\0'; + + if (LS->seq[current] && strm (LS->seq[current], "PDB")) + { + + pdb_name=get_pdb_struc(LS->name[current],0, 0); + pdb_S=get_pdb_sequence (pdb_name); + if (pdb_S) + { + sprintf ( LS->seq[current], "%s", pdb_S->seq[0]); + clen=strlen( pdb_S->seq[0]); + free_sequence ( pdb_S, 1); + } + else + { + add_warning (stderr, "WARNING: Could not fetch PDB file: %s", pdb_name); + } + } + + + LS->len[current]=p; + current++; + } + + else + { + c=fgetc ( fp); + coor++; + } + } + + vfclose (fp); + vfree (sub); + vfree (name); + vfree (buffer); + //LS=clean_sequence (LS); + + return LS; + } + +Sequence* get_sub_fasta_sequence (char *fname, char *comment_out) + { + Sequence *LS; + + FILE *fp; + + int c; + char name[100]; + int clen=0; + int current=0; + int p=0; + int max; + int max_len_seq=0; + int min_len_seq=0; + int nseq=0, l=0; + char *buf; + + + + int *sub; + + nseq=count_n_char_x_in_file(fname, '>'); + min_len_seq=max=count_n_char_in_file(fname); + sub=vcalloc (max+1, sizeof (int)); + buf=vcalloc ( max+1, sizeof (char)); + fp=vfopen (fname,"r"); + + + c=fgetc(fp); + while (c!=EOF) + { + if (c=='>') + { + fscanf_seq_name (fp,name); + while ((c=fgetc(fp))!='\n' && c!=EOF); + buf=fgets ( buf,max, fp); + while ((c=fgetc(fp))!='>' && c!=EOF) + if (isalnum (c)|| is_gap(c)) + clen++; + max_len_seq=(clen> max_len_seq)?clen: max_len_seq; + min_len_seq=(clen< min_len_seq)?clen: min_len_seq; + clen=0; + } + else + c=fgetc (fp); + + } + + vfclose (fp); + LS=declare_sequence ( min_len_seq, max_len_seq,nseq); + LS->nseq=nseq; + + fp=vfopen (fname,"r"); + current=0; + c=fgetc(fp); + while (c!=EOF) + { + if (c=='>') + { + + fscanf_seq_name (fp,LS->name[current]); + l=strlen ( LS->name[current]); + if ( LS->name[current][l-1]==','||LS->name[current][l-1]==';')LS->name[current][l-1]='\0'; + LS->name[current]=translate_name ( LS->name[current]); + while ((c=fgetc(fp))!='\n' && c!=EOF); + + p=0; + while ((c=fgetc(fp))!='>' && c!=EOF) + { + if (isalpha (c)) + LS->seq[current][p++]=tolower (c); + else if (is_gap(c)) + LS->seq[current][p++]=(c); + } + + LS->seq[current][p]='\0'; + LS->len[current]=strlen ( LS->seq[current]); + + current++; + + } + + else + c=fgetc ( fp); + } + + + vfclose (fp); + + + vfree (sub); + return LS; + } +Sequence* get_pir_sequence (char *fname, char *comment_out) + { + Sequence *LS; + + FILE *fp; + int c; + + char name[100]; + int clen=0; + int current=0; + int p=0; + int max_len_seq=0; + int min_len_seq=999999; + int nseq=0, l=0; + char *buf; + + buf=vcalloc ( 1000, sizeof (char)); + if ((fp=vfopen (fname,"r"))==NULL) + {printf ( "\nCOULDN'T OPEN %s",fname); + myexit(EXIT_FAILURE); + } + c=fgetc(fp); + while (c!=EOF) + { + if (c=='>') + { + if ( (c=fgetc(fp))=='P')while ( (c=fgetc(fp))!=';'); + else ungetc ( c, fp); + fscanf_seq_name (fp,name); + + buf=fgets ( buf, 1000, fp); + while ((c=fgetc(fp))!='>' && c!=EOF) + if (isalnum (c)|| is_gap(c)) + clen++; + max_len_seq=(clen> max_len_seq)?clen: max_len_seq; + min_len_seq=(clen< min_len_seq)?clen: min_len_seq; + nseq++; + clen=0; + } + else + c=fgetc (fp); + } + vfclose (fp); + + + + LS=declare_sequence ( min_len_seq, max_len_seq,nseq); + LS->nseq=nseq; + + fp=vfopen (fname,"r"); + + current=0; + c=fgetc(fp); + while (c!=EOF) + { + if (c=='>') + { + if ( (c=fgetc(fp))=='P')while ( (c=fgetc(fp))!=';'); + else ungetc ( c, fp); + + fscanf_seq_name (fp,LS->name[current]); + + l=strlen ( LS->name[current]); + if ( LS->name[current][l-1]==','||LS->name[current][l-1]==',')LS->name[current][l-1]='\0'; + LS->name[current]=translate_name ( LS->name[current]); + buf=fgets ( buf, 1000, fp); + + LS->seq_comment[current]=fgets ( LS->seq_comment[current],COMMENT_SIZE-1, fp); + LS->seq_comment[current][strlen(LS->seq_comment[current])-1]='\0'; + p=0; + while ((c=fgetc(fp))!='>' && c!=EOF) + if (isalpha (c)) + LS->seq[current][p++]=tolower (c); + else if ( !isspace(c) && c!='*') + LS->seq[current][p++]=(c); + LS->seq[current][p]='\0'; + LS->len[current]=strlen ( LS->seq[current]); + current++; + } + else + c=fgetc ( fp); + } + + vfclose (fp); + if (comment_out!=NULL) output_pir_check ( comment_out,LS->nseq, LS->seq_comment); + return LS; + } + +Sequence* get_gor_sequence (char *fname, char *comment_out) + { + Sequence *LS; + + FILE *fp; + int c; + + char name[100]; + int clen=0; + int current=0; + int p=0; + int max_len_seq=0; + int min_len_seq=99999; + int nseq=0; + char *buf; + + buf=vcalloc ( 1000, sizeof (char)); + if ((fp=vfopen (fname,"r"))==NULL) + {printf ( "\nCOULDN'T OPEN %s",fname); + myexit(EXIT_FAILURE); + } + c=fgetc(fp); + while (c!=EOF) + { + if (c=='!') + { + fscanf_seq_name (fp,name); + + buf=fgets ( buf, 1000, fp); + while ((c=fgetc(fp))!='!' && c!=EOF) + if (isalnum (c)|| is_gap(c)) + clen++; + max_len_seq=(clen> max_len_seq)?clen: max_len_seq; + min_len_seq=(clen< min_len_seq)?clen: min_len_seq; + nseq++; + clen=0; + } + else + c=fgetc (fp); + } + vfclose (fp); + + LS=declare_sequence ( min_len_seq, max_len_seq,nseq); + LS->nseq=nseq; + + fp=vfopen (fname,"r"); + + current=0; + c=fgetc(fp); + while (c!=EOF) + { + if (c=='!') + { + + + fscanf_seq_name (fp,LS->name[current]); + LS->name[current]=translate_name ( LS->name[current]); + buf=fgets ( buf, 1000, fp); + + p=0; + while ((c=fgetc(fp))!='!' && c!=EOF) + if (isalnum (c)|| is_gap(c)) + LS->seq[current][p++]=tolower (c); + + LS->seq[current][p]='\0'; + LS->len[current]=strlen ( LS->seq[current]); + current++; + } + else + c=fgetc ( fp); + } + + vfclose (fp); + + return LS; + } +Sequence* get_swissprot_sequence (char *fname, char *comment_out) + { + Sequence *LS; + FILE *fp; + int c; + char *buf; + int nseq=0; + int len, max_len_seq=0, min_len_seq=0; + + if ( !check_file_exists(fname)) + {printf ( "\nCOULDN'T OPEN %s",fname); + myexit(EXIT_FAILURE); + } + + buf=vcalloc (LONG_STRING+1, sizeof (char)); + fp=NULL; + while ( (fp=find_token_in_file(fname,fp,"\nSQ"))) + { + nseq++; + fgets (buf, LONG_STRING, fp); + len=0; + while ((c=fgetc(fp))!='/')if(isalpha(c))len++; + if ( max_len_seq==0)max_len_seq=min_len_seq=len; + else + { + max_len_seq=MAX(len, max_len_seq); + min_len_seq=MIN(len, min_len_seq); + } + } + + LS=declare_sequence ( min_len_seq, max_len_seq,nseq); + LS->nseq=0; + + fp=NULL; + while ( (fp=find_token_in_file(fname,fp,"\nID"))) + { + fscanf_seq_name (fp, LS->name[LS->nseq]); + fp=find_token_in_file(fname,fp,"\nSQ"); + fgets (buf, LONG_STRING, fp); + while ((c=fgetc(fp))!='/')if (isalpha(c))LS->seq[LS->nseq][LS->len[LS->nseq]++]=c; + LS->seq[LS->nseq][LS->len[LS->nseq]]='\0'; + LS->nseq++; + } + + + return LS; + } +int fscanf_seq_name ( FILE *fp, char *sname) +{ + static char *name; + int r; + if ( !sname) return 0; + + if ( !name)name=vcalloc ( 10000, sizeof (char)); + fscanf (fp, "%s", name); + r=strlen (name); + if ( strlen (name)>MAXNAMES) + add_warning (stderr, "\nWARNING: Seq Name Too long: [%s]. Truncated to %d", name, MAXNAMES); + name[MAXNAMES]='\0'; + sprintf ( sname, "%s", name); + return r; +} + +/*******************************************************************************************/ +/* */ +/* */ +/* INPUT ALN */ +/* */ +/***************************************************************************************** */ +void undump_msa ( Alignment *A, char *tmp) +{ + FILE *fp; + int m; + char *buf; + int index; + + if ( !A || !tmp || !check_file_exists (tmp))return; + m=measure_longest_line_in_file (tmp ); + A=realloc_aln2 ( A,A->max_n_seq,m+1); + + buf=vcalloc (m+1, sizeof (char)); + fp=vfopen (tmp, "r"); + while (fscanf (fp, "%d %s\n", &index, buf)==2) + { + sprintf ( A->seq_al[index], "%s", buf); + } + vfclose (fp); + vfree (buf); +} +void dump_msa ( char *file,Alignment *A, int nseq, int *lseq) +{ + FILE *fp; + int a; + fp=vfopen (file, "w"); + for (a=0; aseq_al[lseq[a]]); + vfclose (fp); +} + +void read_aln (char *file_name, Alignment *A) +{ + char *tmp_name; + Sequence *S; + + + tmp_name=vtmpnam (NULL); + + if (printf_system ( "clustalw_aln2fasta_aln.pl %s > %s",file_name, tmp_name)!=EXIT_SUCCESS) + { + printf_exit ( EXIT_FAILURE, stderr, "Could Not Read File %s [FATAL:%s]\n", file_name, PROGRAM); + } + else + { + S=get_fasta_sequence ( tmp_name,NULL); + A=seq2aln (S, A, 0); + } + return; +} +void read_stockholm_aln (char *file_name, Alignment *A) +{ + char *tmp_name; + Sequence *S; + + + tmp_name=vtmpnam (NULL); + if (printf_system ( "clustalw_aln2fasta_aln.pl %s > %s",file_name, tmp_name)!=EXIT_SUCCESS) + { + printf_exit ( EXIT_FAILURE, stderr, "Could Not Read File %s [FATAL:%s]\n", file_name, PROGRAM); + } + else + { + int a; + S=get_fasta_sequence ( tmp_name,NULL); + for (a=0; anseq; a++) + { + if (strstr (S->name[a], "_stockholm")) + { + substitute ( S->name[a], "_stockholmspace_", " "); + substitute ( S->name[a], "_stockholmhasch_", "#"); + } + } + A=seq2aln (S, A, 0); + } + return; +} +Alignment* read_blast_aln ( char *file_name, Alignment *A) +{ + char *tmp_name; + + int type; + + + if ( !(type=is_blast_file (file_name))) + { + myexit (EXIT_FAILURE); + } + tmp_name=vtmpnam ( NULL); + if (type==BLAST_TXT) + { + printf_system("cat %s | blast_aln2fasta_aln.pl | fasta_aln2fasta_aln_unique_name.pl >%s", file_name, tmp_name); + } + else if (type==BLAST_XML) + { + + printf_system("blast_xml2fasta_aln.pl %s >%s", file_name, tmp_name); + } + + main_read_aln (tmp_name, A); + return A; +} + + +void read_number_aln ( char *file_name, Alignment *A) + { + FILE *fp, *fp2; + int * ptr_aln; + int a,b,d; + int c; + char *buf=NULL; + + int tot=0; + int flag=0; + char *fname; + int n_comment=0; + + int nseq=0; + int max_len=0; + + + fp=vfopen ( file_name, "r"); + + fname=vtmpnam(NULL); + fp2=vfopen ( fname, "w"); + while ( (c=fgetc(fp))!=EOF) + { + fprintf ( fp2, "%c", c); + } + vfclose (fp); + vfclose (fp2); + + + /*1 Count The number of sequences*/ + fp=vfopen ( fname, "r"); + buf=vfgets ( buf,fp); + if ( !isblanc (buf)); + while ( isblanc (buf)) + { + buf=vfgets ( buf, fp); + } + while (!isblanc (buf)) + { + buf=vfgets ( buf,fp); + } + while ( !isalnum ((c=fgetc(fp)))) + { + ungetc(c,fp); + buf=vfgets ( buf,fp); + } + + if ( c!='\n')ungetc(c,fp); + + while ( isalnum ((c=fgetc(fp)))) + { + ungetc(c,fp); + a=0; + while ( isgraph ((c=fgetc(fp)))); + nseq++; + buf=vfgets ( buf, fp); + } + vfclose (fp); + + /*DONE*/ + /*2 get_max_len*/ + max_len=count_n_char_in_file(fname)/nseq; + A=realloc_alignment2( A, nseq+1, max_len+1); + + /*DONE*/ + + + fp=vfopen ( fname, "r"); + buf=vfgets ( buf, fp); + if ( !isblanc (buf))sprintf (A->aln_comment[n_comment++], "%s", buf); + while ( isblanc (buf)) + { + buf=vfgets ( buf,fp); + } + while (!isblanc (buf)) + { + buf=vfgets ( buf, fp); + sprintf ( A->aln_comment[n_comment++], "%s", buf); + + } + while ( !isalnum ((c=fgetc(fp)))) + { + ungetc(c,fp); + buf=vfgets ( buf, fp); + + } + + if ( c!='\n')ungetc(c,fp); + + while ( isalnum ((c=fgetc(fp)))) + { + ungetc(c,fp); + + fscanf_seq_name (fp, A->name[A->nseq]); + + if ( name_is_in_list (A->name[A->nseq], A->name, A->nseq, 100)!=-1) + { + fprintf ( stderr, "\nWARNING (read_number_aln): Sequence %s Duplicated in File %s ", A->name[A->nseq], A->file[A->nseq]); + if (!getenv("ALLOW_DUPLICATE")) + { + fprintf ( stderr, " [FATAL:%s]\n", PROGRAM); + myexit (EXIT_FAILURE); + } + } + A->nseq++; + buf=vfgets ( buf,fp); + } + + vfclose (fp); + + + + if ((fp=vfopen ( fname, "r"))==NULL) + printf ( "\nCOULDN'T READ %s", fname); + + ptr_aln=vcalloc ( A->nseq, sizeof(int)); + while ( flag==0) + { + while ( (c=fgetc(fp))!='\n'); + if ( (c=fgetc(fp))=='\n') + flag=1; + } + while ( !isalnum(c=fgetc(fp))); + ungetc ( c, fp); + while ( c!=EOF) + { + tot=0; + while(tot< A->nseq && c!=EOF) + { + b=0; + while ( !isgraph (c=fgetc(fp)) && c!=EOF); + if ( c!=EOF)ungetc(c, fp); + while ( isgraph((buf[b++]=fgetc(fp)))); + buf[b-1]='\0'; + for ( a=-1,d=0; d< A->nseq; d++) + if ( strcmp (A->name[d], buf)==0) + {a=d; + tot++; + } + + if ( a==-1) while ( (c=fgetc(fp))!='\n' && c!=EOF); + else + { + while ( (c=fgetc(fp))!='\n') + { + if ( isgraph(c) || is_gap(c)) + {if ( isalpha(c)) + c=(A->residue_case==2)?c:tolower(c); + + if (!isspace(c))A->seq_al[a][ptr_aln[a]++]=c; + } + } + } + } + while ( !isalnum(c=getc(fp)) && c!=EOF); + if ( c!=EOF) + ungetc (c, fp); + } + + vfclose (fp); + + + for ( a=0; a< A->nseq; a++) + {A->seq_al[a][ptr_aln[a]]='\0'; + A->order[a][0]=a; + A->order[a][1]=0; + } + + A->len_aln= strlen(A->seq_al[0]); + + vfree (buf); + vfree(ptr_aln); + vremove (fname); + + } +void read_amps_aln ( char *in_file, Alignment *A) + { + FILE *fp; + int a, b, c, cont=1; + A->nseq=get_amps_seq_name ( A->name, in_file); + + fp=vfopen ( in_file, "r"); + fp=set_fp_id(fp, "1*"); + while ( (c=fgetc(fp))!='\n'); + b=0; + while ( cont==1) + { + c=fgetc ( fp); + c=fgetc(fp); + if ( c=='*') + { + cont=0; + for ( a=0; anseq; a++) + A->seq_al[a][b]='\0'; + A->len_aln=b; + } + + else + { + ungetc (c, fp); + for ( a=0; a< A->nseq; a++) + { + c=fgetc(fp); + if ( c==' ')A->seq_al[a][b]='-'; + else + { + A->seq_al[a][b]=c; + A->len[a]++; + } + } + while ((c=fgetc(fp))!='\n'); + b++; + } + } + } + + + + + + +int get_amps_seq_name ( char **name, char* fname) + { + FILE *fp; + int nseq=0; + + fp=vfopen ( fname, "r"); + fp=set_fp_id ( fp, "Index"); + while ( (fgetc(fp))!='\n'); + while ( isspace(fgetc(fp))) + {fscanf (fp, "%*d >%s", name[nseq++]); + while ( (fgetc(fp))!='\n'); + } + vfclose ( fp); + return nseq; + } +Alignment * read_gotoh_aln ( char *fname, Alignment *A) + { + FILE *fp; + int * ptr_aln; + int a,b,d,e; + + + char *buf; + char buf2[VERY_LONG_STRING+1]; + char buf3[VERY_LONG_STRING+1]; + char buf4[VERY_LONG_STRING+1]; + + int tot=0; + + int l; + int nseq, max_len; + + + if ( !check_file_exists (fname))return NULL; + fp=vfopen ( fname, "r"); + +/*1 GET THE NUMBER OF SEQUENCES*/ + nseq=0; + buf=vcalloc ( VERY_LONG_STRING+1, sizeof (char)); + while ( isblanc (buf=fgets ( buf, VERY_LONG_STRING, fp))); + while (!isblanc (buf=fgets ( buf, VERY_LONG_STRING, fp))); + while ( isblanc (buf=fgets ( buf, VERY_LONG_STRING, fp))); + while ( !isblanc ( buf) && buf!=NULL) + { + a=-1; + d=sscanf ( buf, "%d %s %s %s", &a, buf2, A->name[A->nseq],buf3); + if ( a!=-1) + { + if ( name_is_in_list (A->name[A->nseq], A->name, A->nseq, 100)!=-1) + { + fprintf ( stderr, "\nWARNING (get_amps_seq_name): Sequence %s Duplicated in File %s ", A->name[A->nseq], A->file[A->nseq]); + if (!getenv("ALLOW_DUPLICATE")) + { + fprintf ( stderr, " [FATAL:%s]\n", PROGRAM); + myexit (EXIT_FAILURE); + } + } + nseq++; + fgets(buf, VERY_LONG_STRING, fp); + } + else ( buf=NULL); + } + vfclose (fp); +/*2 Get the MAX Len and Reallocate*/ + max_len=count_n_char_in_file(fname)/nseq; + A=realloc_aln2( A, nseq+1, max_len+1); +/*3 Get The Sequences Names*/ + A->nseq=0; + fp=vfopen ( fname, "r"); + while ( isblanc (buf=fgets ( buf, VERY_LONG_STRING, fp))); + while (!isblanc (buf=fgets ( buf, VERY_LONG_STRING, fp))); + while ( isblanc (buf=fgets ( buf, VERY_LONG_STRING, fp))); + while ( !isblanc ( buf) && buf!=NULL) + { + a=-1; + d=sscanf ( buf, "%d %s %s %s", &a, buf2, A->name[A->nseq],buf3); + if ( a!=-1) + { + if ( d==4)sprintf (A->name[A->nseq],"%s", buf3); + A->nseq++; + fgets(buf, VERY_LONG_STRING, fp); + } + else ( buf=NULL); + } + vfclose (fp); + +/*READ THE ALN*/ + fp=vfopen ( fname, "r"); + + buf=vcalloc ( VERY_LONG_STRING+1, sizeof (char));; + ptr_aln=vcalloc ( A->nseq, sizeof(int)); + + while ( isblanc (buf=fgets ( buf, VERY_LONG_STRING, fp))); + while (!isblanc (buf=fgets ( buf, VERY_LONG_STRING, fp))); + + + while ( isblanc (buf=fgets ( buf, VERY_LONG_STRING, fp))); + + while (buf!=NULL) + { + tot=0; + while(tot< A->nseq) + { + + e=sscanf (buf, "%d %s %s %s", &e, buf2, buf3, buf4); + if ( e==4)sprintf( buf3, "%s", buf4); + + + for ( d=0; d< A->nseq; d++) + { + + if ( strcmp (A->name[d], buf3)==0) + {a=d; + tot++; + } + } + l=strlen (buf2); + if ( buf2[l-1]=='|')l--; + buf2[l]='\0'; + + for (b=0; bseq_al[a][ptr_aln[a]++]=(A->residue_case==2)?buf2[b]:tolower (buf2[b]); + } + buf=fgets(buf, VERY_LONG_STRING, fp); + } + if ( buf!=NULL) + { + buf=fgets(buf, VERY_LONG_STRING, fp); + while ( isblanc (buf) && buf!=NULL) + { + buf=fgets ( buf, VERY_LONG_STRING, fp); + } + } + + } + + vfclose (fp); + + + for ( a=0; a< A->nseq; a++) + {A->seq_al[a][ptr_aln[a]]='\0'; + } + + A->len_aln= strlen(A->seq_al[0]); + + + + for ( a=0; a< A->nseq; a++) + { + for ( b=0; b< A->len_aln; b++) + A->len[a]+=1-is_gap(A->seq_al[a][b]); + } + for ( a=0, b=0; a< A->len_aln; a++) + { + if ( !is_gap(A->seq_al[0][a]) &&!is_gap(A->seq_al[1][a]))b++; + } + return A; + } + + + + + +void read_msf_aln ( char *fname, Alignment *A) + { + char command[1000]; + char *tmp_name; + Sequence *S; + + tmp_name=vtmpnam(NULL); + sprintf ( command, "msf_aln2fasta_aln.pl %s > %s", fname, tmp_name); + + if ( my_system (command)!=EXIT_SUCCESS) + { + fprintf ( stderr, "\nERROR: file %s does not have a legal msf format [FATAL:%s]", fname,PROGRAM); + myexit (EXIT_FAILURE); + } + + S=get_fasta_sequence ( tmp_name,NULL); + A=seq2aln (S, A, 0); + vremove (tmp_name); + return; + } + +/**************************************************************************************************/ +/*************************************REFORMAT OUT*************************************************/ +/**************************************************************************************************/ +/*******************************************************************************************/ +/* */ +/* */ +/* OUTPUT MATRICES */ +/* */ +/***************************************************************************************** */ + + + +int output_freq_mat ( char *outfile, Alignment *A) + { /* + function documentation: start + + int output_freq_mat ( char *outfile, Aligmnent *A) + + This function counts the number of residues in each column of an alignment (Prot) + It outputs these values in the following format + + A | 0 0 0 1 0 + B | 1 0 0 0 1 + - | 0 1 1 0 0 + + This format can be piped into: + The routine used for computing the p-value gmat-inf-gc-v2c + + function documentation: end + */ + + int a, b; + int **freq_mat; + FILE *fp; + + + freq_mat=aln2count_mat (A); + + fp=vfopen ( outfile, "w"); + for ( b=0; b< 26; b++) + { + fprintf (fp, "%c |", 'A'+b); + for ( a=0; a< A->len_aln; a++)fprintf (fp,"%d ", freq_mat[b][a]); + fprintf (fp, "\n"); + } + fprintf (fp, "- |"); + for ( a=0; a< A->len_aln; a++)fprintf (fp,"%d ", freq_mat[26][a]); + + free_int (freq_mat, -1); + vfclose ( fp); + return 1; + } +/*******************************************************************************************/ +/* */ +/* */ +/* OUTPUT P-Values */ +/* */ +/***************************************************************************************** */ +float output_maln_pval ( char *outfile, Alignment *A) + { + /* + function documentation: start + float output_maln_pval ( char *outfile, Aligmnent *A) + + This function outputs the p-value of a multiple alignmnet as described + in Hertz, Stormo, Bioinformatics, 15-7/8, 563/577 + ftp beagle.colorado.edu /pub/cosensus + Locally + packages/consensus/gmat-inf-gc-v2c + + + The routine used for computing the p-value is the program gmat-inf-gc-v2c + function documentation: end + */ + + + char *mat; + char *result; + FILE *fp; + float value; + char command[LONG_STRING]; + char string[STRING]; + mat=vtmpnam (NULL); + result=vtmpnam (NULL); + + output_freq_mat (mat,A); + sprintf ( command, "more %s | gmat-inf-gc-v2c -A abcdefghijklmnopqrstuvwxyz> %s",mat, result); + my_system ( command); + + if ( !check_file_exists(result))return 0; + fp=find_token_in_file ( result, NULL, "ln(p-value):"); + + fscanf ( fp, "%s",string); + value=atof ( string); + vfclose ( fp); + + vremove ( mat); + vremove ( result); + + fp=vfopen ( outfile, "w"); + fprintf ( fp, "%.6f\n", value); + vfclose ( fp); + + return value; + } + + +/*******************************************************************************************/ +/* */ +/* */ +/* OUTPUT WEIGHTS */ +/* */ +/***************************************************************************************** */ +int output_seq_weights ( Weights *W, char *wfile) + { + FILE*fp; + int a; + + if ( W==NULL)return 0; + + fp=vfopen (wfile, "w"); + if ( fp==NULL)return 0; + + + for ( a=0; a< W->nseq; a++) + { + + fprintf ( fp, "%s %.2f\n", W->seq_name[a],W->SEQ_W[a]); + } + vfclose ( fp); + return 1; + } +void output_pw_weights4saga ( Weights *W, float **w_list, char *wfile) + { + FILE*fp; + int a, b; + fp=vfopen (wfile, "w"); + + fprintf ( fp, "%s\n$\n", W->comments); + for ( a=0; a< W->nseq-1; a++) + { + for (b=a+1; b< W->nseq; b++) + { + fprintf ( fp, "%s %s %f\n", W->seq_name[a], W->seq_name[b],w_list[a][b]); + } + } + fprintf ( fp, "$\n"); + vfclose ( fp); + } + +FILE * display_weights (Weights *W, FILE *fp) +{ + int a; + int max_len; + + if ( W==NULL) + { + fprintf ( fp, "\n\nUN-WEIGHTED MODE: EVERY SEQUENCE WEIGHTS 1\n"); + return fp; + } + fprintf ( fp, "\n\nWEIGHTED MODE:%s\n\n", (W)->mode); + for ( a=0, max_len=0; a< W->nseq; a++)max_len=MAX(max_len, strlen (W->seq_name[a])); + for ( a=0; a< (W->nseq); a++) + { + fprintf ( fp, "\t%*s %.2f\n", max_len,(W)->seq_name[a],W->SEQ_W[a]); + } + fprintf ( fp, "\n"); + return fp; +} + +/*******************************************************************************************/ +/* */ +/* */ +/* OUTPUT SEQ */ +/* */ +/***************************************************************************************** */ +int ** input_similarities (char *file, Alignment *A, char *mode) +{ + int a, b, i, n; + int **sim; + float score; + char name[1000]; + FILE *fp=NULL; + char *buf1=NULL, *buf2=NULL; + int new_aln=0; + + + + if ( !check_file_exists (file) || !is_distance_matrix_file (file) ||!is_similarity_matrix_file (file) ) + { + return NULL; + } + + if ( A) + { + fp=vfopen (file, "r"); + while ((buf2=vfgets (buf1,fp))!=NULL ) + { + if (strstr (buf2, "SEQ_INDEX")) + { + buf1=buf2; + sscanf (buf1, "# SEQ_INDEX %s %d",name, &i); + if ( !strm (A->name[i], name)) + { + return NULL; + } + } + } + vfclose (fp); + } + else + { + + A=similarities_file2aln(file); + new_aln=1; + } + + sim=declare_int ( A->nseq, A->nseq); + for ( a=0; anseq; a++)sim[a][a]=100; + + + fp=find_token_in_file (file, NULL, "PW_SEQ_DISTANCES"); + fp=find_token_in_file (file, fp, "BOT"); + while ((buf2=vfgets (buf1,fp))!=NULL ) + { + if ( !(strstr (buf2, "BOT\t") || strstr (buf2, "TOP\t")))continue; + buf1=buf2; + n=sscanf (buf1, "%*s %d %d %f", &a, &b, &score); + if ( n!=3) + { + free_int (sim, -1); + return NULL; + } + else sim[a][b]=sim[b][a]=(int)score; + } + vfclose (fp); + vfree (buf1); + if (new_aln)free_aln(A); + return sim; +} + +Alignment * similarities_file2aln ( char *file) +{ + int nseq=0, i; + FILE *fp; + char name[1000]; + Alignment *A; + + + fp=vfopen (file, "r"); + while ((fp=find_token_in_file (file,fp, "SEQ_INDEX")))nseq++; + A=declare_aln2 (nseq+1, 10); + + while ((fp=find_token_in_file (file,fp, "SEQ_INDEX"))) + { + fscanf (fp, "%s %d", name,&i); + sprintf ( A->name[i], "%s", name); + } + A->nseq=nseq; + + return A; +} + +void output_similarities (char *file, Alignment *A, char *mode) +{ + float s; + float *tot; + float bigtot=0; + int n, max; + FILE *fp; + int a, b; + char *p; + int **M=NULL; + for (max=0, a=0; a< A->nseq; a++)max=MAX(max,(strlen (A->name[a]))); + + + tot=vcalloc ( A->nseq, sizeof (float)); + fp=vfopen (file, "w"); + fprintf (fp, "# TC_SIMILARITY_MATRIX_FORMAT_01\n"); + for ( a=0; anseq; a++) + fprintf ( fp, "# SEQ_INDEX %s %d\n",A->name[a],a); + fprintf ( fp, "# PW_SEQ_DISTANCES \n"); + for (n=0,a=0;a< A->nseq-1; a++) + { + for ( b=a+1; bnseq; b++, n++) + { + if (strstr (mode, "_sarmat2")) + { + s=get_sar_sim (A->seq_al[a], A->seq_al[b]); + } + else if (strstr (mode, "_sar")) + { + s=get_sar_sim (A->seq_al[a], A->seq_al[b]); + } + else if ( (p=strstr (mode, "_memory_"))) + { + int **sim; + sscanf ( p, "_memory_%ld", (long int*)&sim); + s=sim[a][b]; + } + else if ( strstr (mode, "_idscore") || strstr ( mode, "_covscore")) + { + static Sequence *S; + if (a==0 && b==1) + { + free_sequence (S, -1); + if ( strstr (mode, "idscoreDNA")) + M=read_matrice ("idmat"); + else + M=read_matrice("blosum62mt"); + + S=aln2seq(A); + } + if ( strstr (mode, "_idscore"))s=idscore_pairseq(S->seq[a], S->seq[b], -10,-1, M, "sim"); + else s=idscore_pairseq(S->seq[a], S->seq[b], -10,-1, M, "cov"); + } + else if ( strstr (mode, "cov")) + { + s=get_seq_sim ( A->seq_al[a], A->seq_al[b],GAP_LIST, "cov"); + } + else + { + s=get_seq_fsim2 (A->seq_al[a], A->seq_al[b],GAP_LIST, mode); + } + fprintf (fp, "BOT\t %4d %4d\t %5.2f %*s\t %*s\t %5.2f\n", a,b,s,max,A->name[a], max, A->name[b], s); + fprintf (fp, "TOP\t %4d %4d\t %5.2f %*s\t %*s\t %5.2f\n", b,a,s,max,A->name[b], max, A->name[a], s); + tot[a]+=s; + tot[b]+=s; + bigtot+=s; + } + } + for ( a=0; a< A->nseq; a++) + { + fprintf (fp, "AVG\t %d\t %*s\t %*s\t %5.2f\n", a,max,A->name[a], max, "*", tot[a]/(A->nseq-1)); + + } + vfree (tot);free_int (M, -1); + fprintf (fp, "TOT\t %*s\t %*s\t %5.2f\n", max,"TOT", max, "*", bigtot/n); + vfclose (fp); +} + +void output_similarities_pw (char *file, Alignment *A, Alignment *B,char *mode) +{ + float s; + float *tot; + float bigtot=0; + int n, max; + FILE *fp; + int a, b; + + int **M=NULL; + Sequence *SA, *SB; + + if ( strstr (mode, "idscoreDNA")) + M=read_matrice ("idmat"); + else + M=read_matrice("blosum62mt"); + + SA=aln2seq(A); + SB=aln2seq(B); + + for (max=0, a=0; a< A->nseq; a++)max=MAX(max,(strlen (A->name[a]))); + for (a=0; a< B->nseq; a++)max=MAX(max,(strlen (B->name[a]))); + + + tot=vcalloc ( A->nseq, sizeof (float)); + fp=vfopen (file, "w"); + fprintf (fp, "# TC_SIMILARITY_MATRIX_FORMAT_01\n"); + for ( a=0; anseq; a++) + fprintf ( fp, "# SEQ_INDEX %s %d\n",A->name[a],a); + fprintf ( fp, "# PW_SEQ_DISTANCES \n"); + for (n=0,a=0;a< A->nseq; a++) + { + for ( b=0; bnseq; b++, n++) + { + s=idscore_pairseq(SA->seq[a], SB->seq[b], -10,-1, M, "sim"); + fprintf (fp, "BOT\t %4d %4d\t %5.2f %*s\t %*s\t %5.2f\n", a,b,s,max,A->name[a], max, B->name[b], s); + fprintf (fp, "TOP\t %4d %4d\t %5.2f %*s\t %*s\t %5.2f\n", b,a,s,max,B->name[b], max, A->name[a], s); + tot[a]+=s; + tot[b]+=s; + bigtot+=s; + } + } + + for ( a=0; a< A->nseq; a++) + { + fprintf (fp, "AVG\t %d\t %*s\t %*s\t %5.2f\n", a,max,A->name[a], max, "*", tot[a]/(A->nseq-1)); + } + vfree (tot);free_int (M, -1); + fprintf (fp, "TOT\t %*s\t %*s\t %5.2f\n", max,"TOT", max, "*", bigtot/n); + vfclose (fp); +} +void output_conservation_statistics ( char *file, Alignment *A) +{ + int a, b, c,c1, c2; + double **tot; + char aa[1000]; + int naa; + + sprintf (aa, "%s", BLAST_AA_ALPHABET); + naa=strlen (aa); + + tot=declare_double (256, 256); + + + for ( a=0; anseq; a+=2) + { + b=a+1; + for ( c=0; clen_aln; c++) + { + c1=tolower (A->seq_al[a][c]); + c2=tolower (A->seq_al[b][c]); + if ( !is_gap(c1) && !is_gap(c2)) + { + tot[c1][c2]++; + tot[c2][c1]++; + tot[c1][0]++; + tot[c2][0]++; + tot[0][0]++; + } + } + } + + fprintf ( stdout, "# BLAST_MATRIX FORMAT\n#ALPHABET=%s\n",aa); + for (a=0; anseq; a++)maxname=MAX(strlen(A->name[a]), maxname); + maxname++; + + + fp=vfopen (file, "w"); + + if (mode[0]=='h') + { + b=0; + while ((c=mode[b++])!='\0') + { + if ( c=='n') fprintf (fp, "%-*s ",maxname,"name"); + if ( c=='l') fprintf (fp, "%-*s ",5,"nres"); + if ( c=='g') fprintf (fp, "%-*s ",5,"ngap"); + if ( c=='t') fprintf (fp, "%-*s ",5,"len"); + } + if (is_in_set ( c, "nlgt")) fprintf (fp, "\n"); + mode++; + } + b=0; + while ((c=mode[b++])!='\0') + { + if ( c=='n')break; + if ( c=='N'){d=1;fprintf (fp, "NSEQ %d ", A->nseq);} + if ( c=='L'){d=1;fprintf (fp, "LEN %d ", A->len_aln);} + } + if ( d) fprintf (fp, "\n"); + + for (a=0; anseq; a++) + { + b=0; + d=0; + while ((c=mode[b++])!='\0') + { + if (is_in_set ( c, "nlgt"))d=1; + + if (c=='n'){d=1;fprintf ( fp, "%-*s ", maxname,A->name[a]);} + if (c=='l') + { + for (n=0,d=0; dlen_aln; d++)n+=!is_gap(A->seq_al[a][d]); + fprintf ( fp, "%-5d ",n); + } + if (c=='g') + { + for (n=0,d=0; dlen_aln; d++)n+=((is_gap(A->seq_al[a][d]) && !is_gap(A->seq_al[a][d+1]))||(is_gap(A->seq_al[a][d])&& A->seq_al[a][d+1]=='\0')) ; + fprintf ( fp, "%-5d ",n); + } + if (c=='t') + { + fprintf ( fp, "%-5d ",(int)strlen (A->seq_al[a])); + } + if (c=='N' && d) + { + fprintf ( fp, "%-5d ",A->nseq); + } + if (c=='L'&& d) + { + fprintf ( fp, "%-5d ",A->len_aln); + } + } + if (d)fprintf ( fp, "\n"); + } + vfclose (fp); + } + +int output_age_matrix ( char *outfile, int val) +{ + int **mat; + int a, b; + char alp[]="abcdefghij-"; + int naa; + + mat=declare_int ( 256, 256); + naa=strlen (alp); + for ( a=0; anseq; a++) + { + ungap (A->seq_al[a]); + lower_string (A->seq_al[a]); + s=A->seq_al[a]; + l=strlen (s); + if ( s[0]=='\0') continue; + symbols[(int)s[0]]++; + for ( b=1; b< l; b++) + { + symbols[(int)s[b]]++; + table[(int)s[b-1]][(int)s[b]]++; + tot++; + } + } + for (naa=0, a=0; a< 256; a++) + { + if (symbols[a])alp[naa++]=a; + } + + + for ( a=0; a< 256; a++) + for (b=0; b<256; b++) + { + if (symbols[a]&& symbols[b] && table[a][b] && tot>0) + { + freq=(table[a][b])/tot; + expected=(symbols[a]*symbols[b])/(tot*tot); + log_odd=log (freq/expected); + mat[a-'A'][b-'A']=log_odd*10; + fmat[a-'A'][b-'A']=log_odd; + } + else if ( symbols[a]&& symbols[b]) + { + mat[a-'A'][b-'A']=-999; + fmat[a-'A'][b-'A']=-999; + } + } + output_mat ( mat,outfile, alp, 'A'); + + fp=vfopen (outfile, "a"); + for ( a=0; a<256; a++) + if ( symbols[a]) + { + fprintf (fp, "# %c tot: %6d freq: %7.5f\n", a, (int)symbols[a],(float)symbols[a]/tot); + } + + for ( a=0; a< 256; a++) + for (b=0; b<256; b++) + { + if (symbols[a]&& symbols[b]) + { + freq=(table[a][b])/tot; + fprintf (fp, "# %c%c tot: %6d freq: %7.5f log_odd: %9.3f\n", a, b, (int)table[a][b],(float)freq,fmat[a-'A'][b-'A']); + } + } + vfclose (fp); + vfree(alp); + free_arrayN ((void **)mat, 2); + free_arrayN ((void **)fmat, 2); + + return 1; +} + + + +void output_est_prf (char *fname, Alignment *A) + { + int a; + FILE *fp; + + if ( !A->P) + { + fprintf ( stderr, "\nFormat output_est_prf Impossible: No profile\n"); + myexit(EXIT_FAILURE); + } + + + fp=vfopen ( fname, "w"); + fprintf ( fp, "Consensus Sequence\nReconstructed with %s (%s,%s)\n",PROGRAM,AUTHOR,DATE); + fprintf ( fp, "%4c %4c %4c %4c %15s Consensus\n", 'A','G','C','T', "Internal Gaps"); + + for ( a=0; a< A->len_aln; a++) + { + fprintf (fp, "%4d %4d %4d %4d %15d %c\n", (A->P)->count[0][a],(A->P)->count[1][a],(A->P)->count[2][a], (A->P)->count[3][a], (A->P)->count[4][a],A->seq_al[0][a]); + } + return; + } + + +void output_gotoh_seq (char *fname, Alignment*A ) + { + int a; + FILE *fp; + + fp=vfopen ( fname, "w"); + fprintf ( fp, "%d %d\n",A->nseq, A->max_len); + for ( a=0; a< A->nseq; a++) + { + ungap ( A->seq_al[a]); + fprintf ( fp, ">%s\n", A->name[a]); + fp=output_string_wrap ( 50,A->seq_al[a] , fp); + fprintf ( fp, "//\n"); + } + + vfclose (fp); + } + +void output_mult_fasta_seq (char *fname, Alignment*A, int n ) + { + int a; + FILE *fp; + + fp=vfopen (fname, "w"); + ungap(A->seq_al[0]); + for (a=0; a%s_%d\n%s\n", A->name[0],a+1, A->seq_al[0]); + } + vfclose (fp); + } +int output_wexons (char *name, Alignment *A) +{ + int a,b,c; + FILE *fp; + int **w; + fp=vfopen (name, "w"); + if (!fp) return 0; + if (!A) {vfclose(fp);return 0;} + w=A->score_res; + if (!w) {vfclose (fp);return 0; } + + for (a=0; anseq; a++) + { + fprintf (fp, ">%s\n", A->name[a]); + for (c=0,b=0; blen_aln; b++) + { + int r; + r=A->seq_al[a][b]; + if (!is_gap(r) && r!='f' && r!='F') + { + fprintf (fp, " %c %d ", r,w[a][c++]); + } + else if (!is_gap(r))fprintf (fp,"%c -1 ",r); + } + fprintf (fp, "\n"); + } + return 1; +} +char * output_fasta_seqX (char *name, char *mode, Sequence *S, Alignment *A, int i) +{ + FILE *fp; + + if (!name)name=vtmpnam (NULL); + fp=vfopen (name, mode); + if ( (S && S->nseq<=i) || (A && S->nseq<=i) || (!A && !S)) + { + fprintf ( stderr, "\nERROR in function reformat:output_fasta_seqX[FATAL:%s]", PROGRAM); + myexit (EXIT_FAILURE); + } + + else if ( S) + fprintf ( fp, ">%s %s\n%s\n", S->name[i], S->seq_comment[i], S->seq[i]); + else if ( A) + { + ungap (A->seq_al[i]); + fprintf ( fp, ">%s %s\n%s\n", A->name[i], A->seq_comment[i], A->seq_al[i]); + } + vfclose (fp); + return name; +} + +void output_fasta_seq1 (char *fname, Alignment*A ) + { + char seq_name[VERY_LONG_STRING]; + int a; + FILE *fp; + char *extension; + + for ( a=0; a< A->nseq; a++) + { + if ( strncmp( fname, "name",4)==0) + { + if ( (fname+4)[0]!='\0')extension=fname+5; + else + extension=NULL; + + sprintf ( seq_name,"%s.%s", A->name[a],(extension==NULL)?"seq":extension); + } + else + sprintf ( seq_name,"%s.seq",A->name[a]); + + ungap ( A->seq_al[a]); + fp=vfopen (seq_name, "w"); + fprintf (fp, ">%s %s\n", A->name[a], A->seq_comment[a]); + fp=output_string_wrap ( 50, A->seq_al[a],fp); + fprintf ( fp, "\n"); + vfclose (fp); + } + } +void output_pir_check (char *fname,int nseq, char **comment ) + { + int a; + FILE *fp; + + if ( fname==NULL)return; + fp=vfopen ( fname, "w"); + + for ( a=0; a< nseq; a++)fprintf (fp, "%s\n", comment[a]); + vfclose (fp); + } +void output_fasta_seqS (char *fname, Sequence *S) +{ + Alignment *A; + A=seq2aln (S,NULL,RM_GAP); + output_fasta_seq (fname, A); + free_aln (A); +} + +void output_fasta_seq (char *fname, Alignment*A) +{ + main_output_fasta_seq (fname, A, HEADER); +} +void output_fasta_tree (char *fname, Alignment*A) + { + int a; + FILE *fp; + if ( !A || !A->nseq) return; + + fp=vfopen ( fname, "w"); + + for ( a=0; a< A->nseq; a++) + { + fprintf ( fp, ">%s %s\n%s\n", A->name[a], A->seq_comment[a], A->seq_al[a]); + } + vfclose (fp); + } +void main_output_fasta_seq (char *fname, Alignment*A,int header ) + { + int a; + FILE *fp; + + fp=vfopen ( fname, "w"); + + for ( a=0; a< A->nseq; a++) + { + ungap(A->seq_al[a]); + fprintf ( fp, ">%s", A->name[a]); + if (header==HEADER && A->seq_comment[a][0] && !isblanc(A->seq_comment[a]))fprintf (fp," %s\n",A->seq_comment[a]); + else fprintf ( fp, "\n"); + fp=output_string_wrap ( 50, A->seq_al[a],fp); + fprintf ( fp, "\n"); + } + vfclose (fp); + } +void output_gor_seq (char *fname, Alignment*A ) + { + int a; + FILE *fp; + + fp=vfopen ( fname, "w"); + + for ( a=0; a< A->nseq; a++) + { + ungap(A->seq_al[a]); + fprintf ( fp, "!%s %d \n", A->name[a], (int)strlen(A->seq_al[a])); + upper_string ( A->seq_al[a]); + fp=output_string_wrap ( 50, A->seq_al[a],fp); + fprintf ( fp, "@\n"); + } + vfclose (fp); + } +void output_pir_seq (char *fname, Alignment*A ) + { + int a; + for ( a=0; a< A->nseq; a++)ungap(A->seq_al[a]); + output_pir_aln (fname, A); + } +void output_pir_seq1 (char *fname, Alignment*A ) + { + char seq_name[VERY_LONG_STRING]; + int a; + FILE *fp; + char type[20]; + + + for ( a=0; a< A->nseq; a++) + { + if ( strm ( get_string_type (A->seq_al[a]),"DNA") || strm ( get_string_type (A->seq_al[a]),"RNA"))sprintf(type, "DL"); + else if ( strm ( get_string_type (A->seq_al[a]),"PROTEIN"))sprintf(type, "P1"); + sprintf ( seq_name,"%s;%s_%s.seq",type, fname,A->name[a]); + ungap ( A->seq_al[a]); + fp=vfopen (seq_name, "w"); + fprintf (fp, ">%s\n\n", A->name[a]); + fp=output_string_wrap ( 50, A->seq_al[a],fp); + fprintf ( fp, "\n*\n"); + vfclose (fp); + } + } +/*******************************************************************************************/ +/* */ +/* */ +/* OUTPUT ALN */ +/* */ +/***************************************************************************************** */ +void output_mocca_aln (char *outfile, Alignment *A, Alignment *S) + { + FILE *fp; + int **score; + char **new_name_order; + int a, maxl; + + score=declare_int (S->nseq, 2); + new_name_order=declare_char ( S->nseq,MAXNAMES+1); + for ( a=0; anseq; a++) + { + score[a][0]=a; + score[a][1]=S->score_seq[a]; + } + sort_int_inv (score+1,2,1,0,S->nseq-2); + for ( a=0; anseq; a++) + { + sprintf ( new_name_order[a], "%s", A->name[score[a][0]]); + } + A=reorder_aln (A, new_name_order, A->nseq); + + fp=vfopen (outfile, "w"); + fprintf ( fp, "MOCCA,(%s,%s, C. Notredame)\nSCORE %d\nNSEQ %d\nLEN %d\n",VERSION,DATE, A->score_aln, A->nseq, A->len_aln); + + maxl=return_maxlen ( new_name_order, A->nseq); + + + for (a=0; a< A->nseq; a++) + { + fprintf (fp, "%-*s: %3d\n", maxl, A->name[a], score[a][1]); + } + + fprintf ( fp, "\n"); + + fp=output_Alignment_without_header ( A, fp); + vfclose (fp); + free_int (score, -1); + free_char (new_name_order, -1); + return ; + } + +void print_sub_aln ( Alignment *B, int *ns, int **ls) +{ + Alignment *X; + int a, b; + + + X=copy_aln (B, NULL); + X->nseq=0; + X->len_aln=strlen ( B->seq_al[ls[0][0]]); + + + for (a=0; a< 2; a++) + for ( b=0; bnseq++) + { + sprintf ( X->seq_al[X->nseq], "%s", B->seq_al[ls[a][b]]); + sprintf ( X->name[X->nseq], "%s", B->name[ls[a][b]]); + } + X->name[X->nseq][0]='\0'; + + print_aln (X); + free_aln (X); +} +void print_aln ( Alignment *B) + { + + while(B) + { + output_Alignment_without_header ( B, stderr); + B=B->A; + } + } + + +FILE * output_aln ( Alignment *B, FILE *fp){return output_Alignment(B, fp);} +FILE * output_Alignment ( Alignment *B, FILE *fp) + { + fprintf ( fp, "%s, %s (%s) [%s] [MODE: %s]\n%s\nCPU %d sec\nSCORE %d\nNSEQ %d\nLEN %d\n",PROGRAM,VERSION,DATE,retrieve_mode(),URL,AUTHOR, (B->cpu+get_time())/1000, B->score_aln, B->nseq, B->len_aln); + + return output_Alignment_without_header ( B, fp); + } + +FILE * output_Alignment_without_header ( Alignment *B, FILE *fp) + { + int a,b, c; + int max_len=0; + int line; + int *n_residues; + char s; + + + if (fp==NULL)return fp; + for ( a=0; a< B->nseq; a++) + {if ( strlen (B->name[a])>max_len) + max_len= strlen ( (B->name[a])); + } + max_len=MAX(max_len+2, 16); + line=get_msa_line_length (0, 0); + n_residues=vcalloc ( B->nseq+1, sizeof (int)); + for ( a=0; anseq; a++)n_residues[a]=(B->output_res_num==2)?B->order[a][1]:0; + + + + + fprintf ( fp, "\n"); + for (a=0; alen_aln; a+=line) + {for (b=0; b<=B->nseq; b++) + { + fprintf (fp,"%-*s",max_len,B->name[b]); + if (B->output_res_num)fprintf (fp, " %4d ", n_residues[b]+1); + for (c=a;clen_aln;c++) + { + if (b==B->nseq){n_residues[b]++;s=analyse_aln_column ( B, c);} + else + {n_residues[b]+=!is_gap(B->seq_al[b][c]); + s=GET_CASE(B->residue_case, B->seq_al[b][c]); + } + + fprintf (fp,"%c",s ); + } + if (B->output_res_num)fprintf (fp, " %4d", n_residues[b]); + fprintf (fp,"\n"); + } + + fprintf (fp,"\n"); + } + + fprintf (fp,"\n\n"); + vfree (n_residues); + + return fp; + } +FILE * output_aln_score ( Alignment *B, FILE *fp){return output_Alignment_score(B, fp);} +FILE * output_Alignment_score ( Alignment *B, FILE *fp) + { + int a, b, c; + static int max_len=0; + static int line; + int ch; + + if (fp==NULL)return fp; + if ( max_len==0) + { + for ( a=0; a< B->nseq; a++) + {if ( strlen (B->name[a])>max_len) + max_len= strlen ( (B->name[a])); + } + max_len+=4; + + } + line=get_msa_line_length(0, 0); + sprintf (B->name[B->nseq], "CONS"); + fprintf ( fp, "T_COFFEE ALIGNMENT\nCPU TIME:%d sec.\n", (B->cpu+get_time())/1000); + fprintf ( fp, "SCORE=%d\n", B->score_aln); + for ( a=0;anseq; a++)fprintf ( fp, "%s: %d\n", B->name[a], B->score_seq[a]); + fprintf ( fp, "\n"); + for (a=0; alen_aln; a+=line) + {for (b=0; bnseq; b++) + { + fprintf (fp,"%-*s",max_len,B->name[b]); + for (c=a;clen_aln;c++) + { + ch=B->seq_al[b][c]; + if (ch==NO_COLOR_RESIDUE)fprintf (fp,"-"); + else if ( ch==NO_COLOR_GAP)fprintf (fp,"*"); + else if ( ch<10 && ch>=0)fprintf (fp,"%d",ch); + else if ( ch>10)fprintf (fp,"#"); + else if ( ch<0)fprintf (fp,"."); + else fprintf (fp,"9"); + } + fprintf (fp,"\n"); + } + fprintf (fp,"\n"); + fprintf (fp,"%-*s",max_len,B->name[b]); + for (c=a;clen_aln;c++) + { + ch=B->seq_al[b][c]; + if (ch==NO_COLOR_RESIDUE)fprintf (fp,"-"); + else if ( ch==NO_COLOR_GAP)fprintf ( fp, "*"); + else if ( ch<10 && ch>=0)fprintf (fp,"%d",ch); + else if ( ch>10)fprintf (fp,"#"); + else if ( ch<0)fprintf (fp,"."); + else fprintf (fp,"9"); + } + fprintf (fp,"\n\n\n"); + } + fprintf (fp,"\n\n"); + return fp; + } +FILE * output_aln_with_res_number ( Alignment *B, FILE *fp){return output_Alignment_with_res_number(B, fp);} +FILE * output_Alignment_with_res_number ( Alignment *B, FILE *fp) + { + int a, b, c; + static int max_len=0; + static int line; + int**order; + + if (fp==NULL)return fp; + if ( max_len==0) + { + for ( a=0; a< B->nseq; a++) + {if ( strlen (B->name[a])>max_len) + max_len= strlen ( (B->name[a])); + } + max_len+=4; + line=60; + } + order=copy_int ( B->order,declare_int ( B->nseq, 2), B->nseq, 2); + + fprintf ( fp, "T_COFFEE ALIGNMENT\nCPU TIME:%d sec.\n", (B->cpu+get_time())/1000); + fprintf ( fp, "\n"); + for (a=0; alen_aln; a+=line) + {for (b=0; bnseq; b++) + { + fprintf (fp,"%-*s %3d %4d ",max_len,B->name[b], order[b][0], order[b][1] ); + for (c=a;clen_aln;c++) + { + order[b][1]+=1-is_gap(B->seq_al[b][c]); + fprintf (fp,"%c",toupper(B->seq_al[b][c]) ); + } + fprintf (fp," %4d\n", order[b][1] ); + } + fprintf (fp,"\n"); + } + fprintf (fp,"\n\n"); + + free_int (order, -1); + return fp; + } + +void output_constraints ( char *fname, char *mode,Alignment *A) + { + FILE *fp; + Constraint_list *CL; + char *buf; + char **name_list; + + if ( !A->CL || strm ( mode, "pdb")) + { + if (!A->S) + { + A->S=aln2seq(A); + } + + CL=declare_constraint_list ( A->S, NULL, NULL, 0, NULL, NULL); + CL=aln2constraint_list (A,CL, mode); + fp=save_constraint_list ( CL, 0, CL->ne,fname, NULL, "lib",A->S); + vfclose (fp); + free_constraint_list (CL); + return; + } + else if ( strncmp ( mode, "extended_pair", 13)==0) + { + buf=duplicate_string (mode+14); + + name_list=vcalloc(2, sizeof(char*)); + name_list[0]=strtok (buf,"_"); + name_list[1]=strtok (NULL,"_"); + mode[13]='\0'; + + + CL=A->CL; + fp=save_sub_list_header (vfopen(fname, "w"),2, name_list,CL); + fp=save_extended_constraint_list_pair (CL, "pair",name_list[0],name_list[1],fp); + fp=save_list_footer (fp, CL); + vfree (buf); + } + else if ( strm2 (mode, "extended_lib","extended_cosmetic")) + { + CL=A->CL; + fp=save_extended_constraint_list ( CL,mode+9, vfopen(fname, "w")); + } + else + { + CL=(Constraint_list *)A->CL; + fp=save_constraint_list ( CL, 0, CL->ne,fname, NULL, "lib",A->S); + } + vfclose ( fp); + + if ( (Constraint_list *)A->CL !=CL)free_constraint_list (CL); + + return; + + } +void output_model_aln (char *fname, Alignment*A ) + { + FILE *fp; + int a; + Dp_Model *M; + Dp_Result *R; + char *string; + + if ( A->Dp_result==NULL) + { + fprintf ( stderr, "\nWARNING Could Not Output Model %s [%s]", fname, PROGRAM); + } + R=A->Dp_result; + M=R->Dp_model; + + fp=vfopen ( fname, "w"); + for (a=0; anstate; a++) + { + if (M->model_comments[a][0])fprintf ( fp, "#STATE %c: %s\n", 'a'+a, M->model_comments[a]); + } + string=vcalloc ( R->len+1, sizeof (char)); + for (a=0; alen; a++)string[a]=R->traceback[a]+'a'; + fprintf ( fp, ">%s\n",fname); + fp=output_string_wrap ( 50,string, fp); + vfree(string); + fprintf ( fp, "\n"); + + vfclose (fp); + return; + } +char * output_fasta_sub_aln (char *fname, Alignment*A, int ns, int *ls ) +{ + int a,s; + FILE *fp; + if (fname==NULL)fname=vtmpnam (NULL); + fp=vfopen (fname, "w"); + for (a=0; a%s %s\n%s\n", A->name[s],A->seq_comment[s],A->seq_al[s]); + } + vfclose (fp); + return fname; +} +char * output_fasta_sub_aln2 (char *fname, Alignment*A, int *ns, int **ls ) +{ + int a,g,s; + FILE *fp; + if (fname==NULL)fname=vtmpnam (NULL); + fp=vfopen (fname, "w"); + for ( g=0; g<2; g++) + for (a=0; a%s %s\n%s\n", A->name[s],A->seq_comment[s],A->seq_al[s]); + } + vfclose (fp); + return fname; +} + +int output_suchard_aln (char *out_file, Alignment *A) +{ + int a, b, c, d; + FILE *fp; + + A=back_translate_dna_aln (A); + + for ( c=0,a=0; alen_aln; a++, c++) + { + if (c==3)c=0; + for (b=0; bnseq; b++) + { + if (c==2) + { + A->seq_al[b][a]='-'; + } + } + } + A=ungap_aln_n (A, 1); + fp=vfopen (out_file, "w"); + for ( a=0; a< A->nseq; a++) + { + for (b=0; b< A->len_aln; b++) + { + c=tolower(A->seq_al[a][b]); + if ( c=='a')d=1; + else if ( c=='g')d=2; + else if ( c=='c')d=3; + else if ( c=='t')d=4; + else if ( c=='u')d=5; + else d=6; + + fprintf ( fp, "%d", d); + } + fprintf ( fp, "\n"); + } + vfclose (fp); + myexit (EXIT_SUCCESS); +} + +void output_fasta_aln (char *fname, Alignment*A ) + { + FILE *fp; + int a; + int line=0; + + line=get_msa_line_length (line, A->len_aln+1); + fp=vfopen ( fname, "w"); + + for ( a=0; a< A->nseq; a++) + { + fprintf ( fp, ">%s", A->name[a]); + + if ( A->seq_comment[a][0] && !isblanc (A->seq_comment[a]))fprintf ( fp, " %s", A->seq_comment[a]); + fprintf ( fp, "\n"); + fp=output_string_wrap ( line,A->seq_al[a] , fp); + fprintf ( fp, "\n"); + } + vfclose (fp); + } + +void output_pir_aln (char *fname, Alignment*A ) + { + int a; + FILE *fp; + char type[20]; + + + + + + fp=vfopen ( fname, "w"); + for ( a=0; a< A->nseq; a++) + { + if ( strm ( get_string_type (A->seq_al[a]),"DNA") || strm ( get_string_type (A->seq_al[a]),"RNA"))sprintf(type, "DL"); + else if ( strm ( get_string_type (A->seq_al[a]),"PROTEIN"))sprintf(type, "P1"); + fprintf ( fp, ">%s;%s\n%s\n",type, A->name[a], A->seq_comment[a]); + fp=output_string_wrap ( 50,A->seq_al[a] , fp); + fprintf ( fp, "\n*\n"); + } + + vfclose (fp); + } + +int landscape_msa; +int set_landscape_msa (int len) +{ + if ( len==0)landscape_msa=-1; + else + { + landscape_msa=len; + } + return landscape_msa; +} +int get_msa_line_length (int line, int aln_len) +{ + if (landscape_msa==-1) return aln_len; + else if ( landscape_msa)return landscape_msa; + else if (line) return line; + else + { + return (getenv ("ALN_LINE_LENGTH"))?atoi(getenv("ALN_LINE_LENGTH")):ALN_LINE_LENGTH; + } +} + +void output_msf_aln (char *fname,Alignment *B) + { + int a, b, c; + char *seq; + int *all_checks; + int i,j; + long grand_checksum; + FILE *fp; + int max_len; + int line=0; + int block=10; + int c_block; + char aa; + + + line=get_msa_line_length (line, B->len_aln+1); + + + for ( max_len=0,a=0; a< B->nseq; a++)max_len= MAX(strlen ( B->name[a]),max_len); + + + max_len+=5; + + fp=vfopen (fname, "w"); + + seq =vcalloc(B->len_aln, sizeof(char)); + all_checks =vcalloc(B->nseq, sizeof(int)); + for ( i=0; i< B->nseq; i++) + { + for ( j=0; jlen_aln; j++) + { + if ( is_gap(B->seq_al[i][j]))seq[j]='.'; + else seq[j]=B->seq_al[i][j]=toupper(B->seq_al[i][j]); + + } + all_checks[i] = SeqGCGCheckSum(seq, (int)B->len_aln); + } + grand_checksum = 0; + for(i=0; inseq; i++) grand_checksum += all_checks[i]; + grand_checksum = grand_checksum % 10000; + fprintf(fp,"PileUp\n\n"); + B=get_aln_type(B); + fprintf(fp,"\n\n MSF:%5d Type: ",B->len_aln); + if(strm ( (B->S)->type, "DNA") || strm ( (B->S)->type, "RNA")) + fprintf(fp,"N"); + else + fprintf(fp,"P"); + fprintf(fp," Check:%6ld .. \n\n", (long)grand_checksum); + for (i=0; i< B->nseq; i++) + { + fprintf ( fp, " Name: %s oo Len:%5d Check:%6ld Weight: %.3f\n", B->name[i], B->len_aln,(long)all_checks[i],(B->S)->W?((B->S)->W)->SEQ_W[i]:1.00); + } + fprintf(fp,"\n//\n\n"); + + for (a=0; alen_aln; a+=line) + { + fprintf ( fp,"\n\n"); + for (b=0; bnseq; b++) + { + fprintf (fp,"%-*s ",max_len,B->name[b]); + for (c_block=0,c=a;clen_aln;c++) + { + if ( c_block==block) + { + fprintf (fp, " "); + c_block=0; + } + c_block++; + aa=(is_gap(B->seq_al[b][c]))?'.': toupper(B->seq_al[b][c]); + fprintf (fp,"%c",aa ); + } + if ( c_block==block) + { + fprintf (fp, " "); + c_block=0; + } + fprintf (fp,"\n"); + + } + } + fprintf ( fp,"\n"); + vfclose ( fp); + + + vfree(seq); + vfree(all_checks); + + + return; +} +int SeqGCGCheckSum(char *seq, int len) +{ + int i; + long check; + + for( i=0, check=0; i< len; i++,seq++) + check += ((i % 57)+1) * toupper(*seq); + + return(check % 10000); +} +void old_output_msf_aln (char *fname,Alignment *B) + { + FILE *fp; + static int *put_seq; + int a, b, c; + int line=0; + char aa; + char *buf; + int max_len; + int seq_max_len; + + line=get_msa_line_length (line, B->len_aln+1); + + + for ( max_len=0,a=0; a< B->nseq; a++)max_len= MAX(strlen ( B->name[a]),max_len); + for ( seq_max_len=0,a=0; a< B->nseq; a++)seq_max_len= MAX(strlen ( B->seq_al[a]),max_len); + + + buf=vcalloc(seq_max_len+1, sizeof (int)); + + if ( put_seq==NULL) + put_seq= vcalloc ( B->nseq, sizeof (int)); + put_seq[0]=1; + + + for ( b=1; b< B->nseq; b++) + { + sprintf ( buf, "%s", B->seq_al[b]); + ungap(buf); + put_seq[b]=( strlen (buf)>0)?1:0; + } + + fp=vfopen ( fname, "w"); + fprintf ( fp, "MSF: %d Type P Check: 5083 ..\n", B->len_aln); + for ( a=0; a< B->nseq; a++) + { + if ( put_seq[a]==1) + fprintf ( fp,"Name: %s\n",B->name[a]); + } + fprintf ( fp, "//\n"); + for (a=0; alen_aln; a+=line) + {for (b=0; bnseq; b++) + { + if ( put_seq[b]==1) + { + fprintf (fp,"%-*s ",max_len,B->name[b]); + for (c=a;clen_aln;c++) + { + + + + aa=(B->seq_al[b][c]=='-')?'.': toupper(B->seq_al[b][c]); + fprintf (fp,"%c",aa ); + } + fprintf (fp,"\n"); + } + } + fprintf (fp,"\n"); + } + fprintf ( fp,"\n\n"); + vfclose ( fp); + + vfree (buf); + vfree(put_seq); + } + +void output_saga_aln ( char *name, Alignment *B) + { + int a, b, c; + FILE *fp; + + + + int max_len; + int line=0; + + line=get_msa_line_length (line, B->len_aln+1); + + + + for ( max_len=0,a=0; a< B->nseq; a++)max_len= (strlen ( B->name[a])>max_len)?(strlen ( B->name[a])):max_len; + + + + + fp= vfopen ( name, "w"); + + fprintf (fp, "\nSAGA FORMAT\nalignement %s nseq=%d len=%d\n", name, B->nseq, B->len_aln); + + fprintf (fp, "\n\n"); + for (a=0; alen_aln; a+=line) + {for (b=0; bnseq; b++) + {fprintf (fp,"%-*s ",max_len,B->name[b]); + for (c=a;clen_aln;c++) + { + fprintf (fp,"%c",(B->seq_al[b][c]) ); + } + fprintf (fp,"\n"); + } + fprintf (fp,"\n"); + } + fprintf (fp,"\n\n"); + vfclose ( fp); + } +void output_compact_aln ( char *name, Alignment *B) + { + int a, b, c; + FILE *fp; + int do_print=0; + + + int max_len; + int line=0; + + line=get_msa_line_length (line, B->len_aln+1); + + + for ( max_len=0,a=0; a< B->nseq; a++)max_len= (strlen ( B->name[a])>max_len)?(strlen ( B->name[a])):max_len; + + + + + fp= vfopen ( name, "w"); + + fprintf (fp, "\nSAGA FORMAT\nalignement %s nseq=%d len=%d", name, B->nseq, B->len_aln); + fprintf (fp, "\n\n"); + for (a=0; alen_aln; a+=line) + {for (b=0; bnseq; b++) + { + + for ( do_print=0, c=a;clen_aln;c++) + do_print+=1-is_gap(B->seq_al[b][c]); + if ( do_print>0) + { + fprintf (fp,"%-*s ",max_len,B->name[b]); + + + + for (c=a;clen_aln;c++) + { + if ( is_gap(B->seq_al[b][c])&& B->seq_al[b][c]!='-' )fprintf (fp,"%c", '-'); + else fprintf (fp,"%c",(B->seq_al[b][c]) ); + } + fprintf (fp,"\n"); + } + } + fprintf (fp,"\n"); + } + fprintf (fp,"\n\n"); + vfclose ( fp); + } + +void output_clustal_aln ( char *name, Alignment *B) +{ + return output_generic_clustal_aln (name, B, "tc_clustal"); +} +void output_strict_clustal_aln ( char *name, Alignment *B) +{ + return output_generic_clustal_aln (name, B, "strict_clustal"); +} + +void output_generic_clustal_aln ( char *name, Alignment *B, char *mode) + { + int a, b, c; + FILE *fp; + int max_len=0; + int line=0; + int *n_residues; + + if ( getenv ("SEP_4_TCOFFEE")) + { + while ( linelen_aln && B->seq_al[0][line]!='o' && B->seq_al[0][line]!='O')line++; + if ( B->seq_al[0][line]=='O' || B->seq_al[0][line]=='o')line++; + } + else + { + while ( linelen_aln)line++; + } + + if ( line==B->len_aln)line=get_msa_line_length (0, B->len_aln+1); + + n_residues=vcalloc ( B->nseq+1, sizeof (int)); + for ( a=0; a< B->nseq; a++) + {if ( strlen (B->name[a])>max_len) + max_len= strlen ( (B->name[a])); + n_residues[a]=B->order[a][1]; + } + max_len=MAX(max_len+2, 16); + + + fp= vfopen ( name, "w"); + + if ( strm (mode, "strict_clustal")) + fprintf ( fp, "CLUSTAL W (1.83) multiple sequence alignment"); + else + { + fprintf (fp, "CLUSTAL FORMAT for %s %s [%s] [MODE: %s ], CPU=%.2f sec, SCORE=%d, Nseq=%d, Len=%d ", PROGRAM, VERSION,URL, retrieve_mode (),(float)(B->cpu+get_time())/1000, B->score_aln, B->nseq, B->len_aln); + if (B->ibit>0) + { + float ibit=(float)log ((double)B->ibit)/log ((double)2); + float nibit=(float)log(ibit/(B->len_aln*B->nseq)); + fprintf ( fp, "\nTies: %.1f bits (%d alternative)\n",ibit, B->ibit-1); + + } + } + fprintf (fp, "\n\n"); + + + if ( B->len_aln==0) + { + for (b=0; b<=B->nseq; b++) + fprintf (fp,"%-*s -\n",max_len, B->name[b]); + } + + else + { + for (a=0; alen_aln; a+=line) + {for (b=0; b<=B->nseq; b++) + { + if (b!=B->nseq) + { + fprintf (fp,"%-*s",max_len, B->name[b]); + for (c=a;clen_aln;c++) + { + if ( is_gap(B->seq_al[b][c]))fprintf (fp,"%c", '-'); + else + { + n_residues[b]++; + fprintf (fp, "%c", GET_CASE(B->residue_case, B->seq_al[b][c])); + + } + + } + if (B->output_res_num)fprintf (fp, " %d", n_residues[b]); + fprintf (fp,"\n"); + } + else if ( b==B->nseq) + { + fprintf (fp,"%-*s",max_len," "); + for (c=a;clen_aln;c++) + { + fprintf ( fp, "%c", analyse_aln_column (B, c)); + } + fprintf (fp,"\n"); + } + } + fprintf (fp,"\n"); + } + } + fprintf (fp,"\n\n"); + vfree (n_residues); + vfclose ( fp); + } +FILE * output_generic_interleaved_aln (FILE *fp, Alignment *B, int line, char gap, char *mode) + { + int a, b, c; + int max_len=0; + int *n_residues; + + + n_residues=vcalloc ( B->nseq+1, sizeof (int)); + for ( a=0; a< B->nseq; a++) + {if ( strlen (B->name[a])>max_len) + max_len= strlen ( (B->name[a])); + n_residues[a]=B->order[a][1]; + } + max_len=MAX(max_len+2, 16); + + + + + if ( B->len_aln==0) + { + for (b=0; b<=B->nseq; b++) + fprintf (fp,"%-*s -\n",max_len, B->name[b]); + } + + else + { + for (a=0; alen_aln; a+=line) + {for (b=0; b<=B->nseq; b++) + { + if (b!=B->nseq) + { + fprintf (fp,"%-*s",max_len, B->name[b]); + for (c=a;clen_aln;c++) + { + if ( is_gap(B->seq_al[b][c]))fprintf (fp,"%c", gap); + else + { + n_residues[b]++; + fprintf (fp, "%c", GET_CASE(B->residue_case, B->seq_al[b][c])); + + } + + } + if (B->output_res_num)fprintf (fp, " %d", n_residues[b]); + fprintf (fp,"\n"); + } + } + fprintf (fp,"\n"); + } + } + vfree (n_residues); + return fp; + } +void output_phylip_aln ( char *name, Alignment *B) + { + int a, b, c, d; + FILE *fp; + + int *print_name; + static int line=0; + line=get_msa_line_length(0, 0); + + print_name=vcalloc ( B->nseq, sizeof (int)); + fp= vfopen ( name, "w"); + + fprintf (fp, "%3d %d\n", B->nseq, B->len_aln); + for (a=0; alen_aln; a+=line) + {for (b=0; bnseq; b++) + {if ( print_name[b]==0) + { + + fprintf (fp,"%-10.10s ",B->name[b]); + print_name[b]=1; + } + else + { + fprintf (fp, "%10.10s ", " "); + } + + + for (d=0,c=a;clen_aln;c++, d++) + { + if ( d==10) + { + fprintf ( fp, " "); + d=0; + } + if ( is_gap(B->seq_al[b][c])&& B->seq_al[b][c]!='-' )fprintf (fp,"%c", '-'); + else fprintf (fp,"%c",(B->seq_al[b][c]) ); + } + fprintf (fp,"\n"); + } + fprintf (fp,"\n"); + } + fprintf (fp,"\n\n"); + vfclose ( fp); + } + +void output_rnalign (char *out_file, Alignment *A, Sequence *STRUC) + { + int a, b; + FILE *fp; + char bank_file[100]; + char pep_file[100]; + char *buf; + + sprintf ( bank_file, "%s.mss", out_file); + sprintf ( pep_file, "%s.one_rna", out_file); + + + buf=vcalloc ( strlen ( A->seq_al[0]+1), sizeof (char)); + + for ( b=0,a=0; a< strlen(A->seq_al[0]); a++) + { + if ( is_gap(A->seq_al[0][a])) + buf[a]='.'; + else + buf[a]=STRUC->seq[0][b++]; + } + buf[a]='\0'; + + fp=vfopen ( bank_file, "w"); + + fprintf ( fp, "ST\n"); + fp=output_string_wrap ( 50, buf, fp); + fprintf ( fp, "\n\n"); + + for ( a=0; anseq-1; a++) + { + fprintf ( fp, "AS %s\n ", A->name[a]); + fp=output_string_wrap ( 50, A->seq_al[a], fp); + fprintf ( fp, "\n\n"); + } + vfclose ( fp); + fp=vfopen ( pep_file, "w"); + fprintf ( fp, ">%s\n", A->name[A->nseq-1]); + fp=output_string_wrap ( 50, A->seq_al[A->nseq-1], fp); + fprintf ( fp, "\n"); + vfclose (fp); + } + +void output_lib (char *pw_lib_saga_aln_name, Alignment *A ) + { + Alignment *B; + char fname[VERY_LONG_STRING]; + int a,b; + + B=declare_Alignment (NULL); + + B->nseq=2; + + for ( a=0; a< A->nseq-1; a++) + { + for ( b=a+1; bnseq; b++) + { + sprintf ( B->seq_al[0], "%s", A->seq_al[a]); + sprintf ( B->name[0], "%s", A->name[a]); + sprintf(B->name[1], "%s", A->name[b]); + sprintf ( B->seq_al[1], "%s",A->seq_al[b]); + B->nseq=2; + sprintf ( fname, "%s_%s_%s.lib",pw_lib_saga_aln_name, A->name[a], A->name[b]); + + B->len_aln=strlen ( B->seq_al[0]); + ungap_aln (B); + output_clustal_aln (fname,B); + } + } + } +void output_pw_lib_saga_aln (char *pw_lib_saga_aln_name, Alignment *A ) + { + Alignment *B; + char fname[VERY_LONG_STRING]; + int a,b; + + B=declare_Alignment (NULL); + + B->nseq=2; + + for ( a=0; a< A->nseq-1; a++) + { + for ( b=a+1; bnseq; b++) + { + sprintf ( B->seq_al[0], "%s", A->seq_al[a]); + sprintf ( B->name[0], "%s", A->name[a]); + sprintf(B->name[1], "%s", A->name[b]); + sprintf ( B->seq_al[1], "%s",A->seq_al[b]); + B->nseq=2; + sprintf ( fname, "%s_%s_%s.pw_lib_saga_aln",pw_lib_saga_aln_name, A->name[a], A->name[b]); + + B->len_aln=strlen ( B->seq_al[0]); + ungap_aln (B); + output_clustal_aln (fname,B); + } + } + } +void output_lalign_header( char *name, Alignment *A) + { + FILE *fp; + + fp=vfopen ( name, "w"); + fprintf ( fp, " Lalign mode: best local alignments between two sequences\n"); + fprintf ( fp, " %s(%s) [%s]\n\n", VERSION, DATE, URL); + fprintf ( fp, " Comparison of:\n(A) %s\t%s\t-%d aa\n", (A->S)->file[A->order[0][0]],(A->S)->name[A->order[0][0]], (A->S)->len[A->order[0][0]]); + fprintf ( fp, "(B) %s\t%s\t-%d aa\n", (A->S)->file[A->order[1][0]],(A->S)->name[A->order[1][0]], (A->S)->len[A->order[1][0]]); + + + vfclose ( fp); + return; + } +void output_stockholm_aln (char *file, Alignment *A, Alignment *ST) +{ + FILE *fp; + int a,b; + + for (a=0; anseq; a++) + for (b=0; blen_aln; b++) + if (A->seq_al[a][b]==STOCKHOLM_CHAR)A->seq_al[a][b]='.'; + + fp=vfopen (file, "w"); + fprintf ( fp, "# STOCKHOLM 1.0\n\n"); + output_generic_interleaved_aln (fp,A, 50, '.', NULL); + fprintf ( fp, "//\n"); + vfclose (fp); +} + +void output_glalign ( char *name, Alignment *B, Alignment *S) +{ + int a, b, g, s; + int naln=0; + FILE *fp; + int **nr; + B=B->A; + if ( B==NULL){return;} + + fp=vfopen (name, "w"); + fprintf (fp, "Format: GLALIGN_01 [Generated with %s ]\n", PROGRAM); + fprintf (fp, "#Each Line corresponds to a column\n"); + fprintf (fp, "#First column coresponds to first genome\n"); + fprintf (fp, "#Last Column gives the column reliability on a 0-9 scale\n"); + fprintf (fp, "#[-1] Indicates that the reliability was not evaluated\n"); + + fprintf (fp, "Genome List\n"); + for ( a=0; a< B->nseq; a++) + fprintf (fp, "\tGenome %s\n", B->name[a]); + fprintf (fp, "Alignment List\n"); + while (B) + { + fprintf (fp, "Alignment %d Len %d Score %d\n", ++naln, B->len_aln, S->score_aln); + nr=duplicate_int (B->order, -1, -1); + for ( a=0; a< B->len_aln; a++) + { + fprintf ( fp, "\t"); + for ( b=0; b< B->nseq; b++) + { + g=is_gap (B->seq_al[b][a]); + nr[b][1]+=1-g; + + if (g)fprintf (fp, "---- "); + else fprintf ( fp, "%4d ",nr[b][1]); + } + s=((S)?S->seq_al[S->nseq][a]:-1); + if (s==NO_COLOR_RESIDUE)s=-1; + fprintf ( fp,"[ %d ]",s); + fprintf ( fp, "\n"); + + } + free_int (nr, -1); + B=B->A; + S=S->A; + } + vfclose ( fp); +} +Alignment *input_conc_aln ( char *name, Alignment *IN) +{ + FILE *fp; + char *string, *p, *file; + Alignment *F=NULL,*A=NULL, *B=NULL; + + file=vtmpnam (NULL); + + string=file2string(name); + string=substitute ( string, "@", "!Protected!"); + string=substitute ( string, TC_REC_SEPARATOR, "@"); + strtok (string,"@"); + + + while ( (p=strtok (NULL,"@"))!=NULL) + { + char *buf; + buf=vcalloc ( strlen (p)+1, sizeof (char)); + sprintf (buf,"%s", p); + buf=substitute (buf,"!protected!", "@"); + + fp=vfopen (file, "w"); + fprintf ( fp, "%s",buf); + vfclose (fp); + vfree (buf); + + if ( is_aln (file)) + { + B=main_read_aln (file,NULL); + + if ( !A) + { + if (IN){copy_aln (B, IN);F=A=IN;} + else F=A=B; + } + else + { + A->A=B; + A=A->A; + } + } + } + + vfree (string); + return F; +} + +void output_conc_aln ( char *name, Alignment *B) +{ + FILE *fp; + int a; + + fp=vfopen (name, "w"); + fprintf (fp, "# CONC_MSF_FORMAT_01\n"); + while (B) + { + fprintf (fp, "%s\n", TC_REC_SEPARATOR); + for ( a=0; a< B->nseq; a++) + { + fprintf ( fp, ">%s\n%s\n", B->name[a], B->seq_al[a]); + } + B=B->A; + + } + vfclose (fp); +} + +void output_lalign ( char *name, Alignment *B) +{ + static int output_header; + + B=B->A; + if ( B==NULL){output_header=0;return;} + else if ( output_header==0) + { + output_lalign_header(name, B); + output_header=1; + } + while (B) + { + output_lalign_aln ( name, B); + B=B->A; + } +} +void output_lalign_aln ( char *name, Alignment *B) + { + int a, b, c,d=0, s=0; + char col; + + float tot=0; + float id=0; + + FILE *fp; + int max_len=0; + int line; + int *n_residues; + int res; + + + n_residues=vcalloc ( B->nseq+1, sizeof (int)); + for ( a=0; a< B->nseq; a++) + {if ( strlen (B->name[a])>max_len) + max_len= strlen ( (B->name[a])); + n_residues[a]=B->order[a][1]; + } + max_len=MAX(max_len+2, 16); + line=60; + + + + fp= vfopen ( name, "a"); + + for (a=0; a< B->len_aln; a++) + { + if ( !is_gap(B->seq_al[0][a]) && !is_gap(B->seq_al[1][a])) + { + tot++; + id+=(B->seq_al[0][a]==B->seq_al[1][a]); + } + } + + id=(id*100)/tot; + fprintf (fp, " %.1f%% identity in %d aa overlap; score: %d\n\n", id,(int)tot, B->score_aln); + + + for (a=0; alen_aln; a+=line) + {for (b=0; b<5; b++) + { + if ( b==0 || b==4) + { + if ( b==0)s=0; + if ( b==4)s=1; + fprintf (fp,"%-*s",max_len," "); + for (d=0,c=a;clen_aln;c++) + { + res=!is_gap ( B->seq_al[s][c]); + n_residues[s]+=res; + if ( (n_residues[s]%10)==0 && res && (c-a+4)name[s]); + for (c=a;clen_aln;c++) + { + if ( is_gap(B->seq_al[s][c]))fprintf (fp,"%c", '-'); + else + { + fprintf (fp, "%c", GET_CASE(B->residue_case, B->seq_al[s][c])); + } + } + fprintf (fp,"\n"); + } + else if ( b==2) + { + fprintf (fp,"%-*s",max_len," "); + for (c=a;clen_aln;c++) + { + col=analyse_aln_column (B, c); + if ( col=='*')col=':'; + else if ( col==':')col='.'; + else if ( col=='.')col=' '; + fprintf ( fp, "%c", col); + } + fprintf (fp,"\n"); + } + } + fprintf (fp,"\n"); + } + + fprintf (fp,"\n\n----------\n\n"); + vfree (n_residues); + vfclose ( fp); + } + + +/****************************************************************************************************/ +/*************************************UTIL *********************************************************/ +/**************************************************************************************************/ + + +/****************************************************************************************************/ +/*************************** *************************************/ +/*************************** PROCESSING *************************************/ +/*************************** *************************************/ +/*******************************************************************************************/ +/* */ +/* */ +/* THREADING */ +/***************************************************************************************** */ + +char *thread_aa_seq_on_dna_seq( char *s) + { + int l, b, c; + char *array; + + + l=strlen ( s); + array=vcalloc ( l*3 +1, sizeof (char)); + for ( b=0, c=0; b< l; b++, c+=3) + { + array[c]=s[b]; + array[c+1]='o'; + array[c+2]='o'; + } + array[c]='\0'; + return array; + } + +Alignment *thread_dnaseq_on_prot_aln (Sequence *S, Alignment *A) + { + Alignment *B=NULL; + int a, b, c, n, la, ls, ln, m; + + B=copy_aln ( A, B); + B=realloc_aln2 ( B, B->nseq, B->len_aln*3 +1); + + for ( n=0,a=0; a< A->nseq; a++) + { + for ( m=0,b=0; b< S->nseq; b++) + { + if (strm (A->name[a], S->name[b]) ) + { + m=1; + n++; + ungap ( S->seq[b]); + B->seq_al[a][0]='\0'; + for (la=0, ls=0, ln=0; la< A->len_aln; la++) + { + for (c=0; c< 3; c++) + B->seq_al[a][ls++]=(is_gap(A->seq_al[a][la]))?'-':S->seq[b][ln++]; + } + B->seq_al[a][ls]='\0'; + } + } + if ( m==0) + { + for (la=0, ls=0, ln=0; la< A->len_aln; la++) + { + + B->seq_al[a][ls++]=A->seq_al[a][la]; + B->seq_al[a][ls++]='-'; + B->seq_al[a][ls++]='-'; + } + } + } + + B->len_aln=strlen ( B->seq_al[0]); + return B; + } +void thread_seq_struc2aln ( Alignment *A, Sequence *ST) + { + int a, b, c,d; + int len, cons; + + for ( a=0; a< A->nseq; a++) + for ( b=0; b< ST->nseq; b++) + { + if ( strcmp ( A->name[a], ST->name[b])==0) + { + ungap (ST->seq[b]); + len=strlen(A->seq_al[a]); + for ( c=0, d=0; cseq_al[a][c]))A->seq_al[a][c]=ST->seq[b][d++]; + } + } + } + cons=name_is_in_list ("Cons", ST->name, ST->nseq, 100); + if ( cons!=-1 && A->len_aln==strlen ( ST->seq[cons])) + { + sprintf (A->name[A->nseq], "Cons"); + sprintf (A->seq_al[A->nseq],"%s", ST->seq[cons]); + A->nseq++; + } + } +void cache_id ( Alignment *A) + { + int a, b,n; + char r1, r2, r3; + + for ( a=0; a< A->len_aln; a++) + { + for ( b=0, n=0; b< A->nseq; b++)if ( !is_gap(A->seq_al[b][a]))n++; + for ( b=0; b< A->nseq; b++) + if ( !is_gap(A->seq_al[b][a]) && n==A->nseq)A->seq_al[b][a]='h'; + else if( !is_gap(A->seq_al[b][a]))A->seq_al[b][a]='x'; + } + for ( a=0; a< A->nseq; a++) + { + for ( b=1; b< A->len_aln-1; b++) + { + r1=A->seq_al[a][b-1]; + r2=A->seq_al[a][b]; + r3=A->seq_al[a][b+1]; + if (r2=='h') + { + if ( (r1=='h' || r1=='b') && (r3=='h' || r3=='b'))A->seq_al[a][b]='h'; + else A->seq_al[a][b]='b'; + } + } + for ( b=1; b< A->len_aln-1; b++)if ( A->seq_al[a][b]=='b')A->seq_al[a][b]='x'; + } + + } + + +/*******************************************************************************************/ +/* */ +/* */ +/* PROCESING OF EST */ +/* */ +/***************************************************************************************** */ +int process_est_sequence ( Sequence *S, int *cluster_list) + { + char **inverted_seq; + int T=20; + int a, b; + int V1, V2; + int **sens; + int **a_sens; + int **best; + int *solution; + char buf [VERY_LONG_STRING]; + int n_clusters=0; + int n; + + sens=declare_int ( S->nseq,S->nseq); + a_sens=declare_int ( S->nseq,S->nseq); + best=declare_int ( S->nseq,S->nseq); + + + inverted_seq=vcalloc ( S->nseq, sizeof (char*)); + for ( a=0; anseq; a++) + inverted_seq[a]=invert_seq ( S->seq[a]); + + for ( a=0; a< S->nseq-1; a++) + { + + for ( b=a+1; bnseq; b++) + { + + V1=sens[a][b]=sens[b][a]=get_best_match ( S->seq[a], S->seq[b]); + V2=a_sens[a][b]=a_sens[b][a]=get_best_match ( S->seq[a],inverted_seq[b]); + best[a][b]=best[b][a]=(V1>V2)?V1:V2; + } + } + solution=SHC ( S->nseq, a_sens, sens); + + + for ( a=0; anseq; a++)cluster_list[a]=-1; + for ( a=0; anseq; a++) + { + n=search_for_cluster (a, n_clusters, cluster_list, T, S->nseq, best); + if ( n>0)n_clusters++; + } + fprintf ( stderr, "\nTHERE %s %d Independant Cluster(s) in your sequences",(n_clusters>1)?"are":"is",(n_clusters)); + for (a=0; anseq; b++) + { + if ( cluster_list[b]==a)fprintf ( stderr, "%s ", S->name[b]); + } + } + + for ( a=0; anseq; a++) + { + if ( solution[a]==-1) + { + S->seq[a]=inverted_seq[a]; + sprintf ( buf, "i_%s", S->name[a]); + sprintf ( S->name[a], "%s", buf); + } + } + return n_clusters; + } + +int search_for_cluster ( int seq, int cluster_number, int *cluster_list, int T, int nseq, int **S) + { + int n=0,a; + + if (cluster_list[seq]==-1) + { + cluster_list[seq]=cluster_number; + n++; + } + for ( a=0; aT) + { + n++; + cluster_list[a]=cluster_number; + n+=search_for_cluster ( a, cluster_number, cluster_list, T, nseq, S); + } + } + return n; + } + +int * SHC ( int nseq, int **NST, int **ST) + { + int a; + int mut; + int score, new_score; + int N_IT=VERY_LONG_STRING; + int *sol; + int count; + + sol=vcalloc ( nseq, sizeof (int)); + for ( a=0; a49)?1:-1; + + score=evaluate_sol (sol, nseq, ST, NST); + fprintf ( stderr, "\nI_Score=%d\n", score); + N_IT=N_IT*nseq; + + for ( count=0,a=0; a< N_IT && scorescore) + { + score=new_score; + } + else if ( (addrand ((unsigned long)VERY_LONG_STRING))>score) + { + score=new_score; + } + else + sol[mut]=sol[mut]*-1; + if ( count==VERY_LONG_STRING) + { + count=0; + fprintf ( stderr, "\nScore=%d", score); + } + } + fprintf ( stderr, "\nScore=%d\n", score); + return sol; + } + +int mutate_sol (int *sol, int nseq) + { + int n; + n=addrand ((unsigned long)nseq); + sol[n]=sol[n]*-1; + return n; + } +int evaluate_sol ( int *sol, int nseq, int **ST, int **NST) + { + static int max_score; + int a, b, score=0; + + if ( max_score==0) + { + for ( a=0; aNST[a][b])?ST[a][b]:NST[a][b]; + } + } + + for ( a=0; al2)?l1:l2; + m=declare_int (ml, ml); + } + else if ( (mll2)?l1:l2; + m=declare_int (ml, ml); + } + + for ( a=0; abest)?mdiag[a][0]:best; + + return best; + } + +int** extract_m_diag_streches ( int ** m, int l1, int l2,char *seq1, char *seq2, int *n_mdiag) + { + + int b, x, y, s1, s2; + static int **mdiag; + int in; + static int max_diag=VERY_LONG_STRING; + + /* + diag[0]=len; + diag[1]=x_start; + diag[2]=y_start; + diag[3]=x_end; + diag[4]=y_end; + */ + + if ( mdiag==NULL) + mdiag=declare_int ( max_diag, 5); + + for ( s1=l1-1, s2=0;s20) + { + if (in==1) + mdiag[n_mdiag[0]][0]++; + else + { + mdiag[n_mdiag[0]][0]=1; + mdiag[n_mdiag[0]][1]=x; + mdiag[n_mdiag[0]][2]=y; + in=1; + } + } + else + if (in==1) + { + in=0; + mdiag[n_mdiag[0]][3]=x-1; + mdiag[n_mdiag[0]][4]=y-1; + if ( !is_strech ( "ta", seq1, seq2,mdiag[n_mdiag[0]][0], mdiag[n_mdiag[0]][1],mdiag[n_mdiag[0]][2]))n_mdiag[0]++; + } + if (n_mdiag[0]==(max_diag-1)) + {mdiag=vrealloc (mdiag, (max_diag+VERY_LONG_STRING)*sizeof (int*)); + for ( b=max_diag; bT)return 1; + } + return 0; + } + + +/************************************************************************************/ +/* */ +/* STRUC */ +/* */ +/* */ +/************************************************************************************/ + +char * oneletaa2threeletaa(char aa); +float aa2property (char aa, char *mode); + +int output_seq2struc(char *outfile, Alignment *A) +{ + FILE *fp1, *fp2; + int a,c, l; + float v, h, x, y, z, dx, dy, dz; + char *s; + char *tmpfile1, *tmpfile2; + char command[1000]; + + tmpfile1=vtmpnam(NULL); + tmpfile2=vtmpnam(NULL); + + ungap (A->seq_al[0]); + s=A->seq_al[0];l=strlen (s); + fp1=vfopen (tmpfile1, "w"); + + x=y=z=0; + for ( a=0; a< l; a++) + { + h=aa2property ( s[a], "doolittle" ); + v=aa2property (s[a], "volume"); + /*14.398907: peptide bond length*/ + dx=(float)sqrt ((double)(14.398907/(((h*h)/(v*v))+1))); + dy=dx*(h/v); + dz=0; + + + x+=dx; + y+=dy; + z+=dz; + fprintf (fp1, "ATOM%7d CA %s A%4d%12.3f%8.3f%8.3f 1.00 5.30\n",a+1, oneletaa2threeletaa(s[a]),a+1, x, y, z); + } + vfclose (fp1); + sprintf ( command, "extract_from_pdb -infile %s -force > %s", tmpfile1, tmpfile2); + my_system (command); + fp1=vfopen (tmpfile2, "r"); + fp2=vfopen (outfile, "w"); + + while ( (c=fgetc(fp1))!=EOF)fprintf (fp2, "%c", c); + vfclose (fp1); + vfclose (fp2); + + return 0; +} + +char * oneletaa2threeletaa(char aa) + { + aa=tolower (aa); + if ( aa=='a')return "ALA"; + else if ( aa=='r') return "ARG"; + else if ( aa=='n') return "ASN"; + else if ( aa=='d') return "ASP"; + else if ( aa=='c') return "CYS"; + else if ( aa=='q') return "GLN"; + else if ( aa=='e') return "GLU"; + else if ( aa=='g') return "GLY"; + else if ( aa=='h') return "HIS"; + else if ( aa=='i') return "ILE"; + else if ( aa=='l') return "LEU"; + else if ( aa=='k') return "LYS"; + else if ( aa=='m') return "MET"; + else if ( aa=='f') return "PHE"; + else if ( aa=='p') return "PRO"; + else if ( aa=='s') return "SER"; + else if ( aa=='t') return "THR"; + else if ( aa=='w') return "TRP"; + else if ( aa=='y') return "TYR"; + else if ( aa=='v') return "VAL"; + else + { + fprintf ( stderr, "\nERROR: %c is not an amino acid [FATAL::aa2hydropathy::%s]", aa, PROGRAM); + myexit (EXIT_FAILURE); + return NULL; + } + return NULL; + } + +float aa2property (char aa, char *mode) + { + if ( mode==NULL || strm (mode, "doolittle")) + { + aa=tolower (aa); + if ( aa=='i')return 4.5; + else if ( aa=='v') return 4.2; + else if ( aa=='l') return 3.8; + else if ( aa=='f') return 2.8; + else if ( aa=='c') return 2.5; + else if ( aa=='m') return 1.9; + else if ( aa=='a') return 1.8; + else if ( aa=='g') return -0.4; + else if ( aa=='t') return -0.7; + else if ( aa=='w') return -0.9; + else if ( aa=='s') return -0.8; + else if ( aa=='y') return -1.3; + else if ( aa=='p') return -1.6; + else if ( aa=='h') return -3.2; + else if ( aa=='e') return -3.5; + else if ( aa=='q') return -3.5; + else if ( aa=='d') return -3.5; + else if ( aa=='n') return -3.5; + else if ( aa=='k') return -3.9; + else if ( aa=='r') return -4.5; + else + { + fprintf ( stderr, "\nERROR: %c is not an amino acid [FATAL::aa2hydropathy::%s]", aa, PROGRAM); + myexit (EXIT_FAILURE); + } + } + else if (strm (mode, "volume")) + { + aa=tolower (aa); + if ( aa=='a')return 0.915; + else if ( aa=='r') return 2.02; + else if ( aa=='n') return 1.35; + else if ( aa=='d') return 1.24; + else if ( aa=='c') return 1.18; + else if ( aa=='q') return 1.61; + else if ( aa=='e') return 1.55; + else if ( aa=='g') return 0.66; + else if ( aa=='h') return 1.67; + else if ( aa=='i') return 1.69; + else if ( aa=='l') return 1.68; + else if ( aa=='k') return 1.71; + else if ( aa=='m') return 1.70; + else if ( aa=='f') return 2.03; + else if ( aa=='p') return 1.29; + else if ( aa=='s') return 0.99; + else if ( aa=='t') return 1.22; + else if ( aa=='w') return 2.37; + else if ( aa=='y') return 2.03; + else if ( aa=='v') return 1.41; + else + { + fprintf ( stderr, "\nERROR: %c is not an amino acid [FATAL::aa2hydropathy::%s]", aa, PROGRAM); + myexit (EXIT_FAILURE); + } + } + + else + { + fprintf ( stderr, "\nERROR: %s is an unknown mode [FATAL::aa2hydropathy::%s]", mode , PROGRAM); + myexit (EXIT_FAILURE); + } + return 0; + } + + + + + +/************************************************************************************/ +/* */ +/* DNA */ +/* */ +/* */ +/************************************************************************************/ + +Alignment *code_dna_aln (Alignment *A) + { + int a, b,l,r; + + for ( a=0; a< A->nseq; a++) + { + for (l=0, b=0; b< A->len_aln; b++) + { + r=A->seq_al[a][b]; + if ( r=='-')l++; + else if ( r=='~')continue; + else if ( r=='.')l++; + else if ( !islower(r))A->seq_al[a][b]='4'; + else + { + A->seq_al[a][b]=(l+3)%3+'0'; + l++; + } + } + } + return A; + } + + +Alignment *back_translate_dna_aln (Alignment *A) + { + /*Given a set of aligned sequences + starts from left to right + 1 aa->3 nuc + ambiguities are randomly resolved. + returns the corresponding amino acid alignment + */ + int a; + char *seq ; + + ungap_aln(A); + A=realloc_aln (A, 10000); + seq=vcalloc ( 10000, sizeof (char)); + + + for ( a=0; a< A->nseq; a++) + { + seq=back_translate_dna_seq (A->seq_al[a], seq, RANDOM); + sprintf ( A->seq_al[a], "%s", seq); + } + A->len_aln=A->len_aln*3; + compress_aln (A); + vfree (seq); + return A; + } +char * back_translate_dna_seq ( char *in_seq,char *out_seq, int mode) + { + int a,len; + + len=strlen(in_seq); + + if (out_seq==NULL)out_seq=vcalloc ( len*3+1, sizeof (char)); + + out_seq[0]='\0'; + for (a=0; atype, "DNA") && !strm (S->type, "RNA")) printf_exit (EXIT_FAILURE, stderr, "Sequences should be *RNA* type [FATAL:%s]\n", PROGRAM); + for ( a=0; anseq; a++) + { + for (b=0; bseq[a]); b++) + { + if ( S->seq[a][b]=='u') S->seq[a][b]='t'; + if ( S->seq[a][b]=='U') S->seq[a][b]='T'; + } + HERE ("%s", S->seq[a]); + } + return S; +} +Sequence *dna_seq2rna_seq (Sequence *S) +{ + int a, b; + + if ( !strm(S->type, "DNA") && !strm (S->type, "RNA")) printf_exit (EXIT_FAILURE, stderr, "Sequences should be *DNA* type (type=%s) [FATAL:%s]\n", PROGRAM, S->type); + for ( a=0; anseq; a++) + for (b=0; blen[a]; b++) + { + if ( S->seq[a][b]=='t') S->seq[a][b]='u'; + if ( S->seq[a][b]=='T') S->seq[a][b]='U'; + } + return S; +} + + + +int get_longest_frame (char *seq, int mode); +Sequence *translate_dna_seqS (Sequence *S, int frame, int stop) +{ + //frame: 1->3 + char *s; + int a, b,c,l; + + for (a=0; anseq; a++) + { + s=S->seq[a]; + ungap(s); + l=strlen (s); + for (b=(frame-1); b1 aa + 2nuc+1gap, 1nuc+2gap->3 gaps + 1 stop-> 3gaps + returns the corresponding amino acid alignment + */ + + + int a, b,r; + + + if (frame==3 || frame ==4) + { + + for (a=0; a< A->nseq; a++) + { + char *d, *buf, f; + d=A->seq_al[a]; + f=get_longest_frame (d,frame); + buf=vcalloc ( strlen (d)+1, sizeof (char)); + if ( f<3) + { + sprintf (buf, "%s", d+f); + sprintf (d, "%s", buf); + sprintf (A->seq_comment[a], " frame: %d", f); + } + else if ( f>=3) + { + f-=3; + sprintf ( buf, "%s", d); + buf=complement_string (buf); + sprintf (d, "%s",buf+f); + sprintf (A->seq_comment[a], " frame: %d Reverse Complement", f); + } + vfree (buf); + } + } + else + { + + for ( a=0; a< A->nseq; a++) + for (b=0; b< frame; b++) + A->seq_al[a][b]='-'; + ungap_aln(A); + } + + for ( b=0; b< A->nseq; b++) + for ( a=0; a< A->len_aln;) + { + + r=translate_dna_codon (A->seq_al[b]+a, 'z'); + if (is_gap(r)) + { + A->seq_al[b][a++]='-'; + A->seq_al[b][a++]='-'; + A->seq_al[b][a++]='-'; + } + else if ( r=='x') + { + A->seq_al[b][a++]='o'; + A->seq_al[b][a++]='-'; + A->seq_al[b][a++]='-'; + } + else if ( r=='z') + { + A->seq_al[b][a++]='x'; + A->seq_al[b][a++]='-'; + A->seq_al[b][a++]='-'; + } + else + { + A->seq_al[b][a++]=r; + A->seq_al[b][a++]='-'; + A->seq_al[b][a++]='-'; + } + } + compress_aln (A); + + return A; + } + + +int seq2tblastx_db (char *out,Sequence *S, int strand) +{ + //strand : same values as in ncbi blastall + //1: direct + //2:revers + //3: both + int a, b,d, l; + char *prot, *pprot; + int min_exon_len=5; + FILE *fp; + fp=vfopen (out, "w"); + for (a=0; anseq; a++) + { + for (b=-3; b<=3; b++) + { + int f; + int dl; + + dl=strlen (S->seq[a]); + if (b==0)continue; + else if ( strand==1 && b<0)continue;//only direct strand + else if ( strand==2 && b>0)continue;//only reverse strand + else if (b<0) + { + S->seq[a]=complement_string (S->seq[a]); + f=b*-1; + } + else + f=b; + prot=translate_dna_seq (S->seq[a], f, 'X', NULL); + upper_string (prot); + + l=strlen (prot); + pprot=prot; + for (pprot=prot,d=0; d<=l; d++) + { + if (prot[d]=='\0') + { + prot[d]='\0'; + if ( strlen (pprot)>min_exon_len) + { + int start, end; + end=(d)*3+(f-1); + start=(end-(strlen (pprot))*3)+1; + fprintf (fp, ">%s__%c__%d__%d__%d\n%s\n", S->name[a],(b>0)?'d':'r',start,end,dl, pprot); + pprot=prot+d+1; + } + } + } + vfree (prot); + if (b<0) S->seq[a]=complement_string (S->seq[a]); + } + } + vfclose (fp); + return EXIT_SUCCESS; +} + +int get_longest_frame (char *in_seq, int mode) +{ + char *prot, *seq; + int a; + int max_l=0, l; + int best_frame=0; + int nf; + + seq=vcalloc (strlen (in_seq)+1, sizeof (char)); + prot=vcalloc (strlen (in_seq)+1, sizeof (char)); + sprintf ( seq, "%s", in_seq); + + if ( mode == 3)nf=3; + else if ( mode == 4) nf=6; + + for (a=0; a=3)?a-3:a; + prot=translate_dna_seq ( seq,f,'\0', prot); + l=strlen (prot); + if (l>=max_l){max_l=l;best_frame=a;} + } + vfree (seq); + vfree (prot); + return best_frame; +} + +Alignment *clean_gdna_aln (Alignment *A) + { + int a, b, c, r1, r2,s, p, n, tn; + int *col; + static int **mat; + Alignment *T=NULL; + int **score; + char *buffer; + + + /*Viterbi Parameters*/ + int AL=0; /*Allowed Transition*/ + int F=-1000000; /*Forbiden Transition*/ + int SPLICE_PENALTY=100; + int ORF1=0, ORF2=1, ORF3=2, NC=3; + + int state, pstate, best_e, best_pstate_p,best_state_p, best_pstate_v, best_state_v, v; + int nstate=4; + int **transitions; + int e; + int **v_tab_p; + int **v_tab; + int * is_dna; + + best_state_p=best_state_v=best_pstate_p=best_pstate_v=best_e=0; + buffer=vcalloc ( 100000, sizeof (char)); + is_dna=vcalloc ( A->nseq, sizeof (int)); + score=declare_int ( A->nseq+1, A->len_aln); + + + if ( !mat)mat=read_matrice("pam250mt"); + T=copy_aln (A, T); + col=vcalloc ( A->nseq, sizeof (int)); + + for (a=0; a<= A->len_aln; a++) + for ( b=0; b< A->nseq; b++){A->seq_al[b][a]=tolower(A->seq_al[b][a]); A->seq_al[b][a]=(A->seq_al[b][a]=='t')?'u':A->seq_al[b][a];} + + for ( a=0; a< A->nseq; a++) + { + sprintf ( buffer, "%s", A->seq_al[a]); + ungap (buffer); + is_dna[a]=strm ( get_string_type (buffer), "DNA"); + } + + + for (a=0; a< A->len_aln-2; a++) + { + for (b=0; b< A->nseq; b++) + { + if (is_dna[b])col[b]=translate_dna_codon (A->seq_al[b]+a, 'x'); + else col[b]=tolower ( A->seq_al[b][a]); + } + + for (n=0,tn=0,b=0; b< A->nseq; b++) + for ( c=b; c< A->nseq; c++ ) + { + r1=col[b]; + r2=col[c]; + + if (r1=='x' || r2=='x'){score[A->nseq][a]=F;break;} + else if (r1=='-' && r2=='-'); + else if (r1=='-' || r2=='-'); + else + { + + if ( is_dna[b] && is_dna[c])score[A->nseq][a]+= mat[r1-'A'][r2-'A']; + else score[A->nseq][a]+=mat[r1-'A'][r2-'A']* (A->nseq*A->nseq); + } + n+=( !is_gap(r1) && !is_gap(r2)); + score[A->nseq][a]=(((tn!=0)?score[A->nseq][a]/tn:0)); + } + + } + + /*initialisation*/ + + transitions=declare_int ( nstate, nstate); + v_tab=declare_int ( A->len_aln+2, nstate ); + v_tab_p=declare_int ( A->len_aln+2, nstate ); + + for (a=0; anseq; s++) + { + for ( p=0; p<=A->len_aln; p++){for (state=0; state< nstate; state++)v_tab_p[p][state]=-1; } + for (p=1+2; p<= A->len_aln; p++) + { + + for (state=0; state< nstate; state++) + { + + if ( state==NC){e=-best_e;} + else + { + e=score[A->nseq][(p-1)-state]; + if ( state==0)best_e=e; + else best_e=MAX(e, best_e); + } + + for ( pstate=0; pstatebest_pstate_v) ) + { + best_pstate_v=v; + best_pstate_p=pstate; + } + } + + v_tab[p][state]=best_pstate_v; + v_tab_p[p][state]=best_pstate_p; + if (state==0 ||best_pstate_v>best_state_v ) + { + best_state_p=state; + best_state_v=best_pstate_v; + } + } + + } + + + + for (p=0; p< A->len_aln; p++)T->seq_al[s][p]='.'; + for (p=A->len_aln; p>0; p--) + { + + if ( best_state_p==0)T->seq_al[s][p-1]=translate_dna_codon (A->seq_al[s]+(p-1), 'x'); + else if ( best_state_p==1 || best_state_p==2)T->seq_al[s][p-1]='-'; + + + + best_state_p=v_tab_p[p][best_state_p]; + + } + } + + + + vfree (col); + return T; + } + +Alignment *clean_cdna_aln (Alignment *A) + { + /*Given an alignmnet of nucleotides + Returns the same alignmnent whith non coding nucleotides replaced with dots + + at each position, the emission probability is the sum of pair of the substitution of amino-acids + */ + + int a, b, c,s, p; + static int **mat; + int *emission; + float em1, em2; + char *buffer; + Alignment *B=NULL; + + + + + /*Viterbi Parameters*/ + int AL=0; /*Allowed Transition*/ + int F=-1000000; /*Forbiden Transition*/ + int PENALTY=30; + int NC, C1,C2, C3, START, END; + int nstate=0; + int state=0,best_state=0, score=0, best_score=0; + int p_state; + int e=0; + int **score_tab; + int **state_tab; + + int **transitions; + int n; + int r1, r2, r3; + + NC=nstate++; + C1=nstate++; + C2=nstate++; + C3=nstate++; + START=nstate++; + END=nstate++; + + + B=copy_aln (A, B); + buffer=vcalloc ( 100000, sizeof (char)); + emission=vcalloc (A->len_aln, sizeof (int)); + + if ( !mat) + { + mat=read_matrice("pam250mt"); + } + + /*Computation of the emission proba for the coding state*/ + + + for (a=0; a< A->len_aln; a++) + { + + /*First component: % occupancy of the column*/ + em1=0; + for ( b=0; b< A->nseq; b++) em1+=!is_gap(translate_dna_codon (A->seq_al[b]+a, '-')); + em1=em1/(float)A->nseq; + + /*Second Component: % similarity within column*/ + em2=0; + for (n=0,b=0; b< A->nseq-1; b++) + { + r1=translate_dna_codon (A->seq_al[b]+a, '-'); + + for (c=b+1; cnseq; c++) + { + r2=translate_dna_codon (A->seq_al[c]+a, '-'); + if (is_gap(r2) || is_gap(r1)); + else + { + n++; + em2+=((mat[r1-'A'][r2-'A'])>1)?1:0; + } + } + } + em2=em2/(float)((n==0)?1:n); + + + emission[a]=(em1*100); + + } + + + + /*initialisation*/ + + transitions=declare_int ( nstate, nstate); + score_tab=declare_int ( A->len_aln+2, nstate ); + state_tab=declare_int ( A->len_aln+2, nstate ); + + for (a=0; anseq; s++) + { + for ( p=0; p<=A->len_aln; p++){for (state=0; state< nstate; state++){score_tab[p][state]=F;state_tab[p][state]=-1;} } + score_tab[0][START]=0; + + for (p=1; p<= A->len_aln; p++) + { + for (state=0; state< nstate; state++) + { + if ( state==START || state==END)continue; + else if ( state==NC) e=-10; + else if ( state==C1) + { + e=emission[p-1]; + } + else if ( state ==C2) + { + if ( p-2<0)e=F; + else e=emission[p-2]; + } + else if ( state==C3) + { + if ( p-3<0)e=F; + else e=emission[p-3]; + } + + for (p_state=0; p_statebest_score){ best_score=score;best_state=p_state;} + + } + + score_tab[p][state]=best_score; + state_tab[p][state]=best_state; + + } + } + + best_score=best_state=UNDEFINED; + for (state=0; statebest_score) + { + best_score=score_tab[p-1][state]+e; + best_state=state; + } + + } + + for (p=A->len_aln; p>0;) + { + B->seq_al[s][p-1]=best_state+'0'; + best_state=state_tab[p][best_state]; + p--; + } + } + + for ( a=0; a< A->nseq; a++) + for ( b=0; b< A->len_aln;) + { + s=B->seq_al[a][b]; + if ( s==C1+'0') + { + r1=A->seq_al[a][b]; + r2=A->seq_al[a][b+1]; + r3=A->seq_al[a][b+2]; + + + if ( is_gap(r1) ||is_gap(r2) || is_gap(r3)) + { + A->seq_al[a][b]=(is_gap(r1))?'~':'.'; + A->seq_al[a][b+1]=(is_gap(r2))?'~':'.'; + A->seq_al[a][b+2]=(is_gap(r3))?'~':'.'; + } + b+=3; + } + else if ( s==NC+'0') + { + A->seq_al[a][b]=(is_gap(A->seq_al[a][b]))?'~':'.'; + b++; + } + else + { + fprintf (stderr, "\nPROBLEM: [%d %d]->%d", a, b, s-'0'); + } + } + + + free_aln (B); + free_int (transitions, -1); + free_int (score_tab, -1); + free_int (state_tab, -1); + vfree (emission); + vfree (buffer); + + return A; + } + + + + +Alignment *translate_splice_dna_aln (Alignment *A, Alignment *ST) + { + int a, b, c, r1, r2,s, p, n, tn; + int *col; + static int **mat; + Alignment *T=NULL; + int **score; + + /*Viterbi Parameters*/ + int AL=0; /*Allowed Transition*/ + int F=-1000000; /*Forbiden Transition*/ + int ORF1=0, ORF2=1, ORF3=2,SPL1=3, SPL2=4, SPL3=5, SPL4=6, NC=7; + int SPLICE_PENALTY; + int frame1, frame2, frame3, best_frame; + int nstate=8; + char r; + + + + int state=0, pstate=0, best_pstate_p=0,best_state_p=0, best_pstate_v=0, best_state_v=0, v=0; + + int **transitions; + int e=0; + int **v_tab_p; + int **v_tab; + + score=declare_int ( A->nseq+1, A->len_aln); + + + if ( !mat)mat=read_matrice("pam250mt"); + T=copy_aln (A, T); + col=vcalloc ( A->nseq, sizeof (int)); + + for (a=0; a<= A->len_aln; a++) + for ( b=0; b< A->nseq; b++){A->seq_al[b][a]=tolower(A->seq_al[b][a]); A->seq_al[b][a]=(A->seq_al[b][a]=='t')?'u':A->seq_al[b][a];} + + + + + for (a=0; a< A->len_aln-2; a++) + { + for (b=0; b< A->nseq; b++) + { + col[b]=translate_dna_codon (A->seq_al[b]+a, 'x'); + } + + for (n=0,tn=0,b=0; b< A->nseq-1; b++) + for ( c=b+1; c< A->nseq; c++, tn++ ) + { + r1=col[b]; + r2=col[c]; + + if (r1=='x' || r2=='x')score[A->nseq][a]=F; + else if (r1=='-' && r2=='-'); + else if (r1=='-' || r2=='-'); + else + { + score[A->nseq][a]+= mat[r1-'A'][r2-'A']; + + } + n+=( !is_gap(r1) && !is_gap(r2)); + } + score[A->nseq][a]=(((tn!=0)?score[A->nseq][a]/tn:0)); + + } + + /*initialisation*/ + + transitions=declare_int ( nstate, nstate); + v_tab=declare_int ( A->len_aln+2, nstate*nstate); + v_tab_p=declare_int ( A->len_aln+2, nstate*nstate); + + for (a=0; anseq; s++) + { + for ( p=0; p<=A->len_aln; p++){for (state=0; state< nstate; state++)v_tab_p[p][state]=-1; } + for (p=1+2; p<= A->len_aln; p++) + { + frame1=score[A->nseq][(p-1)]; + frame2=score[A->nseq][(p-1)-1]; + frame3=score[A->nseq][(p-1)-2]; + best_frame=best_int (3, 1, &a, frame1, frame2, frame3); + for (state=0; state< nstate; state++) + { + r=tolower (A->seq_al[s][p-1]); + r=(r=='u')?'t':r; + + if (state==ORF1)e=frame1; + else if (state==ORF2)e=frame2; + else if (state==ORF3)e=frame3; + else if (state==SPL1)e=(r=='g')?best_frame:F; + else if (state==SPL2)e=(r=='t')?best_frame:F; + else if (state==SPL3)e=(r=='a')?best_frame:F; + else if (state==SPL4)e=(r=='g')?best_frame:F; + else if (state==NC)e=-best_frame; + for ( pstate=0; pstatebest_pstate_v) ){best_pstate_v=v;best_pstate_p=pstate;} + } + + v_tab[p][state]=best_pstate_v; + v_tab_p[p][state]=best_pstate_p; + if (state==0 ||best_pstate_v>best_state_v ){best_state_p=state; best_state_v=best_pstate_v;} + } + } + + + + for (p=0; p< A->len_aln; p++)T->seq_al[s][p]='.'; + for (p=A->len_aln; p>0; p--) + { + if ( best_state_p==0)T->seq_al[s][p-1]=toupper(translate_dna_codon (A->seq_al[s]+(p-1), 'x')); + else if ( best_state_p>=SPL1 && best_state_p<=SPL4)T->seq_al[s][p-1]='-'; + best_state_p=v_tab_p[p][best_state_p]; + } + } + + + + vfree (col); + return T; + } + +Alignment * mutate_cdna_aln ( Alignment *A) +{ + int a, b, c, n; + int n1, n2, r1, r2; + int **pos, ps; + int neutral_substitution=50; + int random_substitution=0; + int random_deletion=0; + int amino_acid_deletion=0; + int amino_acid_substitution=0; + char nuc_list[]="agct"; + char *new_codon; + + neutral_substitution=atoi(get_env_variable ("NEUTRAL_SUBSTITUTION",IS_FATAL)); + random_substitution =atoi(get_env_variable ("RANDOM_SUBSTITUTION", IS_FATAL)); + random_deletion =atoi(get_env_variable ("RANDOM_DELETION", IS_FATAL)); + amino_acid_deletion =atoi(get_env_variable ("AMINO_ACID_DELETION", IS_FATAL)); + amino_acid_substitution =atoi(get_env_variable ("AMINO_ACID_SUBSTITUTION", IS_FATAL)); + + + if (A->S)free_sequence ( A->S, (A->S)->nseq); + A->S=aln2seq(A); + + addrandinit(time (NULL)); + + + pos=aln2pos_simple ( A, A->nseq); + + /* 1 Apply neutral substitutions */ + + if ( neutral_substitution) + { + for ( c=0; c< neutral_substitution; c++) + { + for ( a=0; a< A->nseq; a++) + { + + for ( b=0; b< A->len_aln; b++) + { + + if (pos[a][b]<=0)continue; + ps=MAX(0,pos[a][b]-(pos[a][b]-1)%3-1); + + + n1=(A->S)->seq[a][pos[a][b]-1]; + r1=translate_dna_codon ( (A->S)->seq[a]+ps, 'o'); + + n2=nuc_list[(int)addrand((unsigned long) 4)]; + (A->S)->seq[a][pos[a][b]-1]=n2; + r2=translate_dna_codon ( (A->S)->seq[a]+ps, 'o'); + + + if ( r1==r2 && r1!='o')A->seq_al[a][b]=n2; + + else (A->S)->seq[a][pos[a][b]-1]=n1; + } + } + } + } + + /* 2 Apply substitutions */ + if ( random_substitution) + { + for ( a=0; a< A->nseq; a++) + { + for ( b=0; b< A->len_aln; b++) + { + if (pos[a][b]<=0)continue; + if (addrand ((unsigned long) 100)>random_substitution)continue; + + n1=nuc_list[(int)addrand((unsigned long)4)]; + (A->S)->seq[a][pos[a][b]-1]=n1; + A->seq_al[a][b]=n1; + } + } + } + + /* 3 Apply amino acid substitutions */ + if ( amino_acid_substitution) + { + for ( a=0; a< A->nseq; a++) + { + for ( b=0; b< A->len_aln; b+=3) + { + if (pos[a][b]<=0)continue; + if (addrand ((unsigned long) 100)>amino_acid_substitution)continue; + ps=MAX(0,pos[a][b]-(pos[a][b]-1)%3-1); + + r1=translate_dna_codon ( (A->S)->seq[a]+ps, 'o'); + new_codon=mutate_amino_acid(r1, "clustalw_col"); + + for ( c=ps; cS)->seq[a][c]=new_codon[c-ps]; + } + for ( b=0; b< A->len_aln; b++) + { + if (pos[a][b]<=0)continue; + else A->seq_al[a][b]=(A->S)->seq[a][pos[a][b]-1]; + } + } + } + /* 3 Apply amino acid deletions */ + if ( amino_acid_deletion) + { + for ( a=0; a< A->nseq; a++) + { + for ( b=0; b< A->len_aln; b+=3) + { + if (pos[a][b]<=0)continue; + if (addrand ((unsigned long) 1000)>amino_acid_deletion)continue; + ps=MAX(0,pos[a][b]-(pos[a][b]-1)%3-1); + n=addrand ((unsigned long) 4)+1; + + for ( c=ps; clen_aln; c++)(A->S)->seq[a][c]='-'; + } + for ( b=0; b< A->len_aln; b++) + { + if (pos[a][b]<=0)continue; + else A->seq_al[a][b]=(A->S)->seq[a][pos[a][b]-1]; + } + } + } + /* 4 Apply amino acid insertions */ + +/*FRAMESHIFT MUTATIONS*/ + /* 5 Apply nucleotide deletions*/ + if ( random_deletion) + { + for ( a=0; a< A->nseq; a++) + { + for ( b=0; b< A->len_aln; b++) + { + if (pos[a][b]<=0)continue; + if (addrand ((unsigned long) 1000)>random_deletion)continue; + + n1='-'; + (A->S)->seq[a][pos[a][b]-1]=n1; + A->seq_al[a][b]=n1; + } + } + } + /* 6 Apply nucleotide deletions*/ + free_int (pos, -1); + return A; + +} + +Alignment* clean_est ( Alignment *A) + { + /*Rules are as follow: + Internal Gap > 30% Requences ----> - + Best Residue < 50% Residues ----> 'N' + */ + int a, b,c; + int best; + int tot; + + for ( a=0; a< A->len_aln; a++) + { + + for (tot=0, b=0; b<4; b++)tot+=(A->P)->count[b][a]; + best=best_int (5,1, &c, (A->P)->count[0][a],(A->P)->count[1][a],(A->P)->count[2][a],(A->P)->count[3][a],(A->P)->count[4][a]); + + if ( tot==0) + { + fprintf ( stderr, "\nWARNING: POSITION WITH NO INFORMATION [clean_est:%s]", PROGRAM); + A->seq_al[0][a]='-'; + } + else if (((A->P)->count[4][a]*100)/tot >30)A->seq_al[0][a]='-'; + else if ( (best*100)/tot<50)A->seq_al[0][a]='n'; + + } + return A; + } + + + +char **make_symbols ( char *name, int *n) + { + char **symbol; + + symbol=declare_char ( STRING, STRING); + + if ( strcmp (name, "3d_ali")==0) + { + sprintf ( symbol[0], "gih"); + sprintf ( symbol[1], "eb"); + sprintf ( symbol[2], "x"); + sprintf ( symbol[3], "#l"); + n[0]=4; + } + + else if ( strcmp (name, "all")==0) + { + int a, i; + for ( i=0,a=0; a<26; a++) + { + sprintf ( symbol[i++], "%c%c", 'a'+a, 'a'+a); + sprintf ( symbol[i++], "%c%c", 'A'+a, 'A'+a); + } + sprintf ( symbol[i++], "--"); + n[0]=i; + } + + else if ( strcmp (name, "set1")==0) + { + sprintf ( symbol[0], "ilvmfywhktcagH"); + sprintf ( symbol[1], "reqdnsP"); + sprintf ( symbol[2], "--"); + sprintf ( symbol[3], "#l"); + n[0]=4; + } + else if ( strcmp (name, "set2")==0) + { + n[0]=0; + sprintf ( symbol[n[0]++], "gsacT"); + sprintf ( symbol[n[0]++], "ndtvpS"); + sprintf ( symbol[n[0]++], "ilkreqL"); + sprintf ( symbol[n[0]++], "--"); + sprintf ( symbol[n[0]++],"#l"); + } + else if ( strcmp ( name, "any")==0) + { + sprintf ( symbol[0], "*x"); + n[0]=1; + } + + + + + return symbol; + } + +char *testdna2gene (char *dna) +{ + int *w,a,l; + l=strlen (dna); + HERE ("%s", dna); + w=vcalloc(l+1, sizeof (int)); + for (a=0; anseq; a++) + { + p=dna2gene (S->seq[a], w[a]); + if (strstr (p, "F")) + { + HERE ("----FRAMESHIFT: %s", S->name[a]); + } + vfree (PS->seq[a]); + PS->len[a]=strlen(p); + PS->seq[a]=vcalloc (PS->len[a]+1, sizeof (char)); + sprintf ( PS->seq[a], "%s", p); + vfree (p); + } + PS=reset_sequence_len (PS); + return PS; +} + +char *dna2gene (char *dna, int *w) +{ + int a, b, c, ns,l,od; + int I1, I2, I3, START, NCE, NCS; + int C1, S1_1, S2_1, S3_1, S4_1,NC1; + int C2, S1_2, S2_2, S3_2, S4_2,NC2; + int C3, S1_3, S2_3, S3_3, S4_3,NC3; + int ST; + int st; + + double p_C1, p_C2; + double **C1_mat, **C2_mat; + double *tb, **sc_mat, **tb_mat; + double **em, **trans; + double avg_w=0; + + char **string; + double forbiden =-100000; + double frameshift1; + double frameshift2; + double exon_penalty; + double exon_reward; + double nostop_penalty; + double shiftw; + int frameshift_symbol='F'; + char *out_dna; + int max=0; + + char *three_dna; + + three_dna=translate_dna_seq_on3frame (dna, 'x', NULL); + lower_string(three_dna); + l=strlen (dna); + for (a=0; abest_sc) + { + best_sc=sc; + best_t =c; + } + } + } + } + + C1_mat[a][b]=(b==C1)?r:C1_mat[a-1][best_t]; + C2_mat[a][b]=(b==C2)?r:C2_mat[a-1][best_t]; + sc_mat[a][b]=best_sc; + tb_mat [a][b]=best_t; + } + + } + } + + a=l; + b=NCE; + c=sc_mat[a][NCE]; + + while (a>0) + { +// HERE ("**%d [%s] %c in %d", b,string[b], dna[a-1], a); + tb[a]=b; + b=tb_mat[a][b]; + a--; + } + + od=0; + st=0; + for (a=0;anseq; a++) + for (b=0; blen[a]; b++){avg+=w[a][b];n++;} + return avg/n; +} +int res_weights2min(Sequence *R, int **w) +{ + int a,b; + int min=w[0][0]; + + for (a=0; anseq; a++) + for (b=0; blen[a]; b++)min=MIN(min,(w[a][b])); + return min; +} +int res_weights2max(Sequence *R, int **w) +{ + int a, b; + int max=w[0][0]; + + for (a=0; anseq; a++) + for (b=0; blen[a]; b++)max=MAX(max,(w[a][b])); + return max; +} +int scan_res_weights4ac (Sequence *R, int **w, int start, int end, int step) +{ + int best_t, a; + float best_ac=0; + float *count; + float *acc; + int avg; + + avg=res_weights2avg(R,w); + best_t=start; + for (a=start; a<=end; a+=step) + { + + count=res_weights2accuracy_counts (R,w,a,NULL); + acc=counts2accuracy (count); + + if (acc[3]>best_ac) + { + best_ac=acc[3]; + best_t=a; + } + vfree (count);vfree (acc); + } + count=res_weights2accuracy_counts (R,w,best_t,NULL); + acc=counts2accuracy (count); + fprintf (stderr, "\nBest_T: %d ", best_t); + display_accuracy (count,stderr); + + count=res_weights2accuracy_counts (R,w,2*avg,NULL); + acc=counts2accuracy (count); + fprintf (stderr, " Avg_T: %d ", 2*avg); + display_accuracy (count,stderr); + + vfree (acc); vfree (count); + return best_t; +} +int ** shift_res_weights ( Sequence *R, int **w, int shift) +{ + int a, b; + for (a=0; anseq; a++) + for (b=0; blen[a]; b++) + w[a][b]+=shift; + return w; +} +float *res_weights2accuracy_counts ( Sequence *R, int **w,int T, float *result) +{ + int a, b, coding,pcoding; + + if (!result)result=vcalloc (4, sizeof (float)); + + for (a=0; anseq; a++) + { + for (b=0; blen[a]; b++) + { + coding=(isupper(R->seq[a][b]))?1:0; + pcoding=(w[a][b]>T)?1:0; + if ( coding && pcoding)result[0]++;//TP + else if ( !coding && !pcoding)result[1]++;//TN + else if ( !coding && pcoding)result[2]++;//FP + else if ( coding && !pcoding)result[3]++;//FN + } + } + return result; +} + +void genepred_seq2accuracy_counts4all (Sequence *R, Sequence *T) +{ + int a,b; + float *result =vcalloc (4, sizeof (float)); + + fprintf ( stderr, "\n"); + + for (a=0; anseq; a++) + { + fprintf ( stderr, "gene: %s ", R->name[a]); + for (b=0; bnseq; b++) + { + if ( strm (R->name[a], T->name[b]) && hasupper(R->seq[a])) + { + vfree (display_accuracy (genepred2accuracy_counts (R->seq[a], T->seq[b], NULL),stderr)); + break; + } + } + } + vfree(result); +} + +float* genepred_seq2accuracy_counts (Sequence *R, Sequence *T,float *result) +{ + int a,b; + + if (!result)result=vcalloc (4, sizeof (float)); + + for (a=0; anseq; a++) + for (b=0; bnseq; b++) + if ( strm (R->name[a], T->name[b]) && hasupper(R->seq[a])) + genepred2accuracy_counts (R->seq[a], T->seq[b], result); + return result; +} + +float* genepred2accuracy_counts (char *ref, char *target , float *result) +{ + char *ref2, *target2; + int l,a; + if ( !result) result=vcalloc (4, sizeof (float)); + ref2=vcalloc ( strlen (ref)+1, sizeof (char)); + sprintf ( ref2, "%s", ref); + + target2=vcalloc ( strlen (target)+1, sizeof (char)); + sprintf ( target2, "%s", target); + + remove_charset (ref2, "Ff"); + remove_charset (target2, "Ff"); + + if ( strlen (target2) != strlen (ref2)) + {fprintf (stderr, "ERROR: Gene and target have different length [FATAL]\n"); myexit (EXIT_FAILURE);} + + l=strlen (ref2); + for (a=0; a3 + int a, b, l; + char *buf; + + l=strlen (dna_seq); + if ( prot==NULL)prot=vcalloc ( l, sizeof (char)); + frame--; + buf=vcalloc (l+4, sizeof (char)); + sprintf (buf, "%s", dna_seq); + lower_string ( buf); + for ( a=0; a< l; a++)buf[a]=(buf[a]=='t')?'u':buf[a]; + + + for ( b=0,a=0+frame; a< l; a+=3,b++) + { + + prot[b]=translate_dna_codon (buf+a, stop); + } + vfree (buf); + prot[b]='\0'; + upper_string (buf); + return prot; + } +char * back_translate_dna_codon ( char aa, int deterministic) + { + static char *r; + int choice; + + vsrand(0); + if ( r==NULL)r=vcalloc (4, sizeof (char)); + + if (!is_gap(aa))aa=tolower(aa); + + if (is_gap(aa))sprintf (r, "---"); + else if ( aa>=0 && aa<=9) + { + sprintf (r, "%d%d%d", aa, aa,aa); + } + else if ( aa>='0' && aa<='9') + { + sprintf (r, "%c%c%c", aa, aa,aa); + } + else if ( aa=='a') + { + choice=(deterministic)?0:rand()%4; + if ( choice==0)sprintf (r, "gca"); + else if ( choice==1)sprintf (r, "gcg"); + else if ( choice==2)sprintf (r, "gcc"); + else if ( choice==3)sprintf (r, "gct"); + } + else if ( aa=='c') + { + choice=(deterministic)?0:rand()%2; + if ( choice==0)sprintf (r, "tgc"); + else if ( choice==1)sprintf (r, "tgt"); + } + else if ( aa=='d') + { + choice=(deterministic)?0:rand()%2; + if ( choice==0)sprintf (r, "gac"); + else if ( choice==1)sprintf (r, "gat"); + } + + else if ( aa=='e') + { + choice=(deterministic)?0:rand()%2; + if ( choice==0)sprintf (r, "gaa"); + else sprintf (r, "gag"); + } + else if ( aa=='f') + { + choice=(deterministic)?0:rand()%2; + if ( choice==0)sprintf (r, "ttc"); + else sprintf (r, "ttt"); + } + else if ( aa=='g') + { + choice=(deterministic)?0:rand()%4; + if ( choice==0) sprintf (r, "gga"); + else if ( choice==1) sprintf (r, "ggg"); + else if ( choice==2) sprintf (r, "ggc"); + else if ( choice==3) sprintf (r, "ggt"); + } + else if ( aa=='h') + { + choice =rand()%2; + if ( choice==0)sprintf (r, "cac"); + else sprintf (r, "cat"); + } + else if ( aa=='i') + { + choice=(deterministic)?0:rand()%3; + if ( choice==0) sprintf (r, "ata"); + else if ( choice==1) sprintf (r, "atc"); + else if ( choice==2) sprintf (r, "att"); + } + else if ( aa=='k') + { + choice=(deterministic)?0:rand()%2; + if ( choice==0) sprintf (r, "aaa"); + else if ( choice==1) sprintf (r, "aag"); + + } + else if ( aa=='l') + { + choice=(deterministic)?0:rand()%6; + if ( choice==0) sprintf (r, "cta"); + else if ( choice==1) sprintf (r, "ctg"); + else if ( choice==2) sprintf (r, "ctc"); + else if ( choice==3) sprintf (r, "ctt"); + else if ( choice==4) sprintf (r, "tta"); + else if ( choice==5) sprintf (r, "ttg"); + } + else if ( aa=='m')sprintf ( r, "atg"); + else if ( aa=='n') + { + choice=(deterministic)?0:rand()%2; + if ( choice==0) sprintf (r, "aac"); + else if ( choice==1) sprintf (r, "aat"); + } + else if ( aa=='p') + { + choice=(deterministic)?0:rand()%4; + if ( choice==0) sprintf (r, "cca"); + else if ( choice==1) sprintf (r, "ccg"); + else if ( choice==2) sprintf (r, "ccc"); + else if ( choice==3) sprintf (r, "cct"); + } + else if ( aa=='q') + { + choice=(deterministic)?0:rand()%2; + if ( choice==0) sprintf (r, "caa"); + else if ( choice==1) sprintf (r, "cag"); + } + else if ( aa=='r') + { + choice=(deterministic)?0:rand()%6; + if ( choice==0) sprintf (r, "cga"); + else if ( choice==1) sprintf (r, "cgg"); + else if ( choice==2) sprintf (r, "cgc"); + else if ( choice==3) sprintf (r, "cgt"); + else if ( choice==4) sprintf (r, "aga"); + else if ( choice==5) sprintf (r, "agg"); + + } + else if ( aa=='s') + { + choice=(deterministic)?0:rand()%6; + if ( choice==0) sprintf (r, "tca"); + else if ( choice==1) sprintf (r, "tcg"); + else if ( choice==2) sprintf (r, "tcc"); + else if ( choice==3) sprintf (r, "tct"); + else if ( choice==4) sprintf (r, "agt"); + else if ( choice==5) sprintf (r, "agc"); + + } + else if ( aa=='t') + { + choice=(deterministic)?0:rand()%4; + if ( choice==0) sprintf (r, "aca"); + else if ( choice==1) sprintf (r, "acg"); + else if ( choice==2) sprintf (r, "acc"); + else if ( choice==3) sprintf (r, "act"); + } + else if ( aa=='v') + { + choice=(deterministic)?0:rand()%4; + if ( choice==0) sprintf (r, "gta"); + else if ( choice==1) sprintf (r, "gtg"); + else if ( choice==2) sprintf (r, "gtc"); + else if ( choice==3) sprintf (r, "gtt"); + } + else if ( aa=='w') + { + sprintf (r, "tgg"); + } + else if ( aa=='y') + { + choice=(deterministic)?0:rand()%2; + if ( choice==0) sprintf (r, "tac"); + else if ( choice==1) sprintf (r, "tat"); + } + else + { + sprintf (r, "nnn"); + } + return r; + + } +int translate_dna_codon ( char *sequence, char stop) + { + char seq[4]; + int b; + int upper; + int ret; + + if ( strlen (sequence)<1) return 'n'; + upper=isupper (sequence[0])?1:0; + + if ( (b=strlen (sequence))<3) + ret='x'; + else + { + seq[0]=tolower(sequence[0]); + seq[1]=tolower(sequence[1]); + seq[2]=tolower(sequence[2]); + seq[3]='\0'; + + seq[0]=(seq[0]=='u')?'t':seq[0]; + seq[1]=(seq[1]=='u')?'t':seq[1]; + seq[2]=(seq[2]=='u')?'t':seq[2]; + if ( strm5(seq, "gca", "gcg", "gcc", "gct","gcn"))ret='a'; + else if ( strm2(seq, "tgc","tgt"))ret='c'; + else if ( strm2(seq, "gac","gat"))ret='d'; + else if ( strm2(seq, "gaa","gag"))ret='e'; + else if ( strm2(seq, "ttc","ttt"))ret='f'; + else if ( strm5(seq, "gga","ggg","ggc", "ggt", "ggn"))ret='g'; + else if ( strm2(seq, "cac","cat"))ret='h'; + else if ( strm3(seq, "ata","atc","att"))ret='i'; + else if ( strm2(seq, "aaa","aag"))ret= 'k'; + else if ( strm6(seq, "cta","ctg","ctc", "ctt", "tta", "ttg"))ret='l'; + else if ( strm (seq, "ctn"))ret='l'; + else if ( strm (seq, "atg"))ret='m'; + else if ( strm2(seq, "aac","aat"))ret= 'n'; + else if ( strm5(seq, "cca","ccg","ccc", "cct","ccn"))ret='p'; + else if ( strm2(seq, "cag","caa"))ret='q'; + else if ( strm6(seq, "cga","cgg","cgc", "cgt","aga","agg"))ret='r'; + else if ( strm (seq, "cgn"))ret= 'r'; + else if ( strm6(seq, "tca","tcg","tcc", "tct","agc","agt"))ret='s'; + else if ( strm (seq, "ccn"))ret='s'; + else if ( strm5(seq, "aca","acg","acc", "act", "acn"))ret='t'; + else if ( strm5(seq, "gta","gtg","gtc", "gtt", "gtn"))ret='v'; + else if ( strm (seq, "tgg"))ret='w'; + else if ( strm2(seq, "tac","tat"))ret='y'; + else if ( strm3(seq, "tag","taa","tga"))ret=stop; + else ret='x'; + + ret= (upper)?toupper(ret):ret; + } + return ret; + } + +int extend_seqaln (Sequence *S, Alignment *A) +{ + char **s; + int n,a; + if (S){s=S->seq;n=S->nseq;} + else if (A){s=A->seq_al;n=A->nseq;} + else return 0; + + for (a=0; aseq;n=S->nseq;} + else if (A){s=A->seq_al;n=A->nseq;} + else return 0; + + for (a=0; atype, "DNA") || strm(S->type, "RNA"))sprintf (alp, "AGCT"); + else if ( strm(S->type, "PROTEIN"))sprintf (alp, "ACDEFGHIKLMNPQRSTVWY"); + + alp_size=strlen(alp); + + B=copy_aln (A,NULL); + B=realloc_aln(B, B->len_aln*2+1); + + for ( a=0, b=0; a< A->len_aln; a++, b+=2) + { + for ( c=0; c< A->nseq; c++) + { + B->seq_al[c][b]=tolower(A->seq_al[c][a]); + B->seq_al[c][b+1]='~'; + } + } + + for ( c=0; c< A->nseq; c++)B->seq_al[c][b]='\0'; + B->len_aln=A->len_aln*2; + + + + tot=n_mut=0; + for (a=0; a< B->len_aln; a+=2) + for ( b=0; bnseq; b++) + { + if ( is_gap(B->seq_al[b][a]))continue; + mut=((rand()%RAND_MAX)>ratio)?0:1; + tot++; + n_mut+=mut; + + if (mut) + { + type=rand()%2; + if (type==0)/*deletion*/ + { + B->seq_al[b][a]='.'; + } + else if ( type==1) + { + B->seq_al[b][a+1]=alp[rand()%alp_size]; + } + else if (type==2) + { + B->seq_al[b][a]=alp[rand()%alp_size]; + } + + } + } + ungap_aln (B); + + + free_sequence (S, S->nseq); + free_aln (A); + return B; + +} + +char* mutate_amino_acid ( char aa, char *mode) + + { + int a, b, c, d; + char nucleotide[]="agct"; + char amino_acid[]="acdefghiklmnpqrstvwy"; + static char **triplet; + static char **cw_col; + int ng_cw_col; + static int **amino_acid_list; + static int *lu; + char a1, a2; + char *mat; + + aa=tolower(aa); + declare_name(mat); + if ( !mode)sprintf (mat, "clustalw_col"); + else sprintf (mat, "%s", mode); + if (!triplet) + { + triplet=declare_char ( 64, 4); + for (d=0, a=0; a< 4;a++) + for ( b=0; b< 4; b++) + for ( c=0; c< 4; c++, d++) + { + triplet[d][0]=nucleotide[a]; + triplet[d][1]=nucleotide[b]; + triplet[d][2]=nucleotide[c]; + } + } + if ( !cw_col)cw_col=make_group_aa ( &ng_cw_col,mat); + if ( !amino_acid_list) + { + amino_acid_list=declare_int ( 20, 65); + for ( a=0; a< 20; a++) + for ( b=0; b< 64; b++) + { + a1=translate_dna_codon ( triplet[b], 'x'); + a2=amino_acid[a]; + for ( d=0; d< ng_cw_col; d++) + if ( is_in_set ( a1, cw_col[d]) && is_in_set ( a2, cw_col[d])) + { + amino_acid_list[a][++amino_acid_list[a][0]]=b; + } + } + lu=vcalloc ( 26, sizeof (int)); + for ( a=0; a<20; a++) + { + lu[amino_acid[a]-'a']=a; + } + /* + for ( a=0; a< 20; a++) + { + fprintf ( stderr, "\n%c", amino_acid[a]); + for ( b=1; b<=amino_acid_list[a][0]; b++) + fprintf ( stderr, "\n\t%s %c", triplet[amino_acid_list[a][b]], translate_dna_codon (triplet[amino_acid_list[a][b]], 'x')); + } + */ + } + + return triplet [addrand((unsigned long)amino_acid_list[lu[aa-'a']][0])+1]; + } + +/**************************************************************************************************/ +/******************************** ********************************************/ +/******************************** PROCESSING ********************************************/ +/******************************** ********************************************/ + + + +void modify_data (Sequence_data_struc *D1in, Sequence_data_struc *D2in, Sequence_data_struc *DSTin, char **action_list,int n_actions, Action_data_struc *RAD) + { + Sequence *COOR=NULL, *NS=NULL,*BUFS=NULL, *OUT_S=NULL; + Constraint_list *CL; + char *s; + int value,upper_value, lower_value, start, end, a, b,c; + int *count_table=NULL; + char *action; + Sequence_data_struc *D1; + Sequence_data_struc *D2; + Sequence_data_struc *DST; + int s1, s2, r1, r2; + static int clean_flag; + Alignment *BUF; + + /*Switches*/ + + action=action_list[0]; + + if (action[0]=='2') + { + + D1=D2in; + D2=D1in; + DST=DSTin; + action++; + } + else if ( action[0]=='1') + { + D1=D1in; + D2=D2in; + DST=DSTin; + action++; + } + else if ( action[0]=='3') + { + D1=DSTin; + D2=D1in; + DST=DSTin; + action++; + } + else + { + D1=D1in; + D2=D2in; + DST=DSTin; + } + if (!D1->A)D1->A=copy_aln (D1in->A, NULL); + + if ( strm(action, "seqnos")) + { + (D1->A)->output_res_num=1; + } + else if ( strm (action,"aln2bootstrap")) + { + (D1->A)=aln2bootstrap (D1->A, ATOI_ACTION (1)); + D1->S=aln2seq (D1->A); + } + else if ( strm (action,"aln2sample")) + { + (D1->A)=aln2sample (D1->A, ATOI_ACTION (1)); + D1->S=aln2seq (D1->A); + } + else if ( strm (action,"aln2random_aln")) + { + (D1->A)=aln2random_aln (D1->A, ACTION (1)); + D1->S=aln2seq (D1->A); + } + else if ( strm (action, "or_scan")) + { + HERE ("OR SCAN"); + D1->A=or_scan(D1->A, D2->A, ACTION(1)); + D1->S=aln2seq (D1->A); + } + else if ( strm (action, "or_sar")) + { + D1->A=or_sar(D1->A, D2->A, ACTION(1), PRINT); + D1->S=aln2seq (D1->A); + } + else if ( strm ( action, "sar2subsar")) + { + /*in->sequences + in2->sar data + */ + Alignment *subA, *subS; + + if ( n_actions==1) + { + fprintf ( stderr, "\nin=aln, in2=sar sar2subsar [filter value compound1 compound2...] | [jack1] | [file]\n"); + myexit (EXIT_FAILURE); + } + + sarset2subsarset ( D1->A, D2->A, &subA, &subS, main_read_aln (action_list[2], NULL)); + D1->A=subA;D2->A=subS; + } + else if ( strm (action, "display_sar")) + { + D1->A=display_sar (D1->A, D2->A, action_list[1]); + } + else if ( strm ( action, "sar2simpred")) + { + /*in->sequences + in2->sar data + */ + sar2simpred ( D1->A, D2->A, action_list[1], action_list[2], atoi(action_list[3]), atoi (action_list[4])); + } + else if ( strm ( action, "sar2simpred2")) + { + /*in->sequences + in2->sar data + */ + if ( n_actions!=5) + { + fprintf ( stderr, "\nERROR: +sar2simpred2 seqnamesfile posfile compound limit"); + myexit (EXIT_FAILURE); + } + sar2simpred2 ( D1->A, D2->A, action_list[1], action_list[2], action_list[3], atoi (action_list[4])); + } + else if ( strm ( action, "sar_analyze")) + { + /*in->sequences + in2->sar data + */ + sar_analyze ( D1->A, D2->A,action_list[1]); + } + else if ( strm ( action, "simple_sar_predict")) + { + //displays each column with ist score; + simple_sar_predict (D1->A, D2->A,ACTION(1)); + myexit (EXIT_SUCCESS); + } + else if ( strm ( action, "display_sar_analyze")) + { + //displays each column with ist score; + display_simple_sar_analyze_col (D1->A, D2->A,ACTION(1)); + myexit (EXIT_SUCCESS); + } + else if ( strm ( action, "display_sar_analyze_pc")) + { + //displays each column with ist score; + display_simple_sar_analyze_pair_col (D1->A, D2->A,ACTION(1)); + myexit (EXIT_SUCCESS); + } + else if ( strm ( action, "weight2sar")) + { + /*in->sequences + in2->sar data + */ + if ( n_actions!=3) + { + fprintf ( stderr, "\nERROR: +weight2sar "); + myexit (EXIT_FAILURE); + } + D1->A=weight2sar ( D1->A,D2->A, action_list[1], atoi(action_list[2])); + + } + else if ( strm ( action, "sar_weight")) + { + /*in->sequences + in2->sar data + */ + if ( n_actions!=3) + { + fprintf ( stderr, "\nERROR: +sar_weight "); + myexit (EXIT_FAILURE); + } + D1->A=aln2weighted_sar_score ( D1->A,D2->A, action_list[1], action_list[2]); + D1->S=aln2seq ( D1->A); + } + + else if ( strm (action, "name2unique_name")) + { + char *tmp1, *tmp2; + char command[1000]; + tmp1=vtmpnam (NULL); tmp2=vtmpnam (NULL); + + output_fasta_aln (tmp1,D1->A); + free_aln (D1->A);free_sequence (D1->S, -1); + sprintf ( command, "fasta_aln2fasta_aln_unique_name.pl %s >%s", tmp1, tmp2); + my_system ( command); + D1->S=get_fasta_sequence ( tmp2, NULL); + D1->A=seq2aln (D1->S,NULL, 1); + } + else if ( strm (action, "rm_tag") || strm (action, "rm_template")) + { + + char **temp_name=NULL,**temp_list=NULL, temp_nseq=0; + int z; + + if ( D1 && D1->A){temp_name=(D1->A)->name;temp_nseq=(D1->A)->nseq;} + else if ( D1 && D1->S){temp_name=(D1->S)->name;temp_nseq=(D1->S)->nseq;} + temp_list=rm_name_tag (temp_name,temp_nseq, NULL); + if ( n_actions>1 && strm (action_list[1], "template")) + { + + for ( z=0; zS=seq2template_seq (D1->S, action_list[1], NULL); + D1->A=seq2aln(D1->S, NULL, 1); + } + else if ( strm ( action, "seq2year")) + { + D1->S=seq2year (D1->S, (n_actions>1)?atoi(action_list[1]):1); + D1->A=seq2aln(D1->S, NULL, 1); + } + else if ( strm (action, "swap_lib_header")) + { + Sequence *S; + S=main_read_seq (action_list[1]); + (D1->CL)->S=S; + + } + else if ( strm (action, "weight_lib")) + { + int l; + int w; + w=atoi (action_list[1]); + if ( D1->CL) + { + int s1, s2,r1,r2; + Sequence *S=(D1->CL)->S; + int ***r=(D1->CL)->residue_index; + + for (s1=0; s1nseq; s1++) + for (r1=1; r1<=S->len[s1]; r1++) + for (b=1; bS)->nseq; c++) + { + struclist2nb ((D1->S)->name[c],(D1->S)->seq[c], (D1->S)->seq_comment[c], atof(action_list[1]),ACTION(2),ACTION(3) ); + } + myexit (EXIT_SUCCESS); + } + + + + else if ( strm(action, "seq2contacts")) + { + int z; + D1->S=swap_header (D1->S, D2->S); + for ( z=0; z< (D1->S)->nseq; z++)sprintf ( (D1->A)->name[z], "%s", (D1->S)->name[z]); + DST->S=seq2contacts (D1->S, atof (action_list[1])); + DST->A=copy_aln (D1->A, NULL); + thread_seq_struc2aln ( DST->A,DST->S); + for (z=0; z< (D1->S)->nseq; z++) + (DST->A)->S=D1->S; + + } + else if ( strm(action, "struc2contacts")) + { + char *seq; + if ( atof (action_list[3])>0) + { + seq=map_contacts (action_list[1], action_list[2], atof (action_list[3])); + fprintf ( stderr, "\n>%s %s\n%s",action_list[1], action_list[2],seq); + } + else + print_contacts (action_list[1], action_list[2], atof (action_list[3])); + + myexit (EXIT_SUCCESS); + } + else if ( strm(action, "treelist_prune")|| strm(action, "prune_treelist")) + { + Sequence *TS; + if (D2 && D2->S)TS=D2->S; + else TS=treelist2sub_seq((D1->S),ATOI_ACTION(1)); + treelist2prune_treelist ( D1->S,TS, NULL); + D1->A=seq2aln (D1->S, NULL, NO_PAD); + } + else if ( strm (action, "tree2unresolved_nodes")) + { + int ns; + int *l; + ns=tree2nseq (D1->T); + l=vcalloc (ns, sizeof (int)); + tree2nnode_unresolved (D1->T, l); + for ( a=0; aT=main_prune_tree ( D1->T, D2->S); + } + else if ( strm ( action, "tree2seq")) + { + D1->S=tree2seq(D1->T, NULL); + D1->A=seq2aln (D1->S, D1->A, 1); + (D1->A)->len_aln=1; + for ( a=0; a< (D1->A)->nseq; a++)sprintf ( (D1->A)->seq_al[a], "sequence"); + } + else if ( strm (action, "seq2dpatree")) + { + D1->T= seq2dpa_tree(D1->S,"ktup"); + } + else if ( strm (action, "tree2dpatree")) + { + D1->T= tree2dpa_tree(D1->T,(D2 && D2->A)?D2->A:D1->A, (n_actions==1)?"idmat":action_list[1]); + } + else if ( strm (action, "tree2group")) + { + vfclose (tree2group (D1->T, (tree2seq(D1->T,NULL)), atoi(action_list[1]), atoi(action_list[2]),(n_actions==4)?action_list[3]:NULL, stdout)); + myexit (EXIT_SUCCESS); + } + else if ( strm(action, "unroot")) + { + D1->T=unroot_tree(D1->T); + } + + + else if ( strm(action, "treelist2group")|| strm(action, "treelist2groups") ) + { + Sequence *TS; + + if (D2 && D2->S)TS=D2->S; + else TS=treelist2seq((D1->S)); + treelist2groups (D1->S, TS, ACTION(1), stdout); + myexit (EXIT_SUCCESS); + + // treelist2groups (D1->S,(D2)?D2->S:NULL, ACTION(1), stdout ); + //exit (EXIT_SUCCESS); + } + else if ( strm(action, "splits2tree")) + { + + D1->T=split2tree ((D2)?D2->T:NULL,D1->S, ACTION(1)); + + } + else if ( strm(action, "count_splits")) + { + + count_splits ((D2)?D2->T:NULL,D1->S, ACTION(1)); + myexit (EXIT_SUCCESS); + } + else if ( strm(action, "count_groups")) + { + count_tree_groups (D1->S, ACTION(1)); + } + else if ( strm (action, "tree2dist")) + { + int ta, tb, ***td; + Sequence *TS; + + TS=(D2)?D2->S:NULL; + td=tree2dist (D1->T,TS, NULL); + if (!TS)TS=tree2seq(D1->T, NULL); + for (ta=0; tanseq; ta++) + { + fprintf ( stdout, "%-15s ",TS->name[ta]); + for ( tb=0; tbnseq; tb++) + { + int n=0; + if ( ACTION(1) && strm (ACTION(1), "length"))n=1; + + fprintf (stdout, " %4d", td [n][ta][tb]); + } + fprintf ( stdout, "\n"); + } + myexit (EXIT_SUCCESS); + } + else if ( strm (action, "treelist2lti")) + { + Sequence *TS; + if (D2 && D2->S)TS=D2->S; + else TS=treelist2sub_seq((D1->S),ATOI_ACTION(2)); + treelist2lti (D1->S,TS, (int)ATOI_ACTION(1), stdout ); + myexit (0); + } + else if ( strm (action,"treelist2frame")) + { + Sequence *TS; + if (D2 && D2->S)TS=D2->S; + else TS=treelist2sub_seq((D1->S),ATOI_ACTION(1)); + treelist2frame (D1->S, TS); + myexit (EXIT_SUCCESS); + } + + else if ( strm (action, "treelist2seq")) + { + D1->S=treelist2sub_seq (D1->S,ATOI_ACTION(1)); + D1->A=seq2aln(D1->S, NULL, 1); + } + else if ( strm (action, "treelist2leafgroup")) + { + treelist2leafgroup (D1->S, (D2)?D2->S:NULL, ACTION(1)); + myexit (0); + } + else if ( strm(action, "treelist2splits")) + { + if (D1->T)D1->S=add_file2file_list ((D1->T)->file, NULL); + treelist2splits (D1->S, (D2)?D2->S:NULL); + } + + else if ( strm(action, "treelist2dmat")) + { + treelist2dmat (D1->S); + } + else if ( strm(action, "tree2node") ) + { + print_node_list ( D1->T,(DST)?DST->S:NULL); + myexit (EXIT_SUCCESS); + } + else if ( strm(action, "tree_cmp_list") ) + { + D1->T=main_compare_trees_list ( D1->T, D2->S, stdout); + } + else if ( strm(action, "tree_cmp") || strm (action, "tree_compare")) + { + D1->T=main_compare_trees ( D1->T, D2->T, stdout); + } + else if ( strm (action, "tree_scan")) + { + D1->T=tree_scan (D1->A, D2->T, ACTION(1), ACTION(2)); + } + else if ( strm (action, "split_cmp")) + { + main_compare_splits (D1->T, D2->T, ACTION(1), stdout); + } + + else if ( strm(action, "node_sort")) + { + node_sort ( action_list[1], D1->T); + myexit (EXIT_SUCCESS); + } + + else if ( strm ( action, "avg_bootstrap")) + { + display_avg_bootstrap (D1->T); + myexit (EXIT_SUCCESS); + } + else if ( strm (action, "genepred2acc")) + { + //D2->S=reference + //D1->S=prediction + vfree (display_accuracy (genepred_seq2accuracy_counts (D2->S, D1->S, NULL),stderr)); + myexit (EXIT_SUCCESS); + } + else if ( strm (action, "tree_cog_cmp")) + { + main_compare_cog_tree (D1->T,action_list[1]); + myexit (EXIT_SUCCESS); + } + else if ( strm (action, "tree_aln_cmp")) + { + main_compare_aln_tree (D1->T, D2->A, stdout); + myexit (EXIT_SUCCESS); + } + else if ( strm(action, "change_bootstrap")) + { + D1->T=reset_boot_tree ( D1->T, (n_actions>=2)?atoi(action_list[1]):0); + } + else if ( strm(action, "change_distances")) + { + D1->T=reset_dist_tree ( D1->T, (n_actions>=2)?atof(action_list[1]):0.00); + } + + else if ( strm(action, "aln2tree")) + { + D1->T=tree_compute (D1->A, n_actions-1, action_list+1); + } + else if ( strm(action, "similarities2tree")) + { + D1->T=similarities_file2tree (ACTION(1)); + } + + else if ( strm(action, "original_seqnos")) + { + (D1->A)->output_res_num=2; + } + + else if ( strm (action, "aln2pred")) + { + aln2pred (D1->A, D2->A, ACTION (1)); + myexit (EXIT_SUCCESS); + } + else if ( strm(action, "evaluate")) + { + Alignment *A; + + + DST->A=copy_aln (D1->A, NULL); + DST->S=aln2seq(DST->A); + if (n_actions>1 && strm ( action_list[1], "categories")) + { + CL=declare_constraint_list ( DST->S,NULL, NULL, 0,NULL, read_matrice("pam250mt")); + DST->A= main_coffee_evaluate_output(DST->A, CL, "categories"); + } + else if (n_actions>1 && strm ( action_list[1], "sar")) + { + CL=declare_constraint_list ( DST->S,NULL, NULL, 0,NULL, read_matrice("pam250mt")); + DST->A= main_coffee_evaluate_output(DST->A, CL, "sar"); + } + else if (n_actions>1 && strstr ( action_list[1], "boxshade")) + { + char color_mode[1000]; + sprintf (color_mode,"boxshade_%d", atoi(ACTION2(2,"30"))); + CL=declare_constraint_list ( DST->S,NULL, NULL, 0,NULL, read_matrice("pam250mt")); + DST->A= main_coffee_evaluate_output(DST->A, CL, color_mode); + } + else + { + CL=declare_constraint_list ( DST->S,NULL, NULL, 0,NULL, read_matrice((n_actions==1)?"pam250mt":action_list[1])); + DST->A= main_coffee_evaluate_output(DST->A, CL, "matrix"); + } + + DST->S=aln2seq ( DST->A); + + A=D1->A; + + sprintf ( A->name[A->nseq], "cons"); + sprintf ( A->seq_al[A->nseq], "%s", aln2cons_seq_mat (A, "idmat")); + + } + else if ( strm (action, "sp_evaluate")) + { + fprintf ( stdout, "SP Score: %.2f", sum_pair ((DST && DST->A)?DST->A:D1->A,ACTION(1),atoi(ACTION2(2,"0")),atoi(ACTION2(3,"0")))); + myexit (EXIT_SUCCESS); + } + else if ( strm (action, "lat_evaluate")) + { + float score; + score=lat_sum_pair ( D1->A, action_list[1]); + fprintf ( stdout, "\nLAT_SCORE: %.2f", score); + myexit (EXIT_SUCCESS); + + } + else if ( strm (action, "add_scale")) + { + D1->A=aln2scale (D1->A, ACTION(1)); + } + else if ( strm (action, "RNAfold_cmp")) + { + D1->A=compare_RNA_fold (D1->A, D2->A); + } + else if ( strm (action, "aln2alifold")) + { + D1->A=aln2alifold (D1->A); + D1->S=aln2seq ( D1->A); + } + + + else if ( strm (action, "add_alifold")) + { + D1->A=add_alifold2aln (D1->A, (D2)?D2->A:NULL); + + } + else if ( strm (action, "alifold2analyze")) + { + D1->A=alifold2analyze (D1->A, (D2)?D2->A:NULL, ACTION(1)); + D1->S=aln2seq(D1->A); + } + else if ( strm (action, "aln2conservation")) + { + D1->A=aln2conservation ( D1->A, ATOI_ACTION (1), ACTION (2)); + myexit (EXIT_FAILURE); + } + else if ( strm (action, "aln2cons")) + { + char *cons_seq; + char *cons_name; + cons_name=vcalloc (100, sizeof (char)); + sprintf(cons_name, "%s", (n_actions<=2)?"Cons":action_list[2]); + cons_seq=aln2cons_seq_mat (D1->A, (n_actions==1)?"blosum62mt":action_list[1]); + free_aln (D1->A);free_sequence(D1->S, -1); + D1->S=fill_sequence_struc (1, &cons_seq, &cons_name); + /*keep the gaps*/ + (D1->S)->len[0]=strlen (cons_seq); sprintf ( (D1->S)->seq[0], "%s", cons_seq); + D1->A=seq2aln (D1->S, NULL, KEEP_GAP); + vfree (cons_name);vfree (cons_seq); + } + else if ( strm (action, "seq2filter")) + { + D1->S=seq2filter ( D1->S, atoi(action_list[1]), atoi(action_list[2])); + + } + else if ( strm (action, "aln2resindex")) + { + //-in: aln, file: ref_seq ref_res target_seq + //-in2 target sequences + aln2resindex (D1->A, (D2)?D2->A:NULL, stdout); + myexit (EXIT_SUCCESS); + } + else if (strm(action, "keep_name")) + { + RAD->keep_name=1-RAD->keep_name; + } + else if (strm(action, "use_consensus") ||strm(action, "use_cons") ) + { + RAD->use_consensus=1-RAD->use_consensus; + } + else if ( strm(action, "ungap")) + { + seq2aln (D1->S, D1->A, 1); + } + else if ( strm2(action, "rmgap", "rm_gap")) + { + + ungap_aln_n (D1->A, (n_actions==1)?100:atoi(action_list[1])); + //free_sequence ( D1->S, (D1->S)->nseq); + D1->S=aln2seq ( D1->A); + (D1->A)->S=D1->S; + } + else if ( strm(action, "rmgap_col")) + { + D1->A=remove_gap_column ( D1->A,action_list[1]); + } + else if ( strm(action,"random")) + { + + D1->A= make_random_aln(NULL,(n_actions==1)?1:atoi(action_list[1]),(n_actions==2)?100:atoi(action_list[2]),"acdefghiklmnpqrstvwy"); + + D1->S=aln2seq ( D1->A); + } + + else if ( strm(action, "landscape")) + { + + set_landscape_msa ((n_actions==1)?0:atoi(action_list[1])); + } + else if ( strm(action, "clean_maln")) + { + if ( !DST) + { + fprintf ( stderr,"\n[You Need an evaluation File: Change the output format][FATAL:%s]\n", PROGRAM); + myexit(EXIT_FAILURE); + } + (DST->A)=aln2number (DST->A); + D1->A=clean_maln(D1->A, DST->A,(n_actions==1)?1:atoi(action_list[1]),(n_actions==1)?1:atoi(action_list[2])); + } + else if ( strm (action, "extract")) + { + + COOR=get_pir_sequence (RAD->coor_file, NULL); + D1->S=extract_sub_seq ( COOR, D1->S); + free_aln (D1->A); + D1->A=declare_Alignment(D1->S); + seq2aln (D1->S, D1->A, RAD->rm_gap); + free_sequence (COOR, COOR->nseq); + } + else if ( strm (action, "reorder_column")) + { + + + + Alignment *RO1, *RO2; + Sequence *OUT_S; + int s; + + RO1=rotate_aln (D1->A,NULL); + if (ACTION(1) && strm (ACTION(1), "tree")) + { + D1->T=tree_compute (RO1,n_actions-2, action_list+2); + OUT_S=tree2seq(D1->T, NULL); + RO1=reorder_aln(RO1, OUT_S->name, OUT_S->nseq); + } + else if ( ACTION(1) && strm (ACTION(1), "random")) + { + RO1=reorder_aln ( RO1, NULL, RO1->nseq); + } + + RO2=rotate_aln (RO1, NULL); + for (s=0; s< RO2->nseq; s++) + sprintf ( RO2->name[s], "%s", (D1->A)->name[s]); + free_aln (RO1); + free_aln (D1->A); + D1->A=RO2; + D1->S=aln2seq(D1->A); + } + + else if ( strm (action, "reorder")) + { + + if ( n_actions==2 && strm (action_list[1], "random")) + { + D1->A=reorder_aln ( D1->A, NULL, (D1->A)->nseq); + } + else if (n_actions==2 && strm (action_list[1], "invert")) + { + char **nname; + int z, y; + + nname=declare_char ((D1->A)->nseq, 100); + for ( z=0,y=(D1->A)->nseq-1; z<(D1->A)->nseq; z++, y--) + { + sprintf (nname[z], "%s",(D1->A)->name[y]); + } + + D1->A=reorder_aln ( D1->A, nname, (D1->A)->nseq); + free_char (nname, -1); + } + else if (n_actions==2 && strm (action_list[1], "scramble")) + { + D1->A=aln2scramble_seq(D1->A); + } + + else if ( n_actions==2 && strm (action_list[1], "tree")) + { + + OUT_S=tree2seq (D2->T, NULL); + D1->A=reorder_aln(D1->A, OUT_S->name, OUT_S->nseq); + free_sequence (D1->S,(D1->S)->nseq); + D1->S=aln2seq (D1->A); + } + else + { + (D2->A)->S=aln2seq (D2->A); + (D1->A)->S=aln2seq (D1->A); + OUT_S=trim_aln_seq_name(D2->A, D1->A); + D1->A=reorder_aln(D1->A, OUT_S->name, OUT_S->nseq); + free_sequence (D1->S,(D1->S)->nseq); + D1->S=aln2seq (D1->A); + } + } + else if ( strm (action, "aln2replicate")) + { + aln2N_replicate (D1->A, ACTION(1), ACTION(2)); + } + else if ( strm (action, "paralogous_cat")) + { + D1->A=orthologous_concatenate_aln (D1->A,D2->S, ACTION (1)); + } + + else if ( strm (action, "cat_aln")) + { + /*D1->A=aln_cat ( D1->A, D2 ->A);*/ + + if (D2 && D2->A && !ACTION(1)) + D1->A=concatenate_aln (D1->A, D2->A, ACTION(1)); + else if (ACTION(1) && is_aln(ACTION(1))) + { + Alignment *B; + int n=1; + + while (ACTION(n)) + { + + B=main_read_aln (ACTION(n), NULL); + D1->A=concatenate_aln (D1->A, B, NULL); + n++; + } + D1->S=aln2seq(D1->A); + } + + else + { + Alignment *A, *B; + + A=main_read_aln ((D1->A)->name[0], NULL); + + for ( a=1; a<(D1->A)->nseq; a++) + { + B=main_read_aln ((D1->A)->name[a], NULL); + A=concatenate_aln (A, B, ACTION(1)); + + } + D1->A=A; + D1->S=aln2seq(D1->A); + } + } + + else if ( strm ( action, "msalist2cat_pwaln")) + { + int a, b, c; + int sim, min, max; + + if (n_actions!=3) + { + min=0; + max=100; + } + else + { + min=atoi(action_list[1]); + max=atoi(action_list[2]); + } + + fprintf ( stdout, ">A\n"); + for (a=0;a<(D1->S)->nseq; a++) + { + Alignment *A; + HERE ("process %s", (D1->S)->name[a]); + A=main_read_aln((D1->S)->name[a],NULL); + for (b=0; bnseq-1; b++) + { + for ( c=b+1; cnseq; c++) + { + sim=get_seq_sim (A->seq_al[b], A->seq_al[c], "-", ""); + if (sim>=min && sim<=max)fprintf (stdout, "xxx%s", A->seq_al[b]); + } + } + free_aln (A); + } + fprintf ( stdout, "\n>B\n"); + for (a=0;a<(D1->S)->nseq; a++) + { + Alignment *A; + HERE ("process %s", (D1->S)->name[a]); + A=main_read_aln((D1->S)->name[a],NULL); + for (b=0; bnseq-1; b++) + { + for ( c=b+1; cnseq; c++) + { + sim=get_seq_sim (A->seq_al[b], A->seq_al[c], "-", ""); + if (sim>=min && sim<=max)fprintf (stdout, "xxx%s", A->seq_al[c]); + } + } + free_aln (A); + } + + fprintf ( stdout, "\n"); + myexit (EXIT_SUCCESS); + } + + else if ( strm (action, "collapse_tree")) + { + D1->T=tree2collapsed_tree (D1->T, n_actions-1, action_list+1); + } + else if ( strm (action, "collapse_aln")) + { + D1->A=aln2collapsed_aln (D1->A, n_actions-1, action_list+1); + } + else if ( strm (action, "extract_aln")) + { + D1->A=aln2sub_aln_file (D1->A, n_actions-1, action_list+1); + myexit (EXIT_SUCCESS); + } + + + + else if ( strm (action, "remove_aa")) + { + int pos,len, n; + pos=atoi(action_list[1]); + len=atoi(action_list[2]); + n=atoi (action_list[3]); + if ( atoi (action_list[4])==1)len=-len; + if (pos && n>1) + { + fprintf ( stderr, "\nWARNING: rm_aa, position (pos) and iteration number (n) simulatneously defined. Iteration number reset to 1 [%s]\n", PROGRAM); + n=1; + } + for ( a=0; a< n; a++) + D1->A=probabilistic_rm_aa (D1->A, pos, len); + } + else if ( strm (action, "remove_nuc")) + { + int pos; + pos=atoi(action_list[1]); + + if ( pos>3 || pos<1) + printf_exit (EXIT_FAILURE, stderr, "Remove_nuc: indicate a number between 1 and 3\n"); + + pos--; + for ( c=0,a=0; a<(D1->A)->len_aln; a++, c++) + { + if (c==3)c=0; + for (b=0; b<(D1->A)->nseq; b++) + { + if (c==pos) + { + (D1->A)->seq_al[b][a]='-'; + } + } + } + + D1->S=aln2seq (D1->A); + } + + else if (strm ( action, "conserved_positions")) + { + Alignment *A; + int a, b, c; + int *cache=NULL; + + + A=D1->A; + for ( a=0; a< A->nseq && !cache; a++) + { + if ( strm (action_list[1], A->name[a])) + { + cache=vcalloc ( A->len_aln+1, sizeof (int)); + for ( c=0,b=0; blen_aln; b++) + { + if ( is_gap (A->seq_al[a][b]))cache[b]=-1; + else cache[b]=++c; + } + } + } + + for ( a=0; a< A->len_aln; a++) + { + r1=A->seq_al[0][a]; + if ( is_gap(r1))continue; + for ( c=0,b=0; bnseq; b++) + { + r2=A->seq_al[b][a]; + c+=(r1==r2)?1:0; + } + if ( (c*100)/A->nseq>=atoi(action_list[2])) + fprintf ( stdout, "COL: %d Res: %c %s %d\n", a+1, r1, action_list[1], cache[a]+atoi(action_list[3])); + } + myexit (EXIT_FAILURE); + } + else if (strm ( action, "extract_block") ) + { + + BUF=copy_aln (D1->A, NULL); + if ( check_file_exists(action_list[1])) + BUF=extract_aln3(BUF,action_list[1]); + else + BUF=extract_aln2(BUF,atoi(action_list[2]),atoi(action_list[3]),action_list[1]); + D1->A=copy_aln (BUF,D1->A); + + } + else if ( strm ( action, "extract_pos_list")) + { + D1->A=alnpos_list2block (D1->A, n_actions-1, action_list+1); + } + else if ( strm ( action, "seq2msa")) + { + D1->A=simple_progressive_aln ( D1->S, NULL, NULL, action_list[1]); + } + else if ( strm ( action, "realign_block") ) + { + D1->A=realign_block ( D1->A, atoi (action_list[1]), atoi (action_list[2]), (n_actions==4)?action_list[3]:NULL); + } + else if ( strm (action, "extract_seq")) + { + int is_file; + if ( check_file_exists (action_list[1])&& format_is_fasta (action_list[1])) + { + is_file=1; + BUFS=main_read_seq (action_list[1]); + action_list=BUFS->name; + n_actions=BUFS->nseq; + } + else + { + is_file=0; + action_list++; + n_actions--; + } + + for ( a=0; a< n_actions;) + { + s=action_list[a]; + + if ( n_actions==1 || is_file==1) + { + start=1; + end=0; + a+=1; + } + else + { + + start=(strm2 (s,"#","*"))?1:(atoi(action_list[a+1])); + end= (strm2 (action_list[a+2],"#","*"))?0:(atoi(action_list[a+2])); + a+=3; + } + + if ( strm2 (s, "#", "*")) + { + OUT_S=extract_one_seq((D1->A)->name[0],start, end, D1->A, RAD->keep_name); + for (b=1; b< (D1->A)->nseq; b++) + { + NS=extract_one_seq((D1->A)->name[b],start, end, D1->A, RAD->keep_name); + if (count_n_res_in_array(NS->seq[0], -1)) + OUT_S=add_sequence ( NS,OUT_S, 0); + } + } + else + { + if ( a==1)OUT_S=extract_one_seq(s,start, end, D1->A, RAD->keep_name); + else + { + NS=extract_one_seq(s,start, end, D1->A, RAD->keep_name); + OUT_S=add_sequence ( NS,OUT_S, 0); + } + } + } + D1->S=OUT_S; + free_aln (D1->A); + D1->A=declare_Alignment(D1->S); + seq2aln (D1->S, D1->A, RAD->rm_gap); + } + + else if ( strm (action, "extract_seq_list")) + { + if ( check_file_exists (action_list[1]) && format_is_fasta (action_list[1])) + { + + BUFS=main_read_seq (action_list[1]); + action_list=BUFS->name; + n_actions=BUFS->nseq; + } + else + { + action_list++; + n_actions--; + } + + for ( a=0; a< n_actions;a++) + { + + NS=extract_one_seq(action_list[a],1,0, D1->A, KEEP_NAME); + OUT_S=add_sequence ( NS,OUT_S, 0); + + } + + D1->S=OUT_S; + free_aln (D1->A); + D1->A=declare_Alignment(D1->S); + seq2aln (D1->S, D1->A, RAD->rm_gap); + } + else if ( strm (action, "remove_seq") || strm (action, "rm_seq")) + { + char *buf; + char **list; + int n; + int l; + + list=declare_char ((D1->S)->nseq, 200); + + buf=vcalloc ((D1->S)->max_len+1, sizeof (char)); + for ( n=0,a=0; a< (D1->A)->nseq; a++) + { + + sprintf (buf, "%s", (D1->S)->seq[a]); + ungap (buf); + l=strlen(buf); + + for (c=1, b=1; b< n_actions; b++) + { + if ( strm (action_list[b], (D1->S)->name[a])){(D1->S)->seq[a]=NULL;break;} + else if ( strm (action_list[b], "empty") && l==0) + { + fprintf ( stderr, "WARNING: Sequence %s does not contain any residue: automatically removed from the set [WARNING:%s]\n",(D1->S)->name[a], PROGRAM); + (D1->S)->seq[a]=NULL;break; + } + else if ( strm (action_list[b], "unique")) + { + if ( name_is_in_list ((D1->S)->name[a], list,n, 100)!=-1) + { + (D1->S)->seq[a]=NULL;break; + } + else + { + sprintf ( list[n++], "%s", (D1->S)->name[a]); + } + } + } + } + D1->S=duplicate_sequence (D1->S); + free_aln (D1->A); + free_char ( list, -1); + D1->A=declare_Alignment(D1->S); + seq2aln (D1->S, D1->A, RAD->rm_gap); + } + + else if ( strm (action, "aln2overaln")|| strm (action,"overaln_param")) + { + //mode (lower|number|uanlign) Penalty (0-100) Thresold (0-9) + int p1,p2,p3,f, t; + char *s; + int eb=0; + char clean_mode[100]; + OveralnP *F; + + F=vcalloc (1, sizeof (OveralnP)); + if ( D2 && D2->A) + { + D1->A=mark_exon_boundaries (D1->A, D2->A); + eb=1; + } + else if ( (s=get_string_variable ("exon_boundaries"))) + { + Sequence *S; + Alignment *EB; + EB=seq2aln(S=main_read_seq(s),NULL, 0); + D1->A=mark_exon_boundaries (D1->A, EB); + free_sequence (S, S->nseq); free_aln (EB); + eb=1; + } + + + if (ACTION(1)==NULL)sprintf (F->mode, "lower"); + else if (strstr (ACTION(1), "h")) + { + fprintf ( stdout, "aln2unalign lower|number|unalign|uanlign2 F P1 P2 P3 T\n"); + myexit (EXIT_SUCCESS); + } + else sprintf (F->mode, "%s", ACTION(1)); + + F->t=ATOI_ACTION(2); + F->f=ATOI_ACTION(3); + F->p1=ATOI_ACTION(4); + F->p2=ATOI_ACTION(5); + F->p3=ATOI_ACTION(6); + F->p3=ATOI_ACTION(7); + + if (int_variable_isset ("overaln_target"))f=get_int_variable ("overaln_target"); + if (int_variable_isset ("overaln_threshold"))t=get_int_variable ("overaln_threshold"); + if (eb)sprintf (F->model, "fsa2"); + else sprintf (F->model, "fsa1"); + + D1->A=aln2clean_pw_aln (D1->A, F); + + } + else if ( strm (action, "unalign_groups")) + { + //unalign everything in lower case + unalign_aln_2 (D1->A, NULL, 0); + } + else if ( strm (action,"aln2unalign")) + { + Alignment *SA; + Sequence *SS; + SA=copy_aln (D1->A, NULL); + SS=aln2seq(SA); + + thread_seq_struc2aln (SA, SS); + D1->A=unalign_aln (D1->A,SA, ATOI_ACTION(1)); + D1->S=aln2seq ( D1->A); + } + else if ( strm (action, "clean_cdna")) + { + Alignment *A; + A=D1->A; + for (a=0; a< A->nseq; a++) + { + char *d, *buf, f; + + d=A->seq_al[a]; + f=get_longest_frame (d, 3); + buf=vcalloc ( strlen (d)+1, sizeof (char)); + sprintf (buf, "%s", d+f); + sprintf (d, "%s", buf); + vfree (buf); + } + } + else if ( strm (action, "clean_cdna2")) + { + D1->A=clean_cdna_aln ( D1->A); + free_sequence ( D1->S, (D1->S)->nseq); + D1->S=aln2seq ( D1->A); + } + else if ( strm (action, "aln2short_aln")) + { + D1->A=aln2short_aln (D1->A, action_list[1], action_list[2], atoi(action_list[3])); + free_sequence ( D1->S, (D1->S)->nseq); + D1->S=aln2seq ( D1->A); + } + else if ( strm ( action, "complement")) + { + D1->A=complement_aln (D1->A); + free_sequence ( D1->S, (D1->S)->nseq); + D1->S=aln2seq ( D1->A); + } + else if ( strm ( action, "extend")) + { + extend_seqaln( NULL,D1->A); + free_sequence ( D1->S, (D1->S)->nseq); + D1->S=aln2seq ( D1->A); + } + else if ( strm ( action, "unextend")) + { + unextend_seqaln( NULL,D1->A); + free_sequence ( D1->S, (D1->S)->nseq); + D1->S=aln2seq ( D1->A); + } + else if ( strm ( action, "translate")) + { + D1->A=translate_dna_aln( D1->A,(n_actions==1)?0:atoi(action_list[1])); + free_sequence ( D1->S, (D1->S)->nseq); + D1->S=aln2seq ( D1->A); + } + else if (strm2 ( action, "back_translate","backtranslate")) + { + D1->A=back_translate_dna_aln( D1->A); + free_sequence ( D1->S, (D1->S)->nseq); + D1->S=aln2seq ( D1->A); + } + else if (strm ( action, "rotate")) + { + D1->A=rotate_aln( D1->A, action_list[1]); + free_sequence ( D1->S, (D1->S)->nseq); + D1->S=aln2seq ( D1->A); + } + else if (strm ( action, "invert")) + { + D1->A=invert_aln( D1->A); + free_sequence ( D1->S, (D1->S)->nseq); + D1->S=aln2seq ( D1->A); + } + else if (strm ( action, "test_dna2gene")) + { + testdna2gene ((D1->S)->seq[0]); + } + else if (strm ( action, "code_dna_aln")) + { + D1->A=code_dna_aln( D1->A); + free_sequence ( D1->S, (D1->S)->nseq); + D1->S=aln2seq ( D1->A); + } + + else if ( strm ( action, "mutate")) + { + D1->A=mutate_aln( D1->A,(n_actions==1)?"0":action_list[1]); + free_sequence ( D1->S, (D1->S)->nseq); + D1->S=aln2seq (D1->A); + } + else if ( strm ( action, "thread_profile_on_msa")) + { + (D1->A)->S=NULL; + D1->A=thread_profile_files2aln (D1->A, action_list[1], NULL); + D1->S=aln2seq(D1->A); + } + else if ( strm ( action, "thread_dna_on_prot_aln")) + { + D1->A=thread_dnaseq_on_prot_aln (D1->S, D2->A); + free_sequence (D1->S,(D1->S)->nseq); + D1->S=aln2seq (D1->A); + } + else if ( strm ( action, "thread_struc_on_aln")) + { + thread_seq_struc2aln ( D2->A, D1->S); + D1->A=copy_aln(D2->A, D1->A); + free_sequence ( D1->S, (D1->S)->nseq); + D1->S=aln2seq (D1->A); + } + else if ( strm (action, "sim_filter")) + { + D1->A=sim_filter (D1->A, action_list[1], ACTION (2)); + free_sequence (D1->S,(D1->S)->nseq); + D1->S=aln2seq (D1->A); + } + else if ( strm (action, "seq2blast")) + { + D1->A=seq2blast (D1->S); + free_sequence (D1->S,(D1->S)->nseq); + D1->S=aln2seq (D1->A); + } + + else if ( strm (action, "trim")) + { + D1->A=simple_trimseq (D1->A,(D2)?D2->A:NULL, action_list[1], ACTION (2), NULL); + + free_sequence (D1->S,(D1->S)->nseq); + D1->S=aln2seq (D1->A); + } + + else if (strm ( action, "trimTC")) + { + value=(n_actions==1)?10:atoi(action_list[1]); + + D1->A=tc_trimseq(D1->A,D1->S,action_list[1]); + free_sequence (D1->S,(D1->S)->nseq); + D1->S=aln2seq (D1->A); + } + else if (strm ( action, "trimTC2")) + { + char *group_file; + Alignment *B=NULL; + char trim_mode[100]; + if ( n_actions==1 || !(strm (action_list[1], "NSEQ") ||strm (action_list[1], "MINID")) ) + { + fprintf ( stderr, "\nTrimTC2 ()\n"); + myexit (EXIT_FAILURE); + } + sprintf (trim_mode, "%s", action_list[1]);action_list+=2; n_actions-=2; + + if ( strm ( trim_mode, "NSEQ")) + { + group_file=tree2Ngroup( (D1)?D1->A:NULL, (D2)?D2->T:NULL, atoi (action_list[0]), vtmpnam(NULL), (n_actions==1)?"idmat":action_list[1]); + } + else + { + group_file=tree2Ngroup( (D1)?D1->A:NULL, (D2)?D2->T:NULL, -1*atoi (action_list[0]), vtmpnam(NULL), (n_actions==1)?"idmat":action_list[1]); + } + + B=copy_aln (D1->A, B); + B=aln2sub_aln_file (B,1,&group_file); + B=aln2sub_seq (B, 1, &group_file); + D1->A=extract_sub_aln2 (D1->A, B->nseq, B->name); + } + else if ( strm (action, "chain")) + { + D1->A=seq2seq_chain (D1->A,D2->A, ACTION(2)); + } + + + else if (strm ( action, "master_trim")) + { + value=(n_actions==1)?10:atoi(action_list[1]); + + D1->A=master_trimseq(D1->A,D1->S,action_list[1]); + free_sequence (D1->S,(D1->S)->nseq); + D1->S=aln2seq (D1->A); + } + else if ( strm (action, "force_aln")) + { + char ***rlist=NULL; + int count=0; + + if ( n_actions==2) + { + if (!is_lib_02(action_list[1])) + { + fprintf ( stderr, "\nERROR: force_aln requires files in TC_LIB_FORMAT_02 [FATAL:%s]", PROGRAM); + myexit (EXIT_FAILURE); + } + else + rlist=file2list (action_list[1], " "); + } + else + { + rlist=declare_arrayN(3, sizeof (char),3,7, 10); + + strcat (rlist[1][1],action_list[1]);strcat (rlist[1][3],action_list[2]); + strcat (rlist[1][4],action_list[3]);strcat (rlist[1][6],action_list[4]); + sprintf ( rlist[2][0], "-1"); + } + count=1; + while (rlist[count] && atoi(rlist[count][0])!=-1) + { + char st1[100], st2[100], st3[100], st4[100]; + + sprintf ( st1, "%s", rlist[count][1]);sprintf ( st2, "%s", rlist[count][3]); + sprintf ( st3, "%s", rlist[count][4]);sprintf ( st4, "%s", rlist[count][6]); + fprintf ( stderr, "\nFORCE: %s %s %s %s", st1, st2, st3, st4); + + if (is_number (st1))s1=atoi (st1)-1; + else s1=name_is_in_list (st1,(D1->A)->name, (D1->A)->nseq, 100); + if ( s1<0 || s1>= (D1->A)->nseq)crash ("wrong sequence index"); + r1=atoi (st2)-1; + + if (is_number (st3))s2=atoi (st3)-1; + else s2=name_is_in_list (st3,(D1->A)->name, (D1->A)->nseq, 100); + if ( s2<0 || s2>= (D1->A)->nseq)crash ("wrong sequence index"); + r2=atoi (st4)-1; + + (D1->A)=add_constraint2aln ((D1->A), s1, r1, s2, r2); + count++; + } + fprintf ( stderr, "\n"); + free_arrayN((void*)rlist,3); + } + + else if (strm ( action, "grep")) + { + D1->A=grep_seq (D1->A, ACTION(1),ACTION(2), ACTION(3)); + if (D1->A==NULL) myexit (EXIT_SUCCESS); + else D1->S=aln2seq (D1->A); + } + + else if (strm (action, "find")) + { + int r, l; + char *search_string; + + search_string=vcalloc ( 30, sizeof (char)); + if ( strm (action_list[1], "lower"))sprintf ( search_string, "abcdefghijklmnopqrstuvwxyz"); + else if ( strm ( action_list[1], "upper"))sprintf ( search_string, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + else + { + vfree (search_string);search_string=vcalloc ( strlen (action_list[1])+1, sizeof (char)); + sprintf (search_string, "%s", action_list[1]); + } + + for (a=0; a<(D1->A)->nseq; a++) + for ( l=0,b=0; b< (D1->A)->len_aln; b++) + { + r=(D1->A)->seq_al[a][b]; + l+=!is_gap(r); + if ( r!='\0' && strrchr (search_string, r)) + { + /*fprintf ( stdout, "%-15s res %c alnpos %4d seqpos %4d\n", (D1->A)->name[a], r, b+1, l);*/ + fprintf ( stdout, "%s %d %d\n", (D1->A)->name[a], l, l+1); + } + } + myexit (EXIT_SUCCESS); + } + else if ( strm (action, "merge_annotation")) + { + D1->A=merge_annotation (D1->A, DST?DST->A:NULL, ACTION(1)); + D1->S=aln2seq (D1->A); + } + else if ( strm (action, "color_residue")) + { + int i; + Alignment *A; + A=D1->A; + + DST->A=copy_aln (D1->A, NULL); + DST->S=aln2seq (DST->A); + for (a=0; a< (DST->S)->nseq; a++)ungap ((DST->S)->seq[a]); + + if (n_actions>2) + { + for (a=1; aA)->name, (D1->A)->nseq, 100); + if (i!=-1) + { + (DST->S)->seq[i][atoi(action_list[a+1])-1]='0'+atoi(action_list[a+2])-1; + } + else fprintf (stderr, "\nWARNING: Could not find Sequence %s", action_list[a]); + } + } + else + { + char name[1000]; + int pos, val; + FILE *fp; + + fp=vfopen (action_list[1], "r"); + while (fscanf (fp, "%s %d %d\n", name, &pos, &val)==3) + { + + i=name_is_in_list(name, (D1->A)->name, (D1->A)->nseq, 100); + if (i!=-1)(DST->S)->seq[i][pos-1]='0'+val; + else fprintf (stderr, "\nWARNING: Could not find Sequence %s", action_list[a]); + } + vfclose (fp); + } + DST->A=seq2aln (DST->S, NULL, 1); + } + else if ( strm (action, "edit_residue")) + { + FILE *fp; + int i, pos; + int **p; + char mod[100], name[100]; + Alignment *A; + + A=D1->A; + + p=aln2inv_pos (A); + if (n_actions>2) + { + for (a=1; aA)->name, (D1->A)->nseq, 100); + if (i!=-1) + { + pos=atoi(action_list[a+1]); + + pos=p[i][pos]-1; + sprintf (mod, "%s", action_list[a+2]); + if ( strm (mod, "upper"))(D1->A)->seq_al[i][pos]=toupper((D1->A)->seq_al[i][pos]); + else if ( strm (mod, "lower"))(D1->A)->seq_al[i][pos]=tolower((D1->A)->seq_al[i][pos]); + else (D1->A)->seq_al[i][pos]=mod[0]; + } + else fprintf (stderr, "\nWARNING: Could not find Sequence %s", action_list[a]); + + } + } + else + { + fp=vfopen (action_list[1], "r"); + while (fscanf (fp, "%s %d %s\n", name, &pos, mod)==3) + { + + i=name_is_in_list(name, (D1->A)->name, (D1->A)->nseq, 100); + if (i!=-1) + { + pos=p[i][pos]-1; + if ( strm (mod, "upper"))(D1->A)->seq_al[i][pos]=toupper(A->seq_al[i][pos]); + else if ( strm (mod, "lower"))A->seq_al[i][pos]=tolower(A->seq_al[i][pos]); + else A->seq_al[i][pos]=mod[0]; + } + else fprintf(stderr, "\nWARNING: Could not find Sequence %s", action_list[1]); + } + vfclose (fp); + } + D1->S=aln2seq (D1->A); + } + else if ( strm (action, "clean_flag")) + { + clean_flag=1-clean_flag; + } + else if ( strm (action, "aln2case")) + { + D1->A=aln2case_aln (D1->A, ACTION(1), ACTION(2)); + D1->S=aln2seq(D1->A); + } + + else if ( strm5 (action, "convert","upper","lower", "keep", "switchcase")) + { + b=1; + + if ( n_actions>1 && is_number (action_list[b])) + { + lower_value=upper_value=atoi(action_list[b++]); + } + else if ( n_actions>1 && strm (action_list[b], "gap")) + { + DST=vcalloc (1,sizeof(Sequence_data_struc)); + DST->A=aln2gap_cache (D1->A,0); + lower_value=0; + upper_value=0; + b++; + } + else if (n_actions>1 && action_list[b] && action_list[b][0]=='[') + + { + lower_value=atoi(strtok (action_list[b]+1, "-[]")); + upper_value=atoi(strtok (NULL, "-[]")); + + b++; + } + else + { + lower_value=upper_value=-1; + } + + if ( n_actions >b ||strm (action, "keep") ) + { + if ( !RAD->symbol_list)RAD->symbol_list=declare_char (STRING, STRING); + RAD->n_symbol=0; + if ( strm (action, "keep") )sprintf ( RAD->symbol_list[RAD->n_symbol++], "#-"); + else + { + for (a=b; a< n_actions; a++) + { + sprintf ( RAD->symbol_list[RAD->n_symbol], "%s", action_list[a]); + RAD->n_symbol++; + } + } + } + + for ( value=0; value<=9; value++) + { + if ( lower_value==-1)value=-1; + + if ( (value>=lower_value && value<=upper_value)|| value==-1) + { + if (strm(action,"convert")) D1->A=filter_aln_convert (D1->A, DST?DST->A:NULL,RAD->use_consensus,value,RAD->n_symbol, RAD->symbol_list); + else if (strm(action,"upper"))D1->A=filter_aln_lower_upper (D1->A, DST?DST->A:NULL,RAD->use_consensus,value); + else if (strm(action,"lower"))D1->A=filter_aln_upper_lower (D1->A, DST?DST->A:NULL,RAD->use_consensus,value); + else if (strm(action,"switchcase"))D1->A=filter_aln_switchcase (D1->A, DST?DST->A:NULL,RAD->use_consensus,value); + } + else + { + if (strm(action,"keep")) D1->A=filter_aln_convert (D1->A, DST?DST->A:NULL,RAD->use_consensus,value,RAD->n_symbol, RAD->symbol_list); + } + if (value==-1)break; + + } + + /*free_sequence (D1->S,(D1->S)->nseq);*/ + if (!D1->S)D1->S=aln2seq (D1->A); + } + else if ( strm ( action, "count_pairs")) + { + int a, b,c,v, **matrix; + Alignment *A; + matrix=declare_int (300,300); + A=D1->A; + for ( a=0; a< A->nseq-1; a++) + for (b=0; b< A->nseq; b++) + for (c=0; clen_aln; c++) + matrix[(int)A->seq_al[a][c]][(int)A->seq_al[b][c]]++; + for ( a=0; a<255; a++) + for ( b=a; b<256; b++) + { + v=matrix[a][b]+matrix[b][a]; + if (v)fprintf ( stdout, "\n%c %c %d", a, b, v); + } + myexit (EXIT_SUCCESS); + } + else if ( strm (action, "count_misc")) + { + count_misc (D1->A, (!D2)?NULL:D2->A); + } + else if ( strm (action, "count")) + { + b=1; + if ( n_actions>1 && is_number (action_list[b])) + { + lower_value=upper_value=atoi(action_list[b++]); + } + else if (n_actions>1 && action_list[b] && action_list[b] && action_list[b][0]=='[') + + { + lower_value=atoi(strtok (action_list[b]+1, "-[]")); + upper_value=atoi(strtok (NULL, "-[]")); + + b++; + } + else + { + lower_value=upper_value=-1; + } + if ( n_actions >b) + { + if ( !RAD->symbol_list)RAD->symbol_list=declare_char (STRING, STRING); + RAD->n_symbol=0; + for (a=b; a< n_actions; a++) + { + sprintf ( RAD->symbol_list[RAD->n_symbol], "%s", action_list[a]); + RAD->n_symbol++; + } + } + for ( value=lower_value; value<=upper_value; value++) + { + count_table=count_in_aln (D1->A, DST?DST->A:NULL,value,RAD->n_symbol, RAD->symbol_list, count_table); + } + for ( a=0; an_symbol; a++) + { + fprintf ( stdout, "%s %d\n", RAD->symbol_list[a], count_table[a]); + } + free_sequence (D1->S,(D1->S)->nseq); + D1->S=aln2seq (D1->A); + vfree(count_table); + myexit(EXIT_SUCCESS); + } + else if ( strm (action, "species_weight")) + { + seq_weight2species_weight (D1->A, D2->S); + exit (0); + } + else if ( strm (action, "aln2voronoi")) + { + aln2voronoi_weights (D1->A); + + } + else if ( strm (action, "msa_weight")) + { + int random_value; + char command [LONG_STRING]; + char aln_name[FILENAMELEN]; + char tree_name[FILENAMELEN]; + char dist_matrix_name[FILENAMELEN]; + char weight_name[FILENAMELEN]; + char method_4_msa_weights[1000]; + + if ( n_actions==1) + { + fprintf ( stderr, "\nError: msa_weight requires a weight_method"); + } + + sprintf ( method_4_msa_weights, "%s", (get_env_variable ("METHOD_4_MSA_WEIGHTS",NO_REPORT))?get_env_variable ("METHOD_4_MSA_WEIGHTS",NO_REPORT):METHOD_4_MSA_WEIGHTS); + + /*1 Computation of the tree and the distance matrix*/ + random_value=addrand ((unsigned long) 100000)+1; + sprintf (aln_name, "%d.aln", random_value); + sprintf (tree_name, "%d.ph", random_value); + sprintf (dist_matrix_name, "%d.dst", random_value); + sprintf (weight_name, "%d.weight", random_value); + output_fasta_aln (aln_name, D1->A); + + sprintf ( command, "clustalw -infile=%s -tree -outputtree=dist %s", aln_name, TO_NULL_DEVICE); + my_system ( command); + sprintf ( command, "%s -method %s -aln %s -tree %s -dmatrix %s -weightfile %s %s",method_4_msa_weights, action_list[1],aln_name, tree_name, dist_matrix_name,weight_name, TO_NULL_DEVICE); + my_system ( command); + + (D1->A)->S=aln2seq (D1->A); + ((D1->A)->S)->W=read_seq_weight ( (D1->A)->name, (D1->A)->nseq,weight_name); + vremove (weight_name); + vremove (aln_name); + vremove (tree_name); + vremove (dist_matrix_name); + } + else if ( strm (action, "pavie_seq2random_seq")) + { + D1->S=pavie_seq2random_seq (D1->S, action_list[1]); + D1->A=seq2aln (D1->S,NULL,1); + } + else if ( strm ( action, "pavie_seq2noisy_seq")) + { + /* ()*/ + + D1->S=pavie_seq2noisy_seq (D1->S, atoi(action_list[1]),ACTION(2)); + D1->A=seq2aln (D1->S,NULL,1); + } + else if ( strm (action, "pavie_seq2pavie_mat")) + { + + pavie_seq2trained_pavie_mat ( D1->S, (n_actions==2)?action_list[1]:NULL); + myexit (EXIT_SUCCESS); + } + else if ( strm (action, "pavie_seq2pavie_aln")) + { + + pavie_seq2pavie_aln ( D1->S, action_list[1], ACTION(2)); + myexit (EXIT_SUCCESS); + } + else if ( strm (action, "pavie_seq2pavie_dm")) + { + if (strstr (ACTION2(2,""), "_MSA_")) + D1->S=aln2seq_main(D1->A, KEEP_GAP); + + + pavie_seq2pavie_aln ( D1->S, action_list[1],(n_actions==3)?action_list[2]:"_MATDIST_"); + myexit (EXIT_SUCCESS); + } + else if ( strm (action, "pavie_seq2pavie_msa")) + { + D1->A=pavie_seq2pavie_msa ( D1->S, action_list[1], (n_actions==3)?action_list[2]:NULL); + } + else if ( strm (action, "pavie_seq2pavie_tree")) + { + D1->T=pavie_seq2pavie_tree ( D1->S, action_list[1], (n_actions==3)?action_list[2]:NULL); + } + else if ( strm (action, "pavie_seq2pavie_sort")) + { + D1->A=pavie_seq2pavie_sort ( D1->S, action_list[1], (n_actions==3)?action_list[2]:NULL); + } + + else if ( strm (action, "aln2mat_diaa")) + { + aln2mat_diaa (D1->S); + } + else if ( strm (action, "aln2mat")) + { + aln2mat(D1->S); + } + + else if ( strm (action, "seq2latmat")) + { + seq2latmat ( D1->S, "stdout"); + myexit (EXIT_SUCCESS); + } + else if ( strm (action , "rm_target_pdb")) + { + int i, j; + char *buf; + + for (i=0; i< (D1->A)->nseq; i++) + { + j=1;buf=(D1->A)->name[i]; + while (buf[j]!='_' && buf[j-1]!='_' && buf[j]!='\0')j++; + buf[j]='\0'; + } + } + else if ( strm ( action, "mat2cmp")) + { + double *r; + r=mat2cmp (D1->M, D2->M); + fprintf ( stdout, "\nMATRIX COMPARISON: R=%.3f R2=%.3f On %d pairs of values\n", (float)r[0], (float)r[1], (int)r[2]); + myexit (EXIT_SUCCESS); + } +//Special modes + else if ( strm ( action, "overaln_list")) + { + float *re, tre=0,sn, tsn=0, sp, tsp=0; + int p1,p2,p3, t, f; + FILE *fp; + char fname [100]; + Alignment **LA; + Alignment **LB; + + HERE ("F P1 P2 P3 T"); + + t=ATOI_ACTION(1); + f=ATOI_ACTION(2); + p1=ATOI_ACTION(3); + p2=ATOI_ACTION(4); + p3=ATOI_ACTION(5); + + + + LA=vcalloc ((D1->A)->nseq, sizeof (Alignment*)); + LB=vcalloc ((D2->A)->nseq, sizeof (Alignment*)); + for (a=0; a<(D1->A)->nseq; a++) + { + LA[a]=main_read_aln ((D1->A)->name[a], NULL); + LB[a]=main_read_aln ((D2->A)->name[a], NULL); + } + + for ( a=0; a<(D1->A)->nseq; a++) + { + Alignment *A, *B; + A=LA[a]; + B=LB[a]; + re=analyze_overaln (A, B, "_case_l_",t,f,p1,p2,p3); + fprintf (stdout, "\n%d: sn: %.2f sp: %.2f re: %.2f F: %d P: %d P2: %d T: %d",a, re[0],re[1],re[2],f, p1,p2,t); + tsn+=re[0]; + tsp+=re[1]; + tre+=re[2]; + vfree(re); + } + fprintf (stdout, "\nTOT: sn: %.2f sp: %.2f re: %.2f F: %d P: %d P2: %d T: %d", tsn/(D1->A)->nseq,tsp/(D1->A)->nseq, tre/(D1->A)->nseq,f,p1,p2,t); + + myexit (0); + } + else if ( strm ( action, "overaln_list_scan")) + { + float *re, tre=0, tsn=0, tsp; + int p1,p2, p3, t, f; + FILE *fp; + char fname [100]; + Alignment **LA; + Alignment **LB; + + if ( ACTION(1))sprintf ( fname, "%s", ACTION(1)); + else sprintf ( fname, "scan_results.txt"); + + fprintf ( stdout, "SCAN Results will be ouput in %s\n", fname); + + + LA=vcalloc ((D1->A)->nseq, sizeof (Alignment*)); + LB=vcalloc ((D2->A)->nseq, sizeof (Alignment*)); + for (a=0; a<(D1->A)->nseq; a++) + { + LA[a]=main_read_aln ((D1->A)->name[a], NULL); + LB[a]=main_read_aln ((D2->A)->name[a], NULL); + } + for (f=32; f<=40; f++) + { + for (p1=90; p1<=100; p1+=5) + { + for ( t=1; t<=3; t++) + { + for (p2=0; p2<=40; p2+=5) + { + for (p3=0;p3<=0;p3+=5) + { + tre=tsn=tsp=0; + for ( a=0; a<(D1->A)->nseq; a++) + { + Alignment *A, *B; + A=LA[a]; + B=LB[a]; + re=analyze_overaln (A, B, "_case_l_",t,f,p1,p2,p3); + + tsn+=re[0]; + tsp+=re[1]; + tre+=re[2]; + vfree (re); + } + fp=vfopen (fname, "a"); + fprintf (fp, "\nTOT: sn: %.2f sp: %.2f re: %.2f P: %d P2: %d P3: %d T: %d F: %d", tsn/(D1->A)->nseq,tsp/(D1->A)->nseq, tre/(D1->A)->nseq, p1,p2, p3,t,f); + fprintf (stderr, "\nTOT: sn: %.2f sp: %.2f re: %.2f P: %d P2: %d P3: %d T: %d F: %d", tsn/(D1->A)->nseq,tsp/(D1->A)->nseq, tre/(D1->A)->nseq, p1,p2, p3,t,f); + vfclose (fp); + } + } + } + } + } + myexit (0); + } + else if ( strm ( action, "overaln"))//Evaluate the capacity to predict over-aligned regions + { + OveralnP *F; + F=vcalloc (1, sizeof (OveralnP)); + //al1: ref + //al2: alignment + //ATOI(1): P (0-100) + //ATOI(2): T (0-9) + + float *r; + DST=vcalloc (1,sizeof(Sequence_data_struc)); + DST->A=aln2gap_cache (D1->A,0); + lower_value=0; + upper_value=0; + D1->A=filter_aln_upper_lower (D1->A, DST->A, 0, 0); + + sprintf (F->mode, "%s", ((s=get_string_variable ("overaln_mode")))?s:"lower"); + if (!strm (F->mode, "lower") && !strstr (F->mode, "unalign"))printf_exit (EXIT_FAILURE,stderr,"\nERROR: unknown overal_mode in overal output [%s] [FATAL:%s]", F->mode, PROGRAM); + + if (int_variable_isset ("overaln_threshold"))F->t=get_int_variable ("overaln_threshold"); + if (int_variable_isset ("overaln_target"))F->f=get_int_variable ("overaln_target"); + if (int_variable_isset ("overaln_P1"))F->f=get_int_variable ("overaln_P1"); + if (int_variable_isset ("overaln_P1"))F->f=get_int_variable ("overaln_P2"); + if (int_variable_isset ("overaln_P1"))F->f=get_int_variable ("overaln_P3"); + if (int_variable_isset ("overaln_P1"))F->f=get_int_variable ("overaln_P4");//F P1 P2 P3 T; + + D2->A=aln2clean_pw_aln (D2->A, F); + r=aln2pred (D1->A, D2->A,"case_l_"); + fprintf ( stdout, "sn %.2f sp %.2f re %.2f\n", r[0], r[1], r[2]); + myexit (0); + } + + +//JM_START + else if ( strm ( action, "aln2hitMat")) + { + aln2hitMat(D1->A, ACTION(1)); + myexit (EXIT_SUCCESS); + } +//JM_END + + else + { + fprintf ( stderr, "\nWARNING: ACTION %s UNKNOWN and IGNORED\n", action); + } + + } + + +void aln2mat_diaa (Sequence *S) +{ + int a, aa1, aa2, aa3, aa4; + int s1, s2, p; + Alignment *A; + + int ****m; + int **c; + int naa=0; + int count=0; + double Delta=0.00001; + int *alp; + int tot,u; + double observed, expected, f_diaa1, f_diaa2, v; + + + alp=vcalloc (256, sizeof (int)); + for (a=0; a<26; a++)alp[a+'a']=1; + alp['b']=0; + alp['j']=0; + alp['o']=0; + alp['u']=0; + alp['x']=0; + alp['z']=0; + + m=declare_arrayN (4,sizeof (int),26,26,26,26); + c=declare_arrayN (2,sizeof (int),26,26); + + for ( a=0; a< S->nseq; a++) + { + fprintf ( stderr, "%s\n", S->name[a]); + A=main_read_aln (S->name[a],NULL); + for (s1=0; s1nseq; s1++)lower_string (A->seq_al[s1]); + + for ( s1=0; s1nseq-1; s1++) + for (s2=s1+1; s2nseq; s2++) + { + for (p=0; plen_aln-1; p++) + { + + u =alp[aa1=A->seq_al[s1][p]]; + u+=alp[aa2=A->seq_al[s1][p+1]]; + u+=alp[aa3=A->seq_al[s2][p]]; + u+=alp[aa4=A->seq_al[s2][p+1]]; + + if ( u==4) + { + aa1-='a';aa2-='a';aa3-='a'; aa4-='a'; + + c[aa1][aa2]++; + c[aa3][aa4]++; + m[aa1][aa2][aa3][aa4]++; + count+=2; + } + } + } + free_aln (A); + } + fprintf ( stdout, "# DIAA_MATRIX_FORMAT_01\n"); + naa=26; + for (aa1=0; aa10)fprintf ( stdout, "TEST C=%d expected=%.4f observed=%.4f v=%.4f [%d %d %d][%d] tot=%d\n", count, (float)expected, (float)observed, (float) v, c[aa1][aa2], c[aa3][aa4], count, m[aa1][aa2][aa3][aa4], tot); + fprintf ( stdout, "%c%c %c%c %d %d\n", aa1+'a', aa2+'a', aa3+'a', aa4+'a', (int)v, m[aa1][aa2][aa3][aa4]+ m[aa3][aa4][aa1][aa2]); + } + } + myexit (EXIT_SUCCESS); +} +void aln2mat (Sequence *S) +{ + int a, aa1, aa3; + int s1, s2, p; + Alignment *A; + int **mat; + int **m; + int *c; + int naa=0; + int count=0; + double Delta=0.00001; + int *alp; + int tot,u; + double observed, expected, f_diaa1, f_diaa2, v; + char *balp; + + balp=vcalloc ( 256, sizeof (char)); + for (a=0; anseq; a++) + { + fprintf ( stderr, "%s\n", S->name[a]); + A=main_read_aln (S->name[a],NULL); + for (s1=0; s1nseq; s1++)lower_string (A->seq_al[s1]); + + for ( s1=0; s1nseq-1; s1++) + for (s2=s1+1; s2nseq; s2++) + { + for (p=0; plen_aln-1; p++) + { + + u =alp[aa1=A->seq_al[s1][p]]; + u+=alp[aa3=A->seq_al[s2][p]]; + + if ( u==2) + { + aa1-='a';aa3-='a'; + + c[aa1]++; + c[aa3]++; + m[aa1][aa3]++; + count+=2; + } + } + } + free_aln (A); + } + fprintf ( stdout, "# MONOAA_MATRIX_FORMAT_01\n"); + naa=26; + for (aa1=0; aa10)fprintf ( stdout, "TEST C=%d expected=%.4f observed=%.4f v=%.4f [%d %d %d][%d] tot=%d\n", count, (float)expected, (float)observed, (float) v, c[aa1][aa2], c[aa3][aa4], count, m[aa1][aa2][aa3][aa4], tot); + //fprintf ( stdout, "%c %c %d %d\n", aa1+'A', aa3+'A', (int)v, m[aa1][aa3]+ m[aa3][aa1]); + mat[aa1][aa3]=(int)v; + } + } + output_blast_mat (mat, "stdout"); + myexit (EXIT_SUCCESS); +} + + +int **seq2latmat ( Sequence *S, char *fname) +{ + int a, b, r0, r1; + char *aa; + int naa; + int *count, tot; + int **mat; + double observed, expected; + FILE *fp; + + fp=vfopen (fname, "w"); + + count=vcalloc ( 256, sizeof (int)); + mat=declare_int (256, 256); + + naa=strlen ( BLAST_AA_ALPHABET); + aa=vcalloc ( naa+2, sizeof (char)); + sprintf ( aa, "%s", BLAST_AA_ALPHABET); + lower_string (aa); + + for ( tot=0,a=0; a< S->nseq; a++) + { + ungap (S->seq[a]); + for ( b=1; blen[a]; b++) + { + r0=tolower(S->seq[a][b-1]); + r1=tolower(S->seq[a][b]); + + mat[r0][r1]++; + //count[r0]++; + count[r1]++; + tot++; + } + } + for ( a=0; a< naa; a++) + for (b=0; b< naa; b++) + { + if ( aa[a]=='*' || aa[b]=='*'); + else + { + expected=((double)count[(int)aa[a]]/(double)tot)* ((double)count[(int)aa[b]]/(double)tot)*(double)tot; + observed=((double)mat[(int)aa[a]][(int)aa[b]]); + + /* + fprintf ( stderr, "\n%c=%d %c=%d Tot=%d Obs=%d Exp=%d\n", aa[a],count[aa[a]], aa[b],count[aa[b]],tot, mat[aa[a]][aa[b]],(int)expected); + fprintf ( stderr, "\n%d", mat[aa[a]][aa[b]]); + fprintf ( stderr, "\n%d", mat[aa[a]][aa[b]]); + */ + mat[(int)aa[a]][(int)aa[b]]=(expected==0 || observed==0)?0:((int)10*log((observed/expected))); + } + } + + fprintf (fp,"# BLAST_MATRIX FORMAT\n#ALPHABET=%s\n#TRANSITION MATRIX TRAINED ON %d Sequence\n#", BLAST_AA_ALPHABET, S->nseq); + for (a=0; a< naa; a++)fprintf ( fp, "%3c ", toupper(aa[a])); + fprintf (fp,"\n"); + for (a=0; a< naa; a++) + { + + fprintf (fp, "%c", toupper(aa[a])); + for ( b=0; b< naa; b++) + { + fprintf (fp, "%3d ", mat[(int)aa[a]][(int)aa[b]]); + } + fprintf ( fp, "\n"); + } + vfclose (fp); + vfree (count); + vfree (aa); + + return mat; +} + +double* mat2cmp ( int **mat1, int **mat2) +{ + int a, b, n, x, y; + double **list, *r; + if ( !mat1 || !mat2) + { + fprintf ( stderr, "\nERROR: mat2cmp needs two matrices [FATAL:%s]", PROGRAM); + myexit (EXIT_FAILURE); + } + + for (n=0, a=0; a< 256; a++) + for ( b=0; b<256; b++) + { + x=mat1[a][b]; + y=mat2[a][b]; + if ( x|| y)n++; + } + if ( n==0) return 0; + list=declare_double (n, 2); + + for (n=0, a=0; a<256; a++) + for ( b=0; b<256; b++) + { + x=mat1[a][b]; + y=mat2[a][b]; + if ( x || y) + { + list[n][0]=x; + list[n][1]=y; + n++; + } + } + r=return_r (list, n); + free_double(list, -1); + return r; +} + +int ** read_blast_matrix ( char *mat_name) + { + FILE *fp; + int n_aa,aa1, aa2; + int a, b, c; + int **matrix; + int value; + char sbuf[VERY_LONG_STRING]; + char buf[2]; + char alp[257]; + + matrix=declare_int (256,256); + vfree ( matrix[30]); + matrix[30]=vcalloc(10000, sizeof (int)); + fp=vfopen ( mat_name, "r"); + while ( (c=fgetc(fp))=='#' || isspace(c) ) + { + char *p; + fgets ( sbuf, VERY_LONG_STRING, fp); + if ( (p=strstr (sbuf, "ALPHABET"))) + sscanf (p, "ALPHABET=%s", alp); + } + ungetc(c, fp); + lower_string (alp); + n_aa=strlen (alp); + + for ( a=0; a< n_aa; a++) + { + fscanf ( fp, "%s ", buf); + + aa1=tolower(buf[0]); + + if ( aa1!=alp[a]) + { + fprintf ( stderr, "\nParsing_error when reading blast_matrix %s:\n%c %c",mat_name, aa1,alp[a]); + fprintf ( stderr, "\n%c ", fgetc(fp)); + myexit (EXIT_FAILURE); + } + for ( b=0; bnseq; a++) + { + if (S->seq_comment[a] && (s=strstr(S->seq_comment[a], "_FIRSTYEAR"))) + { + sscanf (s, "_FIRSTYEAR%d_", &first); + } + else first=1; + + for ( y=first,b=0; blen[a]; b++) + { + if ( !is_gap(S->seq[a][b])) + { + S->seq[a][b]='a'+((y/modulo))%10; + y++; + } + } + if ( (s=strstr ( S->name[a], "_agechannel"))) + { + sprintf ( s, "%s", new_channel); + } + else strcat (S->name[a], new_channel); + } + return S; +} + +Sequence* output_n_pavie_age_channel (Sequence *S, char *name, int n) +{ + int x, a; + if (!n)n=2; + + + for ( x=1,a=0; a< n; a++, x*=10) + { + S=output_pavie_age_channel(S, name,x); + } +return S; +} + + + + +Sequence* output_pavie_age_channel (Sequence *S, char *name, int modulo) + { + Alignment *A; + FILE *fp; + static int display; + char mat_list_name[100]; + char seq_list[1000]; + char mat_name[1000]; + char *tmp; + + sprintf ( mat_list_name, "%s_pavie_age_matrix.mat_list", name); + sprintf (seq_list, "%s_age_channel.fasta",name); + + if ( display==0 ) + { + if (check_file_exists(seq_list))vremove (seq_list); + if (check_file_exists(mat_list_name))vremove (mat_list_name); + } + sprintf (mat_name, "%s_age_mat_mod%d.mat",name, modulo); + output_age_matrix ( mat_name, modulo); + + fp=vfopen ( mat_list_name,"a"); + fprintf ( fp, "%s\n", mat_name); + vfclose ( fp); + + S=seq2year (S,modulo); + A=seq2aln (S, NULL, KEEP_GAP); + output_fasta_seq (tmp=vtmpnam (NULL),A); + file_cat ( tmp, seq_list); + + if ( display==0) + { + display_output_filename ( stdout, "AGE_MAT_LIST", "MAT_LIST", mat_list_name, CHECK); + display_output_filename ( stdout, "AGE_SEQ", "FASTA", seq_list, CHECK); + display=1; + } + fprintf ( stderr, "\nModulo:%d years", modulo); + fprintf ( stderr, "\n"); + free_aln (A); + return S; + } +// +// Name MAnipulation +// + +Alignment *clean_aln (Alignment *A) +{ + if ( A) + { + A->seq_comment=clean_string (A->nseq, A->seq_comment); + A->aln_comment=clean_string (A->nseq, A->aln_comment); + A->name=translate_names(A->nseq, A->name); + (A->S)=clean_sequence ((A->S)); + } + return A; +} +Sequence *clean_sequence ( Sequence *S) +{ + if ( !S) return S; + + S->seq_comment=clean_string (S->nseq, S->seq_comment); + S->name=translate_names(S->nseq, S->name); + return S; +} +char ** translate_names (int n, char **name) +{ + int a; + for ( a=0; a<'�", name[a]))name[a]='_'; + + } + sprintf (buf,"%s",decode_name (name, DECODE)); + if ( strlen (buf)>read_array_size_new ((char *)name)) + { + name=vrealloc (name, sizeof (char)*(strlen (buf)+1)); + } + sprintf (name, "%s", buf); + + return name; + } +char *decode_name (char *name, int mode) +{ + static char ***name_list; + static int n; + static char tag[100]; + int a; + + if (mode==CLEAN) + { + for (a=0; a %s\n", name_list[a][0], name_list[a][1]); + return file; + } + if (mode ==DECODE && name_list==NULL)return name; + if ( name==NULL) return name; + + + + if (!tag[0]) + { + vsrand (0); + sprintf ( tag, "TCTAG_%d",rand ()%100000); + } + + if ( mode==CODE) + { + for (a=0; a< n; a++) + if ( strm (name, name_list[a][0]))return name_list[a][1]; + + + name_list=realloc (name_list, sizeof (char**)*(n+1)); + name_list[n]=vcalloc (2, sizeof (char*)); + name_list[n][0]=vcalloc (strlen (name)+1, sizeof (char)); + name_list[n][1]=vcalloc (100, sizeof (char)); + sprintf ( name_list[n][0], "%s", name); + sprintf ( name_list[n][1], "%s_%d", tag,n+1); + return name_list[n++][1]; + } + else if ( mode ==DECODE) + { + char *p; + int i; + if ( !(p=after_strstr (name, tag)))return name; + else + { + sscanf (p, "_%d", &i); + return name_list[i-1][0]; + } + } + else + { + printf_exit (EXIT_FAILURE, stderr,"Unknown Mode for Decode_name [FATAL:%s]", PROGRAM); + } + return NULL; +} + + +FILE * display_sequences_names (Sequence *S, FILE *fp, int check_pdb_status, int print_templates) + { + int a; + int max_len; + char *r; + + if ( !S) + { + fprintf (fp,"\nERROR: NO SEQUENCE READ [FATAL:%s]\n", PROGRAM); myexit (EXIT_FAILURE); + } + for ( a=0, max_len=0; a< S->nseq; a++)max_len=MAX(max_len, strlen (S->name[a])); + fprintf ( fp, "\nINPUT SEQUENCES: %d SEQUENCES [%s]", S->nseq,(S->type)?S->type:"Unknown type"); + for ( a=0; a< S->nseq; a++) + { + fprintf (fp, "\n Input File %-*s Seq %-*s Length %4d type %s",max_len,S->file[a], max_len,S->name[a],(int)strlen ( S->seq[a]), S->type); + if (check_pdb_status) + { + if ((r=seq_is_pdb_struc (S, a)))fprintf (fp, " Struct Yes PDBID %s", get_pdb_id(r)); + else fprintf (fp, " Struct No"); + /* + if (is_pdb_struc (S->name[a])||is_pdb_struc (S->file[a]) )fprintf (fp, " Struct Yes"); + else fprintf (fp, " Struct No"); + */ + } + else fprintf (fp, " Struct Unchecked"); + if ( print_templates)fp=display_sequence_templates (S, a, fp); + + + } + fprintf ( fp, "\n"); + return fp; + + } +Sequence *add_file2file_list (char *name, Sequence *S) +{ + + if (!S) S=declare_sequence (1,1,10); + else S=realloc_sequence (S,S->nseq+1,0);S->nseq=0; + + sprintf ( S->name[S->nseq++], "%s", name); + return S; + +} +#ifdef DO_PHECOMP +int parse_phecomp_data (char *in, char *out) +{ + static char *buffer; + in=quick_find_token_in_file (in, "[EXPERIMENT HEADER]"); + while (fgets (buffer,fp,MAX_LINE_LENGTH)); +} +FILE * quick_find_token_in_file (FILE *fp, char *token) +{ + //returns fp pointing to the begining of the line FOLLOWING the line containing token + static char *buffer; + if (!line) line=vcalloc (MAX_LINE_LENGTH+1, sizeof (char)); + while (fgets (buffer,MAX_LINE_LENGTH, fp)!=NULL) + if (strstr (buffer,token))return fp; + vfclose (fp); + return NULL; +} + +int * file2cage (char *file, int cage) +{ + + + + + + + + + + +#endif +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/reformat_struc.c b/binaries/src/tcoffee/t_coffee_source/reformat_struc.c new file mode 100644 index 0000000..86a8177 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/reformat_struc.c @@ -0,0 +1,1095 @@ +#include +#include +#include +#include +#include +#include +#include +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "dp_lib_header.h" +#include "define_header.h" + + + +#define FATAL "fatal:reformat_struc" + +char * process_repeat (char *aln, char *seq, char *pdb) +{ + char *tf, *file, *name; + Alignment *A, *A2; + Sequence *S, *P; + int r1, r2, is_r1, is_r2, l1=0, l2=0, a; + int *pos; + FILE *fp; + + A=main_read_aln (aln, NULL); + for (a=0; anseq; a++)ungap(A->seq_al[a]); + + S=main_read_seq (seq); + P=get_pdb_sequence (pdb); + + + A2=align_two_sequences (S->seq[0], P->seq[0], "pam250mt", -10, -1, "myers_miller_pair_wise"); + + pos=vcalloc ( A2->len_aln+1, sizeof (int)); + + for (l1=0, l2=0,a=0; a< A2->len_aln; a++) + { + + r1=A2->seq_al[0][a]; + r2=A2->seq_al[1][a]; + + is_r1=1-is_gap(r1); + is_r2=1-is_gap(r2); + + l1+=is_r1; + l2+=is_r2; + + if (!is_r1); + else + { + pos[l1]=l2; + } + } + tf=vtmpnam(NULL); + fp=vfopen (tf, "w"); + for (a=0; anseq; a++) + { + int *coor, b, c; + + name=A->name[a]; + file=vtmpnam (NULL); + coor=string2num_list2 (name, "-"); + + //Check the compatibility between the guide sequence and the coordinates + for ( c=0,b=coor[1]-1; bseq_al[a][c])!=tolower(S->seq[0][b])) + printf_exit (EXIT_FAILURE, stderr, "Incompatibility between the repeat [%s] and the master Sequence [%s]\n%s",A->name[a], seq, A->seq_al[a]); + } + + printf_system ( "extract_from_pdb %s -coor %d %d -seq_field SEQRES> %s", pdb,pos[coor[1]-1],pos[coor[2]-1], file); + fprintf (fp, ">%s _P_ %s\n", name, file); + vfree (coor); + } + vfclose (fp); + return tf; +} + + + +char * normalize_pdb_file (char *name_in, char *seq, char *out_file) +{ + char command[1000]; + Sequence *S; + Alignment *A; + int a; + int start, end, npdb, r1, r2; + char name[100]; + + + if ( !name_in) return NULL; + else + { + sprintf ( name, "%s", name_in); + } + + if ( !is_pdb_file(name)) + { + fprintf(stdout, "\nERROR[normalize_pdb_file]: %s is not a pdb file[FATAL:%s]\n", name, PROGRAM); + myexit (EXIT_FAILURE); + } + + S=get_pdb_sequence (name); + A=align_two_sequences (S->seq[0],seq,"idmat",-3,0, "fasta_pair_wise"); + + + + for (start=-1, end=-1,npdb=0,a=0; a< A->len_aln; a++) + { + r1=1-is_gap(A->seq_al[0][a]); + r2=1-is_gap(A->seq_al[1][a]); + + npdb+=r1; + + if (r1 && r2 && start==-1)start=npdb; + if (r1 && r2)end=npdb; + } + + free_aln(A); + free_sequence (S, -1); + + sprintf ( command, "extract_from_pdb -infile %s -atom ALL -chain FIRST -coor %d %d -nodiagnostic > %s", check_file_exists(name), start, end, out_file); + my_system ( command); + return out_file; + } + +Ca_trace * trim_ca_trace (Ca_trace *T, char *seq ) +{ + /*This function: + -removes from Ca trace all the residues that are not in the sequence + -add in the Ca trace residues unmatched in the structure (it gives them a NULL structure) + */ + Alignment *ALN; + Atom *A; + int a,l, s, r, is_r, is_s; + int *seq_cache, *struc_cache; + int tot_l=0; + + char buf1[10000]; + char buf2[10000]; + + /* lower_string (T->seq); + lower_string (seq); + */ + + + sprintf (buf1, "%s", T->seq); + sprintf (buf2, "%s", seq); + lower_string (buf1); + lower_string (buf2); + + + if ( strm (buf1,buf2))return T; + else + { + ALN=align_two_sequences (T->seq,seq, "est_idmat",-1, 0,"fasta_pair_wise"); + struc_cache=vcalloc (ALN->len_aln+1, sizeof (int)); + seq_cache =vcalloc (ALN->len_aln+1, sizeof (int)); + + for ( r=0, s=0,a=0; a< ALN->len_aln; a++) + { + is_r=!is_gap(ALN->seq_al[0][a]); + is_s=!is_gap(ALN->seq_al[1][a]); + + r+=is_r; + s+=is_s; + + if ( is_s && is_r) + { + struc_cache[r-1]=s-1; + seq_cache[s-1]=r-1; + } + else if ( is_s && !is_r) + { + seq_cache[s-1]=-1; + + } + else if ( !is_s && is_r) + { + struc_cache[r-1]=-1; + } + } + + T->ca=vrealloc ( T->ca, sizeof (Atom*)*(ALN->len_aln+1)); + T->peptide_chain=vrealloc ( T->peptide_chain, (sizeof (Amino_acid*))*(ALN->len_aln+1)); + T->seq=vrealloc ( T->seq, ALN->len_aln+1); + + for ( a=T->len; a< ALN->len_aln; a++) + { + T->peptide_chain[a]=vcalloc (1, sizeof (Amino_acid)); + } + + + /*Read every atom*/ + for ( a=0; a< T->n_atom; a++) + { + + A=(T->structure[a]); + if ( struc_cache[A->res_num-1]==-1)continue; + else + { + /*set the struc residue to its sequence index*/ + A->res_num=struc_cache[A->res_num-1]+1; + if (strm (A->type, "CA")) {T->ca[A->res_num-1]=A;tot_l++;} + if ( strm (A->type, "CA"))(T->peptide_chain[A->res_num-1])->CA=A; + if ( strm (A->type, "C"))(T->peptide_chain[A->res_num-1] )->C=A; + if ( strm (A->type, "CB"))(T->peptide_chain[A->res_num-1])->CB=A; + if ( strm (A->type, "N"))(T->peptide_chain[A->res_num-1] )->N=A; + } + } + + l=strlen(seq); + for ( a=0;a< l; a++) + { + + if ( seq_cache[a]==-1) + { + tot_l++; + T->ca[a]=NULL; + + if (!T->peptide_chain[a])T->peptide_chain[a]=vcalloc (1, sizeof (Amino_acid)); + T->peptide_chain[a]->CA=NULL; + T->peptide_chain[a]->C =NULL; + T->peptide_chain[a]->CB=NULL; + T->peptide_chain[a]->N=NULL; + T->seq[a]='x'; + } + else + { + T->seq[a]=seq[a]; + } + } + T->len=ALN->len_aln; + + /* + T->len=tot_l; + */ + + free_aln (ALN); + vfree(seq_cache); + vfree(struc_cache); + + + } + return T; +} + +Ca_trace * read_ca_trace (char *name, char *seq_field ) +{ + char *tp_name=NULL; + char command[10000]; + + + if ( !is_simple_pdb_file (name)) + { + tp_name=vtmpnam (NULL); + sprintf ( command, "extract_from_pdb -seq_field %s -infile %s -atom ALL -chain FIRST -mode simple> %s",seq_field, check_file_exists(name), tp_name); + if ( getenv4debug ("DEBUG_EXTRACT_FROM_PDB"))fprintf ( stderr, "\n[DEBUG_EXTRACT_FROM_PDB:read_ca_trace] %s\n", command); + my_system ( command); + } + else + tp_name=name; + + return simple_read_ca_trace (tp_name); +} + +Ca_trace * simple_read_ca_trace (char *tp_name ) + { + /*This function reads a pdb file into a Ca_trace structure*/ + + + + int a, c, n; + FILE *fp; + Atom *A; + char res; + char *buf; + Ca_trace *T=NULL; + int res_num=0, last_res_num=0; + + + buf=vcalloc ( VERY_LONG_STRING, sizeof (char)); + n=count_n_line_in_file (tp_name ); + + if ( !T) + { + T=vcalloc ( 1, sizeof ( Ca_trace)); + declare_name (T->name); + } + + /*1 Get the complete sequence: replace missing residues with Xs*/ + for (a=0; a< VERY_LONG_STRING; a++)buf[a]='x'; + res=res_num=0; + + fp=vfopen (tp_name, "r"); + while ( (c=fgetc(fp))!='>'); + fscanf ( fp, "%*s" ); + while ( (c=fgetc(fp))!='\n'); + fscanf ( fp, "%*s" ); + while ( (c=fgetc(fp))!='\n'); + while ((c=fgetc(fp))!=EOF) + { + ungetc(c, fp); + + fscanf (fp, "%*s %*s %c %*c %d %*f %*f %*f\n",&res,&res_num); + if (res) + { + + res=tolower (res); + buf[res_num-1]=res; + last_res_num=res_num; + } + res=res_num=0; + } + buf[last_res_num]='\0'; + vfclose (fp); + /*Sequence Read*/ + + + T->len=strlen (buf); + T->seq=vcalloc ( T->len+1, sizeof (char)); + buf=lower_string (buf); + sprintf ( T->seq, "%s", buf); + n+=T->len; + T->structure=vcalloc ( n, sizeof (Atom*)); + for ( a=0; a< n; a++)T->structure[a]=vcalloc ( 1, sizeof (Atom)); + T->ca=vcalloc ( T->len+1, sizeof ( Atom*)); + a=0; + + fp=vfopen (tp_name, "r"); + while ( (c=fgetc(fp))!='>'); + fscanf ( fp, "%*s" ); + while ( (c=fgetc(fp))!='\n'); + fscanf ( fp, "%*s" ); + while ( (c=fgetc(fp))!='\n'); + + while ((c=fgetc(fp))!=EOF) + { + ungetc(c, fp); + A=T->structure[a]; + A->num=a; + fscanf (fp, "%*s %s %s %*c %d %f %f %f\n",A->type, A->res,&A->res_num, &A->x, &A->y, &A->z); + res=A->res[0]; + + res=tolower (res); + + T->seq[A->res_num-1]=res; + + if (( strm ( A->type, "CA")) || ( strm ( A->type, "C3'"))) + T->ca[A->res_num-1]=A; + a++; + } + T->n_atom=a; + + T->peptide_chain=vcalloc (T->len+1, sizeof (Amino_acid*)); + for ( a=0; a<=T->len; a++) T->peptide_chain[a]=vcalloc (1, sizeof (Amino_acid)); + for ( a=0; a< T->n_atom; a++) + { + A=T->structure[a]; + + if ( strm (A->type, "CA"))(T->peptide_chain[A->res_num-1])->CA=A; + if ( strm (A->type, "C3'"))(T->peptide_chain[A->res_num-1])->CA=A; + if ( strm (A->type, "C"))(T->peptide_chain[A->res_num-1] )->C=A; + if ( strm (A->type, "CB"))(T->peptide_chain[A->res_num-1])->CB=A; + if ( strm (A->type, "N"))(T->peptide_chain[A->res_num-1] )->N=A; + } + + + vfclose (fp); + vfree (buf); + return T; + } +Ca_trace * hasch_ca_trace ( Ca_trace *T) + { + + T=hasch_ca_trace_nb (T); + T=hasch_ca_trace_bubble (T); + T=hasch_ca_trace_transversal (T); + return T; + } +Ca_trace * hasch_ca_trace_transversal ( Ca_trace *TRACE) + { + /*This function gets the Coordinates of a protein and computes the distance of each Ca to its + + given a Ca, + Compute the distance between, CA-x and CA+x with x=[1-N_ca] + T->nb[a][0]-->Number of distances. + T->nb[a][1... T->nb[a][0]]-->ngb index with respect to the Ca chain + T->d_nb[a][1... T->d_nb[a][0]]-->ngb index with respect to the Ca chain + */ + + int a, b, d; + float dist; + Atom *A, *B; + + Struct_nb *T; + Pdb_param *PP; + + + TRACE->Transversal=vcalloc ( 1, sizeof (Struct_nb)); + + T=TRACE->Transversal; + PP=TRACE->pdb_param; + + if ( !T->nb)T->nb=declare_int (TRACE->len+1, 1); + if ( !T->d_nb)T->d_nb=declare_float (TRACE->len+1, 1); + + for (d=0,a=0; a< TRACE->len; a++) + { + + for ( b=1; b<=PP->N_ca; b++) + { + if ( (a-b)<0 || (a+b)>=TRACE->len)continue; + A=TRACE->ca[a-b]; + B=TRACE->ca[a+b]; + dist=get_atomic_distance ( A, B); + + T->nb[a]=vrealloc ( T->nb[a], (++T->nb[a][0]+1)*sizeof (int)); + T->nb[a][T->nb[a][0]]=b; + + T->d_nb[a]=vrealloc ( T->d_nb[a], (T->nb[a][0]+1)*sizeof (float)); + T->d_nb[a][T->nb[a][0]]=dist; + + d++; + } + T->max_nb=MAX (T->max_nb, T->nb[a][0]); + } + return TRACE; + + } + +Ca_trace * hasch_ca_trace_nb ( Ca_trace *TRACE) + { + /*This function gets the Coordinates of a protein and computes the distance of each Ca to its + T->N_ca Ngb. + The first Ngb to the left and to the right are excluded + Ngd to the left get negative distances + Ngb to the right receive positive distances + T->nb[a][0]-->Number of ngb. + T->nb[a][1... T->nb[a][0]]-->ngb index with respect to the Ca chain + T->d_nb[a][1... T->d_nb[a][0]]-->ngb index with respect to the Ca chain + */ + + + + int a, b, d; + float dist; + Atom *A, *B; + + Struct_nb *T; + Pdb_param *PP; + + TRACE->Chain=vcalloc ( 1, sizeof (Struct_nb)); + + T=TRACE->Chain; + PP=TRACE->pdb_param; + + if ( !T->nb)T->nb=declare_int (TRACE->len+1, 1); + if ( !T->d_nb)T->d_nb=declare_float (TRACE->len+1, 1); + + for (d=0,a=0; a< TRACE->len; a++) + { + for ( b=MAX(0,a-PP->N_ca); b< MIN( a+PP->N_ca, TRACE->len); b++) + { + if (FABS(a-b)<2)continue; + A=TRACE->ca[a]; + B=TRACE->ca[b]; + if ( !A || !B)continue; + dist=get_atomic_distance ( A, B); + if (bnb[a]=vrealloc ( T->nb[a], (++T->nb[a][0]+1)*sizeof (int)); + T->nb[a][T->nb[a][0]]=b; + + T->d_nb[a]=vrealloc ( T->d_nb[a], (T->nb[a][0]+1)*sizeof (float)); + T->d_nb[a][T->nb[a][0]]=dist; + d++; + } + + T->max_nb=MAX (T->max_nb, T->nb[a][0]); + } + return TRACE; + + } +Ca_trace * hasch_ca_trace_bubble ( Ca_trace *TRACE) + { + + int a, b; + float dist; + Atom *A, *B; + float **list; + Pdb_param *PP; + Struct_nb *T; + + PP=TRACE->pdb_param; + TRACE->Bubble=vcalloc ( 1, sizeof (Struct_nb)); + T=TRACE->Bubble; + + + + if ( !T->nb)T->nb=declare_int (TRACE->len+1, 1); + if ( !T->d_nb)T->d_nb=declare_float (TRACE->len+1, 1); + list=declare_float ( TRACE->n_atom, 3); + + + for (a=0; a< TRACE->len; a++) + { + for ( b=0; b< TRACE->len; b++) + { + A=TRACE->ca[a]; + B=TRACE->ca[b]; + if ( !A || !B)continue; + dist=get_atomic_distance ( A, B); + + if ( distmaximum_distance && FABS((A->res_num-B->res_num))>2) + { + T->nb[a][0]++; + T->nb[a]=vrealloc ( T->nb[a], (T->nb[a][0]+1)*sizeof (int)); + T->nb[a][T->nb[a][0]]=(TRACE->ca[b])->num; + + T->d_nb[a]=vrealloc ( T->d_nb[a], (T->nb[a][0]+1)*sizeof (float)); + T->d_nb[a][T->nb[a][0]]= ((amax_nb=MAX (T->max_nb, T->nb[a][0]); + + } + + for ( a=0; a< TRACE->len; a++) + { + for ( b=0; b< T->nb[a][0]; b++) + { + list[b][0]=T->nb[a][b+1]; + list[b][1]=T->d_nb[a][b+1]; + list[b][2]=(TRACE->structure[T->nb[a][b+1]])->res_num; + } + + sort_float ( list, 3,2, 0, T->nb[a][0]-1); + for ( b=0; b< T->nb[a][0]; b++) + { + T->nb[a][b+1]=list[b][0]; + T->d_nb[a][b+1]=list[b][1]; + } + } + + free_float ( list, -1); + return TRACE; + + } + + +float ** measure_ca_distances(Ca_trace *T) + { + int a, b; + Atom *A, *B; + float **dist; + + dist=declare_float ( T->len, T->len); + + for (a=0; a< T->len-1; a++) + { + for ( b=a+1; b< T->len; b++) + { + + A=T->ca[a]; + B=T->ca[b]; + dist[a][b]=dist[b][a]=get_atomic_distance ( A, B); + + } + } + return dist; + } +float get_atomic_distance ( Atom *A, Atom*B) + { + float dx, dy, dz, d; + + if ( !A || !B) + { + return UNDEFINED; + } + + + dx=A->x - B->x; + dy=A->y - B->y; + dz=A->z - B->z; + + + d=(float) sqrt ( (double) ( dx*dx +dy*dy +dz*dz)); + return d; + } + +char * map_contacts ( char *file1, char *file2, float T) +{ + + Ca_trace *ST1, *ST2; + int *contact_list; + int a; + + + ST1=read_ca_trace (file1, "ATOM"); + ST2=read_ca_trace (file2, "ATOM"); + + contact_list=identify_contacts (ST1, ST2, T); + for ( a=0; alen; a++) + { + ST1->seq[a]=(contact_list[a]==1)?toupper(ST1->seq[a]):tolower(ST1->seq[a]); + } + + return ST1->seq; +} + +float ** print_contacts ( char *file1, char *file2, float T) +{ + + Ca_trace *ST1, *ST2; + float **dist, d; + int a, b; + Atom *A, *B; + char *list; + int *list1=NULL, *list2=NULL; + int *cache1, *cache2; + + + + if ((list=strstr (file1, "_R_"))!=NULL) + { + list[0]='\0'; + list+=3; + list1=string2num_list2(list, "_"); + } + + if ((list=strstr (file2, "_R_"))!=NULL) + { + list[0]='\0'; + list+=3; + list2=string2num_list2(list, "_"); + } + + fprintf ( stdout, "\n#%s (%s) struc2contacts_01", PROGRAM, VERSION); + fprintf ( stdout, "\nStructure %s vs %s", file1, file2); + ST1=read_ca_trace (file1, "SEQRES"); + ST2=read_ca_trace (file2, "SEQRES"); + + + cache1=vcalloc (ST1->len+1, sizeof (int)); + cache2=vcalloc (ST2->len+1, sizeof (int)); + + if (list1)for ( a=1; alen; a++)cache1[a]=1; + + if (list2)for ( a=1; alen; a++)cache2[a]=1; + + + dist=declare_float (ST1->len+1,ST2->len+1); + vfree (list1); vfree(list2); + + for ( a=0; a< ST1->n_atom; a++) + { + A=ST1->structure[a]; + if ( !cache1[A->res_num])continue; + for ( b=0; bn_atom; b++) + { + + B=ST2->structure[b]; + if( !cache2[B->res_num])continue; + + d=get_atomic_distance (A,B); + + if (dist[A->res_num][B->res_num]==0 || dist[A->res_num][B->res_num]>d)dist[A->res_num][B->res_num]=d; + } + } + + for ( a=1; a<=ST1->len; a++) + { + A=ST1->ca[a-1]; + if ( !A || !cache1[A->res_num])continue; + for ( b=1; b<= ST2->len; b++) + { + B=ST2->ca[b-1]; + if( !B || !cache2[B->res_num])continue; + if(dist[a][b]!=0)fprintf ( stdout, "\nResidue %3d [%s] vs %3d [%s] %9.4f Angstrom",A->res_num,A->res,B->res_num,B->res,dist[a][b]); + } + } + fprintf ( stdout, "\n"); + vfree (cache1);vfree(cache2); + free_float (dist, -1); + return NULL; +} + + +int * identify_contacts (Ca_trace *ST1,Ca_trace *ST2, float T) +{ + int a, b; + float d; + int *result; + + + + result=vcalloc ( ST1->len+1, sizeof (int)); + + + for ( a=0; a< ST1->n_atom; a++) + for ( b=0; bn_atom; b++) + + { + + d=get_atomic_distance (ST1->structure[a], ST2->structure[b]); + if (dstructure[a]; B=ST2->structure[b]; + fprintf ( stderr, "\n%d %s %s Vs %d %s %s: %f", A->res_num, A->res, A->type, B->res_num, B->res, B->type, d); */ + result[(ST1->structure[a])->res_num-1]=1; + } + } + return result; +} + +Sequence *seq2contacts ( Sequence *S, float T) +{ + int a; + Sequence *NS; + + + + NS=duplicate_sequence (S); + for ( a=0; a< S->nseq; a++) + { + NS->seq[a]=string2contacts ( S->seq[a], S->name[a], S->seq_comment[a], T); + } + + return NS; +} + +char *string2contacts (char *seq,char *name, char *comment, float T) +{ + char **nlist; + char *r; + char *result; + int a, b, n; + char *struc_name; + static char *struc_file; + static char *ligand_file; + Alignment *A; + char r0, r1; + + int l, ln; + char command[1000]; + /*>seq__struc Ligand1 Chain1 Ligand 2 cahin2 + Chain: index or ANY if unknown + Ligand: name of pdb file + */ + + if ( !struc_file) + { + struc_file=vtmpnam (NULL); + ligand_file=vtmpnam (NULL); + } + + + + result=vcalloc ( strlen (seq)+1, sizeof (char)); + for ( a=0; a< strlen (seq); a++)result[a]='0'; + + nlist=string2list (comment); + if ( !nlist)return result; + else + n=atoi(nlist[0]); + + struc_name=strstr(name, "_S_"); + if (!struc_name && !is_pdb_struc (name)) + { + + return result; + } + else if ( !struc_name && is_pdb_struc (name)) + { + struc_name=name; + } + else + { + struc_name+=3; + if ( check_file_exists (struc_name) && is_simple_pdb_file(struc_name)) + { + sprintf (command, "cp %s %s", name, struc_file); + } + else + { + sprintf ( command, "extract_from_pdb -infile %s -atom ALL -mode simple -force >%s",name, struc_file); + } + my_system (command); + } + + + + for ( a=1, ln=1;a%s", nlist[a], ligand_file); + a++; + } + else + { + sprintf ( command, "extract_from_pdb -infile %s -chain %s -ligand %s -ligand_only -atom ALL -mode simple -force >%s",struc_name, nlist[a+1],nlist[a], ligand_file); + a+=2; + } + my_system (command); + + if ( T>0) + { + r=map_contacts (struc_file,ligand_file,T); + + toggle_case_in_align_two_sequences (KEEP_CASE); + A=align_two_sequences (seq,r,"pam250mt", -10, -1, "myers_miller_pair_wise"); + toggle_case_in_align_two_sequences (CHANGE_CASE); + + + for ( l=0,b=0; b< A->len_aln; b++) + { + r0=A->seq_al[0][b];r1=A->seq_al[1][b]; + if (!is_gap(r0)) + { + if (isupper(r1))result[l]=(result[l]!='0')?'9':'0'+ln; + l++; + } + } + + free_aln (A); + fprintf ( stderr, " [DONE]"); + } + else if ( T==0) + { + print_contacts( struc_file,ligand_file,T); + } + + } + fprintf ( stderr, "\n"); + + return result; +} + + +char **struclist2nb (char *name,char *seq, char *comment, float Threshold, char *atom, char *output) +{ + char *list, **pdb; + int a; + char **R, *tmpf; + + tmpf=vtmpnam (NULL); + + list=strstr ( comment, "_P_")+3; + if ( !strstr (comment, "_P_"))return NULL; + else + { + pdb=string2list ( strstr ( comment, "_P_")+3); + } + + for (a=1; a%s R=%d T=%.2f %s\n%s\n", name, a+1, Threshold, comment, R[a]); + } + else + { + FILE *fp; + char c; + + fp=vfopen (tmpf, "r"); + while ( (c=fgetc(fp))!=EOF)fprintf (stdout, "%c", c); + vfclose (fp); + } + return NULL; +} + +char **struc2nb (char *name,char *seq, char *comment, float Threshold, char *atom, char *output) +{ + char *struc_file; + char *struc_name; + Ca_trace *T; + Atom *A1, *A2; + int a, b; + short **hasch; + FILE *fp; + float d; + char command[10000]; + static char **R; + + struc_file=vtmpnam (NULL); + declare_name (struc_name); + + sscanf ( strstr(comment, "_P_"), "_P_ %s", struc_name); + //struc_name=strstr(name, "_S_"); + + if (!R) + { + int l; + l=strlen (seq); + R=declare_char (l+1, l+1); + for ( a=0; a%s",struc_name,(atom==NULL)?"ALL":atom, struc_file); + } + + my_system (command); + } + T=read_ca_trace (struc_file, "ATOM"); + hasch=declare_short (T->len, T->len); + + if (!R) + { + int l; + l=strlen (seq); + R=declare_char (l+1, l+1); + for ( a=0; an_atom; a++) + for ( b=0; b< T->n_atom; b++) + { + A1=T->structure[a];A2=T->structure[b]; + d=get_atomic_distance (A1, A2); + + if ( dres_num-1][A2->res_num-1]=1; + } + } + fp=vfopen (output, "a"); + fprintf ( fp, "#Distance_map_format_01\n#Sequence %s with T= %.2f", struc_name, Threshold); + for ( a=0; alen; a++) + { + int c; + c=change_residue_coordinate ( T->seq,seq,a); + + if ( c!=-1 && seq) + { + char r1, r2; + r1=(T->seq)[a]; + r2=seq[c]; + r1=tolower(r1);r2=tolower(r2); + if ( r1!=r2) continue; + R[c][c]=toupper (R[c][c]); + fprintf (fp, "\n%s Residue %d ",struc_name,c+1); + for ( b=0; blen; b++) + { + int d; + char r3, r4; + r3=(T->seq)[a];r4=seq[c]; + r3=tolower(r3);r4=tolower(r4); + if ( r3!=r4) continue; + + d=change_residue_coordinate (T->seq,seq,b); + + if ( hasch[a][b] && d!=-1) + { + fprintf (fp, "%d ",d+1); + R[c][d]=toupper (R[c][d]); + } + } + fprintf (fp, ";"); + } + } + free_short (hasch, -1); + fprintf (fp, "\n"); + return R; +} + +short **seq2nb (char *seq, char *pdb, float Threshold, char *atom) +{ + char *struc_file; + + Ca_trace *T; + Atom *A1, *A2; + int a, b; + short **hasch; + short **result; //Contains the result for every residue of seq + float d; + char command[10000]; + + // get a clean pdb file + struc_file=vtmpnam (NULL); + if ( check_file_exists (struc_file) && is_simple_pdb_file(struc_file)) + { + sprintf (command, "cp %s %s", pdb, struc_file); + } + else + { + sprintf ( command, "extract_from_pdb -infile %s -atom %s -mode simple -force >%s",pdb,(atom==NULL)?"ALL":atom, struc_file); + } + my_system (command); + + //Read and hasch the PDB file + T=read_ca_trace (struc_file, "ATOM"); + hasch=declare_short (T->len, T->len); + result=declare_short (strlen (seq)+1, strlen (seq)+1); + for ( a=0; a< T->n_atom; a++) + for ( b=0; b< T->n_atom; b++) + { + A1=T->structure[a];A2=T->structure[b]; + d=get_atomic_distance (A1, A2); + + if ( dres_num-1][A2->res_num-1]=1; + } + } + + for ( a=0; alen; a++) + { + int c; + c=change_residue_coordinate ( T->seq,seq,a); + if ( c!=-1) + { + for ( b=0; blen; b++) + { + int d; + d=change_residue_coordinate (T->seq,seq,b); + + if ( hasch[a][b] && d!=-1) + { + result[c][result[c][0]++]=d; + } + } + } + } + free_short (hasch, -1); + return result; +} +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/scoring.c b/binaries/src/tcoffee/t_coffee_source/scoring.c new file mode 100644 index 0000000..04a89b9 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/scoring.c @@ -0,0 +1,655 @@ + +#include +#include +#include +#include +#include +#include +#include + + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "fastal_lib_header.h" + + + + +/** + * \brief Function to calculate the sum of pairs score with quasi affine gap costs. + * + * \param alignment_file File with the aligned sequences in fasta_format. + * \param file_index Positions of the sequences in \a alignment_file. + * \param number_of_sequences The number of sequences in \a alignment_file. + * \param score_matrix Matrix containing the scores. + * \param gop The gap opening costs. + * \param gep The gep extension costs. + * \return The score of the alignment. + */ +double +calculate_sum_of_pairs_score_affine(char *alignment_file_name, + int **score_matrix, + double gop, + double gep) +{ + + const int LINE_LENGTH = 1000; + int number_of_sequences = 0; + FILE *alignment_file = fopen(alignment_file_name,"r"); + if (alignment_file == NULL) + { + printf("FILE COULD NOT BE OPENED!\n"); + exit(1); + } + int alignment_length = 0; + char line[LINE_LENGTH+1]; + line[0] = '0'; + + while (line[0] != '>') + { + fgets(line, LINE_LENGTH, alignment_file); + } + fgets(line, LINE_LENGTH, alignment_file); + while (line[0] != '>') + { + alignment_length += strlen(line); + fgets(line, LINE_LENGTH, alignment_file); + } + + int alphabet_size = 28; + int **counting = vcalloc(alphabet_size, sizeof(int*)); + + int i; + for (i = 0; i < alphabet_size; ++i) + { + counting[i] = vcalloc(alignment_length, sizeof(int)); + } + + alphabet_size -= 2; + char c; + int was_gap = 0; + int pos_line, pos_alignment = -1; + fseek (alignment_file, 0, SEEK_SET); + pos_line = 0; + + int gap_line = 0; + int current_size = 100; + int gap_size = 0; + int gap_pos = 0; + + int **gaps = vcalloc(100, sizeof(int*)); + + while (fgets(line, LINE_LENGTH, alignment_file) != NULL) + { + if (line[0] != '>') + { + pos_line = -1; + while (((c = line[++pos_line]) != '\n') && (c != '\0')) + { + if (isalpha(c)) + { + ++counting[toupper(c)-'A'][++pos_alignment]; + if (was_gap) + { + gaps[gap_line][gap_pos++] = pos_alignment-1; + } + was_gap = 0; + } + else + { + ++counting[alphabet_size][++pos_alignment]; + if (!was_gap) + { + ++counting[alphabet_size+1][pos_alignment]; + was_gap = 1; + if (gap_pos >= gap_size-4) + { + gap_size += 50; + gaps[gap_line] = vrealloc(gaps[gap_line], gap_size * sizeof(int)); + gaps[gap_line][gap_pos++] = pos_alignment; + } + } + } + } + } + else + { + if (number_of_sequences != 0) + { + if ((gap_pos % 2) != 0) + { + gaps[gap_line][gap_pos++] = pos_alignment-1; + } + gaps[gap_line][gap_pos++] = alignment_length+2; + gaps[gap_line][gap_pos] = alignment_length+2; + ++gap_line; + } + if (current_size == gap_line) + { + current_size += 50; + gaps = vrealloc(gaps, current_size * sizeof(int*)); + } + gap_size = 2; + gaps[gap_line] = vcalloc(gap_size, sizeof(int)); + ++number_of_sequences; + pos_alignment = -1; + was_gap = 0; + + gap_pos = 0; + } + } + + gaps[gap_line][gap_pos++] = alignment_length+2; + gaps[gap_line][gap_pos] = alignment_length+2; + + + long double score = 0; + int j, k, tmp2; + int non_gap; + for (i = 0; i < alignment_length; ++i) + { + for (j = 0; j < alphabet_size; ++j) + { + if ((tmp2 = counting[j][i]) >1) + { + while (tmp2 > 1) + { + score += score_matrix[j][j] * (--tmp2); + } + } + for (k = j+1; k < alphabet_size; ++k) + { + score += score_matrix[j][k] * counting[j][i] * counting[k][i]; + } + + } + + + non_gap = number_of_sequences - counting[alphabet_size][i]; + score += counting[alphabet_size][i] * non_gap * gep; + + } + + ++gap_line; + alignment_length += 2; + unsigned long gap_open = 0; + + int chunk = 500; + +// #pragma omp parallel shared(gaps, chunk, alignment_length, gap_open) private(i, j) + { + int alignment_length2 = alignment_length; +// #pragma omp for schedule(dynamic,chunk) reduction(+:gap_open) nowait + for (i = 0; i < gap_line; ++i) + { + int *gaps1 = gaps[i]; + for (j = i+1; j < gap_line; ++j) + { + int *gaps2 = gaps[j]; + int k = 0; + int l = 0; + while ((gaps1[k] != alignment_length2) && (gaps2[l] != alignment_length2)) + { + if (gaps1[k+1] < gaps2[l]) + { + ++gap_open; + k+=2; + continue; + } + if (gaps2[l+1] < gaps1[k]) + { + ++gap_open; + l+=2; + continue; + } + if (gaps1[k] < gaps2[l]) + { + if (gaps1[k+1] < gaps2[l+1]) + { + ++gap_open; + k+=2; + continue; + } + else + { + l+=2; + continue; + } + } + if (gaps1[k] > gaps2[l]) + { + if (gaps1[k+1] > gaps2[l+1]) + { + ++gap_open; + l+=2; + continue; + } + else + { + k+=2; + continue; + } + } + if (gaps1[k] == gaps2[l]) + { + if (gaps1[k+1] == gaps2[l+1]) + { + k+=2; + l+=2; + continue; + } + else + { + if (gaps1[k+1] ') + break; + fprintf(tmp_file, "%s", line); + } + } + fclose(tmp_file); + + //calculate alignment + char aln_command[1000]; + sprintf(aln_command,"t_coffee -in %s -outfile %s/%i.fa -output fasta_aln 2>/dev/null >/dev/null", tmp_file_name, directory, i); + system(aln_command); + } + + vfree(already_taken); +} + + + +// void +// compute agreement_score(char *alignment_file_name, char *alignment_directory) +// { +// +// } + + + + +/** + * This algorithm choses according to a tree a number of sequenes of which it computes a reference algnment. + * \param seq_file_name The sequence file. + * \param tree_file_name The given tree. + * \param ref_aln_name The file where the reference alignment should be written to. + * \param num_seq_in_ref The number of sequences to choose. +**/ +void +make_ref_alignment(char *seq_file_name, char *tree_file_name, char *ref_aln_name, int num_seq_in_ref) +{ + const int LINE_LENGTH = 200; + char line[LINE_LENGTH]; + + FILE *tree_f = fopen(tree_file_name,"r"); + + + long *file_positions = NULL; + long **tmp = &file_positions; + int num_sequences = make_index_of_file(seq_file_name, tmp); + + + int every_x = num_sequences/(num_seq_in_ref); + + int *seq_ids = vcalloc(num_seq_in_ref,sizeof(int)); + char delims[] = " "; + + int pos = -1; + fseek (tree_f, 0, SEEK_SET); + int node; + int dist = every_x; + while(fgets(line, LINE_LENGTH, tree_f)!=NULL) + { + node = atoi(strtok(line,delims)); + if (node < num_sequences) + { + if (dist == every_x) + { + + seq_ids[++pos] = node; + dist = 0; + } + else + { + ++dist; + } + } + + node = atoi(strtok(NULL,delims)); + if (node < num_sequences) + { + if (dist == every_x) + { + seq_ids[++pos] = node; + dist = 0; + } + else + { + ++dist; + } + } + } + fclose(tree_f); + + + int i = 0; + qsort(seq_ids, num_seq_in_ref, sizeof(int), compare); + + char *seq_ref_name = vtmpnam(NULL); + FILE *seq_ref_f = fopen(seq_ref_name, "w");; + FILE *seq_f = fopen(seq_file_name, "r"); + + for (i = 0; i < num_seq_in_ref; ++i) + { + fseek (seq_f, file_positions[seq_ids[i]], SEEK_SET); + fgets(line, LINE_LENGTH, seq_f); + fprintf(seq_ref_f, "%s", line); + while(fgets(line, LINE_LENGTH, seq_f)!=NULL) + { + if (line[0] == '>') + break; + fprintf(seq_ref_f, "%s", line); + } + } + fclose(seq_ref_f); + fclose(seq_f); + + char command[500]; + sprintf(command, "mafft --quiet %s > %s", seq_ref_name, ref_aln_name); + system(command); +} + + +/** + * This function calculates the agreement between two alignments in a specified number of sequences. + * \param ref_file_name The reference alignment. + * \param aln_file_name The test alignment. + **/ +double +agreement_score(char *ref_file_name, char *aln_file_name) +{ + const int LINE_LENGTH = 200; + char line[LINE_LENGTH]; + + int number_of_sequences = 0; + FILE *ref_f = fopen(ref_file_name,"r"); + while(fgets(line, LINE_LENGTH, ref_f)!=NULL) + { + if (line[0] == '>') + { + ++number_of_sequences; + } + } + fseek(ref_f, 0, SEEK_SET); + char **seq_names = vcalloc(number_of_sequences, sizeof(char*)); + int i = 0; + while(fgets(line, LINE_LENGTH, ref_f)!=NULL) + { + if (line[0] == '>') + { + seq_names[i] = vcalloc(LINE_LENGTH, sizeof(char)); + sprintf(seq_names[i], "%s",line); + ++i; + } + } + + + fclose(ref_f); + FILE *aln_f = fopen(aln_file_name,"r"); + char *tmp_name = vtmpnam(NULL); + FILE *tmp_f = fopen(tmp_name,"w"); + int x = 0; + long last_pos = -1; + while(fgets(line, LINE_LENGTH, aln_f)!=NULL) + { + if (line[0] == '>') + { + for (i = 0; i < number_of_sequences; ++i) + { + if (!strcmp(line, seq_names[i])) + { + fprintf(tmp_f, "%s", line); + last_pos = ftell(aln_f); + while(fgets(line, LINE_LENGTH, aln_f)!=NULL) + { + if (line[0] == '>') + break; + fprintf(tmp_f, "%s", line); + + last_pos = ftell(aln_f); + } + ++x; + fseek(aln_f, last_pos, SEEK_SET); + break; + } + } + } + if (x == number_of_sequences) + break; + } + fclose(aln_f); + fclose(tmp_f); + char command[500]; +// sprintf(command, "cp %s /users/cn/ckemena/Desktop/1.fa", tmp_name); +// system(command); +// fp = popen("ls -l", "r"); + sprintf(command, "t_coffee -other_pg aln_compare -al1 %s -al2 %s ", ref_file_name, tmp_name); + + + FILE *result; + result = popen(command, "r"); + fgets(line, LINE_LENGTH, result); + fgets(line, LINE_LENGTH, result); + fgets(line, LINE_LENGTH, result); + +// sprintf(command, "cp %s ~/Destkop/1.fa", tmp_name); +// system(command); + + char delims[] = " "; + char *tmp_str; + strtok(line, delims); + for (i = 0; i < 3; ++i) + { + while((tmp_str = strtok(NULL, delims))==NULL); + } + return(atof(tmp_str)); +} + + +complete_agreement_score(char *aln_file_name, const char *ref_directory) +{ + struct dirent *dp; + char *name = strrchr(aln_file_name,'/')+1; +// printf("%s ",name); + // enter existing path to directory below + char directory[500]; + if (ref_directory[0]== '~') + { + sprintf(directory,"%s%s",getenv("HOME"),ref_directory+1); + } + else + { + sprintf(directory,"%s",ref_directory); + } + DIR *dir = opendir(directory); + + char ref_file_name[200]; + while ((dp=readdir(dir)) != NULL) + { + if ((strcmp(dp->d_name,".")) && (strcmp(dp->d_name,".."))) + { + + sprintf(ref_file_name, "%s/%s",directory, dp->d_name); + printf("%s %f\n",name, agreement_score(ref_file_name, aln_file_name)); +// printf("%f ", agreement_score(ref_file_name, aln_file_name)); + + } + } + printf("\n"); + closedir(dir); + return 0; + +} + + +// char delims[] = " "; +// int node[3]; +// int alignment_length = -1; +// node[2] = -1; + + + //bottom-up traversal +// while(fgets(line, LINE_LENGTH, tree_file)!=NULL) +// { +// //read profiles +// node[0] = atoi(strtok(line,delims)); +// node[1] = atoi(strtok(NULL,delims)); +// node[2] = atoi(strtok(NULL,delims)); +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/showpair.c b/binaries/src/tcoffee/t_coffee_source/showpair.c new file mode 100644 index 0000000..fafb90e --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/showpair.c @@ -0,0 +1,560 @@ +#include +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" +#include "dp_lib_header.h" + +static void make_p_ptrs(int *tptr, int *pl, int naseq, int l); +static void make_n_ptrs(int *tptr, int *pl, int naseq, int len); +static void put_frag(int fs, int v1, int v2, int flen); +static int frag_rel_pos(int a1, int b1, int a2, int b2); +static void des_quick_sort(int *array1, int *array2, int array_size); +static void pair_align(int seq_no, int l1, int l2); + + +/* +* Prototypes +*/ + +/* +* Global variables +*/ +/*extern int *seqlen_array; + extern char **seq_array; + extern int dna_ktup, dna_window, dna_wind_gap, dna_signif; params for DNA + extern int prot_ktup,prot_window,prot_wind_gap,prot_signif; params for prots + extern int nseqs; + extern Boolean dnaflag; + extern double **tmat; + extern int max_aa; + extern int max_aln_length; +*/ + +static int *seqlen_array; +static char **seq_array; + +static int nseqs; +static int dnaflag; +static int max_aln_length; +static int max_aa; + +static int next; +static int curr_frag,maxsf; +static int **accum; +static int *diag_index; +static char *slopes; + +int ktup,window,wind_gap,signif; /* Pairwise aln. params */ +int *displ; +int *zza, *zzb, *zzc, *zzd; + +static Boolean percent=1; + + +static void make_p_ptrs(int *tptr,int *pl,int naseq,int l) +{ + static int a[10]; + int i,j,limit,code,flag; + int residue; + + /*tptr--> pointer to the last occurence of the same residue or ktuple: + + abcdeabef + + tptr: 0 0 0 0 0 1 2 5 0 + pl[a]=6 + pl[b]=7 + */ + + + for (i=1;i<=ktup;i++) + a[i] = (int) pow((double)(max_aa+1),(double)(i-1)); + + limit = (int) pow((double)(max_aa+1),(double)ktup); + for(i=1;i<=limit;++i) + pl[i]=0; + for(i=1;i<=l;++i) + tptr[i]=0; + + + + for(i=1;i<=(l-ktup+1);++i) { + code=0; + flag=FALSE; + for(j=1;j<=ktup;++j) { + residue = seq_array[naseq][i+j-1]; + if((residue<0) || (residue > max_aa)){ + flag=TRUE; + break; + } + code += ((residue) * a[j]); + } + if(flag) + continue; + ++code; + if(pl[code]!=0)tptr[i]=pl[code]; + pl[code]=i; + } +} + + +static void make_n_ptrs(int *tptr,int *pl,int naseq,int len) +{ + static int pot[]={ 0, 1, 4, 16, 64, 256, 1024, 4096 }; + int i,j,limit,code,flag; + int residue; + + limit = (int) pow((double)4,(double)ktup); + + for(i=1;i<=limit;++i) + pl[i]=0; + for(i=1;i<=len;++i) + tptr[i]=0; + + for(i=1;i<=len-ktup+1;++i) { + code=0; + flag=FALSE; + for(j=1;j<=ktup;++j) { + residue = seq_array[naseq][i+j-1]; + if((residue<0) || (residue>4)){ + flag=TRUE; + break; + } + code += ((residue) * pot[j]); /* DES */ + } + if(flag) + continue; + ++code; + if(pl[code]!=0) + tptr[i]=pl[code]; + pl[code]=i; + } +} + + +static void put_frag(int fs,int v1,int v2,int flen) +{ + int end; + accum[0][curr_frag]=fs; + accum[1][curr_frag]=v1; + accum[2][curr_frag]=v2; + accum[3][curr_frag]=flen; + + if(!maxsf) { + maxsf=1; + accum[4][curr_frag]=0; + return; + } + + if(fs >= accum[0][maxsf]) { + accum[4][curr_frag]=maxsf; + maxsf=curr_frag; + return; + } + else { + next=maxsf; + while(TRUE) { + end=next; + next=accum[4][next]; + if(fs>=accum[0][next]) + break; + } + accum[4][curr_frag]=next; + accum[4][end]=curr_frag; + } +} + + +static int frag_rel_pos(int a1,int b1,int a2,int b2) +{ + int ret; + + ret=FALSE; + if(a1-b1==a2-b2) { + if(a2 0) { + if(lst[p] >= ust[p]) + p--; + else { + i = lst[p] - 1; + j = ust[p]; + pivlin = array1[j]; + while(i < j) { + for(i=i+1; array1[i] < pivlin; i++) + ; + for(j=j-1; j > i; j--) + if(array1[j] <= pivlin) break; + if(i < j) { + temp1 = array1[i]; + array1[i] = array1[j]; + array1[j] = temp1; + + temp2 = array2[i]; + array2[i] = array2[j]; + array2[j] = temp2; + } + } + + j = ust[p]; + + temp1 = array1[i]; + array1[i] = array1[j]; + array1[j] = temp1; + + temp2 = array2[i]; + array2[i] = array2[j]; + array2[j] = temp2; + + if(i-lst[p] < ust[p] - i) { + lst[p+1] = lst[p]; + ust[p+1] = i - 1; + lst[p] = i + 1; + } + else { + lst[p+1] = i + 1; + ust[p+1] = ust[p]; + ust[p] = i - 1; + } + p = p + 1; + } + } + return; + +} + + + + + +static void pair_align(int seq_no,int l1,int l2) +{ + int pot[8],i,j,l,m,flag,limit,pos,tl1,vn1,vn2,flen,osptr,fs; + int tv1,tv2,encrypt,subt1,subt2,rmndr; + int residue; + + if(dnaflag) { + for(i=1;i<=ktup;++i) + pot[i] = (int) pow((double)4,(double)(i-1)); + limit = (int) pow((double)4,(double)ktup); + } + else { + for (i=1;i<=ktup;i++) + pot[i] = (int) pow((double)(max_aa+1),(double)(i-1)); + limit = (int) pow((double)(max_aa+1),(double)ktup); + } + + tl1 = (l1+l2)-1; + + for(i=1;i<=tl1;++i) { + slopes[i]=displ[i]=0; + diag_index[i] = i; + } + + +/* increment diagonal score for each k_tuple match */ +/* Attempt at guessing the best band by looking at identities*/ + + for(i=1;i<=limit;++i) + { + vn1=zzc[i]; + while(TRUE) + { + if(!vn1) break; + vn2=zzd[i]; + while(vn2 != 0) + { + osptr=vn1-vn2+l2; + ++displ[osptr]; /*PLUG THE Pos Dependant Scheme Here!!!! (For Id only)*/ + vn2=zzb[vn2]; + } + vn1=zza[vn1]; + } + } + +/* choose the top SIGNIF diagonals */ + + des_quick_sort(displ, diag_index, tl1); + + j = tl1 - signif + 1; + if(j < 1) j = 1; + +/* flag all diagonals within WINDOW of a top diagonal */ + + for(i=tl1; i>=j; i--) + if(displ[i] > 0) { + pos = diag_index[i]; + l = (1 >pos-window) ? 1 : pos-window; + m = (tl1max_aa)){flag=TRUE; break;}encrypt += ((residue)*pot[j]);} + if(flag) continue; + else flag=FALSE; + + ++encrypt; + vn2=zzd[encrypt]; + + /*now trying to match i-ktup and vn2-ktup*/ + while(TRUE) + { + if(!vn2) + { + flag=TRUE; + break; + } + osptr=i-vn2+l2; /*osptr=Diagonal under investigation*/ + if(slopes[osptr]!=1) /*Get the next diagonal if that one is not flagged*/ + { + vn2=zzb[vn2]; + continue; + } + flen=0; + fs=ktup; + next=maxsf; + + /* A-loop*/ + while(TRUE) + { + if(!next) + { + ++curr_frag; + if(curr_frag>=2*max_aln_length) + { + + return; + } + displ[osptr]=curr_frag; + put_frag(fs,i,vn2,flen); /*sets the coordinates of the fragments*/ + } + else + { + tv1=accum[1][next]; + tv2=accum[2][next]; + if(frag_rel_pos(i,vn2,tv1,tv2)) + { + if(i-vn2==accum[1][next]-accum[2][next]) + { + if(i>accum[1][next]+(ktup-1)) + fs=accum[0][next]+ktup; + else + { + rmndr=i-accum[1][next]; + fs=accum[0][next]+rmndr; + } + flen=next; + next=0; + continue; + } + else + { + if(displ[osptr]==0) + subt1=ktup; + else + { + if(i>accum[1][displ[osptr]]+(ktup-1)) + subt1=accum[0][displ[osptr]]+ktup; + else + { + rmndr=i-accum[1][displ[osptr]]; + subt1=accum[0][displ[osptr]]+rmndr; + } + } + subt2=accum[0][next]-wind_gap+ktup; + if(subt2>subt1) + { + flen=next; + fs=subt2; + } + else + { + flen=displ[osptr]; + fs=subt1; + } + next=0; + continue; + } + + } + else + { + next=accum[4][next]; + continue; + } + } + break; + } + /* + * End of Aloop + */ + + vn2=zzb[vn2]; + } + } + +} + +int ** show_pair(int istart, int iend, int jstart, int jend, int *in_seqlen_array, char **in_seq_array, int dna_ktup, int dna_window, int dna_wind_gap, int dna_signif,int prot_ktup, int prot_window,int prot_wind_gap,int prot_signif, int in_nseqs,int in_dnaflag, int in_max_aa, int in_max_aln_length ) +{ + int i,j,dsr; + double calc_score; + int **tmat; + + seqlen_array=vcalloc ( in_nseqs+1, sizeof(int)); + for ( i=0; i< in_nseqs; i++)seqlen_array[i+1]=in_seqlen_array[i]; + + + seq_array=declare_char ( in_nseqs+1, in_max_aln_length); + for ( i=0; i< in_nseqs; i++)sprintf (seq_array[i+1], "%s",in_seq_array[i]); + + + nseqs=in_nseqs; + dnaflag=in_dnaflag; + max_aa=in_max_aa; + max_aln_length=in_max_aln_length; + + + tmat=declare_int ( nseqs+1, nseqs+1); + accum=declare_int( 5, 2*max_aln_length+1); + + displ = (int *) vcalloc( (2*max_aln_length +1), sizeof (int) ); + slopes = (char *)vcalloc( (2*max_aln_length +1) , sizeof (char)); + diag_index = (int *) vcalloc( (2*max_aln_length +1) , sizeof (int) ); + + zza = (int *)vcalloc( (max_aln_length+1),sizeof (int) ); + zzb = (int *)vcalloc( (max_aln_length+1),sizeof (int) ); + + zzc = (int *)vcalloc( (max_aln_length+1), sizeof (int) ); + zzd = (int *)vcalloc( (max_aln_length+1), sizeof (int) ); + + if(dnaflag) { + ktup = dna_ktup; + window = dna_window; + signif = dna_signif; + wind_gap = dna_wind_gap; + } + else { + ktup = prot_ktup; + window = prot_window; + signif = prot_signif; + wind_gap = prot_wind_gap; + } + + for(i=istart+1;i<=iend;++i) + { + if(dnaflag) + make_n_ptrs(zza,zzc,i,seqlen_array[i]); + else + make_p_ptrs(zza,zzc,i,seqlen_array[i]); + for(j=MAX(jstart+1, i+1);j<=jend;++j) + { + if (i!=j) + { + if(dnaflag) + make_n_ptrs(zzb,zzd,j,seqlen_array[j]); + else + make_p_ptrs(zzb,zzd,j,seqlen_array[j]); + + pair_align(i,seqlen_array[i],seqlen_array[j]); + + if(!maxsf) + calc_score=0.0; + else { + calc_score=(double)accum[0][maxsf]; + if(percent) { + dsr=(seqlen_array[i] %.2f",i, j, (float)calc_score ); + } + } + } + + free_int ( accum, -1); + + vfree(displ); + vfree(slopes); + vfree(diag_index); + + vfree(zza); + vfree(zzb); + vfree(zzc); + vfree(zzd); + return tmat; +} + +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/source_list b/binaries/src/tcoffee/t_coffee_source/source_list new file mode 100644 index 0000000..c47a04e --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/source_list @@ -0,0 +1,55 @@ +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/CUSTOM_evaluate_for_struc.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/aln_compare.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/aln_convertion_util.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/dev1.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/dev2.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/dev3.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/dev4.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/diagonal.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/evaluate.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/evaluate_dirichlet.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/evaluate_for_domain.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/evaluate_for_struc.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/fastal.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/fastal_opt_parsing.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/fsa_dp.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/hsearch.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/io_func.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/iteration.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/parttree.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/pavie_dp.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/pb_util_read_seq_util.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/pb_util_read_sequence.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/random.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/reformat.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/reformat_struc.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/scoring.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/showpair.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/t_coffee.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/tree.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/tree_util.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/util.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/util_aln_analyze.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/util_analyse_constraints_list.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/util_constraints_list.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/util_declare.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/util_domain_constraints_list.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/util_domain_dp.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/util_domain_dp_drivers.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/util_dp_cdna_fasta_nw.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/util_dp_clean_maln.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/util_dp_drivers.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/util_dp_est.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/util_dp_fasta_nw.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/util_dp_fasta_sw.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/util_dp_generic_fasta_nw.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/util_dp_gotoh_nw.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/util_dp_gotoh_sw.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/util_dp_mm_nw.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/util_dp_sim.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/util_dp_ssec_pwaln.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/util_dp_suboptimal_nw.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/util_dps.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/util_graph_maln.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/util_job_handling.c +/Users/admin/tcoffee_ci/sandbox/distributions/T-COFFEE_distribution_Version_8.99/t_coffee_source/util_make_tree.c diff --git a/binaries/src/tcoffee/t_coffee_source/t_coffee b/binaries/src/tcoffee/t_coffee_source/t_coffee new file mode 100644 index 0000000000000000000000000000000000000000..581db9bfaa23a0c348e1e3f646432c863eddb33a GIT binary patch literal 1941017 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

    3bUQSFI_Xw5uvONkgwQ6x(Hke-3O%Qy#Jou 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%0DhpC5h1gihSV-s6k(rX*(R(pqa^n|1eAnTx^| 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

    }t(SAX#n?VEs+ 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

  • 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 +#include +#include +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "dp_lib_header.h" +#include "define_header.h" +#include "t_coffee.h" +static void test(); +static char * get_seq_type_from_cl (int argc, char **argv); +static char *get_defaults(char *buf, char *type); +static char *get_evaluate_defaults(char *buf, char *type); +static char *get_genome_defaults(char *buf, char *type); +static char *get_dali_defaults(char *buf, char *type); +static char *get_mcoffee_defaults(char *buf, char *type); +static char *get_fmcoffee_defaults(char *buf, char *type); +static char *get_t_coffee_defaults(char *buf, char *type); + +static char *get_dmcoffee_defaults(char *buf, char *type); +static char *get_rcoffee_consan_defaults(char *buf, char *type); +static char *get_rmcoffee_defaults(char *buf, char *type);//Original R-Coffee Paper +static char *get_rcoffee_defaults(char *buf, char *type);//Original R-Coffee Paper +static char *get_rmcoffee_defaults_old(char *buf, char *type);//Original R-Coffee Paper +static char *get_rcoffee_defaults_old(char *buf, char *type);//Original R-Coffee Paper +static char *get_best4RNA_defaults(char *buf, char *type); + +static char *get_very_fast_defaults(char *buf, char *type); +static char *get_precomputed_defaults(char *buf, char *type); +static char *get_3dcoffee_defaults(char *buf, char *type); +static char *get_expresso_defaults(char *buf, char *type); + +static char *get_accurate_defaults(char *buf, char *type); +static char *get_accurate4PROTEIN_defaults(char *buf, char *type); +static char *get_accurate4DNA_defaults(char *buf, char *type); +static char *get_accurate4RNA_defaults(char *buf, char *type); + +static char *get_procoffee_defaults(char *buf, char *type); +static char *get_blastr_defaults(char *buf, char *type); +static char *get_psicoffee_defaults(char *buf, char *type); +static char *get_dna_defaults(char *buf, char *type); +static char *get_cdna_defaults(char *buf, char *type); +static char *get_repeat_defaults(char *buf, char *type); +static char *get_low_memory_defaults( char *buf, char *type); + +static char *get_genepredx_defaults(char *buf, char *type); +static char *get_genepredpx_defaults(char *buf, char *type); + +static int set_methods_limits (char **method_limits,int n_methods_limit,char **list_file, int n_list, int *maxnseq, int *maxlen); +static FILE *t_coffee_tip (FILE *fp,char *mode); + +static int run_other_pg(int argc, char *argv[]); + +static Sequence* prepare_master (char *seq,Sequence *S,Constraint_list *CL, char *dmode); + +#define is_a_seq_file(file) (!is_matrix(file) && !is_matrix(file+1) && !is_method (file) && !is_method (file+1) &&(check_file_exists(file) || check_file_exists(file+1))) +static int NO_METHODS_IN_CL; +int batch_main ( int argc, char **argv); +int main (int argc, char *argv[]) +{ + int r, a; + + if (argc>=2 && strcmp (argv[1], "-batch")==0) + { + char **list; + list=file2lines (argv[2]); + for (a=1; a=3 && strm (argv[1], "-other_pg")) + { + //standard_initialisation (NULL,NULL); + return run_other_pg (argc-2, argv+2); + } + +/*PARAMETER PROTOTYPE: READ PARAMETER FILE */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-no_error_report" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Limit the maximum memory usage (in Megabytes). 0: no limit" ,\ + /*Parameter*/ &no_error_report ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +/*PARAMETER PROTOTYPE: READ PARAMETER FILE */ + declare_name (parameters); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-parameters" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "R_F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "get bottom parameters" ,\ + /*Parameter*/ ¶meters ,\ + /*Def 1*/ "NULL" ,\ + /*Def 2*/ "stdin" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + + + special_mode_list1=declare_char (100, STRING); + + n_special_mode1=get_cl_param( \ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-mode" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 100 ,\ + /*DOC*/ "specifies a special mode: genome, quickaln, dali, 3dcoffee" ,\ + /*Parameter*/ special_mode_list1 ,\ + /*Def 1*/ "unspecified" ,\ + /*Def 2*/ "HARD_CODED" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + + + special_mode_list2=declare_char (100, STRING); + n_special_mode2=get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-special_mode" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 100 ,\ + /*DOC*/ "[DEPRECATED ** -special_mode is deprected use -mode instead]" ,\ + /*Parameter*/ special_mode_list2 ,\ + /*Def 1*/ "unspecified" ,\ + /*Def 2*/ "HARD_CODED" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + + special_mode_list=declare_char (n_special_mode1+n_special_mode2, STRING); + n_special_mode=0; + for (a=0; aprompt>special>parameters>defaults*/ + argv=break_list ( argv, &argc, "=;, \n"); + argv=merge_list ( argv, &argc); + if (argc>1 && argv[1][0]!='-')argv=push_string ("-seq ", argv, &argc, 1); + + if ( name_is_in_list ("-method",argv, argc,100)==-1) + { + NO_METHODS_IN_CL=1; + } + +if (t_coffee_defaults_flag) + { + char *pname=NULL; + + pname=getenv ( "TCOFFEE_DEFAULTS"); + + if (check_file_exists ( t_coffee_defaults))pname=t_coffee_defaults; + else if ( getenv ( "TCOFFEE_DEFAULTS")) + { + pname=getenv ( "TCOFFEE_DEFAULTS"); + if (check_file_exists(pname)); + else pname=NULL; + } + else + { + declare_name(pname);sprintf (pname, "%s/.t_coffee_defaults",getenv ( "HOME") ); + if (!check_file_exists (pname)){vfree(pname);pname=NULL;} + } + + if (pname) + { + argv=push_string (file2string(pname), argv, &argc, 1); + t_coffee_defaults=pname; + } + else + { + t_coffee_defaults=NULL; + } + } + + if ( parameters && parameters[0])argv=push_string (file2string (parameters), argv, &argc, 1); + + + if (n_special_mode && !type_only) + { + char *special_mode; + char *lseq_type; + declare_name(lseq_type); + if (type && !strm (type, "")) + sprintf (lseq_type,"%s",type); + else + sprintf (lseq_type,"%s",get_seq_type_from_cl (argc, argv)); + + for ( a=0; a< n_special_mode; a++) + { + char *new_arg=NULL; + + special_mode=special_mode_list[a]; + + store_mode (special_mode); + + + if (special_mode && !special_mode[0]); + else if ( strm (special_mode, "genepredx"))new_arg=get_genepredx_defaults(NULL,lseq_type); + else if ( strm (special_mode, "genepredpx"))new_arg=get_genepredpx_defaults(NULL,lseq_type); + + else if ( strm (special_mode, "regular") || strm (special_mode, "regular_fast")|| strm (special_mode, "default"))new_arg=get_defaults (NULL,lseq_type); + else if ( strm (special_mode, "genome"))new_arg=get_genome_defaults(NULL,lseq_type); + else if ( strm (special_mode, "quickaln"))new_arg=get_very_fast_defaults(NULL,lseq_type); + else if ( strm (special_mode, "dali"))new_arg=get_dali_defaults(NULL,lseq_type); + else if ( strm (special_mode, "evaluate"))new_arg=get_evaluate_defaults(NULL,lseq_type); + else if ( strm (special_mode, "precomputed"))new_arg=get_precomputed_defaults(NULL,lseq_type); + else if ( strm (special_mode, "3dcoffee"))new_arg=get_3dcoffee_defaults(NULL,lseq_type); + else if ( strm (special_mode, "expresso"))new_arg=get_expresso_defaults(NULL,lseq_type); + else if ( strm (special_mode, "repeats"))new_arg=get_repeat_defaults(NULL,lseq_type); + else if ( strm (special_mode, "psicoffee"))new_arg=get_psicoffee_defaults(NULL,lseq_type); + else if ( strm (special_mode, "procoffee"))new_arg=get_procoffee_defaults(NULL,lseq_type); + else if ( strm (special_mode, "blastr"))new_arg=get_blastr_defaults(NULL,lseq_type); + + else if ( strm (special_mode, "accurate") || strm (special_mode, "accurate_slow") || strm (special_mode, "psicoffee_expresso"))new_arg=get_accurate_defaults(NULL, lseq_type); + else if ( strm (special_mode, "accurate4DNA"))new_arg=get_accurate4DNA_defaults(NULL,lseq_type); + else if ( strm (special_mode, "accurate4RNA"))new_arg=get_accurate4RNA_defaults(NULL,lseq_type); + else if ( strm (special_mode, "best4RNA"))new_arg=get_best4RNA_defaults(NULL,lseq_type); + else if ( strm (special_mode, "accurate4PROTEIN"))new_arg=get_accurate4PROTEIN_defaults(NULL,lseq_type); + + else if ( strm (special_mode, "low_memory") || strm (special_mode, "memory"))new_arg=get_low_memory_defaults(NULL,lseq_type); + + + else if ( strm (special_mode, "dna"))new_arg=get_dna_defaults(NULL,lseq_type); + else if ( strm (special_mode, "cdna"))new_arg=get_dna_defaults(NULL,lseq_type); + else if ( strm (special_mode, "protein"))new_arg=get_low_memory_defaults(NULL,lseq_type); + else if ( strm (special_mode, "mcoffee"))new_arg=get_mcoffee_defaults(NULL,lseq_type); + else if ( strm (special_mode, "dmcoffee"))new_arg=get_dmcoffee_defaults(NULL,lseq_type); + else if ( strm (special_mode, "fmcoffee"))new_arg=get_fmcoffee_defaults(NULL,lseq_type); + + else if ( strm (special_mode, "rcoffee_consan"))new_arg=get_rcoffee_consan_defaults(NULL,lseq_type); + else if ( strm (special_mode, "rmcoffee") ||strm (special_mode, "mrcoffee") )new_arg=get_rmcoffee_defaults(NULL,lseq_type); + else if ( strm (special_mode, "rcoffee"))new_arg=get_rcoffee_defaults(NULL,lseq_type); + + else if ( strm (special_mode, "rcoffee_slow_accurate"))new_arg=get_rcoffee_consan_defaults(NULL,lseq_type); + else if ( strm (special_mode, "rcoffee_fast_approximate"))new_arg=get_rmcoffee_defaults(NULL,lseq_type); + else if ( strm (special_mode, "t_coffee"))new_arg=get_t_coffee_defaults(NULL,lseq_type); + + + else if ( strm (special_mode, "unspecified")); + else + { + fprintf ( stderr, "\nERROR: special_mode %s is unknown [FATAL:%s]\n",special_mode, PROGRAM); + myexit (EXIT_FAILURE); + } + + if (new_arg)argv=push_string (new_arg, argv, &argc, 1); + } + } + +if ( getenv ("TCOFFEE_EXTRA_PARAM"))argv=push_string (getenv ("TCOFFEE_EXTRA_PARAM"), argv, &argc, argc); + + +argv=break_list ( argv, &argc, "=;, \n"); +argv=merge_list ( argv, &argc); +/*check_cl4t_coffee ( argc, argv); */ + + +/*PARAMETER PROTOTYPE: VERSION */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-version" ,\ + /*Flag*/ &do_version ,\ + /*TYPE*/ "FL" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "forces the program to output the version number and exit" ,\ + /*Parameter*/ &do_version ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "0" ,\ + /*Max Value*/ "1" \ + ); + + + +/*PARAMETER PROTOTYPE: DO EVALUATE */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-score" ,\ + /*Flag*/ &do_evaluate ,\ + /*TYPE*/ "FL" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "DEPRECATED: use -special_mode evaluate instead " ,\ + /*Parameter*/ &do_evaluate ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "0" ,\ + /*Max Value*/ "1" \ + ); +if ( !do_evaluate) + { +/*PARAMETER PROTOTYPE: DO EVALUATE */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-evaluate" ,\ + /*Flag*/ &do_evaluate ,\ + /*TYPE*/ "FL" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Use -special_mode evaluate for a default behavior " ,\ + /*Parameter*/ &do_evaluate ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "0" ,\ + /*Max Value*/ "1" \ + ); + } +/*PARAMETER PROTOTYPE: DO EVALUATE */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-genepred" ,\ + /*Flag*/ &do_genepred ,\ + /*TYPE*/ "FL" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Use -special_mode genepred for a default behavior " ,\ + /*Parameter*/ &do_genepred ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "0" ,\ + /*Max Value*/ "1" \ + ); +/*PARAMETER PROTOTYPE: DO FORMAT */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-convert" ,\ + /*Flag*/ &do_convert ,\ + /*TYPE*/ "FL" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "forces the program to make a conversion" ,\ + /*Parameter*/ &do_convert ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "0" ,\ + /*Max Value*/ "1" \ + ); + + + +/*PARAMETER PROTOTYPE*/ + + declare_name (se_name); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-quiet" ,\ + /*Flag*/ &quiet ,\ + /*TYPE*/ "W_F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Defines the file in which the log output is written" ,\ + /*Parameter*/ &se_name ,\ + /*Def 1*/ "stderr" ,\ + /*Def 2*/ "/dev/null" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + if (type_only==1)sprintf ( se_name, "/dev/null"); + + /*PARAMETER PROTOTYPE: DO FORMAT */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-check_configuration" ,\ + /*Flag*/ &check_configuration ,\ + /*TYPE*/ "FL" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "checks that the required programs are installed" ,\ + /*Parameter*/ &check_configuration ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "0" ,\ + /*Max Value*/ "1" \ + ); + /*PARAMETER PROTOTYPE: UPDATE */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-update" ,\ + /*Flag*/ &update,\ + /*TYPE*/ "FL" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "checks the existence of an updated version" ,\ + /*Parameter*/ &update ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "0" ,\ + /*Max Value*/ "1" \ + ); + + + + if ( check_configuration) + { + + check_configuration4program(); + return EXIT_SUCCESS; + + } + if ( update) + { + myexit (check_for_update(DISTRIBUTION_ADDRESS)); + } + if ( do_version) + { + fprintf ( stdout, "PROGRAM: %s (%s)\n",PROGRAM,VERSION); + return EXIT_SUCCESS; + } + + + le=vfopen ( se_name, "w"); + fprintf ( le, "\nPROGRAM: %s (%s)\n",PROGRAM,VERSION); + +/*PARAMETER PROTOTYPE: RUN NAME*/ + declare_name (full_log); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-full_log" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Sets the prefix of all the output files" ,\ + /*Parameter*/ &full_log ,\ + /*Def 1*/ "NULL" ,\ + /*Def 2*/ "full_log" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + vremove(full_log); +/*PARAMETER PROTOTYPE: RUN NAME*/ + declare_name (genepred_score); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-genepred_score" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "nsd,tot, " ,\ + /*Parameter*/ &genepred_score ,\ + /*Def 1*/ "nsd" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +/*PARAMETER PROTOTYPE: RUN NAME*/ + declare_name (run_name); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-run_name" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Sets the prefix of all the output files" ,\ + /*Parameter*/ &run_name ,\ + /*Def 1*/ "NULL" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +/*PARAMETER PROTOTYPE: MEM MODE*/ + declare_name(mem_mode); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-mem_mode" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Deprecated" ,\ + /*Parameter*/ &mem_mode ,\ + /*Def 1*/ "mem" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +/*PARAMETER PROTOTYPE: EXTEND */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-extend" ,\ + /*Flag*/ &do_extend ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Do Library Extention On the Fly" ,\ + /*Parameter*/ &do_extend ,\ + /*Def 1*/ "1" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +/*PARAMETER PROTOTYPE: EXTEND */ + declare_name (extend_mode); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-extend_mode" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Library extension mode" ,\ + /*Parameter*/ &extend_mode ,\ + /*Def 1*/ "very_fast_triplet" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + /*PARAMETER PROTOTYPE: EXTEND */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-max_n_pair" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Indicates the Number of Pairs to Compare when making prf Vs prf. 0<=>every pair " ,\ + /*Parameter*/ &max_n_pair ,\ + /*Def 1*/ "10" ,\ + /*Def 2*/ "3" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +/*PARAMETER PROTOTYPE: SEQUENCES TO EXTEND */ + seq_name_for_quadruplet=declare_char ( 200, STRING); + nseq_for_quadruplet=get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-seq_name_for_quadruplet" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 200 ,\ + /*DOC*/ "Indicates which sequence must be used to compute quadruplets" ,\ + /*Parameter*/ seq_name_for_quadruplet ,\ + /*Def 1*/ "all",\ + /*Def 2*/ "" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +/*PARAMETER PROTOTYPE: COMPACT */ + declare_name (compact_mode); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-compact" ,\ + /*Flag*/ &do_compact ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Deprecated" ,\ + /*Parameter*/ &compact_mode ,\ + /*Def 1*/ "default" ,\ + /*Def 2*/ "default" ,\ + /*Min_value*/ "0" ,\ + /*Max Value*/ "1" \ + ); + + +/*PARAMETER PROTOTYPE: CLEAN*/ + declare_name ( clean_mode); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-clean" ,\ + /*Flag*/ &do_clean ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Deprecated" ,\ + /*Parameter*/ &clean_mode ,\ + /*Def 1*/ "no" ,\ + /*Def 2*/ "shadow" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +/*PARAMETER PROTOTYPE: DO SELF */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-do_self" ,\ + /*Flag*/ &do_self ,\ + /*TYPE*/ "FL" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 0 ,\ + /*DOC*/ "Make self extension. Used by Mocca" ,\ + /*Parameter*/ &do_self ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "0" ,\ + /*Max Value*/ "1" \ + ); + +/*PARAMETER PROTOTYPE: DO NORMALISE */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-do_normalise" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Normalisation factor when computing scores" ,\ + /*Parameter*/ &do_normalise ,\ + /*Def 1*/ "1000" ,\ + /*Def 2*/ "1000" ,\ + /*Min_value*/ "-10000" ,\ + /*Max Value*/ "10000" \ + ); +/*PARAMETER PROTOTYPE: IN */ + template_file_list=declare_char (100, STRING); + n_template_file=get_cl_param( \ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-template_file" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1000 ,\ + /*DOC*/ "List of templates file for the sequences",\ + /*Parameter*/ template_file_list , \ + /*Def 1*/ "",\ + /*Def 2*/ "stdin" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +/*PARAMETER PROTOTYPE: VERSION */ + setenv_list=declare_char (100, STRING); + n_setenv=get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-setenv" ,\ + /*Flag*/ &do_version ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 2 ,\ + /*DOC*/ "Declares a parameter variable" ,\ + /*Parameter*/ setenv_list , \ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "0" ,\ + /*Max Value*/ "1" \ + ); +/*PARAMETER PROTOTYPE: IN */ + template_mode_list=declare_char (100, STRING); + n_template_mode=get_cl_param( \ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-template_mode" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1000 ,\ + /*DOC*/ "List of template procedures",\ + /*Parameter*/ template_mode_list , \ + /*Def 1*/ "",\ + /*Def 2*/ "stdin" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + for (a=0; a_sim1, _sim2, _sim3, _cov, _gap" ,\ + /*Parameter*/ &distance_matrix_sim_mode ,\ + /*Def 1*/ "idmat_sim1" ,\ + /*Def 2*/ "idmat_sim1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +/*PARAMETER PROTOTYPE: OUT_LIB */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-quicktree" ,\ + /*Flag*/ &quicktree ,\ + /*TYPE*/ "FL" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 0 ,\ + /*DOC*/ "Use distance_matrix_mode=very_fast" ,\ + /*Parameter*/ &quicktree ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + if ( quicktree)sprintf ( distance_matrix_mode, "very_fast"); +/*PARAMETER PROTOTYPE: OUTFILE */ + declare_name ( out_aln); + tot_out_aln=declare_char (200, STRING); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-outfile" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "W_F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Name of the output alignment" ,\ + /*Parameter*/ &out_aln ,\ + /*Def 1*/ "default" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +/*PARAMETER PROTOTYPE: MAXIMISE */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-maximise" ,\ + /*Flag*/ &maximise ,\ + /*TYPE*/ "FL" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 0 ,\ + /*DOC*/ "Deprecated" ,\ + /*Parameter*/ &maximise ,\ + /*Def 1*/ "1" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +/*PARAMETER PROTOTYPE: OUTPUT_FORMAT */ + out_aln_format=declare_char ( 200, STRING); + n_out_aln_format=get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-output" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 200 ,\ + /*DOC*/ "Specifies one or many formats that must be output: clustalw_aln, msf_aln. The file extension is the output format" ,\ + /*Parameter*/ out_aln_format,\ + /*Def 1*/ "aln,html" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +/*PARAMETER PROTOTYPE: INFILE */ + declare_name (infile); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-infile" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "R_F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "input a pre-computed alignment, or a file to reformat" ,\ + /*Parameter*/ &infile ,\ + /*Def 1*/ "" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +/*PARAMETER PROTOTYPE: INFILE */ + declare_name (matrix); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-matrix" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Specifies the substitution matrix.",\ + /*Parameter*/ &matrix ,\ + /*Def 1*/ "default" ,\ + /*Def 2*/ "default" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +/*PARAMETER PROTOTYPE: TG_MODE */ + + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-tg_mode" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "0: Penalise Term gap with gapopen and gapext\n1: gapopen only\n2: No penalty\n",\ + /*Parameter*/ &tg_mode ,\ + /*Def 1*/ "1",\ + /*Def 2*/ "0",\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +/*PARAMETER PROTOTYPE: DP_MODE */ + declare_name (profile_mode); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-profile_mode" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Function used to compute profile2profile scores",\ + /*Parameter*/ &profile_mode ,\ + /*Def 1*/ "cw_profile_profile",\ + /*Def 2*/ "cw_profile_profile",\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + + declare_name (profile_comparison); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-profile_comparison" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Method used to compare two profiles: full: compares pair of sequence and every pair of structure if a structure method is used,profile: compares only the profiles. ",\ + /*Parameter*/ &profile_comparison ,\ + /*Def 1*/ "profile",\ + /*Def 2*/ "full50",\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +/*PARAMETER PROTOTYPE: DP_MODE */ + declare_name (dp_mode); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-dp_mode" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Type of alignment algorithm used by T-Coffee: gotoh_pair_wise, myers_millers_pair_wise, " ,\ + /*Parameter*/ &dp_mode ,\ + /*Def 1*/ "linked_pair_wise",\ + /*Def 2*/ "cfasta_pair_wise",\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +/*PARAMETER PROTOTYPE: KTUP */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-ktuple" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Word size when using the heursitic dynamic programming modes fasta_pair_wise and cfasta_pair_wise " ,\ + /*Parameter*/ &ktup ,\ + /*Def 1*/ "1",\ + /*Def 2*/ "1",\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +/*PARAMETER PROTOTYPE: FASTA_STEP */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-ndiag" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Number of diagonals to consider when using the heursitic dynamic programming modes fasta_pair_wise and cfasta_pair_wise" ,\ + /*Parameter*/ &fasta_step ,\ + /*Def 1*/ "0",\ + /*Def 2*/ "10",\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +/*PARAMETER PROTOTYPE: FASTA_STEP */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-diag_threshold" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "ND" ,\ + /*Parameter*/ &diag_threshold ,\ + /*Def 1*/ "0",\ + /*Def 2*/ "10",\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +/*PARAMETER PROTOTYPE: diag_mode */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-diag_mode" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "0: Use the whole Diag\n1: Use the best match\n" ,\ + /*Parameter*/ &diag_mode ,\ + /*Def 1*/ "0",\ + /*Def 2*/ "1", + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +/*PARAMETER PROTOTYPE: SIM_MATRIX */ + declare_name (sim_matrix); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-sim_matrix" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Degenerated matrix used to compute a similarity" ,\ + /*Parameter*/ &sim_matrix ,\ + /*Def 1*/ "vasiliky",\ + /*Def 2*/ "idmat",\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +/*PARAMETER PROTOTYPE: INFILE */ + declare_name (transform); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-transform" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "dna2rna, rna2dna, dna2prot", \ + /*Parameter*/ &transform ,\ + /*Def 1*/ "" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +/*PARAMETER PROTOTYPE: INFILE */ + get_cl_param( \ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-extend_seq" ,\ + /*Flag*/ &extend_seq ,\ + /*TYPE*/ "FL" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 0 ,\ + /*DOC*/ "extend the sequences", \ + /*Parameter*/ &extend_seq ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +/*PARAMETER PROTOTYPE: INFILE */ + declare_name (outorder); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-outorder" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Specifies the order of the sequences in the msa: input or aligned" ,\ + /*Parameter*/ &outorder ,\ + /*Def 1*/ "input" ,\ + /*Def 2*/ "input" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +/*PARAMETER PROTOTYPE: INFILE */ + declare_name (inorder); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-inorder" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "aligned: sort the sequences in alphabetic order before starting thus making the input order irrelevant but delivering a library in arbitratry order, keep: input order is used in the library but results become input order dependant" ,\ + /*Parameter*/ &inorder ,\ + /*Def 1*/ "aligned" ,\ + /*Def 2*/ "input" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +/*PARAMETER PROTOTYPE: INFILE */ + declare_name (output_res_num); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-seqnos" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Adds Residue Numbers to the MSA" ,\ + /*Parameter*/ &output_res_num ,\ + /*Def 1*/ "off" ,\ + /*Def 2*/ "on" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +/*PARAMETER PROTOTYPE: INFILE */ + declare_name (residue_case); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-case" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Causes the case to be: kept:lower:upper." ,\ + /*Parameter*/ &residue_case ,\ + /*Def 1*/ "keep" ,\ + /*Def 2*/ "upper" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +/*PARAMETER PROTOTYPE: CPU */ + + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-cpu" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Makes it possible to add a pre-specified amount of cpu time to the measured usage" ,\ + /*Parameter*/ &extra_cpu ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "0" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +/*PARAMETER PROTOTYPE: MAXNSEQ */ + + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-maxnseq" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Maximum number of sequences (-1=no max)" ,\ + /*Parameter*/ &maxnseq ,\ + /*Def 1*/ "1000" ,\ + /*Def 2*/ "0" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +/*PARAMETER PROTOTYPE: MAXLEN */ + + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-maxlen" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Maximum length of a sequence (-1=no max)" ,\ + /*Parameter*/ &maxlen ,\ + /*Def 1*/ "-1" ,\ + /*Def 2*/ "-1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +/*PARAMETER PROTOTYPE: WEIGHT */ + + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-sample_dp" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "defines the tie breaking strategy (only with gotoh_pair_wise)" ,\ + /*Parameter*/ &sample_dp ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "0" ,\ + /*Max Value*/ "2" \ + ); + if ( sample_dp)cputenv ("SAMPLE_DP_4_TCOFFEE=%d", sample_dp); + + +/*PARAMETER PROTOTYPE: WEIGHT */ + declare_name ( weight); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-weight" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Defines the library weight: sim OR sim_(matrix) OR winsim" ,\ + /*Parameter*/ &weight ,\ + /*Def 1*/ "default" ,\ + /*Def 2*/ "sim" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); /*PARAMETER PROTOTYPE: WEIGHT */ + declare_name ( seq_weight); + + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-seq_weight" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Defines the sequences weighting scheme t_coffee" ,\ + /*Parameter*/ &seq_weight ,\ + /*Def 1*/ "t_coffee" ,\ + /*Def 2*/ "t_coffee" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +/*PARAMETER PROTOTYPE: DO ALIGN */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-align" ,\ + /*Flag*/ &do_align ,\ + /*TYPE*/ "FL" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 0 ,\ + /*DOC*/ "forces the program to make the alignment" ,\ + /*Parameter*/ &do_align ,\ + /*Def 1*/ "1" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +/*PARAMETER PROTOTYPE: DO DOMAIN */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-mocca" ,\ + /*Flag*/ &do_domain ,\ + /*TYPE*/ "FL" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 0 ,\ + /*DOC*/ "forces the program to extract domains" ,\ + /*Parameter*/ &do_domain ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + if ( !do_domain) + { +/*PARAMETER PROTOTYPE: DO DOMAIN */ + get_cl_param( \ + /*argc*/ argc , \ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-domain" ,\ + /*Flag*/ &do_domain ,\ + /*TYPE*/ "FL" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 0 ,\ + /*DOC*/ "forces the program to extract domains" ,\ + /*Parameter*/ &do_domain ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + } +/*PARAMETER PROTOTYPE: Domain Param */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-start" ,\ + /*Flag*/ &domain_start ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "start of the master domain in the mocca mode" ,\ + /*Parameter*/ &domain_start ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-len" ,\ + /*Flag*/ &domain_len ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "length of the master domain in the mocca mode" ,\ + /*Parameter*/ &domain_len ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-scale" ,\ + /*Flag*/ &domain_scale ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Decreases the t_coffee score by Scale, so that non match get negative values" ,\ + /*Parameter*/ &domain_scale ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-mocca_interactive" ,\ + /*Flag*/ &domain_interactive ,\ + /*TYPE*/ "FL" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 0 ,\ + /*DOC*/ "Runs Mocca in an interactive manneer" ,\ + /*Parameter*/ &domain_interactive,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +/*PARAMETER PROTOTYPE: WEIGHT */ + declare_name (method_evaluate_mode); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-method_evaluate_mode" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Specifies which method should be used to evaluate the score at the pairwise level" ,\ + /*Parameter*/ &method_evaluate_mode ,\ + /*Def 1*/ "default" ,\ + /*Def 2*/ "default" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + /*PARAMETER PROTOTYPE: WEIGHT */ + declare_name (evaluate_mode); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-evaluate_mode" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Mode used to produce the color output:t_coffee_fast,t_coffee_slow " ,\ + /*Parameter*/ &evaluate_mode ,\ + /*Def 1*/ "triplet" ,\ + /*Def 2*/ "dali" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-get_type" ,\ + /*Flag*/ &get_type ,\ + /*TYPE*/ "FL" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "forces t_coffee top get the type of the sequences" ,\ + /*Parameter*/ &get_type ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "0" ,\ + /*Max Value*/ "1" \ + ); + +get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-clean_aln" ,\ + /*Flag*/ &clean_aln ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Forces weak portion of aln to be realigned" ,\ + /*Parameter*/ &clean_aln ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "0" ,\ + /*Max Value*/ "1" \ + ); +get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-clean_threshold" ,\ + /*Flag*/ &clean_threshold ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Threshold for the portions of the MSA that will are realigned by '-clean_evaluate_mode'. The threshold refers to the CORE score set by '-evaluate_mode'" ,\ + /*Parameter*/ &clean_threshold ,\ + /*Def 1*/ "1" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-clean_iteration" ,\ + /*Flag*/ &clean_iteration ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Number of rounds for '-clean_aln'" ,\ + /*Parameter*/ &clean_iteration ,\ + /*Def 1*/ "1" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +declare_name (clean_evaluate_mode); +get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-clean_evaluate_mode" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Mode used to score residues (see evaluate_mode)" ,\ + /*Parameter*/ &clean_evaluate_mode ,\ + /*Def 1*/ "t_coffee_fast" ,\ + /*Def 2*/ "t_coffee_fast" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +/*PARAMETER PROTOTYPE: DO EXTENDED MATRIX */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-extend_matrix" ,\ + /*Flag*/ &do_extended_matrix ,\ + /*TYPE*/ "FL" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 0 ,\ + /*DOC*/ "Deprecated" ,\ + /*Parameter*/ &do_extended_matrix ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-prot_min_sim" ,\ + /*Flag*/ &prot_min_sim ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Minimum similarity between a sequence and its BLAST relatives" ,\ + /*Parameter*/ &prot_min_sim ,\ + /*Def 1*/ "40" ,\ + /*Def 2*/ "20" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + set_int_variable ("prot_min_sim", prot_min_sim); + +get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-prot_max_sim" ,\ + /*Flag*/ &prot_max_sim ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Maximum similarity between a sequence and its BLAST relatives" ,\ + /*Parameter*/ &prot_max_sim ,\ + /*Def 1*/ "90" ,\ + /*Def 2*/ "100" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + set_int_variable ("prot_max_sim", prot_max_sim); + +get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-prot_min_cov" ,\ + /*Flag*/ &prot_min_cov ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Minimum coverage of a sequence by its BLAST relatives" ,\ + /*Parameter*/ &prot_min_cov ,\ + /*Def 1*/ "40" ,\ + /*Def 2*/ "0" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +set_int_variable ("prot_min_cov", prot_min_cov); +declare_name(pdb_type); +get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-pdb_type" ,\ + /*Flag*/ &pdb_min_sim ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "d: diffraction, n: nmr, m:model" ,\ + /*Parameter*/ &pdb_type ,\ + /*Def 1*/ "d" ,\ + /*Def 2*/ "d" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +set_string_variable ("pdb_type", pdb_type); +get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-pdb_min_sim" ,\ + /*Flag*/ &pdb_min_sim ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Minimum similarity between a sequence and its PDB target" ,\ + /*Parameter*/ &pdb_min_sim ,\ + /*Def 1*/ "35" ,\ + /*Def 2*/ "35" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + + set_int_variable ("pdb_min_sim", pdb_min_sim); + get_cl_param( \ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-pdb_max_sim" ,\ + /*Flag*/ &pdb_max_sim ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Maximum similarity between a sequence and its PDB target" ,\ + /*Parameter*/ &pdb_max_sim ,\ + /*Def 1*/ "100" ,\ + /*Def 2*/ "0" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + set_int_variable ("pdb_max_sim", pdb_max_sim); + get_cl_param( \ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-pdb_min_cov" ,\ + /*Flag*/ &pdb_min_cov ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Minimum coverage of a sequence by its PDB target" ,\ + /*Parameter*/ &pdb_min_cov ,\ + /*Def 1*/ "50" ,\ + /*Def 2*/ "25" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +set_int_variable ("pdb_min_cov", pdb_min_cov); + + + +declare_name (pdb_blast_server); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-pdb_blast_server" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "W_F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "ND" ,\ + /*Parameter*/&pdb_blast_server ,\ + /*Def 1*/ "EBI" ,\ + /*Def 2*/ "default" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +declare_name (prot_blast_server); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-blast" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "W_F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "ND" ,\ + /*Parameter*/&prot_blast_server ,\ + /*Def 1*/ "" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + //make sure that -blast and -blast_server are both supported blast>blast_server + if ( !prot_blast_server[0]) + { + get_cl_param( \ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-blast_server" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "W_F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "ND" ,\ + /*Parameter*/&prot_blast_server ,\ + /*Def 1*/ "EBI" ,\ + /*Def 2*/ "default" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + } + // HERE ("%s", blast_server); + if ( strm (prot_blast_server, "env"))prot_blast_server=get_env_variable ("blast_server_4_TCOFFEE",IS_FATAL); + set_string_variable ("blast_server", prot_blast_server); + + + + declare_name (pdb_db); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-pdb_db" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "W_F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Non Redundant PDB database" ,\ + /*Parameter*/&pdb_db ,\ + /*Def 1*/ "pdb" ,\ + /*Def 2*/ "default" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + if ( strm (pdb_db, "env"))pdb_db=get_env_variable ("pdb_db_4_TCOFFEE", IS_FATAL); + set_string_variable ("pdb_db", pdb_db); + + +declare_name (prot_db); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-protein_db" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "W_F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "ND" ,\ + /*Parameter*/&prot_db ,\ + /*Def 1*/ "uniprot" ,\ + /*Def 2*/ "default" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + if ( strm (prot_db, "env"))prot_db=get_env_variable ("protein_db_4_TCOFFEE", IS_FATAL); + set_string_variable ("prot_db", prot_db); + + declare_name (method_log); + get_cl_param( \ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-method_log" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "W_F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "ND" ,\ + /*Parameter*/&method_log ,\ + /*Def 1*/ "no" ,\ + /*Def 2*/ "default" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +/*PARAMETER PROTOTYPE: IN */ + struc_to_use=declare_char ( 200, STRING); + n_struc_to_use=get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-struc_to_use" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 200 ,\ + /*DOC*/ "Specifies the structures that must be used when combining sequences and structures. The default is to use all the structures." ,\ + /*Parameter*/ struc_to_use ,\ + /*Def 1*/ "",\ + /*Def 2*/ "stdin" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +declare_name (cache); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-cache" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "W_F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Specifies that a cache must be used to save the structures and their comparison, as well as the blast searches.\navailable modes are: use,ignore,update,local, directory name" ,\ + /*Parameter*/ &cache ,\ + /*Def 1*/ "use" ,\ + /*Def 2*/ "update" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +declare_name (align_pdb_param_file); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-align_pdb_param_file" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "W_F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "parameter_file" ,\ + /*Parameter*/ &align_pdb_param_file ,\ + /*Def 1*/ "no" ,\ + /*Def 2*/ "no" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +declare_name (align_pdb_hasch_mode); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-align_pdb_hasch_mode" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "W_F" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "parameter_file" ,\ + /*Parameter*/ &align_pdb_hasch_mode ,\ + /*Def 1*/ "hasch_ca_trace_bubble" ,\ + /*Def 2*/ "hasch_ca_trace_bubble" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +declare_name (use_seqan); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-external_aligner" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Use seqan to compute the MSA",\ + /*Parameter*/ &use_seqan ,\ + /*Def 1*/ "NO" ,\ + /*Def 2*/ "seqan_tcoffee" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +declare_name (msa_mode); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-msa_mode" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Algorithm used to compute the MSA: tree | graph" ,\ + /*Parameter*/ &msa_mode ,\ + /*Def 1*/ "tree" ,\ + /*Def 2*/ "tree" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +declare_name (master_mode); +get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-master" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Align all the sequences to the master sequences: file or number" ,\ + /*Parameter*/ &master_mode ,\ + /*Def 1*/ "no" ,\ + /*Def 2*/ "_LONG_N_10" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + get_cl_param( \ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-blast_nseq" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Maximum number of querries for BLAST (0: all)" ,\ + /*Parameter*/ &blast_maxnseq ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "0" ,\ + /*Min_value*/ "0" ,\ + /*Max Value*/ "any" \ + ); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-lalign_n_top" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Number of local alignments reported by the local method (lalign) when building the library" ,\ + /*Parameter*/ &lalign_n_top ,\ + /*Def 1*/ "10" ,\ + /*Def 2*/ "10" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-iterate" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "NUmber of iteration on the progressive alignment [0: no iteration, -1: Nseq iterations]",\ + /*Parameter*/ &iterate ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "100" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-trim" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "trim dataset",\ + /*Parameter*/ &trim ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-split" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "split dataset",\ + /*Parameter*/ &split ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +declare_name(trimfile); +get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-trimfile" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "trim dataset filename",\ + /*Parameter*/ &trimfile ,\ + /*Def 1*/ "default" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-split" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "split dataset",\ + /*Parameter*/ &split ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + +if (trim && !split)split=trim; + +get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-split_nseq_thres" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Maximum Number of sequences within a subgroup",\ + /*Parameter*/ &split_nseq_thres ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-split_score_thres" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Minimum score within a split dataset",\ + /*Parameter*/ &split_score_thres ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-check_pdb_status" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Reports the existance of a PDB file",\ + /*Parameter*/ &check_pdb_status ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-clean_seq_name" ,\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Remove Special Char from sequence names",\ + /*Parameter*/ &clean_seq_name ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + + +/*PARAMETER PROTOTYPE: SEQ TO ALIGN */ + seq_to_keep=declare_char ( 2000, STRING); + n_seq_to_keep=get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-seq_to_keep",\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 200 ,\ + /*DOC*/ "File containing the name of the sequences to keep when triming OR a list of names)",\ + /*Parameter*/ seq_to_keep ,\ + /*Def 1*/ "NULL" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +/*******************************************************************************************************/ +/* */ +/* TCoffee_dpa Parameter:START */ +/* */ +/*******************************************************************************************************/ +/*PARAMETER PROTOTYPE: dpa_master_aln */ + declare_name (dpa_master_aln); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-dpa_master_aln",\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Approximate Alignment: File|method",\ + /*Parameter*/ &dpa_master_aln ,\ + /*Def 1*/ "" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + /*PARAMETER PROTOTYPE: dpa_maxnseq */ + + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-dpa_maxnseq",\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Maximum number of sequences to be aligned with DPA",\ + /*Parameter*/ &dpa_maxnseq ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "50" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); +/*PARAMETER PROTOTYPE: dpa_min_score1 */ + + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-dpa_min_score1",\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 200 ,\ + /*DOC*/ "Minimum percent ID to merge sequences in the approximate alignment",\ + /*Parameter*/ &dpa_min_score1 ,\ + /*Def 1*/ "" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "0" ,\ + /*Max Value*/ "100" \ + ); +/*PARAMETER PROTOTYPE: dpa_min_score2 */ + + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-dpa_min_score2",\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 200 ,\ + /*DOC*/ "Threshold for aligning a group in the slow double progressive alignment (automatically readjusted)",\ + /*Parameter*/ &dpa_min_score2 ,\ + /*Def 1*/ "" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "0" ,\ + /*Max Value*/ "100" \ + ); +/*PARAMETER PROTOTYPE: dpa_keep_tmp_file */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-dpa_keep_tmpfile" ,\ + /*Flag*/ &dpa_keep_tmpfile ,\ + /*TYPE*/ "FL" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Prevents deletion of the tmpfile generated by t_coffee_dpa",\ + /*Parameter*/ &do_version ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "0" ,\ + /*Max Value*/ "1" \ + + ); +/*PARAMETER PROTOTYPE: dpa_debug */ + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-dpa_debug" ,\ + /*Flag*/ &dpa_debug ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "DEbug mode for DPA ( causes dpa tmp files to be kept)",\ + /*Parameter*/ &do_version ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "0" ,\ + /*Max Value*/ "1" \ + + ); + +/*PARAMETER PROTOTYPE: multi_core */ + declare_name (multi_core); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-multi_core",\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Multi core: template_jobs_relax_[msa|pairwise]_evaluate",\ + /*Parameter*/ &multi_core ,\ + /*Def 1*/ "templates_jobs_relax_msa_evaluate" ,\ + /*Def 2*/ "templates_jobs_relax_msa_evaluate" ,\ + /*Min_value*/ "0" ,\ + /*Max Value*/ "100" \ + ); + if (multi_core[0])set_string_variable ("multi_core",multi_core); +/*PARAMETER PROTOTYPE: multi_core */ + get_cl_param( \ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-n_core",\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Number of cores to be used by machine [default=0 => all those defined in the environement]",\ + /*Parameter*/ &n_core ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "0" ,\ + /*Min_value*/ "0" ,\ + /*Max Value*/ "100" \ + ); + if (n_core)set_int_variable ("n_core",n_core); + + +/*PARAMETER PROTOTYPE: lib_list */ + declare_name (lib_list); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-lib_list",\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "A File that contains every pair/group of sequence to process when computing the lib, Format: ",\ + /*Parameter*/ &lib_list ,\ + /*Def 1*/ "" ,\ + /*Def 2*/ "default" ,\ + /*Min_value*/ "0" ,\ + /*Max Value*/ "100" \ + ); + + /*PARAMETER PROTOTYPE: lib_list */ + declare_name (prune_lib_mode); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-prune_lib_mode",\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "A File that contains every pair/group of sequence to process when computing the lib, Format: ",\ + /*Parameter*/ &prune_lib_mode ,\ + /*Def 1*/ "5" ,\ + /*Def 2*/ "5" ,\ + /*Min_value*/ "0" ,\ + /*Max Value*/ "100" \ + ); + set_string_variable ("prune_lib_mode",prune_lib_mode); + + /*PARAMETER PROTOTYPE: multi_thread */ + declare_name (tip); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-tip",\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Controls The Output of A TIP When Computation is over [one,all,none]",\ + /*Parameter*/ &tip ,\ + /*Def 1*/ "none" ,\ + /*Def 2*/ "all" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + /*PARAMETER PROTOTYPE: RNA LIB */ + declare_name (rna_lib); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-rna_lib",\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "",\ + /*Parameter*/ &rna_lib ,\ + /*Def 1*/ "" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + get_cl_param( \ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-no_warning",\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Suppresses all Warnings",\ + /*Parameter*/ &no_warning ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "0" ,\ + /*Max Value*/ "1" \ + ); + get_cl_param( \ + /*argc*/ argc ,\ + /*argv*/ argv , \ + /*output*/ &le ,\ + /*Name*/ "-run_local_script",\ + /*Flag*/ &garbage , \ + /*TYPE*/ "D" , \ + /*OPTIONAL?*/ OPTIONAL , \ + /*MAX Nval*/ 1 , \ + /*DOC*/ "Run Local Script if in current directory", \ + /*Parameter*/ &run_local_script , \ + /*Def 1*/ "0" , \ + /*Def 2*/ "1" , \ + /*Min_value*/ "0" , \ + /*Max Value*/ "1" \ + ); + set_int_variable ("run_local_script", run_local_script); + declare_name (plugins); + get_cl_param( \ + /*argc*/ argc ,\ + /*argv*/ argv , \ + /*output*/ &le ,\ + /*Name*/ "-plugins",\ + /*Flag*/ &garbage , \ + /*TYPE*/ "S" , \ + /*OPTIONAL?*/ OPTIONAL , \ + /*MAX Nval*/ 1 , \ + /*DOC*/ "Set the directory containing the plugins [no if no plugin]", \ + /*Parameter*/ &plugins , \ + /*Def 1*/ "default" , \ + /*Def 2*/ "" , \ + /*Min_value*/ "any" , \ + /*Max Value*/ "any" \ + ); + + + + declare_name (proxy); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-proxy",\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "proxy used to access to webservices, when required",\ + /*Parameter*/ &proxy ,\ + /*Def 1*/ "unset" ,\ + /*Def 2*/ " " ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + if ( !strm (proxy, "unset"))set_string_variable ("cl_proxy",proxy); + declare_name (email); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-email",\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "email provided to webservices, when required",\ + /*Parameter*/ &email ,\ + /*Def 1*/ "" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + if ( strstr (email, "@")) + { + set_string_variable ("email", email); + set_string_variable ("cl_email", email); + } + + get_cl_param( \ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-clean_overaln",\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Ratio between overaligned exon id Vs legitimates *100",\ + /*Parameter*/ &clean_overaln ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "1" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + overaln_param=declare_char ( 10, STRING); + n_overaln_param=get_cl_param( \ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-overaln_param",\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 10 ,\ + /*DOC*/ "Parameters for the overaln",\ + /*Parameter*/ overaln_param ,\ + /*Def 1*/ "NULL" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + declare_name (overaln_mode); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-overaln_mode",\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "lower || uanlaign",\ + /*Parameter*/ &overaln_mode ,\ + /*Def 1*/ "" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + if (overaln_mode[0])set_string_variable ("overaln_mode", overaln_mode); + declare_name (overaln_model); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-overaln_model",\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "fsa1 (no exon boundaries), fsa2 (exon boundaries)",\ + /*Parameter*/ &overaln_model ,\ + /*Def 1*/ "" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + if (overaln_mode[0])set_string_variable ("overaln_model", overaln_model); + + get_cl_param( \ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-overaln_threshold",\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Ratio between overaligned exon id Vs legitimates *100",\ + /*Parameter*/ &overaln_threshold ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + set_int_variable ("overaln_threshold", overaln_threshold); + + get_cl_param( \ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-overaln_target",\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Ratio between overaligned exon id Vs legitimates *100",\ + /*Parameter*/ &overaln_target ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + set_int_variable ("overaln_target", overaln_threshold); + + get_cl_param( \ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-overaln_P1",\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Ratio between overaligned exon id Vs legitimates *100",\ + /*Parameter*/ &overaln_P1 ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + if (overaln_P1)set_int_variable ("overaln_P1", overaln_P1); + + get_cl_param( \ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-overaln_P2",\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Ratio between overaligned exon id Vs legitimates *100",\ + /*Parameter*/ &overaln_P2 ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + if (overaln_P2)set_int_variable ("overaln_P2", overaln_P2); + + get_cl_param( \ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-overaln_P3",\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Ratio between overaligned exon id Vs legitimates *100",\ + /*Parameter*/ &overaln_P3 ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + if (overaln_P3)set_int_variable ("overaln_P3", overaln_P3); + + get_cl_param( \ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-overaln_P4",\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "D" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "Ratio between overaligned exon id Vs legitimates *100",\ + /*Parameter*/ &overaln_P4 ,\ + /*Def 1*/ "0" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + if (overaln_P4)set_int_variable ("overaln_P4", overaln_P4); + + + declare_name (exon_boundaries); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-exon_boundaries",\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "exon_boundaries [EBI boj format]",\ + /*Parameter*/ &exon_boundaries ,\ + /*Def 1*/ "" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + if ( exon_boundaries[0])set_string_variable ("exon_boundaries", exon_boundaries); + + declare_name (dump); + get_cl_param(\ + /*argc*/ argc ,\ + /*argv*/ argv ,\ + /*output*/ &le ,\ + /*Name*/ "-dump",\ + /*Flag*/ &garbage ,\ + /*TYPE*/ "S" ,\ + /*OPTIONAL?*/ OPTIONAL ,\ + /*MAX Nval*/ 1 ,\ + /*DOC*/ "dump",\ + /*Parameter*/ &dump ,\ + /*Def 1*/ "no" ,\ + /*Def 2*/ "" ,\ + /*Min_value*/ "any" ,\ + /*Max Value*/ "any" \ + ); + + if (!strm (dump, "no")) + { + set_string_variable ("dump_output_file", vtmpnam (NULL)); + set_string_variable ("dump_output_file_list", vtmpnam (NULL)); + + set_string_variable ("dump",dump); + } + + + +/*******************************************************************************************************/ +/* */ +/* TCoffee_dpa Parameter:END */ +/* */ +/*******************************************************************************************************/ + + + + if (argc==1 ) + { + display_method_names ("display", stdout); + return EXIT_SUCCESS; + } + get_cl_param( argc, argv,&le, NULL,NULL,NULL,0,0,NULL); + prepare_cache (cache); +/*******************************************************************************************************/ +/* */ +/* FILL list_file (contains seq, aln and meth) */ +/* */ +/*******************************************************************************************************/ + + + +/*Re-introduce the sequences introduced with -infile*/ +/*Standard*/ + + if ( infile[0] && !do_evaluate) + { + sprintf ( list_file[n_list++], "%s",infile); + } +/*DO EVALUATE: The aln to evaluate must be provided via -infile*/ + else if (do_evaluate) + { + if (!infile[0] || !(main_read_aln ( infile, NULL))) + { + fprintf ( stderr,"\nERROR: When using -evaluate, Provide a multiple sequence alignment via the -infile flag [FATAL:%s]\n", PROGRAM); + myexit (EXIT_FAILURE); + } + else if (! main_read_aln ( infile,NULL)) + { + fprintf ( stderr,"\nERROR: FILE %s is NOT a valid alignment [FATAL:%s]\n", infile, PROGRAM); + myexit (EXIT_FAILURE); + } + else if ( infile[0]=='A' ||infile[0]=='S') + { + sprintf ( list_file[n_list++], "S%s",infile+1); + } + else sprintf ( list_file[n_list++], "S%s",infile); + } + + + +/*Make Sure -infile is set*/ + if (!infile[0]&& (do_evaluate || do_convert)) + { + + if ( do_evaluate || do_convert)sprintf ( infile, "%s",seq_list[0]); + } + +/*EXPAND -in*/ + /*Introduce the sequences from the -profile flag*/ + if ( profile1 && profile1[0]) + { + sprintf ( list_file[n_list++], "R%s",profile1); + } + if ( profile2 && profile2[0]) + { + sprintf ( list_file[n_list++], "R%s",profile2); + } + + for ( a=0; a< n_profile_list; a++) + { + FILE *fp; + if ( (fp=find_token_in_file (profile_list[a], NULL, "FILE_LIST"))!=NULL) + { + int z; + char rname[1000]; + vfclose (fp); + fp=vfopen (profile_list[a], "r"); + + while ( (z=fgetc(fp))!=EOF) + { + ungetc(z, fp); + fscanf (fp, "%s\n", rname); + if ( check_file_exists(rname))sprintf ( list_file[n_list++], "R%s", rname); + } + vfclose (fp); + } + else if (format_is_conc_aln (profile_list[a])) + { + Alignment *P; + char *cname; + + P=input_conc_aln (profile_list[a],NULL); + while (P) + { + cname=vtmpnam (NULL); + output_fasta_aln (cname, P); + P=P->A; + sprintf ( list_file[n_list++], "R%s",cname); + } + free_aln (P); + } + + else + { + sprintf ( list_file[n_list++], "R%s",profile_list[a]); + } + } + /*Introduce the sequences from the -seq flag*/ + for (a=0; anseq); + free_aln (ExA); + } + /*FETCH THE STRUCTURES INTRODUCED WITH -pdb and add them to -in*/ + if ( n_pdb) + { + for ( a=0; a< n_pdb; a++) + { + if ( is_number (pdb_list[a])); + else + { + pdb_start=pdb_end=0; + if ( a+1< n_pdb && is_number (pdb_list[a+1]))pdb_start=atoi (pdb_list[a+1]); + if ( a+2< n_pdb && is_number (pdb_list[a+2]))pdb_end=atoi (pdb_list[a+2]); + + pdb_name=get_pdb_struc ( pdb_list[a],pdb_start, pdb_end); + if (pdb_name){sprintf (list_file[n_list++], "P%s", pdb_name);} + /*Warning: do not free pdb_name: it is statically allocated by get_pdb_struc*/ + } + } + } + + /*Check That Enough Methods/Libraries/Alignments Have been Chiped in*/ + + if (list_file) + { + int *nn; + nn=vcalloc ( 256, sizeof (int)); + for (a=0; aname); + sprintf ( F->name, "%s", lname); + break; + } + + else if ( is_in_set ( list_file[a][0], "P") && is_pdb_struc (list_file[a]+1)) + { + F=parse_fname(is_pdb_struc (list_file[a]+1));break; + + } + } + } + + } + + + /*Get Structures*/ + for ( a=0; a< n_list; a++) + { + if ( list_file[a][0]=='P' && !check_file_exists(list_file[a])) + { + char buf[1000]; + sprintf(buf, "%s", list_file[a]+1); + sprintf(list_file[a], "P%s",is_pdb_struc (buf)); + } + } + + /*FATAL: NO SEQUENCES*/ + if (!F) + { + myexit (fprintf_error(stderr,"You have not provided any sequence")); + } + if (run_name)F=parse_fname(run_name); + else F->path[0]='\0'; + + + identify_list_format (list_file, n_list); + + + fprintf (le, "\nINPUT FILES\n"); + for ( a=0; a< n_list; a++) + { + fprintf (le, "\tInput File (%c) %s ",list_file[a][0],list_file[a]+1); + if ( list_file[a][0]=='A' || list_file[a][0]=='S' || list_file[a][0]=='P'|| list_file[a][0]=='R' ) + { + fprintf (le, " Format %s\n", f=identify_seq_format ( list_file[a]+1)); + + if (!f || f[0]=='\0') + { + myexit (fprintf_error(stderr,"The format of %s is not supported", list_file[a]+1)); + + } + vfree (f); + } + else fprintf (le, "\n"); + } + + +/*CONVERT, ALIGN OR EVALUATE: CHOSE THE RIGHT VERB*/ + /*Set the Hierarchy of the verbs*/ + /*The first one decides...*/ + + + do_list=vcalloc ( 100, sizeof (int*)); + n_do=0; + do_list[n_do++]=&do_genepred; + do_list[n_do++]=&do_extended_matrix; + do_list[n_do++]=&do_convert; + do_list[n_do++]=&do_evaluate; + do_list[n_do++]=&do_domain; + do_list[n_do++]=&do_align; + + + for ( a=0; a< n_do; a++) + { + if ( do_list[a][0]) + { + for ( b=0; b< n_do; b++)if ( b!=a)do_list[b][0]=0; + break; + } + } + + + +/*SET THE DEFAULT NAMES*/ + if ( do_convert) + { + if ( strm (tree_file, "default"))sprintf ( tree_file, "no"); + } + + + + if ( do_evaluate) + { + sprintf ( out_lib, "no"); + sprintf ( tree_file, "no"); + clean_aln=0; + } + if (do_genepred) + { + sprintf ( tree_file, "no"); + clean_aln=0; + } + + if ( F && strm ( tree_file, "default"))sprintf ( tree_file ,"%s%s.dnd",F->path ,F->name); + if ( F && strm ( ph_tree_file, "default"))sprintf ( ph_tree_file ,"%s%s.ph",F->path ,F->name); + + for (a=0; a< n_out_aln_format; a++) + { + if (is_out_format_list (out_aln_format[a])); + else + { + fprintf (stderr, "\n%s is not a valid format [FATAL:%s]\n", out_aln_format[a], PROGRAM); + myexit (EXIT_FAILURE); + } + } + + for (a=0; apath,F->name,out_aln_format[a]); + } + } + else + { + sprintf ( tot_out_aln[0], "%s", out_aln); + for (a=1; a< n_out_aln_format; a++) + sprintf ( tot_out_aln[a] ,"%s%s.%s", F->path ,out_aln, out_aln_format[a]); + } + + + + if ( F && strm ( out_lib , "default"))sprintf ( out_lib ,"%s%s.tc_lib",F->path , F->name); + + if ( type && type[0]) + { + if (strm2 (type,"Protein", "protein"))sprintf ( type, "PROTEIN"); + if (strm2 (type,"DNA", "dna"))sprintf ( type, "DNA"); + if (strm2 (type,"RNA", "rna"))sprintf ( type, "RNA"); + + } + + + if ( !use_tree && check_file_exists (tree_file))vremove (tree_file); + else if ( !use_tree || (use_tree && strm (use_tree, "default"))); + else sprintf ( tree_file, "%s", use_tree); + + +/*******************************************************************************************************/ +/* */ +/* Input Sequences and Library */ +/* */ +/*******************************************************************************************************/ + + set_methods_limits (method_limits,n_method_limits,list_file, n_list, &maxnseq, &maxlen); + /*Set Global Values*/ + + + +/*START*/ + + /*1 READ THE SEQUENCES*/ + + S=read_seq_in_n_list (list_file, n_list, type,seq_source); + + if ( check_type) + { + if (!strm (S->type, get_array_type (S->nseq, S->seq))) + { + fprintf ( stderr, "\nINCORRECT SEQUENCE TYPE (USE %s ONLY) [FATAL:%s]", S->type, PROGRAM); + myexit (EXIT_FAILURE); + } + } + + if (S->nseq<=1 && !do_domain) + { + printf_exit (EXIT_FAILURE,stderr, "\nERROR: Your Dataset Contains %d Sequence. For multiple alignments you need at least 2 sequences[FATAL:%s]", S->nseq,PROGRAM); + } + + store_seq_type (S->type); + + if ( type_only==1) + { + fprintf ( stdout, "%s", S->type); + return EXIT_SUCCESS; + } + /*Translate Sequences*/ + if ( transform && transform[0]) + { + S=transform_sequence (S, transform); + } + + /*Abort if the sequences are too long */ + if (maxlen!=-1 && S->max_len>maxlen) + { + fprintf ( stderr, "\nSEQUENCES TOO LONG [Longuest=%d][MAX=%d][FATAL:%s]\n", S->max_len,maxlen, PROGRAM); + myexit (EXIT_FAILURE); + + } + + + + + + /* Get the Templates*/ + + + + + + + + + + if ( get_type) + { + S=get_sequence_type (S); + fprintf ( stdout , "%s\n", S->type); + free_sequence(S, S->nseq); + return 1; + } + + + /*Reorder the sequences*/ + new_order=duplicate_char (S->name, -1, -1); + if ( strm (inorder, "aligned"))new_order=sort_string_array (new_order, S->nseq); + + initial_order=duplicate_char (S->name, -1, -1); + S=reorder_seq(S,new_order,S->nseq); + free_char (new_order, -1); + + + + /*3 PREPARE THE CONSTRAINT LIST*/ + + CL=declare_constraint_list ( S,NULL, NULL, 0,(strm(mem_mode, "disk"))?tmpfile():NULL, NULL); + + sprintf ( CL->method_evaluate_mode, "%s", method_evaluate_mode); + + (CL->TC)->use_seqan=use_seqan; + CL->local_stderr=le; + /*set the genepred parameters*/ + sprintf ( CL->genepred_score, "%s", genepred_score); + /*Estimate the distance Matrix*/ + + + if (extend_seq)extend_seqaln(CL->S,NULL); + CL->DM=cl2distance_matrix ( CL,NOALN,distance_matrix_mode, distance_matrix_sim_mode,1); + if (extend_seq)unextend_seqaln(CL->S,NULL); + + + + /*one to all alignment*/ + MASTER_SEQ=prepare_master(master_mode,S,CL, "ktup"); + if (!blast_maxnseq)CL->o2a_byte=(CL->S)->nseq; + else CL->o2a_byte=blast_maxnseq; + + /*4 GET TEMPLATES*/ + //Intercept Master Sequences + + if (MASTER_SEQ) + { + TEMP_SEQ=S; + S=MASTER_SEQ; + } + + if ( n_template_file) + { + fprintf ( le, "\nLooking For Sequence Templates:\n"); + for ( a=0; a< n_template_file; a++) + { + //correct for missing extension modes + if (strm (template_file_list[a],"RNA") && !strstr (extend_mode, "rna"))sprintf ( extend_mode, "rna2"); + + + fprintf ( le, "\n\tTemplate Type: [%s] Mode Or File: [%s] [Start", template_type2type_name(template_file_list[a]), template_file_list[a]); + S=seq2template_seq(S, template_file_list[a], F); + fprintf ( le, "]"); + + if (S==NULL) + { + add_warning (stderr, "\nImpossible to find %s Templates\nCheck that your blast server is properly installed [See documentation][FATAL:%s]\n", template_file_list[a],PROGRAM); + myexit (EXIT_FAILURE); + } + } + + if (seq2n_X_template ( S, "_*_")) + { + + sprintf (S->template_file, "%s",seq2template_file (S, NULL)); + } + } + else + { + int ptf=0; + for ( a=0; anseq; a++) + { + if ( seq_has_template ( S, a, "_P_"))ptf=1; + } + if (ptf) + { + int j; + sprintf ( S->template_file ,"%s%s.template_file",F->path , F->name); + seq2template_file (S,S->template_file); + display_output_filename ( stdout, "Template_List","fasta_seq", S->template_file, STORE); + } + } + + + if (n_profile_template_file) + { + fprintf ( le, "\nLooking For Profile Templates"); + for ( a=0; a< n_profile_template_file; a++) + { + fprintf ( le, "\n\tTemplate Type: [%s] Mode Or File: [%s] [Start", template_type2type_name(profile_template_file_list[a]), profile_template_file_list[a]); + S=profile_seq2template_seq(S, profile_template_file_list[a], F); + fprintf ( le, "]"); + if (S==NULL) + { + add_warning(stderr, "Impossible to find %s Templates\nCheck that your blast server is properly installed [See documentation][FATAL:%s]\n",profile_template_file_list[a], PROGRAM); + myexit (EXIT_FAILURE); + } + } + } + + + + + //Release Master Sequences + if (MASTER_SEQ ) + { + int i; + S=TEMP_SEQ; + for (a=0; a< MASTER_SEQ->nseq; a++) + if ((i=name_is_in_list (MASTER_SEQ->name[a], S->name, S->nseq, 100))!=-1) + { + S->T[i]=MASTER_SEQ->T[a]; + } + } + S=seq2template_seq(S, "SELF_S_",F); + S=seq2template_type (S); + + le=display_sequences_names ( S, le, check_pdb_status, TEMPLATES); + /*4 GET TEMPLATES: DONE*/ + + + + + if ( matrix && matrix[0]) + { + sprintf ( CL->method_matrix,"%s", matrix); + + } + /*Set the filtering*/ + CL->filter_lib=filter_lib; + /*Set the evaluation Functions*/ + CL->profile_mode=get_profile_mode_function (profile_mode, NULL); + sprintf ( CL->profile_comparison, "%s", profile_comparison); + if ( n_struc_to_use) + { + CL->STRUC_LIST=declare_sequence (1,1,n_struc_to_use); + CL->STRUC_LIST->nseq=0; + for ( a=0; a< n_struc_to_use; a++) + { + + sprintf ( (CL->STRUC_LIST)->name[(CL->STRUC_LIST)->nseq++],"%s",struc_to_use[a]); + } + } + sprintf (CL->align_pdb_param_file, "%s", align_pdb_param_file); + sprintf (CL->align_pdb_hasch_mode, "%s", align_pdb_hasch_mode); + + + + /*Blast Parameters*/ + (CL->Prot_Blast)->min_id=prot_min_sim; + (CL->Prot_Blast)->max_id=prot_max_sim; + (CL->Prot_Blast)->min_cov=prot_min_cov; + sprintf ( (CL->Prot_Blast)->blast_server, "%s", prot_blast_server); + sprintf ( (CL->Prot_Blast)->db, "%s", prot_db); + + (CL->Pdb_Blast)->min_id=pdb_min_sim; + + (CL->Pdb_Blast)->max_id=pdb_max_sim; + (CL->Pdb_Blast)->min_cov=pdb_min_cov; + sprintf ( (CL->Pdb_Blast)->blast_server, "%s", pdb_blast_server); + sprintf ( (CL->Pdb_Blast)->db, "%s", pdb_db); + CL->check_pdb_status=check_pdb_status; + /*split parameters */ + CL->split=split; + CL->split_nseq_thres=split_nseq_thres; + CL->split_score_thres=split_score_thres; + /*Blast Parameters + (CL->DNA_Blast)->min_id=dna_min_sim; + (CL->DNA_Blast)->max_id=dna_max_sim; + (CL->DNA_Blast)->min_cov=dna_min_cov; + sprintf ( (CL->DNA_Blast)->blast_server, "%s", dna_blast_server); + sprintf ( (CL->DNA_Blast)->db, "%s", dna_db); + */ + + if ( method_log) + { + if ( strm (method_log, "default")) + { + sprintf ( CL->method_log, "%s%s.method_log",F->path, F->name); + } + else if ( !strm (method_log, "no")) + { + sprintf ( CL->method_log, "%s", method_log); + } + set_string_variable ("method_log", method_log); + } + + + CL->lalign_n_top=lalign_n_top; + sprintf ( CL->multi_thread, "%s", multi_core); + + sprintf ( CL->lib_list, "%s", lib_list); + sprintf (CL->rna_lib, "%s", rna_lib); +/* Important: This is where the library is compiled!!!!*/ + + if ((CL->S)->nseq>1 && !do_convert) + { + CL=read_n_constraint_list (list_file,n_list,NULL, mem_mode,weight,type, le, CL, seq_source); + //CL=post_process_constraint_list (CL); //needed when constraints are added, for instance the RNA modes + } + else if ( do_convert && out_lib[0]) + { + if ( infile[0]) + {sprintf (list_file[0], "%s", name2type_name(infile)); + CL=read_n_constraint_list (list_file,1,NULL, mem_mode,weight,type, le, CL, seq_source); + } + else + { + CL=read_n_constraint_list (list_file,n_list,NULL, mem_mode,weight,type, le, CL, seq_source); + } + } + if ( CL->M)clean_aln=0; + + if ( is_number (weight))set_weight4constraint_list (CL, atoi(weight)); + + free_pair_wise ();//Free ststic memory allocated in some of the pairwise functions + + + //Shrink: re-run slow_pair using the library, remove everything + + + /*If the List is empty*/ + if ( (CL->S)->nseq>1 && CL->ne==0 && !CL->M &&!(do_convert && n_list>0)) + { + fprintf ( stderr, "\n******************ERROR*****************************************\n"); + + fprintf ( stderr, "\nYou have not provided any method or enough Sequences[FATAL]"); + fprintf ( stderr, "\nIf you have used the '-in' Flag, ADD the methods you wish to use:"); + fprintf ( stderr, "\n\t-in Mlalign_id_pair Mfast_pair\n"); + fprintf ( stderr, "\nAnd make sure you provide at least TWO sequences\n"); + for ( a=0; a< argc; a++)fprintf ( stderr, "%s ", argv[a]); + fprintf ( stderr, "\n*****************************************************************\n"); + myexit(EXIT_FAILURE); + } + + + CL->normalise=do_normalise; + + if ( type && type[0])sprintf ( (CL->S)->type, "%s", type); + CL->extend_jit=(do_extend>0)?1:0; + + CL->extend_threshold=(do_extend==1)?0:do_extend; + CL->do_self=do_self; + sprintf (CL->extend_clean_mode, "%s", clean_mode); + sprintf (CL->extend_compact_mode, "%s", compact_mode); + if ( CL->extend_jit && CL->extend_threshold !=0)filter_constraint_list (CL,WE,CL->extend_threshold); + CL->pw_parameters_set=1; + + + + CL->nomatch=nomatch; + set_int_variable ("nomatch", nomatch); + /*Gep and Gop*/ + if ( !gep && !gop && CL->M) + { + CL->gop=get_avg_matrix_mm ( CL->M, (strm3((CL->S)->type,"PROTEIN", "Protein", "protein")?AA_ALPHABET:"gcuta"))*10; + CL->gep=CL->gop/10; + fprintf ( CL->local_stderr, "\nAUTOMATIC PENALTIES: gapopen=%d gapext=%d", CL->gop, CL->gep); + } + else if ( !CL->M && cosmetic_penalty && !gep && !gop) + { + CL->gep=0; + CL->gop=cosmetic_penalty; + } + else + { + CL->gep=gep; + CL->gop=gop; + fprintf ( CL->local_stderr, "\nMANUAL PENALTIES: gapopen=%d gapext=%d", CL->gop, CL->gep); + } + + /*Frame Penalties*/ + CL->f_gep=f_gep; + CL->f_gop=f_gop; + + + CL->maximise=maximise; + + if (strm(retrieve_seq_type(),"DNA")|| strm(retrieve_seq_type(),"RNA") ) + CL->ktup=MAX(2,ktup); + else + CL->ktup=ktup; + + CL->use_fragments=diag_mode; + CL->fasta_step=fasta_step; + CL->diagonal_threshold=diag_threshold; + + sprintf ( CL->matrix_for_aa_group, "%s", sim_matrix); + sprintf ( CL->dp_mode, "%s", dp_mode); + CL->TG_MODE=tg_mode; + + sprintf ( CL->evaluate_mode, "%s", evaluate_mode); + fprintf (le, "\n\n\tLibrary Total Size: [%d]\n", CL->ne); + + + CL=choose_extension_mode (extend_mode, CL); + CL->max_n_pair=max_n_pair; + + processed_lib=0; + //use the L, vener touch it again + + + if (CL->ne>0 && out_lib[0]!='\0' && !strm (out_lib, "no")) + { + + if (strstr (out_lib_mode, "extended")) + { + char emode[1000]; + + //Do the processing before saving the extended lib*/ + processed_lib=1; + if ( filter_lib) CL=filter_constraint_list (CL,CL->weight_field, filter_lib); + for (a=0; ane, out_lib, NULL, "ascii",CL->S); + } + vfclose (OUT); + CL->local_stderr=display_output_filename (le, "TCLIB","tc_lib_format_01",out_lib, CHECK); + } + + + if ( lib_only)return EXIT_SUCCESS; + + //fprintf ( stderr, "AVG LINK: %3f", constraint_list2connectivity (CL); exit (0); + if (!processed_lib) + { + if ( filter_lib) CL=filter_constraint_list (CL,CL->weight_field, filter_lib); + if (atoigetenv ("EXTEND4TC")==1)CL=extend_constraint_list(CL); + for (a=0; adistance_matrix_mode, "%s", distance_matrix_mode); + sprintf ( CL->distance_matrix_sim_mode, "%s", distance_matrix_sim_mode); + + sprintf ( CL->tree_mode, "%s", tree_mode); + //Re-estimate the distance matrix with consistency// + if ( strm ("cscore", distance_matrix_mode)) + { + CL->DM=cl2distance_matrix ( CL,NOALN,distance_matrix_mode, distance_matrix_sim_mode,1); + } + /*WEIGHT CONSTRAINT LIST*/ + + if ( !do_convert) + { + + CL->DM=cl2distance_matrix (CL, NOALN, NULL, NULL,0); + + CL=weight_constraint_list(CL, seq_weight); + + if (output_seq_weights (CL->W, outseqweight)) + CL->local_stderr=display_output_filename( CL->local_stderr,"WEIGHT","tc_weight",outseqweight, CHECK); + le=display_weights(CL->W, le); + } + + + + /*Prepare quadruplets*/ + if ( nseq_for_quadruplet && !strm(seq_name_for_quadruplet[0], "all")) + { + CL->nseq_for_quadruplet=nseq_for_quadruplet; + CL->seq_for_quadruplet=vcalloc ((CL->S)->nseq, sizeof (int)); + for (a=0; a< CL->nseq_for_quadruplet; a++) + { + printf ( "\nquad: %s", seq_name_for_quadruplet[a]); + if ( (b=name_is_in_list (seq_name_for_quadruplet[a],(CL->S)->name,(CL->S)->nseq, 100))!=-1)CL->seq_for_quadruplet[b]=1; + else add_warning ( stderr, "\nWARNING: Sequence %s is not in the set and cannot be used for quadruplet extension\n",seq_name_for_quadruplet[a]); + } + } + else if ( nseq_for_quadruplet && strm(seq_name_for_quadruplet[0], "all")) + { + + CL->nseq_for_quadruplet=(CL->S)->nseq; + CL->seq_for_quadruplet=vcalloc ((CL->S)->nseq, sizeof (int)); + for (a=0; a< CL->nseq_for_quadruplet; a++) + { + CL->seq_for_quadruplet[a]=1; + } + } + +/*******************************************************************************************************/ +/* */ +/* Prepare The Alignment */ +/* */ +/*******************************************************************************************************/ + + if ( do_align ) + { + + + A=seq2aln ((CL->S),NULL,1); + ungap_array(A->seq_al,A->nseq); + + /*Chose the right Mode for evaluating Columns*/ + + if ( A->nseq==1); + else if ( strm ( msa_mode, "seq_aln")) + { + A=seq_aln (A,(CL->S)->nseq, CL); + } + else if ( strm ( msa_mode, "sorted_aln")) + { + A=sorted_aln (A, CL); + } + else if ( strm ( msa_mode, "full_sorted_aln")) + { + full_sorted_aln (A, CL); + output_constraints (out_lib, "sim", A); + CL->local_stderr=display_output_filename (le, "TCLIB","tc_lib_format_01",out_lib, CHECK); + return EXIT_SUCCESS; + } + + else if ( strm ( msa_mode, "profile_aln")) + { + A=iterative_tree_aln (A, 0, CL); + A=profile_aln (A, CL); + } + else if ( strm ( msa_mode, "iterative_aln")) + { + A=iterative_tree_aln (A, 0, CL); + A=iterative_aln (A,10, CL); + } + else if ( strm ( msa_mode, "iterative_tree_aln")) + { + A=iterative_tree_aln (A,1, CL); + } + else if ( strm ( msa_mode, "dpa_aln")) + { + A=dpa_aln (A, CL); + } + else if ( strm ( msa_mode, "new_dpa_aln")) + { + A=new_dpa_aln (A, CL); + } + else if ( strm ( msa_mode, "delayed_tree_aln")) + { + A=make_delayed_tree_aln (A,2, CL); + } + else if ( strm ( msa_mode, "groups")) + { + A=seq2aln_group (A,dpa_maxnseq, CL); + out_aln_format[0]="conc_aln"; + n_out_aln_format=1; + } + else if ( strm ( msa_mode, "upgma")) + { + A=upgma_tree_aln (A, A->nseq, CL); + } + else if ( strm ( msa_mode, "graph")) + { + fprintf ( stderr, "\nDO GRAPH ALIGNMENT"); + A=graph_aln ( A, CL, (CL->S)); + } + else if ( strm ( msa_mode, "tsp")) + { + fprintf ( stderr, "\nDO TSP ALIGNMENT"); + A=tsp_aln ( A, CL, (CL->S)); + } + else if ( strm ( msa_mode, "precomputed")) + { + if (infile[0]) {free_aln (A);A=main_read_aln ( infile, declare_aln(CL->S));} + else{fprintf ( stderr, "\nERROR: distance_matrix_mode=aln requires an aln passed via the -infile flag [FATAL:%s]", PROGRAM);crash ("");} + + sprintf ( CL->dp_mode, "precomputed_pair_wise"); + sprintf ( CL->distance_matrix_mode, "aln"); + CL->tree_aln=A=reorder_aln ( A, (CL->S)->name,(CL->S)->nseq); + + pc=tree_file; + if ( strm (tree_file, "default") || !check_file_exists (tree_file)) + T=make_tree ( A,CL,gop, gep,(CL->S),pc, maximise); + else if ( strm (tree_file, "no")) + T=make_tree ( A,CL,gop, gep,(CL->S),NULL, maximise); + else + { + T=read_tree (pc,&tot_node,(CL->S)->nseq, (CL->S)->name); + } + + SNL=tree_aln ((T[3][0])->left,(T[3][0])->right,A,(CL->S)->nseq, CL); + } + else if ( strm ( msa_mode, "tree")) + { + if ( strm (CL->distance_matrix_mode, "aln")) + { + if (infile[0]) {free_aln (A);A=main_read_aln ( infile, declare_aln(CL->S));} + else{fprintf ( stderr, "\nERROR: distance_matrix_mode=aln requires an aln passed via the -infile flag [FATAL:%s]", PROGRAM);crash ("");} + CL->tree_aln=A; + } + pc=tree_file; + if ( strm (tree_file, "default") || !check_file_exists (tree_file)) + T=make_tree ( A,CL,gop, gep,(CL->S),pc,maximise); + else if ( strm (tree_file, "no")) + T=make_tree ( A,CL,gop, gep,(CL->S),NULL, maximise); + else + { + fprintf ( le, "\nREAD PRECOMPUTED TREE: %s\n", pc); + T=read_tree (pc,&tot_node,(CL->S)->nseq, (CL->S)->name); + } + SNL=tree_aln ((T[3][0])->left,(T[3][0])->right,A,(CL->S)->nseq, CL); + A->nseq=(CL->S)->nseq; + } + + else + { + fprintf ( stderr, "\nERROR: msa_mode %s is unknown [%s:FATAL]\n", msa_mode, PROGRAM); + crash (""); + } + + } + else if ( (do_evaluate || do_convert)) + { + + + A=(infile[0])?main_read_aln ( infile, declare_aln(CL->S)):NULL; + + if (!A)A=seq2aln((CL->S), NULL,0); + + + A->S=CL->S; + A->nseq=(CL->S)->nseq; + + + } + else if ( do_genepred) + { + Alignment *A1, *A2; + A1=seq2aln(CL->S, NULL, 1); + A1->S=CL->S; + A2=coffee_seq_evaluate_output (A1, CL); + if (!A2->score_res)myexit(0); + for ( b=0; b< n_out_aln_format; b++) + { + Alignment *OUT; + + OUT=copy_aln (A2,NULL); + output_format_aln (out_aln_format[b],OUT,NULL, tot_out_aln[b]); + le=display_output_filename( le,"MSA",out_aln_format[b], tot_out_aln[b], CHECK); + free_aln (OUT); + } + return EXIT_SUCCESS; + } + + else if (do_domain) + { + CL->moca=vcalloc ( 1, sizeof ( Moca)); + if (strm ( "cfasta_pair_wise", dp_mode))sprintf (CL->dp_mode, "%s","domain_pair_wise"); + (CL->moca)->moca_start=domain_start; + (CL->moca)->moca_len =domain_len; + (CL->moca)->moca_scale=(domain_scale==0)?-(CL->normalise/20):domain_scale; + (CL->moca)->moca_interactive=domain_interactive; + + + + if (!cosmetic_penalty && !gep && !gop) + { + CL->gop=-200; + CL->gep=-100; + } + + CL=prepare_cl_for_moca (CL); + aln_list=moca_aln (CL); + free_int ( CL->packed_seq_lu, -1); + CL->packed_seq_lu=NULL; + + a=0; + while ( aln_list[a]) + { + for ( b=0; b< n_out_aln_format; b++) + { + + output_format_aln (out_aln_format[b],aln_list[a],EA=fast_coffee_evaluate_output(aln_list[a], CL), tot_out_aln[b]); + le=display_output_filename( le,"MSA",out_aln_format[b], tot_out_aln[b], CHECK); + } + a++; + } + return EXIT_SUCCESS; + } + else if ( do_extended_matrix) + { + A=seq2aln(CL->S, NULL, 1); + A->CL=CL; + for ( a=0; a< n_out_aln_format; a++) + { + output_format_aln (out_aln_format[a],A,EA, tot_out_aln[a]); + le=display_output_filename( le,"MSA",out_aln_format[a], tot_out_aln[a], CHECK); + } + + return EXIT_SUCCESS; + } + + +/*******************************************************************************************************/ +/* */ +/* PREPARE THE ALIGNMENT FOR OUTPUT */ +/* */ +/*******************************************************************************************************/ + + if (A) + { + /* + for ( a=0; a< A->nseq; a++) + { + for ( b=0; b< A->len_aln ; b++) + if ( A->seq_al[a][b]=='O' || A->seq_al[a][b]=='o')A->seq_al[a][b]='-'; + } + */ + + + + + if ( check_file_exists(outorder)) + { + Sequence *OS; + OS=get_fasta_sequence (outorder, NULL); + if ( prf_in_seq (CL->S))A->expanded_order=OS->name; + else A=reorder_aln ( A,OS->name,A->nseq); + } + else if ( strm(outorder, "aligned") && T) + { + A=reorder_aln ( A,A->tree_order,A->nseq); + + } + else + { + + A=reorder_aln ( A, (CL->S)->name,(CL->S)->nseq); + A=reorder_aln ( A, initial_order,(CL->S)->nseq); + + } + + A->output_res_num=strm3 ( output_res_num, "on", "On", "ON"); + + if ( strm2 (residue_case, "keep", "retain"))A->residue_case=KEEP_CASE; + else if (strm3 (residue_case, "upper", "Upper", "UPPER"))A->residue_case=UPPER_CASE; + else if (strm3 (residue_case, "lower", "Lower", "LOWER"))A->residue_case=LOWER_CASE; + else A->residue_case=1; + + + + + + + if ( iterate) + { + A=iterate_aln (A, iterate, CL); + A=ungap_aln(A); + } + + if ( clean_aln) + { + EA=main_coffee_evaluate_output(A, CL,clean_evaluate_mode); + A=clean_maln(A, EA,clean_threshold,clean_iteration); + free_aln (EA); + A=ungap_aln(A); + } + + //overaln + if (clean_overaln) + { + char *over_aln_tmp; + over_aln_tmp=vtmpnam(NULL); + output_format_aln ("overaln", A, NULL, over_aln_tmp); + A=main_read_aln (over_aln_tmp,A); + } + + EA=main_coffee_evaluate_output(A, CL, evaluate_mode); + + //correct ascii file + if (clean_overaln) + { + EA=overlay_alignment_evaluation (A,EA); + } + + + if (A->A)A=A->A; + if (!strm2(out_aln, "stdout", "stderr") && le==stderr && !do_convert)output_format_aln ("aln",A,NULL,"stdout"); + + + A->CL=CL; + for ( a=0; a< n_out_aln_format; a++) + if ( !strstr ( out_aln_format[a], "expand"))output_format_aln (out_aln_format[a],A,EA, tot_out_aln[a]); + for ( a=0; a< n_out_aln_format; a++) + if ( strstr (out_aln_format[a], "expand"))output_format_aln (out_aln_format[a],A,EA, tot_out_aln[a]); + + + + fprintf (le, "\n\nOUTPUT RESULTS"); + if ((CL->S)->nseq>2) + le=display_output_filename (le, "GUIDE_TREE","newick", tree_file, CHECK); + + for ( a=0; a< n_out_aln_format; a++) + le=display_output_filename( le,"MSA",out_aln_format[a], tot_out_aln[a], CHECK); + if (CL->ne>0 && out_lib[0]!='\0' && !strm (out_lib, "no")) + CL->local_stderr=display_output_filename (le, "TCLIB","tc_lib_format_01",out_lib, CHECK); + + if (!strm (ph_tree_file, "NO") && A->nseq>2) + { + NT_node T; + FILE *tfp; + char **tmode; + tmode=declare_char (2, 100); + sprintf (tmode[0], "nj"); + T=tree_compute (A, 1, tmode); + tfp=vfopen (ph_tree_file, "w"); + tfp=print_tree (T, "newick", tfp); + vfclose (tfp); + le=display_output_filename (le, "PHYLOGENIC_TREE","newick", ph_tree_file, CHECK); + } + + } + + if (split) + { + + if (trim && n_seq_to_keep) + { + if (n_seq_to_keep==1 && check_file_exists (seq_to_keep[0])) + { + + SEQ_TO_KEEP=read_sequences (seq_to_keep[0]); + } + else + { + + SEQ_TO_KEEP=declare_sequence ( 1, 1,n_seq_to_keep); + for ( a=0; a< n_seq_to_keep; a++)sprintf ( SEQ_TO_KEEP->name[a], "%s", seq_to_keep[a]); + } + } + + sprintf ( CL->dp_mode, "precomputed_pair_wise"); + sprintf ( CL->distance_matrix_mode, "aln"); + + + + CL->tree_aln=A=reorder_aln ( A, (CL->S)->name,(CL->S)->nseq); + CL->S=aln2seq ( A); + + if (!T) + { + + pc=tree_file; + if ( strm (tree_file, "default") || !check_file_exists (tree_file)) + T=make_tree ( A,CL,gop, gep,(CL->S),pc, maximise); + else if ( strm (tree_file, "no")) + T=make_tree ( A,CL,gop, gep,(CL->S),NULL, maximise); + else + { + T=read_tree (pc,&tot_node,(CL->S)->nseq, (CL->S)->name); + } + } + + SNL=tree_aln ((T[3][0])->left,(T[3][0])->right,A,(CL->S)->nseq, CL); + + + for ( a=0, b=0; anseq; a++)b+=(SNL[a])?1:0; + fprintf ( le, "\n\nSPLIT DATASET: %d Groups\n", b); + /*Display Group Names*/ + + if ( trim && SEQ_TO_KEEP) + { + for ( a=0; a< SEQ_TO_KEEP->nseq; a++) + { + + trim_subS=extract_one_seq(SEQ_TO_KEEP->name[a],0,0,A,KEEP_NAME); + trim_S=add_sequence (trim_subS,trim_S,0); + } + } + for ( a=0, b=0; anseq; a++) + { + + if ( SNL[a]) + { + b++; + fprintf ( le, "\n\tSPLIT_GROUP %d ; Nseq %d ; Score %d ; List ",b, (SNL[a])->nseq, (int)(SNL[a])->score); + for ( c=0; c< (SNL[a])->nseq; c++) + { + fprintf ( le, "%s ",(CL->S)->name[(SNL[a])->lseq[c]]); + } + + SPLIT_ALN=extract_sub_aln (A, (SNL[a])->nseq,(SNL[a])->lseq); + SPLIT_ALN->S=A->S; + ungap_aln (SPLIT_ALN); + + if (!trim) + { + sprintf ( split_format, "%s", "clustalw"); + sprintf ( split_name, "%s.split.%d.%s", F->name, b,split_format); + fprintf ( le, " ; File %s", split_name); + output_format_aln (split_format,SPLIT_ALN,NULL,split_name); + le=display_output_filename( le,"SPLIT_SEQ",split_format,split_name, CHECK); + } + else if (trim) + { + t=aln2most_similar_sequence(SPLIT_ALN, "idmat"); + trim_subS=extract_one_seq(SPLIT_ALN->name[t],0,0,SPLIT_ALN,KEEP_NAME); + trim_S=add_sequence (trim_subS,trim_S,0); + fprintf ( le, "\n\tTRIM_SEQ: Kept sequence %s",SPLIT_ALN->name[t]); + } + free_aln (SPLIT_ALN); + fprintf (le, "\n"); + } + } + + if (trim) + { + + + SPLIT_ALN=seq2aln (trim_S,NULL, KEEP_GAP); + ungap_aln (SPLIT_ALN); + sprintf ( trim_format, "%s", "fasta_aln"); + if ( strm (trimfile, "default"))sprintf ( trimfile, "%s.trim.%s", F->name,trim_format); + + output_format_aln (trim_format,SPLIT_ALN,NULL,trimfile); + le=display_output_filename( le,"TRIM_SEQ",trim_format,trimfile, CHECK); + } + } + + if (remove_template_file){S=vremove_seq_template_files(S);} + else + { + S=display_seq_template_files (S); + } + + //fLUSH OUT THE NAME OF ALL THE FILES THAT HAVE BEEN PRODUCED + + le=display_output_filename (le, NULL, NULL, NULL, FLUSH); + + + fprintf (le, "\n\n"); + + free_char (list_file, -1); + free_Alignment (A); + free_Alignment (EA); + + + S=free_constraint_list (CL); + free_sequence (S, S->nseq); + + + + vremove ( "core"); + + vfree_all(); + + le=t_coffee_tip (le, tip); + le=print_command_line ( le); + //le=print_mem_usage (le, PROGRAM); + //le=print_cpu_usage(le, PROGRAM); + le=print_program_information (le, NULL); + + + if (full_log && full_log[0])log_function(full_log); + + return EXIT_SUCCESS; + } + +/*Specialized set of Parameters*/ +char *get_defaults (char *buf, char *type) +{ + return NULL; +} +char *get_precomputed_defaults(char *buf, char *type) + { + + if (buf==NULL)buf=vcalloc (1000, sizeof (char)); + + buf=strcat (buf," -msa_mode=precomputed "); + buf=strcat (buf," -seq_weight=no "); + buf=strcat (buf," -evaluate_mode no "); + buf=strcat (buf," -in Xpam250mt "); + return buf; + } +char *get_evaluate_defaults(char *buf, char *type) + { + + if (buf==NULL)buf=vcalloc (1000, sizeof (char)); + + buf=strcat (buf," -quiet=stdout "); + /*buf=strcat (buf," -seq_weight=no ");*/ + buf=strcat (buf," -output score_ascii html "); + buf=strcat (buf," -iterate 0 "); + + buf=strcat (buf," -evaluate "); + + + + return buf; + } +char *get_genome_defaults(char *buf, char *type) + { + + if (buf==NULL)buf=vcalloc (1000, sizeof (char)); + + buf=strcat (buf," -seq_weight=no "); + buf=strcat (buf," -dp_mode sim_pair_wise_lalign "); + buf=strcat (buf," -output glalign "); + buf=strcat (buf," -iterate 0 "); + buf=strcat (buf," -distance_matrix_mode ktup "); + buf=strcat (buf," -evaluate_mode t_coffee_slow "); + buf=strcat (buf," -gapopen 100 -gapext 20 -nomatch 30 "); + buf=strcat (buf," -clean_aln 0 "); + buf=strcat (buf,"-output clustalw,score_ascii "); + + + return buf; + } +char *get_dali_defaults(char *buf, char *type) + { + + if (buf==NULL)buf=vcalloc (1000, sizeof (char)); + + buf=strcat (buf,"-cosmetic_penalty=-50 "); + buf=strcat (buf,"-distance_matrix_mode=slow "); + buf=strcat (buf,"-output clustalw,score_ascii "); + buf=strcat (buf,"-evaluate_mode=non_extended_t_coffee "); + buf=strcat (buf,"-clean_aln 0 "); + + return buf; + } + +char *get_very_fast_defaults(char *buf, char *type) + { + + if (buf==NULL)buf=vcalloc (1000, sizeof (char)); + + buf=strcat (buf,"-in Xblosum62mt "); + buf=strcat (buf,"-distance_matrix_mode ktup "); + buf=strcat (buf,"-maxnseq 10000 "); + buf=strcat (buf,"-dpa_maxnseq 0 "); + buf=strcat (buf,"-dp_mode fasta_pair_wise "); + buf=strcat (buf,"-extend_mode matrix "); + buf=strcat (buf,"-gapopen -10 "); + buf=strcat (buf,"-gapext -1 "); + buf=strcat (buf,"-iterate 0 "); + /*buf=strcat (buf,"-in ");*/ + + return buf; + } + +char *get_low_memory_defaults(char *buf, char *type) + { + if (buf==NULL)buf=vcalloc (1000, sizeof (char)); + + if (NO_METHODS_IN_CL)buf=strcat (buf,"-distance_matrix_mode=idscore -method lalign_id_pair slow_pair -dp_mode=linked_pair_wise "); + else buf=strcat (buf,"-distance_matrix_mode=idscore -dp_mode=linked_pair_wise "); + return buf; + } +char *get_dna_defaults(char *buf, char *type) +{ + + return buf; +} +char *get_cdna_defaults(char *buf, char *type) +{ + buf=strcat (buf,"-distance_matrix_mode=idscore -dp_mode=fasta_cdna_pair_wise "); + return buf; +} +char *get_3dcoffee_defaults(char *buf, char *type) + { + if (buf==NULL)buf=vcalloc (1000, sizeof (char)); + + buf=strcat (buf,"-in Msap_pair -template_file SELF_P_ -profile_template_file SELF_P_"); + /*buf=strcat (buf,"-in ");*/ + + return buf; + } +char *get_expresso_defaults(char *buf, char *type) + { + + if (buf==NULL)buf=vcalloc (1000, sizeof (char)); + + buf=strcat (buf,"-method sap_pair -template_file EXPRESSO -profile_template_file EXPRESSO"); + + /*buf=strcat (buf,"-in ");*/ + + return buf; + } +char *get_procoffee_defaults(char *buf, char *type) + { + + if (buf==NULL)buf=vcalloc (1000, sizeof (char)); + + buf=strcat (buf,"-in Mpromo_pair -extend_seq "); + /*buf=strcat (buf,"-in ");*/ + + return buf; + } +char *get_blastr_defaults(char *buf, char *type) + { + + if (buf==NULL)buf=vcalloc (1000, sizeof (char)); + + buf=strcat (buf,"-in Mblastr_pair -extend_seq "); + /*buf=strcat (buf,"-in ");*/ + + return buf; + } +char *get_psicoffee_defaults(char *buf, char *type) + { + + if (buf==NULL)buf=vcalloc (1000, sizeof (char)); + + buf=strcat (buf,"-in Mproba_pair -template_file BLAST "); + /*buf=strcat (buf,"-in ");*/ + + return buf; + } +char *get_accurate_defaults ( char *buf, char *type) +{ + + if ( strm (type, "PROTEIN")) return get_accurate4PROTEIN_defaults(buf, type); + else if ( strm (type, "DNA")) return get_accurate4DNA_defaults(buf, type); + else if ( strm (type, "RNA")) return get_accurate4RNA_defaults(buf, type); + else return get_defaults(buf, type); +} +char *get_accurate4PROTEIN_defaults(char *buf, char *type) + { + if (buf==NULL)buf=vcalloc (1000, sizeof (char)); + if (NO_METHODS_IN_CL)buf=strcat (buf,"-in Mbest_pair4prot -template_file BLAST -template_file EXPRESSO "); + else buf=strcat (buf,"-template_file BLAST -template_file EXPRESSO "); + buf=strcat (buf,"-output aln, expanded_fasta_aln "); + + return buf; + } + + + + +char *get_accurate4DNA_defaults(char *buf, char *type) +{ + return get_low_memory_defaults (buf,type); +} +char *get_accurate4RNA_defaults(char *buf, char *type) +{ + return get_rcoffee_defaults (buf,type); +} +char *get_t_coffee_defaults(char *buf, char *type) +{ + return buf; +} +char *get_fmcoffee_defaults(char *buf, char *type) + { + //Fast Mcoffee + if (buf==NULL)buf=vcalloc (1000, sizeof (char)); + + if (NO_METHODS_IN_CL) buf=strcat (buf,"-in Mkalign_msa Mmuscle_msa Mmafft_msa -multi_core methods_relax_msa"); + + /*buf=strcat (buf,"-in ");*/ + + return buf; + } + +char *get_mcoffee_defaults(char *buf, char *type) + { + + if (buf==NULL)buf=vcalloc (1000, sizeof (char)); + + + if (NO_METHODS_IN_CL) buf=strcat (buf,"-in Mclustalw2_msa Mt_coffee_msa Mpoa_msa Mmuscle_msa Mmafft_msa Mdialignt_msa Mpcma_msa Mprobcons_msa -multi_core methods_relax_msa "); + /*buf=strcat (buf,"-in ");*/ + return buf; + } +char *get_dmcoffee_defaults(char *buf, char *type) + { + + if (buf==NULL)buf=vcalloc (1000, sizeof (char)); + + if (NO_METHODS_IN_CL)buf=strcat (buf,"-in Mkalign_msa Mt_coffee_msa Mpoa_msa Mmuscle_msa Mmafft_msa Mdialignt_msa Mprobcons_msa Mamap_msa -multi_core methods_relax_msa"); + /*buf=strcat (buf,"-in ");*/ + + return buf; + } +char *get_rcoffee_consan_defaults(char *buf, char *type) + { + + if (buf==NULL)buf=vcalloc (1000, sizeof (char)); + + check_program_is_installed (RNAPLFOLD_4_TCOFFEE,NULL, NULL,RNAPLFOLD_ADDRESS, INSTALL_OR_DIE); + if (NO_METHODS_IN_CL)buf=strcat (buf,"-in Mconsan_pair -multi_core templates_relax_msa -dp_mode myers_miller_pair_wise -extend_mode rna2 -template_file RCOFFEE -transform dna2rna -type DNA -relax_lib 0"); + else buf=strcat (buf,"-dp_mode myers_miller_pair_wise -extend_mode rna2 -template_file RCOFFEE -transform dna2rna -type DNA -relax_lib 0"); + /*buf=strcat (buf,"-in ");*/ + + return buf; + } +char *get_rmcoffee_defaults(char *buf, char *type) + { + + if (buf==NULL)buf=vcalloc (1000, sizeof (char)); + + check_program_is_installed (RNAPLFOLD_4_TCOFFEE,NULL, NULL,RNAPLFOLD_ADDRESS, INSTALL_OR_DIE); + if (NO_METHODS_IN_CL)buf=strcat (buf,"-in Mprobcons_msa Mmafft_msa Mmuscle_msa -extend_mode rna2 -template_file RCOFFEE -transform dna2rna -check_type -type DNA -relax_lib 0"); + else buf=strcat (buf,"-extend_mode rna2 -template_file RCOFFEE -transform dna2rna -check_type -type DNA -relax_lib 0"); + /*buf=strcat (buf,"-in ");*/ + + return buf; + } + +// if (NO_METHODS_IN_CL)buf=strcat (buf,"-in Mbest_pair4prot -template_file BLAST -template_file EXPRESSO "); + char *get_best4RNA_defaults(char *buf, char *type) + { + + if (buf==NULL)buf=vcalloc (1000, sizeof (char)); + + check_program_is_installed (RNAPLFOLD_4_TCOFFEE,NULL, NULL,RNAPLFOLD_ADDRESS, INSTALL_OR_DIE); + buf=strcat (buf," -extend_mode rna2 -template_file PDB,RNA -in Mbest_pair4rna -transform dna2rna -relax_lib 0"); + /*buf=strcat (buf,"-in ");*/ + + return buf; + } + +char *get_rcoffee_defaults(char *buf, char *type) + { + + if (buf==NULL)buf=vcalloc (1000, sizeof (char)); + + check_program_is_installed (RNAPLFOLD_4_TCOFFEE,NULL, NULL,RNAPLFOLD_ADDRESS, INSTALL_OR_DIE); + buf=strcat (buf," -extend_mode rna2 -template_file RCOFFEE -transform dna2rna -check_type -type DNA -relax_lib 0"); + /*buf=strcat (buf,"-in ");*/ + + return buf; + } +char *get_genepredx_defaults(char *buf, char *type) + { + + if (buf==NULL)buf=vcalloc (1000, sizeof (char)); + + buf=strcat (buf, "-method tblastx_msa -evaluate_mode sequences -genepred -relax_lib 0 -output fasta_seq,exons,texons,wexons -seq_weight no -check_type -type DNA -out_lib"); + return buf; + } +char *get_genepredpx_defaults(char *buf, char *type) + { + + if (buf==NULL)buf=vcalloc (1000, sizeof (char)); + + buf=strcat (buf, "-method tblastpx_msa -evaluate_mode sequences -genepred -relax_lib 0 -output fasta_seq,exons,texons,wexons -seq_weight no -check_type -type DNA -out_lib"); + return buf; + } + +char *get_repeat_defaults(char *buf, char *type) + { + + if (buf==NULL)buf=vcalloc (1000, sizeof (char)); + + buf=strcat (buf,"-in slow_pair -matrix idmat -out_lib -profile_comparison profile -profile_mode channel_profile_profile -dp_mode myers_miller_pair_wise "); + /*buf=strcat (buf,"-in ");*/ + return buf; + } + + +int check_configuration4program() + { + return 1; + + } + +/*Chose the right Mode for comparing residues*/ + +void test () +{ + char command[1000]; + char *c2; + + c2=vcalloc ( 100, sizeof (char)); + + sprintf (command, "cat hmgt_mouseVsnrl3d.blast_result |blast_aln2fasta_aln.pl | fasta_aln2fasta_aln_unique_name.pl > my_test"); + + fprintf ( stderr, "C1: %d, C2:%d", is_dynamic_memory (c2), is_dynamic_memory (c2)); + + + myexit (0); +} + +int run_other_pg ( int argc, char *argv[]) +{ + //make minimum initialization + + + if ( strm (argv[0], "seq_reformat") || strm (argv[0], "saltt")) + { + return seq_reformat (argc, argv); + } + else if ( strm (argv[0], "aln_compare")) + { + return aln_compare (argc, argv); + } + else if ( strm (argv[0], "analyse_pdb") || strm (argv[0], "apdb") || strm (argv[0], "irmsd") || strm (argv[0], "trmsd")) + { + return apdb ( argc, argv); + } + else if ( strm (argv[0], "quantile")) + { + return quantile ( argc, argv); + } + else if ( strstr ( argv[0], "unpack_")) + { + unpack_all_perl_script (argv[0]+strlen ("unpack_")); + } + else if ( strstr ( argv[0], "fastal")) + { + return fastal_main(argc, argv); + } + else + { + return my_system_cl (argc, argv); + } + return EXIT_FAILURE; +} + +FILE * t_coffee_tip (FILE *fp,char *mode) +{ + static char **tip; + static int n; + int a; + if ( !tip) + { + tip=declare_char ( 100, 300); + sprintf ( tip[n++],"Get the most accurate protein alignments with: t_coffee -special_mode accurate [Slow]\n"); + sprintf ( tip[n++],"Change the Width of your MSA with the environement variable ALN_LINE_LENGTH (all formats)"); + sprintf ( tip[n++],"Align 2 or more profiles with -profiles= aln1, aln2"); + sprintf ( tip[n++],"-special_mode=expresso to fetch your structures automatically"); + sprintf ( tip[n++],"-special_mode=psicoffee to expand your sequences"); + sprintf ( tip[n++],"-special_mode=accurate The best we can do [slow]"); + + sprintf ( tip[n++],"-special_mode=3dcoffee to combine sequences and structures"); + sprintf ( tip[n++],"-special_mode=mcoffee to combine alternative msa methods"); + sprintf ( tip[n++],"-special_mode=dmcoffee to combine alternative msa methods on debian"); + + sprintf ( tip[n++],"-usetree= to use your own guide tree"); + sprintf ( tip[n++],"-infile= -special_mode=evaluate to evaluate your own alignment"); + sprintf ( tip[n++],"-other_pg seq_reformat to access seq_reformat"); + sprintf ( tip[n++],"-other_pg extract_from_pdb to use our pdb retriever"); + sprintf ( tip[n++],"All the latest versions on www.tcoffee.org"); + sprintf ( tip[n++],"-version to check for updates"); + sprintf ( tip[n++],"-output=html will produce a colored output"); + sprintf ( tip[n++],"-outorder=aligned will order the sequences according to the guide tree in newick"); + sprintf ( tip[n++],"-special_mode=quickaln will produce fast/low accuracy alignments"); + sprintf ( tip[n++],"-other_pg seq_reformat -in -action +trim %%50 Will reduce the redundancy of your MSA"); + sprintf ( tip[n++],"-tip=all to see all the tips, tip=no will prevent them all"); + sprintf ( tip[n++],"-other_pg unpack_all will unpack all the perl scripts within t_coffee"); + } + + if ( strm (mode, "none"))return fp; + + fprintf ( fp, "\n# TIP :See The Full Documentation on www.tcoffee.org\n"); + + if (strm ( mode, "all")) + { + for ( a=0; a< n; a++) + { + fprintf (fp, "# TIP %d: %s\n", a+1,tip[a]); + } + } + else if ( strm ( mode, "one")) + { + int b; + vsrand(0); + b=(rand()%(n-1))+1; + fprintf (fp, "# TIP %2s: %s","1", tip[0]); + fprintf (fp, "# TIP %2d: %s\n", b+1, tip[b]); + + } + + fprintf ( fp, "\n"); + return fp; +} + + + +Sequence* prepare_master (char *seq, Sequence *S, Constraint_list *CL, char *dmode) + { + int a,b,s1, n, i; + FILE *fp; + + CL->master=vcalloc (S->nseq+1, sizeof(int)); + + if ( S->nseq==2 || strm (seq, "no") || strm (seq, "default")) + { + for (a=0; anseq; a++)CL->master[a]=1; + return NULL; + } + else if ( check_file_exists (seq)) + { + Sequence *L; + L=main_read_seq (seq); + for (a=0; a< L->nseq; a++) + if ( (b=name_is_in_list (L->name[a], S->name,S->nseq, 100))!=-1)CL->master[b]=1; + } + else + { + + if ( strstr (seq, "_P_")) + { + for (a=0; anseq; a++) + { + if (seq_has_template (S, a, "_P_"))CL->master[a]=1; + } + } + if ( is_number (seq) || strstr (seq, "_N_")) + { + int nseq; + char **name; + Alignment *A=NULL, *SA=NULL; + if ( strstr (seq, "_N_")){nseq=atoi (strstr(seq, "_N_")+strlen ("_N_"));} + else nseq=atoi (seq); + if ( nseq<0) + nseq=((float)S->nseq*((float)nseq/(float)100.0)*(float)-1); + + nseq=MIN(nseq,S->nseq); + if ( nseq>=S->nseq) + { + for (a=0; a<(CL->S)->nseq; a++)CL->master[a]=1; + } + else + { + + char tmode[1000]; + int **sim; + + A=(strm (dmode, "msa"))?(very_fast_aln (seq2aln (S, NULL, RM_GAP), 0, NULL)):(seq2aln (S, NULL, RM_GAP)); + sim=(strm (dmode, "ktup") && CL->DM)?(CL->DM)->similarity_matrix:NULL; + + sprintf (tmode, "_aln_n%d", nseq); + SA=simple_trimseq (A, NULL, tmode, NULL, NULL); + nseq=SA->nseq; + name=SA->name; + for (a=0; aS)->nseq)CL->master[a]=1; + else if ((b=name_is_in_list (name[a], S->name,S->nseq, 100))!=-1)CL->master[b]=1; + } + free_aln (A); + free_aln (SA); + } + } + if ( strstr (seq, "_LONG_")) + { + int ml=0; + int ls=0; + for (a=0; a< (CL->S)->nseq; a++) + { + int l=strlen ((CL->S)->seq[a]); + if (l>ml){ml=l;ls=a;} + } + CL->master[ls]=1; //keep the longest seqquence + } + } + + + fprintf ( CL->local_stderr, "\n"); + for (b=0,a=0; anseq; a++) + { + if ( CL->master[a]) + { + fprintf (CL->local_stderr, "\tMaster_sequence: %s\n", S->name[a]); + b++; + } + } + if ( b==0) + { + printf_exit (EXIT_FAILURE, stderr, "ERROR: %s is neither a file nor a method nor a number for -master [FATAL:%s]\n",seq,PROGRAM); + } + + if (b!=(CL->S)->nseq) + { + Sequence *T, *MS; + T=duplicate_sequence (CL->S); + for(a=0; anseq; a++) + { + if (!CL->master[a]){vfree (T->seq[a]); T->seq[a]=NULL;} + } + MS=duplicate_sequence (T); + free_sequence (T, -1); + return MS; + } + else + return CL->S; + } +int set_methods_limits (char ** method,int nl,char **list, int n, int *maxnseq, int *maxlen) +{ + int a,ns, ml, nm=0; + char string[1000]; + + nl/=3; + for (a=0; ans))maxnseq[0]=ns; + if (ml!=-1 && (maxlen[0]==-1 || maxlen[0]>ml))maxlen[0]=ml; + nm++; + } + } + return nm; +} + + + +char * get_seq_type_from_cl (int argc, char **argv) +{ + char *buf, *r; + char file[100]; + int a; + int seq=0; + + sprintf (file, "%d.tmp", rand()%10000); + buf=vcalloc ( 1000, sizeof (char)); + sprintf ( buf, "%s ", get_string_variable ("t_coffee")); + for (a=1, seq=0; a"); + buf=strcat (buf, file); + + my_system ( buf); + + r=file2string (file); + vremove (file); + return r; +} +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/t_coffee.h b/binaries/src/tcoffee/t_coffee_source/t_coffee.h new file mode 100644 index 0000000..9d51bf7 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/t_coffee.h @@ -0,0 +1,31 @@ +int run_default (char *pg,char *filename); +//int check_configuration4program(); +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/tree.c b/binaries/src/tcoffee/t_coffee_source/tree.c new file mode 100644 index 0000000..0928bb2 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/tree.c @@ -0,0 +1,459 @@ +#include "stdio.h" +#include "stdlib.h" +#include "math.h" +#include "ctype.h" + + +#include "io_lib_header.h" +#include "util_lib_header.h" +// #include "define_header.h" +// #include "dp_lib_header.h" +// #include "fastal_lib_header.h" + + + +#include "fast_tree_header.h" + +/*! + * \file tree.c + * \brief Source code for the fastal tree algorithm + */ + +/* + + +int +main(int argc, char** argv) +{ + int alphabet_size = 5; + int aa[256]; + if (alphabet_size == 5) + { + aa['A'] = 0; + aa['B'] = 1; + aa['C'] = 1; + aa['D'] = 0; + aa['G'] = 2; + aa['H'] = 0; + aa['K'] = 3; + aa['M'] = 1; + aa['N'] = 0; + aa['R'] = 0; + aa['S'] = 1; + aa['T'] = 3; + aa['U'] = 4; + aa['W'] = 3; + aa['Y'] = 1; + } + else + { + aa['A'] = 0; + aa['B'] = 1; + aa['C'] = 2; + aa['D'] = 3; + aa['E'] = 4; + aa['F'] = 5; + aa['G'] = 6; + aa['H'] = 7; + aa['I'] = 8; + aa['J'] = 9; + aa['K'] = 10; + aa['L'] = 11; + aa['M'] = 12; + aa['N'] = 13; + aa['P'] = 14; + aa['Q'] = 15; + aa['R'] = 16; + aa['S'] = 17; + aa['T'] = 18; + aa['V'] = 19; + aa['W'] = 20; + aa['X'] = 21; + aa['Y'] = 22; + aa['Z'] = 23; + } + compute_oligomer_distance_tree(argv[1], &aa[0], argv[2], 5, 2, alphabet_size); + return 0; +}*/ + + +void +compute_oligomer_distance_tree(char *seq_file_name, int* char2value, char *tree_file_name, int max_dist, int word_length, int alphabet_size) +{ + int i; + int *compare = vcalloc(1,sizeof(int)); + int *num_seq = vcalloc(1,sizeof(int)); + + int num_features = (int)pow(alphabet_size,word_length); + + num_features *= num_features * (max_dist+1); + + + Cluster_info *matrix = feature_extract(seq_file_name, max_dist, word_length, char2value, alphabet_size, compare, num_seq, num_features); + + int *node = vcalloc(1, sizeof(int)); + *node = *num_seq; + + FILE *tree_f = fopen(tree_file_name,"w"); + double *mean = vcalloc(num_features, sizeof(double)); + double *variance = vcalloc(num_features, sizeof(double)); + cluster_recursive(0, *num_seq-1, matrix, num_features, mean, variance, compare, tree_f, node); + + for (i = 0; i < *num_seq; ++i) + { +// printf("ERG: %i\n", i); + vfree(matrix[i].features); + } + vfree(matrix); + fclose (tree_f); + vfree(mean); + vfree(variance); + vfree(compare); + vfree(node); + vfree(num_seq); +} + + + +/** + * Recodes a given sequence into a sequence of it's k-mers. + * + * \param seq The sequence to encode. + * \param seq_length The length of \a seq. + * \param char2value Array giving each character in seq a unique value. + * \param alphabet_size The size of the alphabet. + * \param word_length The length of the k-mers to use. + * + * \return The recodes sequence. + */ +int* +recode_sequence(char * seq, int seq_length, int *char2value, int alphabet_size, int word_length) +{ + + int *recoded = vcalloc(seq_length - word_length + 1, sizeof(int)); + int i; + + if (word_length == 1) + { + for (i = 0; i < seq_length; ++i) + { + recoded[i] = char2value[(short)seq[i]]; + } + } + else + { + int *prod=vcalloc (word_length, sizeof(int)); + for ( i=0; i') + { + if (num_seq >= 0) + { + seq[++seq_pos] = '\0'; + if (num_seq > matrix_size -2) + { + matrix_size += STEP; + matrix = vrealloc(matrix, matrix_size * sizeof(Cluster_info)); + } + int *recoded_seq = recode_sequence(seq, seq_pos, char2value, alphabet_size, k_tup); + matrix[num_seq].seq_number = num_seq; + matrix[num_seq].elem_2_compare = elem_2_compare; + matrix[num_seq].features=get_features(recoded_seq, seq_pos- k_tup +1, k_tup, max_coding, max_dist, num_features); + vfree(recoded_seq); + seq_pos = -1; + } + ++num_seq; + } + else + { + if (size - seq_pos < 500) + { + size += STEP; + seq = vrealloc(seq, size*sizeof(char)); + } + c_p = &line[0]; + while ((*c_p != '\n') && (*c_p != '\0')) + { + seq[++seq_pos] = toupper(*(c_p)); + ++c_p; + } + } + } + + fclose(tree_f); + seq[++seq_pos] = '\0'; + int *recoded_seq = recode_sequence(seq, seq_pos, char2value, alphabet_size, k_tup); + matrix[num_seq].seq_number = num_seq; + matrix[num_seq].elem_2_compare = elem_2_compare; + matrix[num_seq].features=get_features(recoded_seq, seq_pos- k_tup +1, k_tup, max_coding, max_dist, num_features); + *num_seq_p = ++num_seq; + vfree(seq); + vfree(recoded_seq); + return matrix; +} + + + +/** + * Compare function for qsort given an array of Cluster_info. + * + * The field used for sorting is done according to the element determined in the Cluster_info object. + * \param a void pointer to an object of Cluster_info. + * \param b void pointer to an object of Cluster_info. + * + * \return Value showing wheather \a a is bigger, smaller or equal to \a b. + */ +int +cluster_compare (const void * a, const void * b) +{ + Cluster_info *tmp1 = (Cluster_info*)a; + Cluster_info *tmp2 = (Cluster_info*)b; + int elem = *(tmp1->elem_2_compare); + if ((tmp1->features[elem]) > (tmp2->features[elem])) + return 1; + else if ((tmp1->features[elem]) < (tmp2->features[elem])) + return -1; + else + return 0; +} + + + +/** + * Recursive function to build a tree according to a given feature matrix. + * + * \param start The begin of this set in \a matrix. + * \param end The end of this set in \a matrix. + * \param matrix The feature matrix. + * \param dim The number of features. + * \param mean Array of size \a dim. + * \param variance Array of size \a dim. + * \param elem_2_compare Pointer to a single in. This will save the feature according to which shall be sorted (biggest variance). + * \param tree_f The file in which the tree will be written. + * \param node The current node. + * + * \return The number of the current node. + */ +int +cluster_recursive(int start, + int end, + Cluster_info* matrix, + int dim, + double *mean, + double *variance, + int *elem_2_compare, + FILE* tree_f, + int *node) +{ + + //stop recursion + if (end-start < 1) + { + return matrix[start].seq_number; + } + + //reset mean/variance + int i; + int num_seq = end - start +1; + for (i = 0; i < dim; ++i) + { + mean[i] = 0; + variance[i] = 0; + } + + //calculate mean + Cluster_info *start_p = &matrix[start]-1; + Cluster_info *end_p = &matrix[end]; + double *tmp; + while (start_p < end_p) + { + tmp = &(++start_p)->features[0]; + for (i = 0; i < dim; ++i) + { + mean[i] += *(tmp++); + } + } + for (i = 0; i < dim; ++i) + mean[i] /= num_seq; + + + //calculate variance + start_p = &matrix[start] -1; + + while (start_p < end_p) + { + tmp = &(++start_p)->features[0]; + for (i = 0; i < dim; ++i) + { + variance[i] += ((*tmp) - mean[i]) * ((*tmp) - mean[i]); + ++tmp; + } + } + + //get maximal variance + double max = variance[0]; + int index = 0; + for (i = 1; i < dim; ++i) + { + if (variance[i] > max) + { + max = variance[i]; + index = i; + } + } + *elem_2_compare = index; + + + //devide into to different sets and start recursion on these child sets + qsort (&matrix[start], num_seq, sizeof(Cluster_info), cluster_compare); + int split = start + (end-start)/2; + int split_value = matrix[split].features[index]; + while ((matrix[split+1].features[index] == split_value) && (split < end-1)) + ++split; + + int left_child = cluster_recursive(start, split, matrix, dim, mean, variance, elem_2_compare, tree_f, node); + int right_child = cluster_recursive(split+1, end, matrix, dim, mean, variance, elem_2_compare, tree_f, node); + int node2 = *node; + ++(*node); + //print node into file + fprintf(tree_f, "%i %i %i\n", left_child, right_child, node2); + + return node2; +} + +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/tree_util.c b/binaries/src/tcoffee/t_coffee_source/tree_util.c new file mode 100644 index 0000000..b41bc76 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/tree_util.c @@ -0,0 +1,5302 @@ +#include +#include +#include +#include +#include +#include +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "dp_lib_header.h" +#include "define_header.h" + +#define TOPOLOGY 1 +#define WEIGHTED 2 +#define LENGTH 3 +#define RECODE 4 + +int distance_tree; +int rooted_tree; +int tot_nseq; +static NT_node compute_fj_tree (NT_node T, Alignment *A, int limit, char *mode); +static NT_node compute_cw_tree (Alignment *A); +static NT_node compute_std_tree (Alignment *A, int n, char **arg); +static NT_node tree2fj_tree (NT_node T); +int tree_contains_duplicates (NT_node T); +int display_tree_duplicates (NT_node T); + +static int compare_node1 ( int *b1, int *b2, int n); +static int compare_node2 ( int *b1, int *b2, int n); +static int find_seq_chain (Alignment *A, int **sim,int *used,int seq0,int seq1, int seq2,int chain_length, int limit, int max_chain, int *nseq); +int new_display_tree (NT_node T, int n); +NT_node display_code (NT_node T, int nseq, FILE *fp); +NT_node display_dist (NT_node T, int n, FILE *fp); +/*********************************************************************/ +/* */ +/* dpa_tree_manipulation */ +/* */ +/*********************************************************************/ +static NT_node code_dpa_tree ( NT_node T, int **D); +NT_node collapse_sub_tree ( NT_node T,int nseq, int *list, char *new_name); +NT_node seq2dpa_tree (Sequence *S, char *mode) +{ + Constraint_list *CL; + NT_node **T; + NT_node Tree; + CL=declare_constraint_list_simple (S); + CL->local_stderr=NULL; + + + CL->DM=cl2distance_matrix (CL,NOALN,(mode==NULL)?"ktup":mode, NULL, 0); + + T=int_dist2nj_tree ( (CL->DM)->similarity_matrix, S->name, S->nseq, vtmpnam (NULL)); + Tree=T[3][0]; + + Tree=recode_tree (Tree, S); + Tree=reset_dist_tree (Tree, -1); + + Tree=code_dpa_tree (Tree, (CL->DM)->similarity_matrix); + free_distance_matrix (CL->DM); + return Tree; +} + +NT_node tree2dpa_tree (NT_node T, Alignment *A, char *mode) +{ + /*This Function sets the branches with Length values used by DP*/ + /*The tree must be rooted*/ + Sequence *S; + int **D; + + S=aln2seq (A); + T=recode_tree (T, S); + T=reset_dist_tree (T, -1); + D=get_sim_aln_array (A,mode); + + T=code_dpa_tree (T, D); + return T; +} + +NT_node code_dpa_tree ( NT_node T, int **D) +{ + if ( !T) return T; + else if ( T->leaf==1) + { + T->dist=100; + return T; + } + else + { + int nl, *ll; + int nr, *lr; + int a, b, min=100; + float tot, n=0; + + nl=(T->left)->nseq;ll=(T->left)->lseq; + nr=(T->right)->nseq;lr=(T->right)->lseq; + + for (tot=0,n=0, a=0; a< nl; a++) + for ( b=0; b< nr; b++, n++) + { + tot+=D[ll[a]][lr[b]]; + min=MIN(min,(D[ll[a]][lr[b]])); + } + /* T->dist=(mode==AVERAGE)?(tot/n):min:;*/ + T->dist=(n>0)?tot/n:0; + T->dist=min; + code_dpa_tree ( T->right, D); + code_dpa_tree ( T->left, D); + return T; + } +} +static int group_number; +char *tree2Ngroup (Alignment *A, NT_node T, int max_n, char *fname, char *mat) +{ + double top, bot, mid, pmid; + Sequence *S; + int n; + + + + if (!T) + { + char **list; + + list=declare_char ( 2, 100); + sprintf (list[0], "%s",mat); + + fprintf ( stderr, "\nCompute Phylogenetic tree [Matrix=%s]", mat); + T=compute_std_tree(A,1, list); + fprintf ( stderr, "\nCompute dpa tree"); + T=tree2dpa_tree (T,A, mat); + } + + S=tree2seq(T, NULL); + + if ( max_n<0) + { + max_n*=-1; + n=tree2group_file (T,S,0, max_n, fname); + fprintf ( stderr, "\n#TrimTC: Split in %d Groups at a minimum of %d%% ID\n",n, (int)max_n); + return fname; + + } + else if ( max_n>0) + { + if ( max_n>S->nseq)max_n=S->nseq; + + top=100; bot=0; + pmid=0; mid=50; + n=tree2group_file(T, S,0, (int)mid,fname); + mid=dichotomy((double)n, (double)max_n,(pmid=mid), &bot, &top); + while (n!=max_n && (int)pmid!=(int)mid) + { + n=tree2group_file(T, S,0, (int)mid, fname); + mid=dichotomy((double)n, (double)max_n,(pmid=mid), &bot, &top); + } + fprintf ( stderr, "\nDONE2"); + fprintf ( stderr, "\n#TrimTC: Split in %d Groups at a minimum of %d%% ID\n",n, (int)mid); + return fname; + } + return NULL; +} +static int group_number; +int tree2group_file ( NT_node T,Sequence *S, int maxnseq, int minsim, char *name) + { + FILE *fp; + + + fp=vfopen (name, "w"); + vfclose (tree2group (T, S,maxnseq,minsim, "tree2ngroup",fp)); + + return count_n_line_in_file(name); + } + + +FILE * tree2group ( NT_node T,Sequence *S, int maxnseq, int minsim,char *name, FILE *fp) +{ + if ( !T)return fp; + else + { + int m,d; + + m=(maxnseq==0)?S->nseq:maxnseq; + d=minsim; + + + + if ( T->nseq<=m && T->dist>=d) + { + int a; + fprintf ( fp, ">%s_%d ", (name)?name:"", ++group_number); + for ( a=0; a< T->nseq; a++) + fprintf ( fp, "%s ", S->name[T->lseq[a]]); + fprintf (fp, "\n"); + if (!T->parent)group_number=0; + return fp; + } + else + { + fp=tree2group (T->right, S, maxnseq, minsim, name,fp); + fp=tree2group (T->left, S, maxnseq, minsim, name,fp); + if (!T->parent)group_number=0; + return fp; + } + + } +} + + +NT_node tree2collapsed_tree (NT_node T, int n, char **string) +{ + char ***list; + Sequence *A; + int a, *nlist; + + + A=tree2seq(T, NULL); + T=recode_tree(T, A); + list=vcalloc (A->nseq, sizeof (char***)); + nlist=vcalloc (A->nseq, sizeof (int)); + if ( n==0)return T; + else if (n>1) + { + int l; + char *buf; + + for (l=0,a=0; a< n; a++)l+=strlen (string[a]); + buf=vcalloc ( 2*n+l+1, sizeof (char)); + for (a=0; a< n; a++){buf=strcat (buf,string[a]), buf=strcat ( buf, " ");} + list[0]=string2list (buf); + vfree (buf); + } + else if ( file_exists (NULL,string[0])) + { + list=read_group (string[0]); + } + else + { + fprintf (stderr, "\nERROR: file <%s> does not exist [FATAL:%s]\n",string[0], PROGRAM); + myexit (EXIT_FAILURE); + } + + + a=0; + while (list[a]) + { + int i, b; + n=atoi (list[a][0]); + for (b=0; bnseq; b++)nlist[b]=0; + for (b=2; bname, A->nseq, MAXNAMES); + nlist[i]=1; + } + T=collapse_sub_tree ( T,A->nseq,nlist,list[a][1]); + free_char (list[a], -1); + a++; + } + vfree (list); + return T; +} + +NT_node collapse_sub_tree ( NT_node T,int nseq, int *list, char *new_name) +{ + if (!T) return T; + else + { + int a=0; + + + while (alseq2[a]){a++;} + if (a==nseq) + { + sprintf ( T->name, "%s", new_name); + T->leaf=T->isseq=1; + T->left=T->right=NULL; + return T; + } + else + { + collapse_sub_tree (T->right, nseq, list, new_name); + collapse_sub_tree (T->left, nseq, list, new_name); + return T; + } + } +} + +/*********************************************************************/ +/* */ +/* tree pruning */ +/* */ +/* */ +/*********************************************************************/ +NT_node remove_leaf ( NT_node T); +NT_node prune_root (NT_node T); +NT_node main_prune_tree ( NT_node T, Sequence *S) +{ + T=prune_tree ( T, S); + return T; +} + +NT_node prune_tree ( NT_node T, Sequence *S) +{ + + if (!T ) return T; + + if (T->leaf && T->isseq && name_is_in_list (T->name,S->name, S->nseq, 100)==-1) + { + NT_node C, P, PP; + + P=T->parent; + if ( !P) + { + int a; + for (a=0; a< S->nseq; a++) + { + HERE ("prune pb ---%s", S->name[a]); + } + myexit (EXIT_FAILURE); + } + C=(P->right==T)?P->left:P->right; + PP=C->parent=P->parent; + + if (PP && PP->right==P)PP->right=C; + else if (PP)PP->left=C; + else + { + if (T==P->right)P->right=NULL; + else P->left=NULL; + T=C; + + } + } + else + { + prune_tree (T->left, S); + prune_tree (T->right, S); + } + return prune_root(T); +} + +NT_node prune_root (NT_node T) +{ + //This function prunes the root if needed (and frees it). + if (T->parent)return T; + + if (!T->right && T->left) + { + return prune_root (T->left); + } + else if (T->right && !T->left) + { + + return prune_root (T->right); + } + else + { + return T; + } +} +/*********************************************************************/ +/* */ +/* tree comparison */ +/* */ +/* */ +/*********************************************************************/ +int main_compare_cog_tree (NT_node T1, char *cogfile) +{ + char ***array; + int a, nbac, n=0, p, c, b; + Alignment *A; + + array=file2list(cogfile, ";\n"); + nbac=atoi(array[0][0])-2; + + A=declare_aln2 (nbac+1, 10); + for (a=0; aname[a], "%s", array[0][a+2]); + A->seq_al[a][0]='a'; + A->seq_al[a][1]='\0'; + + } + sprintf ( A->name[nbac], "cons"); + + A->nseq=nbac+1; + A->len_aln=1; + + + n=3; + while (array[n]!=NULL) + { + for (b=0; bseq_al[b][0]=p; + A->seq_al[b][1]=c; + A->seq_al[b][2]='\0'; + + } + sprintf (A->file[0], "%s", array[n][1]); + A->len_aln=2; + main_compare_aln_tree (T1, A, stdout); + n++; + } + return n; +} + + +int main_compare_aln_tree (NT_node T1, Alignment *A, FILE *fp) +{ + int n=0; + + fprintf ( fp, "\nTOT_CLASH COG %s N %d", A->file[0], compare_aln_tree (T1, A, &n, fp)); + vfclose (fp); + return n; +} + +int compare_aln_tree (NT_node T, Alignment *A, int *n, FILE *fp) +{ + if (T->leaf) + { + int i; + i=name_is_in_list (T->name, A->name, A->nseq, 100); + T->seqal=A->seq_al[i]; + return 0; + } + else + { + char *seq1, *seq2; + if (!(T->left )->seqal)compare_aln_tree (T->left, A,n, fp); + if (!(T->right)->seqal)compare_aln_tree (T->right, A,n, fp); + + seq1=(T->left)->seqal; + seq2=(T->right)->seqal; + (T->left)->seqal=(T->right)->seqal=NULL; + if ( seq1 && seq2) + { + if (strm (seq1, seq2)) + { + T->seqal=seq1; + + } + else + { + + if (seq1[0]!=seq2[0] && seq1[1]!=seq2[1]) + { + fprintf ( fp, "\nNODE_CLASH: COG %s (%s,%s):(",A->file[0],seq1,seq2 ); + display_leaf_below_node (T->left, fp); + fprintf ( fp, ");("); + display_leaf_below_node (T->right, fp); + fprintf ( fp, ")"); + n[0]++; + } + } + } + } + return n[0]; +} +//********************************************************************** + +int compare_split (int *s1, int *s2, int l); +int get_split_size (int *s, int l); + +int main_compare_splits ( NT_node T1, NT_node T2, char *mode,FILE *fp) +{ + Sequence *S1, *S2, *S; + int a, b; + + + + int **sl1, n1; + int **sl2, n2; + if ( tree_contains_duplicates (T1)) + { + display_tree_duplicates (T1); + printf_exit (EXIT_FAILURE, stderr, "\nFirst Tree Contains Duplicated Sequences [main_compare_trees][FATAL:%s]", PROGRAM); + + } + else if ( tree_contains_duplicates (T2)) + { + display_tree_duplicates (T2); + printf_exit (EXIT_FAILURE, stderr, "\nSecond Tree Contains Duplicated Sequences [main_compare_trees]"); + + } + + //Identify the commom Sequence Set + S1=tree2seq(T1, NULL); + + + S2=tree2seq(T2, NULL); + + + S=trim_seq ( S1, S2); + + //Prune the trees and recode the subtree list + T1=prune_tree (T1, S); + T1=recode_tree(T1, S); + + T2=prune_tree (T2, S); + T2=recode_tree(T2, S); + HERE ("1"); + sl1=declare_int (10*S->nseq, S->nseq); + sl2=declare_int (10*S->nseq, S->nseq); + + HERE ("2"); + n1=n2=0; + tree2split_list (T1, S->nseq, sl1, &n1); + tree2split_list (T2, S->nseq, sl2, &n2); + + for (a=0; anseq); + for (best=0,b=0; bnseq); + best=MAX(s,best); + } + fprintf ( fp, "\n%4d %4d ", MIN(n,(S->nseq)), best); + for (b=0; bnseq; b++)fprintf ( fp, "%d", sl1[a][b]); + } + + free_sequence (S, -1); + free_sequence (S1, -1); + free_sequence (S2, -1); + myexit (EXIT_SUCCESS); + return 1; +} +int compare_split (int *s1, int *s2, int l) +{ + int n1, n2, score1, score2, a; + n1=get_split_size (s1, l); + n2=get_split_size (s2, l); + + for (score1=0,a=0; a< l; a++) + { + score1+=(s1[a]==1 && s2[a]==1)?1:0; + } + score1=(score1*200)/(n1+n2); + + for ( score2=0, a=0; a SCORE_MAX) + SCORE_MAX = score[i]; + } + for(i = 0; i < len; i++) + score[i] = (9*(score[i]-SCORE_MIN)/(SCORE_MAX-SCORE_MIN)); +} + +int new_compare_trees ( NT_node T1, NT_node T2, int nseq, Tree_sim *TS); +NT_node new_search_split (NT_node T, NT_node B, int nseq); +int new_compare_split ( int *b1, int *b2, int n); +Tree_sim* tree_scan_pos (Alignment *A, int start, int end, char *ptree, NT_node RT); +Tree_sim* tree_scan_pos_woble (Alignment *A, int center, int max, char *ptree, NT_node RT, int *br, int *bl ); +Tree_sim* tree_scan_pair_pos (Alignment *A, int start, int end, int start2, int end2,char *ptree, NT_node RT); +Tree_sim* tree_scan_multiple_pos (int *poslist, int *wlist,int nl, Alignment *A, char *ptree, NT_node RT); +NT_node aln2std_tree(Alignment *A, int ipara1, int ipara2, char *mode); + +NT_node tree_scan (Alignment *A,NT_node RT, char *pscan, char *ptree) +{ + int l, a,ax, c, cx, b; + char mode[100]; + int start, w; + int nl, *poslist; + char posfile[100]; + + char *pcFileName = A->file[0]; + char prefix[200] ={0}; + int len = (strrchr(pcFileName,'.')?strrchr(pcFileName,'.')-pcFileName:strlen(pcFileName)); + strncpy(prefix, pcFileName, len); + + float *fascore; + char out_format[100]; + + char *score_csv_file = vcalloc(200, sizeof (char)); + char *score_html_file = vcalloc(200, sizeof (char)); + char *hit_matrix_file = vcalloc(200, sizeof (char)); + char *hit_html_file = vcalloc(200, sizeof (char)); + char *tree_file = vcalloc(200, sizeof (char)); + + sprintf(score_csv_file, "%s%s", prefix, ".score_csv"); + sprintf(score_html_file, "%s%s", prefix, ".ts_html"); + sprintf(hit_matrix_file, "%s%s", prefix, ".hit_matrix"); + sprintf(hit_html_file, "%s%s", prefix, ".hit_html"); + sprintf(tree_file, "%s%s", prefix, ".trees_txt"); + + if ( pscan && strstr ( pscan, "help")) + { + fprintf ( stdout, "\n+tree_scan| _W_ : Window size for the tree computation|STD size in norscan mode"); + fprintf ( stdout, "\n+tree_scan| _MODE_ : Mode for the number of windows (single, double, list, scan, pairscan, norscan, hit, norhit)"); + fprintf ( stdout, "\n+tree_scan| _MINW_ : Minimum Window size when using the scan mode (4)"); + fprintf ( stdout, "\n+tree_scan| _OUTTREE_ : specify the format of outputing tree in every position (default: not ouput)"); + myexit (EXIT_SUCCESS); + } + + strget_param (pscan, "_W_", "5", "%d",&w); + strget_param (pscan, "_MODE_", "single", "%s",mode); + strget_param (pscan, "_MINW_", "1", "%d",&start); + strget_param (pscan, "_POSFILE_", "NO", "%s", posfile); + strget_param (pscan, "_OUTTREE_", "", "%s", &out_format); + + if(strlen(out_format) > 1) + unlink(tree_file); + + l=intlen (A->len_aln); + + poslist=vcalloc ( A->len_aln, sizeof (int)); + nl=0; + fascore = vcalloc(A->len_aln, sizeof (float)); + + if ( strm (posfile, "NO")) + { + + for ( a=0; a< A->len_aln; a++)poslist[nl++]=a+1; + } + else + { + int *p; + p=file2pos_list (A,posfile); + poslist=pos2list (p, A->len_aln, &nl); + for (a=0; auw); + vfree (TS); + } + } + else if ( strm (mode, "single")) + { + for (b=0,ax=0; axA->len_aln)continue; + if (pend<1 || pend>A->len_aln)continue; + TS=tree_scan_pos (A, pstart,pend, ptree, RT); + fprintf ( stdout, "P: %*d I: %*d %*d SIM: %6.2f L: %2d\n", l,a,l,pstart,l,pend,TS->uw, (w*2)+1); + vfree (TS); + } + } + else if (strm (mode, "scan")||strm (mode, "hit")) + { + FILE *fp_ts; + fp_ts=vfopen (score_csv_file, "w"); + fprintf ( fp_ts, "Position,Win_Beg,Win_End,Similarity,Win_Len\n"); + for ( ax=0; axA->len_aln)continue; + if (pend<1 || pend>A->len_aln)continue; + TS=tree_scan_pos (A, pstart,pend, ptree, RT); + if (TS->uw>=best_score) + {best_score=TS->uw;best_w=b;best_start=pstart; best_end=pend;} + vfree (TS); + } + fprintf (fp_ts, "%*d,%*d,%*d,%6.2f,%2d\n", l,best_pos, l,best_start, l,best_end, best_score,(best_w*2)+1); + fascore[ax]=(float)best_score; + if(strlen(out_format) > 1) + vfclose (print_tree (aln2std_tree(A, best_start, best_end, mode), out_format, vfopen (tree_file, "a+"))); + if(strm (mode, "hit")) + TreeArray[ax] = aln2std_tree(A, best_start, best_end, mode); + } + vfclose(fp_ts); + } +//tree scan by using normal distribution window +//or +//generate hit matrix + else if ( strm (mode, "norscan")||strm (mode, "norhit")) + { + FILE *fp_ts; + ptree=vcalloc(100, sizeof (char)); + fp_ts=vfopen (score_csv_file, "w"); + fprintf ( fp_ts, "Position,Similarity,STD_Len\n"); + for ( ax=0; axuw>=best_score) + {best_score=TS->uw;best_STD=b;} + vfree (TS); + } + fascore[ax]=best_score; + fprintf ( fp_ts, "%*d,%6.2f,%d\n", l,a, fascore[ax], best_STD); + if(strlen(out_format) > 1) + vfclose (print_tree (aln2std_tree(A, best_STD, a, mode), out_format, vfopen (tree_file, "a+"))); + if(strm (mode, "norhit")) + TreeArray[ax] = aln2std_tree(A, best_STD, a, mode); + } + vfclose(fp_ts); + } +//generate hit matrix + if (strm (mode, "hit")||strm (mode, "norhit")) + { +//Compute the pair score of tree scan segqtion + fprintf (stdout, "[STRAT] Calculate the hit matrix of the tree scan\n"); + float **ffpHitScoreMatrix; + + ffpHitScoreMatrix=vcalloc (nl, sizeof (float*)); + int i, j; + for(i = 0; i < nl; i++) + ffpHitScoreMatrix[i]=vcalloc (nl-i, sizeof (float)); + + fprintf (stdout, "Process positions\n", i); + for(i = 0; i < nl; i++) + { + fprintf (stdout, "%d, ", i); + for(j = i; j < nl; j++) + { + Tree_sim *TS; + TS=tree_cmp (TreeArray[i], TreeArray[j]); + ffpHitScoreMatrix[i][j-i] = TS->uw; + vfree (TS); + } + } + vfree(TreeArray); + fprintf (stdout, "\n"); + output_hit_matrix(hit_matrix_file, ffpHitScoreMatrix, nl); + fprintf (stdout, "[END]Calculate the hit matrix of the tree scan\n"); + +//Output Hit Score into color html + output_hit_color_html (A, ffpHitScoreMatrix, nl, hit_html_file); + vfree(ffpHitScoreMatrix); + } + else if ( strm (mode, "pairscan")) + { + int d, set; + + for ( ax=0; axA->len_aln)continue; + if (pend<1 || pend>A->len_aln)continue; + if (p2start<1 || p2start>A->len_aln)continue; + if (p2end<1 || p2end>A->len_aln)continue; + if (pstart<=p2start && pend>=p2start) continue; + if (pstart<=p2end && pend>=p2end) continue; + TS=tree_scan_pair_pos (A, pstart,pend,p2start, p2end, ptree, RT); + + if (TS->uw>=best_score){best_score=TS->uw; best_pos=a;best_w=b;best_start=pstart; best_end=pend; best_pos2=c, best_w2=d, best_start2=p2start, best_end2=p2end;set=1;} + vfree (TS); + } + } + if (set)fprintf ( stdout, "P1: %*d I1: %*d %*d P2: %*d I2: %*d %*d SIM: %6.2f L: %2d\n", l,best_pos, l,best_start, l,best_end, l, best_pos2, l, best_start2, l, best_end2, best_score,(best_w*2)+1 ); + + set=0; + } + } + } + else if ( strm (mode, "multiplescan")) + { + int n, **wlist, best_pos; + float best_score; + Tree_sim *TS; + wlist=generate_array_int_list (nl*2,start, w,1, &n, NULL); + HERE ("Scan %d Possibilities", n); + + for (best_score=best_pos=0,a=0; auw>best_score) + { + best_score=TS->uw; + fprintf ( stdout, "\n"); + for (b=0; bS; + ST=copy_aln (A, NULL); + for (a=0; anseq; a++) + { + i=name_is_in_list (ST->name[a],S->name, S->nseq, 100); + if ( i!=-1) + { + for (b=0; blen_aln; b++) + { + r1=ST->seq_al[a][b]; + if ( r1!='-') + r1 = (int)fascore[b] + 48; + ST->seq_al[a][b]=r1; + } + } + } + output_color_html ( A, ST, score_html_file); + +//free memory + free_aln(ST); + vfree(fascore); + vfree(score_csv_file); + vfree(score_html_file); + vfree(hit_matrix_file); + vfree(hit_html_file); + + myexit(EXIT_SUCCESS);return NULL; +} + +NT_node aln2std_tree(Alignment *A, int ipara1, int ipara2, char *mode) +{ + Alignment *B; + NT_node T; + char *cpSet = vcalloc(100, sizeof (char)); + + if(strm (mode, "norhit")) + { + B=extract_aln (A, 1, A->len_aln); + sprintf ( cpSet, "+aln2tree _COMPARE_nordisaln__STD_%d__CENTER_%d_", ipara1, ipara2); + } + else + B=extract_aln (A, ipara1, ipara2); + + T=compute_std_tree (B, (cpSet)?1:0, (cpSet)?&cpSet:NULL); + free_aln(B); + return T; +} + +Tree_sim* tree_scan_multiple_pos (int *poslist, int *wlist,int nl, Alignment *A, char *ptree, NT_node RT) +{ + static Alignment *B; + static int *pos; + int a, b, n, s, p, left, right; + Tree_sim *TS; + NT_node T=NULL; + + + //poslist positions come [1..n] + vfree(pos); + free_aln (B); + + pos=vcalloc ( A->len_aln+1, sizeof (int)); + B=copy_aln (A, NULL); + + for (a=0; aA->len_aln) return NULL; + else pos[b]++; + + if (pos[b]>1) return NULL; + } + } + + for (s=0; snseq; s++) + { + for (n=0,a=1; a<=A->len_aln; a++) + { + if (pos[a])B->seq_al[s][n++]=A->seq_al[s][a-1]; + } + } + + B->len_aln=n; + for (s=0; snseq; s++)B->seq_al[s][B->len_aln]='\0'; + + T=compute_std_tree (B, (ptree)?1:0, (ptree)?&ptree:NULL); + + TS=tree_cmp (T, RT); + + free_tree(T); + return TS; + } + +Tree_sim* tree_scan_pair_pos (Alignment *A, int start, int end, int start2, int end2,char *ptree, NT_node RT) + { + Tree_sim *TS; + Alignment *B,*B1, *B2; + NT_node T=NULL; + int a; + + + B=copy_aln (A, NULL); + B1=extract_aln (A,start,end); + B2=extract_aln (A,start2, end2); + + + for ( a=0; a< B->nseq;a++) + sprintf (B->seq_al[a], "%s%s", B1->seq_al[a], B2->seq_al[a]); + B->len_aln=strlen (B->seq_al[0]); + + T=compute_std_tree (B, (ptree)?1:0, (ptree)?&ptree:NULL); + TS=tree_cmp (T, RT); + + free_tree(T); + free_aln (B);free_aln(B1); free_aln(B2); + + return TS; + } + +Tree_sim* tree_scan_pos (Alignment *A, int start, int end, char *ptree, NT_node RT) + { + Tree_sim *TS; + Alignment *B; + NT_node T; + + if ( start<1 || start>A->len_aln) return NULL; + if ( end<1 || end>A->len_aln) return NULL; + + B=extract_aln (A,start,end); + T=compute_std_tree (B, (ptree)?1:0, (ptree)?&ptree:NULL); + TS=tree_cmp (T, RT); + free_tree(T);free_aln (B); + return TS; + } +Tree_sim* tree_scan_pos_woble (Alignment *A, int center, int max, char *ptree, NT_node RT, int *br, int *bl ) + { + Tree_sim *TS,*BTS; + + + int left, right; + float best_score=0; + int start, end; + + br[0]=bl[0]=0; + BTS=vcalloc (1, sizeof (Tree_sim)); + + for (left=0; leftuw >best_score) + { + best_score=TS->uw; + BTS[0]=TS[0]; + br[0]=right; bl[0]=left; + vfree(TS); + } + } + return BTS; + } + +Tree_sim* tree_cmp( NT_node T1, NT_node T2) +{ + Sequence *S1, *S2, *S; + int n; + int a; + + Tree_sim *TS1, *TS2; + + if ( tree_contains_duplicates (T1)) + { + display_tree_duplicates (T1); + printf_exit (EXIT_FAILURE, stderr, "\nFirst Tree Contains Duplicated Sequences [main_compare_trees][FATAL:%s]", PROGRAM); + + } + else if ( tree_contains_duplicates (T2)) + { + display_tree_duplicates (T2); + printf_exit (EXIT_FAILURE, stderr, "\nSecond Tree Contains Duplicated Sequences [main_compare_trees]"); + + } + + //Identify the commom Sequence Set + S1=tree2seq(T1, NULL); + S2=tree2seq(T2, NULL); + + S=trim_seq ( S1, S2); + + if ( S->nseq<=2) + { + fprintf ( stderr, "\nERROR: Your two do not have enough common leaf to be compared [FATAL:PROGRAM]"); + } + + //Prune the trees and recode the subtree list + T1=prune_tree (T1, S); + T1=recode_tree(T1, S); + + T2=prune_tree (T2, S); + T2=recode_tree(T2, S); + + TS1=vcalloc (1, sizeof (Tree_sim)); + TS2=vcalloc (1, sizeof (Tree_sim)); + + new_compare_trees ( T1, T2, S->nseq, TS1); + new_compare_trees ( T2, T1, S->nseq, TS2); + + + TS1->n=tree2nnode (T1); + TS1->nseq=S->nseq; + + TS2->n=tree2nnode (T2); + /*if (TS1->n !=TS2->n) + printf_exit (EXIT_FAILURE, stderr,"\nERROR: Different number of Nodes in the two provided trees after prunning [FATAL: %s]", PROGRAM); + */ + + free_sequence (S, -1); + free_sequence (S1, -1); + free_sequence (S2, -1); + + TS1->uw=(TS1->uw+TS2->uw)*100/(TS1->max_uw+TS2->max_uw); + TS1->w=(TS1->w+TS2->w)*100/(TS1->max_w+TS2->max_w); + TS1->d=(TS1->d+TS2->d)*100/(TS1->max_d+TS2->max_d); + TS1->rf=(TS1->rf+TS2->rf)/2; + vfree (TS2); + return TS1; +} +int print_node_list (NT_node T, Sequence *RS) +{ + NT_node *L; + Sequence *S; + int *nlseq2; + + S=tree2seq(T, NULL); + L=tree2node_list (T, NULL); + if (!RS)RS=S; + + nlseq2=vcalloc ( RS->nseq, sizeof (int)); + while (L[0]) + { + int d,b; + d=MIN(((L[0])->nseq), (S->nseq-(L[0])->nseq)); + fprintf ( stdout, "Bootstrap: %5.2f Depth: %5d Splits: ", (L[0])->bootstrap, d); + + for (b=0; bnseq; b++)nlseq2[b]='-'; + for (b=0; bnseq; b++) + { + int p; + p=name_is_in_list (S->name[b], RS->name, RS->nseq, 100); + if (p!=-1)nlseq2[p]=(L[0])->lseq2[b]+'0'; + } + for (b=0; bnseq; b++) fprintf ( stdout, "%c", nlseq2[b]); + fprintf (stdout, "\n"); + L++; + } + return 1; +} +NT_node main_compare_trees_list ( NT_node RT, Sequence *S, FILE *fp) +{ + Tree_sim *T; + NT_node *TL; + Sequence *RS; + int a; + + T=vcalloc (1, sizeof (Tree_sim)); + RS=tree2seq(RT, NULL); + + TL=read_tree_list (S); + + reset_boot_tree (RT,0.0001); + for (a=0; anseq; a++) + { + TL[a]=prune_tree(TL[a],RS); + TL[a]=recode_tree (TL[a],RS); + new_compare_trees (RT, TL[a], RS->nseq,T); + } + + vfree (T); + return RT; +} +NT_node main_compare_trees ( NT_node T1, NT_node T2, FILE *fp) +{ + Tree_sim *T; + + T=tree_cmp (T1, T2); + fprintf ( fp, "\n#tree_cmp|T: %.f W: %.2f L: %.2f RF: %d N: %d S: %d", T->uw, T->w, T->d, T->rf, T->n, T->nseq); + fprintf ( fp, "\n#tree_cmp_def|T: ratio of identical nodes"); + fprintf ( fp, "\n#tree_cmp_def|W: ratio of identical nodes weighted with the min Nseq below node"); + fprintf ( fp, "\n#tree_cmp_def|L: average branch length similarity"); + fprintf ( fp, "\n#tree_cmp_def|RF: Robinson and Foulds"); + fprintf ( fp, "\n#tree_cmp_def|N: number of Nodes in T1 [unrooted]"); + fprintf ( fp, "\n#tree_cmp_def|S: number of Sequences in T1\n"); + + vfree (T); + return T1; +} + +int new_compare_trees ( NT_node T1, NT_node T2, int nseq, Tree_sim *TS) +{ + int n=0; + NT_node N; + float t1, t2; + + if (!T1 || !T2) return 0; + + n+=new_compare_trees (T1->left, T2, nseq,TS); + n+=new_compare_trees (T1->right, T2, nseq,TS); + + //Exclude arbitrary splits (dist==0) + if ((T1->dist==0) && !(T1->parent))return n; + + N=new_search_split (T1, T2, nseq); + t1=FABS(T1->dist); + t2=(N)?FABS(N->dist):0; + TS->max_d+=MAX(t1, t2); + + if (!N)TS->rf++; + if (T1->nseq>1) + { + int w; + w=MIN((nseq-T1->nseq),T1->nseq); + TS->max_uw++; + TS->max_w+=w; + + if (N) + { + TS->uw++; + TS->w+=w; + TS->d+=MIN(t1, t2); + T1->bootstrap++; + //T1->dist=T1->nseq; + } + else + { + //T1->dist=T1->nseq*-1; + ; + } + } + else + { + TS->d+=MIN(t1, t2); + //T1->dist=1; + } + return ++n; +} +NT_node new_search_split (NT_node T, NT_node B, int nseq) +{ + NT_node N; + if (!T || !B) return NULL; + else if ( new_compare_split (T->lseq2, B->lseq2, nseq)==1)return B; + else if ( (N=new_search_split (T, B->right, nseq)))return N; + else return new_search_split (T, B->left, nseq); +} +int new_compare_split ( int *b1, int *b2, int n) +{ + int a, flag; + + for (flag=1, a=0; aparent && T1->nseq>1)n+=search_node ( T1, T2, nseq, mode); + + n+=compare_trees ( T1->left, T2, nseq, mode); + n+=compare_trees ( T1->right, T2, nseq, mode); + + return n; +} + +float search_node ( NT_node B, NT_node T, int nseq, int mode) +{ + int n=0; + if ( !B || !T) return -1; + if (getenv4debug("DEBUG_TREE_COMPARE"))display_node ( T, "\n\t", nseq); + + n=compare_node ( B->lseq2, T->lseq2, nseq ); + + if ( n==1) + { + if (getenv4debug("DEBUG_TREE_COMPARE"))fprintf ( stderr, "[1][%d]", (int)evaluate_node_similarity ( B, T, nseq, mode)); + if (mode==RECODE)B->dist=B->leaf; + return evaluate_node_similarity ( B, T, nseq, mode); + } + else if ( n==-1) + { + if (getenv4debug("DEBUG_TREE_COMPARE"))fprintf ( stderr, "[-1]"); + if (mode==RECODE)B->dist=-B->leaf; + return 0; + } + else + { + if (getenv4debug("DEBUG_TREE_COMPARE"))fprintf ( stderr, "[0]"); + n=search_node ( B, T->left, nseq, mode); + if ( n>0) return n; + n=search_node ( B, T->right, nseq, mode); + if ( n>0) return n; + n=search_node ( B, T->bot, nseq, mode); + if ( n>0) return n; + } + return n; +} + +float evaluate_node_similarity ( NT_node B, NT_node T, int nseq, int mode) +{ +int a, c; + + if ( mode==TOPOLOGY || mode ==RECODE) + { + for ( a=0; a< nseq; a++) + if ( B->lseq2[a]!=T->lseq2[a]) return 0; + return 1; + } + else if ( mode == WEIGHTED) + { + for (c=0, a=0; a< nseq; a++) + { + if ( B->lseq2[a]!=T->lseq2[a]) return 0; + else c+=B->lseq2[a]; + } + return (float)(MIN(c,nseq)); + } + else if ( mode == LENGTH ) + { + float d1, d2; + + for (c=0, a=0; a< nseq; a++) + { + if ( B->lseq2[a]!=T->lseq2[a]) return 0; + } + d1=FABS((B->dist-T->dist)); + d2=MAX(B->dist, T->dist); + return (d2>0)?(d1*100)/d2:0; + } + else + { + return 0; + } +} +int compare_node ( int *b1, int *b2, int nseq) +{ + int n1, n2; + + n1=compare_node1 ( b1, b2, nseq); + /*fprintf ( stderr, "[%d]", n1);*/ + if ( n1==1) return 1; + + n2=compare_node2 ( b1, b2, nseq); + /* fprintf ( stderr, "[%d]", n2);*/ + if ( n2==1)return 1; + else if ( n2==-1 && n1==-1) return -1; + else return 0; +} +int compare_node1 ( int *b1, int *b2, int n) +{ + int a; + int l1, l2; + int r=1; + for ( a=0; a< n; a++) + { + l1=b1[a]; + l2=b2[a]; + if ( l1==1 && l2==0) return -1; + if ( l1!=l2)r=0; + } + return r; +} +int compare_node2 ( int *b1, int *b2, int n) +{ + int a; + int l1, l2; + int r=1; + + for ( a=0; a< n; a++) + { + l1=1-b1[a]; + l2=b2[a]; + if ( l1==1 && l2==0) return -1; + if ( l1!=l2) r=0; + } + return r; +} +void display_node (NT_node N, char *string,int nseq) +{ + int a; + fprintf ( stderr, "%s", string); + for (a=0; a< nseq; a++)fprintf ( stderr, "%d", N->lseq2[a]); +} + + +/*********************************************************************/ +/* */ +/* FJ_tree Computation */ +/* */ +/* */ +/*********************************************************************/ + + +NT_node tree_compute ( Alignment *A, int n, char ** arg_list) +{ + if (n==0 || strm (arg_list[0], "cw")) + { + return compute_cw_tree (A); + } + else if ( strm (arg_list[0], "fj")) + { + return compute_fj_tree ( NULL, A, (n>=1)?atoi(arg_list[1]):8, (n>=2)?arg_list[2]:NULL); + } + + else if ( ( strm (arg_list[0], "nj"))) + { + return compute_std_tree (A, n, arg_list); + } + else + return compute_std_tree (A, n, arg_list); +} + +NT_node compute_std_tree (Alignment *A, int n, char **arg_list) +{ + return compute_std_tree_2 (A, NULL, list2string (arg_list, n)); +} +NT_node compute_std_tree_2 (Alignment *A, int **s, char *cl) +{ + + NT_node T, **BT=NULL; + char *tree_name; + + char matrix[100]; + char score [100]; + char compare[100]; + char tmode[100]; + int free_s=0; + + tree_name =vtmpnam (NULL); + + if (strstr (cl, "help")) + { + fprintf ( stdout, "\n+aln2tree| _MATRIX_ : matrix used for the comparison (idmat, sarmat, pam250mt..)\n"); + fprintf ( stdout, "\n+aln2tree| _SCORE_ : score mode used for the distance (sim, raw)\n"); + fprintf ( stdout, "\n+aln2tree| _COMPARE_: comparison mode (aln, ktup, align, nordisaln)\n"); + fprintf ( stdout, "\n+aln2tree| _TMODE_ : tree mode (nj, upgma)\n"); + myexit (EXIT_SUCCESS); + } + + + //matrix: idmat, ktup,sarmat, sarmat2 + strget_param (cl, "_MATRIX_", "idmat", "%s",matrix); + + //score: sim, raw + strget_param (cl, "_SCORE_", "sim", "%s",score); + + //compare: aln, ktup, align + strget_param (cl, "_COMPARE_", "aln", "%s",compare); + + //compare: aln, ktup, align + strget_param (cl, "_TMODE_", "nj", "%s",tmode); + + int STD, CENTER; + if ( strm (compare, "nordisaln")) + { + strget_param (cl, "_STD_", "1", "%d", &STD); + strget_param (cl, "_CENTER_", "5", "%d", &CENTER); + } + //Use external msa2tree methods + if ( strm (tmode, "cw")) + { + free_int (s, -1); + return compute_cw_tree (A); + } + + //compute distance matrix if needed + if ( !s) + { + free_s=1; + if ( strm (compare, "ktup")) + { + ungap_array (A->seq_al, A->nseq); + s=get_sim_aln_array ( A,cl); + } + else if ( strm ( compare, "aln")) + { + if (strm (score, "sim")) + s=get_sim_aln_array(A, matrix); + else if ( strm (score, "raw")) + { + s=get_raw_sim_aln_array (A,matrix); + } + } + else if ( strm ( compare, "nordisaln")) + { + s=get_sim_aln_array_normal_distribution(A, matrix, &STD, &CENTER); + } + s=sim_array2dist_array(s, 100); + } + + //Compute the tree + if (strm (tmode, "nj")) + { + + BT=int_dist2nj_tree (s, A->name, A->nseq, tree_name); + T=main_read_tree (tree_name); + free_read_tree(BT); + } + else if (strm (tmode, "upgma")) + { + BT=int_dist2upgma_tree (s,A, A->nseq, tree_name); + T=main_read_tree (tree_name); + free_read_tree(BT); + } + + if ( strm ( cl, "dpa")) + { + s=dist_array2sim_array(s, 100); + T=code_dpa_tree (T,s); + } + + if (free_s)free_int (s, -1); + return T; +} + +NT_node similarities_file2tree (char *mat) +{ + int **s; + Alignment *A; + char *tree_name; + NT_node T; + + + + tree_name =vtmpnam (NULL); + + s=input_similarities (mat,NULL, NULL); + + + A=similarities_file2aln(mat); + s=sim_array2dist_array(s, 100); + + + int_dist2nj_tree (s, A->name, A->nseq, tree_name); + T=main_read_tree(tree_name); + free_int (s, -1); + return T; +} + +NT_node compute_cw_tree (Alignment *A) +{ + char *tmp1, *tmp2, tmp3[1000]; + + tmp1=vtmpnam (NULL); + tmp2=vtmpnam (NULL); + + sprintf ( tmp3, "%s.ph", tmp1); + output_clustal_aln (tmp1, A); + printf_system ("clustalw -infile=%s -tree -newtree=%s %s ", tmp1,tmp3, TO_NULL_DEVICE); + printf_system("mv %s %s", tmp3, tmp2); + + return main_read_tree(tmp2); +} + +NT_node compute_fj_tree (NT_node T, Alignment *A, int limit, char *mode) +{ + static int in_fj_tree; + if (!in_fj_tree)fprintf ( stderr, "\nComputation of an NJ tree using conserved positions\n"); + + in_fj_tree++; + if (T && T->leaf<=2); + else + { + T=aln2fj_tree(T,A,limit, mode); + T->right=compute_fj_tree ( T->right, A, limit, mode); + T->left=compute_fj_tree ( T->left, A, limit, mode); + } + in_fj_tree--; + return T; +} + + +NT_node aln2fj_tree(NT_node T, Alignment *A, int limit_in, char *mode) +{ + NT_node NT; + Sequence *S=NULL; + Alignment *subA=NULL; + int fraction_gap; + int l, limit; + + if (T) + S=tree2seq (T,NULL); + else + S=aln2seq (A); + + + l=0; + for ( fraction_gap=100; fraction_gap<=100 && l<1; fraction_gap+=10) + for ( limit=limit_in; limit>0 && l<1; limit--) + { + fprintf ( stderr, "\n%d %d", limit, fraction_gap); + free_aln (subA); + subA=extract_sub_aln2 (A,S->nseq,S->name); + subA=filter_aln4tree (subA,limit,fraction_gap, mode); + l=subA->len_aln; + } + + /* while ( subA->len_aln<1) + { + subA=extract_sub_aln2 (A,S->nseq,S->name); + subA=filter_aln4tree (subA,limit,fraction_gap,mode); + free_aln (subA); + subA=extract_sub_aln2 (A,S->nseq,S->name); + subA=filter_aln4tree (subA,--limit,fraction_gap, mode); + } + */ + NT=aln2tree (subA); + NT=tree2fj_tree (NT); + + NT=realloc_tree (NT,A->nseq); + fprintf ( stderr, "Limit:%d Gap: %d Columns: %4d Left: %4d Right %4d BL:%4.2f\n",limit,fraction_gap, subA->len_aln, (NT->right)->leaf,(NT->left)->leaf, (NT->left)->dist+(NT->right)->dist); + + if ( T) + { + NT->dist=T->dist; + NT->parent=T->parent; + } + free_tree(T); + free_aln (subA); + free_sequence (S, -1); + return NT; +} + +Alignment * filter_aln4tree (Alignment *A, int n,int fraction_gap,char *mode) +{ + char *aln_file; + char *ungaped_aln_file; + char *scored_aln_file; + char *filtered_aln_file; + + aln_file=vtmpnam(NULL); + ungaped_aln_file=vtmpnam (NULL); + scored_aln_file=vtmpnam (NULL); + scored_aln_file=vtmpnam(NULL); + filtered_aln_file=vtmpnam(NULL); + + + + output_clustal_aln (aln_file, A); + /* 1: remove columns with too many gaps*/ + printf_system ("t_coffee -other_pg seq_reformat -in %s -action +rm_gap %d -output clustalw > %s", aln_file,fraction_gap, ungaped_aln_file); + + /* 2: evaluate the alignment*/ + + printf_system ("t_coffee -other_pg seq_reformat -in %s -action +evaluate %s -output clustalw > %s", ungaped_aln_file,(mode)?mode:"categories", scored_aln_file); + + + /*3 extract the high scoring columns*/ + printf_system("t_coffee -other_pg seq_reformat -in %s -struc_in %s -struc_in_f number_aln -action +use_cons +keep '[%d-8]' +rm_gap -output clustalw > %s", ungaped_aln_file, scored_aln_file,n, filtered_aln_file); + + + free_aln (A); + + A=main_read_aln ( filtered_aln_file, NULL); + print_aln (A); + + return A; +} + +NT_node tree2fj_tree (NT_node T) +{ + NT_node L; + + return T; + + L=find_longest_branch (T, NULL); + T=reroot_tree (T, L); + return T; +} + + +/*********************************************************************/ +/* */ +/* Tree Filters and MAnipulation */ +/* */ +/* */ +/*********************************************************************/ +int tree2star_nodes (NT_node R, int n_max) +{ + if ( !R) return 0; + else if (!R->left && !R->right) + { + if (n_max>=1)R->dist=0; + return 1; + } + else + { + int n=0; + + n+=tree2star_nodes (R->right, n_max); + n+=tree2star_nodes (R->left, n_max); + + if (ndist=0; + return n; + } +} + +NT_node aln2tree (Alignment *A) +{ + NT_node **T=NULL; + + + T=make_nj_tree (A, NULL, 0, 0, A->seq_al, A->name, A->nseq, NULL, NULL); + tree2nleaf (T[3][0]); + + return T[3][0]; +} +NT_node realloc_tree ( NT_node R, int n) +{ + if ( !R)return R; + R->right=realloc_tree (R->right,n); + R->left=realloc_tree (R->left,n); + R->bot=realloc_tree (R->bot,n); + + R->lseq=vrealloc (R->lseq, n*sizeof (int)); + R->lseq2=vrealloc (R->lseq2, n*sizeof (int)); + return R; +} + +NT_node reset_boot_tree ( NT_node R, int n) +{ + if ( !R)return R; + R->right=reset_boot_tree (R->right,n); + R->left=reset_boot_tree (R->left,n); + R->bot=reset_boot_tree (R->bot,n); + R->bootstrap=(float)n; + + return R; +} +NT_node tree_dist2normalized_tree_dist ( NT_node R, float max) +{ + if (!R)return R; + else + { + tree_dist2normalized_tree_dist ( R->right, max); + tree_dist2normalized_tree_dist ( R->left, max); + R->bootstrap=(int)((R->dist*100)/max); + } + return R; +} +NT_node reset_dist_tree ( NT_node R, float n) +{ + if ( !R)return R; + R->right=reset_dist_tree (R->right,n); + R->left=reset_dist_tree (R->left,n); + R->bot=reset_dist_tree (R->bot,n); + + if (R->parent && !(R->parent)->parent && !(R->parent)->bot)R->dist=n/2; + else R->dist=n; + + return R; +} + + +NT_node* free_treelist (NT_node *L) +{ + int n=0; + while (L[n])free_tree (L[n++]); + vfree (L); + return NULL; +} +NT_node free_tree ( NT_node R) +{ + if ( !R)return R; + R->right=free_tree (R->right); + R->left=free_tree (R->left); + R->bot=free_tree (R->bot); + free_tree_node (R); + return R; +} + +NT_node free_tree_node ( NT_node R) +{ + if (!R)return NULL; + + vfree (R->seqal); + vfree (R->idist); + vfree (R->ldist); + vfree (R->file); + vfree ( R->name); + vfree ( R->lseq); vfree ( R->lseq2); + vfree (R); + return NULL; +} + +NT_node rename_seq_in_tree ( NT_node R, char ***list) +{ + if ( !R || !list) return R; + + if ( R->leaf!=1) + { + R->right=rename_seq_in_tree (R->right, list); + R->left=rename_seq_in_tree (R->left, list); + R->bot=rename_seq_in_tree (R->bot, list); + } + else + { + int n=0; + while ( list[n][0][0]) + { + if ( strm (list[n][0], R->name))sprintf (R->name, "%s",list[n][1]); + n++; + } + } + return R; +} +Sequence * tree2seq (NT_node R, Sequence *S) +{ + + if ( !R)return S; + if ( !S) + { + S=declare_sequence (10, 10, tree2nseq (R)); + S->nseq=0; + } + + if (R->leaf==1) + { + sprintf ( S->name[S->nseq++], "%s", R->name); + } + else + { + S=tree2seq (R->left, S); + S=tree2seq (R->right, S); + } + return S; +} + +NT_node balance_tree (NT_node T) +{ + static int **list; + NT_node NL[3]; + + if ( !T) return T; + else if ( T->leaf<=2)return T; + else + { + if (!list)list=declare_int (3, 2); + + NL[0]=T->left; + NL[1]=T->right; + NL[2]=T->bot; + + list[0][0]=(T->left)?(T->left)->leaf:0; + list[0][1]=0; + list[1][0]=(T->right)?(T->right)->leaf:0; + list[1][1]=1; + list[2][0]=(T->bot)?(T->bot)->leaf:0; + list[2][1]=2; + + sort_int (list,2,0,0,2); + + T->left=NL[list[2][1]]; + T->right=NL[list[1][1]]; + T->bot=NL[list[0][1]]; + + T->left=balance_tree (T->left); + T->right=balance_tree (T->right); + T->bot=balance_tree (T->bot); + return T; + } +} +FILE * display_tree (NT_node R, int nseq, FILE *fp) +{ + int a; + + if ( !R); + else + { + /* + if ( R->nseq==1)fprintf (stderr,"\n[%s] ", R->name); + else fprintf ( stderr, "\n[%d Node] ",R->nseq); + for ( a=0; a< R->nseq; a++) fprintf ( stderr, "[%d]", R->lseq[a]); + */ + fprintf (fp, "\n %10s N ", R->name); + for ( a=0; a< nseq; a++)fprintf (fp, "%d", R->lseq2[a]); + fprintf (fp, "\n %10s D ", R->name); + for ( a=0; a< nseq; a++)fprintf (fp, "%d", R->idist[a]); + + + if (R->leaf==1) fprintf (fp, " %s", R->name); + fprintf (fp, " :%.4f", R->dist); + HERE ("\nGo Left");fp=display_tree (R->left, nseq, fp); + HERE ("\nGo Right");fp=display_tree (R->right, nseq, fp); + HERE ("\nGo Bot");fp=display_tree (R->bot, nseq, fp); + } + return fp; +} +int tree2nnode_unresolved (NT_node R, int *l) +{ + if ( !R)return 0; + else if (R->leaf && R->dist==0){return 1;} + else + { + int n=0; + n+=tree2nnode_unresolved (R->right, l); + n+=tree2nnode_unresolved (R->left, l); + if (R->dist==0) + { + return n; + } + else + { + if (n)l[n]++; + return 0; + } + } + +} + +int tree2nnode ( NT_node R) +{ + int n; + if ( !R)n=0; + else if ( R->leaf==1){R->node=1;n=1;} + else + { + n=1; + n+=tree2nnode (R->right); + n+=tree2nnode (R->left); + n+=tree2nnode (R->bot); + R->node=n; + } + return n; +} +int tree2nleaf (NT_node R) +{ + if ( !R)return 0; + else if (R->leaf==1){return 1;} + else if (R->right==NULL && R->left==NULL && R->bot==NULL){R->leaf=1; return 1;} + else + { + int n=0; + n+=tree2nleaf (R->right); + n+=tree2nleaf (R->left); + n+=tree2nleaf (R->bot); + + R->leaf=n; + return n; + } +} + +int tree2nseq ( NT_node R) +{ + return tree2nleaf(R); +} + +int tree_file2nseq (char *fname) +{ + FILE *fp; + char *string; + int p, a, b, c, n; + + string=vcalloc (count_n_char_in_file(fname)+1, sizeof (char)); + + fp=vfopen (fname, "r"); + n=0; + while ( (c=fgetc(fp))!=EOF){if (c=='(' || c==')' || c==',' || c==';') string[n++]=c;} + vfclose (fp);string[n]='\0'; + + for (n=0, p=1; pvisited=0; + + if ( R->leaf==1); + else + { + clear_tree ( R->right); + clear_tree ( R->left); + clear_tree ( R->bot); + } +} +int display_leaf_below_node (NT_node T, FILE *fp) +{ + int n=0; + if ( !T)return 0; + + if ( T->leaf==1) + { + fprintf (fp, " %s", T->name); + return 1; + } + else + { + n+=display_leaf_below_node ( T->right, fp); + n+=display_leaf_below_node ( T->left, fp); + return n; + } +} +int display_leaf ( NT_node T, FILE *fp) +{ + int n=0; + if ( !T)return 0; + else if ( T->visited)return 0; + else T->visited=1; + + if ( T->leaf==1) + { + fprintf (fp, " %s", T->name); + return 1; + } + else + { + n+=display_leaf ( T->right, fp); + n+=display_leaf ( T->left, fp); + n+=display_leaf ( T->bot, fp); + return n; + } +} + + + + +NT_node find_longest_branch ( NT_node T, NT_node L) + { + + if ( !L || T->dist>L->dist) + { + + L=T; + } + + if ( T->leaf==1)return L; + else + { + L=find_longest_branch ( T->right, L); + L=find_longest_branch ( T->left, L); + return L; + } + } +int node2side (NT_node N); +int test_print (NT_node T); +NT_node straighten_node (NT_node N); +NT_node EMPTY; +NT_node Previous; +NT_node reroot_tree ( NT_node TREE, NT_node Right) +{ + /*ReRoots the tree between Node R and its parent*/ + NT_node NR; + int n1, n2; + + if (!EMPTY)EMPTY=vcalloc (1, sizeof (NT_node)); + if ( !Right->parent)return Right; + + TREE=unroot_tree (TREE); + if (Right->parent==NULL && Right->bot) + Right=Right->bot; + + n1=tree2nleaf (TREE); + + NR=declare_tree_node(TREE->maxnseq); + + NR->right=Right; + NR->left=Right->parent; + Right->parent=NR; + + Right->dist=Right->dist/2; + + if ((NR->left)->right==Right)(NR->left)->right=EMPTY; + else if ( (NR->left)->left==Right) (NR->left)->left=EMPTY; + + Previous=NULL; + + + NR->left=straighten_node (NR->left); + + + + (NR->left)->parent=NR; + (NR->left)->dist=Right->dist; + + + + n2=tree2nleaf(NR); + + if ( n1!=n2){fprintf ( stderr, "\n%d %d", n1, n2);myexit (EXIT_FAILURE);} + return NR; +} + +NT_node straighten_node ( NT_node N) +{ + NT_node Child; + + + if ( N->parent) + { + if (N->right==EMPTY)N->right=N->parent; + else if ( N->left==EMPTY) N->left=N->parent; + + Child=N->parent; + if (Child->right==N) + { + Child->right=EMPTY; + } + else if (Child->left==N) + { + Child->left=EMPTY; + } + + Previous=N; + Child=straighten_node (Child); + Child->parent=N; + Child->dist=N->dist; + return N; + } + else if ( N->bot && N->bot!=Previous) + { + if ( N->right==EMPTY)N->right=N->bot; + else if ( N->left==EMPTY)N->left=N->bot; + + N->bot=NULL; + return N; + } + else + { + N->bot=NULL; + return N; + } +} +int test_print (NT_node T) +{ + if ( !T) + { + fprintf ( stderr, "\nEMPTY"); + } + else if ( !T->left && !T->right) + { + fprintf ( stderr, "\n%s",T->name); + } + else + { + fprintf ( stderr, "\nGoing Right"); + test_print (T->right); + fprintf ( stderr, "\nGoing Left"); + test_print (T->left); + } + return 1; +} +int node2side (NT_node C) +{ + if ( !C->parent) return UNKNOWN; + else if ( (C->parent)->left==C)return LEFT; + else if ( (C->parent)->right==C)return RIGHT; + else return UNKNOWN; +} +NT_node straighten_tree ( NT_node P, NT_node C, float new_dist) +{ + float dist; + + if ( C==NULL)return NULL; + + + dist=C->dist; + C->dist=new_dist; + C->bot=NULL; + + if (C->left && C->right) + { + C->parent=P; + } + else if (!C->left) + { + C->left=C->parent; + C->parent=P; + } + + if ( C->parent==P); + else if ( C->left==NULL && C->right==NULL) + { + C->parent=P; + } + else if ( C->right==P) + { + C->right=C->parent; + C->parent=P; + + C=straighten_tree(C, C->right, dist); + } + else if ( C->left==P) + { + C->left=C->parent; + C->parent=P; + C=straighten_tree (C, C->left, dist); + } + else if ( C->parent==NULL) + { + C->parent=P; + } + + return C; +} + + +NT_node unroot_tree ( NT_node T) +{ + + if (!T || T->visited) return T; + else T->visited=1; + + if (T->parent==NULL) + { + + (T->right)->dist=(T->left)->dist=(T->right)->dist+(T->left)->dist; + (T->right)->parent=T->left; + (T->left)->parent=T->right; + T=T->left; + T->leaf=0; + vfree (T->parent); + } + else + { + T->parent=unroot_tree (T->parent); + T->right=unroot_tree (T->right); + T->left=unroot_tree (T->left); + } + T->visited=0; + return T; +} + +FILE * print_tree_list ( NT_node *T, char *format,FILE *fp) +{ + int a=0; + while ( T[a]) + { + fp=print_tree (T[a], format, fp); + a++; + } + return fp; +} +char * tree2string (NT_node T) +{ + if (!T) return NULL; + else + { + static char *f; + FILE *fp; + + if (!f)f=vtmpnam (NULL); + fp=vfopen (f, "w"); + print_tree (T, "newick", fp); + vfclose (fp); + return file2string (f); + } +} +char * tree2file (NT_node T, char *name, char *mode) +{ + if (!name)name=vtmpnam (NULL); + string2file (name, mode, tree2string(T)); + return name; +} +FILE * print_tree ( NT_node T, char *format,FILE *fp) +{ + Sequence *S; + + tree2nleaf(T); + S=tree2seq(T, NULL); + + recode_tree (T, S); + + free_sequence (S, -1); + if ( format && strm (format, "binary")) + fp=display_tree ( T,S->nseq, fp); + else if ( ! format || strm2 (format, "newick_tree","newick")) + { + /*T=balance_tree (T);*/ + fp=rec_print_tree (T, fp); + fprintf ( fp, ";\n"); + } + else + { + fprintf ( stderr, "\nERROR: %s is an unknown tree format [FATAL:%s]\n", format, PROGRAM); + myexit (EXIT_FAILURE); + } + return fp; +} +int print_newick_tree ( NT_node T, char *name) +{ + FILE *fp; + fp=vfopen (name, "w"); + fp=rec_print_tree (T,fp); + fprintf (fp, ";\n"); + vfclose (fp); + return 1; +} +FILE * rec_print_tree ( NT_node T, FILE *fp) +{ + + + + if (!T)return fp; + + if ( T->isseq) + { + fprintf ( fp, " %s:%.5f",T->name, T->dist); + } + else + { + if (T->left && T->right) + { + fprintf ( fp, "(");fp=rec_print_tree ( T->left, fp); + fprintf ( fp, ",");fp=rec_print_tree ( T->right, fp); + fprintf ( fp, ")"); + if (T->parent || T->dist) + { + if ( T->bootstrap!=0)fprintf (fp, " %d", (int)T->bootstrap); + fprintf (fp, ":%.5f", T->dist); + } + } + else if (T->left)fp=rec_print_tree (T->left, fp); + else if (T->right)fp=rec_print_tree(T->right, fp); + } + + return fp; +} + + + + + +/*********************************************************************/ +/* */ +/* Tree Functions */ +/* */ +/* */ +/*********************************************************************/ + +int ** make_sub_tree_list ( NT_node **T, int nseq, int n_node) + { + + +/*This function produces a list of all the sub trees*/ + + +/* /A */ +/* -* */ +/* \ /B */ +/* \ / */ +/* ---* */ +/* \ */ +/* *--C */ +/* \ */ +/* \D */ + +/* Contains 4 i_nodes */ +/* 8 nodes (internal nodes +leaves) */ +/* 8 sub trees: */ +/* ABCD */ +/* 1111 */ +/* 0111 */ +/* 1000 */ +/* 0100 */ +/* 0011 */ +/* 0001 */ +/* 0010 */ + + int **sub_tree_list; + int a, n=0; + + + if (T) + { + sub_tree_list=declare_int ( (n_node), nseq); + make_all_sub_tree_list (T[3][0],sub_tree_list, &n); + + } + else + { + sub_tree_list=declare_int (nseq, nseq); + for ( a=0; a< nseq; a++)sub_tree_list[a][a]=1; + } + + return sub_tree_list; + } + +void make_all_sub_tree_list ( NT_node N, int **list, int *n) + { + make_one_sub_tree_list (N, list[n[0]++]); + if (N->leaf!=1) + { + make_all_sub_tree_list (N->left , list, n); + make_all_sub_tree_list (N->right, list, n); + } + return; + } + +void make_one_sub_tree_list ( NT_node T,int *list) + { + if (T->leaf==1) + { + + list[T->seq]=1; + } + else + { + make_one_sub_tree_list(T->left , list); + make_one_sub_tree_list(T->right, list); + } + return; + } + + +NT_node old_main_read_tree(char *treefile) +{ + /*Reads a tree w/o needing the sequence file*/ + NT_node **T; + T=simple_read_tree (treefile); + return T[3][0]; +} + + + +NT_node** simple_read_tree(char *treefile) +{ + int tot_node=0; + NT_node **T; + T=read_tree ( treefile, &tot_node,tree_file2nseq (treefile),NULL); + return T; +} + +void free_read_tree ( NT_node **BT) +{ + int a, s; + + + if (!BT) return; + + for (s=0,a=0; a<3; a++) + { + vfree (BT[a]); + } + free_tree (BT[3][0]); + vfree (BT); + return; +} + +NT_node** read_tree(char *treefile, int *tot_node,int nseq, char **seq_names) + { + + /*The Tree Root is in the TREE[3][0]...*/ + /*TREE[0][ntot]--> pointer to each node and leave*/ + char ch; + int a,b; + + FILE *fp; + int nseq_read = 0; + int nnodes = 0;/*Number of Internal Nodes*/ + int ntotal = 0;/*Number of Internal Nodes + Number of Leaves*/ + int flag; + int c_seq; + NT_node **lu_ptr; + NT_node seq_tree, root,p; + + + tot_nseq=nseq; + rooted_tree=distance_tree=TRUE; + + fp = vfopen(treefile, "r"); + fp=skip_space(fp); + ch = (char)getc(fp); + if (ch != '(') + { + fprintf(stderr, "Error: Wrong format in tree file %s\n", treefile); + myexit (EXIT_FAILURE); + } + rewind(fp); + + + lu_ptr=(NT_node **)vcalloc(4,sizeof(NT_node*)); + lu_ptr[0] = (NT_node *)vcalloc(10*nseq,sizeof(NT_node)); + lu_ptr[1] = (NT_node *)vcalloc(10*nseq,sizeof(NT_node)); + lu_ptr[2] = (NT_node *)vcalloc(10*nseq,sizeof(NT_node)); + lu_ptr[3] =(NT_node *) vcalloc(1,sizeof(NT_node)); + + seq_tree =(NT_node) declare_tree_node(nseq); + + set_info(seq_tree, NULL, 0, " ", 0.0, 0); + + + fp=create_tree(seq_tree,NULL,&nseq_read, &ntotal, &nnodes, lu_ptr, fp); + fclose (fp); + + + if (nseq != tot_nseq) + { + fprintf(stderr," Error: tree not compatible with alignment (%d sequences in alignment and %d in tree\n", nseq,nseq_read); + myexit (EXIT_FAILURE); + } + + if (distance_tree == FALSE) + { + if (rooted_tree == FALSE) + { + fprintf(stderr,"Error: input tree is unrooted and has no distances, cannot align sequences\n"); + myexit (EXIT_FAILURE); + } + } + + if (rooted_tree == FALSE) + { + root = reroot(seq_tree, nseq,ntotal,nnodes, lu_ptr); + lu_ptr[1][nnodes++]=lu_ptr[0][ntotal++]=root; + + } + else + { + root = seq_tree; + } + + lu_ptr[3][0]=root; + tot_node[0]=nnodes; + + + + for ( a=0; a< ntotal; a++) + { + (lu_ptr[0][a])->isseq=(lu_ptr[0][a])->leaf; + (lu_ptr[0][a])->dp=(lu_ptr[0][a])->dist; + } + + + for ( a=0; a< nseq; a++) + { + if (!seq_names) + { + flag=1; + (lu_ptr[2][a])->order=(lu_ptr[2][a])->seq=a; + } + else + { + for ( flag=0,b=0; bname, seq_names[b], MAXNAMES)==0) + { + flag=1; + + (lu_ptr[2][a])->order=(lu_ptr[2][a])->seq=b; + /*vfree ( (lu_ptr[2][a])->name);*/ + sprintf ((lu_ptr[2][a])->name, "%s", seq_names[b]); + } + } + } + /* + if ( flag==0 && (lu_ptr[0][a])->leaf==1) + { + fprintf ( stderr, "\n%s* not in tree",(lu_ptr[2][a])->name); + for ( a=0; a< ntotal; a++) + { + fprintf ( stderr, "\n%d %s",(lu_ptr[2][a])->leaf, (lu_ptr[2][a])->name); + } + } + */ + } + + if (seq_names) + { + int tnseq; + char *s; + char **tree_names; + int fail_flag=0; + tnseq=tree_file2nseq(treefile); + tree_names=vcalloc ( tnseq, sizeof (char*)); + for (a=0; aname; + tree_names[a]=s; + if ( name_is_in_list(s, seq_names, nseq, MAXNAMES+1)==-1) + { + fprintf (stderr, "\nERROR: Sequence %s in the tree [%s] is not in the alignment[FATAL:%s]\n", s, treefile, PROGRAM); + fail_flag=1; + } + } + for (a=0; aseq; + + while ( p!=NULL) + { + p->lseq[p->nseq]=c_seq; + p->nseq++; + p=p->parent; + } + } + + + return lu_ptr; + } + +FILE * create_linear_tree ( char **name, int n, FILE *fp) +{ + + if (!name || n==0 ||!fp) return NULL; + + + if (n==2) + fprintf ( fp, "(%s,%s);",name[0],name[1]); + else if ( n==3) + fprintf ( fp, "((%s,%s),%s);",name[0],name[1], name[2]); + else + { + int a; + for (a=0; aleft, ptree, nseq,ntotal,nnodes,lu,fp); + ch = (char)getc(fp); + if ( ch == ',') + { + fp=create_tree(ptree->right, ptree,nseq,ntotal,nnodes,lu,fp); + ch = (char)getc(fp); + if ( ch == ',') + { + + ptree = insert_tree_node(ptree); + lu[0][ntotal[0]] = lu[1][nnodes[0]] = ptree; + ntotal[0]++; + nnodes[0]++; + fp=create_tree(ptree->right, ptree,nseq,ntotal,nnodes,lu,fp); + rooted_tree = FALSE; + if ( getenv4debug ( "DEBUG_TREE")){fprintf ( stderr, "\n[DEBUG_TREE:create_tree] Unrooted Tree");} + } + } + + fp=skip_space(fp); + ch = (char)getc(fp); + } + else + { + type=LEAF; + lu[0][ntotal[0]] = lu[2][nseq[0]] = ptree; + ntotal[0]++; + nseq[0]++; + name[0] = ch; + i=1; + ch = (char)getc(fp); + if ( name[0]=='\'') + { + /*This protects names that are between single quotes*/ + while ( ch!='\'') + { + if (i < MAXNAMES) name[i++] = ch; + ch = (char)getc(fp); + } + if (i < MAXNAMES) name[i++] = ch; + while ((ch != ':') && (ch != ',') && (ch != ')'))ch = (char)getc(fp); + } + else + { + while ((ch != ':') && (ch != ',') && (ch != ')')) + { + if (i < MAXNAMES) name[i++] = ch; + ch = (char)getc(fp); + } + } + + name[i] = '\0'; + + if ( i>=(MAXNAMES+1)){fprintf (stderr, "\nName is too long");myexit (EXIT_FAILURE);} + if (ch != ':' && !isdigit(ch)) + { + /*distance_tree = FALSE*/; + } + } + if (ch == ':') + { + fp=skip_space(fp); + fscanf(fp,"%f",&dist); + fp=skip_space(fp); + bootstrap=0; + } + /*Tree with Bootstrap information*/ + else if (isdigit (ch)) + { + ungetc(ch,fp); + fscanf(fp,"%f",&bootstrap); + if ( fscanf(fp,":%f",&dist)==1); + else dist=0; + fp=skip_space(fp); + } + else + { + ungetc ( ch, fp); + skip_space(fp); + } + + set_info(ptree, parent, type, name, dist, bootstrap); + + + vfree (name); + return fp; + } + +NT_node declare_tree_node (int nseq) + { + NT_node p; + + p= (NT_node)vcalloc (1, sizeof ( Treenode)); + p->left = NULL; + p->right = NULL; + p->parent = NULL; + p->dist = 0.0; + p->leaf = 0; + p->order = 0; + p->maxnseq=nseq; + p->name=(char*)vcalloc (MAXNAMES+1,sizeof (char)); + p->name[0]='\0'; + p->lseq=(int*)vcalloc ( nseq, sizeof (int)); + return p; + + } + +void set_info(NT_node p, NT_node parent, int pleaf, char *pname, float pdist, float bootstrap) + { + p->parent = parent; + p->leaf = pleaf; + p->dist = pdist; + p->bootstrap=bootstrap; + p->order = 0; + + + sprintf (p->name, "%s", pname); + + if (pleaf ==1) + { + p->left = NULL; + p->right = NULL; + } + + } +NT_node insert_tree_node(NT_node pptr) + { + + NT_node newnode; + + newnode = declare_tree_node( pptr->maxnseq); + create_tree_node(newnode, pptr->parent); + + newnode->left = pptr; + pptr->parent = newnode; + + set_info(newnode, pptr->parent, 0, "", 0.0, 0); + + return(newnode); + } + +void create_tree_node(NT_node pptr, NT_node parent) + { + pptr->parent = parent; + pptr->left =declare_tree_node(pptr->maxnseq) ; + (pptr->left)->parent=pptr; + + pptr->right =declare_tree_node(pptr->maxnseq) ; + (pptr->right)->parent=pptr; + } + +FILE * skip_space(FILE *fp) + { + int c; + + do + c = getc(fp); + while(isspace(c)); + if ( c==EOF) + { + fprintf ( stderr, "\nEOF"); + myexit (EXIT_FAILURE); + } + ungetc(c, fp); + return fp; + } + + +NT_node reroot(NT_node ptree, int nseq, int ntotal, int nnodes, NT_node **lu) + { + NT_node p, rootnode, rootptr; + float diff, mindiff=0, mindepth = 1.0, maxdist; + int i; + int first = TRUE; + + + + rootptr = ptree; + + for (i=0; iparent == NULL) + diff = calc_root_mean(p, &maxdist, nseq, lu); + else + diff = calc_mean(p, &maxdist, nseq, lu); + + if ((diff == 0) || ((diff > 0) && (diff < 2 * p->dist))) + { + if ((maxdist < mindepth) || (first == TRUE)) + { + first = FALSE; + rootptr = p; + mindepth = maxdist; + mindiff = diff; + } + } + + } + if (rootptr == ptree) + { + mindiff = rootptr->left->dist + rootptr->right->dist; + rootptr = rootptr->right; + } + + rootnode = insert_root(rootptr, mindiff); + diff = calc_root_mean(rootnode, &maxdist, nseq, lu); + return(rootnode); + } + + +float calc_root_mean(NT_node root, float *maxdist, int nseq, NT_node **lu) + { + float dist , lsum = 0.0, rsum = 0.0, lmean,rmean,diff; + NT_node p; + int i; + int nl, nr; + int direction; + + + dist = (*maxdist) = 0; + nl = nr = 0; + for (i=0; i< nseq; i++) + { + p = lu[2][i]; + dist = 0.0; + while (p->parent != root) + { + dist += p->dist; + p = p->parent; + } + if (p == root->left) direction = LEFT; + else direction = RIGHT; + dist += p->dist; + + if (direction == LEFT) + { + lsum += dist; + nl++; + } + else + { + rsum += dist; + nr++; + } + + if (dist > (*maxdist)) *maxdist = dist; + } + + lmean = lsum / nl; + rmean = rsum / nr; + + diff = lmean - rmean; + return(diff); + } + +float calc_mean(NT_node nptr, float *maxdist, int nseq,NT_node **lu) + { + float dist , lsum = 0.0, rsum = 0.0, lmean,rmean,diff; + NT_node p, *path2root; + float *dist2node; + int depth = 0, i,j , n; + int nl , nr; + int direction, found; + + + path2root = (NT_node *)vcalloc(nseq,sizeof(Treenode)); + dist2node = (float *)vcalloc(nseq,sizeof(float)); + + depth = (*maxdist) = dist = 0; + nl = nr = 0; + p = nptr; + while (p != NULL) + { + path2root[depth] = p; + dist += p->dist; + dist2node[depth] = dist; + p = p->parent; + depth++; + } + +/*************************************************************************** + *nl = *nr = 0; + for each leaf, determine whether the leaf is left or right of the node. + (RIGHT = descendant, LEFT = not descendant) +****************************************************************************/ + for (i=0; i< nseq; i++) + { + p = lu[2][i]; + if (p == nptr) + { + direction = RIGHT; + dist = 0.0; + } + else + { + direction = LEFT; + dist = 0.0; + + found = FALSE; + n = 0; + while ((found == FALSE) && (p->parent != NULL)) + { + for (j=0; j< depth; j++) + if (p->parent == path2root[j]) + { + found = TRUE; + n = j; + } + dist += p->dist; + p = p->parent; + } + + if (p == nptr) direction = RIGHT; + + } + if (direction == LEFT) + { + lsum += dist; + lsum += dist2node[n-1]; + nl++; + } + else + { + rsum += dist; + nr++; + } + + if (dist > (*maxdist)) *maxdist = dist; + } + + vfree(dist2node); + vfree(path2root); + + + + if ( nl==0 || nr==0) + { + myexit (EXIT_FAILURE); + } + lmean = lsum / nl; + rmean = rsum / nr; + + diff = lmean - rmean; + return(diff); +} + +NT_node insert_root(NT_node p, float diff) +{ + NT_node newp, prev, q, t; + float dist, prevdist,td; + + + newp = declare_tree_node( p->maxnseq); + t = p->parent; + + + prevdist = t->dist; + p->parent = newp; + + dist = p->dist; + + p->dist = diff / 2; + if (p->dist < 0.0) p->dist = 0.0; + if (p->dist > dist) p->dist = dist; + + t->dist = dist - p->dist; + + newp->left = t; + newp->right = p; + newp->parent = NULL; + newp->dist = 0.0; + newp->leaf = NODE; + + if (t->left == p) t->left = t->parent; + else t->right = t->parent; + + prev = t; + q = t->parent; + + t->parent = newp; + + while (q != NULL) + { + if (q->left == prev) + { + q->left = q->parent; + q->parent = prev; + td = q->dist; + q->dist = prevdist; + prevdist = td; + prev = q; + q = q->left; + } + else + { + q->right = q->parent; + q->parent = prev; + td = q->dist; + q->dist = prevdist; + prevdist = td; + prev = q; + q = q->right; + } + } + +/* + remove the old root node +*/ + q = prev; + if (q->left == NULL) + { + dist = q->dist; + q = q->right; + q->dist += dist; + q->parent = prev->parent; + if (prev->parent->left == prev) + prev->parent->left = q; + else + prev->parent->right = q; + prev->right = NULL; + } + else + { + dist = q->dist; + q = q->left; + q->dist += dist; + q->parent = prev->parent; + if (prev->parent->left == prev) + prev->parent->left = q; + else + prev->parent->right = q; + prev->left = NULL; + } + + return(newp); +} + + + + +/*********************************************************************/ +/* */ +/* TrimTC3 */ +/* */ +/* */ +/*********************************************************************/ + +int *aln2seq_chain (Alignment *A, int **sim,int seq1, int seq2, int limit, int max_chain); + +Alignment *seq2seq_chain (Alignment *A,Alignment*T, char *arg) +{ + int **sim=NULL; + int *buf=NULL, *seq2keep, *list, *tname; + int a, b, c, nl; + int sim_limit; + int min_sim=15; + int max_chain=20; + + /*Estimate Similarity within the incoming sequences*/ + sim=seq2comp_mat (aln2seq(A), "blosum62mt", "sim2"); + + /*Read and store the list of sequences to keep*/ + seq2keep=vcalloc (A->nseq, sizeof (int)); + tname=vcalloc (T->nseq, sizeof (int)); + for ( a=0; a< T->nseq; a++) + { + tname[a]=name_is_in_list ( T->name[a], A->name, A->nseq, 100); + if (tname[a]>=0)seq2keep[tname[a]]=1; + } + + /*Consider Every Pair of Sequences within the list of sequences to keep*/ + + fprintf ( stderr, "\n"); + for ( a=0; a< T->nseq-1; a++) + { + if (tname[a]<0) continue; + for ( b=a+1;bnseq; b++) + { + + if (tname[b]<0) continue; + + buf=NULL;sim_limit=90; + while (!buf && sim_limit>min_sim) + { + buf=aln2seq_chain ( A, sim,tname[a],tname[b],sim_limit, max_chain); + sim_limit-=5; + } + + if ( buf) + { + for (c=0; c< A->nseq; c++)seq2keep[c]+=buf[c]; + vfree (buf); + } + else + { + fprintf ( stderr, "\n#Could Not Find any Intermediate sequence [MAx chain %d MinID %d\n", max_chain, min_sim); + } + } + } + + list=vcalloc (A->nseq, sizeof (int)); + for ( nl=0,a=0; a< A->nseq; a++) + if ( seq2keep[a]) + list[nl++]=a; + + A=extract_sub_aln (A, nl, list); + + free_int (sim, -1); + vfree (list); + return A; +} +int max_explore=10000000;/*Limits the number of explorations that tends to increase when id is small*/ +int n_explore; + +int *aln2seq_chain (Alignment *A, int **sim, int seq1, int seq2, int limit, int max_chain) +{ + int *used; + int **chain; + char output1[10000]; + char output2[10000]; + int a; + int *list; + int n, nseq=0; + + + output1[0]=output2[0]='\0'; + used=vcalloc (A->nseq, sizeof(int)); + used[seq1]=1; + + if (find_seq_chain ( A, sim,used,seq1,seq1, seq2,1,limit, max_chain, &nseq)) + { + list=vcalloc (A->nseq, sizeof (int)); + chain=declare_int (A->nseq, 2); + for (n=0, a=0; a< A->nseq; a++) + { + if ( used[a]) + { + chain[n][0]=used[a]; + chain[n][1]=a; + list[used[a]-1]=a;n++; + } + } + + sprintf ( output2, "#%s %s N: %d Lower: %d Sim: %d DELTA: %d\n", A->name[list[0]], A->name[list[n-1]],n, limit,sim[list[0]][list[n-1]],limit-sim[list[0]][list[n-1]]);strcat (output1, output2); + + sort_int ( chain, 2, 0, 0, n-1); + sprintf ( output2, "#");strcat(output1, output2); + + for ( a=0; a< n-1; a++) + { + sprintf (output2, "%s -->%d -->", A->name[chain[a][1]],sim[chain[a][1]][chain[a+1][1]]);strcat ( output1, output2); + } + sprintf ( output2, "%s\n", A->name[chain[n-1][1]]);strcat (output1, output2); + + free_int (chain, -1); + vfree (list); + } + else + { + vfree (used); + used=NULL; + } + /* fprintf ( stdout, "%s", output1);*/ + fprintf ( stderr, "%s", output1); + n_explore=0; + return used; +} +static int ***pw_sim; +int find_seq_chain (Alignment *A, int **sim,int *used,int seq0,int seq1, int seq2,int chain_length, int limit, int max_chain, int *nseq) +{ + int a,b, seq, seq_sim; + + n_explore++; + if ( n_explore>=max_explore) + { + return 0; + } + if (!pw_sim) + { + pw_sim=declare_arrayN(3, sizeof (int), A->nseq, A->nseq, 3); + for ( a=0; a< A->nseq; a++) + { + for ( b=0; bnseq; b++) + { + pw_sim[a][b][0]=b; + pw_sim[a][b][1]=sim[a][b]; + pw_sim[a][b][2]=sim[b][seq2]; + } + sort_int_inv ( pw_sim[a],3, 1, 0, A->nseq-1); + } + } + + if ( chain_length>max_chain)return 0; + else if ( sim[seq1][seq2]>=limit) + { + used[seq2]=chain_length+1; + nseq[0]++; + return 1; + } + else + { + int delta_seq2; + for ( a=0; a< A->nseq; a++) + { + seq=pw_sim[seq1][a][0]; + seq_sim=pw_sim[seq1][a][1]; + delta_seq2=pw_sim[seq1][a][2]-sim[seq1][seq2]; + + + + if ( used[seq])continue; + else if ( seq_simnseq); + vfree (T->file); + T->file=vcalloc ( strlen (treefile)+1, sizeof (char)); + sprintf ( T->file, "%s", treefile); + return T; +} + +//This function codes the tree into lseq and lseq2 +//lseq: list of the N->nseq child sequences of the node +//lsseq2:Array of size Nseq, with lseq[a]=1 if sequence a is child of node N +static int node_index; +NT_node index_tree_node (NT_node T) +{ + if (!T)return T; + if (!T->parent){node_index=tree2nseq (T)+1;} + + index_tree_node(T->left); + index_tree_node(T->right); + + if (!T->left && !T->right)T->index=T->lseq[0]+1; + else T->index=node_index++; + return T; +} + + + +NT_node simple_recode_tree (NT_node T, int nseq) +{ + + //recodes atree wher the leafs are already coded + if (!T) return T; + + + + + T->nseq=0; + + if ( T->isseq) + { + + ; + + } + else + { + NT_node R,L; + int a; + vfree (T->lseq); T->lseq=vcalloc (nseq, sizeof (int)); + vfree (T->lseq2); T->lseq2=vcalloc (nseq, sizeof (int)); + vfree (T->idist); T->idist=vcalloc (nseq, sizeof (int)); + vfree (T->ldist); T->ldist=vcalloc (nseq, sizeof (int)); + + R=simple_recode_tree (T->left,nseq); + + L=simple_recode_tree (T->right,nseq); + + if (R)for (a=0; anseq; a++) + { + T->lseq2[R->lseq[a]]=1; + } + + if (L)for (a=0; anseq; a++) + { + T->lseq2[L->lseq[a]]=1; + } + + for (a=0; alseq2[a])T->lseq[T->nseq++]=a; + if (T->lseq2[a])T->idist[a]=(!R)?0:R->idist[a]+((!L)?0:L->idist[a])+1; + if (T->lseq2[a])T->ldist[a]=(!R)?0:R->ldist[a]+((!L)?0:L->ldist[a])+(int)(T->dist*10000); + } + } + return T; +} + +NT_node recode_tree (NT_node T, Sequence *S) +{ + + + if (!T) return T; + + + vfree (T->lseq); T->lseq=vcalloc (S->nseq, sizeof (int)); + vfree (T->lseq2); T->lseq2=vcalloc (S->nseq, sizeof (int)); + vfree (T->idist); T->idist=vcalloc (S->nseq, sizeof (int)); + vfree (T->ldist); T->ldist=vcalloc (S->nseq, sizeof (int)); + T->nseq=0; + + if ( T->isseq) + { + + int i; + i=name_is_in_list (T->name, S->name, S->nseq, -1); + + if (i!=-1) + { + T->lseq[T->nseq++]=i; + T->lseq2[i]=1; + T->idist[i]=1; + T->ldist[i]=(int)(T->dist*10000);; + } + else + { + printf_exit ( EXIT_FAILURE, stderr, "\nERROR: Sequence %s is in the Tree but Not in the Sequence dataset [code_lseq][FATAL:%s]", T->name, PROGRAM); + } + + } + else + { + NT_node R,L; + int a; + + R=recode_tree (T->left, S); + + L=recode_tree (T->right, S); + + if (R) + for (a=0; anseq; a++) + { + T->lseq2[R->lseq[a]]=1; + } + + if (L)for (a=0; anseq; a++) + { + T->lseq2[L->lseq[a]]=1; + } + + for (a=0; anseq; a++) + { + //don't count the root + int d; + + if ( !(T->parent) || !(T->parent)->parent)d=0; + else if ( T->dist==0)d=0; + else d=1; + + if (T->lseq2[a])T->lseq[T->nseq++]=a; + if (T->lseq2[a])T->idist[a]=(!R)?0:(R->idist[a]+((!L)?0:L->idist[a])+d); + if (T->lseq2[a])T->ldist[a]=(!R)?0:R->ldist[a]+((!L)?0:L->ldist[a])+(int)(T->dist*10000); + + } + } + return T; +} +int tree2split_list (NT_node T, int ns,int **sl, int* n) +{ + if (!T) return 0; + if (!sl) return 0; + + tree2split_list (T->right, ns, sl, n); + tree2split_list (T->left , ns, sl, n); + + if (!T->right) return 1; + else if (T->parent && !(T->parent)->parent)return 1; + else if ( T->dist==0)return 1; + else + { + int t=0,t2=0, c=0, a; + + for (a=0; a< ns; a++) + { + t2+=(a+1)*T->lseq2[a]; + t+=T->lseq2[a]; + } + + if (t2==0) HERE ("0"); + c=(t>(ns-t))?1:0; + sl[n[0]][ns]=t2;//Hash value for quick comparison; + + for (a=0; a< ns; a++)sl[n[0]][a]=(c==0)?T->lseq2[a]:(1-T->lseq2[a]); + n[0]++; + + } + return 1; +} + +NT_node display_splits (NT_node T,Sequence *S, FILE *fp) +{ + int a; + if (!T) return T; + + if (!S)S=tree2seq (T,NULL); + + display_splits (T->right,S, fp); + display_splits (T->left, S, fp); + + + + if (!T->right); + else if (T->parent && !(T->parent)->parent); + else + { + int t=0; + for (a=0; a< S->nseq; a++) + { + fprintf (fp, "%d", T->lseq2[a]); + t+=T->lseq2[a]; + } + + fprintf ( fp, " %5d \n", MIN(t,((S->nseq)-t))); + } + return T; +} +NT_node display_leaf_nb (NT_node T, int n, FILE *fp, char * name) +{ + int a; + if (!T) return T; + + + display_leaf_nb (T->right, n, fp, name); + display_leaf_nb (T->left, n, fp, name); + + + if (!T->isseq); + else + { + NT_node P; + + P=T->parent; + fprintf (fp, "%s ", T->name); + for (a=0; a< n; a++)fprintf (fp, "%d", P->lseq2[a]); + fprintf ( fp," %s\n", name); + } + return T; +} +static int root4dc; +NT_node display_code (NT_node T, int n, FILE *fp) +{ + int a, debug=0, t=0; + if (!T) return T; + + if (!T->parent) + root4dc=0; + + + + if (!T->parent && debug) fprintf ( fp, "\nDISPLAY TREE: START"); + display_code (T->right, n, fp); + display_code (T->left, n, fp); + + fprintf ( fp, "\n"); + if (!T->parent) return T; + else if ( !(T->parent)->parent && root4dc==1)return T; + else if ( !(T->parent)->parent && root4dc==0)root4dc=1; + + for (a=0; a< n; a++) + t+=T->lseq2[a]; + if ( t<=n/2) + for (a=0; a< n; a++)fprintf (fp, "%d", T->lseq2[a]); + else + for (a=0; a< n; a++)fprintf (fp, "%d", 1-T->lseq2[a]); + if (T->isseq && debug)fprintf (fp, "%s", T->name); + + if (!T->parent && debug) fprintf (fp, "\nDISPLAY TREE: FINISHED"); + return T; +} +NT_node display_dist (NT_node T, int n, FILE *fp) +{ + int a; + if (!T) return T; + + if (!T->parent) + root4dc=0; + + display_dist (T->right, n, fp); + display_dist (T->left, n, fp); + + fprintf ( stdout, "\n"); + for ( a=0; a< n; a++) + fprintf ( stdout, " %2d ", T->idist[a]); + fprintf ( stdout, "\n"); + + return T; +} + +NT_node check_tree (NT_node T) +{ + if (T) HERE("CHECK %s", T->name); + if (!T) + { + HERE ("ERROR: Empty Group"); + } + + else if (T->isseq)return T; + else + { + HERE ("R"); + check_tree (T->right); + HERE ("L"); + check_tree (T->left); + return NULL; + } + return 0;} + +NT_node new_reroot_tree( NT_node T) +{ + T=unroot_tree (T); + return T; +} +NT_node new_get_node (NT_node T, FILE *fp) +{ + NT_node NN; + int c; + static int n; + + c=fgetc (fp); + if (!T)T=declare_tree_node (100); + + + if ( c==';') + { + + if (!T->right)T=T->left; + else if (!T->left)T=T->right; + vfree (T->parent);T->parent=NULL; + return T; + } + else if ( c==')') + { + --n; + scan_name_and_dist (fp, T->name, &T->dist); + if (T->name && T->name [0])T->bootstrap=atof (T->name); + return new_get_node (T->parent, fp); + } + else if ( c==',') + { + return new_get_node (T, fp); + } + else + { + NN=new_insert_node (T); + + if ( c=='(') + { + ++n; + return new_get_node (NN, fp); + } + else + { + ungetc (c, fp); + scan_name_and_dist (fp, NN->name, &NN->dist); + + NN->leaf=1; + NN->isseq=1; + return new_get_node (T, fp); + } + } +} +int scan_name_and_dist ( FILE *fp, char *name, float *dist) +{ + int a, c; + char number [1000]; + + a=0; + c=fgetc (fp);ungetc (c, fp); + + + if ( c==';')return 0; + + while ((c=fgetc(fp))!=':' && c!=EOF && c!=')' && c!=';' && c!=',') + { + name[a++]=c; + } + name [a]='\0'; + + if ( c!=':') + { + ungetc (c, fp); + dist[0]=FLT_MIN; + return 1; + } + a=0; + while (isdigit((c=fgetc(fp))) || c=='.' || c=='-') + { + number[a++]=c; + } + + ungetc (c, fp); + number[a]='\0'; + + dist[0]=atof (number); + + return 2; +} +NT_node new_insert_node (NT_node T) +{ + NT_node NN; + + + NN=new_declare_tree_node (); + NN->parent=T; + if (!T) + { + return NN; + } + else if (T->left==NULL) + { + T->left=NN; + + } + else if ( T->right==NULL) + { + T->right=NN; + } + else + { + NT_node NN2; + NN2=new_declare_tree_node (); + NN2->left=T->left; + NN2->right=T->right; + NN2->parent=T; + + T->left=NN2; + T->right=NN; + } + + /* + + else + { + NN->right=T->right; + (T->right)->parent=NN; + + NN->parent=T; + T->right=NN; + NN->left=new_declare_tree_node (); + (NN->left)->parent=NN; + return NN->left; + } + */ + /* + This caused a crash when internal undefined nodes, removed 19/02/08 + else + { + NT_node P; + NN->right=T; + P=NN->parent=T->parent; + T->parent=NN; + + if (P && P->right==T)P->right=NN; + else if ( P && P->left==T)P->left=NN; + + NN->left=new_declare_tree_node (); + (NN->left)->parent=NN; + return NN->left; + } + */ + return NN; +} + +NT_node new_declare_tree_node () +{ + NT_node p; + static int node_index; + p= (NT_node)vcalloc (1, sizeof ( Treenode)); + p->left = NULL; + p->right = NULL; + p->parent = NULL; + p->dist = 0.0; + p->leaf = 0; + p->order = 0; + p->index=++node_index; + p->maxnseq=1000; + p->name=(char*)vcalloc (MAXNAMES+1,sizeof (char)); + p->name[0]='\0'; + return p; + + } +int new_display_tree (NT_node T, int n) +{ + int in; + + in=n; + + + if ( T->parent)fprintf (stdout, "\nNode %d: has parents)", in); + else fprintf (stdout, "\nNode %d: NO parents)", in); + + if ( T->right) + { + fprintf (stdout, "\nNode %d has Right Child", in); + n=new_display_tree (T->right, n+1); + } + else fprintf ( stdout, "\nNode %d No Right\n", in); + + if ( T->left) + { + fprintf (stdout, "\nNode %d has Left Child", in); + n=new_display_tree (T->left, n+1); + } + else fprintf ( stdout, "\nNode %d No Left\n", in); + + if ( T->bot) + { + fprintf (stdout, "\nNode %d has Bot Child", in); + n=new_display_tree (T->bot, n+1); + } + else fprintf ( stdout, "\nNode %d No Bot\n", in); + + + if (T->isseq) + { + fprintf (stdout, "\nNode %d is %s", in, T->name); + return in; + } + else return 0;} +int display_tree_duplicates (NT_node T) +{ + static Sequence *S; + static int *dup; + int a, b; + + free_sequence (S, -1); + vfree (dup); + + S=tree2seq (T, NULL); + dup=vcalloc ( S->nseq, sizeof (int)); + + for (a=0; a< S->nseq-1; a++) + for ( b=a+1; bnseq; b++) + { + if ( strm (S->name[a], S->name[b])) + { + dup[a]++; + } + } + for (a=0; a< S->nseq-1; a++) + for ( b=a+1; bnseq; b++) + { + if ( strm (S->name[a], S->name[b]) && dup[a]) + { + fprintf ( stderr, "\nSequence %s is duplicated %d Times in the tree", S->name[a], dup[a]); + dup[a]=0; + } + } + return 0; +} +int tree_contains_duplicates (NT_node T) +{ + static Sequence *S; + int a, b; + + free_sequence (S, -1); + + S=tree2seq (T, NULL); + for (a=0; a< S->nseq-1; a++) + for ( b=a+1; bnseq; b++) + { + if ( strm (S->name[a], S->name[b]))return 1; + } + return 0; +} + +float display_avg_bootstrap ( NT_node T) +{ + float tot; + int n; + + tot=tree2tot_dist (T, BOOTSTRAP); + n=tree2n_branches (T, BOOTSTRAP); + fprintf ( stdout, "\nAVERAGE BOOTSRAP: %.3f on %d Branches\n", (n>0)?tot/n:0, n); + return (n>0)?tot/n:0; +} + + +int tree2n_branches(NT_node T, int mode) +{ + int n=0; + + if (!T) return 0; + if (!T->parent); + else if ((T->isseq && mode !=BOOTSTRAP) || !T->isseq) + { + n++; + } + n+=tree2n_branches(T->right, mode); + n+=tree2n_branches(T->left, mode); + + return n; +} + +float tree2tot_dist ( NT_node T, int mode) +{ + float t=0; + + + if ( !T)return 0; + + if ( !T->parent); + else if ((T->isseq && mode !=BOOTSTRAP) || !T->isseq) + { + if ( mode == BOOTSTRAP && T->bootstrap!=0)t+=T->bootstrap; + else t+=T->dist; + } + + t+=tree2tot_dist(T->right, mode); + t+=tree2tot_dist(T->left, mode); + return t; +} + +//This function displays all the sequences within the tree sorted by node label +int cmp_tree_array ( const void *vp, const void *vq); +int node_sort ( char *name, NT_node T) +{ + NT_node N; + int nseq; + int **array, a; + Sequence *S; + while (T->parent)T=T->parent; + + nseq=tree2nseq (T); + array=declare_int (nseq, 2); + N=tree2node (name, T); + + if (N==NULL)printf_exit (EXIT_FAILURE, stderr, "ERROR: %s is not in the tree [FATAL:%s]\n", name, PROGRAM); + array=display_tree_from_node (N,0,0, array); + qsort ( array, nseq, sizeof (int**), cmp_tree_array); + S=tree2seq(T, NULL); + for (a=0; a%s %d %d\n", S->name[array[a][0]], array[a][1], array[a][2]); + myexit (EXIT_SUCCESS); +} + +NT_node tree2root ( NT_node R) +{ + if (R)while (R->parent)R=R->parent; + return R; +} + +NT_node tree2node (char *name, NT_node T) +{ + NT_node T1, T2; + if ( !T) return T; + else if (T->leaf && strm (T->name, name)) return T; + else + { + + T1=tree2node ( name, T->right); + T2=tree2node ( name, T->left); + return (T1>T2)?T1:T2; + } + +} +static int ni; +NT_node * tree2node_list (NT_node T, NT_node *L) +{ + + + if (!T) return NULL; + if (!L) {ni=0;L=vcalloc (tree2nnode(T)+1, sizeof (NT_node));} + tree2node_list (T->left, L); + tree2node_list (T->right, L); + L[ni++]=T; + return L; +} + + + +int ** display_tree_from_node (NT_node T, int up, int down, int **array) +{ + + if (!T || T->visited)return array; + + T->visited=1; + if (T->isseq) + { + array[T->lseq[0]][0]=T->lseq[0]; + array[T->lseq[0]][1]=up; + array[T->lseq[0]][2]=down; + + } + else + { + array=display_tree_from_node ( T->left ,up, down+1, array); + array=display_tree_from_node ( T->right,up, down+1, array); + } + array=display_tree_from_node ( T->parent,up+1, 0, array); + T->visited=0; + return array; + +} + +int cmp_tree_array ( const void *p, const void *q) +{ + const int **vp=(const int**)p; + const int **vq=(const int**)q; + if (vp[0][1]>vq[0][1])return 1; + else if ( vp[0][1]vq[0][2]) return 1; + else if ( vp[0][2]nseq+1, sizeof (NT_node)); + + for ( a=0; anseq; a++) + { + char *fname; + if (S->seq && S->seq[a] && strlen (S->seq[a])<2) + fname=S->name[a]; + else + string2file ((fname=vtmpnam(NULL)), "w", S->seq[a]); + + T[a]=main_read_tree (fname); + T[a]->file=vcalloc (strlen (S->name[a])+1, sizeof (char)); + sprintf (T[a]->file, "%s", S->name[a]); + } + return T; +} + +int treelist2dmat ( Sequence *S) +{ + NT_node *T; + int n=0, a, b; + float v; + Sequence *TS; + + + + n=S->nseq; + T=read_tree_list (S); + TS=tree2seq(T[0], NULL); + fprintf (stdout, "\n%d", S->nseq); + for (a=0; aname[a]); + for ( b=0; bnseq*10, sizeof (char)); + ref_group=vcalloc (TS->nseq*10, sizeof (char)); + list=vcalloc (100*S->nseq, sizeof (char)); + split_file=vtmpnam (NULL); + sorted_split_file =vtmpnam (NULL); + + n=S->nseq; + used=vcalloc (n, sizeof (int)); + + T=read_tree_list (S); + if (!TS)TS=tree2seq(T[0], NULL); + nseq=TS->nseq; + fp=vfopen (split_file, "w"); + + for ( a=0; a< S->nseq; a++) + { + + T[a]=prune_tree (T[a], TS); + T[a]=recode_tree (T[a], TS); + display_leaf_nb (T[a], TS->nseq,fp, S->name[a]); + } + vfclose (fp); + + + for (s=0; s< TS->nseq; s++) + { + int i; + + + if (taxon && !(strm (taxon, TS->name[s]) ))continue; + else + printf_system ( "cat %s | grep %s| sort > %s::IGNORE_FAILURE::", split_file,TS->name[s], sorted_split_file); + + vfopen (sorted_split_file, "r"); + ref_group[0]=group[0]='\0'; + + while ( (c=fgetc (fp))!=EOF) + { + + ungetc (c, fp); + buf=vfgets (buf, fp); + sscanf (buf, "%s %s %s\n", name, group, fname); + + if ( !ref_group[0]|| !strm (group, ref_group)) + { + if (ref_group[0]) + + {fprintf (stdout, "%s %6.2f %s",name, (((float)n*100)/(float)S->nseq), ref_group); + for (i=0,a=0; aname[a]); + fprintf ( stdout, "\n"); + fprintf (stdout, "\nLIST: %s\n", list); + } + list[0]='\0'; + sprintf ( ref_group, "%s", group); + list=strcatf (list, " %s", fname); + n=1; + } + else + { + + list=strcatf (list, " %s", fname); + n++; + } + } + + fprintf (stdout, "%s %6.2f %s",name, (((float)n*100)/(float)S->nseq), group); + for (i=0,a=0; aname[a]); + fprintf (stdout, "\nLIST %s\n", list); + fprintf ( stdout, "\n"); + vfclose (fp); + } + + myexit (0); +} +int count_tree_groups( Sequence *LIST, char *group_file) +{ + NT_node *T; + Sequence *S; + int a, b, c,n, w, wo, ng=0; + int **list, ***rlist, **blist; + char ***l; + int *gs; + + + + T=read_tree_list (LIST); + S=tree2seq(T[0], NULL); + for ( a=0; a< LIST->nseq; a++) + { + T[a]=prune_tree (T[a], S); + T[a]=recode_tree (T[a], S); + } + + + + gs=vcalloc (2, sizeof (int)); + list=declare_int (LIST->nseq*S->nseq*2, S->nseq+1); + + blist=declare_int (2, S->nseq+1); + for ( n=0, a=0; a< LIST->nseq; a++) + { + int n2=0; + tree2split_list (T[a], S->nseq, list+n, &n2); + n+=n2; + + + for (b=0; bnseq; c++) + list[n+b][c]=1-list[n-n2+b][c]; + } + n+=n2; + } + + if ( group_file) + { + rlist=declare_arrayN(3, sizeof (int), 2,LIST->nseq*S->nseq, S->nseq+1); + l=file2list (group_file, " "); + + while (l[ng]) + { + int i, b, g; + if (!strstr (l[ng][1], "group")){ng++;continue;} + g=(strm (l[ng][1], "group2"))?0:1; + + for (b=2; bname, S->nseq, 100))!=-1)rlist[g][gs[g]][i]=1; + } + gs[g]++; + ng++; + } + } + else + { + rlist=vcalloc ( 2, sizeof (int**)); + rlist[1]=count_int_strings (list, n, S->nseq); + gs[1]=read_array_size_new (rlist[1]); + + rlist[0]=declare_int (S->nseq, S->nseq); + gs[0]=S->nseq; + for ( a=0; anseq; a++)rlist[0][a][a]=1; + } + + + for (wo=w=0,a=0; anseq; b++) + { + blist[0][b]=blist[1][b]=rlist[1][c][b]; + blist[0][b]=(rlist[0][a][b]==1)?1:blist[0][b]; //WITH GROUP 1 + blist[1][b]=(rlist[0][a][b]==1)?0:blist[1][b]; //wiTHOUT gROUP 1 + + } + for (b=0; bnseq)==0)?1:0; + w+=x1; + x2=(memcmp (blist[1], list[b], sizeof (int)*S->nseq)==0)?1:0; + wo+=x2; + + } + fprintf ( stdout, "\n%d ", MIN(wo, w)); + fprintf ( stdout, "("); + for (b=0; bnseq; b++)if (rlist[1][c][b])fprintf ( stdout, "%s ",S->name[b]); + fprintf ( stdout, ") +/- ("); + for (b=0; bnseq; b++)if (rlist[0][a][b])fprintf ( stdout, "%s ",S->name[b]); + + fprintf (stdout , ") + %d - %d Delta %d", w, wo, FABS((wo-w))); + } + } + myexit (0); +} +Split * print_split ( int n, int **list, Sequence *LIST, Sequence *S, char *buf, char *file); + +NT_node split2tree ( NT_node RT,Sequence *LIST, char *param) +{ + Split **S; + Alignment *A; + S=count_splits (RT, LIST, param); + A=seq2aln ((S[0])->S,NULL, KEEP_GAP); + + return split2upgma_tree (S,A, A->nseq, "no"); +} + +Split** count_splits( NT_node RT,Sequence *LIST, char *param) +{ + NT_node *T, OrderT; + Sequence *S=NULL; + int a, b, c, d, n1, n2; + int **list1, **list2; + Split **SL; + int nb, tlist; + char *main_buf; + char *in=NULL,*in2=NULL, *out=NULL, order[100], filter[100]; + FILE *fp, *fp2; + static char *def_param; + char *cache=NULL; + //+count_splits _NB_x_FILTER_ + //_ + if (!def_param)def_param=vcalloc ( 10, sizeof (char)); + + + + if (!param)param=def_param; + + + strget_param (param, "_NB_", "0", "%d", &nb); + strget_param (param, "_TLIST_", "0", "%d", &tlist); + strget_param (param, "_ORDER_", "NO", "%s", order); + strget_param (param, "_FILTER_", "NO", "%s", filter); + + fprintf ( stderr, "\nREAD TREE LIST [%d Trees...", LIST->nseq); + T=read_tree_list (LIST); + fprintf ( stderr, "..]"); + + if ( !(strm (order, "NO"))) + { + if (is_newick (order)) + { + OrderT=main_read_tree (order); + } + else + { + S=main_read_seq (order); + } + } + else + { + OrderT=(RT)?RT:T[0]; + } + fprintf ( stderr, "\nTrees Ordered according to: %s", (strm (order, "NO"))?"First Tree":order); + + + if (!S)S=tree2seq(OrderT, NULL); + + for (a=0; anseq; a++) + { + fprintf ( stdout, "\n#ORDER %15s : %3d", S->name[a], a+1); + } + if ( !strm (filter, "NO")) + { + Sequence *F; + int i; + + F=main_read_seq (filter); + cache=vcalloc (S->nseq, sizeof (int)); + for ( a=0; anseq; a++) + { + if ( (i=name_is_in_list (F->name[a], S->name, S->nseq, 100))!=-1) + cache[i]=1; + } + free_sequence (F, -1); + } + + main_buf=vcalloc ( S->nseq*(STRING+1), sizeof(int)); + + list1=declare_int (S->nseq*3, S->nseq+1); + list2=declare_int (S->nseq*3, S->nseq+1); + + for ( a=0; a< LIST->nseq; a++) + { + T[a]=prune_tree (T[a], S); + T[a]=recode_tree (T[a], S); + } + + + + if (!RT) + { + char *buf; + int i,nl; + + in=vtmpnam (NULL);in2=vtmpnam(NULL); out=vtmpnam (NULL); + + fp=vfopen (in, "w"); + fp2=vfopen (in2, "w"); + for ( a=0; a< LIST->nseq; a++) + { + n2=0; + tree2split_list (T[a], S->nseq, list2, &n2); + for ( b=0; bnseq; c++) + {fprintf (fp, "%d", list2[b][c]);} + fprintf (fp, "\n"); + for (c=0; c< S->nseq; c++) + {fprintf (fp, "%d", 1-list2[b][c]);} + fprintf (fp, "\n"); + + for (c=0; c< S->nseq; c++) + {fprintf (fp2, "%d", list2[b][c]);} + fprintf (fp2, " "); + for (c=0; c< S->nseq; c++) + {fprintf (fp2, "%d", 1-list2[b][c]);} + fprintf (fp2, " %s\n",LIST->name[a]); + } + } + vfclose (fp2); + vfclose (fp); + + count_strings_in_file (in, out); + nl=count_n_line_in_file(out); + list1=declare_int (nl+1, S->nseq+2); + + fp=vfopen (out, "r"); + n1=0; + buf=vcalloc (measure_longest_line_in_file (out)+1, sizeof (char)); + while ( fscanf (fp, "%s %d",buf, &i)==2) + { + for (a=0; anseq; a++)list1[n1][a]=buf[a]-'0'; + list1[n1++][S->nseq+1]=i; + } + vfclose (fp); + vfree (buf); + } + else + { + + RT=prune_tree (RT, S); + RT=recode_tree (RT, S); + n1=0; + tree2split_list (RT, S->nseq, list1,&n1); + for ( a=0; a< LIST->nseq; a++) + { + n2=0; + tree2split_list (T[a], S->nseq, list2, &n2); + for (b=0; bnseq; d++) + { + if (list1[b][d]!=list2[c][d])di++; + } + list1[b][S->nseq+1]+=(di==0 || di== S->nseq)?1:0; + } + + } + } + } + SL=vcalloc ( n1+1, sizeof (Split*)); + + for (a=0; anseq; b++)if (cache[b]!=list1[a][b])cont=0; + if (!cont) continue; + + SL[a]=print_split (a, list1, LIST, S, main_buf, (tlist==1)?in2:NULL); + for (b=0; bnseq; c++) + { + s1+=list1[b][c]; + s2+=list1[a][c]; + d+=(list1[a][c]!=list1[b][c])?1:0; + } + + } + if (d<=nb &&((s1==s2)|| ((S->nseq-s1)==s2)))print_split (b, list1, LIST, S, main_buf, (tlist==1)?in2:NULL); + } + } + a=0; + vfree (cache); + return SL; +} +Split * declare_split (int nseq, int ntrees); +Split* print_split ( int a, int **list1, Sequence *LIST, Sequence *S, char *buf, char *split_file) + { + int f1,t,b; + Split *SP=NULL; + + + + SP=declare_split (S->nseq, LIST->nseq); + + fprintf ( stdout, "\n>"); + for (t=0,b=0; bnseq; b++){fprintf ( stdout, "%d", list1[a][b]);t+=list1[a][b];SP->split[b]='0'+list1[a][b];} + fprintf ( stdout, " NumberSplit %5d SplitSize %5d Score %5.2f %s ", list1[a][S->nseq+1],t, (float)(list1[a][S->nseq+1]*100)/LIST->nseq, (buf)?buf:""); + SP->n= list1[a][S->nseq+1]; + SP->score=(float)(list1[a][S->nseq+1]*100)/LIST->nseq; + SP->S=S; + + for (f1=1,b=0; b< S->nseq; b++) + { + + if (list1[a][b]) + { + if (f1==1)fprintf ( stdout, "("); + else fprintf (stdout, ","); + f1=0; + fprintf ( stdout, "%s", S->name [b]); + } + } + fprintf ( stdout, ")"); + if (split_file) + { + char *buf=NULL; + FILE *fp; + + char c; + fp=vfopen (split_file, "r"); + while ( (c=fgetc(fp))!=EOF) + { + + c=ungetc (c, fp); + buf=vfgets (buf, fp); + if ( strstr (buf, SP->split)) + { + char **list; + list=string2list (buf); + fprintf ( stdout, "\n\t%s %s", SP->split, list[3]); + free_char (list, -1); + } + } + vfclose (fp); + } + + return SP; + } +Split * declare_split (int nseq, int ntrees) +{ + Split *S; + S=vcalloc (1, sizeof (Split)); + S->split=vcalloc ( nseq+1, sizeof (char)); + return S; +} +int treelist2splits( Sequence *S, Sequence *TS) +{ + NT_node *T; + int n=0,nseq, a, c; + + int *used; + + char *split_file, *sorted_split_file; + char *buf=NULL, *ref_buf=NULL; + FILE *fp; + + split_file=vtmpnam (NULL); + sorted_split_file =vtmpnam (NULL); + + n=S->nseq; + used=vcalloc (n, sizeof (int)); + + T=read_tree_list (S); + if (!TS)TS=tree2seq(T[0], NULL); + nseq=TS->nseq; + fp=vfopen (split_file, "w"); + + + for ( a=0; a< S->nseq; a++) + { + + T[a]=prune_tree (T[a], TS); + T[a]=recode_tree (T[a], TS); + display_splits (T[a], TS,fp); + } + + vfclose (fp); + printf_system ("cp %s split_file::IGNORE_FAILURE::", split_file); + printf_system ( "cat %s | grep 1| sort > %s::IGNORE_FAILURE::", split_file, sorted_split_file); + + fp=vfopen (sorted_split_file, "r"); + fprintf (stdout, "LEGEND: <#occurences> <(group1,)> <(group2,>\n"); + + for ( a=0; anseq; a++)fprintf ( stdout, "SEQ_INDEX %d %s\n", a+1, TS->name[a]); + while ( (c=fgetc (fp))!=EOF) + { + + ungetc (c, fp); + buf=vfgets (buf, fp); + buf [strlen(buf)-1]='\0'; + + if ( ref_buf==NULL) + { + ref_buf=vcalloc (strlen (buf)+1, sizeof (char)); + sprintf ( ref_buf, "%s", buf); + n=1; + } + else if ( !strm (buf, ref_buf)) + { + int i; + fprintf ( stdout, "SPLIT_COUNT %3d %s (", n, ref_buf); + for (i=0,a=0; aname[a]); + i=1; + } + fprintf ( stdout, "),("); + for (i=0,a=0; aname[a]); + i=1; + } + + fprintf (stdout, ")\n"); + sprintf ( ref_buf, "%s", buf); + n=1; + } + else + { + n++; + } + } + vfclose (fp); + + + myexit (0); +} + +int treelist2splits_old ( Sequence *S, Sequence *TS) +{ + NT_node *T; + int n=0,nseq, a,c; + + int *used; + + char *split_file, *sorted_split_file; + char *buf=NULL, *ref_buf=NULL; + FILE *fp; + + split_file=vtmpnam (NULL); + sorted_split_file =vtmpnam (NULL); + + n=S->nseq; + used=vcalloc (n, sizeof (int)); + + T=read_tree_list (S); + if (!TS)TS=tree2seq(T[0], NULL); + nseq=TS->nseq; + fp=vfopen (split_file, "w"); + + for ( a=0; a< S->nseq; a++) + { + + T[a]=prune_tree (T[a], TS); + T[a]=recode_tree (T[a], TS); + display_leaf_nb (T[a], TS->nseq,fp, S->name[a]); + } + vfclose (fp); + printf_system ("cp %s split_file::IGNORE_FAILURE::", split_file);myexit (0); + + printf_system ( "cat %s | grep 1| sort > %s::IGNORE_FAILURE::", split_file, sorted_split_file); + + vfopen (sorted_split_file, "r"); + + while ( (c=fgetc (fp))!=EOF) + { + + ungetc (c, fp); + buf=vfgets (buf, fp); + buf [strlen(buf)-1]='\0'; + + if ( ref_buf==NULL) + { + ref_buf=vcalloc (strlen (buf)+1, sizeof (char)); + sprintf ( ref_buf, "%s", buf); + n=1; + } + else if ( !strm (buf, ref_buf)) + { + int i; + fprintf ( stdout, "%3d %s(", n, ref_buf); + for (i=0,a=0; aname[a]); + i=1; + } + fprintf ( stdout, "),("); + for (i=0,a=0; aname[a]); + i=1; + } + + fprintf (stdout, ")\n"); + sprintf ( ref_buf, "%s", buf); + n=1; + } + else + { + n++; + } + } + vfclose (fp); + + + myexit (0); +} + +NT_node *treelist2prune_treelist (Sequence *S, Sequence *TS, FILE *out) +{ + NT_node *T; + int a, b, c; + + T=read_tree_list (S); + T=vrealloc (T, (S->nseq+1)*sizeof (NT_node)); + for (b=0,a=0; anseq; a++) + { + T[a]=prune_tree (T[a], TS); + if (tree2nleaf(T[a])nseq) + { + ; + } + else + { + char *s; + T[b]=T[a]; + T[b]=recode_tree (T[b], TS); + sprintf ( S->name[b], "%s", S->name[a]); + s=tree2string (T[a]); + S->seq[b]=vrealloc (S->seq[b], (strlen (s)+1)*sizeof (char)); + sprintf (S->seq[b], "%s",s); + sprintf (S->seq_comment[b], " NSPECIES: %d", TS->nseq); + vfree (s); + + b++; + } + + } + + S->nseq=b; + T[S->nseq]=NULL; + + if (out) + { + for (a=0; anseq; a++) + { + print_tree (T[a], "newick", out); + } + } + return T; +} +int** treelist2lti2 ( Sequence *S, Sequence *TS, int ngb, FILE *out); +int treelist2frame (Sequence *S, Sequence *TS) +{ + int n, a, b, c,d, **r, **order; + Sequence *temp; + + temp=duplicate_sequence (S); + order= treelist2lti (temp, TS,0,stdout); + + TS=reorder_seq_2 (TS, order, 0, TS->nseq); + n=TS->nseq; + + for (a=3; anseq=a+1; + temp=duplicate_sequence (S); + r=treelist2groups (temp,TS, NULL, NULL); + fprintf ( stdout, "\n>Tree_%d [%d %%]\n ", a+1,r[0][1]); + tree=main_read_tree (temp->name[r[0][0]]); + tree=prune_tree (tree, TS); + print_tree (tree, "newick",stdout); + + free_int (r, -1); + free_sequence (temp,-1); + } + myexit (EXIT_SUCCESS); +} +int** treelist2lti2 ( Sequence *S, Sequence *TS, int ngb, FILE *out) +{ + NT_node *T; + int a,b, c, d, ****dist, i; + int **score, **order; + + score=declare_int (TS->nseq, 3); + order=declare_int (TS->nseq, 2); + vsrand (0); + + for (a=0; a<50; a++) + { + Sequence *seq, *trees; + int **r; + trees=duplicate_sequence (S); + seq=duplicate_sequence (TS); + for (b=0; bnseq; b++){order[b][0]=b;order[b][1]=rand()%10000;} + sort_int (order, 2, 1, 0, TS->nseq-1); + seq=reorder_seq_2(seq, order, 0,5); + r=treelist2groups (trees,seq, NULL, NULL); + + for (b=0; b<5; b++) + { + score[order[b][0]][1]+=r[0][1]; + score[order[b][0]][2]++; + } + HERE ("Score=%d", r[0][1]); + free_int (r, -1); + free_sequence (seq, -1); + free_sequence (trees, -1); + + } + + for ( a=0; a< TS->nseq; a++) + { + score[a][0]=a; + HERE ("%s => %d [%d]",TS->name[a], score[a][1]/score[a][2], score[a][2]); + score[a][1]/=(score[a][2])?score[a][2]:1; + } + sort_int_inv (score, 3, 1, 0, TS->nseq-1); + + return score; +} + + +int** treelist2lti ( Sequence *S, Sequence *TS, int ngb, FILE *out) +{ + NT_node *T; + int a,b, c, d, ****dist, i; + float score0=0, score1=0; + int **result; + + + i=S->nseq; + T=treelist2prune_treelist (S, TS,NULL); + + if (!ngb)ngb=TS->nseq*2; + dist=vcalloc ( S->nseq, sizeof (int****)); + result=declare_int (TS->nseq, 2); + for (a=0; anseq; a++) + { + float score_seq=0; + float n_seq=0; + for (b=0; bnseq;b++) + { + float score_pair=0; + float n_pair=0; + for (c=0; cnseq; c++) + { + if (!dist[c])dist[c]=tree2dist(T[c], TS, NULL); + for (d=0; dnseq; d++) + { + float score, d1, d2; + + if (!dist[d])dist[d]=tree2dist(T[d], TS, NULL); + d1=dist[c][0][a][b]; + d2=dist[d][0][a][b]; + score=FABS((d1-d2)); + if (d1>ngb || d2>ngb); + else + { + score_seq+=score; + score_pair+=score; + n_seq++; + n_pair++; + } + // if (d1 && d2) HERE ("%d %d", (int)d1, (int)d2); + } + } + score_pair=(score_pair*100)/(float)n_pair; + if (out)fprintf ( stdout, "\n>%-20s %-20s LTI: %7.3f [Kept %d Trees Out of %d] ", TS->name[a],TS->name[b], score_pair, S->nseq,i); + } + + score_seq=(score_seq*100)/n_seq; + result[a][0]=a; + result[a][1]=(int)(100*score_seq); + if (out)fprintf ( stdout, "\n>%-20s %-20s LTI: %7.3f [Kept %d Trees Out of %d] ", TS->name[a],"*", score_seq, S->nseq, i); + } + sort_int (result,2,1,0, TS->nseq-1); + return result; +} + + +int ***tree2dist (NT_node T, Sequence *S, int ***d) +{ + int *l0, *r0,*l1, *r1, a, b; + + + if (!T) return d; + if (!S)S=tree2seq(T, NULL); + if (!d) + { + d=declare_arrayN (3, sizeof (float),2, S->nseq, S->nseq); + T=prune_tree(T, S); + T=recode_tree (T, S); + } + + if (!T->left)return d; + if (!T->right) return d; + + l0=(T->left)->idist; + r0=(T->right)->idist; + + l1=(T->left)->ldist; + r1=(T->right)->ldist; + + + + for (a=0; a< S->nseq; a++) + for (b=0; bnseq; b++) + { + if (l0[a]>0 && r0[b]>0)d[0][a][b]=d[0][b][a]=l0[a]+r0[b]; + if (l0[a]>0 && r0[b]>0)d[1][a][b]=d[1][b][a]=l1[a]+r1[b]; + } + + d=tree2dist (T->left, S, d); + d=tree2dist (T->right, S, d); + + + return d; +} + + + +int **tree2dist_split ( NT_node T, Sequence *S, int **dist) +{ + + FILE *fp; + int a, b, c, n=0; + char *buf=NULL, **list=NULL, *split_file; + + + if (!S)S=tree2seq(T, NULL); + + T=prune_tree (T, S); + T=recode_tree (T, S); + + split_file=vtmpnam (NULL); + fp=vfopen (split_file, "w"); + display_code (T, S->nseq,fp); + vfclose (fp); + + list=declare_char (2*S->nseq, S->nseq+1); + fp=vfopen (split_file, "r"); + + while ((buf=vfgets (buf,fp))!=NULL) + { + if (buf[0]=='1' || buf[0]=='0')sprintf (list[n++], "%s", buf); + } + vfclose (fp); + dist=declare_int ( S->nseq, S->nseq); + for (a=0; a< S->nseq; a++) + for ( b=0; bnseq; b++) + for (c=0; cnseq; + T=treelist2prune_treelist (S, TS,NULL); + nsn=(star_node)?atoi(star_node):0; + + results=declare_int (S->nseq+1, 2); + + if (nsn) + { + for (a=0; a< S->nseq; a++)tree2star_nodes(T[a],nsn); + } + + used=vcalloc (S->nseq, sizeof (int)); + for (ntop=0,a=0; anseq; a++) + { + + if (used[a]==0) + { + ntop++; + if (out)fprintf ( out, "\nTree %s:",S->name[a]); + used[a]=1; + } + else continue; + tot=1; + for ( b=0; bnseq; b++) + { + v=0; + + v=(int)simple_tree_cmp (T[a], T[b], TS, 1); + if ( v==100) + { + used[b]=1; + used[a]++; + if (out)fprintf (stdout," %s ", S->name[b]); + tot++; + } + } + + if (out)fprintf ( stdout, "__ N=%d\n", tot-1); + } + + + for (n=0,a=0; anseq; a++) + { + if ( used[a]>1) + { + if (out)fprintf ( out, "\n>%-15s %4d %6.2f TOPOLOGY_LIST\n", S->name[a], used[a]-1, (float)(((float)used[a]-1)*100/(float)S->nseq)); + if (out)print_tree (T[a], "newick_tree", out); + results[n][0]=a; + results[n][1]=((used[a]-1)*100)/i; + n++; + } + } + + for (a=0; anseq; a++) free_tree(T[a]); + vfree (T); + + if (out)fprintf ( stdout, "\nTotal Number of different topologies: %d\n", ntop); + results[n][0]=-1; + sort_int_inv (results,2,1,0, n-1); + for (a=0; anseq; a++) free_tree(T[a]); + vfree (T); + return results; + } +float simple_tree_cmp (NT_node T1, NT_node T2,Sequence *S, int mode) +{ + Tree_sim *TS1, *TS2; + float t, w, l, n; + + TS1=vcalloc (1, sizeof (Tree_sim)); + TS2=vcalloc (1, sizeof (Tree_sim)); + + + T1=recode_tree(T1, S); + T2=recode_tree(T2, S); + + n=new_compare_trees ( T1, T2, S->nseq, TS1); + new_compare_trees ( T2, T1, S->nseq, TS2); + + + + t=(TS1->uw+TS2->uw)*100/(TS1->max_uw+TS2->max_uw); + w=(TS1->w+TS2->w)*100/(TS1->max_w+TS2->max_w); + l=(TS1->d+TS2->d)*100/(TS1->max_d+TS2->max_d); + + vfree (TS1); vfree (TS2); + if ( mode ==1)return t; + else if (mode ==2) return w; + else return l; +} +int treelist2n (NT_node *L) +{ + int n=0; + while (L[n])n++; + return n; +} +int **treelist2avg_treecmp (NT_node *L, char *file) +{ + int a, b, n; + int **score; + + if (file) L=read_tree_list (main_read_seq(file)); + n=treelist2n (L); + + score=declare_int (n, 2); + for (a=0; auw; + score[b][1]+=ts->uw; + vfree (ts); + } + } + sort_int_inv (score, 2, 1, 0, n-1); + if (file)free_treelist(L); + return score; +} + +int treelist_file2consense (char *tree_file, char *outtree, char *outfile) +{ + static char *command; + static char *tmp_outtree; + static char *tmp_outfile; + FILE *fp; + int flag1=0; + int flag2=0; + + if (!command) + { + command=vtmpnam (NULL); + tmp_outtree=vtmpnam (NULL); + tmp_outfile=vtmpnam (NULL); + } + if (!check_program_is_installed ("consense",NULL,NULL,"www.phylip.com",NO_REPORT))return 0; + + fp=vfopen (command, "w");fprintf ( fp, "%s\nY\n", tree_file);fclose (fp); + if ( check_file_exists ("outtree")){flag1=1;printf_system ("mv outtree %s::IGNORE_FAILURE::", tmp_outtree);} + if ( check_file_exists ("outfile")){flag2=1;printf_system ("mv outfile %s::IGNORE_FAILURE::", tmp_outfile);} + printf_system ("consense <%s > /dev/null 2>/dev/null::IGNORE_FAILURE::", command); + + if ( outtree)printf_system ("mv outtree %s::IGNORE_FAILURE::", outtree); + remove ("outtree"); + if ( outfile)printf_system ("mv outfile %s::IGNORE_FAILURE::", outfile); + remove ("outfile"); + if (flag1)printf_system ("mv %s outtree::IGNORE_FAILURE::", tmp_outtree); + if (flag2)printf_system ("mv %s outfile::IGNORE_FAILURE::", tmp_outfile); + return 1; +} + + +NT_node treelist2filtered_bootstrap ( NT_node *L,char *file, int **score, float t) +{ + NT_node BT, *L2; + int n,a; + + if (t==1 || t==0 || !score)return treelist2bootstrap (L, file); + + if (file)L=read_tree_list (main_read_seq(file)); + + n=treelist2n(L)*t; + + if (n==0) return NULL; + + L2=vcalloc ( n+1, sizeof (NT_node)); + for (a=0; a/dev/null 2>/dev/null", file, outfile); + + T=main_read_tree (outfile); + T=tree_dist2normalized_tree_dist (T,treelist2n(L)); + + + return T; +} + + + +Sequence * treelist2seq (Sequence *S) +{ + int a, b, c, n, i; + char **name; + NT_node *T; + Sequence *TS; + char *fname; + FILE *fp; + + name=vcalloc (1, sizeof (char*)); + fp=vfopen ((fname=vtmpnam (NULL)), "w"); + + T=read_tree_list (S); + for (n=0,a=0; a< S->nseq; a++) + { + TS=tree2seq(T[a], NULL); + for (b=0; bnseq; b++) + { + if ( (i=name_is_in_list (TS->name[b], name, n, 100))==-1) + { + name[n]=vcalloc (100, sizeof (int)); + sprintf ( name[n], "%s", TS->name[b]); + n++; + name=vrealloc (name, (n+1)*sizeof (char*)); + fprintf ( fp, ">%s\n", TS->name[b]); + } + } + free_sequence(TS, TS->nseq); + free_tree (T[a]); + } + + vfclose (fp); + vfree (T); + return get_fasta_sequence (fname, NULL); +} + + +Sequence * treelist2sub_seq ( Sequence *S, int f) +{ + NT_node *T; + int a,b,c, s, i, n, maxnseq, tot; + int **count, **grid; + char *fname; + Sequence *FS, *TS; + FILE *fp; + if (!f)return treelist2seq(S); + + + //keep as many taxons as possible so that f% of the trees are kept + //1: count the frequency of each taxon + + FS=treelist2seq (S); + maxnseq=FS->nseq; + + count=declare_int (maxnseq, 3); + grid=declare_int (S->nseq,maxnseq+1); + T=read_tree_list (S); + + + + for (a=0; anseq; a++){count[a][0]=a;count[a][2]=1;} + for (n=0,a=0; a< S->nseq; a++) + { + TS=tree2seq(T[a], NULL); + for (b=0; bnseq; b++) + { + i=name_is_in_list (TS->name[b], FS->name, FS->nseq, 100); + if ( i==-1){myexit (EXIT_FAILURE);} + count[i][1]++; + grid[a][i]=1; + } + free_sequence(TS, TS->nseq); + free_tree (T[a]); + } + vfree (T); + sort_int ( count,3,1, 0, maxnseq-1); + + for (a=0; anseq; b++)grid[b][maxnseq]=1;//prepare to keep everything + for ( tot=S->nseq, b=0; b< S->nseq; b++) + { + for (c=0; cnseq; + if ( tot>=f)break; + } + if (tot%s LIMIT: %d %%\n", FS->name[count[a][0]], f); + + } + } + vfclose (fp); + free_int (grid, -1); free_int (count, -1); + free_sequence (FS, FS->nseq); + + return get_fasta_sequence (fname, NULL); +} +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/util.c b/binaries/src/tcoffee/t_coffee_source/util.c new file mode 100644 index 0000000..14ef0d2 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/util.c @@ -0,0 +1,8569 @@ +// DIR_4_TCOFFEE [def: ~/.t_coffee]: UNIQUE_DIR_4_TCOFFEE -> DIR_4_TCOFFEE ->HOME/.t_coffee +//TMP_4_TCOFFEE [def: ~/.t_coffee/tmp]:: UNIQUE_DIR_4_TCOFFEE -> TMP_4_TCOFFEE ->DIR_4_TCOFFEE/tmp + +#define FILE_CHECK 1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" +#include "perl_header_lib.h" + +//defined this way because all compilers cannot pas ap +//safe printf: it declares buf to the proper size +#define cvsprintf(buf,string)\ +if(1)\ + { \ + va_list ap; \ + int n; \ + char buf2[2]; \ + va_start (ap,string); \ + n=vsnprintf (buf2,1, string, ap)+3; \ + va_end (ap); \ + va_start (ap, string); \ + buf=vcalloc (n, sizeof (char)); \ + vsnprintf (buf, n,string, ap); \ + va_end(ap);} + +int my_vsscanf(char *buf, char *fmt, va_list parms); +static int get_vtmpnam2_root(); + + + + +static int global_exit_signal; +static int no_error_report; +static int clean_exit_started; +static int debug_lock; +static char *in_cl; +static char *logfile; +/*********************************************************************/ +/* */ +/* DICHOTOMY */ +/* */ +/* */ +/*********************************************************************/ +double dichotomy (double value, double target_value, double middle, double *bottom,double *top) +{ + if ( value> target_value)top[0]=middle; + else if ( value= 0; sp--) { + char *lb, *ub, *m; + char *P, *i, *j; + + lb = lbStack[sp]; + ub = ubStack[sp]; + + while (lb < ub) { + + /* select pivot and exchange with 1st element */ + offset = (ub - lb) >> 1; + P = lb + offset - offset % size; + exchange (lb, P, size); + + /* partition into two segments */ + i = lb + size; + j = ub; + while (1) { + while (i < j && compar(lb, i) > 0) i += size; + while (j >= i && compar(j, lb) > 0) j -= size; + if (i >= j) break; + exchange (i, j, size); + j -= size; + i += size; + } + + /* pivot belongs in A[j] */ + exchange (lb, j, size); + m = j; + + /* keep processing smallest segment, and stack largest */ + if (m - lb <= ub - m) { + if (m + size < ub) { + lbStack[sp] = m + size; + ubStack[sp++] = ub; + } + ub = m - size; + } else { + if (m - size > lb) { + lbStack[sp] = lb; + ubStack[sp++] = m - size; + } + lb = m + size; + } + } + } +} +#endif +int pstrcmp(char *p1, char *p2); + + + +/*********************************************************************/ +/* */ +/* HEAPSORT */ +/* */ +/* */ +/*********************************************************************/ +FILE * hsort_file ( FILE *fp,int n,int len, size_t size,int first_comp_field, int n_comp_fields,int (*compare)(const void *, const void*,int, int, size_t),void * (*copy)(void *,void*, size_t)) + { + unsigned long i, ir, j, l; + void *rra, *rrb, *ra_j, *ra_j_1; + void *tp; + long start; + int FE=1; + + + + start=ftell(fp); + rra =vcalloc ( len, size); + rrb =vcalloc ( len, size); + ra_j =vcalloc ( len, size); + ra_j_1=vcalloc ( len, size); + + if ( n<2)return fp; + l=(n >>1)+1; + ir=n; + + for (;;) + { + if ( l>FE) + { + l--; + fseek( fp, start+(((l-1)*len)*size), SEEK_SET); + fread( rra, size, len,fp); /*rra=ra[--l]*/ + } + else + { + fseek( fp, start+((ir-1)*len*size), SEEK_SET); + fread( rra, size, len,fp); /*rra=ra[ir]*/ + + fseek( fp, start, SEEK_SET); + fread( rrb, size, len,fp); /*rrb=ra[0]*/ + + fseek( fp, start+((ir-1)*len*size), SEEK_SET); + fwrite(rrb,size, len, fp); /*ra[ir]=rrb=ra[0]*/ + + if (--ir ==FE) + { + fseek ( fp,start, SEEK_SET); + fwrite(rra,size, len, fp); /*ra[0]=rra*/ + break; + } + } + i=l; + j=l+l; + while ( j<=ir) + { + fseek ( fp, start+((j-1)*len*size), SEEK_SET); + fread (ra_j, size, len, fp); + + if ( j>1)+1; + ir=n; + + for (;;) + { + if ( l>FE) + { + copy ( rra, ra[--l],len); + } + else + { + copy ( rra, ra[ir],len); + copy ( ra[ir], ra[FE], len); + if (--ir ==FE) + { + copy ( ra[FE],rra,len); + break; + } + } + i=l; + j=l+l; + while ( j<=ir) + { + if ( j1) + { + i=(lower+upper) >> 1; + + fseek ( fp,start+(i*el_size*entry_len), SEEK_SET); + fread ( key2, el_size, entry_len,fp); + c=compare(key2,key, comp_first, comp_len,el_size); + + if ( c==0){p[0]=i;return key2;} + else if ( c< 0)upper=i; + else if ( c> 0)lower=i; + } + return NULL; + } + +void * bsearch_array ( const void *key,int *p,int comp_first, int comp_len,void**list,int len, int entry_len,size_t el_size, int (*compare)(const void *, const void*,int, int, size_t)) + { + int upper, lower, c, i; + void *key2; + + upper=-1; + lower=len; + while ((lower-upper)>1) + { + i=(lower+upper) >>1; + key2=list[i]; + c=compare(key2,key, comp_first,comp_len,el_size); + + if ( c==0){p[0]=i;return key2;} + else if ( c< 0)upper=i; + else if ( c> 0)lower=i; + } + return NULL; + } + +/**********************************************************************/ +/* */ +/* HSORT/BSEARCH WRAPPERS */ +/* */ +/* */ +/**********************************************************************/ +void **search_in_list_file ( void *key, int *p,int comp_len,FILE *fp, int len, size_t size, int entry_len) + { + static void **l; + + + if ( l==NULL)l=vcalloc ( 1, sizeof (int*)); + + l[0]=bsearch_file (key,p,0,comp_len,fp,len,entry_len,size,hsort_cmp); + if (l[0]==NULL)return NULL; + else return l; + } +void **search_in_list_array ( void *key,int *p, int comp_len,void **L, int len, size_t size, int entry_len) + { + static void **l; + + if ( l==NULL)l=vcalloc ( 1, sizeof (int*)); + + l[0]=bsearch_array (key,p,0,comp_len,L,len,entry_len,size,hsort_cmp); + if (l[0]==NULL)return NULL; + else return l; + } +void **hsort_list_array ( void **L, int len, size_t size, int entry_len, int first_comp_field, int n_comp_fields) + { + return hsort_array (L, len,entry_len, size,first_comp_field, n_comp_fields,hsort_cmp , hsort_cpy); + } +FILE *hsort_list_file ( FILE*fp , int len, size_t size, int entry_len, int first_comp_field, int n_comp_fields) + { + + return hsort_file (fp, len,entry_len, size,first_comp_field, n_comp_fields,hsort_cmp , hsort_cpy); + } + +int hsort_cmp ( const void *a, const void *b, int first, int clen, size_t size) + { + int*ax; + int*bx; + int p; + + ax=(int*)a; + bx=(int*)b; + for ( p=first; pb[0][c])return 1; + else if ( a[0][c]b[0][c])return 1; + else if ( a[0][c]=max_len[0]) + list=vrealloc ( list, (n[0]+100)*sizeof (int)); + max_len[0]=(n[0]+100); + + fscanf ( fp, "%d",&list[n[0]++]); + } + } + return fp; + } +/*********************************************************************/ +/* */ +/* QUANTILE */ +/* */ +/* */ +/*********************************************************************/ +int quantile (int argc, char *argv[]) +{ + FILE *fp; + int a,n,c, t; + int **list; + char *** string_list; + char *name, s1[1000], s2[1000]; + + + if ( argc<2) + { + + fprintf (stderr, "\nquantile []"); + fprintf (stderr, "\nSplits your data in two according to the quantile"); + fprintf (stderr, "\nReturns the top quantile or the bottom quantile"); + fprintf (stderr, "\nData must be in with two fields/line: Field1=index, Field2=value\n"); + fprintf (stderr, "\n1 27\n2 46\n3 5\n...\n"); + fprintf (stderr, "\nValue can either be integer or float"); + + + myexit (EXIT_FAILURE); + } + + if (strm (argv[1], "stdin")) + { + name=vtmpnam(NULL); + fp=vfopen (name, "w"); + while ( (c=fgetc(stdin))!=EOF) + { + fprintf ( fp, "%c", c); + } + vfclose (fp); + } + else + name=argv[1]; + + + + + n=count_n_line_in_file (name); + list=declare_int (n, 2); + string_list=declare_arrayN(3,sizeof (char), n, 2, 10); + + fp=vfopen (name, "r"); + n=0; + while ( (c=fgetc (fp))!=EOF) + { + ungetc(c,fp); + fscanf ( fp, "%s %s\n", s1, s2); + list[n][0]=(int)(atof(s1)*1000); + list[n][1]=(int)(atof(s2)*1000); + list[n][2]=n; + + sprintf (string_list[n][0],"%s",s1); + sprintf (string_list[n][1],"%s",s2); + + + n++; + } + sort_int_inv ( list,3, 1, 0, n-1); + t=quantile_rank ( list,1,n, atof (argv[2])); + if ( argc!=4 || (argc==4 && strm (argv[3], "bottom"))) + { + for (a=t; a=q)nr++; + vfree(l); + } + return nr; +} +/*********************************************************************/ +/* */ +/* DUPLICATION */ +/* */ +/* */ +/*********************************************************************/ +short* ga_memcpy_short ( short *array1, short *array2, int n) + { + int a; + + for ( a=0; a< n; a++) + array2[a]=array1[a]; + + return array2; + } +int * ga_memcpy_int ( int *array1, int *array2, int n) + { + int a; + + for ( a=0; a< n; a++) + array2[a]=array1[a]; + + return array2; + } + +float* ga_memcpy_float ( float *array1, float *array2, int n) + { + int a; + + for ( a=0; a< n; a++) + array2[a]=array1[a]; + + return array2; + } +double* ga_memcpy_double (double *array1, double*array2, int n) + { + int a; + + for ( a=0; a< n; a++) + array2[a]=array1[a]; + + return array2; + } + + + +/*recycle: get the bottom pointer on the top of the heap*/ + +void ** recycle (void **A, int l, int cycle) +{ + void **B; + int a,b,c; + B=vcalloc (l, sizeof (void*)); + + for ( c=0; c< cycle; c++) + { + for ( a=1, b=0; amax)max=index[i];\ + }\ + va_end(ap);\ + if (list==NULL)list=vcalloc ( max+1, sizeof (type));\ + for ( i=0; inseq; + rec_list=realloc_aln_array ( rec_list, end-first); + for ( a=first, b=rec_list_start; a, UNDEFINED_SHORT) +RETURN_MAX_COOR(char,write_size_char,read_size_char,return_max_coor_char,>, UNDEFINED_CHAR) +RETURN_MAX_COOR(int,write_size_int,read_size_int,return_max_coor_int,>, UNDEFINED_INT) +RETURN_MAX_COOR(float,write_size_float,read_size_float,return_max_coor_float,>, UNDEFINED_FLOAT) +RETURN_MAX_COOR(double,write_size_double,read_size_double,return_max_coor_double,>, UNDEFINED_DOUBLE) +RETURN_MAX_COOR(short,write_size_short,read_size_short,return_min_coor_short,<, UNDEFINED_SHORT) +RETURN_MAX_COOR(char,write_size_char,read_size_char,return_min_coor_char,<, UNDEFINED_CHAR) +RETURN_MAX_COOR(int,write_size_int,read_size_int,return_min_coor_int,<, UNDEFINED_INT) +RETURN_MAX_COOR(float,write_size_float,read_size_float,return_min_coor_float,<, UNDEFINED_FLOAT) +RETURN_MAX_COOR(double,write_size_double,read_size_double,return_min_coor_double,<, UNDEFINED_DOUBLE) +#define RETURN_MAX(type,wf,rf,function,comparison,undef)\ +type function ( type ** array, int len_array, int field)\ + {\ + type max;\ + int a;\ +\ + if (array==NULL || len_array==0)return 0;\ + else\ + {\ + if (len_array==-1)len_array=rf(array,sizeof (type*));\ + max=array[0][field];\ + for ( a=1; a< len_array; a++)\ + if ( max==undef)max=array[a][field];\ + else if ( array[a][field]!=undef)max=( array[a][field] comparison max)?array[a][field]:max;\ + }\ + return (max==undef)?0:max;\ + } + +RETURN_MAX(short,write_size_short,read_size_short,return_max_short,>,UNDEFINED_SHORT) +RETURN_MAX(char,write_size_char,read_size_char,return_max_char,>,UNDEFINED_CHAR) +RETURN_MAX(int,write_size_int,read_size_int,return_max_int,>,UNDEFINED_INT) +RETURN_MAX(float,write_size_float,read_size_float,return_max_float,>,UNDEFINED_FLOAT) +RETURN_MAX(double,write_size_double,read_size_double,return_max_double,>,UNDEFINED_DOUBLE) +RETURN_MAX(short,write_size_short,read_size_short,return_min_short,<,UNDEFINED_SHORT) +RETURN_MAX(char,write_size_char,read_size_char,return_min_char,<,UNDEFINED_CHAR) +RETURN_MAX(int,write_size_int,read_size_int,return_min_int,<,UNDEFINED_INT) +RETURN_MAX(float,write_size_float,read_size_float,return_min_float,<,UNDEFINED_FLOAT) +RETURN_MAX(double,write_size_double,read_size_double,return_min_double,<,UNDEFINED_DOUBLE) + + + +#define RETURN_2DMAX(type,wf,rf,function,comparison,undef)\ +type function ( type ** array, int start, int len_array, int first_field, int number_field)\ + {\ + type max;\ + int a,b;\ + if (array==NULL || len_array==0 || first_field<0 || number_field==0)return 0;\ + else\ + {max=array[start][first_field];\ + for ( a=start; a< start+len_array; a++)\ + for (b=first_field; b< first_field+number_field; b++)\ + if (array[a][b]!=undef)max=( array[a][b] comparison max)?array[a][b]:max;\ + }\ + return max;\ + } +RETURN_2DMAX(short,write_size_short,read_size_short,return_2Dmax_short,>, UNDEFINED_SHORT) +RETURN_2DMAX(char,write_size_char,read_size_char,return_2Dmax_char,>,UNDEFINED_CHAR) +RETURN_2DMAX(int,write_size_int,read_size_int,return_2Dmax_int,>,UNDEFINED_INT) +RETURN_2DMAX(float,write_size_float,read_size_float,return_2Dmax_float,>,UNDEFINED_FLOAT) +RETURN_2DMAX(double,write_size_double,read_size_double,return_2Dmax_double,>,UNDEFINED_DOUBLE) +RETURN_2DMAX(short,write_size_short,read_size_short,return_2Dmin_short,<,UNDEFINED_SHORT) +RETURN_2DMAX(char,write_size_char,read_size_char,return_2Dmin_char,<,UNDEFINED_CHAR) +RETURN_2DMAX(int,write_size_int,read_size_int,return_2Dmin_int,<,UNDEFINED_INT) +RETURN_2DMAX(float,write_size_float,read_size_float,return_2Dmin_float,<,UNDEFINED_FLOAT) +RETURN_2DMAX(double,write_size_double,read_size_double,return_2Dmin_double,<,UNDEFINED_DOUBLE) + +#define RETURN_2DMAX_COOR(type,wf,rf,function,compare,undef)\ +type function ( type **array, int start1 , int end1, int start2, int end2,int *i, int *j)\ + {\ + int a, b;\ + double max=undef;\ + if ( start1==-1)start1=0;\ + if ( start2==-1)start2=0;\ + if ( end1==-1)end1=rf(array,sizeof (type*));\ + if ( end2==-1)end2=rf(array[0],sizeof (type));\ + if ( array==NULL || (end1-start1)==0 || (end1-start1)>rf ( array,sizeof (type*)) || (end2-start2)==0)\ + {\ + return 0;\ + i[0]=0;\ + j[0]=0;\ + }\ + i[0]=0;\ + j[0]=0;\ + for ( a=start1; a,UNDEFINED_SHORT) +RETURN_2DMAX_COOR(char,write_size_char,read_size_char,return_2Dmax_coor_char,>,UNDEFINED_CHAR) +RETURN_2DMAX_COOR(int,write_size_int,read_size_int,return_2Dmax_coor_int,>,UNDEFINED_INT) +RETURN_2DMAX_COOR(float,write_size_float,read_size_float,return_2Dmax_coor_float,>,UNDEFINED_FLOAT) +RETURN_2DMAX_COOR(double,write_size_double,read_size_double,return_2Dmax_coor_double,>,UNDEFINED_DOUBLE) +RETURN_2DMAX_COOR(short,write_size_short,read_size_short,return_2Dmin_coor_short,<,UNDEFINED_SHORT) +RETURN_2DMAX_COOR(char,write_size_char,read_size_char,return_2Dmin_coor_char,<,UNDEFINED_CHAR) +RETURN_2DMAX_COOR(int,write_size_int,read_size_int,return_2Dmin_coor_int,<,UNDEFINED_INT) +RETURN_2DMAX_COOR(float,write_size_float,read_size_float,return_2Dmin_coor_float,<,UNDEFINED_FLOAT) +RETURN_2DMAX_COOR(double,write_size_double,read_size_double,return_2Dmin_coor_double,<,UNDEFINED_DOUBLE) + +#define RETURN_WMEAN(type,wf,rf,function,sum_function,undef)\ +double function ( type **array, int len, int wfield,int sfield)\ + {\ + double b;\ + int a, c;\ + if ( len==0 ||array==NULL || len>rf ( array,sizeof (type*)))return 0;\ + else\ + {\ + if ( len==-1)len=rf(array,sizeof (type*));\ + for ( b=0, c=0,a=0; a< len; a++)\ + {\ + if (array[a][sfield]!=undef && array[a][wfield]!=undef )\ + {\ + b+=array[a][sfield];\ + c+=array[a][wfield];\ + }\ + }\ + }\ + return (c==0)?0:(b/c);\ + } +RETURN_WMEAN(short,write_size_short,read_size_short,return_wmean_short, return_sum_short,UNDEFINED_SHORT) +RETURN_WMEAN(char,write_size_char,read_size_char, return_wmean_char,return_sum_char,UNDEFINED_CHAR) +RETURN_WMEAN(int,write_size_int,read_size_int,return_wmean_int,return_sum_int,UNDEFINED_INT) +RETURN_WMEAN(float,write_size_float,read_size_float,return_wmean_float,return_sum_float,UNDEFINED_FLOAT) +RETURN_WMEAN(double,write_size_double,read_size_double,return_wmean_double,return_sum_double,UNDEFINED_DOUBLE) + + +#define RETURN_MEAN(type,wf,rf,function,sum_function,undef)\ +double function ( type **array, int len, int field)\ + {\ + double b;\ + int a, c;\ + if ( len==0 ||array==NULL || len>rf ( array,sizeof(type*)))return 0;\ + else\ + {\ + for ( b=0, c=0,a=0; a< len; a++)\ + {\ + if (array[a][field]!=undef)\ + {\ + b+=array[a][field];\ + c++;\ + }\ + }\ + }\ + return (c==0)?0:(b/c);\ + } +RETURN_MEAN(short,write_size_short,read_size_short,return_mean_short, return_sum_short,UNDEFINED_SHORT) +RETURN_MEAN(char,write_size_char,read_size_char, return_mean_char,return_sum_char,UNDEFINED_CHAR) +RETURN_MEAN(int,write_size_int,read_size_int,return_mean_int,return_sum_int,UNDEFINED_INT) +RETURN_MEAN(float,write_size_float,read_size_float,return_mean_float,return_sum_float,UNDEFINED_FLOAT) +RETURN_MEAN(double,write_size_double,read_size_double,return_mean_double,return_sum_double,UNDEFINED_DOUBLE) + +#define RETURN_SUM(type,wf,rf,function,undef)\ +type function(type **array, int len, int field)\ +{\ + int a;\ + type b=0;\ + if ( len==0 ||array==NULL)return 0;\ + else\ + {\ + if ( len==-1)len=rf ( array,sizeof (type*));\ + for ( a=0; a< len; a++)\ + if ( array[a][field]!=undef)b+=array[a][field];\ + }\ + return b;\ + } +RETURN_SUM(short,write_size_short,read_size_short, return_sum_short,UNDEFINED_SHORT) +RETURN_SUM(char,write_size_char,read_size_char,return_sum_char,UNDEFINED_CHAR) +RETURN_SUM(int,write_size_int,read_size_int,return_sum_int,UNDEFINED_INT) +RETURN_SUM(float,write_size_float,read_size_float,return_sum_float,UNDEFINED_FLOAT) +RETURN_SUM(double,write_size_double,read_size_double,return_sum_double,UNDEFINED_DOUBLE) + +#define RETURN_SD(type,wf,rf,function,undef)\ + type function ( type **array, int len, int field,type mean) \ + {\ + int a;\ + double c=0;\ + if ( len==0 ||array==NULL || len>rf ( array,sizeof(type*)))return 0;\ + else\ + {\ + for ( a=0; a< len; a++)\ + {\ + if ((array[a][field]!=undef) && (mean-array[a][field])!=0)\ + c+=((double)mean-array[a][field])*((double)mean-array[a][field]);\ + }\ + c=sqrt(c)/(double)len;\ + return (type)MAX(c,1);\ + }\ + } +RETURN_SD(short,write_size_short,read_size_short, return_sd_short,UNDEFINED_SHORT) +RETURN_SD(char,write_size_char,read_size_char,return_sd_char,UNDEFINED_CHAR) +RETURN_SD(int,write_size_int,read_size_int,return_sd_int,UNDEFINED_INT) +RETURN_SD(float,write_size_float,read_size_float,return_sd_float,UNDEFINED_FLOAT) +RETURN_SD(double,write_size_double,read_size_double,return_sd_double,UNDEFINED_DOUBLE) +double return_z_score( double x,double sum, double sum2, double n) + { + double sd; + double avg; + double z; + + + sd=(n==0)?0:sqrt(sum2*n -sum*sum)/n; + avg=(n==0)?0:(sum/n); + z=(sd==0)?0:(x-avg)/sd; + return z; + } + +double* return_r (double **list, int n) +{ + double Sy, Sx, Sxy, Sx2, Sy2,r_up, r_low, x, y; + double *r; + int a; + + r=vcalloc ( 3, sizeof (double)); + Sy=Sx=Sxy=Sx2=Sy2=0; + + for ( a=0; a,UNDEFINED_SHORT) +RETURN_MAX_HORIZ(char,write_size_char,read_size_char,return_max_char_hor,>,UNDEFINED_CHAR) +RETURN_MAX_HORIZ(int,write_size_int,read_size_int,return_max_int_hor,>,UNDEFINED_INT) +RETURN_MAX_HORIZ(float,write_size_float,read_size_float,return_max_float_hor,>,UNDEFINED_FLOAT) +RETURN_MAX_HORIZ(double,write_size_double,read_size_double,return_max_double_hor,>,UNDEFINED_DOUBLE) + +RETURN_MAX_HORIZ(short,write_size_short,read_size_short,return_min_short_hor,<,UNDEFINED_SHORT) +RETURN_MAX_HORIZ(char,write_size_char,read_size_char,return_min_char_hor,<,UNDEFINED_CHAR) +RETURN_MAX_HORIZ(int,write_size_int,read_size_int,return_min_int_hor,<,UNDEFINED_INT) +RETURN_MAX_HORIZ(float,write_size_float,read_size_float,return_min_float_hor,<,UNDEFINED_FLOAT) +RETURN_MAX_HORIZ(double,write_size_double,read_size_double,return_min_double_hor,<,UNDEFINED_DOUBLE) + + + +#define BEST_OF_MANY(type,wf,rf,function,undef)\ +type function (int n, ...)\ + {\ + va_list ap;\ + int *fop,a;\ + type v, best;\ + int maximise;\ + /*first Arg: number of values\ + 2nd Arg: maximise(1)/minimise(0)\ + 3rd Arg: *int contains the indice of the best value\ + ... Arg: n type values\ + */\ + va_start (ap, n);\ + maximise=va_arg (ap, int);\ + fop=va_arg (ap, int*);\ + best=va_arg (ap, type);\ + fop[0]=0;\ + for ( a=1; abest)\ + {\ + fop[0]=a;\ + best=v;\ + }\ + else if ( maximise==0 && vmax)?strlen ( array[a]):max; + + return max; + } + + +int return_minlen ( char ** array, int number) + { + int a; + int min; + + min=strlen( array[0]); + for ( a=1; a< number; a++) + min=( strlen ( array[a])>min)?strlen ( array[a]):min; + + return min; + } + + + +float return_mean_diff_float ( float **array, int len, int field,float mean) + { + int a; + float b=0; + + for ( a=0; a< len; a++) + { + if ( (mean-array[a][field])!=0) + b+=sqrt((double)((float) ( mean-array[a][field])*(float)(mean-array[a][field]))); + } + + return ((float)b/(float)len); + } + + + +void inverse_int ( int**array, int len, int field, int max, int min) + { + int a; + for ( a=0; a< len; a++) + array[a][field]=max-array[a][field]+min; + } +void inverse_float ( float**array, int len, int field, int max, int min) + { + int a; + for ( a=0; a< len; a++) + array[a][field]=max-array[a][field]+min; + } +void inverse_2D_float ( float **array, int start, int len, int start_field, int number_field, float max,float min) + { + int a, b; + for ( a=0; a< start+len; a++) + for ( b=start_field; b< start_field+ number_field; b++) + array[a][b]=max-array[a][b]+min; + } + +int max_int (int*i, ...) +{ + va_list ap; \ + int index, best_value=0, value; + int a=0; + // expects n values : n, &index, i1, v1, i2, v2...., -1 + va_start(ap, i); + while ((index=va_arg(ap,int))!=-1) + { + value=va_arg(ap, int); + if ( a==0 || value>best_value) + { + i[0]=index; + best_value=value; + a=1; + } + } + va_end (ap); + return best_value; +} + +/*********************************************************************/ +/* */ +/* SHELL INTERFACES */ +/* */ +/* */ +/*********************************************************************/ +char* getenv4debug (const char * val) +{ + /*efficient mean of getting an environment variable: checks only if one DEBUG is on*/ + static int check; + + if ( !check) + { + + if (getenv ("DEBUG_BLAST"))check=1; + else if ( getenv ("DEBUG_TREE_COMPARE"))check=1; + else if ( getenv ("DEBUG_MALN"))check=1; + else if ( getenv ("DEBUG_EXTRACT_FROM_PDB"))check=1; + else if ( getenv ("DEBUG_LIBRARY"))check=1; + else if ( getenv ("DEBUG_FUGUE"))check=1; + + else if ( getenv ("DEBUG_REFORMAT"))check=1; + else if ( getenv ("DEBUG_RECONCILIATION"))check=1; + else if ( getenv ("DEBUG_TMP_FILE"))check=1; + else if ( getenv ("DEBUG_TREE"))check=1; + + else if ( getenv ("DEBUG_SEQ_REFORMAT") && strm (PROGRAM, "SEQ_REFORMAT"))check=2; + else if ( getenv ("DEBUG_TCOFFEE") && strm (PROGRAM, "T-COFFEE"))check=2; + else check=-1; + } + + if ( check>0 && strm ( val, "DEBUG_TMP_FILE")) + { + return "1"; + } + + else if ( check==1) + { + return getenv (val); + } + else if ( check==2) + { + return "1"; + } + else + return NULL; +} + +int atoigetenv (const char*var) +{ + char *v; + if (!var) return 0; + else if (!(v=getenv(var)))return 0; + else if ( is_number(v))return atoi(v); + else return 1; +} +char* get_env_variable ( const char *var, int mode) + { + /*mode 0: return NULL if variable not set*/ + /*mode 1: crash if variable not set*/ + if ( !getenv (var)) + { + if (mode==NO_REPORT)return NULL; + else if ( mode ==IS_NOT_FATAL) + { + myexit(fprintf_error ( stderr, "\nYou must set the variable %s [FATAL]\n", var)); + return NULL; + } + else + { + myexit(fprintf_error ( stderr, "\nYou must set the variable %s [FATAL]\n", var)); + myexit (EXIT_FAILURE); + return NULL; + } + } + else return getenv (var); + } + +void get_pwd ( char *name) + { + char *string; + FILE *fp; + + + string=vtmpnam(NULL); + printf_system_direct ("pwd > %s", string); + + fp=vfopen ( string, "r"); + fscanf ( fp, "%s",name); + vfclose (fp); + printf_system_direct ("rm %s", string); + } +int pg_is_installed ( char *pg) + { + char *fname; + FILE *fp; + int r=0; + + return 1; + + fname= vtmpnam(NULL); + + printf_system_direct("which %s > %s", pg, fname); + + if ((fp=find_token_in_file ( fname, NULL, "Command"))){r=1;vfclose(fp);} + + + return r; + + } + + +/*********************************************************************/ +/* */ +/* MISC */ +/* */ +/*********************************************************************/ +char *num2plot (int value, int max, int line_len) + { + int len; + int value_len; + char *buf; + static char *string; + + if ( string==NULL)string=vcalloc (1000, sizeof(char)); + + if ( line_len==-1)len=30; + else len=line_len; + + value_len=((float)value/(float)max)*(float)len; + if ( value==0) + sprintf ( string, "|"); + else + { + buf=generate_string(value_len, '*'); + sprintf ( string,"%s", buf); + vfree(buf); + } + return string; + } + +int perl_strstr ( char *string, char *pattern) +{ + char *tmp; + FILE *fp; + int r; + + char *string2; + + if (!string) return 0; + if (!pattern) return 0; + + + + string2=vcalloc ( strlen (string)+1, sizeof (char)); + sprintf ( string2,"%s", string); + string2=substitute (string2, "(", " "); + string2=substitute (string2, ")", " "); + string2=substitute (string2, "'", " "); + tmp=vtmpnam(NULL); + printf_system_direct("perl -e '$s=\"%s\";$x=($s=~/%s/);$x=($x==1)?1:0;print $x;'>%s", string2, pattern,tmp); + + if (check_file_exists(tmp)) + { + fp=vfopen (tmp, "r"); + fscanf (fp, "%d", &r); + vfclose (fp); + } + else + { + fprintf ( stderr, "COM: %s\n", string); + r=0; + } + vfree (string2); + return r; +} + +void crash_if ( int val, char *s) + { + if ( val==0)crash(s); + } +void crash ( char *s) + { + int *a; + + + + fprintf ( stderr, "%s",s); + a=vcalloc ( 10, sizeof (int)); + a[20]=1; + error_exit(); + } + +static int *local_table; +int ** make_recursive_combination_table ( int tot_n_param, int *n_param, int *nc, int**table, int field) + { + int a, b, c; + + /* makes a table of all possible combinations*/ + + if ( tot_n_param==0) + { + nc[0]=1; + fprintf ( stderr, "\nNULL RETURNED"); + return NULL; + } + if (table==NULL) + { + if ( local_table!=NULL)vfree (local_table); + local_table=vcalloc ( tot_n_param, sizeof (int)); + field=0; + for ( a=0; a< tot_n_param; a++)local_table[a]=-1; + for ( a=0; a< tot_n_param; a++)nc[0]=nc[0]*n_param[a]; + + + table=declare_int ( nc[0],tot_n_param); + nc[0]=0; + } + + for ( b=0; bsuffix)sprintf ( name, "%s.%s", F->name, F->suffix); + else sprintf (name, "%s", F->name); + free_fname (F); + return name; +} +Fname* parse_fname ( char *array) + { + int l; + Fname *F; + + + + F=declare_fname (sizeof (array)); + + sprintf ( F->full, "%s", array); + sprintf ( F->path, "%s", array); + l=strlen (array); + while (l!=-1 && (F->path)[l]!='/')(F->path)[l--]='\0'; + + sprintf ( F->name, "%s", array+l+1); + l=strlen (F->name); + while (l!=-1) + { + if((F->name)[l]=='.') + { + F->name[l]='\0'; + sprintf ( F->suffix, "%s", F->name+l+1); + break; + } + else l--; + } + + return F; + } +char *filename2path (char *name) +{ + char *nname; + int x; + if (isdir (name))return name; + + x=strlen (name)-1; + nname=vcalloc (x+2, sizeof (char)); + sprintf ( nname, "%s", name); + while ( x >=0 && nname[x]!='/')nname[x--]='\0'; + + if ( !isdir (nname) || !nname[0]){vfree (nname); return NULL;} + return nname; +} + + + + + +char *extract_suffixe ( char *array) + { + int l; + char *new_string; + char *x; + l=strlen (array); + new_string=vcalloc ( l+1, sizeof (char)); + sprintf (new_string, "%s",array); + + x=new_string+l; + while (x!=new_string && x[0]!='.' && x[0]!='/' )x--; + if ( x[0]=='.')x[0]='\0'; + else if (x[0]=='/')return x+1; + + while ( x!=new_string && x[0]!='/')x--; + + return (x[0]=='/')?x+1:x; + } +void string_array_upper ( char **string, int n) + { + int a; + for ( a=0; a< n; a++)upper_string (string[a]); + } +void string_array_lower ( char **string, int n) + { + int a; + for ( a=0; a< n; a++)lower_string (string[a]); + } + +char *upper_string ( char *string) + { + int len, a; + + len=strlen ( string); + for ( a=0; a< len; a++)string[a]=toupper ( string[a]); + return string; + } +char *lower_string ( char *string) + { + int len, a; + + len=strlen ( string); + for ( a=0; a< len; a++)string[a]=tolower ( string[a]); + return string; + } +void string_array_convert ( char **array, int n_strings, int ns, char **sl) + { + int a; + + for ( a=0; a< n_strings; a++)string_convert ( array[a], ns, sl); + } +void string_convert( char *string, int ns, char **sl) + { + int a, l; + l=strlen ( string); + for ( a=0; a< l; a++) + string[a]=convert(string[a], ns, sl); + } +int convert ( char c, int ns, char **sl) + { + int a; + int return_char; + + for ( a=0; a< ns; a++) + { + if ((return_char=convert2 ( c, sl[a]))!=-1) + return return_char; + } + return c; + + + } +int convert2 ( char c, char *list) + { + int a; + int l1; + int return_char; + + l1=strlen ( list); + + return_char=(list[l1-1]=='#')?c:list[l1-1]; + + for ( a=0; a< l1; a++) + if (list[a]=='#')return return_char; + else if ( list[a]==c)return return_char; + + return -1; + } +char* substitute_old ( char *string_in, char *t, char *r) +{ + char *string_out; + char *p, *heap_in; + int delta, l; + /*REplaces every occurence of token t with token r in string_in*/ + + if ( string_in==NULL || t==NULL || r==NULL) return string_in; + + heap_in=string_in; + + l=read_array_size_new ((void*)string_in)+1; + + string_out=vcalloc (l, sizeof (char)); + delta=strlen(r)-strlen (t); + delta=(delta<0)?0:delta; + + while ( (p=strstr ( string_in, t))!=NULL) + { + + p[0]='\0'; + if ( delta) + { + l+=delta; + string_out=vrealloc(string_out, sizeof (char)*l); + } + + strcat ( string_out, string_in); + strcat ( string_out, r); + string_in=p+strlen (t); + } + strcat ( string_out, string_in); + if (l0)?(lr-lt):0; + nt=0; + while ( (p=strstr (string_in, t))!=NULL) + { + string_in=p+lt; + nt++; + } + string_in=heap_in; + + lso=nt*delta+lsi; + string_out=vcalloc (lso+1, sizeof (char)); + + while ((N==0 ||n end1)string1[a]=x; + for ( a=0; a< l2; a++)if ( a end2)string2[a]=x; + + free_int ( array, l1); + + return max_val; + } + } + +int get_string_line ( int start, int n_lines, char *in, char *out) + { + int nl=0; + int a=0; + int c=0; + + while ( nlA\nthecat\n>B\nthecat\n"); + vfclose (fp); + result=safe_system (command); + printf_system ( "rm %s.*", name); + vfree (name); + if (result) {myexit (EXIT_FAILURE);return 0;} + else return 1; + } +} + +char** merge_list ( char **argv, int *argc) + { + int a, b; + int n_in; + char **out; + char current [STRING]; + + out=declare_char (argc[0], STRING); + n_in=argc[0]; + argc[0]=0; + + a=0; + while (a< n_in && !is_parameter ( argv[a])) + { + sprintf (out[argc[0]++], "%s", argv[a]); + argv[a][0]='\0'; + a++; + } + + + for ( a=0; a< n_in; a++) + { + if ( is_parameter (argv[a])) + { + sprintf ( out[argc[0]++], "%s", argv[a]); + sprintf ( current, "%s", argv[a]); + + for ( b=0; b< n_in;) + { + if ( is_parameter (argv[b]) && strm (current, argv[b])) + { + argv[b][0]='\0'; + b++; + while ( b=MAX_N_PARAM) + { + myexit(fprintf_error ( stderr, "\nERROR: too many parameters, recompile with MAX_N_PARAM set at a higher velue [FATAL:%s]\n", PROGRAM));\ + myexit (EXIT_FAILURE); + } + + for ( a=0; a< n_in; a++) + { + + + + if (cont)ar=get_list_of_tokens( argv[a], separators,&n_ar); + else ar=get_list_of_tokens( argv[a],"",&n_ar); + + + for ( b=0; b< n_ar; b++) + { + out[argc[0]]=vcalloc( strlen (ar[b])+1, sizeof (char)); + sprintf (out[argc[0]++], "%s", ar[b]); + } + free_char (ar, -1); + ar=NULL; + if ( strstr (argv[a], "-other_pg"))cont=0; + } + free_char (ar, -1); + return out; + } + +char *invert_string2 (char *string) +{ + char *buf; + int a, b, l; + + l=strlen (string); + buf=vcalloc ( l+1, sizeof (char)); + for ( a=l-1, b=0; a>=0; a--, b++) + buf[b]=string[a]; + sprintf (string, "%s", buf); + vfree (buf); + return string; +} +char *invert_string (char *string) +{ + return string2inverted_string(string); +} +char* string2inverted_string(char *string) +{ + char *buf; + int a, b, l; + + l=strlen (string); + buf=vcalloc ( l+1, sizeof (char)); + for ( a=l-1, b=0; a>=0; a--, b++) + buf[b]=string[a]; + return buf; +} + +char ** get_list_of_tokens ( char *in_string, char *separators, int *n_tokens) +{ + char **list=NULL; + char *p=NULL; + char *string; + + + n_tokens[0]=0; + if ( in_string==NULL || strm(in_string, "")); + else if ( in_string[0]=='[') + { + list=declare_char (1, strlen ( in_string)+1); + sprintf ( list[n_tokens[0]], "%s",in_string); + n_tokens[0]++; + } + else + { + list=declare_char (strlen ( in_string)+1, 1); + string=vcalloc ( strlen(in_string)+1, sizeof (char)); + sprintf ( string, "%s", in_string); + + while ( (p=strtok ((p==NULL)?string:NULL, ((separators==NULL)?SEPARATORS:separators)))!=NULL) + { + list[n_tokens[0]]=vrealloc ( list[n_tokens[0]], sizeof (char) *strlen (p)+1); + sprintf ( list[n_tokens[0]], "%s", p); + n_tokens[0]++; + } + + vfree (string); + } + return list; + } + +char **ungap_array ( char **array, int n) + { + int a; + for ( a=0; a< n; a++)ungap(array[a]); + return array; + } + +void ungap ( char *seq) +{ + remove_charset ( seq, "ungap"); +} +int seq2len (char *seq, char *pset,char *nset) +{ + int a, l, t=0; + //count all the residues in pset and NOT in nset + if ( !seq) return 0; + + l=strlen (seq); + //returns the len of the string + for (a=0; a< l; a++) + { + char c=seq[a]; + if ( pset && nset && strchr (pset, c) && !strchr (nset, c))t++; + else if ( pset && strchr (pset, c))t++; + else if ( nset && !strchr (nset, c))t++; + } + return t; +} +int seq2res_len (char *seq) +{ + return seq2len (seq, NULL, GAP_LIST); +} +char* remove_charset_from_file (char *fname, char *set) +{ + char *tmp; + char c; + FILE *fp1; + FILE *fp2; + + fp1=vfopen (fname, "r"); + fp2=vfopen (tmp=vtmpnam (NULL), "w"); + while ( (c=fgetc(fp1))!=EOF) + { + if (!strchr ( set,c))fprintf ( fp2, "%c", c); + } + vfclose (fp1); + vfclose (fp2); + return tmp; +} + +void remove_charset ( char *seq, char *set) + { + int a, b, l; + char *set2; + + set2=vcalloc (256, sizeof (char)); + if ( strm (set, "!alnum")) + { + for ( b=0,a=1;a< 256; a++)if ( !isalnum (a))set2[b++]=a; + } + else if ( strm ( set, "ungap")) + { + sprintf ( set2, "%s", GAP_LIST); + } + else + { + sprintf ( set2, "%s", set); + } + + l=strlen ( seq); + for (b=0, a=0; a<=l; a++) + { + if ( strchr ( set2, seq[a])); + else seq[b++]=seq[a]; + } + seq[b]='\0'; + vfree (set2); + } + + +char **char_array2number ( char ** array, int n) + { + int a; + for ( a=0; a< n; a++)array[a]=char2number(array[a]); + return array; + } +char *char2number ( char * array) + { + int a, l; + + + l=strlen ( array); + for ( a=0; a< l; a++) + { + if ( isdigit(array[a]) && array[a]!=NO_COLOR_RESIDUE && array[a]!=NO_COLOR_GAP )array[a]-='0'; + else if ( array[a]<9); + else if ( array[a]==NO_COLOR_RESIDUE || array[a]==NO_COLOR_GAP)array[a]=NO_COLOR_RESIDUE; + } + return array; + } +long atop (char*p) +{ + /*turns a char into a pointer*/ + if ( p==NULL) return 0; + else return atol(p); +} + +char *mark_internal_gaps(char *seq, char symbol) +{ + int l, a, gap; + int in_seq; + char *cache_seq; + + l=strlen(seq); + cache_seq=vcalloc ( l+1, sizeof (char)); + sprintf ( cache_seq, "%s", seq); + + for ( gap=0, in_seq=0,a=0; a< l; a++) + { + gap=is_gap(seq[a]); + if ( !gap && !in_seq)in_seq=1; + if (gap && in_seq)seq[a]=symbol; + } + + for (gap=0, in_seq=0,a=l-1; a>=0; a--) + { + gap=is_gap(seq[a]); + if ( !gap && !in_seq)break; + if (gap && !in_seq)seq[a]=cache_seq[a]; + } + vfree(cache_seq); + return seq; +} + +void splice_out ( char *seq, char x) + + { + int a, b, l; + + l=strlen ( seq); + for (b=0, a=0; a<=l; a++) + if ( seq[a]==x); + else seq[b++]=seq[a]; + seq[b]='\0'; + } +char *splice_out_seg ( char *seq, int pos, int len) +{ + int l, a; + + if (seq==NULL || pos<0) return seq; + l=strlen (seq); + if ( l<(pos+len)) + printf_exit ( EXIT_FAILURE, stderr, "Splice_out_seg out of bound: Length %d seg: [%d %d] [splice_out_seg::util.c][FATAL:%s]\n", l, pos, pos+len, PROGRAM); + l-=len; + for (a=pos; a< l; a++) + seq[a]=seq[a+len]; + seq[a]='\0'; + return seq; +} + +int isblanc ( char *buf) + { + int a, l; + + if ( buf==NULL)return 0; + l=strlen (buf); + for ( a=0; a< l; a++) + if (isalnum (buf[a]))return 0; + return 1; + } + + + +int is_number ( char *num) + { + int a, l; + l=strlen (num); + + for (a=0;amax_len) + { + max_len=l; + max_index=a; + } + } + if (index!=NULL)index[0]=max_index; + if (len!=NULL)len[0]=max_len; + } + + return max_len; + } + +int get_shortest_string (char **array,int n, int *len, int *index) + { + int a, l; + int min_len; + + if ( n==0|| array==NULL || read_size_char ( array,sizeof (char*))tms_stime*milli_sec_conv; + tms_utime=(long)time_buf->tms_utime*milli_sec_conv; + + + + + if ( ref==0) + { + ref=(tms_stime+tms_utime); + return 0; + } + else + { + time=(tms_utime+tms_stime)-ref; + return (int) ((time)/ticks); + } + } +int get_ctime () + { + static long time; + struct tms time_buf[1]; + long tms_cutime, tms_cstime; + + if ( ticks==0)ticks = sysconf(_SC_CLK_TCK); + times ( time_buf); + + + + tms_cstime=(long)time_buf->tms_cstime*milli_sec_conv; + tms_cutime=(long)time_buf->tms_cutime*milli_sec_conv; + + if ( ref==0) + { + child=1; + ref=tms_cstime+tms_cutime; + return 0; + } + else + { + time=(tms_cutime+tms_cstime)-ref; + return (int)((time)/ticks); + } + } +int reset_time() + { + ref=0; + return (int)get_time(); + } +int increase_ref_time(int increase) + { + if ( ref==0)get_time(); + + ref-=(long)ticks*(long)increase; + if (ref==0)ref++; + return (int)ref; + } + +/*********************************************************************/ +/* */ +/* SYSTEM CALLS */ +/* */ +/* */ +/*********************************************************************/ +int evaluate_sys_call_io ( char *out_file, char *com, char *fonc) + { + if ( file_exists (NULL,out_file))return 1; + else + { + add_warning (stderr, "COMMAND FAILED: %s",com); + return 0; + } + } +void HERE (char *string, ...) +{ + va_list ap; + + va_start (ap, string); + fprintf ( stderr, "HERE: "); + vfprintf (stderr, string, ap); + fprintf ( stderr, "\n"); + va_end (ap); + +} + + +int fprintf_fork (FILE *fp, char *string, ...) +{ + static char *openF; + static char *closeF; + + + FILE *flag; + + + + char *buf; + + if (!openF) + { + openF=vcalloc (100, sizeof (char)); + sprintf (openF, "cedric1"); + closeF=vcalloc (100, sizeof (char)); + sprintf (closeF, "cedric2"); + + //openF =vtmpnam (NULL); + //closeF=vtmpnam (NULL); + vfclose(vfopen (openF,"w")); + } + while ((rename (openF,closeF))==-1); + + cvsprintf (buf,string); + fprintf ( fp, "%s", buf); + fflush (fp); + rename (closeF, openF); + vfree (buf); + return 0; +} +int fprintf_fork2 (FILE *fp, char *string, ...) +{ + + + + char* buf; + + cvsprintf (buf, string); + fprintf ( fp, "%s", buf); + vfree (buf); + fflush (fp); + return 0; +} + +int printf_file (char *file,char *mode, char *string,...) +{ + FILE *fp; + va_list ap; + + if (!(fp=vfopen (file, mode)))return 0; + va_start (ap, string); + vfprintf (fp, string, ap); + va_end (ap); + vfclose (fp); + return 1; + } +int printf_system_direct (char *string, ...) +{ + char *buf; + int r; + + cvsprintf (buf, string); + + + r=system (buf); + vfree(buf); + return r; +} + +int printf_system (char *string, ...) +{ + char *buf; + int r; + + cvsprintf (buf, string); + r=my_system (buf); + vfree(buf); + return r; +} + +int my_system_cl (int argc, char *argv[]) +{ + int a,l; + char *command; + + for ( a=0, l=0; a< argc; a++)l+=(strlen(argv[a])+2); + command=vcalloc (l+1, sizeof(char)); + for ( a=0; a< argc; a++) + { + command=strcat (command, argv[a]); + command=strcat (command, " "); + } + a=my_system ( command); + vfree (command); + return a; +} + +int my_system ( char *command0) +{ + static char ***unpacked_list; + static int n_unpacked; + + if (!unpacked_list) + { + unpacked_list=declare_arrayN(3, sizeof (char), 3, 200,300); + } + + if ( getenv ("DEBUG_PERL"))return safe_system (command0); + else + { + char **list; + int is_command; + int a, c=0; + char *command1; + char *command2; + int return_val; + + command1=vcalloc ( 3*strlen (command0)+1, sizeof (char)); + command2=vcalloc ( 100000, sizeof (char)); + sprintf ( command1, "%s", command0); + + command1=substitute (command1, "|", " | "); + command1=substitute (command1, ";", " ; "); + + list=string2list (command1); + + if ( !list) return EXIT_SUCCESS; + is_command=1; + + //Identify T-Coffee self threads and install threads + + for ( a=1; a< atoi(list[0]); a++) + { + if ( is_command) + { + if ( strstr ( list[a], "unpack_")) + { + unpack_all_perl_script (list[a]+strlen ("unpack_")); + myexit (EXIT_SUCCESS); + } + else if ((c=name_is_in_list (list[a], unpacked_list[0], n_unpacked, 100))!=-1); + else + { + + n_unpacked=unpack_perl_script (list[a], unpacked_list, n_unpacked);c=n_unpacked-1; + + } + //if non unpacked script check pg is installed: + + if ( strm (unpacked_list[2][c], "shell")) + { + check_program_is_installed (list[a], NULL, NULL, NULL, INSTALL_OR_DIE); + } + strcat (command2, ((c!=-1)?unpacked_list[1][c]:list[a])); + strcat (command2, " "); + is_command=0; + + } + else + { + strcat (command2, list[a]); + strcat (command2, " "); + if ( strm (list[a], ",") ||strm (list[a], "|")) is_command=1; + } + } + + free_char (list,-1); + vfree ( command1); + command2=substitute ( command2, "//", "/"); + + return_val=safe_system (command2); + + vfree ( command2); + return return_val; + } +} +int has_warning_lock() +{ + if (lock(getpid(), LWARNING, LCHECK,NULL))return 1; + else return 0; +} +int has_error_lock() +{ + if (lock(getpid(), LERROR, LCHECK,NULL))return 1; + else return 0; +} +int is_shellpid(int pid) +{ + if ( lock(pid, LLOCK, LCHECK, NULL) && strstr (lock(pid,LLOCK, LREAD, NULL), "-SHELL-"))return 1; + else return 0; +} +int is_rootpid() +{ + + if (debug_lock) + { + char *f; + fprintf ( stderr,"\n\t------ check if %d isrootpid (util): %s->%d", getpid(),f=lock2name (getppid(),LLOCK), (lock(getppid(), LLOCK, LCHECK, NULL))?1:0); + vfree (f); + } + + + if(lock (getppid(), LLOCK, LCHECK, NULL)!=NULL)return 0; + else return 1; +} + +int shift_lock ( int from, int to, int from_type,int to_type, int action) +{ + //action: SET (concatenate) or RESET (replace parent with child content) + char *e; + if (!lock (from,from_type, LCHECK, NULL))return 0; + e=lock (from,from_type, LREAD, NULL); + lock (from,from_type, LRELEASE, NULL); + + if ( action==LSET || action==LRESET)lock (to, to_type,action, e); + else + { + myexit(fprintf_error (stderr, "Unsupported type for shift_lock")); + } + vfree (e); + return 1; +} + +char*lock2name (int pid, int type) +{ + char *fname; + char host[1024]; + gethostname(host, 1023); + + fname=vcalloc (strlen(host)+strlen (get_lockdir_4_tcoffee())+1000, sizeof (char)); + if (type == LLOCK)sprintf (fname, "%s/.%d.%s.lock4tcoffee",get_lockdir_4_tcoffee(), pid,host); + else if ( type == LERROR) sprintf (fname, "%s/.%d.%s.error4tcoffee", get_lockdir_4_tcoffee(),pid,host); + else if ( type == LWARNING) sprintf (fname, "%s/.%d.%s.warning4tcoffee",get_lockdir_4_tcoffee(),pid,host); + else myexit(fprintf_error ( stderr, "ERROR: Unknown type for lock")); + return fname; +} + +int release_all_locks (int pid) +{ + lock (pid, LLOCK, LRELEASE, NULL); + lock (pid, LERROR, LRELEASE, NULL); + lock (pid, LWARNING, LRELEASE, NULL); + return 1; +} +char* lock(int pid,int type, int action,char *string, ...) +{ + char *fname; + char *r; + + + + fname=lock2name (pid, type); + + if (debug_lock) + { + fprintf (stderr,"\n\t\t---loc4tc(util.h) %d =>%s [RD: %s]\n", action, fname, getcwd(NULL, 0)); + } + + if (action == LREAD) + { + r=file2string (fname); + } + else if ( action == LCHECK) + { + r=(file_exists (NULL,fname))?"x":NULL; + } + else if (action== LRELEASE) + { + + if (debug_lock) + { + printf_system_direct ("mv %s %s.released", fname, fname); + } + else if (file_exists (NULL, fname)) + { + vremove (fname); + //safe_remove (fname);return NULL; + } + r=" "; + } + else if ( clean_exit_started) return NULL; //NO MORE LOCK SETTING during EXIT Phase + else if (action== LSET || action == LRESET) + { + char *value; + + if (string) + { + cvsprintf (value,string); + } + else + { + value=vcalloc (2, sizeof(char)); + sprintf (value, " "); + } + string2file (fname, (action==LSET)?"a":"w", value); + vfree (value); + r= " "; + + } + else myexit(fprintf_error ( stderr, "ERROR: Unknown action for LOCK")); + vfree (fname); + return r; + +} +int check_process (const char *com,int pid,int r, int failure_handling) +{ + + //If the child process has an error lock, copy that lock into the parent'lock + //The error stack trace of the child gets passed to the parent + if (debug_lock)fprintf (stderr, "\nEVAL_CALL ----- %d ->%s\n",pid, (r==EXIT_FAILURE)?"FAIL":"SUCCESS"); + + if ( failure_handling == IGNORE_FAILURE) return r; + if ( lock(pid, LWARNING, LCHECK, NULL)) + { + shift_lock (pid, getpid(), LWARNING, LWARNING,LSET); + } + + + if ( lock(pid, LERROR, LCHECK, NULL)) + { + shift_lock (pid, getpid(), LERROR,LERROR, LSET); + } + else if (r==EXIT_FAILURE) + { + //Reconstruct missing errorlock + lock (getpid(), LERROR,LSET,"%d -- ERROR: UNSPECIFIED UNSPECIFIED\n",pid); + lock (getpid(), LERROR,LSET,"%d -- COM: %s\n",pid,com); + lock (getpid(), LERROR, LSET,"%d -- STACK: %d -> %d\n",pid,getpid(), pid); + } + //lock is now ready. Shall we use it? + + if (lock(getpid(), LERROR, LCHECK, NULL)) + { + if (failure_handling==RETURN_ON_FAILURE) + { + shift_lock(getpid(),getpid(),LERROR, LWARNING,LSET); + } + else + { + myexit (EXIT_FAILURE); + } + } + return r; +} + + +int safe_system (const char * com_in) +{ + pid_t pid; + int status; + + int failure_handling; + char *p; + char command[1000]; + + static char *com; + + if ( clean_exit_started) return system (com_in); + if ( com)vfree (com); + if ( strstr ( com_in, "SCRATCH_FILE")) + { + com=vcalloc ( strlen ( com_in)+1, sizeof (char)); + sprintf ( com, "%s", com_in); + while (strstr ( com, "SCRATCH_FILE")) + { + char *t; + t=vtmpnam(NULL); + com=vrealloc (com, (strlen (com)+strlen (t)+1)*sizeof (char)); + + + com=substitute (com,"SCRATCH_FILE", t); + } + } + else + { + com=vcalloc (strlen (com_in)+1, sizeof (char)); + sprintf ( com, "%s", com_in); + } + + + if (com == NULL) + return (1); + else if ( (p=strstr (com, "::IGNORE_FAILURE::"))) + { + p[0]='\0'; + failure_handling=IGNORE_FAILURE; + } + else if ( (p=strstr (com, "::RETURN_ON_FAILURE::"))) + { + p[0]='\0'; + failure_handling=RETURN_ON_FAILURE; + } + else + { + failure_handling=EXIT_ON_FAILURE; + } + + + sprintf ( command, " -SHELL-%s (tc)", com_in); + if ((pid = vvfork (command)) < 0) + return (-1); + + if (pid == 0) + { + char * argv [4]; + + argv [0] = "sh"; + + + argv [1] = "-c"; + argv [2] =(char*) com; + argv [3] = 0; + + if ( debug_lock)fprintf (stderr,"\n--- safe_system (util.h): %s (%d)\n", com, getpid()); + execvp ("/bin/sh", argv); + } + else + { + set_pid(pid); + } + + + while (1) + { + int r; + r=vwaitpid (pid, &status, 0); + + + if (errno ==EINTR)r=EXIT_SUCCESS; + else if (r==-1 || status != EXIT_SUCCESS)r=EXIT_FAILURE; + else r=EXIT_SUCCESS; + if ( debug_lock) + fprintf ( stderr, "\n--- safe system return (util.c): p:%d c:%d r:%d (wait for %d", getppid(), getpid(), r, pid); + return check_process (com_in,pid,r, failure_handling); + } +} + + + + + +static int **pidtable; +int assert_pid (pid_t p) +{ + if ( p>= MAX_N_PID || p<0) + { + printf_exit (EXIT_FAILURE, stderr, "MAX_N_PID exceded -- Recompile changing the value of MAX_N_PID (current: %d Requested: %d)", MAX_N_PID, p); + } + return 1; +} +pid_t **declare_pidtable () +{ + int a; + + pidtable=vcalloc (MAX_N_PID, sizeof (pid_t*)); + for (a=0; a0) + { + vwait (NULL); + sub--; + } + } + else if ( sub>=max) + { + while (sub>=min) + { + vwait (NULL); + sub--; + } + } + else{;} + return sub; +} + + +pid_t vwaitpid (pid_t p, int *status, int options) +{ + + + p=waitpid (p, status, options); + + if (pidtable) + { + assert_pid (p); + pidtable[(int)p][0]=pidtable[(int)p][1]=0; + } + return p; +} +pid_t vwait (pid_t *p) +{ + pid_t p2; + int rv=0; + int handle_failure; + + if (atoigetenv("RETURN_ON_FAILURE"))handle_failure=RETURN_ON_FAILURE; + else handle_failure=EXIT_ON_FAILURE; + + + p2=wait (&rv); + if (p2!=-1)rv=check_process("forked::T-Coffee", p2, rv,handle_failure); + if ( p) p[0]=rv; + + return p2; +} + + +int get_child_list (int pid,int *clist); +int kill_child_list (int *list); +int kill_child_pid(int pid) +{ + int *list; + int n,a, cpid; + + cpid=getpid(); + list=vcalloc (MAX_N_PID, sizeof (int)); + + while ((n=get_child_list (pid,list))) + { + kill_child_list (list); + } + + for (a=0; a1) + { + add_information ( stderr, "Corrupted Lock System" ); + for (a=0; a%s", tmp); + sprintf ( string, "%s", file2string (tmp)); + chomp (string); + nproc=atoi (string); + } + else + nproc=1; + + return nproc; +} + + + + + +char * get_os() +{ + static char os[100]; + char *file; + + if ( os[0])return os; + else + { + char *s; + + file=tmpnam (NULL); + printf_system_direct ("uname > %s", file); + + s=file2string (file); + lower_string (s); + + if (strstr (s, "cygwin"))sprintf ( os, "windows"); + else if ( strstr (s, "linux"))sprintf ( os, "linux"); + else if ( strstr (s, "osx"))sprintf ( os, "macosx"); + else if ( strstr (s, "darwin"))sprintf ( os, "macosx"); + else sprintf (os, "linux"); + vfree (s); + vremove (file); + } + return os; +} + + + + + +int cputenv (char *string, ...) +{ + + + + + + char *s; + char *s2; + int r; + + + if (!string)return 0; + + cvsprintf (s, string); + + s2=vcalloc (strlen (s)+1, sizeof (char)); + sprintf ( s2, "%s", s); + + r=putenv (s2); + //vfree (s); //Potential leak + return r; +} + + +int fcputenv (char *file, char *mode,char * string, ...) +{ + va_list ap; + FILE *fp; + if (!string)return 0; + + if (!(fp=vfopen (file, mode)))return 0; + + va_start (ap, string); + vfprintf (fp, string, ap); + vfclose (fp); + va_end (ap); + return 1; +} +int isdir4path (char *p) +{ + if ( !p) return 0; + if ( !p || access (p, F_OK)==-1 || access (p, W_OK)==-1 || access(p, R_OK)==-1 || access (p, X_OK)==-1)return 0; + + return 1; +} +int check_dir_getenv ( char *string) +{ + char *p; + return (isdir4path(p=getenv ( string))); + +} + + + + +int set_unique_dir_4_tcoffee (char *dir); +int set_unique_dir_4_tcoffee (char *dir) +{ + static char **string; + int m, n; + m=n=0; + if ( !dir || !isdir(dir) || strm (dir, "no"))return 0; + string=declare_char (10, 100); + sprintf ( string[m++], "DIR_4_TCOFFEE=%s", dir);putenv (string[n++]); + sprintf ( string[m++], "CACHE_4_TCOFFEE=%s", dir);putenv (string[n++]); + sprintf ( string[m++], "TMP_4_TCOFFEE=%s", dir);putenv (string[n++]); + sprintf ( string[m++], "PLUGINS_4_TCOFFEE=%s", dir);putenv (string[n++]); + sprintf ( string[m++], "MCOFFEE_4_TCOFFEE=%s", dir);putenv (string[n++]); + sprintf ( string[m++], "METHODS_4_TCOFFEE=%s", dir);putenv (string[n++]); + + return 1; +} + + + + + +void myexit (int signal) +{ + + if (clean_exit_started==1)return; //protects processes while they are doing a clean exit + global_exit_signal=signal; + exit (global_exit_signal); //ONLY BARE EXIT!!!!!!!!!!!!!! +} + + +static int n_warning; +static char **warning_list; + +FILE *fatal_exit (FILE *fp,int exit_mode, char *string, ...) +{ + va_list ap; + va_start (ap, string); + vfprintf (fp, string, ap); + va_end (ap); + myexit (exit_mode); + return fp; +} +static int warning_mode; +int set_warning_mode ( int mode) +{ + warning_mode=mode; + return mode; +} + +int fprintf_error( FILE *fp, char *string, ...) +{ + char *msg; + + cvsprintf (msg, string); + msg=substitute ( msg, "\n", ""); + msg=substitute ( msg, "ERROR", " "); + if (fp)fprintf ( fp, "\n--ERROR: %s\n", msg); + if ( clean_exit_started) return EXIT_FAILURE; + + lock (getpid(), LERROR,LSET,"%d -- ERROR: %s\n",getpid(),msg); + lock (getpid(), LERROR,LSET,"%d -- COM: %s\n",getpid(),in_cl); + lock (getpid(), LERROR, LSET,"%d -- STACK: %d -> %d\n",getpid(), getppid(),getpid()); + + vfree (msg); + return EXIT_FAILURE; +} +void printf_exit (int exit_code, FILE *fp, char *string, ...) +{ + char *msg; + + cvsprintf (msg, string); + myexit(fprintf_error (fp,msg)); + myexit (exit_code); +} + + +FILE *add_warning (FILE *fp, char *string, ...) +{ + char *buf; + + if ( warning_mode==NO || getenv("NO_WARNING_4_TCOFFEE"))return fp; + else + { + + cvsprintf (buf, string); + if (fp)fprintf (fp, "\npid %d -- %s\n",getpid(), buf); + if ( clean_exit_started)return fp; + + + lock(getpid(),LWARNING, LSET, "%d -- WARNING: %s\n", getpid(),buf); + vfree (buf); + } + return fp; +} +FILE *add_information (FILE *fp, char *string, ...) +{ + char *buf; + + if ( warning_mode==NO || getenv("NO_INFORMATION_4_TCOFFEE"))return fp; + else + { + + cvsprintf (buf, string); + if (fp)fprintf (fp, "\npid %d -- %s\n",getpid(), buf); + if ( clean_exit_started)return fp; + + + lock(getpid(),LWARNING, LSET, "%d -- INFORMATION: %s\n", getpid(),buf); + vfree (buf); + } + return fp; +} + + + +int count_n_res_in_array (char *array, int len) + { + return count_n_symbol_in_array(array, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", len); + } +int count_n_gap_in_array (char *array, int len) + { + int l; + if ( len<=0 ||len>strlen(array) )l=strlen(array); + else l=len; + + return l- count_n_res_in_array (array,len); + } +int count_n_symbol_in_array ( char *array, char *array_list, int len) + { + int a=0, t=0; + int l; + + if ( len<=0 ||len>strlen(array) )l=strlen(array); + else l=len; + + for ( a=0; a< l; a++)t+=is_in_set (array[a], array_list); + return t; + } + +char* count_strings_in_file ( char *in, char *out) +{ + FILE *fp; + int n,c; + char **list, **result; + + + if (!out) out=vtmpnam (NULL); + list=declare_char (count_n_line_in_file(in)+1, measure_longest_line_in_file (in)+1); + + n=0; + fp=vfopen (in, "r"); + while ((c=fgetc (fp))!=EOF) + { + ungetc (c, fp); + fscanf (fp, "%s\n",list[n]); + n++; + } + vfclose (fp); + + result=count_strings (list, n); + + + n=0; + fp=vfopen (out, "w"); + while (result[n])fprintf ( fp,"%s\n", result[n++]); + vfclose (fp); + + free_char (list, -1); + free_char (result, -1); + + return out; +} + +int ** count_int_strings (int **array, int len, int s) +{ + int **result; + int a,n; + + sort_list_int (array,s, s,0, len-1); + result=vcalloc (len, sizeof (int*)); + for (n=-1,a=0; a:$PATH\n"); + fprintf ( fp, "* Make this permanent by adding this line to the file\n"); + fprintf ( fp, "* ~/.bashrc\n"); + fprintf ( fp, "* If this package is not installed but supported you can try to install it via t_coffee:\n"); + fprintf ( fp, "* t_coffee -other_pg install \n"); + fprintf ( fp, "* Otherwise you must install it yourself\n"); + fprintf ( fp, "*************************************************************************************************\n"); + + return fp; +} +FILE* proxy_msg(FILE*fp) + { + fprintf ( fp, "\n\n"); + fprintf ( fp, "*************************************************************************************************\n"); + fprintf ( fp, "* CONFIGURATION: Faulty Network OR Missing Proxy \n"); + fprintf ( fp, "* \n"); + fprintf ( fp, "* \n"); + fprintf ( fp, "* It looks like you cannot access the network\n"); + fprintf ( fp, "* Check that your network is up and running...\n"); + fprintf ( fp, "* If you are behind a firewall, you must enter your proxy address to use webservices\n"); + fprintf ( fp, "* This address is usualy something like: http://some.place.here:8080\n"); + fprintf ( fp, "* Todo this via the command line:\n"); + fprintf ( fp, "* \n"); + fprintf ( fp, "* -proxy= \n"); + fprintf ( fp, "* \n"); + fprintf ( fp, "*To make it permanent:\n"); + fprintf ( fp, "* export PROXY_4_TCOFFEE=\n"); + fprintf ( fp, "*Add this line to either:\n"); + fprintf ( fp, "* /.bashrc\n"); + fprintf ( fp, "* OR %s/.t_coffee_env\n", get_dir_4_tcoffee()); + fprintf ( fp, "*************************************************************************************************\n"); + + return fp; +} +FILE* email_msg(FILE*fp) +{ + fprintf ( fp, "\n\n"); + fprintf ( fp, "*************************************************************************************************\n"); + fprintf ( fp, "* CONFIGURATION: Missing Email \n"); + fprintf ( fp, "* \n"); + + fprintf ( fp, "* This mode of T-Coffee uses the EBI BLAST webservices. The EBI requires a valid E-mail \n"); + fprintf ( fp, "* address for this service to be used (check: www.ebi.ac.uk/Tools/webservices/). \n"); + + fprintf ( fp, "* \n"); + fprintf ( fp, "* To provide the email, add to the command line:*\n"); + fprintf ( fp, "* \n"); + fprintf ( fp, "* -email= *\n"); + fprintf ( fp, "*To make it permanent:\n"); + fprintf ( fp, "* export EMAIL_4_TCOFFEE=\n"); + fprintf ( fp, "*Add this line to either:\n"); + fprintf ( fp, "* ~/.bashrc\n"); + fprintf ( fp, "* OR %s/.t_coffee_env\n", get_dir_4_tcoffee()); + fprintf ( fp, "*************************************************************************************************\n"); + + return fp; +} + +void update_error_dir() +{ + + + ; + + + +} +void dump_tcoffee(char *target, char *nature) +{ + char **list, *s; + int a=0; + FILE *fp; + char *f; + char *out_list; + + if ((fp=fopen (target, "w"))) + { + fprintf (fp, "\n%s\n", nature); + fprintf (fp, "%s\n", PROGRAM); + fprintf (fp, "%s\n",VERSION); + if ((f=strstr (in_cl, "-dump")))f[0]='\0'; + fprintf (fp, "%s\n",in_cl); + fprintf (fp, "\n"); + stack_msg(fp); + fprintf (fp, "\n\n"); + warning_msg (fp); + fprintf (fp, "\n"); + + //dump input + list=string2list (in_cl); + out_list=file2string (get_string_variable ("dump_output_file_list")); + + for (a=1; a\ninput\n"); + fprintf (fp, "%s\n",s); + fprintf (fp, "\n"); + while ((c=fgetc(fp2))!=EOF)fprintf ( fp, "%c", c); + fclose (fp2); + fprintf (fp, "\n\n"); + } + } + //dump output + if ((f=get_string_variable ("dump_output_file"))) + { + FILE *fp2; + char c; + + if ((fp2=fopen (f, "r"))!=NULL) + { + while ((c=fgetc (fp2))!=EOF)fprintf (fp, "%c",c); + fclose (fp2); + } + + } + + fprintf (fp, "\n"); + fclose (fp); + printf_system_direct("printenv >> %s", target); + fp=fopen (target, "a"); + fprintf (fp, "\n"); + fclose (fp); + + fprintf ( stderr, "\n#----- Dumped File: %s\n",target); + } + else fprintf ( stderr, "\n#----- Could NOT Produce Dump File: %s -- Sorry \n", target); + + +} +void dump_error_file() +{ + char target[1000]; + + + + char **list, *s; + int a=0; + FILE *fp; + + + sprintf ( target, "%s",getenv("ERRORFILE_4_TCOFFEE")); + dump_tcoffee (target, "error"); + return; + + if ((fp=fopen (target, "w"))) + { + + fprintf ( fp, "\n######### RUN_REPORT START ######"); + fprintf ( fp, "\n######### PROGRAM_VERSION START ######"); + fprintf ( fp, "\n %s, %s", PROGRAM, VERSION); + fprintf ( fp, "\n######### PROGRAM_VERSION END ######"); + + fprintf ( fp, "\n######### COMMAND_LINE START ######"); + fprintf ( fp, "\n%s", in_cl); + fprintf ( fp, "\n######### COMMAND_LINE END ######\n"); + fprintf ( fp, "\n######### MESSAGES START ######\n"); + + stack_msg(fp); + warning_msg (fp); + + fprintf ( fp, "\n######### MESSAGES END ######\n"); + fprintf ( fp, "\n######### FILES START ######\n"); + + list=string2list (in_cl); + for (a=1; a> %s", target); + + fprintf ( stderr, "\n#----- Dumped ErrorFile: %s\n",target); + } + else fprintf ( stderr, "\n#----- Could NOT Dumpe ErrorFile: %s -- Sorry \n", target); + +} + + + +FILE* error_msg(FILE*fp ) + { + if ( no_error_report)return fp; + + fprintf( fp,"\n\t******************************************************************"); + fprintf( fp, "\n\t* Abnormal Termination"); + fprintf( fp, "\n\t* Job NOT Completed:[%s, %s]",PROGRAM, VERSION); + fprintf( fp, "\n\t* Please CHECK: "); + fprintf( fp, "\n\t* \t-1 The format of your Input Files "); + fprintf( fp, "\n\t* \t-2 The parameters "); + fprintf( fp, "\n\t* \t-3 The use of special characters in sequence names:"); + fprintf( fp, "\n\t* \t\t (@, |, %%...)"); + + fprintf( fp, "\n\t* \t-4 The Online Doc (%s) ", URL); + fprintf( fp, "\n\t* \t-5 Send the file:"); + fprintf (fp, "\n\t*"); + fprintf (fp, "\n\t*\t %s ", getenv("ERRORFILE_4_TCOFFEE")); + fprintf (fp, "\n\t* to:"); + fprintf( fp, "\n\t* \t\t%s",EMAIL); + + fprintf( fp, "\n\t* If you run T-Coffee over the WEB:"); + fprintf( fp, "\n\t* \tWindows Cut and Paste is sometimes erratic and"); + fprintf( fp, "\n\t* \tit can loose carriage returns. If you suspect this,"); + fprintf( fp, "\n\t* \ttry to cut and paste through an intermediate application"); + fprintf( fp, "\n\t* \t(word pad) and inspect the results\n\n"); + fprintf( fp, "\n\t* CONFIDENTIALITY:"); + fprintf( fp, "\n\t* \tThe File %s may contain your personnal DATA", getenv("ERRORFILE_4_TCOFFEE")); + fprintf( fp, "\n\t* \tRemove ALL confidential DATA from this file BEFORE sending it"); + fprintf( fp, "\n\t******************************************************************\n"); + print_command_line(fp); + return fp; + } + + +char *get_email_from_env () +{ + char *email=NULL; + if ( (email=get_string_variable ("cl_email"))); + else if ( (email=get_string_variable ("email"))); + else if ( (email=getenv ("EMAIL_4_TCOFFEE"))); + else if ( (email=getenv ("EMAIL"))); + else email=vcalloc ( 1, sizeof (char)); + return email; +} + +int set_email (char *email) +{ + if (!email) return 0; + + cputenv ("EMAIL_4_TCOFFEE=%s", email); + cputenv ("EMAIL=%s",email); + + return 1; +} +char *chomp (char *name) +{ + int a=0; + while ( name[a]!='\n' && name[a]!='\0')a++; + name[a]='\0'; + return name; +} +static Tmpname *tmpname; +static Tmpname *ntmpname; + +static int n_tmpname; +static int file2remove_flag; + +char *set_file2remove_extension (char *extension, int mode) +{ + static char ext[100]; + if (mode==SET)sprintf (ext, "%s", extension); + else if ( mode==UNSET) ext[0]='\0'; + else if ( mode==GET); + return ext; +} +int flag_file2remove_is_on () +{ + return file2remove_flag; +} +void set_file2remove_on() +{ + file2remove_flag=1; +} +void set_file2remove_off() +{ + file2remove_flag=0; +} + +char *add2file2remove_list (char *name) +{ + + + if ( !tmpname || !name)ntmpname=tmpname=vcalloc ( 1, sizeof (Tmpname)); + else if (!ntmpname->name); + else ntmpname=ntmpname->next=vcalloc ( 1, sizeof (Tmpname)); + + if (!name) return NULL; + + ntmpname->name=vcalloc(strlen(name)+1, sizeof (char)); + + sprintf (ntmpname->name, "%s", name); + return ntmpname->name; +} +//char *short_tmpnam_2(char *s);//used to generate very compact tmp names +void initiate_vtmpnam (char *file) +{ + add2file2remove_list (NULL); + tmpnam_2(NULL); +} +char *vtmpnam ( char *s1) +{ + char *s,*s2; + + n_tmpname++; + + standard_initialisation(NULL, NULL); + + s=vcalloc ( VERY_LONG_STRING, sizeof (char)); + s[0]='\0'; + + s=tmpnam_2 (s); + + s2=add2file2remove_list (s); + if (s!=s2)vfree (s); + if (s1){sprintf (s1, "%s",s2);return s1;} + else return s2; +} + + + +int get_vtmpnam2_root() +{ + int MAX_TMPNAM_ROOT=10000; + static int v; + + if (v) ; + else + { + vsrand(0); + v=rand()%MAX_TMPNAM_ROOT; + } + return v; +} +char *tmpnam_2 (char *s) +{ + static int root; + static int file; + char buf[VERY_LONG_STRING]; + static char root2[VERY_LONG_STRING]; + static char *tmpdir; + static int name_size; + + if ( !root || !s) + { + char *vtmpnam_prefixe; + + name_size=MAX( 2*L_tmpnam, MAXNAMES*2)+1; + root=get_vtmpnam2_root(); + sprintf ( root2, "%d%d_", root, (int)getpid()); + + vtmpnam_prefixe=vcalloc (strlen (root2)+strlen (get_tmp_4_tcoffee())+2, sizeof (char)); + sprintf (vtmpnam_prefixe, "%s/%s", get_tmp_4_tcoffee(), root2); + set_string_variable ("vtmpnam_prefixe1", vtmpnam_prefixe); + set_string_variable ("vtmpnam_prefixe2", root2); + vfree (vtmpnam_prefixe); + } + + if (!s)return NULL; + tmpdir=get_tmp_4_tcoffee(); + + sprintf (buf, "%s/%s%d_TCtmp%s",tmpdir,root2, file++,set_file2remove_extension (NULL, GET)); + if ( strlen(buf)>=name_size)s=vrealloc (s,(strlen(buf)+1)*sizeof (char)); + sprintf (s, "%s", buf); + return s; +} +char *short_tmpnam_2(char *s) +{ + static int root; + static int file; + char buf[VERY_LONG_STRING]; + static char root2[VERY_LONG_STRING]; + + static int name_size; + + if ( !root || !s) + { + char *vtmpnam_prefixe; + + name_size=MAX( 2*L_tmpnam, MAXNAMES*2)+1; + root=get_vtmpnam2_root(); + sprintf ( root2, "%d%d", root,getpid()); + + vtmpnam_prefixe=vcalloc (strlen (root2)+strlen (get_tmp_4_tcoffee())+2, sizeof (char)); + sprintf (vtmpnam_prefixe, "%s", root2); + set_string_variable ("vtmpnam_prefixe1", vtmpnam_prefixe); + set_string_variable ("vtmpnam_prefixe2", root2); + vfree (vtmpnam_prefixe); + } + if (!s) return NULL; + + sprintf (buf, "%s%d%s",root2, file++,set_file2remove_extension (NULL, GET)); + if ( strlen(buf)>=name_size)s=vrealloc (s,(strlen(buf)+1)*sizeof (char)); + sprintf (s, "%s", buf); + return s; +} + +char *vremove2 (char *s) +{ + char list_file[1000]; + char ***list; + int a; + + + //Remove filenames with a wildcard + + sprintf (list_file, "list_file_%d", (int)getpid()); + printf_system_direct("ls -1 %s>%s 2>/dev/null", s, list_file); + list=file2list (list_file, " "); + + a=0; + while (list && list[a]) + { + if ( file_exists (NULL,list[a][1])) + { + vremove (list[a][1]); + } + a++; + } + vremove (list_file); + return NULL; +} +void safe_remove (char *s)//remove even if the file is partly unaccessible +{ + FILE *fp; + + + if ( !s) return; + else if (!(fp=fopen (s, "w")))return; + else + { + fclose (fp); + remove (s); + } +} + +char *vremove (char *s) +{ + + + if ( s && strstr (s, "*"))return vremove2(s); + else if ( !s || !file_exists(NULL,s) ) return NULL; + else if ( isdir (s)) + { + rmdir (s); + return NULL; + } + else + { + remove (s); + return NULL; + } + return NULL; +} +int log_function ( char *fname) +{ + + + if ( file_exists (NULL,error_file)) + { + + printf_system_direct ("cp %s %s", error_file, fname); + + fprintf( stderr,"\n\t******************************************************************"); + fprintf( stderr, "\n\t* Full Log of [%s, %s] in File [%s]",PROGRAM, VERSION, fname); + fprintf( stderr, "\n\t******************************************************************\n"); + } + return 1; +} + + + +FILE *NFP;/*Null file pointer: should only be open once*/ + +/*********************************************************************/ +/* */ +/* CACHE_FUNCTION */ +/* */ +/* */ +/*********************************************************************/ +static char *cache; +char * prepare_cache ( const char *mode) +{ + cache =vcalloc ( 10000, sizeof(char)); + + if (strm (mode, "use")) + { + sprintf (cache, "%s",get_cache_4_tcoffee()); + } + + else if ( strm (mode, "ignore") || strm (mode, "no")) + { + + cache=vtmpnam(cache); + strcat (cache, "/"); + printf_system_direct ("mkdir %s",cache); + + } + else if ( strm (mode, "update")) + { + cache=vtmpnam(cache); + strcat (cache, "/"); + printf_system_direct ("mkdir %s",cache); + } + else if ( strm (mode, "local")) + { + cache[0]='\0'; + } + else + { + sprintf ( cache, "%s/",mode); + my_mkdir ( cache); + } + return cache; + +} + +char * get_cache_dir() +{ + if ( cache==NULL){cache=vcalloc (1, sizeof (char));cache[0]='\0';} + return cache; +} + +void update_cache () +{ + char old_cache[1000]; + + sprintf ( old_cache, "%s", get_cache_dir()); + prepare_cache( "use"); + printf_system_direct ("mv %s* %s",old_cache, get_cache_dir()); + printf_system_direct ("rmdir %s",old_cache); +} +void ignore_cache() +{ + if (getenv4debug ("DEBUG_TMP_FILE")) + { + fprintf ( stderr, "\n[DEBUG_TMP_FILE:%s] TEMPORARY CACHE HAS NOT Been Removed:\n\t%s\n", PROGRAM,get_cache_dir()); + } + else + { + + printf_system_direct ("rm -r %s",get_cache_dir()); + } + return; + +} + +FILE *fopenN ( char *fname, char *mode, int max_n_tries, int delay); +FILE * vfopen ( char *name_in, char *mode) + { + FILE *fp; + int get_new_name; + int tolerate_mistake; + int cache_used=0; + FILE *tmp_fp; + int c; + static char *name; + static char *name2; + static char *stdin_file; + + + if ( !name_in)return NULL; + if (!name){name=vcalloc (1000, sizeof (char));} + if (!name2){name2=vcalloc (1000, sizeof (char));} + + sprintf ( name, "%s", name_in); + tild_substitute (name, "~", get_home_4_tcoffee()); + + get_new_name=tolerate_mistake=0; + if ( mode[0]=='g'){get_new_name=1; mode++;} + else if ( mode[0]=='t'){tolerate_mistake=1;mode++;} +/*Use the cached version from CACHE_4_TCOFFEE*/ + else if ( mode[0]=='c'){cache_used=1;mode++;} + + if (name==NULL ||strm5 ( name, "no","NO","No","NULL","/dev/null") || strm2 (name, "no_file", "NO_FILE")) + { + if ( NFP==NULL)NFP=fopen (NULL_DEVICE, mode); + return NFP; + } + else if ( strm3 (name,"stderr","STDERR","Stderr"))return stderr; + else if ( strm3 (name,"stdout","STDOUT","Stdout"))return stdout; + else if ( strm3 ( name, "stdin","STDIN","Stdin")) + { + if (!stdin_file) + { + stdin_file=vtmpnam (NULL); + tmp_fp=vfopen ( stdin_file, "w"); + while ( (c=fgetc(stdin))!=EOF)fprintf (tmp_fp, "%c", c); + vfclose ( tmp_fp); + } + return vfopen (stdin_file, "r"); + } + + else if ( strm (name, "") && (strm (mode, "w") ||strm (mode, "a")) )return stdout; + else if ( strm (name, "") && strm (mode, "r"))return stdin; + else if ( (fp= fopen ( name, mode))==NULL) + { + if ( strcmp (mode, "r")==0 && cache_used==0) + { + sprintf ( name2, "%s%s",get_cache_dir(), name); + return vfopen ( name2, "cr"); + } + else if ( strcmp (mode, "r")==0 && cache_used==1) + { + fprintf (stderr, "\n--COULD NOT READ %s\n", name); + if ( get_new_name){fprintf ( stderr, "\nNew name: ");return vfopen (input_name(), mode-1);} + else if ( tolerate_mistake)return NULL; + else + { + myexit(fprintf_error (stderr, "\nFORCED EXIT (NON INTERACTIVE MODE pid %d)\n", getpid())); + } + } + else if ( strcmp (mode, "a")==0 && cache_used==0) + { + sprintf ( name2, "%s%s",get_cache_dir(), name); + return vfopen ( name, "ca"); + } + else if ( strcmp (mode, "a")==0 && cache_used==1) + { + fprintf (stderr, "\nCOULD NOT Append anything to %s\n", name); + if ( get_new_name){fprintf ( stderr, "\nNew name: ");return vfopen (input_name(), mode-1);} + else if ( tolerate_mistake)return NULL; + else + { + myexit(fprintf_error (stderr, "\nFORCED EXIT (NON INTERACTIVE MODE pid %d)\n", getpid())); + } + } + else if ( strcmp (mode, "w")==0) + { + fprintf (stderr, "\nCANNOT WRITE %s\n", name); + if ( get_new_name==1){fprintf ( stderr, "\nNew name: ");return vfopen (input_name(), mode-1);} + else if ( tolerate_mistake)return NULL; + else + { + myexit(fprintf_error (stderr, "\nFORCED EXIT (NON INTERACTIVE MODE pid %d): %s %s\n", getpid(),(strcmp ( mode, "r")==0)?"READ":"WRITE", name)); + + } + } + } + else + return fp; + + return NULL; + } +FILE *fopenN ( char *fname, char *mode, int max_n_tries, int delay) +{ + FILE *fp; + int a; + + for (a=0; a< max_n_tries; a++) + { + if ((fp=fopen (fname, mode))) return fp; + else sleep (delay); + HERE ("---- failed opening: %s", fname); + } + return NULL; +} + +FILE * vfclose ( FILE *fp) + { + if ( fp==NFP)return NULL; + if ( fp==stdout)return stdout; + if ( fp==stderr)return stderr; + if ( fp==stdin) return stdin; + if ( fp==NULL)return NULL; + else fclose (fp); + return NULL; + } + + +int echo ( char *string, char *fname) +{ +int a; +/* +description: +prints the content of string into file fname + +in: +string= string to print +fname =name of the file to create +*/ + +FILE *fp; + + fp=vfopen ( fname, "w"); + fprintf (fp, "%s", string); + a=fclose (fp); + return a; + +} + +int file_cat ( char *from, char *to) +{ + FILE *fp; + //appends the content of file1 to file 2 + if (!(fp=vfopen (to, "a")))return 0; + if (!display_file_content (fp, from)) return 0; + vfclose (fp); + return 1; +} + +FILE* display_file_content (FILE *output, char *name) +{ + FILE *fp; + int c; + if ( !name || !file_exists (NULL,name) || !(fp=vfopen (name, "r")))return NULL; + while ( (c=fgetc(fp))!=EOF)fprintf (output,"%c", c); + vfclose (fp); + return output; +} + +char ***file2list ( char *name, char *sep) +{ + /*Rturns an array where + list[0]: first line + list[0][0]: number of words + list[0][1]:first word; + list[n]=NULL + */ + char **lines, ***list; + int a, n; + + lines=file2lines (name); + if (!lines) return NULL; + else + { + n=atoi (lines[0]); + + list=vcalloc ( n+1, sizeof (char**)); + for ( a=1; anlines; + lines[1]->first_line + */ + char **lines; + char *string; + + + string=file2string (name); + if ( !string) return NULL; + else + { + lines=string2list2(string, "\n"); + vfree ( string); + return lines; + } +} +int string2file (char *file, char *mode, char *string,...) +{ + FILE *fp; + va_list ap; + + if (!file) return 0; + else if ( !mode) return 0; + else if ( !(fp=vfopen (file, mode)))return 0; + va_start (ap, string); + vfprintf (fp, string, ap); + vfclose (fp); + va_end (ap); + return 1; +} + +char *file2string (char *name) +{ + FILE*fp; + char *string; + int a, c; + + if (!name || !file_exists (NULL,name))return NULL; + else + { + a=0; + if ((fp=fopen (name, "r"))) + { + while ( (c=fgetc(fp))!=EOF)a++; + fclose (fp); + } + else return NULL; + + string=vcalloc (a+1, sizeof (char)); + a=0; + if ((fp=fopen (name, "r"))) + { + while ( (c=fgetc(fp))!=EOF)string[a++]=c; + fclose (fp); + } + else return NULL; + string[a]='\0'; + return string; + } +} + +int get_cl_param (int argc, char **argv, FILE **fp,char *para_name, int *set_flag, char *type, int optional, int max_n_val,char *usage, ...) + { + /* + usage: + argc: n_ arg + argv list * + para_name param + set_flag set to 1 if param set; + para_type F, I, S, R_FN (read_file, name), W_FN (written file, name), R_FP (pointer) + max_n_val maximum number of values; + optional 1 for yes, 0 for no + usage usage list with optional value; + val pointer to the varaible holding the value(s) + default1 default value (if value id not there) + default2 default value if the flag is there but no value set ("")indicates an error + range_left min value ( "any" for any); + range_right max_value ( "any" for any); + */ + int pos=0; + int a; + va_list ap; + + int *int_val=NULL; + float *float_val=NULL; + char **string_val=NULL; + + + char *range_right; + char *range_left; + + + char *default_value1; + char *default_value2; + int n_para=0; + double max, min; + + static char **parameter_list; + static int number_of_parameters; + + char **para_name_list; + int n_para_name; + + char **para_val; + int n_para_val; + + char **pv_l=NULL; + int n_pv_l; + char **pv_r=NULL; + int n_pv_r; + char value[STRING]; + + + +/*CHECK THAT ALL THE PARAM IN ARG EXIST*/ + if ( para_name==NULL) + { + for ( a=1; a< argc; a++) + { + if ( is_parameter ( argv[a])) + { + if (strstr (argv[a], "help"))myexit (EXIT_SUCCESS); + else if ( name_is_in_list ( argv[a], parameter_list, number_of_parameters, STRING)==-1) + { + myexit(fprintf_error ( stderr, "\n%s IS NOT A PARAMETER OF %s [FATAL/%s %s]\n",argv[a], argv[0], argv[0], VERSION)); + + } + } + + } + + free_char (parameter_list,-1); + return 0; + } + + if ( parameter_list==NULL)parameter_list=declare_char(MAX_N_PARAM,STRING); + para_name_list=get_list_of_tokens(para_name,NULL, &n_para_name); + for ( a=0; a< n_para_name; a++) + { + sprintf ( parameter_list[number_of_parameters++],"%s", para_name_list[a]); + } + free_char(para_name_list,-1); + + + + + + set_flag[0]=0; + va_start (ap, usage); + + if (strm3 (type, "S","R_F","W_F")) + string_val=va_arg(ap, char**); + else if (strm2 (type, "D","FL")) + int_val=va_arg(ap, int*); + else if (strm (type, "F")) + float_val=va_arg(ap, float*); + else + myexit (EXIT_FAILURE); + + + + default_value1=va_arg(ap, char*); + default_value2=va_arg(ap, char*); + range_left =va_arg(ap, char*); + range_right =va_arg(ap, char*); + va_end(ap); + + + para_name_list=get_list_of_tokens(para_name, NULL, &n_para_name); + for ( a=0; a=max_n_val) + { + n_para=max_n_val-1; + + } + if ( !(strm ( argv[a], "NULL"))) + { + if ( strm3(type, "S", "R_F", "W_F")) + { + sprintf ( string_val[n_para],"%s", argv[a]); + } + else if (strm (type, "D")) + { + int_val[n_para]=atoi(argv[a]); + } + else if (strm ( type,"F")) + { + float_val[n_para]=atof(argv[a]); + } + } + n_para++; + } + } + + if ( n_para==0 && !strm2(default_value2,"","NULL") && !strm(type, "FL")) + { + para_val=get_list_of_tokens(default_value2, NULL, &n_para_val); + for ( n_para=0; n_paramax) + { + myexit(fprintf_error ( stderr, "\n%s out of range [%d %d] [FATAL/%s]\n", para_name, (int)min, (int)max,argv[0])); + + } + } + else + { + sprintf ( value, "%d", int_val[a]); + if ( name_is_in_list(value, pv_l, n_pv_l, STRING)==-1) + fprintf ( stderr, "\n%s out of range [%s: ", para_name, value); + print_array_char (stderr, pv_l, n_pv_l, " "); + fprintf ( stderr, "\n"); + myexit(EXIT_FAILURE); + } + } + else if ( strm (type, "F")) + { + if ( n_pv_l==1) + { + min=(double)atof(range_left); + max=(double)atof(range_right); + if ( float_val[a]max) + { + myexit(fprintf_error ( stderr, "\n%s out of range [%f %f] [FATAL/%s]\n", para_name, (float)min, (float)max,argv[0])); + + } + } + else + { + sprintf ( value, "%f", float_val[a]); + if ( name_is_in_list(value, pv_l, n_pv_l, STRING)==-1) + fprintf ( stderr, "\n%s out of range [%s: ", para_name, value); + print_array_char (stderr, pv_l, n_pv_l, " "); + fprintf ( stderr, "\n"); + + } + } + } + + + if ( fp[0]!=NULL) + { + fprintf (fp[0], "%-15s\t%s\t[%d] ", para_name, type, set_flag[0]); + for (a=0; a=buf_len) + {buf_len+=100;buf=vrealloc (buf, buf_len*sizeof (char));} + buf[l++]=c; + } + /*Add the cariage return*/ + if ( c=='\n') + { + if (l>=buf_len){buf_len+=100,buf=vrealloc (buf, buf_len*sizeof (char));} + buf[l++]='\n'; + } + /*add the terminator*/ + if (l>=buf_len){buf_len+=100,buf=vrealloc (buf, buf_len*sizeof (char));} + buf[l]='\0'; + + if ( bufin!=buf && bufin!=NULL && debug==1) + fprintf ( stderr, "\nPointer change in vfgets..."); + + return buf; +} + + +FILE * find_token_in_file ( char *fname, FILE * fp, char *token) + { + int c; + static char *name; + int token_len; + + int only_start; + + /*Note: Token: any string + If Token[0]=='\n' Then Token only from the beginning of the line + */ + + if (!fp && !file_exists("CACHE",fname))return NULL; + + if ( token[0]=='\n'){token++;only_start=1;} + else only_start=0; + + token_len=strlen (token); + + + + + + if (!fp) + { + if (name)vfree (name); + name = vcalloc (((fname)?measure_longest_line_in_file (fname):10000)+1, sizeof (char)); + fp=vfopen ( fname, "r"); + } + + while ( (fscanf ( fp, "%s", name))!=EOF) + { + + if ( name[0]=='*')while ( ((c=fgetc (fp))!='\n')&& (c!=EOF)); + else if (strncmp ( name, token,token_len)==0){return fp;} + else if (only_start) while ( ((c=fgetc (fp))!='\n')&& (c!=EOF)); + } + + vfclose ( fp); + return NULL; + } +int **get_file_block_pattern (char *fname, int *n_blocks, int max_n_line) + { + int c; + FILE *fp; + char *line; + int lline; + int **l; + int in_block; + + int max_block_size; + int block_size; + int x; + int n_line; + + lline=measure_longest_line_in_file (fname)+1; + line=vcalloc ( sizeof (char),lline+1); + + fp=vfopen (fname, "r"); + max_block_size=block_size=0; + in_block=1; + n_blocks[0]=0; + n_line=0; + while ((c=fgetc(fp))!=EOF && (n_line max_block_size)myexit(fprintf_error ( stderr, "\nERROR %d", l[n_blocks[0]][0])); + + l[n_blocks[0]] [l[n_blocks[0]][0]]=x; + } + else + { + in_block=0; + } + } + n_blocks[0]++; + vfree(line); + vfclose (fp); + return l; + } + +char * strip_file_from_comments (char *com, char *in_file) +{ + /*Removes in file in_file every portion of line to the right of one of the symbols included in com + Writes the striped file into a vtmpnam file + */ + FILE *fp1; + FILE *fp2; + char *out_file; + int c; + + out_file=vtmpnam(NULL); + + + fp1=vfopen (in_file , "r"); + fp2=vfopen (out_file, "w"); + while ( (c=fgetc(fp1))!=EOF) + { + if (strchr(com, c)) + { + while ( (c=fgetc(fp1))!='\n' && c!=EOF); + } + else + { + fprintf (fp2, "%c", c); + while ( (c=fgetc(fp1))!='\n' && c!=EOF)fprintf (fp2, "%c", c); + if ( c!=EOF)fprintf (fp2, "%c", c); + } + } + vfclose (fp1); + vfclose (fp2); + + return out_file; +} +FILE * skip_commentary_line_in_file ( char com, FILE *fp) +{ + int c=0; + + if ( fp==NULL)return NULL; + while ((c=fgetc(fp))==com) + { + while ((c=fgetc(fp))!='\n' && c!=EOF); + } + if ( c!=EOF && c!='\n')ungetc(c, fp); + return fp; +} + +int check_for_update ( char *web_address) +{ + char command[1000]; + char *file; + float new_version, old_version; + FILE *fp; + + check_internet_connection (IS_NOT_FATAL); + file=vtmpnam(NULL); + + sprintf ( command, "%s/%s.version",DISTRIBUTION_ADDRESS, PROGRAM); + url2file ( command, file); + + fp=vfopen ( file, "r"); + fscanf ( fp, "Version_%f", &new_version); + vfclose ( fp); + sscanf ( VERSION, "Version_%f", &old_version); + + if ( old_version new_version) + { + fprintf ( stdout, "\nUpdate Status: beta-release"); + fprintf ( stdout, "\nYour are using a beta-release of %s(%s)\n", PROGRAM, VERSION); + } + else + { + fprintf (stdout, "\nUpdate Status: uptodate"); + fprintf (stdout, "\nProgram %s(%s) is up to date\n", PROGRAM, VERSION); + } + return EXIT_SUCCESS; +} + + + + + +int check_environement_variable_is_set ( char *variable, char *description, int fatal) +{ + if ( getenv (variable)==NULL) + { + myexit(fprintf_error ( stderr, "\nERROR: You must set %s\n%s %s", variable, description, description)); + if ( fatal==IS_FATAL) + { + myexit(fprintf_error ( stderr, "\n[%s:FATAL]\n", PROGRAM)); + + } + else + add_warning ( stderr, "\n[%s:WARNING]\n", PROGRAM); + } + return 1; +} + +int url2file (char *address, char *out) +{ + + if (check_program_is_installed ("wget",NULL, NULL,WGET_ADDRESS, IS_NOT_FATAL))return printf_system( "wget %s -O%s >/dev/null 2>/dev/null", address, out); + else if (check_program_is_installed ("curl",NULL, NULL,CURL_ADDRESS, IS_NOT_FATAL))return printf_system("curl %s -o%s >/dev/null 2>/dev/null", address, out); + else + { + printf_exit (EXIT_FAILURE, stderr, "ERROR: Impossible to fectch external file: Neither wget nor curl is installed on your system [FATAL:%s]\n", PROGRAM); + return EXIT_FAILURE; + } +} + +int wget (char *address, char *out) +{ + return printf_system ( "curl %s -O%s >/dev/null 2>/dev/null", address, out); + } + +int curl (char *address, char *out) +{ + return printf_system ( "curl %s -o%s >/dev/null 2>/dev/null", address, out); +} + + +int simple_check_internet_connection (char *ref_site) +{ + char *test; + int n, internet=0; + + test=vtmpnam (NULL); + if (url2file((ref_site)?ref_site:TEST_WWWSITE_4_TCOFFEE,test)!=EXIT_SUCCESS)internet=0; + else if ((n=count_n_char_in_file(test))<10)internet=0; + else internet =1; + + return internet; +} +int check_internet_connection (int mode) +{ + int internet; + internet=simple_check_internet_connection (NULL); + if (internet)return 1; + else if ( mode==IS_NOT_FATAL)return internet; + else proxy_msg(stderr); + myexit (EXIT_FAILURE); +} +char *pg2path (char *pg) +{ + char *path; + + char *tmp; + + + if ( !pg) return NULL; + tmp=vtmpnam(NULL); + + printf_system_direct("which %s>%s 2>/dev/null", pg, tmp); + path=file2string (tmp); + chomp (path); + if (!file_exists (NULL,path) && !strstr (pg, ".exe")) + { + char pg2[1000]; + sprintf ( pg2, "%s.exe", pg); + path=pg2path (pg2); + } + + return path; +} + + +int check_program_is_installed ( char *program_name, char *path_variable, char *path_variable_name, char *where2getit, int fatal) + { + + static char *path; + int install_4_tcoffee=0; + + if (atoigetenv("INSTALL_4_TCOFFEE"))install_4_tcoffee=1; + + if ( strm (where2getit, "built_in"))return 1; + + if (path)vfree (path); + + if ( check_file_exists (path_variable)) + { + return 1; + } + else + { + + path=pg2path (program_name); + if (path && path[0])return 1; + else + { + int install=EXIT_FAILURE; + + if ((fatal==INSTALL || fatal==INSTALL_OR_DIE) && install_4_tcoffee) + { + HERE ("************** %s is missing from your system. T-Coffee will make an attempt to install it.\n", program_name); + install=printf_system ("install.pl %s -plugins=%s -clean", program_name, get_plugins_4_tcoffee()); + } + if ( install==EXIT_SUCCESS)return 1; + else if ( fatal==INSTALL)return 0; + else if ( fatal==NO_REPORT)return 0; + + if (fatal==IS_FATAL || fatal==INSTALL_OR_DIE)check_configuration4program(); + + fprintf ( stderr, "\n#*****************************************************************"); + if (fatal) fprintf_error ( stderr, "\n#ERROR [FATAL:%s]", PROGRAM); + else fprintf ( stderr, "\n#WARNING [%s]", PROGRAM); + fprintf ( stderr, "\n# The Program %s Needed by %s Could not be found", program_name, PROGRAM); + fprintf ( stderr, "\n# If %s is installed on your system:", program_name); + fprintf ( stderr, "\n#\t -Make sure %s is in your $path:",program_name); + + fprintf ( stderr, "\n# If %s is NOT installed obtain a copy from:", program_name); + fprintf ( stderr, "\n#\t%s\n#\n#",where2getit); + fprintf ( stderr, "\n# and install it manualy"); + fprintf ( stderr, "\n******************************************************************\n"); + } + } + if ( fatal==IS_FATAL || fatal==INSTALL_OR_DIE) myexit (EXIT_FAILURE); + return 0; + } + +FILE * display_output_filename ( FILE *io, char *type, char *format, char *name, int check_output) +{ + static char ***buf; + static int nbuf; + char *f; + + if ( strm ( name, "stdout") || strm (name, "stderr"))return io; + + if ( check_output==STORE) + { + int a; + if ( buf==NULL)buf=vcalloc ( 1000, sizeof (char**)); + + for (a=0; a\n"); + fprintf (out,"output\n"); + fprintf (out,"%s\n", type); + fprintf (out, "%s\n", format); + fprintf (out, "%s\n", name); + fprintf (out, "\n"); + if ((fp=fopen (name, "r"))!=NULL) + { + while ((c=fgetc (fp))!=EOF){fprintf(out, "%c",c);} + fclose (fp); + } + fprintf (out,"\n\n"); + fclose (out); + } + } + + } + return io; +} + +FILE * display_input_filename ( FILE *io, char *type, char *format, char *name, int check_output) +{ + if ( check_output==CHECK && check_file_exists(name)==NULL) + { + fprintf ( io, "\n\tIIII INPUT File Type= %10s Format= %10s Name= %s | NOT PRODUCED [WARNING:%s:%s]\n",type, format, name, PROGRAM, VERSION ); + return io; + } + fprintf ( io, "\n\t#### File Type= %10s Format= %10s Name= %s",type, format, name ); + return io; +} + +int file_is_empty (char *fname) +{ + struct stat s; + if (!fname) return 1; + + stat (fname, &s); + if (s.st_size)return 0; + else return 1; + } +int file_exists (char *path, char *fname) +{ + struct stat s; + char file[1000]; + + if (!fname)return 0; + else if (path && strm (path, "CACHE")) + { + if (file_exists (NULL, fname))return 1; + else return file_exists (get_cache_dir(), fname); + } + else if (path) sprintf ( file, "%s/%s", path, fname); + else if (!path)sprintf (file, "%s", fname); + + if (stat(file,& s)!=-1) + return S_ISREG(s.st_mode); + else return 0; +} + +int isdir (char *file) +{ + struct stat s; + if (stat (file,&s)!=-1) + return S_ISDIR(s.st_mode); + else return 0; +} +int rrmdir (char *s) +{ + if (isdir(s))return printf_system_direct ("rm -r %s", s); + return EXIT_FAILURE; +} + +int isexec (char *file) +{ + char *state; + + + state=ls_l(NULL,file); + + if (state[0]==0) return 0; + + if ( state[0]=='d') return 0; + if ( state[3]=='x') return 1; + if ( state[6]=='x') return 1; + if ( state[9]=='x') return 1; + return 0; +} + +char *ls_l ( char *path,char *file) +{ + char *tmpfile; + static char *state; + FILE *fp; + int a; + + tmpfile=vtmpnam (NULL); + if (!state) + { + + state=vcalloc (100, sizeof (char)); + } + for (a=0;a<100; a++)state[a]=0; + if (!file || !file_exists (path, file))return state; + printf_system_direct ("ls -l %s%s%s >%s 2>/dev/null",(path!=NULL)?path:"", (path!=NULL)?"/":"",file, tmpfile); + + fp=vfopen (tmpfile, "r"); + if (!fscanf ( fp, "%s", state)) + { + vfclose(fp); return 0; + } + vfclose (fp); + return state; +} + +int my_rmdir ( char *dir_in) +{ + int dir_sep='/'; + + int a, buf; + char *dir; + + dir=vcalloc ( strlen (dir_in)+strlen (get_home_4_tcoffee())+100, sizeof (char)); + sprintf ( dir, "%s", dir_in); + tild_substitute ( dir, "~",get_home_4_tcoffee()); + + if (access(dir, F_OK)==-1); + else + { + if ( strstr (dir, "coffee"))printf_system ( "rm -rf %s", dir); + else myexit(fprintf_error ( stderr, "\nERROR: directory %s does not contain 'coffee' [FATAL:%s]", dir, PROGRAM)); } + vfree (dir);return; +} + +int my_mkdir ( char *dir_in) +{ + + int dir_sep='/'; + + int a, buf; + char *dir; + + dir=vcalloc ( strlen (dir_in)+strlen (get_home_4_tcoffee())+100, sizeof (char)); + sprintf ( dir, "%s", dir_in); + tild_substitute ( dir, "~",get_home_4_tcoffee()); + + + + a=0; + + while (dir[a]!='\0') + { + + if ( dir[a]==dir_sep || dir[a+1]=='\0') + { + buf= dir[a+1]; + dir[a+1]='\0'; + + if (access(dir, F_OK)==-1) + { + + + printf_system_direct("mkdir %s", dir); + if ( access (dir, F_OK)==-1) + { + myexit(fprintf_error ( stderr, "\nERROR: Could Not Create Directory %s [FATAL:%s]", dir, PROGRAM)); } + } + dir[a+1]=buf; + } + a++; + } + + vfree (dir); + return 1; +} + +int filename_is_special (char *fname) +{ + if ( strm5 (fname, "default", "stdin", "stdout","stderr", "/dev/null"))return 1; + if ( strm3 (fname, "STDIN", "STDOUT", "STDERR"))return 1; + return 0; +} + +char* check_file_exists ( char *fname_in) + { + + static char *fname1; + static char *fname2; + + + if (!fname_in)return NULL; + if (!fname_in[0])return NULL; + if (fname_in[0]=='-')return NULL; + + if (!fname1){fname1=vcalloc (1000, sizeof (char));} + if (!fname2){fname2=vcalloc (1000, sizeof (char));} + + sprintf ( fname1, "%s", fname_in);tild_substitute (fname1, "~", get_home_4_tcoffee()); + sprintf ( fname2, "%s%s", get_cache_dir(),fname1); + + if ( filename_is_special (fname1))return fname1; + if ( strm5 (fname1, "no", "NO", "No", "NO_FILE","no_file"))return NULL/*fname1*/; + if (!file_exists( NULL,fname1)) + { + if (!file_exists (NULL,fname2))return NULL; + else return fname2; + } + else return fname1; + return NULL; + } + + +void create_file ( char *name) + { + FILE *fp; + + fp=fopen (name, "w"); + fclose (fp); + } +void delete_file ( char *fname) + { + + FILE * fp; + + fp=fopen ( fname, "w"); + fprintf ( fp, "x"); + fclose ( fp); + + printf_system_direct ("rm %s", fname); + } + +int util_rename ( char *from, char *to) + { + FILE *fp_from; + FILE *fp_to; + int c; + + + if ( !check_file_exists (from))return 0; + else if ( check_file_exists (to) && !vremove (to) && !rename ( from, to)==0 ); + else + { + + fp_from=vfopen ( from, "r"); + fp_to=vfopen ( to, "w"); + + while ( (c=fgetc (fp_from))!=EOF)fprintf ( fp_to, "%c", c); + + fclose (fp_from); + fclose ( fp_to); + + vremove ( from); + return 1; + } + return 0; + } + + +int util_copy ( char *from, char *to) + { + FILE *fp_from; + FILE *fp_to; + int c; + + + if (!check_file_exists (from))return 0; + else + { + + fp_from=vfopen ( from, "r"); + fp_to=vfopen ( to, "w"); + + while ( (c=fgetc (fp_from))!=EOF)fprintf ( fp_to, "%c", c); + + fclose (fp_from); + fclose ( fp_to); + return 1; + } + return 0; + } +FILE * output_completion4halfmat ( FILE *fp,int n, int tot, int n_reports, char *s) + +{ + int max, left, achieved; + int up; + + if (n>=0)up=1; + else up=-1; + + + max=((tot*tot)-tot)/2; + left=((tot-n)*(tot-n)-(tot-n))/2; + + achieved=max-left; + if (up==1); + else + { + int b; + b=achieved; + achieved=left; + left=b; + } + return output_completion (fp,achieved, max, n_reports, s); +} + + +FILE * output_completion ( FILE *fp,int n, int tot, int n_reports, char *string) + { + + static int ref_val; + static int flag; + static int ref_time; + int t, elapsed; + n++; + + if ( n==1) + { + ref_val=flag=0; + ref_time=get_time()/1000; + } + t=get_time()/1000; + elapsed=t-ref_time; + + if ( !ref_val && !flag) + { + fprintf (fp, "\n\t\t[%s][TOT=%5d][%3d %%][ELAPSED TIME: %4d sec.]",(string)?string:"",tot,(tot==1)?100:0, elapsed); + flag=1; + } + else if ( n==tot)fprintf (fp, "\r\t\t[%s][TOT=%5d][%3d %%][ELAPSED TIME: %4d sec.]",(string)?string:"", tot,100, elapsed); + else if ( ((n*100)/tot)>ref_val) + { + ref_val=((n*100)/tot); + t=(ref_val==0)?0:elapsed/ref_val; + t=t*(100-ref_val); + t=0; + fprintf (fp, "\r\t\t[%s][TOT=%5d][%3d %%][ELAPSED TIME: %4d sec.]", (string)?string:"",tot,ref_val, elapsed); + flag=0; + } + return fp; + } +void * null_function (int a,...) +{ + myexit(fprintf_error ( stderr, "\n[ERROR] Attempt to use the Null Function [FATAL:%s]", PROGRAM)); + + return NULL; +} + +int btoi ( int nc,...) +{ + va_list ap; + int a, b; + va_start (ap, nc); + for ( a=0, b=0; a< nc; a++) + { + b+=pow(2,a)*va_arg (ap,int); + } + va_end(ap); + return b; +} + +/*********************************************************************/ +/* */ +/* Geometric FUNCTIONS */ +/* */ +/* */ +/*********************************************************************/ + +float get_geometric_distance ( float ** matrix, int ncoor, int d1, int d2, char *mode) +{ + float d; + float t=0; + int a; + + if ( strm (mode, "euclidian")) + { + for ( a=0; a< ncoor; a++) + { + d=(matrix[d1][a]-matrix[d2][a]); + t+=d*d; + } + return (float)sqrt((double)t); + } + return 0; +} + + + +/*********************************************************************/ +/* */ +/* MATHEMATICAL FUNCTIONS */ +/* */ +/* */ +/*********************************************************************/ +static double EXP_UNDERFLOW_THRESHOLD = -4.60f; +static double LOG_UNDERFLOW_THRESHOLD = 7.50f; +static double LOG_ZERO = -FLT_MAX; +static double LOG_ONE = 0.0f; +double log_addN (int N, double*L) + +{ + double v; + int a; + if (N==0)return 0; + if ( N==1)return L[0]; + + v=L[0]; + for ( a=1; a= LOG_UNDERFLOW_THRESHOLD)) ? y : log (exp (x-y) + 1) + x; + else + x = (y == LOG_ZERO || ((x - y) >= LOG_UNDERFLOW_THRESHOLD)) ? x : log (exp (x-y) + 1) + y; + return x; +} + + + + +float M_chooses_Nlog ( int m, int N) +{ + /*Choose M elemets in N*/ + float z1, z2,z=0; + if ( m==N) return 0; + else if ( m>N) + { + myexit(fprintf_error ( stderr, "\nERROR: M chosses N out of bounds ( M>N) [FATAL:%s]", PROGRAM)); + myexit (EXIT_FAILURE); + } + else + { + z1=factorial_log (m+1, N); + z2=factorial_log (1, N-m); + z=z1-z2; + return z; + } + + return -1; +} + +float factorial_log ( int start, int end) +{ + if ( end==0)return 0; + else if ( end==start) return (float)my_int_log((double)start); + else if ( start>end) + { + fprintf_error ( stderr, "\nERROR: factorial log out of bounds (%d %d) [FATAL:%s]",start, end, PROGRAM); + myexit (EXIT_FAILURE); + } + else + { + int a=0; + float x=0; + for ( x=0,a=start; a<=end; a++) + { + x+=(float)my_int_log(a); + } + return x; + } + return 0; +} + +float my_int_log(int a) +{ + + if ( a>=100000)return log(a); + else + { + static float *lu; + if (!lu) lu=vcalloc ( 100000, sizeof (float)); + if ( !lu[a]){lu[a]=log(a);} + return lu[a]; + } + return 0; +} + +double factorial (int start, int end); +double M_chooses_N ( int m, int N) +{ + /*Choose M elemets in N*/ + if ( m==N) return 1; + else if ( m>N) + { + fprintf_error ( stderr, "\nERROR: M chosses N out of bounds ( M>N) [FATAL:%s]", PROGRAM); + myexit (EXIT_FAILURE); + } + else if ( N<50) + { + return factorial (m+1, N)/factorial (1, N-m); + } + else + { + fprintf_error ( stderr, "\nERROR: M chosses N out of bounds ( N>50). Use log space [FATAL:%s]", PROGRAM); + myexit (EXIT_FAILURE); + } + return -1; +} +double factorial (int start, int end) + { + + if ( start>end || start<0 || end<0) + { + fprintf_error ( stderr, "\nERROR: Negative Factorial [FATAL:%s]", PROGRAM); + myexit ( EXIT_FAILURE); + } + else if (end==0) return 1; + else if (end==start) return end; + else + { + static double **lu; + if ( !lu)lu=declare_double (100, 100); + + if ( lu[start][end])return lu[start][end]; + else + { + int a; + lu[start][end]=(double)start; + for ( a=start+1; a<=end; a++) + { + lu[start][end]*=(double)a; + } + return lu[start][end]; + } + } + return -1; + } +/*********************************************************************/ +/* */ +/* Fast Log Additions (adapted from Probcons)*/ +/* */ +/* */ +/*********************************************************************/ +double EXP (double x){ + //return exp(x); + if (x > -2){ + if (x > -0.5){ + if (x > 0) + return exp(x); + return (((0.03254409303190190000*x + 0.16280432765779600000)*x + 0.49929760485974900000)*x + 0.99995149601363700000)*x + 0.99999925508501600000; + } + if (x > -1) + return (((0.01973899026052090000*x + 0.13822379685007000000)*x + 0.48056651562365000000)*x + 0.99326940370383500000)*x + 0.99906756856399500000; + return (((0.00940528203591384000*x + 0.09414963667859410000)*x + 0.40825793595877300000)*x + 0.93933625499130400000)*x + 0.98369508190545300000; + } + if (x > -8){ + if (x > -4) + return (((0.00217245711583303000*x + 0.03484829428350620000)*x + 0.22118199801337800000)*x + 0.67049462206469500000)*x + 0.83556950223398500000; + return (((0.00012398771025456900*x + 0.00349155785951272000)*x + 0.03727721426017900000)*x + 0.17974997741536900000)*x + 0.33249299994217400000; + } + if (x > -16) + return (((0.00000051741713416603*x + 0.00002721456879608080)*x + 0.00053418601865636800)*x + 0.00464101989351936000)*x + 0.01507447981459420000; + return 0; +} + +float LOOKUP (float x){ + + if (x <= 1.00f) return ((-0.009350833524763f * x + 0.130659527668286f) * x + 0.498799810682272f) * x + 0.693203116424741f; + if (x <= 2.50f) return ((-0.014532321752540f * x + 0.139942324101744f) * x + 0.495635523139337f) * x + 0.692140569840976f; + if (x <= 4.50f) return ((-0.004605031767994f * x + 0.063427417320019f) * x + 0.695956496475118f) * x + 0.514272634594009f; + + return ((-0.000458661602210f * x + 0.009695946122598f) * x + 0.930734667215156f) * x + 0.168037164329057f; +} +void LOG_PLUS_EQUALS (float *x, float y){ + + if (x[0] < y) + x[0] = (x[0] == LOG_ZERO || y - x[0] >= LOG_UNDERFLOW_THRESHOLD) ? y : LOOKUP(y-x[0]) + x[0]; + else + x[0] = (y == LOG_ZERO || x[0] - y >= LOG_UNDERFLOW_THRESHOLD) ? x[0] : LOOKUP(x[0]-y) + y; +} + +float LOG_ADD (float x, float y){ + if (x < y) return (x == LOG_ZERO || y - x >= LOG_UNDERFLOW_THRESHOLD) ? y : LOOKUP((y-x)) + x; + return (y == LOG_ZERO || x - y >= LOG_UNDERFLOW_THRESHOLD) ? x : LOOKUP((x-y)) + y; +} + +float LOG_ADD3 (float x1, float x2, float x3){ + return LOG_ADD (x1, LOG_ADD (x2, x3)); +} +float LOG_ADD4 (float x1, float x2, float x3, float x4){ + return LOG_ADD (x1, LOG_ADD (x2, LOG_ADD (x3, x4))); +} +float LOG_ADD5 (float x1, float x2, float x3, float x4, float x5){ + return LOG_ADD (x1, LOG_ADD (x2, LOG_ADD (x3, LOG_ADD (x4, x5)))); +} +float LOG_ADD6 (float x1, float x2, float x3, float x4, float x5, float x6){ + return LOG_ADD (x1, LOG_ADD (x2, LOG_ADD (x3, LOG_ADD (x4, LOG_ADD (x5, x6))))); +} +float LOG_ADD7 (float x1, float x2, float x3, float x4, float x5, float x6, float x7){ + return LOG_ADD (x1, LOG_ADD (x2, LOG_ADD (x3, LOG_ADD (x4, LOG_ADD (x5, LOG_ADD (x6, x7)))))); +} + + +#define LONG_SIZE 2 +#define SHORT_SIZE 1 +#define SPACE_PAD 4 +#define STD_SIZE 0 +char *strscn(char *s, char *pattern); +long unsigned strtou(char *s, int base, char **scan_end); +long int strtoi(char *s, int base, char **scan_end); +int my_isnumber(char c, int base); +int tonumber(char c); + +int my_vsscanf(char *buf, char *fmt, va_list parms) + { + int scanned = 0, size = 0, suppress = 0; + int w = 0, flag = 0, l = 0; + char c, *c_ptr; + long int n1, *n1l; + int *n1b; + short int *n1s; + long unsigned n2, *n2l, parsing = 0; + unsigned *n2b; + short unsigned *n2s; + double n3, *n3l; + float *n3s; + char *base = buf; + while (*fmt != 0) { + if (*fmt != '%' && !parsing) { + /* No token detected */ + fmt++; + } else { + /* We need to make a conversion */ + if (*fmt == '%') { + fmt++; + parsing = 1; + size = STD_SIZE; + suppress = 0; + w = 0; + flag = 0; + l = 0; + } + /* Parse token */ + switch (*fmt) { + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '0': + if (parsing == 1) { + w = strtou(fmt, 10, &base); + /* We use SPACE_PAD to parse %10s + * commands where the number is the + * maximum number of char to store! + */ + flag |= SPACE_PAD; + fmt = base - 1; + } + break; + case 'c': + c = *buf++; + c_ptr = va_arg(parms, char *); + *c_ptr = c; + scanned++; + parsing = 0; + break; + case 's': + c_ptr = va_arg(parms, char *); + while (*buf != 0 && isspace(*buf)) + buf++; + l = 0; + while (*buf != 0 && !isspace(*buf)) { + if (!(flag & SPACE_PAD)) + *c_ptr++ = *buf; + else if (l < w) { + *c_ptr++ = *buf; + l++; + } + buf++; + } + *c_ptr = 0; + scanned++; + parsing = 0; + break; + case 'i': + case 'd': + buf = strscn(buf, "1234567890-+"); + n1 = strtoi(buf, 10, &base); + buf = base; + if (!suppress) { + switch (size) { + case STD_SIZE: + n1b = va_arg(parms, int *); + *n1b = (int) n1; + break; + case LONG_SIZE: + n1l = va_arg(parms, + long int *); + *n1l = n1; + break; + case SHORT_SIZE: + n1s = va_arg(parms, + short int *); + *n1s = (short) (n1); + break; + } + scanned++; + } + parsing = 0; + break; + case 'u': + buf = strscn(buf, "1234567890"); + n2 = strtou(buf, 10, &base); + buf = base; + if (!suppress) { + switch (size) { + case STD_SIZE: + n2b = va_arg(parms, + unsigned *); + *n2b = (unsigned) n2; + break; + case LONG_SIZE: + n2l = va_arg(parms, + long unsigned *); + *n2l = n2; + break; + case SHORT_SIZE: + n2s = va_arg(parms, short unsigned + *); + *n2s = (short) (n2); + break; + } + scanned++; + } + parsing = 0; + break; + case 'x': + buf = strscn(buf, "1234567890xabcdefABCDEF"); + n2 = strtou(buf, 16, &base); + buf = base; + if (!suppress) { + switch (size) { + case STD_SIZE: + n2b = va_arg(parms, + unsigned *); + *n2b = (unsigned) n2; + break; + case LONG_SIZE: + n2l = va_arg(parms, + long unsigned *); + *n2l = n2; + break; + case SHORT_SIZE: + n2s = va_arg(parms, short unsigned + *); + *n2s = (short) (n2); + break; + } + scanned++; + } + parsing = 0; + break; + case 'f': + case 'g': + case 'e': + buf = strscn(buf, "1234567890.e+-"); + n3 = strtod(buf, &base); + buf = base; + if (!suppress) { + switch (size) { + case STD_SIZE: + n3l = va_arg(parms, double *); + *n3l = n3; + break; + case LONG_SIZE: + n3l = va_arg(parms, double *); + *n3l = n3; + break; + case SHORT_SIZE: + n3s = va_arg(parms, float *); + *n3s = (float) (n3); + break; + } + scanned++; + } + parsing = 0; + break; + case 'l': + size = LONG_SIZE; + break; + case 'h': + case 'n': + size = SHORT_SIZE; + break; + case '*': + suppress = 1; + break; + default: + parsing = 0; + break; + } + fmt++; + } + } + return (scanned); + } +char *strscn(char *s, char *pattern) + { + char *scan; + while (*s != 0) { + scan = pattern; + while (*scan != 0) { + if (*s == *scan) + return (s); + else + scan++; + } + s++; + } + return (NULL); + } + +long unsigned strtou(char *s, int base, char **scan_end) + { + int value, overflow = 0; + long unsigned result = 0, oldresult; + /* Skip trailing zeros */ + while (*s == '0') + s++; + if (*s == 'x' && base == 16) { + s++; + while (*s == '0') + s++; + } + /* Convert number */ + while (my_isnumber(*s, base)) { + value = tonumber(*s++); + if (value > base || value < 0) + return (0); + oldresult = result; + result *= base; + result += value; + /* Detect overflow */ + if (oldresult > result) + overflow = 1; + } + if (scan_end != 0L) + *scan_end = s; + if (overflow) + result = INT_MAX; + return (result); + } +long int strtoi(char *s, int base, char **scan_end) + { + int sign, value, overflow = 0; + long int result = 0, oldresult; + /* Evaluate sign */ + if (*s == '-') { + sign = -1; + s++; + } else if (*s == '+') { + sign = 1; + s++; + } else + sign = 1; + /* Skip trailing zeros */ + while (*s == '0') + s++; + /* Convert number */ + while (my_isnumber(*s, base)) { + value = tonumber(*s++); + if (value > base || value < 0) + return (0); + oldresult = result; + result *= base; + result += value; + /* Detect overflow */ + if (oldresult > result) + overflow = 1; + } + if (scan_end != 0L) + *scan_end = s; + if (overflow) + result = INT_MAX; + result *= sign; + return (result); + } + +int my_isnumber(char c, int base) + { + static char *digits = "0123456789ABCDEF"; + if ((c >= '0' && c <= digits[base - 1])) + return (1); + else + return (0); + } + + int tonumber(char c) + { + if (c >= '0' && c <= '9') + return (c - '0'); + else if (c >= 'A' && c <= 'F') + return (c - 'A' + 10); + else if (c >= 'a' && c <= 'f') + return (c - 'a' + 10); + else + return (c); + } + +/////////////////////////////////////////////////////////////////////////////////////////// +// Hash function +//////////////////////////////////////////////////////////////////////////////////////////// +unsigned long hash_file(char* file) //returns the hash value for key + { + // Calculate a hash value by the division method: + // Transform key into a natural number k = sum ( key[i]*128^(L-i) ) and calculate i= k % num_slots. + // Since calculating k would lead to an overflow, i is calculated iteratively + // and at each iteration the part divisible by num_slots is subtracted, i.e. (% num_slots is taken). + + unsigned long i=0; // Start of iteration: k is zero + unsigned long num_slots=999999999; + + + FILE *fp; + unsigned long c; + + + if (file==NULL || !check_file_exists (file) ) {printf("Warning from util.c:hasch_file: No File [FATAL:%s]\n", PROGRAM); myexit (EXIT_FAILURE);} + num_slots/=128; + fp=vfopen (file, "r"); + while ( (c=fgetc (fp))!=EOF) + { + i = ((i<<7) + c) % num_slots; + } + vfclose (fp); + + return i; + } +int ** r_generate_array_int_list ( int len, int min, int max,int step, int **array, int f, int *n,FILE *fp, int *c_array); +int **generate_array_int_list (int len, int min, int max, int step, int *n, char *file) + { + int **array, *c_array; + FILE *fp=NULL; + + if (n==NULL) + { + array=NULL; + fp=vfopen (file, "w"); + } + else + { + int a,s; + n[0]=0; + for (s=1, a=0; a %d -- %s %s\n", getpid(), getppid(), getpid(), PROGRAM, VERSION); + lock (getpid(), LERROR, LSET, "%d -- COM: %s\n",getpid(),in_cl ); + + // + } + + + if (is_rootpid()) + { + + kill_child_pid(getpid()); + if (has_error_lock()) + { + char *e=NULL; + stack_msg (stderr); + warning_msg (stderr); + e=lock (getpid(), LERROR, LREAD, NULL); + + + + //explicit the most common error messages + if ( strstr (e, "EMAIL"))email_msg (stderr); + if ( strstr (e, "INTERNET"))proxy_msg (stderr); + if ( strstr (e, "PG")) install_msg(stderr); + if ( strstr (e, "COREDUMP")) + { + error_msg (stderr); + dump_error_file(); + } + print_exit_failure_message (); + vfree (e); + } + else if ( has_warning_lock()) + { + warning_msg (stderr); + } + else + print_exit_success_message(); + + if ( (f=get_string_variable ("dump"))) + { + dump_tcoffee (f, "standard dump"); + //unset_string_variable ("dump"); + //unset_string_variable ("dump_output_file"); + //display_output_filename (stdout, "DUMP", "DUMP_4_TCOFFEE",f, CHECK); + } + + + lock (getpid(), LLOCK, LRELEASE, ""); + lock (getpid(), LWARNING, LRELEASE, ""); + lock (getpid(), LERROR, LRELEASE, ""); + } + + + + + add_method_output2method_log (NULL, NULL, NULL, NULL, decode_name (NULL, CODELIST)); + + //Remove all temporary files + debug=(atoigetenv ("DEBUG_TMP_FILE")); + + + + while ( start) + { + if (!debug) + { + + if (isdir(start->name))rrmdir (start->name); + else + { + char test[1000]; + vremove (start->name); + if (start->name)sprintf (test, "%s.dnd", start->name);vremove (test); + if (start->name)sprintf (test, "%s.html",start->name);vremove (test); + } + } + else + { + if (isdir(start->name)) + {fprintf ( stderr, "DEBUG_TMP_FILE SET : Dir %s not removed (%d)\n", start->name, getpid());} + else + {fprintf ( stderr, "DEBUG_TMP_FILE SET : File %s not removed (%d)\n", start->name, getpid());} + } + b=start; + start=start->next; + //vfree(b->name);vfree(b); + } + if (!debug && is_rootpid())my_rmdir (get_tmp_4_tcoffee()); + + + //Remove the lock + //lock (getpid(), LLOCK, LRELEASE,NULL); Now keep the lock unless it is a parent process + + //UNIQUE TERMINATION FOR EVERYBODY!!!!!! + return; +} + + +int cputenv4path (char *p) +{ + if (!p)return 0; + else if (isdir4path (p)) + { + cputenv ("PATH=%s:%s", p, getenv("PATH")); + return 1; + } + else + { + return 0; + } +} + + +int string_putenv ( char *s) +{ + //extract from command line all the occurences -setenv val1 val2 and sets environement + + char *p; + int n; + char *v1, *v2; + + + if (!s) return 0; + v1=vcalloc ( strlen (s)+1, sizeof (char)); + v2=vcalloc ( strlen (s)+1, sizeof (char)); + + p=s; + n=0; + while ( (p=strstr (p, "-setenv"))) + { + if (sscanf (p, "-setenv %s %s", v1,v2)==2) + { + + if (strm (v1, "PATH"))cputenv4path (v2); + else cputenv ( "%s=%s", v1, v2); + } + p+=strlen ("-setenv"); + n++; + } + p=s; + if ( (p=strstr (p, "-plugins"))) + { + sscanf (p, "-plugins %s", v1); + cputenv ("PROXY_4_TCOFFEE=%s",v1); + cputenv4path (v1); + + } + p=s; + if ( (p=strstr (p, "-email"))) + { + sscanf (p, "-email %s", v1); + cputenv ("EMAIL_4_TCOFFEE=%s", v1); + } + p=s; + if ( (p=strstr (p, "-proxy"))) + { + sscanf (p, "-proxy %s", v1); + cputenv ("PROXY_4_TCOFFEE=%s", v1); + } + + + + vfree (v1); vfree (v2); + return n; +} + +char* file_putenv (char *file) +{ + //puts in environement all the variables conatinned in file + //format VAR=value on each line + + char ***list; + int n=0; + + + if (!file || !file_exists(NULL,file)) return NULL; + + list=file2list (file, "\n="); + fprintf ( stderr, "Import Environement Variables from %s\n", file); + + while (list[n]) + { + if ( list[n][1][0]!='#') + { + if ( strm (list[n][1], "PATH")) + { + + cputenv ( "PATH=%s:%s",list[n][2], getenv ("PATH")); + fprintf ( stderr, "\tPATH=%s:$PATH", list[n][2]); + } + else + { + + cputenv("%s=%s", list[n][1],list[n][2]); + fprintf ( stderr, "\t%s=%s", list[n][1],list[n][2]); + } + n++; + } + } + free_arrayN ((void ***)list, 3); + return NULL; + } + +char * bachup_env (char *mode,char *f) +{ + static char *file; + static char *buf; + if (!file) + { + file=vtmpnam (NULL); + buf=vcalloc ( 10000, sizeof (char)); + } + + if (!f)f=file; + if (strm (mode, "DUMP")) + { + printf_system_direct ("/usr/bin/env > %s", f); + return EXIT_SUCCESS; + } + else if ( strm (mode,"RESTAURE") && file_exists (NULL,f)) + { + file_putenv (f); + return EXIT_SUCCESS; + } + return NULL; +} + + +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/util_aln_analyze.c b/binaries/src/tcoffee/t_coffee_source/util_aln_analyze.c new file mode 100644 index 0000000..acdde3a --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/util_aln_analyze.c @@ -0,0 +1,6379 @@ +#include +#include +#include +#include +#include +#include +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "dp_lib_header.h" +#include "define_header.h" +/************************************************************************************/ +/* NEW ANALYZE 2 : SAR */ +/************************************************************************************/ +float display_prediction_old (int **prediction, int n, Alignment *A, Alignment *S, int field); + +float display_prediction (int ***count, Alignment *S, int c, int n); +Alignment * filter_aln4sar0 ( Alignment *A, Alignment *S, int c, int leave, char *mode); +Alignment * filter_aln4sar1 ( Alignment *A, Alignment *S, int c, int leave, char *mode); +Alignment * filter_aln4sar2 ( Alignment *A, Alignment *S, int c, int leave, char *mode); +Alignment * filter_aln4sar3 ( Alignment *A, Alignment *S, int c, int leave, char *mode); +Alignment * filter_aln4sar4 ( Alignment *A, Alignment *S, int c, int leave, char *mode); +Alignment * filter_aln4sar5 ( Alignment *A, Alignment *S, int c, int leave, char *mode); + +int **sar2profile ( Alignment *A, Alignment *S, int c, int leave); +int **sar2profile_sim ( Alignment *A, Alignment *S, int **sim, int comp, int leave); +int sar_profile2score ( char *seq, int **profile); +double sar_vs_iseq1( char *sar, int *seq, float gl, int **sim, char *best_aa); +double sar_vs_seq1 ( char *sar, char *seq, float gl, int **sim, char *best_aa); +double sar_vs_seq2 ( char *sar, char *seq, float ng, int **mat, char *a); +double sar_vs_seq3 ( char *sar, char *seq, float ng, int **mat, char *a); + +double sar_vs_iseq4 ( char *sar, int *seq, float ng, int **mat, char *a);//supports an extended alphabet +double sar_vs_seq4 ( char *sar, char *seq, float ng, int **mat, char *a); + +double sar_vs_seq5 ( char *sar, char *seq, float ng, int **mat, char *a); +int make_sim_pred ( Alignment *A,Alignment *S, int comp, int seq); + +int **sar2profile_sim ( Alignment *A, Alignment *S, int **sim, int comp, int leave) +{ + + int a, b, r, c, c1, c2, r1, r2, s, p; + int ***cache, **profile; + + + profile=declare_int (A->len_aln, 26); + cache=declare_arrayN (3,sizeof (int),2,A->len_aln, 26); + + for ( a=0; a< A->len_aln; a++) + for ( b=0; b< A->nseq; b++) + { + r=tolower(A->seq_al[b][a]); + c=( S->seq_al[comp][b]=='I')?1:0; + if (b==leave || is_gap(r)) continue; + cache [c][a][r-'a']++; + } + for (a=0; a< A->nseq; a++) + { + if ( a==leave) continue; + for ( b=0; b< A->nseq; b++) + { + c1=(S->seq_al[comp][a]=='I')?1:0; + c2=(S->seq_al[comp][b]=='I')?1:0; + if ( b==leave || b==a || c1!=1 || c1==c2) continue; + s=sim[a][b]; + + for (p=0; plen_aln; p++) + { + r1=tolower(A->seq_al[a][p]); + r2=tolower(A->seq_al[b][p]); + if ( is_gap(r1) || is_gap(r2) || r1==r2)continue; + r1-='a';r2-='a'; + if (cache[1][p][r2])continue; + if ( s<50)continue; + profile[p][r2]-=s; + } + } + } + + free_arrayN((void***)cache,3); + return profile; + +} +int **sar2profile ( Alignment *A, Alignment *S, int comp, int leave) +{ + + int a, b,c,r, n, v, npos=0; + int ***cache, **profile; + int ncat; + float n_gap, max_gap; + profile=declare_int (A->len_aln, 26); + cache=declare_arrayN (3,sizeof (int),2,A->len_aln, 26); + + + + for ( n=0, a=0; a< A->nseq; a++) + { + if ( a==leave) continue; + else n+=(S->seq_al[comp][a]=='I')?1:0; + } + + for ( a=0; a< A->len_aln; a++) + for ( b=0; b< A->nseq; b++) + { + r=tolower(A->seq_al[b][a]); + c=( S->seq_al[comp][b]=='I')?1:0; + if (b==leave) continue; + else if (is_gap(r))continue; + r-='a'; + cache [c][a][r]++; + } + + ncat=15; /*ncat: limit the analysis to columns containing less than ncat categories of aa*/ + max_gap=0.05; + for (a=0; a< A->len_aln; a++) + { + for (n_gap=0,b=0; b< A->nseq; b++) + n_gap+=(is_gap(A->seq_al[b][a])); + n_gap/=(float)A->nseq; + + if ( n_gap> max_gap)continue; + + for (v=0,r=0; r< 26; r++) + { + if (cache [0][a][r] || cache[1][a][r])v++; + } + + for (n=0,r=0; r< 26 && vnseq, 2); + list2=declare_int ( inA->len_aln, 2); + + cache=declare_arrayN (3,sizeof (int),inA->len_aln,2, 26); + F=copy_aln (inA, NULL); + + A=copy_aln (inA, NULL); + A->nseq=strlen (S->seq_al[comp]); + + strget_param (mode, "_T1_", "5", "%d", &T1); + for ( a=0; a< A->len_aln; a++) + { + n1=n0=g=0; + for (b=0; b< A->nseq; b++) + { + if ( b==leave) continue; + i=(S->seq_al[comp][b]=='I')?1:0; + r=tolower(A->seq_al[b][a]); + if ( r=='-')continue; + cache[a][i][r-'a']++; + } + } + + for (a=0; a< A->nseq; a++) + for ( score=0,b=0; blen_aln; b++) + { + r=tolower (A->seq_al[a][b]); + if ( is_gap(r))continue; + else if ( cache[b][0][r-'a'] && !cache[b][1][r-'a'])list1[a][0]++; + } + + for (a=0; a< A->len_aln; a++) + { + for ( score=0,b=0; b< A->nseq; b++) + { + r=tolower (A->seq_al[b][a]); + if ( r=='-')continue; + else r-='a'; + if ( cache[a][0][r] && !cache[a][1][r])score ++; + } + list2[a][0]=a; + list2[a][1]=score; + } + sort_int (list2, 2, 1, 0, F->len_aln-1); + + Delta=A->len_aln/(100/T1); + for ( a=0; a< F->len_aln-Delta; a++) + { + b=list2[a][0]; + for ( c=0; cnseq; c++) + { + F->seq_al[c][b]='-'; + } + } + + ungap_aln (F); + free_aln (A); + free_arrayN ( (void ***)cache, 3); + free_arrayN ((void**)list1, 2); + free_arrayN ((void**)list2, 2); + + return F; +} +Alignment * filter_aln4sar2 ( Alignment *inA, Alignment *S, int comp, int leave, char *mode) +{ + Alignment *F, *A; + int a,b,r,ncat; + int *cache; + int max_ncat=10; + + /*Keep Low entropy columns that contain less than ncat categories of different amino acids*/ + /*REmove columns containing 10% or more gaps*/ + + cache=vcalloc ( 500, sizeof (char)); + F=copy_aln (inA, NULL); + A=copy_aln (inA, NULL); + A->nseq=strlen (S->seq_al[comp]); + for ( a=0; a< A->len_aln; a++) + { + for (ncat=0,b=0; b< A->nseq; b++) + { + if ( b==leave) continue; + + r=tolower(A->seq_al[b][a]); + if ( !cache[r])ncat++; + cache[r]++; + } + + if ( ncat nseq)<10) + { + ; + } + else + { + for (b=0; bnseq; b++) + { + r=tolower(F->seq_al[b][a]); + F->seq_al[b][a]='-'; + cache[r]=0; + } + } + for (b=0; bnseq; b++) + { + r=tolower(A->seq_al[b][a]); + cache[r]=0; + } + } + + free_aln (A); + ungap_aln (F); + vfree (cache); + return F; +} + +Alignment * filter_aln4sar3 ( Alignment *inA, Alignment *S, int comp, int leave, char *mode) +{ + Alignment *F, *rA, *A; + int a, b,c; + int **list1; + char *bufS, *bufA; + int Delta; + int T3; + + /*Keep the 10% positions most correlated with the 0/1 pattern*/ + + A=copy_aln (inA, NULL); + A->nseq=strlen (S->seq_al[comp]); + F=copy_aln (inA, NULL); + rA=rotate_aln (A, NULL); + + strget_param (mode, "_T3_", "10", "%d", &T3); + + + list1=declare_int ( inA->len_aln, 2); + bufA=vcalloc ( A->nseq+1, sizeof (char)); + bufS=vcalloc ( A->nseq+1, sizeof (char)); + + sprintf ( bufS, "%s", S->seq_al[comp]); + splice_out_seg(bufS,leave, 1); + + + for (a=0; a< A->len_aln; a++) + { + char aa; + list1[a][0]=a; + sprintf (bufA, "%s", rA->seq_al[a]); + splice_out_seg (bufA,leave,1); + list1[a][1]=(int)sar_vs_seq3 ( bufS, bufA,0,NULL, &aa); + } + + sort_int (list1, 2, 1, 0, F->len_aln-1); + Delta=F->len_aln/(100/T3); + for ( a=0; a< F->len_aln-Delta; a++) + { + b=list1[a][0]; + + for ( c=0; cnseq; c++) + { + F->seq_al[c][b]='-'; + } + + } + F->score_aln=list1[F->len_aln-1][1]; + ungap_aln (F); + + free_aln (rA); + free_aln(A); + free_arrayN ((void**)list1, 2); + vfree (bufS);vfree (bufA); + return F; +} +Alignment * filter_aln4sar4 ( Alignment *inA, Alignment *S, int comp, int leave, char *mode) +{ + Alignment *F, *A; + int a, b,c, i,r, n0, n1,g,score; + int ***cache, **list1, **list2; + + /*Keep only the positions where there are residues ONLY associated with 0 sequences*/ + + list1=declare_int ( inA->nseq, 2); + list2=declare_int ( inA->len_aln, 2); + + cache=declare_arrayN (3,sizeof (int),inA->len_aln,2, 26); + F=copy_aln (inA, NULL); + A=copy_aln (inA, NULL); + A->nseq=strlen (S->seq_al[comp]); + + for ( a=0; a< A->len_aln; a++) + { + n1=n0=g=0; + for (b=0; b< A->nseq; b++) + { + if ( b==leave) continue; + i=(S->seq_al[comp][b]=='I')?1:0; + r=tolower(A->seq_al[b][a]); + if ( r=='-')continue; + cache[a][i][r-'a']++; + n1+=i; + } + } + + + for (a=0; a< A->len_aln; a++) + { + for ( score=0,b=0; b< A->nseq; b++) + { + r=tolower (F->seq_al[b][a]); + if ( r=='-')continue; + else r-='a'; + if (cache[a][1][r]>=n1/2)score=1; + } + list2[a][0]=a; + list2[a][1]=score; + } + + + for ( a=0; a< F->len_aln; a++) + { + if ( list2[a][1]==1); + else + { + b=list2[a][0]; + for ( c=0; cnseq; c++) + { + F->seq_al[c][b]='-'; + } + } + } + ungap_aln (F); + free_aln (A); + free_arrayN ( (void ***)cache, 3); + free_arrayN ((void**)list1, 2); + free_arrayN ((void**)list2, 2); + + return F; +} + +Alignment * filter_aln4sar5 ( Alignment *inA, Alignment *S, int comp, int leave, char *mode) +{ + Alignment *F, *rA, *A; + int a, b,c; + int **list1; + char *bufS, *bufA; + int max; + /*Look for the positions that show the best correlation between the sequence variation and the SAR*/ + + A=copy_aln (inA, NULL); + A->nseq=strlen (S->seq_al[comp]); + + rA=rotate_aln (inA, NULL); + F=copy_aln (inA, NULL); + + list1=declare_int ( A->len_aln, 2); + bufA=vcalloc ( A->nseq+1, sizeof (char)); + bufS=vcalloc ( A->nseq+1, sizeof (char)); + + + + sprintf ( bufS, "%s", S->seq_al[comp]); + splice_out_seg(bufS,leave, 1); + + + for (a=0; a< A->len_aln; a++) + { + char aa; + list1[a][0]=a; + sprintf (bufA, "%s", rA->seq_al[a]); + splice_out_seg (bufA,leave,1); + list1[a][1]=(int)sar_vs_seq4 ( bufS, bufA,0,NULL, &aa); + } + + sort_int (list1, 2, 1, 0, F->len_aln-1); + max=F->score=list1[F->len_aln-1][1]; + max-=(max/10); + + + for ( a=0; a< F->len_aln-10; a++) + { + + b=list1[a][0]; + + for ( c=0; cnseq; c++) + { + F->seq_al[c][b]='-'; + } + + } + F->score_aln=10; + ungap_aln (F); + free_aln (inA); + free_aln (rA); + free_arrayN ((void**)list1, 2); + vfree (bufS);vfree (bufA); + return F; +} + +int sar_profile2score ( char *seq, int **P) +{ + int a,r, l, score; + + l=strlen (seq); + for ( score=0,a=0; a< l; a++) + { + r=seq[a]; + if ( is_gap(r))continue; + score+=P[a][tolower(r)-'a']; + } + return score; +} +int make_sim_pred ( Alignment *A,Alignment *S, int comp, int seq) +{ + int a, b, i, r1, r2; + static float **cscore; + static float **tscore; + + if ( !cscore) + { + cscore=declare_float (2, 2); + tscore=declare_float (2, 2); + } + + for (a=0; a< 2; a++)for (b=0; b<2; b++)cscore[a][b]=tscore[a][b]=0; + + for ( a=0; alen_aln; a++) + { + r1=A->seq_al[seq][a]; + if ( r1=='-') continue; + else + { + for ( b=0; b< A->nseq; b++) + { + if (b==seq) continue; + else + { + r2=A->seq_al[b][a]; + if (r2=='-')continue; + else + { + + i=(S->seq_al[comp][b]=='I')?1:0; + cscore[i][0]+=(r1==r2)?1:0; + cscore[i][1]++; + } + } + } + + for (i=0; i<2; i++) + { + cscore[i][0]/=(cscore[i][1]==0)?1:cscore[i][1]; + tscore[i][0]+=cscore[i][0];tscore[i][1]++; + cscore[i][0]=cscore[i][1]=0; + } + } + } + + fprintf ( stdout, "\nn\t 1: %.2f 0: %.2f", tscore[1][0],tscore[0][0]); + return ( tscore[1][0]>=tscore[0][0])?1:0; +} + + +Alignment * sar_analyze (Alignment *inA, Alignment *inS, char *mode) +{ + int ***sim,***glob_results, ***comp_results; + int *count; + int a,b,c,m; + float *tot2; + Alignment *A=NULL,*S=NULL,*F, *SUBSET; + char *subset, *target; + int jack, T, filter; + filter_func *ff; + int n_methods=0; + char *prediction, *reliability; + int pred_start=0, pred_end, ref_start=0, ref_end; + int display, CSV=1, NONCSV=0; + char method[5]; + + strget_param (mode, "_METHOD_", "1111", "%s_", method); + ff=vcalloc (6,sizeof (filter_func)); + if (method[0]=='1')ff[n_methods++]=filter_aln4sar0; + if (method[1]=='1')ff[n_methods++]=filter_aln4sar1; + if (method[2]=='1')ff[n_methods++]=filter_aln4sar2; + if (method[3]=='1')ff[n_methods++]=filter_aln4sar3; + /* + ff[n_methods++]=filter_aln4sar4; + ff[n_methods++]=filter_aln4sar5; + */ + sim=vcalloc (n_methods, sizeof (int**)); + + + tot2=vcalloc ( 10, sizeof (float)); + subset=vcalloc ( 100, sizeof (char)); + target=vcalloc ( 100, sizeof (char)); + + strget_param (mode, "_TARGET_", "no", "%s_", target); + strget_param (mode, "_SUBSET_", "no", "%s_", subset); + strget_param (mode, "_JACK_", "0", "%d", &jack); + strget_param (mode, "_T_", "0", "%d", &T); + strget_param (mode, "_FILTER_", "11", "%d", &filter); + strget_param (mode, "_DISPLAY_", "0", "%d", &display); + + + + if ( !strm (target, "no")) + { + Alignment *T; + T=main_read_aln(target, NULL); + if ( T->len_aln !=inA->len_aln ) + { + printf_exit ( EXIT_FAILURE,stderr, "Error: %s is incompatible with the reference alignment [FATAL:%s]",target,PROGRAM); + } + + inA=stack_aln (inA, T); + + } + + if ( !strm(subset, "no")) + { + SUBSET=main_read_aln (subset, NULL); + sarset2subsarset ( inA, inS, &A, &S, SUBSET); + } + else + { + A=inA; + S=inS; + } + + + prediction=vcalloc ( n_methods+1, sizeof (char)); + reliability=vcalloc ( n_methods+1, sizeof (char)); + + glob_results=declare_arrayN(3, sizeof (int), n_methods*2, 2, 2); + + count=vcalloc (S->nseq, sizeof (int)); + for (a=0; anseq; a++) + { + int l; + l=strlen (S->seq_al[a]); + for ( b=0; bseq_al[a][b]=='I')?1:0; + } + if ( display==CSV) + {fprintf ( stdout, "\nCompound %s ; Ntargets %d", S->name[a],count[a]); + pred_start=(strlen (S->seq_al[0])==A->nseq)?0:strlen (S->seq_al[0]); + pred_end=A->nseq; + for (a=pred_start; a< pred_end; a++) + fprintf ( stdout, ";%s", A->name[a]); + fprintf ( stdout, ";npred;"); + } + + + for (a=0; anseq; a++) + { + int n_pred; + comp_results=declare_arrayN(3, sizeof (int), n_methods*2, 2, 2); + + pred_start=(strlen (S->seq_al[a])==A->nseq)?0:strlen (S->seq_al[a]); + pred_end=A->nseq; + if ( display==CSV)fprintf ( stdout, "\n%s;%d", S->name[a],count[a]); + + for (n_pred=0,b=pred_start; b%-15s %10s %c ", S->name[a], A->name[b], (pred_start==0)?S->seq_al[a][b]:'?'); + if (jack || b==pred_start) + { + for (m=0; mseq_al[m]); + + for (c=ref_start;cseq_al[a][c]=='O') + { + Nbsim=MAX(Nbsim,sim[m][b][c]); + } + else + { + Ybsim=MAX(Ybsim,sim[m][b][c]); + } + } + + bsim=(Ybsim>Nbsim)?Ybsim:-Nbsim; + pred=(bsim>0)?1:0; + real=(S->seq_al[a][b]=='O')?0:1; + comp_results[m][pred][real]++; + glob_results[m][pred][real]++; + score+=pred; + prediction[m]=pred+'0'; + reliability[m]=(FABS((Ybsim-Nbsim))-1)/10+'0'; + } + + if ( score>0)n_pred++; + prediction[m]=reliability[m]='\0'; + if (display==NONCSV)fprintf ( stdout, "Compound_Count:%d primary_predictions: %s Total: %d", count[a],prediction, score); + else if ( display==CSV)fprintf ( stdout, ";%d", score); + for (t=0; tt) + { + comp_results[t+n_methods][1][real]++; + glob_results[t+n_methods][1][real]++; + } + else + { + comp_results[t+n_methods][0][real]++; + glob_results[t+n_methods][0][real]++; + } + } + } + if ( display==NONCSV) + {if ( pred_start==0)display_prediction (comp_results, S,a, n_methods*2);} + else fprintf (stdout, ";%d;",n_pred); + } + if ( display==NONCSV)if (pred_start==0)display_prediction (glob_results, S,-1, n_methods*2); + + + myexit (EXIT_SUCCESS); +} +float display_prediction (int ***count, Alignment *S, int c, int n) +{ + float tp,tn,fn,fp,sp,sn,sn2; + int a, nm; + + nm=n/2; + + for (a=0; a#Method %d Compound %15s sp=%.2f sn=%.2f sn2=%.2f",a, (c==-1)?"TOTAL":S->name[c],sp, sn, sn2 ); + else fprintf ( stdout, "\n>#Combined: T=%d Compound %15s sp=%.2f sn=%.2f sn2=%.2f",a-nm, (c==-1)?"TOTAL":S->name[c],sp, sn, sn2 ); + } + fprintf ( stdout, "\n"); + return 0; +} + +float display_prediction_2 (int **prediction, int n,Alignment *A, Alignment *S, int field) +{ + int a, t, T; + float max_sn, max_sp; + + if ( field==17 || field ==18) + { + printf_exit ( EXIT_FAILURE, stderr, "\nERROR: Do not use filed %d in display_prediction", field); + } + + sort_int_inv ( prediction, 10,field, 0, n-1); + for (t=0,a=0; a=0; a--) + { + prediction[a][18]=t; + t+=prediction[a][3]; + } + + max_sn=max_sp=T=0; + for (a=0; a0.8) + { + if (sn>max_sn) + { + max_sn=sn; + max_sp=sp; + + T=prediction[a][field]; + } + } + } + if (max_sn==0) + fprintf (stdout, "\n T =%d SN=%.2f SP= %.2f",T,max_sn,max_sp); + else + fprintf (stdout, "\n T =%d SN=%.2f SP= %.2f",T,max_sn,max_sp); + + return max_sn; +} + + +/************************************************************************************/ +/* NEW ANALYZE : SAR */ +/************************************************************************************/ +float** cache2pred1 (Alignment *A,int**cache, int *ns, int **ls, Alignment *S, char *compound, char *mode); +float** cache2pred2 (Alignment *A,int**cache, int *ns, int **ls, Alignment *S, char *compound, char *mode); +float** cache2pred3 (Alignment *A,int**cache, int *ns, int **ls, Alignment *S, char *compound, char *mode); +float** cache2pred4 (Alignment *A,int**cache, int *ns, int **ls, Alignment *S, char *compound, char *mode); +float** cache2pred5 (Alignment *A,int**cache, int *ns, int **ls, Alignment *S, char *compound, char *mode); +float** cache2pred_new (Alignment *A,int**cache, int *ns, int **ls, Alignment *S, char *compound, char *mode); + +int **sar2cache_adriana ( Alignment *A, int *ns,int **ls, Alignment *S, char *compound, char *mode); +int **sar2cache_proba_old ( Alignment *A, int *ns,int **ls, Alignment *S, char *compound, char *mode); +int **sar2cache_count1 ( Alignment *A, int *ns,int **ls, Alignment *S, char *compound, char *mode); +int **sar2cache_count2 ( Alignment *A, int *ns,int **ls, Alignment *S, char *compound, char *mode); +int **sar2cache_count3 ( Alignment *A, int *ns,int **ls, Alignment *S, char *compound, char *mode); + +int **sar2cache_proba_new ( Alignment *A, int *ns,int **ls, Alignment *S, char *compound, char *mode); +int **sar2cache_proba2 ( Alignment *A, int *ns,int **ls, Alignment *S, char *compound, char *mode); +int **analyze_sar_compound1 ( char *name, char *seq, Alignment *A, char *mode); +int **analyze_sar_compound2 ( char *name, char *seq, Alignment *A, char *mode); + +int aln2n_comp_col ( Alignment *A, Alignment *S, int ci); + + + + +int ***simple_sar_analyze_vot ( Alignment *inA, Alignment *SAR, char *mode); +int ***simple_sar_analyze_col ( Alignment *inA, Alignment *SAR, char *mode); + + + +int sarset2subsarset ( Alignment *A, Alignment *S, Alignment **subA, Alignment **subS, Alignment *SUB); +int benchmark_sar (int v); +int aln2jack_group1 (Alignment *A, int seq, int **l1, int *nl1, int **l2, int *nl2); +int aln2jack_group2 (Alignment *A, int seq, int **l1, int *nl1, int **l2, int *nl2); +int aln2jack_group3 (Alignment *A, char *sar_seq, int **l1, int *nl1, int **l2, int *nl2); +float** jacknife5 (Alignment*A,int **cache, int *ns, int **ls, Alignment *S, char *compound, char *mode); +float** jacknife6 (Alignment*A,int **cache, int *ns, int **ls, Alignment *S, char *compound, char *mode); + +int process_cache ( Alignment *A,Alignment *S, int ***Cache, char *mode); +Alignment *analyze_compounds (Alignment *A, Alignment *S, char *mode); + +Alignment *analyze_compounds (Alignment *A, Alignment *S, char *mode) +{ + int a, b, c, tot, n; + int **sim; + int sar1, sar2; + + sim=aln2sim_mat (A, "idmat"); + for (a=0; a< S->nseq; a++) + { + for (n=0, tot=0, b=0; b< A->nseq-1; b++) + { + sar1=(S->seq_al[a][b]=='I')?1:0; + for ( c=b+1; cnseq; c++) + { + sar2=(S->seq_al[a][c]=='I')?1:0; + + if (sar1 && sar2) + { + tot+=sim[b][c]; + n++; + } + } + } + fprintf ( stdout, ">%-10s CMPSIM: %.2f\n", S->name[a],(float)tot/(float)n); + } + free_int (sim, -1); + return A; +} + +int print_seq_pos ( int pos, Alignment *A, char *seq); +int abl1_evaluation (int p); +int print_seq_pos ( int pos, Alignment *A, char *seq) +{ + int a, b, s; + + s=name_is_in_list (seq, A->name, A->nseq, MAXNAMES); + fprintf ( stdout, "S=%d", s); + + for (b=0,a=0; aseq_al[s][a]))b++; + } + fprintf ( stdout, "Pos %d SEQ %s: %d ", pos+1, seq, b+246); + if ( strm ( seq, "ABL1")) fprintf ( stdout , "PT: %d", abl1_evaluation (b+246)); + return 0; +} + +int process_cache ( Alignment *A,Alignment *S, int ***Cache, char *mode) +{ + int a, b; + int **pos, **pos2; + int **C; + int ab1, *ab1_pos; + int weight_mode; + + strget_param ( mode, "_WEIGHT_", "1", "%d", &weight_mode); + pos=declare_int(A->len_aln+1,2); + pos2=declare_int (A->len_aln+1,S->nseq); + for (a=0; anseq; a++) + { + C=Cache[a]; + for (b=0; b< A->len_aln; b++) + { + pos[b][0]+=C[26][b]; + if ( C[26][b]>0) + { + pos[b][1]++; + pos2[b][a]=1; + } + } + } + + C=Cache[0]; + ab1=name_is_in_list ("ABL1", A->name, A->nseq,100); + ab1_pos=vcalloc (A->len_aln+1, sizeof (int)); + + for ( b=0,a=0; a< A->len_aln; a++) + { + if ( A->seq_al[ab1][a]=='-')ab1_pos[a]=-1; + else ab1_pos[a]=++b; + } + + for ( a=0; a< A->len_aln; a++) + { + fprintf ( stdout, "\n%4d %5d %5d %5d [%c] [%2d] ALN", a+1, pos[a][0], pos[a][1], ab1_pos[a]+246,A->seq_al[ab1][a],abl1_evaluation (ab1_pos[a]+246)); + for ( b=0; b< S->nseq; b++)fprintf ( stdout, "%d", pos2[a][b]); + } + return 1; +} +int abl1_evaluation (int p) +{ + if ( p==248) return 10; + if ( p==250) return 10; + if ( p==253) return 10; + if ( p==254) return 10; + if ( p==255) return 9; + if ( p==256) return 10; + if ( p==257) return 5; + if ( p==258) return 8; + if ( p==269) return 8; + if ( p==291) return 4; + if ( p==294) return 8; + if ( p==299) return 10; + if ( p==306) return 0; + if ( p==314) return 9; + if ( p==315) return 10; + if ( p==318) return 10; + + if ( p==319) return 10; + if ( p==321) return 10; + if ( p==323) return 0; + if ( p==324) return 0; + if ( p==339) return 0; + if ( p==340) return 0; + if ( p==355) return 5; + if ( p==364) return 10; + + if ( p==366) return 0; + if ( p==368) return 10; + if ( p==370) return 10; + if ( p==372) return 0; + if ( p==378) return 8; + if ( p==382) return 10; + + if ( p==384) return 10; + if ( p==387) return 10; + if ( p==395) return 8; + + if ( p==398) return 8; + if ( p==399) return 8; + if ( p==400) return 8; + if ( p==403) return 0; + if ( p==416) return 8; + if ( p==419) return 5; + if ( p>400) return 0; + return -1; +} +float** cache2pred1 (Alignment*A,int **cache, int *ns, int **ls, Alignment *S, char *compound, char *mode) +{ + int s1, s2, seq1, seq2, r1, r2,col, pred, real, ci; + double score, max, id, m; + float **R, T; + + + int used_col, used_res,is_used_col, n_res=0; + int weight_mode; + /*Predict on ns[1] what was trained on ns[0]*/ + + strget_param ( mode, "_THR_", "0.09", "%f", &T); + strget_param ( mode, "_WEIGHT_", "0", "%d", &weight_mode); + + R=declare_float (2, 2); + ci=name_is_in_list ( compound, S->name, S->nseq, -1); + + + + for (s1=0; s1len_aln; col++) + { + int max1; + r1=tolower (A->seq_al[seq1][col]); + for (max1=0,id=0, m=0,s2=0; s2seq_al[ci][seq2]=='O')continue; + if ( cache[seq2][col]==0 && !is_gap( A->seq_al[seq2][col]))continue; + + r2=tolower ( A->seq_al[seq2][col]); + if ( is_gap(r2))continue; + + v=(cache[seq2][col]>0 && weight_mode==1)?cache[seq2][col]:1; + + max+=v; + if ( r2==r1) + { + score+=v; + } + + } + + } + pred=(( score/max) >T)?1:0; + real=(S->seq_al[ci][seq1]=='I')?1:0; + R[pred][real]++; + + fprintf ( stdout, "\n>%s %d%d SCORE %.2f C %s [SEQ]\n", A->name[seq1],real, pred, (float)score/(float)max, compound); + } + + for (used_col=0,used_res=0,col=0; collen_aln; col++) + { + for (is_used_col=0,s2=0; s2seq_al[seq2][col]))n_res++; + else if (is_gap(A->seq_al[seq2][col])); + else + { + is_used_col=1; + used_res++; + } + } + used_col+=is_used_col; + } + fprintf ( stdout, "\n>%s USED_POSITIONS: COL: %.2f RES: %.2f COMP\n", S->name[ci], (float)used_col/(float)A->len_aln, (float)used_res/(float) n_res); + + return R; +} + +float** cache2pred2 (Alignment*A,int **cache, int *ns, int **ls, Alignment *S, char *compound, char *mode) +{ + int s1, s2, seq1, seq2, r1, r2,col, pred, real, ci; + double score, max; + float **R, T; + + + int used_col, used_res,is_used_col, n_res=0; + /*Predict on ns[1] what was trained on ns[0]*/ + + strget_param ( mode, "_THR_", "0.5", "%f", &T); + + + R=declare_float (2, 2); + ci=name_is_in_list ( compound, S->name, S->nseq, -1); + + for (s1=0; s1len_aln; col++) + { + int used; + + r1=tolower (A->seq_al[seq1][col]); + for (used=0,s2=0; s2seq_al[ci][seq2]=='O')continue; + if ( cache[seq2][col]==0 && !is_gap( A->seq_al[seq2][col]))continue; + + + r2=tolower ( A->seq_al[seq2][col]); + if ( is_gap(r2))continue; + + v=cache[seq2][col]; + if ( r2==r1){score+=v;} + used=1; + max+=v; + } + if (used) fprintf ( stdout, "%c", r1); + } + + pred=(( score/max) >T)?1:0; + real=(S->seq_al[ci][seq1]=='I')?1:0; + R[pred][real]++; + + fprintf ( stdout, "PSEQ: %-10s SC: %4d MAX: %4d S: %.2f R: %4d", A->name[seq1],(int)score, (int)max, (float)score/max,real); + + } + + for (used_col=0,used_res=0,col=0; collen_aln; col++) + { + for (is_used_col=0,s2=0; s2seq_al[seq2][col]))n_res++; + else if (is_gap(A->seq_al[seq2][col])); + else + { + is_used_col=1; + used_res++; + } + } + used_col+=is_used_col; + } + fprintf ( stdout, "\n>%s USED_POSITIONS: COL: %.2f RES: %.2f COMP\n", S->name[ci], (float)used_col/(float)A->len_aln, (float)used_res/(float) n_res); + + return R; +} + +float** cache2pred3 (Alignment*A,int **cache, int *ns, int **ls, Alignment *S, char *compound, char *mode) +{ + int s1, s2, seq1, seq2, r1, r2,col, pred, real, ci, a, n; + double score, max; + float **R, T; + + + + int tp, tn, fn, fp; + int best_tp, best_fp; + int delta, best_delta; + int **list; + + /*Predict on ns[1] what was trained on ns[0]*/ + + strget_param ( mode, "_THR_", "0.5", "%f", &T); + + + R=declare_float (2, 2); + ci=name_is_in_list ( compound, S->name, S->nseq, -1); + list=declare_int ( ns[1],3); + + for (s1=0; s1len_aln; col++) + { + int used; + + r1=tolower (A->seq_al[seq1][col]); + for (used=0,s2=0; s2seq_al[ci][seq2]=='O')continue; + if ( cache[seq2][col]==0 && !is_gap( A->seq_al[seq2][col]))continue; + + + r2=tolower ( A->seq_al[seq2][col]); + if ( is_gap(r2))continue; + + v=cache[seq2][col]; + if ( r2==r1){score+=v;} + used=1; + max+=v; + } + } + + + + pred=(( score/max) >T)?1:0; + real=(S->seq_al[ci][seq1]=='I')?1:0; + + list[s1][0]=real; + list[s1][1]=(int)((score/max)*(float)1000); + list[s1][2]=seq1; + + + + } + sort_int_inv (list, 3, 1, 0, ns[1]-1); + + for ( a=0; aname[seq1],list[a][0], list[a][1]); + } + + for (n=0, a=0; alen_aln, sizeof (int)); + for (a=0; a< A->len_aln; a++) + for ( b=0; b< A->nseq; b++) + if ( cache[b][a])ul[nused++]=a; + + /*compute the similarity on the used columns*/ + + R=declare_float (2, 2); + sim=declare_int (A->nseq, A->nseq); + for (a=0; a< A->nseq; a++) + for ( b=0; b< A->nseq; b++) + { + for (c=0; c< nused; c++) + { + if ( A->seq_al[a][ul[c]]==A->seq_al[b][ul[c]])sim[a][b]++; + } + sim[a][b]=(sim[a][b]*100)/nused; + } + vfree (ul); + + + + + ci=name_is_in_list ( compound, S->name, S->nseq, -1); + list=declare_int ( ns[1],2); + + for (s1=0; s1seq_al[ci][seq2]=='I')score=MAX(score, sim[seq1][seq2]); + } + list[s1][0]=(S->seq_al[ci][seq1]=='I')?1:0; + list[s1][1]=(int)score; + + } + sort_int_inv (list, 2, 1, 0, ns[1]-1); + + for (n=0, a=0; aname, S->nseq, -1); + list=declare_int ( ns[1],2); + + for (s1=0; s1seq_al[ci][seq2]=='I')score=MAX(score, sim[seq1][seq2]); + } + list[s1][0]=(S->seq_al[ci][seq1]=='I')?1:0; + list[s1][1]=(int)score; + + } + sort_int_inv (list, 2, 1, 0, ns[1]-1); + + for (n=0, a=0; aname, S->nseq, -1); + list=declare_int (A->nseq,2); + R=declare_float (2, 2); + + + for ( a=0; anseq; a++) + { + int real, res; + + ns[0]=A->nseq-1; + ns[1]=1; + for (c=0,b=0; bnseq; b++) + if (a!=b)ls[0][c++]=b; + ls[1][0]=a; + + + cache=sar2cache_count1 (A, ns, ls,S, compound, mode); + for (b=0; b<=26; b++) + for ( c=0; c< A->len_aln; c++) + cacheIN[b][c]+=cache[b][c]; + + seq1=a; + real=(S->seq_al[ci][seq1]=='I')?1:0; + fprintf ( stdout, ">%-10s %d ", A->name[seq1], real); + + + + for (max_score=0,b=0; blen_aln; b++) + max_score+=cache[26][b]; + + for (score=0,b=0; blen_aln; b++) + { + res=tolower (A->seq_al[seq1][b]); + if ( cache[26][b]==0) continue; + if ( !is_gap(res)) + { + score+=cache[res-'a'][b]; + } + /*fprintf ( stdout, "%c[%3d]", res,b);*/ + } + fprintf ( stdout, " SCORE: %5d SPRED %d RATIO: %.2f \n", (int)score, a, (score*100)/max_score); + list[a][0]=real; + + if ( strstr (mode, "SIMTEST"))list[a][1]=(score*100)/max_score; + else list[a][1]=(score*100)/max_score; + free_int (cache, -1); + } + + + sort_int_inv (list, 2, 1, 0, A->nseq-1); + for (n=0, a=0; anseq; a++) + { + n+=list[a][0]; + } + + for (best_delta=100000,best_tp=0,tp=0,fp=0,best_fp=0,a=0; anseq; a++) + { + + tp+=list[a][0]; + fp+=1-list[a][0]; + delta=(n-(tp+fp)); + if (FABS(delta)nseq-(tp+fp+fn); + R[1][1]=tp; + R[1][0]=fp; + R[0][1]=fn; + R[0][0]=tn; + free_int (list, -1); + + return R; +} +float** jacknife6 (Alignment*A,int **cache, int *ns, int **ls, Alignment *S, char *compound, char *mode) +{ + int seq1, ci, a,b, c,d,e,f, n; + double score; + float **R; + + + int tp, tn, fn, fp; + int best_tp, best_fp; + int delta, best_delta; + int **list; + + ci=name_is_in_list ( compound, S->name, S->nseq, -1); + list=declare_int (A->len_aln,2); + R=declare_float (2, 2); + + + for ( a=0; anseq; a++) + { + int sar, res; + int **new_cache; + + ns[0]=A->nseq-1; + ns[1]=1; + for (c=0,b=0; bnseq; b++) + if (a!=b)ls[0][c++]=b; + ls[1][0]=a; + + cache=sar2cache_proba_new (A, ns, ls,S, compound, mode); + + + new_cache=declare_int (27,A->len_aln); + + for (d=0; d< A->len_aln; d++) + { + int **analyze; + if ( cache[26][d]==0)continue; + analyze=declare_int (26, 2); + + for ( e=0; e< ns[0]; e++) + { + f=ls[0][e]; + sar=(S->seq_al[ci][f]=='I')?1:0; + res=tolower (A->seq_al[f][d]); + + if ( res=='-') continue; + analyze[res-'a'][sar]++; + } + for (e=0;e<26; e++) + { + if ( analyze[e][1]){new_cache[26][d]=1;new_cache[e][d]+=cache[e][d];} + /* + if ( analyze[e][0] && analyze[e][1]){new_cache[26][d]=1;new_cache[e][d]+=analyze[e][1];} + else if ( analyze[e][0]){new_cache[26][d]=1;new_cache[e][d]-=analyze[e][0]*10;} + else if ( analyze[e][1]){new_cache[26][d]=1;new_cache[e][d]+=analyze[e][1];} + else if ( !analyze[e][0] &&!analyze[e][1]); + */ + } + free_int (analyze, -1); + } + + seq1=a; + sar=(S->seq_al[ci][seq1]=='I')?1:0; + fprintf ( stdout, ">%-10s %d ", A->name[seq1], sar); + + for (score=0,b=0; blen_aln; b++) + { + res=tolower (A->seq_al[seq1][b]); + if ( cache[26][b]==0) continue; + if ( !is_gap(res)) + { + score+=new_cache[res-'a'][b]; + } + } + fprintf ( stdout, " SCORE: %5d SPRED\n", (int)score); + list[seq1][0]=sar; + list[seq1][1]=(int)score; + + free_int (new_cache, -1); + free_int (cache, -1); + } + sort_int_inv (list, 2, 1, 0, A->nseq-1); + for (n=0, a=0; anseq; a++)n+=list[a][0]; + for (best_delta=100000,best_tp=0,tp=0,fp=0,best_fp=0,a=0; anseq; a++) + { + tp+=list[a][0]; + fp+=1-list[a][0]; + delta=(n-(tp+fp)); + if (FABS(delta)nseq-(tp+fp+fn); + R[1][1]=tp; + R[1][0]=fp; + R[0][1]=fn; + R[0][0]=tn; + free_int (list, -1); + + + return R; +} +float** cache2pred_new (Alignment*A,int **cache, int *ns, int **ls, Alignment *S, char *compound, char *mode) +{ + int s1, seq1, ci, a,b, n; + double score; + float **R; + + + int tp, tn, fn, fp; + int best_tp, best_fp; + int delta, best_delta; + int **list; + + ci=name_is_in_list ( compound, S->name, S->nseq, -1); + list=declare_int ( ns[1],2); + R=declare_float (2, 2); + + for (s1=0; s1seq_al[ci][seq1]=='I')?1:0; + fprintf ( stdout, ">%-10s %d ", A->name[seq1], real); + for (score=0,b=0; blen_aln; b++) + { + res=tolower (A->seq_al[seq1][b]); + if ( cache[26][b]==0) continue; + if ( !is_gap(res)) + { + score+=cache[res-'a'][b]; + } + fprintf ( stdout, "%c", res); + } + fprintf ( stdout, " SCORE: %5d SPRED\n", (int)score); + list[s1][0]=real; + list[s1][1]=(int)score; + } + + sort_int_inv (list, 2, 1, 0, ns[1]-1); + + for (n=0, a=0; aname, S->nseq, -1); + list=declare_int ( ns[1],2); + R=declare_float (2, 2); + + for (s1=0; s1seq_al[ci][seq1]=='I')?1:0; + fprintf ( stdout, ">%-10s %d ", A->name[seq1], real); + for (score=0,b=0; blen_aln; b++) + { + res=tolower (A->seq_al[seq1][b]); + if ( cache[26][b]==0) continue; + if ( !is_gap(res)) + { + score+=cache[res-'a'][b]; + } + fprintf ( stdout, "%c", res); + } + fprintf ( stdout, " SCORE: %5d SPRED\n", (int)score); + list[s1][0]=real; + list[s1][1]=(int)score; + } + new_cache=declare_int (27,A->len_aln); + for (a=0; a< A->len_aln; a++) + { + int **analyze, real, res, d; + int *res_type; + int **sub; + int *keep; + keep=vcalloc ( 26, sizeof (int)); + res_type=vcalloc ( 26, sizeof (int)); + sub=declare_int (256, 2); + + if ( cache[26][a]==0)continue; + analyze=declare_int (26, 2); + for ( b=0; b< ns[0]; b++) + { + seq1=ls[0][b]; + real=(S->seq_al[ci][seq1]=='I')?1:0; + res=tolower (A->seq_al[seq1][a]); + + if ( res=='-') continue; + analyze[res-'a'][real]++; + } + fprintf ( stdout, "RSPRED: "); + for (c=0;c<26; c++)fprintf ( stdout, "%c", c+'a'); + fprintf ( stdout, "\nRSPRED: "); + for (c=0;c<26; c++) + { + if ( analyze[c][0] && analyze[c][1]){fprintf ( stdout, "1");res_type[c]='1';} + else if ( analyze[c][0]){new_cache[26][a]=1;new_cache[c][a]-=analyze[c][0];fprintf ( stdout, "0");res_type[c]='0';} + else if ( analyze[c][1]){new_cache[26][a]=1;new_cache[c][a]+=analyze[c][1];fprintf ( stdout, "1");res_type[c]='1';} + else if ( !analyze[c][0] &&!analyze[c][1]){fprintf ( stdout, "-");res_type[c]='-';} + } + + + for ( c=0; c<26; c++) + { + for ( d=0; d<26; d++) + { + + if ( res_type[c]==res_type[d]) + { + sub[res_type[c]][0]+=mat[c][d]; + sub[res_type[c]][1]++; + } + if ( res_type[c]!='-' && res_type[d]!='-') + { + sub['m'][0]+=mat[c][d]; + sub['m'][1]++; + } + } + } + for ( c=0; c< 256; c++) + { + if ( sub[c][1])fprintf ( stdout, " %c: %5.2f ", c, (float)sub[c][0]/(float)sub[c][1]); + } + fprintf ( stdout, " SC: %d\nRSPRED ", cache[26][a]); + + for ( c=0; c<26; c++) + if ( res_type[c]=='1') + { + for (d=0; d<26; d++) + if (mat[c][d]>0)keep[d]++; + keep[c]=9; + } + + for (c=0; c<26; c++) + { + if ( keep[c]>10)fprintf ( stdout, "9"); + else fprintf ( stdout, "%d", keep[c]); + } + for ( c=0; c<26; c++) + { + if ( keep[c]>8)new_cache[c][a]=10; + else new_cache[c][a]=-10; + } + fprintf ( stdout, "\n"); + free_int (analyze, -1); + free_int (sub, -1); + vfree (res_type); + vfree (keep); + + } + for ( a=0; a<25; a++) + for (b=a+1; b<26; b++) + { + int r1, r2; + r1=a+'a';r2=b+'a'; + if ( strchr("bjoxz", r1))continue; + if ( strchr("bjoxz",r2))continue; + + if ( mat[a][b]>0 && a!=b)fprintf ( stdout, "\nMATANALYZE %c %c %d", a+'a', b+'a', mat[a][b]); + } + + for (s1=0; s1seq_al[ci][seq1]=='I')?1:0; + fprintf ( stdout, ">%-10s %d ", A->name[seq1], real); + for (score=0,b=0; blen_aln; b++) + { + res=tolower (A->seq_al[seq1][b]); + if ( cache[26][b]==0) continue; + if ( !is_gap(res)) + { + score+=new_cache[res-'a'][b]; + } + fprintf ( stdout, "%c", res); + } + fprintf ( stdout, " SCORE: %5d SPRED\n", (int)score); + list[s1][0]=real; + list[s1][1]=(int)score; + } + free_int (new_cache, -1); + sort_int_inv (list, 2, 1, 0, ns[1]-1); + + + for (n=0, a=0; aname, S->nseq, -1); + cache=declare_int (A->nseq, A->len_aln); + + strget_param ( mode, "_FILTER1_", "0" , "%f", &T1); + strget_param ( mode, "_FILTER2_", "1000000", "%f", &T2); + strget_param ( mode, "_FILTER3_", "0" , "%f", &T3); + strget_param ( mode, "_FILTER4_", "1000000", "%f", &T4); + strget_param ( mode, "_SIMWEIGHT_", "1", "%d", &sim_weight); + strget_param ( mode, "_SWTHR_", "30", "%d", &sw_thr); + strget_param (mode, "_TRAIN_","1", "%d", &train_mode); + strget_param (mode, "_ZSCORE_","0", "%f", &zscore); + + + + + + if (sim_weight==1 && !sim) sim=aln2sim_mat(A, "idmat"); + for ( ms=0; msseq_al[ci][mseq]!='I')continue; + + list=declare_int (A->len_aln+1, nfield); + for (t=0,n=0, col=0; col< A->len_aln; col++) + { + int same_res; + + mres=tolower(A->seq_al[mseq][col]); + list[col][RES]=mres; + list[col][COL_INDEX]=col; + + if ( is_gap(mres))continue; + for ( s=0; sseq_al[seq][col]); + if (is_gap(res))continue; + + + if (sim_weight==1) + { + w=sim[seq][mseq];w=(mres==res)?100-w:w; + if (wseq_al[ci][seq]=='I')same_res=1; + else same_res=(res==mres)?1:0; + } + else + same_res=(res==mres)?1:0; + + list[col][N]+=w; + + if (S->seq_al[ci][seq]=='I' && same_res)list[col][N11]+=w; + else if (S->seq_al[ci][seq]=='I' && same_res)list[col][N10]+=w; + else if (S->seq_al[ci][seq]=='O' && same_res)list[col][N01]+=w; + else if (S->seq_al[ci][seq]=='O' && same_res)list[col][N00]+=w; + + if ( S->seq_al[ci][seq]=='I')list[col][N1sar]+=w; + if ( same_res)list[col][N1msa]+=w; + + } + + list[col][SCORE]=(int)evaluate_sar_score1 (list[col][N], list[col][N11], list[col][N1msa], list[col][N1sar]); + + } + + strget_param ( mode, "_MAXN1_", "5", "%d", &maxn1); + strget_param ( mode, "_WEIGHT_", "1", "%d", &weight_mode); + strget_param ( mode, "_QUANT_", "0.0", "%f", &quant); + + sort_int_inv (list,nfield,SCORE,0,A->len_aln-1); + if ( quant !=0) + { + + n=quantile_rank ( list,SCORE, A->len_aln,quant); + sort_int (list,nfield,N1msa, 0, n-1); + maxn1=MIN(n,maxn1); + } + + for (a=0; aT1 && valuelen_aln+1, nfield); + for ( col=0; col< A->len_aln; col++) + { + list[col][COL_INDEX]=col; + for ( s=0; slen_aln; col++) + if (list[col][SCORE]T4) + { + list[col][SCORE]=0; + for (s=0; s< A->nseq; s++) + if (!is_gap(A->seq_al[s][col]))cache[s][col]=0; + } + + /*Keep The N Best Columns*/ + if ( zscore!=0) + { + double sum=0, sum2=0, z; + int n=0; + for (a=0; a< A->len_aln; a++) + { + if ( list[a][SCORE]>0) + { + sum+=list[a][SCORE]; + sum2+=list[a][SCORE]*list[a][SCORE]; + n++; + } + } + for (a=0; alen_aln; a++) + { + if ( list[a][SCORE]>0) + { + z=return_z_score (list[a][SCORE], sum, sum2,n); + if ((float)znseq; s++) + cache [s][col]=0; + } + else + { + fprintf ( stdout, "\nZSCORE: KEEP COL %d SCORE: %f SCORE: %d\n", list[a][COL_INDEX], (float)z, list[a][SCORE]); + } + } + } + } + else + { + sort_int_inv (list,nfield,SCORE,0,A->len_aln-1); + strget_param ( mode, "_MAXN2_", "100000", "%d", &maxn2); + + for (a=maxn2;alen_aln; a++) + { + col=list[a][COL_INDEX]; + for (s=0; snseq; s++) + cache [s][col]=0; + } + } + + /*Get Rid of the N best Columns*/; + strget_param ( mode, "_MAXN3_", "0", "%d", &maxn3); + + for (a=0; anseq; s++) + cache [s][col]=0; + } + + return cache; +} +int aln2n_comp_col ( Alignment *A, Alignment *S, int ci) +{ + int res, seq,sar, col, r; + int **analyze; + + int tot=0; + + analyze=declare_int (27, 2); + for ( col=0; col< A->len_aln; col++) + { + int n1, n0; + + + for ( n1=0, n0=0,seq=0; seqnseq; seq++) + { + res=tolower(A->seq_al[seq][col]); + sar=(S->seq_al[ci][seq]=='I')?1:0; + n1+=(sar==1)?1:0; + n0+=(sar==0)?1:0; + if ( res=='-')continue; + res-='a'; + analyze[res][sar]++; + } + + for (r=0; r<26; r++) + { + int a0,a1; + a0=analyze[r][0]; + a1=analyze[r][1]; + + + if ( a1==n1 && a0len_aln, 2); + cache=declare_int ( 27, A->len_aln); + analyze=declare_int (27, 2); + + ci=name_is_in_list ( compound, S->name, S->nseq, -1); + + for ( col=0; col< A->len_aln; col++) + { + int n1, n0; + + + for ( n1=0, n0=0,s=0; sseq_al[seq][col]); + sar=(S->seq_al[ci][seq]=='I')?1:0; + n1+=(sar==1)?1:0; + n0+=(sar==0)?1:0; + if ( res=='-')continue; + res-='a'; + + analyze[res][sar]++; + } + + for (r=0; r<26; r++) + { + + a0=analyze[r][0]; + a1=analyze[r][1]; + + if ( strstr (mode, "SIMTEST")) + { + w=a1; + } + else if (a1 ) + { + w=n0-a0; + } + else w=0; + + cache[r][col]+=w; + cache[26][col]=MAX(w, cache[26][col]); + } + + for ( r=0; r<26; r++)analyze[r][0]=analyze[r][1]=0; + list[col][0]=col; + list[col][1]=cache[26][col]; + } + + free_int (analyze, -1); + + sort_int_inv (list, 2, 1, 0, A->len_aln-1); + + strget_param ( mode, "_MAXN2_", "100000", "%d", &maxn2); + + for ( col=maxn2; collen_aln; col++) + for ( r=0; r<=26; r++)cache[r][list[col][0]]=0; + + free_int (list, -1); + return cache; +} + + +int **sar2cache_count2 ( Alignment *A, int *ns,int **ls, Alignment *S, char *compound, char *mode) +{ + int maxn2, res, seq,sar, ci, col,s, r; + int **analyze, **list, **cache, **conseq; + static int **mat; + int w=0; + if (!mat) mat=read_matrice ("blosum62mt"); + + + list=declare_int ( A->len_aln, 2); + cache=declare_int ( 27, A->len_aln); + conseq=declare_int ( A->len_aln,3); + + analyze=declare_int (27, 2); + + ci=name_is_in_list ( compound, S->name, S->nseq, -1); + for ( col=0; col< A->len_aln; col++) + { + int n1, n0; + + for ( n1=0, n0=0,s=0; sseq_al[seq][col]); + sar=(S->seq_al[ci][seq]=='I')?1:0; + n1+=(sar==1)?1:0; + n0+=(sar==0)?1:0; + if ( res=='-')continue; + res-='a'; + analyze[res][sar]++; + } + for (r=0; r<26; r++) + { + int a0,a1; + a0=analyze[r][0]; + a1=analyze[r][1]; + if ( a1==n1 && a0len_aln; col++) + { + + res=tolower(A->seq_al[seq][col]); + if ( is_gap(res))continue; + else res-='a'; + + if ( conseq[col][1] && res!=conseq[col][0])w1++; + if ( conseq[col][1])w2++; + } + for (col=0; collen_aln; col++) + { + res=tolower(A->seq_al[seq][col]); + if ( is_gap(res))continue; + else res-='a'; + + if ( conseq[col][1] && res!=conseq[col][0])conseq[col][2]+=(w2-w1); + } + } + + for (col=0; collen_aln; col++) + { + r=conseq[col][0]; + w=conseq[col][2]; + + + cache[r][col]=cache[26][col]=list[col][1]=w; + list[col][0]=col; + } + sort_int_inv (list, 2, 1, 0, A->len_aln-1); + strget_param ( mode, "_MAXN2_", "100000", "%d", &maxn2); + + for ( col=maxn2; collen_aln; col++) + for ( r=0; r<=26; r++)cache[r][list[col][0]]=0; + + + free_int (list, -1); + return cache; +} + +int **sar2cache_count3 ( Alignment *A, int *ns,int **ls, Alignment *S, char *compound, char *mode) +{ + int maxn2, res, seq,sar, ci, col,s, r, a1, a0, n1, n0; + int **analyze, **list, **cache; + static int **mat; + + if (!mat) mat=read_matrice ("blosum62mt"); + + + list=declare_int ( A->len_aln, 2); + cache=declare_int ( 27, A->len_aln); + analyze=declare_int (27, 2); + + ci=name_is_in_list ( compound, S->name, S->nseq, -1); + + for ( col=0; col< A->len_aln; col++) + { + double e, g; + for ( n1=0, n0=0,s=0; sseq_al[seq][col]); + sar=(S->seq_al[ci][seq]=='I')?1:0; + n1+=(sar==1)?1:0; + n0+=(sar==0)?1:0; + if ( res=='-')continue; + res-='a'; + + analyze[res][sar]++; + } + + /*Gap*/ + for (g=0,r=0; rnseq; r++) + g+=is_gap(A->seq_al[r][col]); + g=(100*g)/A->nseq; + + /*enthropy + for (e=0, r=0; r<26; r++) + { + a0=analyze[r][0]; + a1=analyze[r][1]; + t=a0+a1; + + if (t>0) + e+= t/(double)A->nseq*log(t/(double)A->nseq); + } + e*=-1; + */ + e=0; + if (g>10) continue; + if (e>10) continue; + + if ( strstr ( mode, "SIMTEST")) + { + for (r=0; r<26; r++) + { + + a0=analyze[r][0]; + a1=analyze[r][1]; + + if (a1) + { + cache[r][col]=a1; + cache[26][col]=MAX(cache[26][col],a1); + } + } + } + else + { + + + + for (r=0; r<26; r++) + { + + a0=analyze[r][0]; + a1=analyze[r][1]; + + if (!a1 && a0) + { + cache[r][col]=a0; + cache[26][col]=MAX(cache[26][col],a0); + } + } + } + + for ( r=0; r<26; r++)analyze[r][0]=analyze[r][1]=0; + list[col][0]=col; + list[col][1]=cache[26][col]; + } + + free_int (analyze, -1); + + sort_int_inv (list, 2, 1, 0, A->len_aln-1); + + strget_param ( mode, "_MAXN2_", "100000", "%d", &maxn2); + + for ( col=maxn2; collen_aln; col++) + for ( r=0; r<=26; r++)cache[r][list[col][0]]=0; + + free_int (list, -1); + return cache; +} + + +int **sar2cache_proba_new ( Alignment *A, int *ns,int **ls, Alignment *S, char *compound, char *mode) +{ + int col, s, seq,ms,mseq, res, mres, res1, n,maxn1, maxn2,maxn3, t, ci, a,w; + + int **list; + + int N1msa,N1sar, N, N11, N10, N01,N00, SCORE, COL_INDEX, RES; + int nfield=0; + int value; + + + int **cache; + static int **sim; + int sw_thr; + float zscore; + + RES=nfield++;COL_INDEX=nfield++;N1msa=nfield++;N1sar=nfield++;N=nfield++;N11=nfield++;N10=nfield++;N01=nfield++;N00=nfield++;SCORE=nfield++; + ci=name_is_in_list ( compound, S->name, S->nseq, -1); + cache=declare_int (27, A->len_aln); + + strget_param ( mode, "_SWTHR_", "30", "%d", &sw_thr); + strget_param (mode, "_ZSCORE_","0", "%f", &zscore); + + + if (!sim)sim=aln2sim_mat(A, "idmat"); + for ( ms=0; msseq_al[ci][mseq]!='I')continue; + + list=declare_int (A->len_aln+1, nfield); + for (t=0,n=0, col=0; col< A->len_aln; col++) + { + int same_res; + + mres=tolower(A->seq_al[mseq][col]); + if ( is_gap(mres))continue; + + list[col][RES]=mres; + list[col][COL_INDEX]=col; + + for ( s=0; sseq_al[seq][col]); + if (is_gap(res))continue; + w=sim[seq][mseq];w=(mres==res)?100-w:w; + if (wseq_al[ci][seq]=='I' && same_res)list[col][N11]+=w; + else if (S->seq_al[ci][seq]=='I' && same_res)list[col][N10]+=w; + else if (S->seq_al[ci][seq]=='O' && same_res)list[col][N01]+=w; + else if (S->seq_al[ci][seq]=='O' && same_res)list[col][N00]+=w; + + if ( S->seq_al[ci][seq]=='I')list[col][N1sar]+=w; + if ( same_res)list[col][N1msa]+=w; + + } + + list[col][SCORE]=(int)evaluate_sar_score1 (list[col][N], list[col][N11], list[col][N1msa], list[col][N1sar]); + + } + strget_param ( mode, "_MAXN1_", "5", "%d", &maxn1); + sort_int_inv (list,nfield,SCORE,0,A->len_aln-1); + for (a=0; alen_aln+1, nfield); + for ( col=0; col< A->len_aln; col++) + { + list[col][COL_INDEX]=col; + list[col][SCORE]=cache[26][col]; + } + /*Keep The N Best Columns*/ + if ( zscore!=0) + { + double sum=0, sum2=0, z; + int n=0; + for (a=0; a< A->len_aln; a++) + { + if ( list[a][SCORE]>0) + { + sum+=list[a][SCORE]; + sum2+=list[a][SCORE]*list[a][SCORE]; + n++; + } + } + for (a=0; alen_aln; a++) + { + if ( list[a][SCORE]>0) + { + z=return_z_score (list[a][SCORE], sum, sum2,n); + if ((float)zlen_aln-1); + strget_param ( mode, "_MAXN2_", "100000", "%d", &maxn2); + + for (a=maxn2;alen_aln; a++) + { + col=list[a][COL_INDEX]; + for (s=0; s<27; s++) + cache [s][col]=0; + } + } + + /*Get Rid of the N best Columns*/; + strget_param ( mode, "_MAXN3_", "0", "%d", &maxn3); + + for (a=0; aname, S->nseq, -1); + cache=declare_int (A->nseq, A->len_aln); + + + for ( ms=0; msseq_al[ci][mseq]!='I')continue; + + list=declare_int (A->len_aln+1, 5); + for (t=0,n=0, col=0; col< A->len_aln; col++) + { + mres=tolower(A->seq_al[mseq][col]); + list[col][0]=mres; + list[col][1]=col; + + if ( is_gap(mres))continue; + for ( s=0; sseq_al[seq][col]); + if (is_gap(res))continue; + + if (S->seq_al[ci][seq]=='I' && res==mres)list[col][3]++; + if (res==mres)list[col][2]++; + } + } + + sort_int_inv (list,5,3,0,A->len_aln-1); + + strget_param ( mode, "_MAXN1_", "5", "%d", &maxn1); + strget_param ( mode, "_QUANT_", "0.95", "%f", &quant); + + n=quantile_rank ( list, 3, A->len_aln,quant); + sort_int (list, 5, 2, 0, n-1); + + for (a=0; anseq, A->len_aln); + ci=name_is_in_list ( compound, S->name, S->nseq, -1); + + strget_param ( mode, "_FILTER1_", "0" , "%f", &T1); + strget_param ( mode, "_FILTER2_", "1000000", "%f", &T2); + strget_param ( mode, "_FILTER3_", "0" , "%f", &T3); + strget_param ( mode, "_FILTER4_", "1000000", "%f", &T4); + + list=declare_int (A->len_aln+1,A->nseq+2); + SCORE=A->nseq; + COL=A->nseq+1; + + for ( ms=0; msseq_al[ci][mseq]!='I')continue; + + for (t=0,n=0, col=0; col< A->len_aln; col++) + { + int N11=0,N10=0,N01=0,N00=0,N1sar=0,N1msa=0,N=0; + + mres=tolower(A->seq_al[mseq][col]); + if ( is_gap(mres))continue; + for ( s=0; sseq_al[seq][col]); + if (is_gap(res))continue; + + N++; + if (S->seq_al[ci][seq]=='I' && res==mres)N11++; + else if (S->seq_al[ci][seq]=='I' && res!=mres)N10++; + else if (S->seq_al[ci][seq]=='O' && res==mres)N01++; + else if (S->seq_al[ci][seq]=='O' && res!=mres)N00++; + + if ( S->seq_al[ci][seq]=='I')N1sar++; + if ( res==mres)N1msa++; + } + list[col][mseq]=(int)evaluate_sar_score1 (N,N11,N1msa,N1sar); + list[col][SCORE]+=list[col][mseq]; + list[col][COL]=col; + } + } + + strget_param ( mode, "_MAXN1_", "5", "%d", &maxn1); + strget_param ( mode, "_QUANT_", "0.95", "%f", &quant); + sort_int_inv (list,A->nseq+2,SCORE, 0, A->len_aln-1); + n=quantile_rank ( list,A->nseq, A->len_aln,quant); + n=5; + + + for (a=0; anseq; b++) + { + value=list[col][b]; + if ( value>T1 && valuenseq, 2); + seq_list=declare_int (A->nseq, 2); + for (a=0; a< A->nseq; a++) + { + if (comp[a]=='I') + { + sar_list[nsar][0]=a; + sar_list[nsar][1]=rand()%100000; + nsar++; + } + else + { + seq_list[nseq][0]=a; + seq_list[nseq][1]=rand()%100000; + nseq++; + } + } + + + l1[0]=vcalloc (A->nseq, sizeof (int)); + l2[0]=vcalloc (A->nseq, sizeof (int)); + nl1[0]=nl2[0]=0; + + sort_int (seq_list, 2, 1, 0,nseq-1); + sort_int (sar_list, 2, 1, 0,nsar-1); + mid=nsar/2; + for (a=0; anseq, 2); + l1[0]=vcalloc (A->nseq, sizeof (int)); + l2[0]=vcalloc (A->nseq, sizeof (int)); + nl1[0]=nl2[0]; + + vsrand (0); + for ( a=0; a< A->nseq; a++) + { + list[a][0]=a; + list[a][1]=rand()%100000; + } + sort_int (list, 2, 1, 0,A->nseq-1); + mid=A->nseq/2; + for (a=0; anseq; b++, a++) + { + l2[0][nl2[0]++]=list[b][0]; + } + + free_int (list, -1); + return 1; +} +int aln2jack_group1 (Alignment *A, int seq, int **l1, int *nl1, int **l2, int *nl2) +{ + int **sim; + int **list; + int a, mid; + + list=declare_int ( A->nseq, 3); + l1[0]=vcalloc (A->nseq, sizeof (int)); + l2[0]=vcalloc (A->nseq, sizeof (int)); + nl1[0]=nl2[0]; + + sim=aln2sim_mat (A, "idmat"); + for ( a=0; a< A->nseq; a++) + { + list[a][0]=seq; + list[a][1]=a; + list[a][2]=(a==seq)?100:sim[seq][a]; + } + sort_int_inv (list, 3, 2, 0, A->nseq-1); + fprintf ( stderr, "\nJacknife fromsequence %s [%d]\n", A->name[seq], seq); + mid=A->nseq/2; + for (a=0; a< mid; a++) + l1[0][nl1[0]++]=list[a][1]; + for (a=mid; anseq; a++) + l2[0][nl2[0]++]=list[a][1]; + return 1; +} + + +int sarset2subsarset ( Alignment *A, Alignment *S, Alignment **subA, Alignment **subS, Alignment *SUB) +{ + Alignment *rotS, *intS; + int a,b, *list, nl; + + list=vcalloc ( SUB->nseq, sizeof (int)); + for (nl=0,a=0; anseq; a++) + { + b=name_is_in_list(SUB->name[a], A->name, A->nseq, 100); + if ( b!=-1)list[nl++]=b; + } + + subA[0]=extract_sub_aln (A, nl, list); + rotS=rotate_aln (S, NULL); + intS=extract_sub_aln (rotS, nl, list); + + subS[0]=rotate_aln (intS, NULL); + + for ( a=0; anseq; a++) sprintf ( (subS[0])->name[a], "%s", S->name[a]); + + + return 0; +} + +int ***simple_sar_analyze_vot ( Alignment *A, Alignment *SAR, char *mode) +{ + int a, b, c, d; + int res1, res2, sar1, sar2; + float s; + int **sim; + static float ***result; + static int ***iresult; + if (!result) + { + result=declare_arrayN (3,sizeof (float),SAR->nseq, A->len_aln,3); + iresult=declare_arrayN (3,sizeof (int),SAR->nseq, A->len_aln,3); + } + + sim=aln2sim_mat (A, "idmat"); + + + for (a=0; anseq; a++) + for (b=0; blen_aln; b++) + result[a][b][0]=1; + + for ( a=0; a< SAR->nseq; a++) + for ( b=0; bnseq-1; b++) + for ( c=b+1; c< A->nseq; c++) + for ( d=0; dlen_aln; d++) + { + res1=A->seq_al[b][d]; + res2=A->seq_al[c][d]; + + sar1=(SAR->seq_al[a][b]=='I')?1:0; + sar2=(SAR->seq_al[a][c]=='I')?1:0; + + s=sim[b][c]; + + + + + if ( sar1!=sar2 && res1!=res2) + result[a][d][0]*=(1/(100-s)); + + else if ( sar1==sar2 && sar1==1 && res1==res2) + result[a][d][0]*=1/s; + + + + + /* + else if ( sar1==sar2 && res1==res2)result[a][d][0]+=(100-s)*(100-s); + else if ( sar1==sar2 && res1!=res2)result[a][d][0]-=s*s; + else if ( sar1!=sar2 && res1==res2)result[a][d][0]-=(100-s)*(100-s); + */ + + result[a][d][1]='a'; + } + for ( a=0; anseq; a++) + for ( b=0; blen_aln; b++) + { + fprintf ( stderr, "\n%f", result[a][b][0]); + iresult[a][b][0]=100*log(1-result[a][b][0]); + } + return iresult; +} +int display_simple_sar_analyze_pair_col (Alignment *A, Alignment *SAR, char *mode) +{ + int **r; + int a, b, n, do_tm; + + + Alignment *rA; + int *nI; + + + strget_param (mode, "_TM_", "0", "%d", &do_tm); + r=simple_sar_analyze_pair_col (A, SAR,mode); + rA=rotate_aln (A, NULL); + n=0; + + nI=vcalloc ( SAR->nseq, sizeof (int)); + for (a=0; a< SAR->nseq; a++) + for (b=0; blen_aln; b++) nI[a]+=(SAR->seq_al[a][b]=='I')?1:0; + + + + while ( r[n][0]!=-1) + { + if (r[n][3]>0) + {fprintf ( stdout, "COMP S: %3d %3d %s %20s %2d #\n", r[n][3],0,SAR->seq_al[r[n][0]], SAR->name[r[n][0]], nI[r[n][0]]); + fprintf ( stdout, "SEQ1 S: %3d %3d %s %20s %2d #\n", r[n][3],r[n][1],rA->seq_al[r[n][1]], SAR->name[r[n][0]],nI[r[n][0]]); + fprintf ( stdout, "SEQ2 S: %3d %3d %s %20s %2d #\n\n", r[n][3],r[n][2],rA->seq_al[r[n][2]], SAR->name[r[n][0]],nI[r[n][0]]); + } + n++; + } + return 0; +} +int display_simple_sar_analyze_col (Alignment *A, Alignment *SAR, char *mode) +{ + int ***result, **r2, **r3, **r4, **aa; + int a, b, c, n; + char *cons; + int threshold=20; + int do_tm; + strget_param (mode, "_TM_", "0", "%d", &do_tm); + result=simple_sar_analyze_col (A, SAR,mode); + r2=declare_int (A->len_aln*SAR->nseq, 5); + r3=declare_int (A->len_aln+1, 5); + r4=declare_int (A->len_aln+1, SAR->nseq+1); + aa=declare_int (2, 256); + cons=vcalloc (A->len_aln+1, sizeof (char)); + for (a=0; alen_aln; a++){r3[a][0]=a;cons[a]='A';} + + + + for (n=0,a=0; a< SAR->nseq; a++) + { + double sum, sum2; + for (sum=0, sum2=0,b=0; blen_aln; b++) + { + sum+=result[a][b][0]; + sum2+=result[a][b][0]*result[a][b][0]; + } + + for (b=0; blen_aln; b++, n++) + { + r2[n][0]=a;//compound + r2[n][1]=b;//pos + r2[n][2]=result[a][b][1]; //AA + r2[n][3]=result[a][b][0]; //Score + r2[n][4]=result[a][b][2]; //(int)10*return_z_score ((double)result[a][b][0], sum, sum2, A->len_aln); //ZScore + } + } + sort_int (r2,5, 3, 0, n-1);//sort on Score (3rd field) + for ( a=0; a< n; a++) + { + int comp, pos, bad; + + comp=r2[a][0]; + pos=r2[a][1]; + fprintf ( stdout, "SEQ %5d %5d %5d %s ",r2[a][1]+1,r2[a][3], r2[a][4], (do_tm)?alnpos2hmmtop_pred (A, NULL, r2[a][1], SHORT):"x"); + for (c=0; cnseq; c++)fprintf (stdout, "%c", A->seq_al[c][r2[a][1]]); + + + + bad=0; + for (c=0; c< A->nseq; c++) + { + int activity, res; + + activity=SAR->seq_al[comp][c]; + res=A->seq_al[c][pos]; + + if (activity=='O')aa[0][res]++; + if (activity=='I')aa[1][res]++; + } + + for (c=0; c< A->nseq; c++) + { + int activity, res; + activity=SAR->seq_al[comp][c]; + res=A->seq_al[c][pos]; + bad+=(aa[0][res] && aa[1][res])?1:0; + aa[0][res]=aa[1][res]=0; + } + fprintf ( stdout, " %20s %d |\nCOM %5d %5d %5d %s %s %20s %d |\n\n", SAR->name[r2[a][0]],bad,r2[a][1]+1,r2[a][3],r2[a][4], (do_tm)?alnpos2hmmtop_pred (A, NULL, r2[a][1], SHORT):"x",SAR->seq_al[r2[a][0]], SAR->name[r2[a][0]], bad); + + + if (r2[a][4]>threshold) + { + cons[r2[a][1]]++; + r3[r2[a][1]][1]++; + r3[r2[a][1]][2]+=r2[a][3]; + r4[r2[a][1]][r2[a][0]]=1; + } + } + sort_int (r3, 3,1,0, A->len_aln-1); + + for (a=0; alen_aln; a++) + { + if (r3[a][1]>0) + { + fprintf ( stdout, "\nPOS %4d %4d %4d %c ", r3[a][0]+1, r3[a][1], r3[a][2], cons[r3[a][0]]); + for (b=0; bnseq; b++)fprintf ( stdout, "%d", r4[r3[a][0]][b]); + if (do_tm)fprintf ( stdout, " %s",alnpos2hmmtop_pred (A, NULL, r3[a][0], VERBOSE)); + } + } + for (a=0; a< A->nseq; a++)fprintf ( stdout, "\n#MSA >%s\n#MSA %s",A->name[a], A->seq_al[a]); + fprintf ( stdout, "\n#MSA >cons\n#MSA %s", cons); + + return 0; +} +int *** simple_sar_predict (Alignment *A, Alignment *SAR, char *mode) +{ + //This function estimates the z score of every poition with every compound + //The best Z-score position is then used for the prediction + + int a, b, c, nts, pos, Rscore,Zscore; + int ***r; + int ***pred; + int **aa; + + + aa=declare_int (2,256); + pred=declare_arrayN (3, sizeof (int),SAR->nseq, A->nseq, 5); + + + r=simple_sar_analyze_col (A, SAR, mode); + nts=SAR->len_aln; //number_trainning_sequences; + + for (a=0; anseq; a++) + { + sort_int (r[a],4, 2, 0, A->len_aln-1); + + pos=r[a][A->len_aln-1][3]; //Best Position + Zscore=r[a][A->len_aln-1][2]; //Best Z-Score + Rscore=r[a][A->len_aln-1][0]; //Best Z-Score + + + for (c=0; cseq_al[a][c]=='I')aa[1][(int)A->seq_al[c][pos]]++;//Build Positive Alphabet for Compound a + if (SAR->seq_al[a][c]=='O')aa[0][(int)A->seq_al[c][pos]]++;//Build Positive Alphabet for Compound a + } + for (c=nts; cnseq; c++) + { + pred[a][c][0]=pos; + pred[a][c][1]=Zscore; + pred[a][c][2]=Rscore; + if (aa[1][(int)A->seq_al[c][pos]]>0) + { + + pred[a][c][3]=aa[1][(int)A->seq_al[c][pos]]; + pred[a][c][4]=aa[0][(int)A->seq_al[c][pos]]; + } + } + for (c=0; cseq_al[c][pos]]=aa[1][(int)A->seq_al[c][pos]]=0; + } + + for ( a=nts; a< A->nseq; a++) + { + for ( b=0; bnseq; b++) + { + fprintf ( stdout, ">%-25s %-25s Pos %3d ZScore %3d Rscore %3d Activity +: %d -: %d ", A->name [a], SAR->name[b], pred[b][a][0],pred[b][a][1], pred[b][a][2], pred[b][a][3], pred[b][a][4]); + if (pred[b][a][4]==0)for (c=0; cnseq; c++)fprintf ( stdout, "%c", A->seq_al[c][ pred[b][a][0]]); + fprintf ( stdout, " %s\n", SAR->name[b]); + for (c=0; cnseq-1; c++)fprintf ( stdout, "%c", SAR->seq_al[b][c]); + fprintf ( stdout, " %s\n", SAR->name[b]); fprintf ( stdout, "\n"); + + } + } + return pred; +} +int *pair_seq2seq (int *iseq, char *seq1, char *seq2); +int **simple_sar_analyze_pair_col ( Alignment *inA, Alignment *SAR, char *mode) +{ + + int a, b, c, n, n2; + int *iseq=NULL; + static int **result, **fresult; + int sar_mode=1; + int maxgapratio=0; + int nresults=10; + double sum, sum2, score; + Alignment *A; + char aa; + + if (!result) + { + result=declare_int (inA->len_aln*inA->len_aln,5); + + fresult=declare_int (inA->len_aln*nresults*SAR->nseq, 5); + + } + + A=rotate_aln (inA, NULL); + + + for (n2=0,a=0; anseq; a++) + { + + for (n=0, sum=0, sum2=0,b=0; bnseq-1; b++) + { + for ( c=b+1; cnseq; c++, n++) + { + + iseq=pair_seq2seq (iseq,A->seq_al[b], A->seq_al[c]); + if ( sar_mode==1) + score=sar_vs_iseq1(SAR->seq_al[a],iseq,maxgapratio,NULL,&aa); + else if (sar_mode==4) + score=sar_vs_iseq4(SAR->seq_al[a],iseq,maxgapratio,NULL,&aa); + //HERE ("%d", (int)score); + result[n][0]=a;//compound; + result[n][1]=b; //pos1 + result[n][2]=c; //pos2 + result[n][3]=(int)score; + + sum+=score; + sum2+=score*score; + } + } + for (b=0; bnseq, inA->len_aln,4); + + + sim=aln2sim_mat (inA, "idmat"); + A=rotate_aln (inA, NULL); + + + for ( a=0; anseq; a++) + { + best_pos=best_score=0; + for ( sum=0, sum2=0,b=0; bnseq; b++) + { + + if ( sar_mode==1) + score=sar_vs_seq1(SAR->seq_al[a], A->seq_al[b],maxgapratio, sim, &aa); + else if ( sar_mode==2) + score=sar_vs_seq2(SAR->seq_al[a], A->seq_al[b],maxgapratio, sim, &aa); + else if (sar_mode ==3) + score=sar_vs_seq3(SAR->seq_al[a], A->seq_al[b],maxgapratio, sim, &aa); + else if (sar_mode ==4) + score=sar_vs_seq4(SAR->seq_al[a], A->seq_al[b],maxgapratio, sim, &aa); + else if (sar_mode ==5) + score=sar_vs_seq5(SAR->seq_al[a], A->seq_al[b],maxgapratio, sim, &aa); + + + result[a][b][0]+=score*10; + result[a][b][1]=aa; + result[a][b][3]=b; + sum+=result[a][b][0]; + sum2+=result[a][b][0]*result[a][b][0]; + + } + for ( b=0; b< A->nseq; b++)result[a][b][2]=10*return_z_score ((double)result[a][b][0], sum, sum2, A->nseq); //Score + } + + return result; + + } +int *seq2iseq ( char *seq); +double sar_vs_seq4 ( char *sar, char *seq, float gl, int **sim, char *best_aa) +{ + + return sar_vs_iseq4 (sar, seq2iseq(seq), gl, sim, best_aa); +} +double sar_vs_seq1 ( char *sar, char *seq, float gl, int **sim, char *best_aa) +{ + + return sar_vs_iseq1 (sar, seq2iseq(seq), gl, sim, best_aa); +} + +int *seq2iseq ( char *seq) +{ + static int *iseq, clen; + int a; + + if (!iseq || clengl) return 0; + + if (!aa) + { + aa=vcalloc (256*256, sizeof(int)); + aal=vcalloc (N, sizeof (int)); + } + naa=0; + for ( a=0; areturn_score) + { + best_aa[0]=res; + return_score=score; + } + } + } + for ( a=0; agl) return 0; + + //Identify all the AA associated with a I (Positive alphabet) + aa=vcalloc ( 256, sizeof (int)); + for (b=0; b=1 || N01>=1) return 0; + if (N11) + { + score=evaluate_sar_score1 ( N, N11, Nmsa, Nsar); + } + else score=0; + + vfree (aa); + return score; + +} + + + +double sar_vs_iseq4 ( char *sar, int *seq, float gl, int **sim, char *best_aa) +{ + int N, Ni, No; + int a, b,c, r, s; + double Ng=0; + static int **aa; + + /*Correlation between AA conservation and Activity*/ + + N=strlen (sar); + for (a=0; agl) return 0; + + + if (!aa)aa=declare_int(2,257*257); + for (No=Ni=b=0; bgl) return 0; + + //Identify all the AA associated with a I (Positive alphabet) + aa=vcalloc ( 256, sizeof (int)); + for (b=0; bgl) return 0; + for (a=0; a<26; a++) + { + + N=Nmsa=Nsar=N11=N10=N01=0; + res='a'+a; + for (d=0,b=0; bmax_depth) + { + printf_exit (EXIT_FAILURE, stderr,"maximum depth: %d", max_depth); + } + if ( depth==0) depth=2; + A=declare_aln2 (strlen (S1->seq[0]),depth); + a0=A->seq_al[0]; + a1=A->seq_al[1]; + A->len_aln=strlen (S1->seq[0]); + + for (a=0; a< S1->nseq; a++) + for ( b=0; bnseq; b++) + { + A->nseq=2; + sprintf (a0, "%s", S1->seq[a]); + sprintf (a1, "%s", S2->seq[b]); + + if ( strlen (a0)!=strlen (a1)) + { + add_warning (stderr, "WARNING %s (%d) and %s (%d) do not have the same length", S1->name[a], strlen (S1->seq[a]), S2->name[b], strlen (S2->seq[b])); + myexit (EXIT_FAILURE); + } + + fprintf ( stdout, ">2 %15s %15s CORR: %.3f EVAL: %5d\n",S1->name[a], S2->name[b], sar_aln2cor (A), sar_aln2ev (A)); + sarseq2anti_sarseq (S1->seq[a],a0); + fprintf ( stdout, ">2 %15s %15s ANTI: %.3f EVAL: %5d\n", S1->name[a], S2->name[b], sar_aln2cor (A), sar_aln2ev (A)); + if ( depth >=3) + { + A->nseq=3; + a2=A->seq_al[2]; + for (c=b+1; cnseq; c++) + { + sprintf (a0, "%s", S1->seq[a]); + sprintf (a1, "%s", S2->seq[b]); + sprintf (a2, "%s", S2->seq[c]); + fprintf ( stdout, ">2 %15s %15s %15s CORR: %.3f EVAL: %5d\n",S1->name[a], S2->name[b],S2->name[c], sar_aln2cor (A), sar_aln2ev (A)); + sarseq2anti_sarseq (S1->seq[a],a0); + fprintf ( stdout, ">2 %15s %15s %15s ANTI: %.3f EVAL: %5d\n", S1->name[a], S2->name[b], S2->name[c],sar_aln2cor (A), sar_aln2ev (A)); + } + if ( depth>=4) + { + A->nseq=4; + a3=A->seq_al[2]; + for (d=c+1; dnseq; d++) + { + sprintf (a0, "%s", S1->seq[a]); + sprintf (a1, "%s", S2->seq[b]); + sprintf (a2, "%s", S2->seq[c]); + sprintf (a3, "%s", S2->seq[d]); + + fprintf ( stdout, ">2 %15s %15s %15s %15s CORR: %.3f EVAL: %5d\n",S1->name[a], S2->name[b],S2->name[c],S2->name[d], sar_aln2cor (A), sar_aln2ev (A)); + sarseq2anti_sarseq (S1->seq[a],a0); + fprintf ( stdout, ">2 %15s %15s %15s %15s ANTI: %.3f EVAL: %5d\n", S1->name[a], S2->name[b], S2->name[c],S2->name[d],sar_aln2cor (A), sar_aln2ev (A)); + } + if (depth>=5) + { + A->nseq=5; + a4=A->seq_al[3]; + for (e=d+1; enseq; e++) + { + sprintf (a0, "%s", S1->seq[a]); + sprintf (a1, "%s", S2->seq[b]); + sprintf (a2, "%s", S2->seq[c]); + sprintf (a3, "%s", S2->seq[d]); + sprintf (a4, "%s", S2->seq[d]); + } + } + } + } + } + + return S1; +} +char* sarseq2anti_sarseq (char *seq_in, char *seq_out) +{ + int a; + if (!seq_out)seq_out=vcalloc (strlen (seq_in)+1, sizeof (char)); + for (a=0; anseq-1; a++) + for (b=a+1; bnseq; b++) + { + for (n11=n1=0,c=0; clen_aln; c++) + { + n11+=(A->seq_al[a][c]=='I' && A->seq_al[b][c]=='I'); + n1+= (A->seq_al[a][c]=='I' || A->seq_al[b][c]=='I'); + } + tot_cor+=(n1==0)?0:n11/n1; + n++; + } + tot_cor/=n; + return tot_cor; +} +int sarseq_pair2ev ( char *s1, char *s2,int mode); +int sar_aln2ev (Alignment *A) +{ + float n1, n11; + int a, b, c, tot=0, n=0; + + tot=0; + for (a=0; anseq-1; a++) + for (b=a+1; bnseq; b++) + { + tot+=sarseq_pair2ev (A->seq_al[a], A->seq_al[b], 1); + n++; + } + return tot; +} +int sarseq_pair2ev ( char *s1, char *s2,int mode) +{ + int l, t1, t2, t11,a, n1, n2, s; + if ( (l=strlen (s1))!=strlen (s2)) + { + return -1; + } + if (mode==2) + { + t1=l/2; + t2=l/2; + t11=l/2; + } + else + { + for (t1=t2=t11=0,a=0; an11 || n01>n11)return 0; + + p1= M_chooses_Nlog (n1msa, N) + M_chooses_Nlog (n1sar-n11, N-n1msa) + M_chooses_Nlog (n11, n1msa); + p2=(M_chooses_Nlog (n1msa, N)+ M_chooses_Nlog (n1sar, N)); + p=(p1-p2); + + return -p; + +} +double evaluate_sar_score2 ( int N, int n11, int n1msa, int n1sar) +{ + + + return n11-((n1msa-n11)+(n1sar-n11)); + + if ( n11nseq, sizeof (int**)); + + + list=file2list (weight_file, " "); + + a=b=0; + for (a=0; a< SAR->nseq; a++) + { + b=c=0; + while (list[b]) + { + if ( strm (list[b][1], SAR->name[a]) && atoi (list[b][3])>0)c++; + b++; + } + + weight[a]=declare_int (c+1, 3); + fprintf ( stderr, "\n%s %d", SAR->name[a], c); + b=c=0; + while (list[b]) + { + if ( strm (list[b][1], SAR->name[a]) && atoi (list[b][3])>0) + { + weight[a][c][0]=atoi(list[b][2])-1; + weight[a][c][1]=list[b][5][0]; + weight[a][c][2]=atoi (list[b][3]); + c++; + } + b++; + } + weight[a][c][0]=-1; + } + + for (a=0; anseq; a++) + { + fprintf ( stdout, ">%s\n", A->name[a]); + for ( b=0; b< SAR->nseq; b++) + { + score=seq2weighted_sar_score(A->seq_al[a], weight[b]); + fprintf ( stdout, "%c", (score>limit)?'I':'O'); + } + fprintf (stdout, "\n"); + } + myexit (EXIT_SUCCESS); + return A; +} + +Alignment *display_sar ( Alignment *A, Alignment *SAR, char *compound) +{ + int a,c; + char name[100]; + + c=name_is_in_list ( compound, SAR->name, SAR->nseq, 100); + if ( c==-1)return A; + + for ( a=0; a< A->nseq; a++) + { + sprintf (name, "%s", A->name[a]); + sprintf ( A->name[a], "%c_%s_%s", SAR->seq_al[c][a], name,compound); + } + return A; +} +Alignment *aln2weighted_sar_score ( Alignment *A,Alignment *SAR, char *weight_file, char *compound) +{ + + int a, b, c=0; + int **weight; + + int score; + char reactivity; + char ***list; + + + if ( SAR) + { + c=name_is_in_list (compound, SAR->name, SAR->nseq, 100); + } + + list=file2list (weight_file, " "); + a=b=0; + while (list[a]) + { + if (strm (list[a][1], compound))b++; + a++; + } + weight=declare_int ( b+1, 3); + + + a=b=0; + while (list[a]) + { + if ( !strm (list[a][1], compound) || strm ("TOTPOS", list[a][1])); + else + { + weight[b][0]=atoi(list[a][2])-1; + weight[b][1]=list[a][5][0]; + weight[b][2]=atoi(list[a][3]); + b++; + } + a++; + } + weight[b][0]=-1; + for ( a=0; a< A->nseq; a++) + { + score=seq2weighted_sar_score (A->seq_al[a], weight); + reactivity=(!SAR || c==-1)?'U':SAR->seq_al[c][a]; + + sprintf (A->seq_comment[a], "Compound %-15s Reactivity %c SAR_SCORE %5d", compound,reactivity, (int) score); + + } + return A; +} + +float seq2weighted_sar_score ( char *seq, int **weight) +{ + int a, p, r, w; + float score=0; + + a=0; + while (weight[a][0]!=-1) + { + p=weight[a][0]; + r=weight[a][1]; + w=weight[a][2]; + + if ( is_gap(seq[p])); + else if ( tolower(seq[p])==r)score+=w; + a++; + } + return score; + } + +Alignment * sar2simpred (Alignment *A, Alignment *SAR, char *posfile, char *compound, int L1,int L2 ) +{ + int a, b, c, c1, c2; + int **sim, **sim_ref, npred=0; + float n11, n10, n01, n00; + float sn, sp; + + int tot_sim=0; + int N11=1, N01=2, N10=3, NXX=4, SIM=5; + float ***tot; + int i1, i2; + + + n11=n10=n01=n00=0; + tot=declare_arrayN(3,sizeof (float), 10, 6, 2); + + sim_ref=aln2sim_mat (A, "idmat"); + if (strm (posfile, "all")) + sim=sim_ref; + else + { + Alignment *B; + B=copy_aln ( A,NULL); + B=extract_aln3(B,posfile); + + /*if (B->len_aln==0)L1=100; + else + L1=((B->len_aln-1)*100)/B->len_aln; + + if (L1<=0)L1=100; + */ + sim=aln2sim_mat (B, "idmat"); + } + + for (a=0; a< A->nseq-1; a++) + { + for ( b=a+1; b< A->nseq; b++) + { + for ( c=0; cnseq; c++) + { + if ( (strm (compound, SAR->name[c]) || strm ( compound, "all"))) + { + /*if ( sim_ref[a][b]<30 || sim_ref[a][b]>60)continue;*/ + i1=0; /*sim_ref[a][b]/10;if (i1==10)i1--;*/ + + i2=sim[a][b]; + + + c1=(SAR->seq_al[c][a]=='I')?1:0; + c2=(SAR->seq_al[c][b]=='I')?1:0; + + n11=(c1 && c2)?1:0; + n01=(!c1 && c2)?1:0; + n10=(c1 && !c2)?1:0; + n00=(!c1 && !c2)?1:0; + + tot[i1][N11][0]+=n11; + tot[i1][N01][0]+=n01; + tot[i1][N10][0]+=n10; + /*tot[i1][N00][0]+=n00;*/ + tot[i1][NXX][0]++; + tot[i1][SIM][0]+=sim_ref[a][b]; + + if ( i2>=L1) + { + tot[i1][N11][1]+=n11; + tot[i1][N01][1]+=n01; + tot[i1][N10][1]+=n10; + /*tot[i1][N00][1]+=n00;*/ + tot[i1][NXX][1]++; + tot[i1][SIM][1]+=sim_ref[a][b]; + } + } + } + } + } + + for (a=0; a<1; a++) + { + sp=(tot[a][N11][0])/(tot[a][N11][0]+tot[a][N10][0]); + fprintf ( stdout, "\n%15s N11 %5d SP %.2f ",compound, (int)tot[a][N11][0],sp); + sp=((tot[a][N11][1]+tot[a][N10][1])==0)?1:(tot[a][N11][1])/(tot[a][N11][1]+tot[a][N10][1]); + sn=(tot[a][N11][0]==0)?1:(tot[a][N11][1]/tot[a][N11][0]); + fprintf ( stdout, " N11 %5d SP %.2f SN %.2f SIM %.2f", (int)tot[a][N11][1], sp,sn, (tot[a][SIM][1]/tot[a][NXX][1])); + } + + myexit (EXIT_FAILURE); + sp=((n11+n01)==0)?1:n11/(n11+n01); + sn=((n11+n01)==0)?1:n11/(n11+n10); + + fprintf ( stdout, "\nLimit: %d NPRED %d AVGSIM %d SN %.2f SP %.2f TP %d FP %d FN %d",L1, npred, tot_sim, sn, sp, (int)n11, (int)n01, (int)n10); + myexit (EXIT_SUCCESS); + return A; +} + +Alignment * sar2simpred2 (Alignment *A, Alignment *SAR, char *seqlist, char *posfile, char *compound, int L ) +{ + int a,b, c,c1, c2, p, s; + float n11, n10, n01, n00, n, sn2, prediction,sp, n1, n0, t, entropy, Delta; + int *rlist, *tlist, *pred, *npred, tsim, psim; + int **sim, **sim_ref; + int nr=0; + int nrs; + char *out; + int delta_max; + Alignment *B; + int printall=1; + + out=vcalloc (A->nseq+1, sizeof (char)); + rlist=vcalloc ( A->nseq, sizeof (int)); + tlist=vcalloc ( A->nseq, sizeof (int)); + pred=vcalloc(2, sizeof (int)); + npred=vcalloc(2, sizeof (int)); + + nrs=0; + if ( strm (seqlist, "first")) + { + for ( a=0; anseq; a++) + { + if ( strm ( compound, SAR->name[a])) + { + for ( b=0; bnseq; b++) + { + if ( SAR->seq_al[a][b]=='I') + { + fprintf ( stderr, "COMP: %s REF SEQ: %s\n", A->name[b], compound); + rlist[nrs]=b; + tlist[rlist[nrs]]=1; + nrs++; + break; + } + } + } + } + } + else if (strm (seqlist, "all")) + { + for ( a=0; a< A->nseq; a++) + { + rlist[nrs]=a; + tlist[rlist[a]]=1; + nrs++; + } + } + else if ((a=name_is_in_list ( seqlist, A->name, A->nseq, 100))!=-1) + { + rlist[nrs]=a; + tlist[rlist[nrs]]=1; + nrs++; + } + else + { + Alignment *R; + R=main_read_aln (seqlist, NULL); + for (a=0; anseq; a++) + { + rlist[a]=name_is_in_list( R->name[a], A->name, A->nseq, 100); + tlist[rlist[a]]=1; + } + free_aln (R); + } + + c=name_is_in_list ( compound, SAR->name, SAR->nseq, 100); + + sim_ref=aln2sim_mat (A, "idmat"); + if (strm (posfile, "all")) + { + sim=sim_ref; + B=A; + } + else + { + B=copy_aln ( A,NULL); + B=extract_aln3(B,posfile); + sim=aln2sim_mat (B, "idmat"); + } + + n11=n10=n01=n00=n=n1=n0=0; + delta_max=0; + for (a=0; anseq; a++) + { + if ( tlist[a] && !strm (seqlist, "all")) + out[a]=(SAR->seq_al[c][a]=='I')?'Z':'z';/*SAR->seq_al[c][a];*/ + else + { + + pred[0]=pred[1]=0; + npred[0]=npred[1]=1; + c1=(SAR->seq_al[c][a]=='I')?1:0; + for (nr=0,tsim=0,psim=0,b=0; bseq_al[c][rlist[b]]=='o'); + else + { + c2=(SAR->seq_al[c][rlist[b]]=='I')?1:0; + nr+=c2; + s=sim[a][rlist[b]]; + tsim+=sim_ref[a][rlist[b]]; + psim+=sim[a][rlist[b]]; + if (s>=L) + { + pred[c2]+=s; + npred[c2]++; + } + } + } + + if (c1==0)n0++; + else n1++; + t++; + + + Delta=pred[1]-pred[0]; + + if (Delta<-delta_max){p=0;out[a]= (c1==0)?'O':'o';} + else if (Delta>delta_max){p=1;out[a]=(c1==1)?'I':'i';} + else {p=-1; out[a]=(c1==1)?'U':'u';} + + if ( p==-1); + else if ( p && c1)n11++; + else if ( p && !c1)n10++; + else if ( !p && !c1)n00++; + else if ( !p && c1)n01++; + + if (p!=-1)n++; + if (printall)fprintf ( stdout, ">%-15s %d %c OVERALL_SIM:%d POSITION_SIM %d\n%s\n", B->name[a], c1, out[a],tsim/nrs,psim/nrs,B->seq_al[a]); + } + } + sp=((n11+n10)==0)?1:n11/(n11+n10); + sn2=((n1)==0)?1:n11/n1; + prediction=(n11+n00)/(n1+n0); + entropy=(float)(M_chooses_Nlog (nr, nrs)/M_chooses_Nlog(nrs/2, nrs)); + + fprintf ( stdout, ">%-15s Sp %.2f Sn %.2f Pred %.2f E %.2f\n", compound,sp, sn2,prediction,entropy ); + fprintf ( stdout, "%s\n", out); + + myexit (EXIT_SUCCESS); + return A; +} +/************************************************************************************/ +/* ALIGNMENT ANALYZE : SAR FOR OR */ +/************************************************************************************/ + +void display_or_help(); +void display_or_help() +{ + fprintf ( stdout, "\nor_sar options:"); + fprintf ( stdout, "\n_ORCL_: Command_line in a file"); + + fprintf ( stdout, "\n_ROTATE_ : rotate the sar matrix (if each entry is a compound rather than a sequence)"); + fprintf ( stdout, "\n_JNIT_ : number cycles of Jacknife"); + fprintf ( stdout, "\n_JNSEQ_ : Number of sequences picked up in alignment [0 to keep them all, 10 by default]"); + fprintf ( stdout, "\n_JSAR_ : Number of compounds picked up in the SAR matrix [0 to keep them all => default"); + fprintf ( stdout, "\n_JRSAR_ : Randomization of the SAR file between each JNIT iteration: S, C, R, SC, SR... (S: seq, C, column, R: residue"); + fprintf ( stdout, "\n_JRALN_ : Randomization of the ALN file between each JNIT iteration: S, C, R, SC, SR... (S: seq, C, column, R: residue"); + + + fprintf ( stdout, "\n_NPOS_ : Number of positions used to make the prediction [4 by default]"); + fprintf ( stdout, "\n_DEPTH_ : Depth of the motif degenerated alphabet [Default=2]"); + fprintf ( stdout, "\n_POSFILE_ : Predefined list of positions in a filename, A->nseq); + S=aln2jacknife (S, 0, sarlen); +} +Alignment *or_scan (Alignment *A,Alignment *S, char *pmode) +{ + int l, a,ax,cx, b; + char mode[100]; + int start, offset,w; + int nl, *poslist; + + + fprintf ( stdout, "\nPARAMETERS: %s\n", pmode); + fprintf ( stderr, "\nPARAMETERS: %s\n", pmode); + + strget_param (pmode, "_SW_", "15", "%d",&w); + strget_param (pmode, "_SMINW_", "5", "%d",&start); + strget_param (pmode, "_SSTART_", "5", "%d",&offset); + strget_param (pmode, "_SMODE_", "single", "%s",&mode); + + + l=intlen (A->len_aln); + poslist=vcalloc ( A->len_aln, sizeof (int)); + nl=0; + + for ( a=0; a< A->len_aln; a++)poslist[nl++]=a+1; + + if ( strm (mode, "single")) + { + for ( a=0; alen_aln-2; a++) + { + int c, gap, score; + for (gap=0,c=0; cnseq; c++)gap+=(A->seq_al[c][a]=='-'); + if ( !gap) + { + Alignment *B; + B=extract_aln (A, a+1, a+2); + B=or_sar (B, S, pmode, NO_PRINT); + score=B->score_aln; + free_aln (B); + } + else + { + score=0; + } + fprintf ( stdout, "P: %*d S: %4d\n",l,a+1, score); + //fprintf ( stderr, "P: %*d S: %4d\n",l,a+1, score); + + } + } + else if strm (mode, "scan") + { + + for ( ax=0; axA->len_aln)continue; + if (pend<1 || pend>A->len_aln)continue; + B=extract_aln (A, a-w, a+w); + + B=or_sar (B, S,pmode, NO_PRINT); + + + if (B->score_aln>=best_score){best_score=B->score_aln; best_pos=a;best_w=b;best_start=pstart; best_end=pend;} + free_aln (B); + } + fprintf ( stdout, "P: %*d I: %*d %*d Score: %5d L: %2d\n", l,best_pos, l,best_start+offset, l,best_end, best_score,(best_w*2)+1 ); + } + } + else if ( strm ( mode, "scan_comp")) + { + Alignment *NS=NULL; + int *tresults; + int s, n=0, p1; + int nbest; + int *poscache; + float sc, eval; + int **index; + int **poslist; + int len=1; + float best_sc, best_eval; + int best_pos; + char *best_word; + int sth; + int sev; + + index=aln2pos_simple (A, A->nseq); + strget_param (pmode, "_NPOS_", "1", "%d", &len); + strget_param (pmode, "_STH_", "0", "%d", &sth); + strget_param (pmode, "_SEV_", "0", "%d", &sev); + + if (sev==0)for (a=0, sev=1; alen_aln; + + tresults=vcalloc ( A->len_aln, sizeof (int)); + poscache=vcalloc ( A->len_aln, sizeof (int)); + poslist=generate_array_int_list (len, 0, A->len_aln-1,1, &n, NULL); + for (s=0; slen_aln; s++) + { + + char *word; + NS=aln2block (S, s+1, s+2, NS); + fprintf ( stderr, "\nProcess: %s ...\n", get_compound_name(s, mode)); + + for (best_sc=0,best_pos=0,best_word=NULL,a=0; abest_sc) + { + best_sc=sc; + best_eval=eval; + best_word=word; + best_pos=a; + nbest=1; + } + else if ( word && sc>=best_sc) + { + nbest++; + } + else + vfree (word); + } + nbest/=len; + for (a=0; a<=A->nseq; a++) + { + + + + fprintf (stdout, "\n>%s PPPP: S: %s SC: %d EV: %d NBest: %d W: %s", get_compound_name(s, mode),(a==A->nseq)?"cons":A->name[a],(int)best_sc, (int) best_eval, nbest,best_word); + for ( b=0; bnseq) + { + p1=poslist[best_pos][b]; + if (best_sc>sth && nbest0)p1++; + } + fprintf ( stdout, " %d ", p1); + + } + } + + } + for ( p1=0; p1len_aln;p1++) + fprintf ( stdout, "\n>TOT_P: %d %d", p1+1, tresults[p1]); + } + + else if ( strm ( mode, "scan_comp_old")) + { + Alignment *NS=NULL, *BLOCK=NULL; + int **results, *tresults; + int s, n, p1, p2; + int npos=1; + int *poscache; + + results=declare_int (A->len_aln*A->len_aln, 3); + tresults=vcalloc ( A->len_aln, sizeof (int)); + poscache=vcalloc ( A->len_aln, sizeof (int)); + for (s=0; slen_aln; s++) + { + int count; + NS=aln2block (S, s+1, s+2, NS); + fprintf ( stderr, "\nProcess: %s ...", get_compound_name(s, mode)); + for (n=0,p1=0; p1len_aln-w; p1++, count ++) + { + if ( count == 50){fprintf ( stderr, "*");count=0;} + for ( p2=p1; p2len_aln-w; p2++, n++) + { + poscache[p1]=1; + poscache[p2]=1; + + BLOCK=alnpos2block (A,poscache,BLOCK); + + if ( aln2ngap(BLOCK)<=0)BLOCK=or_sar (BLOCK,NS, pmode, NO_PRINT); + else BLOCK->score_aln=0; + + //if ( BLOCK->score_aln>0)HERE ("P: %d %d %d", p1, p2,BLOCK->score_aln); + results[n][0]=p1; + results[n][1]=p2; + results[n][2]=BLOCK->score_aln; + poscache[p1]=poscache[p2]=0; + + } + } + sort_int_inv (results, 3, 2, 0, n-1); + for (p1=0; p1%s PPPP: %d %d SC: %d", get_compound_name(s, mode), results[p1][0]+1,results[p1][1]+1, results[p1][2]); + fprintf ( stderr, "\n>%s PPPP: %d %d SC: %d", get_compound_name(s, mode), results[p1][0]+1,results[p1][1]+1, results[p1][2]); + tresults[results[p1][0]]++; + tresults[results[p1][1]]++; + } + } + for ( p1=0; p1len_aln;p1++) + if ( tresults[p1])fprintf ( stdout, "\n>TOT_P: %d %d", p1+1, tresults[p1]); + } + + myexit (EXIT_SUCCESS); +} + + +ORP * or_sar_compound(Alignment *A, Alignment *S, char *mode, int print); +ORP* set_orp_name ( ORP* P, char *name); +ORP* set_orp_offset ( ORP* P,int offset); +Alignment * or_sar(Alignment *inA, Alignment *inS, char *mode, int print) +{ + char rsar[4],raln[4], sarmode[100]; + int rotate, a, b, start, end; + ORP **R, *ORS; + Alignment *A, *S; + + if ( mode && (strstr (mode, "help") || strstr (mode, "HELP"))) + display_or_help(); + + strget_param (mode, "_SARMODE_", "single", "%s", &sarmode);//single | all + strget_param (mode, "_RSAR_", "NO", "%s", rsar); + strget_param (mode, "_RALN_", "NO", "%s", raln); + strget_param (mode, "_ROTATE_", "0", "%d", &rotate); + + strget_param (mode, "_START_", "1", "%d", &start);start--; + strget_param (mode, "_END_", "0", "%d", &end); + + A=copy_aln (inA, NULL); + S=copy_aln (inS, NULL); + + if ( end==0)end=A->len_aln; + if ( start!=0 || end!=A->len_aln) + { + int c; + if ( start>=A->len_aln || end<=start || end >A->len_aln) + printf_exit (EXIT_FAILURE, stderr, "ERROR: _START_%d and _END_%d are incompatible with the aln [len=%d][FATAL:%s]", start, end, A->len_aln, PROGRAM); + for (b=0; bnseq; b++) + for (c=0,a=start; aseq_al[b][c]=A->seq_al[b][a]; + A->len_aln=c; + for (b=0; bnseq; b++)A->seq_al[b][c]='\0'; + } + + + S=aln2random_aln (S, rsar); + A=aln2random_aln (A, raln); + + + + if (rotate) + { + Alignment *rS; + + if (S->len_aln!=A->nseq) + printf_exit ( EXIT_FAILURE,stderr, "ERROR: Alignment and SAR matrix are incompatible [FATAL:%s]", PROGRAM); + + rS=rotate_aln (S, NULL); + + for (a=0; a< A->nseq; a++)sprintf (rS->name[a], "%s", A->name[a]); + free_aln (S); + S=rS; + } + + R=vcalloc ( S->len_aln+2, sizeof (ORP*)); + if (strm (sarmode, "all"))R[0]=or_sar_compound (A, S, mode, print); + else if ( strm (sarmode, "single")) + { + for ( a=0; alen_aln; a++) + { + Alignment *NS=NULL; + + NS=aln2block (S, a+1, a+2, NS); + + R[a]=or_sar_compound (A, NS, mode, NO_PRINT); + set_orp_name ((R[a]), get_compound_name (a, mode)); + set_orp_offset(R[a], start); + display_or_summary (R[a], mode, stdout, print); + + } + } + + + + ORS=combine_n_predictions (R, A, S); + + display_or_summary (ORS, mode, stdout, print); + inA->score_aln=(int)(ORS->best*(float)1000); + + free_orp_list (R); + free_orp(ORS); + + return inA; + } +ORP* set_orp_offset ( ORP* P,int offset) +{ + if (!P) return NULL; + else + { + P->offset=offset; + return set_orp_offset(P->PR, offset); + } +} + +ORP* set_orp_name ( ORP* P, char *name) +{ + if (!P) return NULL; + else + { + sprintf ( P->name, "%s", name); + return set_orp_name(P->PR, name); + } +} + +ORP * combine_n_predictions (ORP**R, Alignment *A, Alignment *S) +{ + int a=0; + ORP*N=NULL; + while (R[a]) + { + N=combine_2_predictions (R[a++], N, A, S); + } + sprintf ( N->name, "ALL"); + sprintf ( N->mode, "COMBINED"); + + return N; +} + +ORP *combine_2_predictions ( ORP*IN, ORP *TO,Alignment *A, Alignment *S) +{ + int a; + + if ( !TO) + { + TO=declare_or_prediction (IN->ncomp, IN->nseq, IN->len); + TO->A=A; + TO->S=S; + TO->P=copy_aln(S, NULL); + TO->offset=IN->offset; + TO->ncomp=0; + } + + for (a=0; a< IN->len; a++) + { + TO->pos[a]+=IN->pos[a]; + } + + TO->fp+=IN->fp; + TO->fn+=IN->fn; + TO->tp+=IN->tp; + TO->tn+=IN->tn; + rates2sensitivity (TO->tp, TO->tn, TO->fp, TO->fn, &(TO->sp), &(TO->sn), &(TO->sen2), &(TO->best)); + + + for (a=0; a<(TO->A)->nseq; a++) + { + (TO->P)->seq_al[a][TO->ncomp]=(IN->P)->seq_al[a][0]; + //(TO->S)->seq_al[a][TO->ncomp]=(IN->S)->seq_al[a][0]; + } + TO->ncomp++; + (TO->P)->len_aln=TO->ncomp; + (TO->A)->score_aln=TO->best; + + return TO; +} + + + +ORP * display_or_summary (ORP *CP, char *mode, FILE *fp, int print) +{ + int a; + char *pred; + char *exp; + char *motif; + Alignment *A, *P, *S; + + + + A=CP->A; + P=CP->P; + S=CP->S; + + + + pred=vcalloc ( P->nseq*P->len_aln*2, sizeof (char)); + exp=vcalloc ( P->nseq*P->len_aln*2, sizeof (char)); + motif=vcalloc (CP->len+1, sizeof (char)); + + + + if (P && S) + { + for ( a=0; anseq; a++) + { + strcat (pred,P->seq_al[a]); + strcat (exp, S->seq_al[a]); + } + CP->evalue=profile2evalue(pred, exp); + } + a=0; + while ( CP->motif && CP->motif[a] && CP->motif[0][a][0])strcat (motif, CP->motif[0][a++]); + + if ( print==PRINT) + { + fprintf (fp, "\n>%-10s Mode: %s Accuracy: %6.2f E-value: %6.2f Motif: ",CP->name,CP->mode, CP->best, CP->evalue); + + if (motif[0]) + { + fprintf (fp, " %s",motif); + } + for ( a=0; alen; a++) + { + if ( CP->pos[a]) fprintf ( fp, "\n>%-10s Mode: %s P: cons %3d SC: %4d", CP->name, CP->mode, a+1+CP->offset, CP->pos[a]); + } + fprintf ( fp, "\n"); + } + vfree (pred); vfree(motif); vfree(exp); + if (CP->PR)display_or_summary (CP->PR, mode, fp, print); + return CP; +} + + +ORP * or_sar_compound(Alignment *A, Alignment *S, char *mode, int print) +{ + char rmode[100]; + Alignment *P=NULL; + ORP *PR=NULL; + + strget_param (mode, "_MODE_", "predict", "%s", rmode); + + + + if (strm (rmode, "jack"))P=or_jack (A, S, mode); + else if (strm (rmode, "loo")) PR=or_loo (A, S, mode,NULL, print); + else if (strm (rmode, "comploo")) P=or_comp_loo (A, S, mode,NULL, print); + else if ( strm (rmode, "comppos")){or_comp_pos ( A, S, mode,print);myexit (EXIT_FAILURE); return NULL;} + else if ( strm (rmode, "pos"))P=or_aln2pos_aln ( A, S, mode); + else if ( strm (rmode, "predict"))P=or_predict ( A, S, mode); + else if ( strm (rmode, "self"))PR=or_self_predict ( A, S, mode, NULL, print); + else if ( strm (rmode, "sim"))P=or_sim ( A, S, mode); + + else if ( strm (rmode, "test"))P=or_test ( A, S, mode); + else + { + printf_exit (EXIT_FAILURE, stderr, "ERROR: %s is an unknown mode of or_sar [FATAL:%s]\n", rmode,PROGRAM); + return NULL; + } + + if (!PR) + { + PR=vcalloc (1, sizeof (ORP)); + PR->P=P; + } + return PR; +} +Alignment * or_test ( Alignment *inA, Alignment *inS, char *mode) +{ + return inA; +} + + + +float or_id_evaluate ( Alignment *A, Alignment *S, char *mode, int *pos, int print) +{ + char *w; + float score; + + w=or_id_evaluate2(A,S, mode, pos,print, &score); + + vfree (w); + return score; +} +char* or_id_evaluate2 ( Alignment *A, Alignment *S, char *mode, int *pos, int print, float *rscore) +{ + static char **words; + static int *plist; + char *bword; + + int res, p,nl, w, c, s, exp, pred; + int tp, tn, fp, fn; + float sn, sp, sen2, best, best_score; + + if (!A) + {free_char (words, -1); + vfree (plist); + return NULL; + } + rscore[0]=0; + + plist=pos2list (pos, A->len_aln, &nl); + words=declare_char (A->nseq, nl+1); + bword=vcalloc (nl+1, sizeof (char)); + for (p=0; pnseq; s++) + { + res=A->seq_al[s][plist[p]]; + if (res=='-'){or_id_evaluate2 (NULL, NULL, NULL, NULL, 0, NULL);vfree (bword);return 0;} + words[s][p]=res; + } + } + + for (best_score=0,w=0; wnseq; w++) + { + tp=fp=fn=tn=0; + + for (c=0; clen_aln; c++) + { + for (s=0; snseq; s++) + { + exp=(S->seq_al[s][c]=='I')?1:0; + pred=strm (words[w], words[s]); + if ( exp && pred)tp++; + else if ( exp && !pred)fn++; + else if (!exp && !pred)tn++; + else if (!exp && pred)fp++; + } + } + rates2sensitivity (tp, tn, fp,fn,&sp, &sn, &sen2, &best); + if ( best>best_score) + { + best_score=best; + sprintf (bword, "%s", words[w]); + } + } + rscore[0]=(float)1000*best_score; + or_id_evaluate2 (NULL, NULL, NULL, NULL, 0, NULL); + return bword; +} + +float or_loo_evaluate2 ( Alignment *A, Alignment *S, char *mode, int *pos, int print) +{ + int c, s, p, res, sar; + + int *plist, nl; + int tp, tn, fp, fn; + float sn, sp, sen2, best; + char **words, **positive, **negative; + + tp=tn=fp=fn=0; + plist=pos2list (pos, A->len_aln, &nl); + + words=declare_char (A->nseq, nl+1); + + for (p=0; pnseq; s++) + { + res=A->seq_al[s][plist[p]]; + if (res=='-'){vfree (plist);free_char (words, -1); return 0;} + words[s][p]=res; + } + } + positive=vcalloc ( A->nseq, sizeof (char*)); + negative=vcalloc ( A->nseq, sizeof (char*)); + for (c=0; clen_aln; c++) + { + //Fill the match matrix + for (p=0; pnseq; s++) + { + sar=S->seq_al[s][c]; + if (sar=='I')positive[s]=words[s]; + else if ( sar=='O')negative[s]=words[s]; + } + } + + //Evaluate the scores + for (s=0; s< A->nseq; s++) + { + int pos=0, neg=0, pred; + sar=S->seq_al[s][c]; + positive[s]=negative[s]=NULL; + + if ( name_is_in_list (words[s], positive, A->nseq, nl+1)!=-1) + pos=1; + if ( name_is_in_list (words[s], negative, A->nseq, nl+1)!=-1) + neg=1; + + if (pos & !neg) pred=1; + else pred=0; + + if ( pred && sar=='I')tp++; + else if (!pred && sar=='I')fn++; + else if (!pred && sar=='O')tn++; + else if ( pred && sar=='O')fp++; + + if ( sar=='I')positive[s]=words [s]; + else negative[s]=words[s]; + } + } + + vfree (negative); vfree (positive); + vfree (plist); free_char (words, -1); + rates2sensitivity (tp, tn, fp,fn,&sp, &sn, &sen2, &best); + + return (float)1000*best; +} +float or_loo_evaluate ( Alignment *A, Alignment *S, char *mode, int *pos, int print) +{ + int c, s, p, res, sar; + int **matP,**matN; + int *plist, nl; + int tp, tn, fp, fn; + float sn, sp, sen2, best; + + tp=tn=fp=fn=0; + plist=pos2list (pos, A->len_aln, &nl); + matP=declare_int (nl, 256); + matN=declare_int (nl, 256); + + for (c=0; clen_aln; c++) + { + //Fill the match matrix + for (p=0; pnseq; s++) + { + res=A->seq_al[s][plist[p]]; + sar=S->seq_al[s][c]; + if (res=='-'){vfree (plist); free_int (matP, -1);free_int (matN, -1); return 0;} + if (sar=='I')matP[p][res]++; + if (sar=='O')matN[p][res]++; + } + } + + //Evaluate the scores + for (s=0; s< A->nseq; s++) + { + int scoreP, scoreN; + int pred, valP, valN; + + sar=S->seq_al[s][c]; + for (scoreN=0,scoreP=0,p=0; pseq_al[s][plist[p]]; + + valP=matP[p][res]-(sar=='I')?1:0; + scoreP+=(valP>0)?1:0; + + valN=matN[p][res]-(sar=='O')?1:0; + scoreN+=(valN>0)?1:0; + } + + if ( scoreP==nl && scoreNnseq; s++) + { + res=A->seq_al[s][plist[p]]; + sar=S->seq_al[s][c]; + if (sar=='I')matP[p][res]=0; + else matN[p][res]=0; + } + } + } + + vfree (plist); free_int (matP, -1);free_int (matN, -1); + rates2sensitivity (tp, tn, fp,fn,&sp, &sn, &sen2, &best); + + return (float)1000*best; +} +int* or_comp_pos ( Alignment *inA, Alignment *inS, char *mode,int print) +{ + Alignment *A=NULL, *S=NULL, *inS2=NULL; + int a, b, c; + int *main_pos, *pos=NULL; + + set_sar (inA, inS, mode); + main_pos=vcalloc ( inA->len_aln, sizeof (int)); + + inS2=copy_aln (inS, NULL); + inS2->len_aln=1; + + + + //Run every SAR, one at a time + for ( c=0; c< inS->len_aln; c++) + { + int max, p; + + fprintf ( stdout, ">%d\n", c); + for (a=0; a< inS->nseq; a++) + { + inS2->seq_al[a][0]=inS->seq_al[a][c]; + inS2->seq_al[a][1]='\0'; + } + + vfree (pos); + free_aln (S); + free_aln (A); + + pos=vcalloc (inA->len_aln, sizeof (int)); + A=copy_aln (inA, NULL); + S=copy_aln (inS2, NULL); + set_sar (A,S, mode); + pos=aln2predictive_positions (A, S, mode,PRINT); + + for (max=0,b=0; blen_aln; b++) + { + main_pos[b]+=pos[b]; + if (main_pos[b]>max) + { + max=main_pos[b]; + p=b+1; + } + } + + + for (a=0; anseq; a++) + { + fprintf ( stdout, "\t"); + for ( b=0; blen_aln; b++) + if ( pos[b]) fprintf ( stdout, "%c", A->seq_al[a][b]); + fprintf ( stdout, " %c\n", inS2->seq_al[a][0]); + } + fprintf ( stdout, "\n\tBest: %d %d\n", p, max); + + } + + if (print==PRINT) + { + for ( a=0; alen_aln; a++)fprintf ( stdout, "\nP2: cons %4d %4d [FINAL]", a+1, main_pos[a]); + } + return main_pos; +} +Alignment * or_comp_loo ( Alignment *inA, Alignment *inS, char *mode, int *pos,int print) +{ + int a, b,c, n; + char **keep, **remove; + Alignment *A, *S, *P, *P1, *SEQ, *inS2; + int **main_pos, *compound_pos, **comp_list; + int pos_exists=0; + char *comp_pred, *comp_exp; + int sar_threshold; + + strget_param (mode, "_SARTHRES_", "3", "%d", &sar_threshold); + + if (pos)pos_exists=1; + set_sar (inA, inS, mode); + P=copy_aln (inS, NULL); + keep=declare_char (inA->nseq, MAXNAMES); + remove=declare_char (inA->nseq, MAXNAMES); + + main_pos=declare_int ( inA->len_aln,4); + comp_list=declare_int (inA->len_aln, sizeof (int*)); + inS2=copy_aln (inS, NULL); + inS2->len_aln=1; + + + comp_pred=vcalloc ( inA->nseq+1, sizeof (int)); + comp_exp=vcalloc ( inA->nseq+1, sizeof (int)); + compound_pos=NULL; + //Run every SAR, one at a time + for ( c=0; c< inS->len_aln; c++) + { + for (a=0; a< inS->nseq; a++) + { + inS2->seq_al[a][0]=inS->seq_al[a][c]; + inS2->seq_al[a][1]='\0'; + } + vfree (compound_pos); + compound_pos=vcalloc (inA->len_aln, sizeof (int)); + for (a=0; anseq; a++) + { + char ***motifs; + + A=copy_aln (inA, NULL); + S=copy_aln (inS2, NULL); + + for (n=0,b=0; bnseq; b++) + { + if (b!=a)sprintf (keep[n++ ], "%s", A->name [b]); + } + sprintf ( remove[0], "%s", A->name[a]); + reorder_aln (A,keep, A->nseq-1); + + set_sar (A,S, mode); + if (!pos_exists) + { + pos=aln2predictive_positions (A, S, mode,NO_PRINT); + } + for (b=0; blen_aln; b++) + { + compound_pos[b]+=pos[b]; + } + + motifs=compounds2motifs (A, S, pos,0, mode, NO_PRINT); + + SEQ=copy_aln (inA, NULL); + SEQ=reorder_aln (SEQ, remove, 1); + + P1=aln2prediction (SEQ, motifs, pos); + comp_pred[a]=P1->seq_al[0][0]; + comp_exp[a]=inS2->seq_al[a][0]; + P->seq_al[a][c]=P1->seq_al[0][0]; + + + free_aln (SEQ); + free_aln (S); + free_aln (A); + free_aln (P1); + free_arrayN( (void *)motifs, 3); + if (!pos_exists)vfree (pos); + } + if (print==PRINT) + fprintf ( stdout, ">%-15s SC: %.2f E; %.2f\n%s\n%s\n", get_compound_name(c, mode),profile2sensitivity (comp_pred, comp_exp, NULL, NULL, NULL, NULL),profile2evalue(comp_pred, comp_exp),comp_pred, comp_exp); + for (b=0; blen_aln; b++) + { + main_pos[b][2]+=compound_pos[b]; + if (compound_pos[b])main_pos[b][3]++; + if (profile2evalue(comp_pred, comp_exp)>sar_threshold) + { + main_pos[b][0]+=compound_pos[b]; + if (compound_pos[b]) + { + main_pos[b][1]++; + comp_list[b][0]++; + comp_list[b]=vrealloc (comp_list[b], sizeof (int)*(comp_list[b][0]+1)); + comp_list[b][comp_list[b][0]]=c; + } + } + } + + } + + P->score_aln=(int)((float)1000*evaluate_prediction (P, inS, mode,print)); + + if (print==PRINT) + { + for ( a=0; alen_aln; a++)fprintf ( stdout, "\nP: cons %4d RS: %4d RC: %5d FC: %4d %4d[FINAL]", a+1, main_pos[a][2], main_pos[a][3], main_pos[a][0], main_pos[a][1]); + + for ( a=0; alen_aln; a++) + { + fprintf ( stdout, "\nP: cons %4d RS: %4d RC: %5d FC: %4d %4d CLIST: ", a+1, main_pos[a][2], main_pos[a][3], main_pos[a][0], main_pos[a][1]); + for ( c=1; c<=comp_list[a][0]; c++) + { + fprintf ( stdout, "%s ", get_compound_name(comp_list[a][c], mode)); + } + fprintf ( stdout, " [COMP_LIST]"); + } + } + free_int (main_pos, -1); + free_int (comp_list, -1); + return P; +} + +ORP* or_loo ( Alignment *inA, Alignment *inS, char *mode, int *pos,int print) +{ + int a, b, n; + char **keep, **remove; + Alignment *A, *S, *P, *P1, *SEQ; + + int pos_exists=0; + ORP *PR; + + + + if (pos)pos_exists=1; + set_sar (inA, inS, mode); + PR=declare_or_prediction (inS->nseq, inA->nseq, inA->len_aln); + sprintf (PR->mode, "loo "); + P=copy_aln (inS, NULL); + + + keep=declare_char (inA->nseq, MAXNAMES); + remove=declare_char (inA->nseq, MAXNAMES); + + + PR->A=inA; + PR->P=P; + PR->S=inS; + + for (a=0; anseq; a++) + { + char ***motifs; + + A=copy_aln (inA, NULL); + S=copy_aln (inS, NULL); + + for (n=0,b=0; bnseq; b++) + { + if (b!=a)sprintf (keep[n++ ], "%s", A->name [b]); + } + sprintf ( remove[0], "%s", A->name[a]); + reorder_aln (A,keep, A->nseq-1); + + set_sar (A,S, mode); + + if (!pos_exists) + { + pos=aln2predictive_positions (A, S, mode,print); + + } + + for (b=0; blen_aln; b++) + { + PR->pos[b]+=pos[b]; + } + + motifs=compounds2motifs (A, S, pos,0, mode, print); + + SEQ=copy_aln (inA, NULL); + SEQ=reorder_aln (SEQ, remove, 1); + SEQ->nseq=1; + + P1=aln2prediction (SEQ, motifs, pos); + + + if (print==PRINT) + { + fprintf ( stdout, "\n%s\nPred: %s\nReal: %s\n", P1->name[0], P1->seq_al[0], inS->seq_al[a]); + } + sprintf ( P->seq_al[a], "%s", P1->seq_al[0]); + free_aln (P1); + + + free_aln (SEQ); + free_aln (S); + free_aln (A); + + free_arrayN( (void *)motifs, 3); + if (!pos_exists)vfree (pos); + + } + free_char (keep, -1); + free_char (remove, -1); + + + PR=new_evaluate_prediction (PR, mode,print); + + + PR->PR=or_self_predict(inA, inS, mode,NULL, print); + + if (print==PRINT)for ( a=0; alen_aln; a++)fprintf ( stdout, "\nP: cons %d %d [FINAL]", a+1, PR->pos[a]); + + + + return PR; +} + + + +Alignment * or_jack(Alignment *inA, Alignment *inS, char *mode) +{ + int a,b; + int n_cycles=100; + int subnseq=10; + int subsar=0; + Alignment *A, *S; + int *main_pos,*pos; + char jrsar[10], jraln[10]; + + strget_param (mode, "_JNIT_", "100", "%d", &n_cycles); + strget_param (mode, "_JNSEQ_", "10", "%d", &subnseq); + strget_param (mode, "_JNAR_", "0", "%d", &subsar); + + strget_param (mode, "_JRSAR_", "NO", "%s", jrsar); + strget_param (mode, "_JRALN_", "NO", "%s", jraln); + + + + main_pos=vcalloc ( inA->len_aln, sizeof (int)); + for (a=0; alen_aln; b++)main_pos[b]+=pos[b]; + vfree (pos); + + } + display_pos (A, S, main_pos, mode); + + + return inA; +} + +Alignment * display_pos (Alignment *A, Alignment *S, int *pos,char *mode) +{ + Alignment *B; + int a, b; + int **index; + + int intl; + + intl=intlen (A->len_aln); + index=aln2pos_simple (A, A->nseq); + B=copy_aln (A,NULL); + B->len_aln=0; + for ( a=0; alen_aln; a++) + fprintf ( stdout, "\nP: cons %*d %*d S: %4d [DISPLAY_FULL_POS]", intl,a+1,intl, a+2, pos[a]); + fprintf ( stdout, "\n\n"); + for (a=0; alen_aln; a++) + { + if (pos[a]) + { + for ( b=0; bnseq; b++) + { + B->seq_al[b][B->len_aln]=A->seq_al[b][a]; + if (index[b][a]>0)fprintf ( stdout, "\nP: %s %d %d S: %d [DISPLAY_POS]",A->name[b], index[b][a], index[b][a]+1, pos[a]); + } + B->len_aln++; + fprintf ( stdout, "\nP: cons %d %d S: %d [DISPLAY_POS]", a+1, a+2, pos[a]); + } + } + fprintf ( stdout, "\n"); + for (a=0; anseq; a++)B->seq_al[a][B->len_aln]='\0'; + return B; +} +Alignment * or_aln2pos_aln (Alignment *A, Alignment *S, char *mode) +{ + Alignment *B; + + int *pos; + char outaln[100], outtree[100]; + + + strget_param (mode, "_OUTALN_", "NO", "%s", outaln); + strget_param (mode, "_OUTTREE_", "NO", "%s", outtree); + + set_sar (A, S, mode); + pos=aln2predictive_positions (A, S,mode, PRINT); + + B=display_pos (A, S, pos, mode); + + + if (!strm(outaln, "NO")) vfclose (output_aln (B, vfopen (outaln, "w"))); + if (!strm(outtree, "NO"))vfclose (print_tree (aln2tree(B), "newick", vfopen (outtree, "w"))); + + return B; +} +Alignment * or_sim(Alignment *A, Alignment *S, char *mode) +{ + //Predict all the sequences that are not both in inS and inA + int *pos; + + set_sar (A, S, mode); + pos=aln2predictive_positions (A, S,mode, PRINT); + fprintf ( stdout, "R: %.3f", pos2sim (A,S, pos)); + + myexit (EXIT_SUCCESS); + return A; +} +ORP* or_self_predict(Alignment *A, Alignment *S, char *mode,int *pos, int print) +{ + //Predict all the sequences that are not both in inS and inA + Alignment *P; + char ***motifs; + + + int a; + + int pre_set_pos=0; + ORP *PR; + + + set_sar (A, S, mode); + PR=declare_or_prediction (S->nseq, A->nseq, A->len_aln); + sprintf (PR->mode, "self"); + PR->A=A; + PR->S=S; + + if (!pos) + { + pos=aln2predictive_positions (A, S,mode,print); + pre_set_pos=0; + } + else + pre_set_pos=1; + + for (a=0; a< A->len_aln; a++) + PR->pos[a]=pos[a]; + + + PR->motif=motifs=compounds2motifs (A, S, pos,0, mode, print); + P=PR->P=aln2prediction (A, motifs, pos); + + if (!pre_set_pos)vfree (pos); + + PR=new_evaluate_prediction (PR, mode,print); + return PR; +} + + +Alignment * or_predict(Alignment *inA, Alignment *inS, char *mode) +{ + //Predict all the sequences that are not both in inS and inA + Alignment *P, *A, *S, *T; + char ***motifs; + int *pos; + + int a, b; + + + + + + + A=copy_aln (inA, NULL); + S=copy_aln (inS, NULL); + set_sar (A, S, mode); + + pos=aln2predictive_positions (A, S,mode,PRINT); + motifs=compounds2motifs (A, S, pos,0, mode, PRINT); + T=get_prediction_target (inA, inS, mode); + + + P=aln2prediction (T, motifs, pos); + //recall=evaluate_prediction (S, P, mode); + for ( a=0; alen_aln; a++) + { + for (b=0; bnseq; b++) + { + if (tolower(P->seq_al[b][a])=='i')fprintf (stdout, "\n>%20s %20s %c", T->name [0],get_compound_name (a, mode), P->seq_al[b][a]); + } + } + fprintf ( stdout, "\n"); + return P; +} + +Alignment *get_prediction_target (Alignment *A, Alignment *S, char *param) +{ + char **name; + int n, a; + Alignment *T; + + T=copy_aln (A, NULL); + name=declare_char (A->nseq, 100); + for (n=0,a=0; a< A->nseq; a++) + { + if ( name_is_in_list (A->name[a], S->name, S->nseq, 100)==-1) + { + sprintf (name[n++], "%s", A->name[a]); + } + } + T=reorder_aln (T,name, n); + return T; +} + +Alignment *set_sar (Alignment *A, Alignment *S, char *param) +{ + char **name; + int n, a; + + name=declare_char (A->nseq, 100); + for (n=0,a=0; a< A->nseq; a++) + { + if ( name_is_in_list (A->name[a], S->name, S->nseq, 100)!=-1) + { + sprintf (name[n++], "%s", A->name[a]); + } + } + A=reorder_aln (A,name, n); + S=reorder_aln (S,name, n); + free_char (name, -1); + return S; +} + +ORP* new_evaluate_prediction (ORP *PR, char *mode, int print) +{ + int a,b, i, r, p; + int tp, tn, fp, fn; + float sn, sp, sen2, best; + float tot_best_seq=0; + float tot_best_comp=0; + Alignment *P, *R; + + int ns=0; + float *recall; + + + P=PR->P; + R=PR->S; + + recall=vcalloc (P->len_aln, sizeof (float)); + if (P->len_aln!=R->len_aln) + { + HERE ("Mismatch between number of compounds in prediction and reference"); + myexit (EXIT_FAILURE); + } + if (print==PRINT)fprintf ( stdout, "\n"); + + for (a=0; anseq; a++) + { + tp=tn=fp=fn=0; + if ((i=name_is_in_list (P->name[a], R->name, R->nseq, 100))!=-1) + { + + for (b=0;blen_aln; b++) + { + r=R->seq_al[i][b]; + p=P->seq_al[a][b]; + + if ( p=='I' && r=='I')tp++; + else if ( p=='I' && r=='O')fp++; + else if ( p=='O' && r=='I')fn++; + else if ( p=='O' && r=='O')tn++; + } + rates2sensitivity (tp, tn, fp, fn, &sp, &sn, &sen2, &best); + if (print==PRINT)fprintf (stdout, ">%-s sp: %.2f sn: %.2f sn2: %.2f best: %.2f [SEQ]\n",P->name[a], sp, sn, sen2, best); + if ( best>0) + { + ns++; + tot_best_seq+=best; + } + } + } + if (ns) + { + tot_best_seq/=ns; + } + if (print==PRINT)fprintf ( stdout, ">TotSeq sp: %.2f N: %d[SEQ]\n",tot_best_seq, ns); + + tot_best_comp=0; + for (ns=0,b=0; blen_aln; b++) + { + tp=tn=fp=fn=0; + for (a=0; anseq;a++) + { + if ((i=name_is_in_list (P->name[a], R->name, R->nseq, 100))!=-1) + { + r=R->seq_al[i][b]; + p=P->seq_al[a][b]; + + if ( p=='I' && r=='I'){PR->tp++;tp++;} + else if ( p=='I' && r=='O'){PR->fp++;fp++;} + else if ( p=='O' && r=='I'){PR->fn++;fn++;} + else if ( p=='O' && r=='O'){PR->tn++;tn++;} + } + } + rates2sensitivity (tp, tn, fp, fn, &sp, &sn, &sen2, &best); + + if (print==PRINT) fprintf (stdout, ">%-25s sp: %.2f sn: %.2f sen2: %.2f best: %.2f [COMP]\n",get_compound_name (b, mode), PR->sp, PR->sn, PR->sen2,PR->best); + if ( best>0) + { + ns++; + tot_best_comp+=best; + } + } + + if (ns) + { + tot_best_comp/=ns; + } + rates2sensitivity (PR->tp, PR->tn, PR->fp,PR->fn,&(PR->sp), &(PR->sn), &(PR->sen2), &(PR->best)); + if (print==PRINT)fprintf ( stdout, ">FullTot sp: %.2f sn: %.2f sen2: %.2f best: %.2f N: %d[COMP]\n", PR->sp, PR->sn, PR->sen2,PR->best, ns); + P->score_aln=(int)((float)1000*(PR->best)); + return PR; +} +float evaluate_prediction (Alignment *R, Alignment *P, char *mode, int print) +{ + int a,b, i, r, p; + int tp, tn, fp, fn; + int tot_tp, tot_tn, tot_fp, tot_fn; + float sn, sp, sen2, best; + float tot_sp=0; + float tot_sn=0; + float tot_sen2=0; + float tot_best_seq=0; + float tot_best_comp=0; + float tot_best=0; + + int ns=0; + float *recall; + + + + + recall=vcalloc (P->len_aln, sizeof (float)); + if (P->len_aln!=R->len_aln) + { + HERE ("Mismatch between number of compounds in prediction and reference"); + myexit (EXIT_FAILURE); + } + if (print==PRINT)fprintf ( stdout, "\n"); + for (a=0; anseq; a++) + { + tp=tn=fp=fn=0; + if ((i=name_is_in_list (P->name[a], R->name, R->nseq, 100))!=-1) + { + + for (b=0;blen_aln; b++) + { + r=R->seq_al[i][b]; + p=P->seq_al[a][b]; + + if ( p=='I' && r=='I')tp++; + else if ( p=='I' && r=='O')fp++; + else if ( p=='O' && r=='I')fn++; + else if ( p=='O' && r=='O')tn++; + } + rates2sensitivity (tp, tn, fp, fn, &sp, &sn, &sen2, &best); + if (print==PRINT)fprintf (stdout, ">%-s sp: %.2f sn: %.2f sn2: %.2f best: %.2f [SEQ]\n",P->name[a], sp, sn, sen2, best); + if ( best>0) + { + ns++; + tot_best_seq+=best; + tot_sn+=sn; + tot_sp+=sp; + tot_sen2+=sen2; + } + } + } + if (ns) + { + tot_best_seq/=ns; + tot_sn/=ns; + tot_sp/=ns; + tot_sen2/=ns; + } + if (print==PRINT)fprintf ( stdout, ">Tot sp: %.2f sn: %.2f sen2: %.2f best: %.2f N: %d[SEQ]\n", tot_sp, tot_sn, tot_sen2,tot_best_seq, ns); + + tot_fp=tot_fn=tot_tp=tot_tn=0; + tot_sp=tot_sn=tot_sen2=tot_best_comp=0; + for (ns=0,b=0; blen_aln; b++) + { + tp=tn=fp=fn=0; + for (a=0; anseq;a++) + { + if ((i=name_is_in_list (P->name[a], R->name, R->nseq, 100))!=-1) + { + r=R->seq_al[i][b]; + p=P->seq_al[a][b]; + + if ( p=='I' && r=='I'){tot_tp++;tp++;} + else if ( p=='I' && r=='O'){tot_fp++;fp++;} + else if ( p=='O' && r=='I'){tot_fn++;fn++;} + else if ( p=='O' && r=='O'){tot_tn++;tn++;} + } + } + rates2sensitivity (tp, tn, fp, fn, &sp, &sn, &sen2, &best); + + if (print==PRINT) fprintf (stdout, ">%-25s sp: %.2f sn: %.2f sen2: %.2f best: %.2f [COMP]\n",get_compound_name (b, mode), sp, sn, sen2,best); + recall[b]=sen2; + if ( best>0) + { + ns++; + tot_best_comp+=best; + tot_sn+=sn; + tot_sp+=sp; + tot_sen2+=sen2; + } + } + + if (ns) + { + tot_best_comp/=ns; + tot_sn/=ns; + tot_sp/=ns; + tot_sen2/=ns; + } + rates2sensitivity (tot_tp, tot_tn, tot_fp,tot_fn,&tot_sp, &tot_sn, &tot_sen2, &tot_best); + if (print==PRINT)fprintf ( stdout, ">FullTot sp: %.2f sn: %.2f sen2: %.2f best: %.2f N: %d[COMP]\n", tot_sp, tot_sn, tot_sen2,tot_best, ns); + return tot_best; +} + + + +Alignment * aln2prediction (Alignment *A,char ***motif, int *pos) +{ + int a, b,nc, nl; + int *list; + char **array, **sar; + Alignment *R; + Sequence *S; + nc=read_array_size ((void *)motif, sizeof (char***)); + + + list=pos2list (pos, A->len_aln, &nl); + + + array=declare_char (A->nseq, nl+1); + sar=declare_char(A->nseq, nc+1); + for (a=0; anseq; a++) + { + for (b=0; bseq_al[a][list[b]]; + } + + for (a=0; anseq; b++) + { + + sar[b][a]=(match_motif (array[b], motif[a]))?'I':'O'; + } + } + + + S=fill_sequence_struc (A->nseq,sar,A->name); + R=seq2aln (S, NULL, KEEP_GAP); + free_sequence (S, S->nseq); + free_char (sar, -1); + vfree (list); + free_char (array, -1); + return R; +} + +int * file2pos_list (Alignment *A, char *posfile) +{ + char ***file; + int **index; + int *pos; + int i, n, p; + + //pos_file: + // 1 2 3 4 + + + if ( !check_file_exists (posfile)) + { + printf_exit ( EXIT_FAILURE, stderr, "ERROR: Could not read posfile %s\n", posfile); + } + + file=file2list (posfile, " "); + + index=aln2inv_pos (A); + pos=vcalloc ( A->len_aln, sizeof (int)); + + n=0; + while (file[n]) + { + + if ( !strm (file[n][1], "P:")); + else + { + if ( (strm (file[n][2], "cons"))) + p=atoi(file[n][3])-1; + else + { + i=name_is_in_list ( file[n][2], A->name, A->nseq, MAXNAMES+1); + if (i!=-1) + p=index[i][atoi(file[n][3])]-1; + else p=-1; + } + if (p!=-1)pos[p]+=atoi(file[n][4]); + } + n++; + } + + + free_int (index, -1); + free_arrayN ( (char **)file, 3); + return pos; +} +int * aln2predictive_positions (Alignment *A, Alignment *B, char *mode, int print) +{ + char posmode[100]; + + if (!mode) return NULL; + HERE ("%s", mode); + strget_param (mode, "_POSMODE_", "scan", "%s", posmode); + if ( strm (posmode, "mat"))return aln2predictive_positions_mat (A, B, mode, print); + else if ( strm (posmode, "scan")) return aln2predictive_positions_scan (A, B, mode, print); + else + { + printf_exit (EXIT_FAILURE,stderr, "ERROR: %s is an unknown _POSMODE_ mode",posmode); + return NULL; + } +} + +int * aln2predictive_positions_mat (Alignment *A, Alignment *B, char *mode, int print) + { + int a, b, c,gap, res1, res2, sar1, sar2, npos, s, idscore; + float id1,id2,id3,nid1,nid2,nid3; + int **pos, *fpos; + pos=declare_int (A->len_aln,2); + fpos=vcalloc ( A->len_aln, sizeof (int)); + + strget_param (mode, "_NPOS_", "2", "%d", &npos); + for ( a=0; a< A->len_aln; a++) + { + pos[a][0]=a; + id1=id2=id3=nid1=nid2=nid3=0; + for ( gap=0,b=0; bnseq; b++)gap+=(A->seq_al[b][a]=='-'); + if ( gap>0){pos[a][1]=0;continue;} + + for (s=0; slen_aln; s++) + { + for ( gap=0,b=0; bnseq-1; b++) + { + sar1=B->seq_al[b][s]; + res1=A->seq_al[b][a]; + + for ( c=b+1; cnseq; c++) + { + sar2=B->seq_al[c][s]; + res2=A->seq_al[c][a]; + + idscore=(res1==res2)?1:0; + if ( sar1 == 'I' && sar2=='I'){id1+=idscore;nid1++;} + else if ( sar1 =='0' && sar2=='0'){id2+=idscore;nid2++;} + else {id3+=idscore; nid3++;} + + } + } + id1=(nid1==0)?1:id1/nid1; + id2=(nid1==0)?1:id2/nid2; + id3=(nid3==0)?1:id3/nid3; + pos[a][1]=(int)((float)1000*id1*(1-id3)); + + } + } + + sort_int (pos, 2,1, 0, A->len_aln-1); + for ( a=MAX(0,(A->len_aln-npos));alen_aln; a++) + { + fpos[pos[a][0]]=1; + } + + free_int (pos, -1); + return fpos; + } +int * aln2predictive_positions_scan (Alignment *A, Alignment *B, char *mode, int print) +{ + int a, b, c, best_pos,nl, nplist=0, max, posw; + float best_score, score; + static int *list, *tpos,**plist,*array; + int *pos; + + + char posfile[100]; + char predmode[100]; + char target_posfile[100]; + + + + if (!A) + { + vfree (list); + vfree (tpos); + + free_int (plist, -1); + vfree (array); + return NULL; + } + + strget_param (mode, "_PREDMODE_", "ID", "%s", predmode); + strget_param (mode, "_POSW_", "1", "%d", &posw); + strget_param (mode, "_NPOS_", "2", "%d", &max); + strget_param (mode, "_POSFILE_", "NO", "%s", posfile); + strget_param (mode, "_TPOSFILE_", "NO", "%s", target_posfile); + + if ( !strm(posfile, "NO"))return file2pos_list (A,posfile); + if ( !strm(target_posfile, "NO"))tpos=file2pos_list (A,target_posfile); + else + { + tpos=vcalloc (A->len_aln, sizeof (int)); + for (a=0; alen_aln; a++)tpos[a]=1; + } + + //Declare the positions that are going to be scanned + + + if (posw==1) + { + plist=declare_int (A->len_aln, 2); + nplist=0; + for (a=0; alen_aln; a++) + { + if(tpos[a]) + { + plist[nplist][0]=1; + plist[nplist][1]=a; + nplist++; + } + } + } + else if ( posw==2) + { + nplist=0; + plist=declare_int (A->len_aln*A->len_aln, 3); + for (a=0; alen_aln; a++) + for (b=0; blen_aln; b++) + { + plist[nplist][1]=a; + plist[nplist][2]=b; + plist[nplist][0]=2; + nplist++; + } + } + else if ( posw==3) + { + nplist=0; + plist=declare_int (A->len_aln*A->len_aln*A->len_aln, 3); + for (a=0; alen_aln; a++) + for (b=0; blen_aln; b++) + { + plist[nplist][1]=a; + plist[nplist][2]=b; + plist[nplist][3]=0; + + + plist[nplist][0]=3; + nplist++; + } + } + + + pos=vcalloc ( A->len_aln, sizeof (int)); + if (max==0)max=A->len_aln; + else if ( max==-1) + { + for (a=0; alen_aln; a++)if (tpos[a]){pos[a]=1;} + aln2predictive_positions_scan (NULL, NULL, NULL, 0); + return pos; + } + + + + pos=vcalloc ( A->len_aln, sizeof (int)); + list=vcalloc (A->len_aln, sizeof (int)); + nl=0; + + + + for (a=0; a< max; a++) + { + int previous_best_pos=-1; + for (best_score=-9999,best_pos=0,b=0; bbest_score) + { + best_score=score; + best_pos=b; + } + for (c=1; c<=plist[b][0]; c++)pos[plist[b][c]]=0; + + } + if (best_pos==previous_best_pos)break; + else previous_best_pos=best_pos; + + //update the best_pos_list + for (b=1; b<=plist[best_pos][0]; b++) + list[nl++]=plist[best_pos][b]; + + + if ( print==PRINT) + { + for (b=0; blen_aln, sizeof (char**)); + for (a=0; alen_aln; a++) + { + + motifs[a]=compound2motif (A, B, pos, depth, a, mode, print); + } + + return motifs; +} +char ** compound2regexp_motif (Alignment *A, Alignment *B, int *pos, int depth, int c, char *mode, int print); +char ** compound2word_motif (Alignment *A, Alignment *B, int *pos, int depth, int c, char *mode, int print); + +char ** compound2motif (Alignment *A, Alignment *B, int *pos, int depth, int c, char *mode, int print) +{ + char mmode[100]; + + strget_param (mode, "_MOTIFMODE_", "word", "%s", mmode); //words, regexp + if ( strm (mmode, "regexp"))return compound2regexp_motif (A,B,pos, depth, c, mode, print); + else if ( strm (mmode, "word"))return compound2word_motif (A,B,pos, depth, c, mode, print); + else return NULL;} +char ** compound2word_motif (Alignment *A, Alignment *B, int *pos, int depth, int c, char *mode, int print) +{ + int a,l; + char *word, **motif; + float score; + + + word=or_id_evaluate2 (A, B, mode, pos,print, &score); + if ( !word) return NULL; + l=strlen (word); + + motif=declare_char (l+1, 2); + for (a=0; anseq=O->nseq=I->len_aln=O->len_aln=0; + for (a=0; alen_aln; a++) + { + if (pos[a]) + { + for (i=o=0,b=0; bnseq; b++) + { + if ( is_gap(A->seq_al[b][a]))return 0; + if (B->seq_al[b][c]=='I')I->seq_al[i++][I->len_aln]=A->seq_al[b][a]; + else O->seq_al[o++][O->len_aln]=A->seq_al[b][a]; + } + I->len_aln++; + O->len_aln++; + } + } + + if (O->len_aln==0 || I->len_aln==0) return 0; + O->nseq=o; + I->nseq=i; + for (a=0; aseq_al[a][O->len_aln]='\0'; + for (a=0; aseq_al[a][I->len_aln]='\0'; + + if (!I->nseq) return NULL; + + + + best_pred=best_motif=best_sn=best_sp=best_sen2=0; + + motif_file=vtmpnam (NULL); + + n=0; + if (depth>0) + { + alp=vcalloc ( sizeof (char**), I->len_aln); + alp_size= vcalloc ( I->len_aln, sizeof (int)); + for (a=0; alen_aln; a++) + { + char *col; + alp[a]=string2alphabet ( (col=aln_column2string (I,a)),depth, &alp_size[a]); + vfree (col); + } + generate_array_string_list (I->len_aln, alp, alp_size, &n, motif_file, OVERLAP); + } + else + { + int *used; + char r; + + used=vcalloc (256, sizeof (int)); + fpp=vfopen (motif_file,"w"); + for (a=0;alen_aln; a++) + { + for (b=0; bnseq; b++) + { + r=I->seq_al[b][a]; + if (!used[(int)r]){fprintf (fpp, "%c", r);used[(int)r]=1;} + } + for (b=0; bnseq; b++) + { + r=I->seq_al[b][a]; + used[(int)r]=0; + } + fprintf (fpp, " "); + } + fprintf (fpp, "\n"); + vfree (used); + vfclose (fpp); + + n=1; + depth=I->nseq; + } + + buf=vcalloc (2*(I->len_aln*depth)+1, sizeof (char)); + best_buf=vcalloc (2*(I->len_aln*depth)+1, sizeof (char)); + fpp=vfopen (motif_file, "r"); + + for (a=0; anseq; b++) + { + if (match_motif (I->seq_al[b], m2))tp++; + else fn++; + } + for (b=0; bnseq; b++) + { + if (match_motif (O->seq_al[b], m2))fp++; + else tn++; + } + rates2sensitivity (tp, tn, fp, fn, &sp, &sn, &sen2, &best); + + if (best>= best_pred) + { + best_pred=best; + best_sp=sp; + best_sen2=sen2; + best_sn=sn; + sprintf (best_buf, "%s", buf); + } + m2--; + free_char (m2, -1); + } + vfclose (fpp); + if (print==PRINT)fprintf ( stdout, "\nMotifCompound %25s sp: %.2f sn: %.2f sen2: %.2f best: %.2f motif: ", get_compound_name(c, mode), best_sp, best_sn, best_sen2, best_pred); + m2=string2list (best_buf); + m=declare_char (I->len_aln+1, depth+1); + + for (a=0; alen_aln; a++) + { + sprintf (m[a], "%s", m2[a+1]); + if (print==PRINT) fprintf ( stdout, "[%2s]",m[a]); + } + if (print==PRINT)fprintf ( stdout, " N-motifs %d", n); + free_char (m2, -1); + + if (alp)free_arrayN((void ***) alp, 3); + if (alp_size)vfree (alp_size); + vfree (buf); vfree(best_buf); + + return m; +} + +double pos2sim (Alignment *A, Alignment *B, int *pos) +{ + return sar_aln2r (A, B,pos, PRINT); +} +double sar_aln2r (Alignment *A, Alignment *B, int *pos, int print) +{ + int a, b, c, d,r1, r2, n, score, sim; + double *r, result; + static double **slist; + int declare=0; + static int **M; + + + + if (!M)M=read_matrice ("blosum62mt"); + if (!slist) + { + int maxslist; + maxslist=A->nseq*A->nseq*10; + slist=declare_double (maxslist, 2); + } + + if (pos==NULL) + { + + declare=1; + pos=vcalloc ( A->len_aln+1, sizeof (int)); + for (a=0; alen_aln; a++)pos[a]=1; + pos[a]=-1; + + } + + for (n=0,a=0; a< A->nseq-1; a++) + { + + for (b=a+1; bnseq; b++) + { + + + for (sim=d=0,c=0; clen_aln; c++) + { + + if (pos[c]==0)continue; + + r1=A->seq_al[a][c]; + r2=A->seq_al[b][c]; + if (is_gap(r1) || is_gap(r2))return 0; + + sim+=M[r1-'A'][r2-'A']*pos[c]; + d+=MAX((M[r1-'A'][r1-'A']),(M[r2-'A'][r2-'A'])); + } + sim=(d==0)?0:(100*sim)/d; + score=(int)get_sar_sim(B->seq_al[a], B->seq_al[b]); + slist[n][0]=(double)sim; + slist[n][1]=(double)score; + if (print==PRINT)fprintf ( stdout, "SIM: %d %d [%s %s]\n", sim, score, A->name[a], A->name[b]); + n++; + } + } + + r=return_r(slist, n); + for (a=0; alen_aln; c++) + { + + I->nseq=O->nseq=I->len_aln=O->len_aln=0; + for (a=0; alen_aln; a++) + { + if (pos[a]) + { + for (i=o=0,b=0; bnseq; b++) + { + if ( is_gap(A->seq_al[b][a]))return 0; + if (B->seq_al[b][c]=='I')I->seq_al[i++][I->len_aln]=A->seq_al[b][a]; + else O->seq_al[o++][O->len_aln]=A->seq_al[b][a]; + } + I->len_aln++; + O->len_aln++; + } + } + if (O->len_aln==0 || I->len_aln==0) return 0; + O->nseq=o; + I->nseq=i; + for (a=0; aseq_al[a][O->len_aln]='\0'; + for (a=0; aseq_al[a][I->len_aln]='\0'; + + delta+=aln2sim(I,"blosum62mt")-aln2sim(O, "blosum62mt"); + + } + + return delta; +} + +char * get_compound_name (int c, char *mode) +{ + static int isset; + static Alignment *S; + static char *lname; + + if (!isset) + { + char *comp_list; + isset=1; + lname=vcalloc (100, sizeof (char)); + + if (!mode); + else + { + strget_param (mode, "_COMPLIST_", "NO", "%s", comp_list=vcalloc (100, sizeof (char))); + if (strm(comp_list, "NO")); + else + { + S=main_read_aln (comp_list, NULL); + vfree (comp_list); + } + } + } + if (!S || c>=S->nseq)sprintf (lname, "%d", c); + else + { + sprintf (lname, "%s", S->name [c]); + } + return lname; +} +ORP * declare_or_prediction ( int ncomp, int nseq, int len) +{ + ORP *P; + P=vcalloc ( 1, sizeof (ORP)); + P->ncomp=ncomp; + P->nseq=nseq; + P->len=len; + P->PR=NULL; + + P->pos=vcalloc (len+1, sizeof (int)); + + return P; +} + +void free_orp_list ( ORP**P) +{ + int a=0; + while (P[a]) + { + free_orp(P[a++]); + } +} +void free_orp ( ORP*P) +{ + if (!P) return; + free_aln (P->A); + free_aln (P->S); + free_aln (P->P); + vfree (P->pos); + free_arrayN((void **)P->motif, 3); + if (P->PR)free_orp(P->PR); + vfree (P); +} + + + + + + + + + + + + + + + +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/util_analyse_constraints_list.c b/binaries/src/tcoffee/t_coffee_source/util_analyse_constraints_list.c new file mode 100644 index 0000000..94d6b58 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/util_analyse_constraints_list.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" + + + +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/util_constraints_list.c b/binaries/src/tcoffee/t_coffee_source/util_constraints_list.c new file mode 100644 index 0000000..cda0ce7 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/util_constraints_list.c @@ -0,0 +1,6277 @@ +#include + +#include +#include +#include +#include +#include +#include + + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" +#include "dp_lib_header.h" +static int entry_len; +int compare_constraint_list_entry ( const void*vx, const void*vy); +int compare_constraint_list_entry4bsearch ( const void*vx, const void*vy); + +/*********************************************************************/ +/* */ +/* Post Process Constraint_list */ +/* */ +/* */ +/*********************************************************************/ + +/*********************************************************************/ +/* */ +/* PRODUCE IN LIST */ +/* */ +/* */ +/*********************************************************************/ +Constraint_list *make_test_lib (Constraint_list *CL); + + +Constraint_list *fork_line_produce_list ( Constraint_list *CL, Sequence *S, char * method,char *weight,char *mem_mode,Job_TC *job, FILE *local_stderr); +Constraint_list *fork_cell_produce_list ( Constraint_list *CL, Sequence *S, char * method,char *weight,char *mem_mode,Job_TC *job, FILE *local_stderr); +Constraint_list *nfork_produce_list ( Constraint_list *CL, Sequence *S, char * method,char *weight,char *mem_mode,Job_TC *job, FILE *local_stderr); +Constraint_list *fork_subset_produce_list ( Constraint_list *CL, Sequence *S, char * method,char *weight,char *mem_mode, Job_TC *job, FILE *local_stderr); +int job2first_seq(Job_TC *job); +Constraint_list *produce_list ( Constraint_list *CL, Sequence *S, char * method,char *weight,char *mem_mode) +{ + Job_TC *job=NULL; + FILE *local_stderr; + int njob; + + + store_seq_type (S->type); + if ( CL==NULL)CL=declare_constraint_list ( S,NULL, NULL, 0,(strm(mem_mode, "disk"))?vtmpfile():NULL, NULL); + local_stderr=(CL->local_stderr!=NULL)?CL->local_stderr:stderr; + + CL->local_stderr=vfopen("/dev/null", "w"); + job=queue2heap(method2job_list ( method,S,weight, CL->lib_list,CL->DM, CL)); + njob=queue2n(job)+1; + + + if ( get_nproc()==1 || njob==1)return nfork_produce_list (CL, S, method, weight, mem_mode,job, local_stderr); + else if (strstr ( CL->multi_thread, "jobcells"))return fork_cell_produce_list (CL, S, method, weight, mem_mode,job,local_stderr); + else if (strstr ( CL->multi_thread, "joblines"))return fork_line_produce_list (CL, S, method, weight, mem_mode,job, local_stderr); + else if (strstr ( CL->multi_thread, "jobs"))return fork_subset_produce_list (CL, S, method, weight, mem_mode,job, local_stderr); //Recommended default + else return nfork_produce_list (CL, S, method, weight, mem_mode,job, local_stderr); +} +int job2first_seq(Job_TC *job) +{ + int *seqlist; + int r; + + if (!job) return -1; + else if ( !job->param)return -1; + else if ( !(job->param)->seq_c) return -1; + seqlist=string2num_list ((job->param)->seq_c); + if (seqlist[0]<2)r=-1; + else r=seqlist[2]; + vfree (seqlist); + return r; +} + +Constraint_list *fork_subset_produce_list ( Constraint_list *CL, Sequence *S, char * method,char *weight,char *mem_mode, Job_TC *job, FILE *local_stderr) +{ + //forks lines of the matrix + int a,b; + Job_TC *heap,*end,*start, ***jl; + TC_method *M; + char **pid_tmpfile; + int *pid_list; + int pid,npid, njob; + int nproc, max_nproc, submited; + int cseq, seq, nlines; + int n_aln; + + max_nproc=nproc=get_nproc(); + max_nproc*=2; + /*OUT_MODE: + A-> alignment provided in a file + L-> list provided in a file + aln-> alignment computed and provided in a file + list->list computed and provided in a file + */ + + + + + if ( job->jobid==-1) + { + M=(job->param)->TCM; + fprintf (local_stderr, "\n\tMethod %s: No Suitable Sequences [Type: %s]\n", method,M->seq_type); + return CL; + } + + job=queue2heap (job); + heap=job; + njob=queue2n (job); + + M=(job->param)->TCM; + if (M)M->PW_CL=method2pw_cl ( M, CL); + pid_tmpfile=vcalloc (MAX(njob,get_nproc())+1, sizeof (char*)); + pid_list =vcalloc (MAX_N_PID, sizeof (int *)); + + fprintf ( local_stderr, "\n\tMulti Core Mode: %d processors [subset]\n", get_nproc()); + + jl=split_job_list(job,get_nproc()); + a=npid=0; + + a=npid=0; + while (jl[a]) + { + + start=job=jl[a][0]; + end=jl[a][1]; + pid_tmpfile[a]=vtmpnam(NULL); + pid=vvfork(NULL); + + if (pid==0)//child process + { + FILE *fp; + int done, todo, t; + freeze_constraint_list (CL);//record the current state, so as not to dump everything + initiate_vtmpnam(NULL); + vfclose(vfopen (pid_tmpfile[a],"w")); + + todo=0; + while (job!=end){todo++;job=job->c;} + job=start; + + done=0; + while (job!=end) + { + if (a==0)output_completion ( local_stderr,done,todo,1, "Submit Job"); + job=print_lib_job (job, "io->CL=%p control->submitF=%p control->retrieveF=%p control->mode=%s",CL,submit_lib_job, retrieve_lib_job, CL->multi_thread ); + + job=submit_job (job); + retrieve_job (job); + + job=job->c; + done++; + } + dump_constraint_list (CL, pid_tmpfile[a], "a"); + freeze_constraint_list (CL); + myexit (EXIT_SUCCESS); + } + else + { + pid_list[pid]=npid; + //set_pid(pid); + npid++; + a++; + } + } + + //wait for all processes to finish + for (a=0; alocal_stderr=local_stderr; + free_queue (heap); + return CL; +} + + +Constraint_list *fork_line_produce_list ( Constraint_list *CL, Sequence *S, char * method,char *weight,char *mem_mode, Job_TC *job, FILE *local_stderr) +{ + //forks lines of the matrix + int a,b; + Job_TC *heap; + TC_method *M; + + char **pid_tmpfile; + int *pid_list; + int pid,npid, njob; + int nproc, max_nproc, submited; + int cseq, seq, nlines; + + max_nproc=nproc=get_nproc(); + max_nproc*=2; + /*OUT_MODE: + A-> alignment provided in a file + L-> list provided in a file + aln-> alignment computed and provided in a file + list->list computed and provided in a file + */ + + + + + if ( job->jobid==-1) + { + M=(job->param)->TCM; + fprintf (local_stderr, "\n\tMethod %s: No Suitable Sequences [Type: %s]\n", method,M->seq_type); + return CL; + } + + + job=queue2heap (job); + + heap=job; + M=(job->param)->TCM; + if (M)M->PW_CL=method2pw_cl ( M, CL); + + + /* Cf. parse method for possible out_mode flags*/ + + njob=queue2n(job)+1; + pid_tmpfile=vcalloc (njob, sizeof (char*)); + + pid_list =vcalloc (MAX_N_PID, sizeof (int *)); + fprintf ( local_stderr, "\n\tMulti Core Mode: %d processors [jobline]\n", get_nproc()); + + + //count the number of lines + cseq=-1; + nlines=0; + while (job) + { + nlines++; + seq=job2first_seq(job); + if ( seq!=cseq) + { + cseq=seq; + while (job && cseq==job2first_seq(job))job=job->c; + } + } + job=heap; + + npid=submited=0; + cseq=-1; + while (job) + { + seq=job2first_seq(job); + if ( seq!=cseq) + { + cseq=seq; + pid_tmpfile[npid]=vtmpnam(NULL); + + pid=vvfork(NULL); + + if (pid==0)//Child Process + { + initiate_vtmpnam(NULL); + while (job && cseq==job2first_seq(job)) + { + job=print_lib_job (job, "io->CL=%p control->submitF=%p control->retrieveF=%p control->mode=%s",CL,submit_lib_job, retrieve_lib_job, CL->multi_thread ); + job=submit_job (job); + retrieve_job (job); + dump_constraint_list ((job->io)->CL,pid_tmpfile[npid], "a"); + job=job->c; + } + myexit (EXIT_SUCCESS); + } + else //parent process + { + + pid_list[pid]=npid; + //set_pid (pid); + npid++; + submited++; + if (submited>max_nproc) + { + //wait for nproc + for (a=0; ac; + } + } + + for (a=0; alocal_stderr=local_stderr; + + free_queue (heap); + + return CL; +} + +Constraint_list *fork_cell_produce_list ( Constraint_list *CL, Sequence *S, char * method,char *weight,char *mem_mode, Job_TC *job, FILE *local_stderr) +{ + //forks cells of the matrix + int a,b, n; + Job_TC *heap; + TC_method *M; + + int *pid_list; + char **pid_tmpfile; + int pid,npid, njob; + int nproc, max_nproc; + int submited; + + max_nproc=nproc=get_nproc(); + + /*OUT_MODE: + A-> alignment provided in a file + L-> list provided in a file + aln-> alignment computed and provided in a file + list->list computed and provided in a file + */ + + + if ( job->jobid==-1) + { + M=(job->param)->TCM; + fprintf (local_stderr, "\n\tMethod %s: No Suitable Sequences [Type: %s]\n", method,M->seq_type); + return CL; + } + + + job=queue2heap (job); + + heap=job; + M=(job->param)->TCM; + if (M)M->PW_CL=method2pw_cl ( M, CL); + + + /* Cf. parse method for possible out_mode flags*/ + + njob=queue2n(job)+1; + pid_tmpfile=vcalloc (njob, sizeof (char*)); + pid_list =vcalloc (MAX_N_PID, sizeof (int *)); + + fprintf ( local_stderr, "\n\tMulti Core Mode: %d processors:\n", get_nproc()); + npid=0; + submited=0; + while (job) + { + job=print_lib_job (job, "io->CL=%p control->submitF=%p control->retrieveF=%p control->mode=%s",CL,submit_lib_job, retrieve_lib_job, CL->multi_thread ); + pid_tmpfile[npid]=vtmpnam(NULL); + pid=vvfork (NULL); + if ( pid==0) + { + initiate_vtmpnam (NULL); + job=submit_job (job); + retrieve_job (job); + dump_constraint_list ((job->io)->CL,pid_tmpfile[npid], "w"); + myexit (EXIT_SUCCESS); + } + else + { + job=job->c; + pid_list[pid]=npid; + //set_pid(pid); + npid++; + submited++; + + if (submited>max_nproc) + { + for (a=0; alocal_stderr=local_stderr; + + free_queue (heap); + + return CL; +} +Constraint_list *nfork_produce_list ( Constraint_list *CL, Sequence *S, char * method,char *weight,char *mem_mode, Job_TC *job, FILE *local_stderr) +{ + int n_aln; + Job_TC *heap; + TC_method *M; + int n_elements_in, n_new_elements; + int b; + + /*OUT_MODE: + A-> alignment provided in a file + L-> list provided in a file + aln-> alignment computed and provided in a file + list->list computed and provided in a file + */ + + + if ( job->jobid==-1) + { + M=(job->param)->TCM; + fprintf (local_stderr, "\n\tMethod %s: No Suitable Sequences [Type: %s]\n", method,M->seq_type); + return CL; + } + + + job=queue2heap (job); + + + heap=job; + n_aln=queue2n (job); + M=(job->param)->TCM; + + if (M)M->PW_CL=method2pw_cl ( M, CL); + n_elements_in=CL->ne; + + b=0; + while (job) + { + local_stderr=output_completion ( local_stderr, b, n_aln+1,1, "Submit Job"); + job=print_lib_job (job, "io->CL=%p control->submitF=%p control->retrieveF=%p control->mode=%s",CL,submit_lib_job, retrieve_lib_job, CL->multi_thread ); + + job=submit_job (job); + if (retrieve_job (job)) + { + CL=merge_constraint_list ((job->io)->CL, CL, "default"); + } + job=job->c; + b++; + } + job=heap; + fprintf ( local_stderr, "\n"); + + while (job) job=delete_job (job); + + + CL->local_stderr=local_stderr; + + free_queue (heap); + return CL; +} + + + + + + + + + + +Job_TC *retrieve_lib_job ( Job_TC *job) +{ + Job_param_TC *p; + Job_io_TC *io; + TC_method *M; + + p=job->param; + io=job->io; + M=(job->param)->TCM; + + + if ( job->status==EXIT_SUCCESS) + { + static char *log_output; + static int log; + + if ( !M) return job; + else if (strm2(M->out_mode, "aln", "A")) + { + io->CL=read_constraint_list (io->CL,io->out,"aln","disk",M->weight); + } + else if (strm2(M->out_mode, "lib","L")) + { + + io->CL=read_constraint_list (io->CL,io->out,"lib","disk",M->weight); + + } + return job; + } + else + return NULL; +} + +int add_method_output2method_log (char *l,char *command,Alignment *A, Constraint_list *CL, char *io_file) +{ + static int header; + static int log; + static char *file, *log_file; + static int set; + + if ( set && log_file==NULL && l==NULL) return 0; + if (!set ){log_file=get_string_variable ("method_log");if (log_file && strm (log_file, "no"))log_file=NULL; set=1;} + if (!file)file=vtmpnam (NULL); + + if ( l); + else if (!l && log_file) l=log_file; + else return 0; + + + if (!header){printf_file ( l, "w", "# CONC_MSF_FORMAT_01\n");header=1;} + if (command)printf_file (l, "a", "%s\n#----------------------------------------------\n#%s\n", TC_REC_SEPARATOR,command); + + + if ( A) + { + + io_file=file; + output_fasta_aln (io_file, A); + } + else if (CL) + { + io_file=file; + vfclose (save_constraint_list ( CL, 0, CL->ne,io_file, NULL, "ascii",CL->S)); + } + else + file_cat (io_file,l); + + + return 1; +} + + + +Job_TC *submit_lib_job ( Job_TC *job) +{ + Job_param_TC *p; + Job_io_TC *io; + TC_method *M; + static char *l; + static int log; + + p=job->param; + io=job->io; + M=(job->param)->TCM; + add_method_output2method_log (NULL, p->aln_c, NULL, NULL, NULL); + if ( getenv4debug ("DEBUG_LIBRARY"))fprintf ( stderr, "\n[DEBUG_LIBRARY:produce_list] Instruction: %s\n", p->aln_c); + + if ( !M) + { + return job; + } + else if (strm4 (M->out_mode,"A", "L", "aln", "lib")) + { + seq_list2in_file ( M, (io->CL)->S, p->seq_c, io->in); + printf_system ("%s ::IGNORE_FAILURE::", p->aln_c); + add_method_output2method_log (NULL,NULL, NULL, NULL, io->out); + if (!evaluate_sys_call_io (io->out,p->aln_c, "") || (strm (M->out_mode, "aln") && !(is_aln (io->out) || is_seq(io->out))) ) + { + job->status=EXIT_FAILURE; + //myexit (EXIT_FAILURE); + return job; + } + } + else if ( strm2 (M->out_mode, "fA", "fL")) + { + + io->CL= seq2list(job); + if (!io->CL) + { + add_warning (stderr, "\nFAILED TO EXECUTE:%s [SERIOUS:%s]", p->aln_c, PROGRAM); + job->status=EXIT_FAILURE; + } + } + else + { + myexit(fprintf_error ( stderr, "\nERROR: Unknown out_mode=%s for method[FATAL:%s]\n", M->out_mode, M->executable)); + } + + return job; +} + + + +Job_TC* method2job_list ( char *method_name,Sequence *S, char *weight, char *lib_list, Distance_matrix *DM, Constraint_list *CL) +{ + int preset_method; + static char *fname, *bufS, *bufA; + char *in,*out; + TC_method *method; + char aln_mode[100]; + char out_mode[100]; + Job_TC *job; + int hijack_P_jobs=1; + + /*A method can be: + 1- a pre computed alignment out_mode=A + 2- a precomputed Library out_mode=L + 3- a method producing an alignment out_mode=aln + 4- a method producing an alignment out_mode=list + 5- a function producing an alignment out_mode=faln + 6- a function producing a library out_mode=flist + */ + + if ( !fname) + { + fname=vcalloc ( 1000, sizeof (char)); + bufS=vcalloc ( S->nseq*10, sizeof (char)); + } + + /*Make sure that fname is a method*/ + + + sprintf(fname, "%s", method_name); + + if ( fname[0]=='A' || fname[0]=='L') + { + method=method_file2TC_method("no_method"); + sprintf ( method->out_mode, "%c", fname[0]); + + if (!strm (weight, "default"))sprintf ( method->weight, "%s", weight); + + return print_lib_job(NULL,"param->out=%s param->TCM=%p",fname+1, method); + } + else if ( fname[0]=='M' && is_in_pre_set_method_list (fname+1)) + { + preset_method=1; + fname++; + } + else if ( is_in_pre_set_method_list (fname)) + { + preset_method=1; + } + else + { + char buf[1000]; + if ( check_file_exists ( fname)); + else if (fname[0]=='M' && check_file_exists(fname+1)); + else + { + sprintf ( buf, "%s/%s", get_methods_4_tcoffee(), fname); + if( check_file_exists(buf)){sprintf ( fname, "%s", buf);} + else + { + myexit (fprintf_error ( stderr, "%s is not a valid method", fname)); + } + } + } + + + method=method_file2TC_method(fname); + job=print_lib_job (NULL, "param->TCM=%p", method); + job->jobid=-1; + + if (!strm (weight, "default"))sprintf ( method->weight, "%s", weight); + + sprintf ( aln_mode, "%s", method->aln_mode); + sprintf ( out_mode, "%s", method->out_mode); + + + if (lib_list && lib_list[0]) + { + static char **lines, **list=NULL; + int a,i, x, n, nl; + + + + if ( lines) free_char (lines, -1); + + + if ( strstr (lib_list, "prune")) + { + lines=file2lines (list2prune_list (S,DM->similarity_matrix)); + } + else + { + lines=file2lines (lib_list); + } + + nl=atoi (lines[0]); + for (a=1; a 2 && strm (aln_mode, "pairwise"))continue; + if ( n==2 && strm (aln_mode, "multiple"))continue; + + for (i=2; iname, S->nseq, 100))!=-1)sprintf(list[i], "%d", x); + else + { + add_warning ( stderr, "\nWARNING: %s is not part of the sequence dataset \n", list[i]); + continue; + } + } + sprintf ( bufS, "%s", list[1]); + for ( i=2; i')==NULL)strcat (bufA,TO_NULL_DEVICE); + if ( check_seq_type ( method, bufS, S)) + { + job->c=print_lib_job (NULL, "param->TCM=%p param->method=%s param->aln_c=%s param->seq_c=%s io->in=%s io->out=%s ", method, fname, bufA, bufS, in, out); + job=queue_cat (job, job->c); + } + vfree (bufA); + + } + } + else if ( strcmp (aln_mode, "multiple")==0) + { + int d; + char buf[10000]; + + sprintf (bufS, "%d",S->nseq); + for (d=0; d< S->nseq; d++) + { + sprintf ( buf," %d",d); + strcat ( bufS, buf); + } + + bufA=make_aln_command (method, in=vtmpnam(NULL),out=vtmpnam(NULL)); + if (strrchr(bufA, '>')==NULL)strcat (bufA,TO_NULL_DEVICE); + + if ( check_seq_type ( method, bufS, S)) + { + job->c=print_lib_job (NULL, "param->TCM=%p param->method=%s param->aln_c=%s param->seq_c=%s io->in=%s io->out=%s ", method, fname, bufA, bufS, in, out, S->template_file); + + job=queue_cat (job, job->c); + + } + vfree (bufA); + } + else if ( strstr(aln_mode, "o2a")) + { + int x, y, n; + int *used; + static char *tmpf; + FILE *fp; + int byte=CL->o2a_byte; + int max=0; + + for (x=0; x<(CL->S)->nseq; x++)max+=(CL->master[x]); + + if (CL->o2a_byte>=max)byte=(max/get_nproc())+1; + + if (!tmpf)tmpf=vtmpnam (NULL); + + fp=vfopen (tmpf, "w"); + for (n=0,x=0; x<(CL->S)->nseq; x++) + { + if (CL->master[x]){fprintf (fp, "%d ", x);n++;} + if (n==byte || (n && x==(CL->S)->nseq-1)) + { + vfclose (fp); + sprintf (bufS, "%d %s", n,file2string (tmpf));n=0; + + bufA=make_aln_command (method, in=vtmpnam(NULL),out=vtmpnam(NULL)); + if (strrchr(bufA, '>')==NULL)strcat (bufA,TO_NULL_DEVICE); + if ( check_seq_type ( method, bufS, S)) + { + job->c=print_lib_job (NULL, "param->TCM=%p param->method=%s param->aln_c=%s param->seq_c=%s io->in=%s io->out=%s ", method, fname, bufA, bufS, in, out, S->template_file); + job=queue_cat (job, job->c); + } + vfree (bufA); + fp=vfopen (tmpf, "w"); + } + } + vfclose (fp); + } + + else if ( strstr(aln_mode, "old_o2a")) + { + int x, y; + + for (x=0; x< S->nseq; x++) + { + if (!CL->master[x])continue; + sprintf (bufS, "%d %d", S->nseq, x); + for ( y=0; y< S->nseq; y++) + { + char buf[1000]; + if (y==x)continue; + sprintf (buf, " %d",y); + strcat ( bufS, buf); + } + bufA=make_aln_command (method, in=vtmpnam(NULL),out=vtmpnam(NULL)); + if (strrchr(bufA, '>')==NULL)strcat (bufA,TO_NULL_DEVICE); + if ( check_seq_type ( method, bufS, S)) + { + + job->c=print_lib_job (NULL, "param->TCM=%p param->method=%s param->aln_c=%s param->seq_c=%s io->in=%s io->out=%s ", method, fname, bufA, bufS, in, out, S->template_file); + + job=queue_cat (job, job->c); + } + vfree (bufA); + } + } + else if ( strstr(aln_mode, "pairwise")) + { + int do_mirror, do_self, x, y, id; + do_mirror=(strstr(aln_mode, "m_"))?1:0; + do_self=(strstr(aln_mode, "s_"))?1:0; + + for (x=0; x< S->nseq; x++) + { + if (!CL->master[x])continue; + for ( y=(do_mirror)?0:x; y< S->nseq; y++) + { + + id=DM->similarity_matrix[x][y]; + + if ( x==y && !do_self); + else if ( !is_in_range(id,method->minid, method->maxid)); + else + { + sprintf (bufS, "2 %d %d",x,y); + bufA=make_aln_command (method,in=vtmpnam(NULL),out=vtmpnam (NULL)); + + if (strrchr(bufA, '>')==NULL)strcat (bufA, TO_NULL_DEVICE); + if (check_seq_type (method, bufS, S)) + { + job->c=print_lib_job (job->c, "param->TCM=%p param->method=%s param->aln_c=%s param->seq_c=%s io->in=%s io->out=%s ",method,fname,bufA, bufS, in, out); + job=queue_cat (job, job->c); + } + else if ( method->seq_type[0]=='P' && hijack_P_jobs) + { + //Hijack _P_ jobs without enough templates + static TC_method *proba_pairM; + + add_information(stderr, "Method %s cannot be applied to [%s vs %s], proba_pair will be used instead",(method->executable2)?method->executable2:method->executable, (CL->S)->name[x], (CL->S)->name [y]); + if (!proba_pairM) + { + proba_pairM=method_file2TC_method(method_name2method_file ("proba_pair")); + proba_pairM->PW_CL=method2pw_cl(proba_pairM, CL); + } + job->c=print_lib_job (job->c, "param->TCM=%p param->method=%s param->aln_c=%s param->seq_c=%s io->in=%s io->out=%s ",proba_pairM,fname,bufA, bufS, in, out); + job=queue_cat (job, job->c); + } + + vfree (bufA); + } + } + } + } + + return job; +} + +int check_seq_type (TC_method *M, char *list,Sequence *S) +{ + char t1, t2; + int s1, s2, n1, nseq, ntype, i; + int *slist; + Template *T1, *T2; + + + slist=string2num_list (list); + + nseq=slist[1]; + ntype=strlen (M->seq_type); + t1=M->seq_type[0]; + t2=M->seq_type[1]; + n1=0; + + /*Profiles and Sequences MUST NOT be distinguished so that sequences and profiles can easily be aligned*/ + if ( tolower(t1)=='r')t1='S'; + if ( tolower(t2)=='r')t2='S'; + + + if ( strm ( M->aln_mode, "pairwise") && nseq>2)n1=0; + else if (strm ( M->aln_mode, "multiple" ) && ntype>1)n1=0; + else if (ntype==1) + { + + for (n1=0, i=0; iT[s1]; + + n1+=(strchr (T1->seq_type,t1) || check_profile_seq_type (S, s1, t1))?1:0; + } + n1=(n1==nseq)?1:0; + } + else if (ntype==2) + { + int s1_has_t1; + int s1_has_t2; + int s2_has_t1; + int s2_has_t2; + + s1=slist[2]; + s2=slist[3]; + T1=(S->T[s1]); + T2=(S->T[s2]); + + s1_has_t1=(strchr ( T1->seq_type, t1) || check_profile_seq_type (S, s1, t1))?1:0; + s1_has_t2=(strchr ( T1->seq_type, t2) || check_profile_seq_type (S, s1, t2))?1:0; + s2_has_t1=(strchr ( T2->seq_type, t1) || check_profile_seq_type (S, s2, t1))?1:0; + s2_has_t2=(strchr ( T2->seq_type, t2) || check_profile_seq_type (S, s2, t2))?1:0; + n1=((s1_has_t1 && s2_has_t2) || (s1_has_t2 && s2_has_t1))?1:0; + } + + vfree (slist); + return n1; +} + +int check_profile_seq_type (Sequence *S, int i, char t) +{ + Alignment *A; + Template *T; + int a; + + /*returns 1 if the sequence S is associated with a profile containing the right sequence*/ + A=seq2R_template_profile (S, i); + if (A==NULL || A->S==NULL) return 0; + for ( a=0; a< A->nseq; a++) + { + + T=(A->S)->T[a]; + if ( T && strchr( T->seq_type,t))return 1; + + } + return 0; +} + + +char **method_list2method4dna_list ( char **list, int n) +{ + int a; + static char *buf; + + if ( !buf)buf=vcalloc ( 1000, sizeof (char)); + + if ( !list || n==0)return list; + buf=vcalloc ( 1000, sizeof (char)); + + for ( a=0; a< n; a++) + { + + sprintf ( buf,"%s",list[a]); + + if ( strm ( list[a], "4dna")); + else + { + + char **para ; + int b; + + para=string2list2 (list[a], "@"); + sprintf ( buf, "%s4dna", para[1]); + if (method_name2method_file (buf) || method_name2method_file(buf+1)) + { + sprintf ( list[a],"%s", buf); + for (b=2; b< atoi (para[0]); b++) + { + strcat (list[a], "@"); + strcat (list[a], para[b]); + } + } + + free_char (para, -1); + } + } + return list; +} + +int is_in_pre_set_method_list ( char *method) +{ + char *new_name; + + + + + new_name=method_name2method_file (method); + + if ( !new_name) return 0; + else + { + + sprintf ( method, "%s", new_name); + return 1; + } +} +char *** display_method_names (char *mode, FILE *fp) +{ + char ***list, ***l2; + int n=0, a, ml1=0, ml2=0, ml3=0; + int status; + + + + + + + list=produce_method_file (NULL); + l2=declare_arrayN(3,sizeof (char), 1000, 10, 100); + + fprintf ( fp, "\n####### Compiling the list of available methods ... (will take a few seconds)\n"); + a=0; + + while (list[a]) + { + + + sprintf (l2[a][0], "%s", method_file_tag2value (list[a][1],"ADDRESS")); + sprintf (l2[a][1], "%s", method_file_tag2value (list[a][1],"PROGRAM")); + sprintf (l2[a][2], "%s", method_file_tag2value (list[a][1],"ALN_MODE")); + sprintf (l2[a][3], "%s", method_file_tag2value (list[a][1],"SEQ_TYPE")); + ml1=MAX((strlen (list[a][0])),ml1); + ml2=MAX((strlen (l2 [a][0])),ml2); + ml3=MAX((strlen (l2 [a][1])),ml3); + l2[a][4][0]= check_program_is_installed (l2[a][1],NULL,NULL,l2[a][0],NO_REPORT); + if (strm (l2[a][0], "built_in")){sprintf (l2[a][5], "built_in");} + else if (l2[a][4][0])l2[a][5]=pg2path (l2[a][1]); + + a++; + } + fprintf ( fp, "\n####### Methods For which an Interface is available in T-Coffee\n"); + fprintf ( fp, "You must install the packages yourself when required (use the provided address)\n"); + fprintf ( fp, "Contact us if you need an extra method to be added [%s]\n", EMAIL); + + + fprintf ( fp, "\n****** Pairwise Sequence Alignment Methods:\n"); + fprintf ( fp, "--------------------------------------------\n"); + a=0; + while (list[a]) + { + if ( strm (l2[a][2], "pairwise") && !strstr (l2[a][3], "P")) + fprintf ( fp, "%-*s %-*s [pg: %*s is %s Installed][%s]\n", ml1,list[a][0],ml2, l2[a][0], ml3,l2[a][1], (l2[a][4][0]==0)?"NOT":"",(l2[a][5])?l2[a][5]:""); + a++; + } + + fprintf ( fp, "\n****** Pairwise Structural Alignment Methods:\n"); + fprintf ( fp, "--------------------------------------------\n"); + a=0; + while (list[a]) + { + if ( strm (l2[a][2], "pairwise") && strstr (l2[a][3], "P")) + fprintf ( fp, "%-*s %-*s [pg: %*s is %s Installed][%s]\n", ml1,list[a][0],ml2, l2[a][0], ml3,l2[a][1], (l2[a][4][0]==0)?"NOT":"",(l2[a][5])?l2[a][5]:""); + a++; + } + fprintf ( fp, "\n****** Multiple Sequence Alignment Methods:\n"); + fprintf ( fp, "--------------------------------------------\n"); + a=0; + while (list[a]) + { + if ( strm (l2[a][2], "multiple")) + fprintf ( fp, "%-*s %-*s [pg: %*s is %s Installed][%s]\n", ml1,list[a][0],ml2, l2[a][0], ml3,l2[a][1], (l2[a][4][0]==0)?"NOT":"",(l2[a][5])?l2[a][5]:""); + a++; + } + fprintf ( fp, "\n####### Prediction Methods available to generate Templates\n"); + fprintf ( fp, "-------------------------------------------------------------\n"); + a=0; + while (list[a]) + { + if ( strm (l2[a][2], "predict")) + fprintf ( fp, "%-*s %-*s [pg: %*s is %s Installed][%s]\n", ml1,list[a][0],ml2, l2[a][0], ml3,l2[a][1], (l2[a][4][0]==0)?"NOT":"",(l2[a][5])?l2[a][5]:""); + a++; + } + fprintf ( fp, "\n\n\nAll these Methods are supported by T-Coffee, but you HAVE to install them yourself [use the provided address]\n\n"); + fprintf ( fp, "\nThese methods were selected because they are freeware opensource, easy to install and well supported"); + fprintf ( fp, "\nContact us if you need an extra method to be added [%s]\n", EMAIL); + + return l2; +} + +char* method_name2method_file (char *method) +{ + char *fname=NULL; + char ***mlist, *p; + char address[100]; + char program[100]; + int a; + + if ( check_file_exists (method) || (toupper(method[0])==method[0] && check_file_exists (method+1)))return NULL; + + if ( (p=strstr (method, "@"))!=NULL && !strstr (method, "em@"))p[0]='\0'; + mlist=produce_method_file (method); + + + + a=0; + while (mlist[a]) + { + if ( lstrstr (method,mlist[a][0])){fname=mlist[a][1];break;} + else {a++;} + } + if (p)p[0]='@'; + if ( fname==NULL) return NULL; + else + { + sprintf (address, "%s", method_file_tag2value (fname,"ADDRESS")); + sprintf (program, "%s", method_file_tag2value (fname,"PROGRAM")); + check_program_is_installed (program,NULL,NULL,address,INSTALL_OR_DIE); + if ( (method=strstr (method, "EP@"))!=NULL) + { + int a; + char **list; + FILE *fp; + list=string2list2 ( method, "@"); + fp=vfopen (fname, "a"); + for ( a=2; a + if (!line) + { + line=vcalloc (LONG_STRING+1, sizeof ( char)); + subcommand=vcalloc ( LONG_STRING, sizeof (char)); + } + + m=vcalloc ( 1, sizeof (TC_method)); + + /*set default parameter values*/ + m->gop=m->gep=UNDEFINED; + sprintf (m->seq_type, "S"); + sprintf (m->weight, "sim"); + m->minid=0; + m->maxid=100; + + fp=vfopen (method, "r"); + while ( (c=fgetc (fp))!=EOF) + { + ungetc ( c, fp); + fgets ( line,LONG_STRING, fp); + + + line=substitute (line, "\n", " "); + line=substitute (line, "%s", " "); + line=substitute (line, "%e", "="); + line=substitute (line, "%m", "-"); + + if ( (line && (line[0]=='*' || line[0]=='#' || line[0] == '$'|| line[0]==' ' || line[0]=='\0' )))subcommand[0]='\0'; + //Parse PARAM, PARM1 and PARAM2 first because they may contain keywords + else if ( (p=strstr (line, "PARAM1" ))) + { + sprintf (subcommand, " %s ", p+6); + strcat ( m->param1, subcommand); + } + else if ( (p=strstr (line, "PARAM2" ))) + { + sprintf (subcommand, " %s ", p+6); + strcat ( m->param2, subcommand); + } + else if ( (p=strstr (line, "PARAM" ))) + { + sprintf (subcommand, " %s ", p+5); + strcat ( m->param, subcommand); + }else if ( (p=strstr (line, "EXECUTABLE2" ))) + { + sscanf (p, "EXECUTABLE2 %s", m->executable2); + } + else if ( (p=strstr (line, "EXECUTABLE" ))) + { + sscanf (p, "EXECUTABLE %s", m->executable); + } + else if ( (p=strstr (line, "IN_FLAG2" ))) sscanf (p, "IN_FLAG2 %s" , m->in_flag2); + else if ( (p=strstr (line, "IN_FLAG" ))) sscanf (p, "IN_FLAG %s" , m->in_flag); + else if ( (p=strstr (line, "OUT_FLAG" ))) sscanf (p, "OUT_FLAG %s" , m->out_flag); + else if ( (p=strstr (line, "OUT_MODE" ))) sscanf (p, "OUT_MODE %s" , m->out_mode); + else if ( (p=strstr (line, "ALN_MODE" ))) sscanf (p, "ALN_MODE %s" , m->aln_mode); + else if ( (p=strstr (line, "SEQ_TYPE" ))) sscanf (p, "SEQ_TYPE %s" , m->seq_type); + else if ( (p=strstr (line, "WEIGHT" ))) sscanf (p, "WEIGHT %s" , m->weight); + else if ( (p=strstr (line, "MATRIX" ))){ sscanf (p, "MATRIX %s" , m->matrix);} + else if ( (p=strstr (line, "GOP" ))) sscanf (p, "GOP %d" , &m->gop); + else if ( (p=strstr (line, "GEP" ))) sscanf (p, "GEP %d" , &m->gep); + else if ( (p=strstr (line, "MAXID" ))) sscanf (p, "MAXID %d" , &m->maxid); + else if ( (p=strstr (line, "MINID" ))) sscanf (p, "MINID %d" , &m->minid); + else if ( (p=strstr (line, "EXTEND_SEQ" ))) sscanf (p, "EXTEND_SEQ %d" , &m->extend_seq); + else if ( (p=strstr (line, "REVERSE_SEQ" ))) sscanf (p, "REVERSE_SEQ %d" , &m->reverse_seq); + + + } + vfclose ( fp); + + + + return m; +} + +int TC_method2method_file( struct TC_method*m,char *fname ) +{ + FILE *fp; + if ( !m) return 0; + fp=vfopen ( fname, "w"); + if ( m->executable[0])fprintf (fp, "EXECUTABLE %s\n", m->executable); + if (m->in_flag[0])fprintf (fp, "IN_FLAG %s\n", m->in_flag); + if (m->out_flag[0])fprintf (fp, "OUT_FLAG %s\n", m->out_flag); + if (m->out_mode[0])fprintf (fp, "OUT_MODE %s\n", m->out_mode); + if (m->aln_mode[0])fprintf (fp, "ALN_MODE %s\n", m->aln_mode); + if (m->seq_type)fprintf (fp, "SEQ_TYPE %s\n", m->seq_type); + if (m->weight[0])fprintf (fp, "WEIGHT %s\n", m->weight); + if (m->matrix[0])fprintf (fp, "MATRIX %s\n", m->matrix); + if (m->gop!=UNDEFINED)fprintf (fp, "GOP %d\n", m->gop); + if (m->gep!=UNDEFINED)fprintf (fp, "GEP %d\n", m->gep); + if (m->minid!=0 )fprintf (fp, "MINID %d\n", m->minid); + if (m->maxid!=100)fprintf (fp, "MAXID %d\n", m->maxid); + if (m->param[0])fprintf (fp, "PARAM %s\n", m->param); + if (m->param1[0])fprintf (fp, "PARAM1 %s\n", m->param1); + if (m->param2[0])fprintf (fp, "PARAM1 %s\n", m->param2); + if (m->in_flag2[0])fprintf (fp, "IN_FLAG2 %s\n", m->in_flag2); + + vfclose ( fp); + return 1; +} + +char *make_aln_command(TC_method *m, char *seq, char *aln) +{ + char *command; + char buf[1000]; + + // sprintf ( buf, "%s %s %s%s %s%s %s", m->executable, m->param1, m->in_flag, seq,m->param2, m->out_flag,aln, m->param); + + sprintf ( buf, "%s %s %s%s %s %s%s %s", m->executable, m->param1, m->in_flag, seq,m->param2, m->out_flag,aln, m->param); + command=vcalloc ( strlen (buf)+100, sizeof (char)); + sprintf ( command, "%s", buf); + //HERE ("%s", command); exit (0); + + command=substitute (command, "&bnsp", " "); + command=substitute (command, "no_name", ""); + + return command; +} + + + + + +/*********************************************************************/ +/* */ +/* WRITE IN LIST */ +/* */ +/* */ +/*********************************************************************/ +Constraint_list * unfreeze_constraint_list (Constraint_list *CL) +{ + free_int (CL->freeze, -1); + CL->freeze=NULL; +} +Constraint_list * freeze_constraint_list (Constraint_list *CL) +{ + int a, b, d=0; + Sequence *S=CL->S; + int **freeze=declare_int2 (S->nseq, S->len, 1); + + for ( a=0; anseq; a++) + { + b=1; + while (CL->residue_index[a][b]) + { + d+=CL->residue_index[a][b][0]; + freeze[a][b]=CL->residue_index[a][b][0]; + b++; + } + } + CL->freeze=freeze; + return CL; +} +Constraint_list * empty_constraint_list (Constraint_list *CL) +{ + //reset all the indexes + int a, b; + + if ( !CL || ! CL->residue_index) return CL; + for (a=0; a<(CL->S)->nseq; a++) + { + b=0; + while (CL->residue_index[a][b]) + { + CL->residue_index[a][b][0]=1; + b++; + } + } + CL->ne=0; + return CL; +} + +Constraint_list * undump_constraint_list (Constraint_list *CL, char *file) +{ + int *entry; + FILE *fp; + int a, b, c,e,tot; + + if (!CL || !CL->residue_index)return CL; + entry=vcalloc ( CL->entry_len+1, sizeof (int)); + fp=vfopen (file, "r"); + b=0;c=0;tot=0; + while ((fscanf (fp, "%d ", &e))!=EOF) + { + entry [b++]=e; + if (b==CL->entry_len) + { + b=0; + int nl; + CL=add_entry2list2 (entry, CL); + //dump does not make the entries symetrical + //It reads in EXACTLY what was dumped + } + } + + vfclose (fp); + remove(file); + return CL; +} + +int safe_dump_constraint_list (Constraint_list *CL,char *file, char *mode, Sequence *RS) +{ + Sequence *S; + int **cache=NULL; + FILE *fp; +// static int *entry; + int *entry = vcalloc (CL->entry_len+1, sizeof (int)); + int b,c,s1, r1, s2, r2; + int d=0; + if (!CL || !CL->S || !CL->residue_index || CL->ne==0)return; + S=CL->S; + if (RS)cache=fix_seq_seq (S, RS); +// if (!entry) +// { +// entry=vcalloc (CL->entry_len+1, sizeof (int)); +// } + + fp=vfopen (file, mode); + for (s1=0; s1nseq; s1++) + { + if (cache && cache[s1][0]==-1)continue; + for (r1=1; r1<=S->len[s1]; r1++) + { + entry[SEQ1]=(cache)?cache[s1][0]:s1; + entry[R1]=(cache)?cache[s1][r1]:r1; + if (entry[R1]<=0)continue; + + b=(CL->freeze)?CL->freeze[s1][r1]:1; + for (;bresidue_index[s1][r1][0]; b+=ICHUNK) + { + s2=CL->residue_index[s1][r1][b+SEQ2]; + r2=CL->residue_index[s1][r1][b+R2]; + + entry[SEQ2]=(cache)?cache[s2][0]:s2; + if ( entry[SEQ2]==-1)continue; + else + { + entry[R2]=(cache)?cache[s2][r2]:r2; + if (entry[R2]<=0)continue; + else + { + d++; + entry[WE]=CL->residue_index[s1][r1][b+WE]; + entry[CONS]=CL->residue_index[s1][r1][b+CONS]; + entry[MISC]=CL->residue_index[s1][r1][b+MISC]; + + for (c=0; centry_len; c++)fprintf ( fp, "%d ", entry[c]); + } + } + } + } + } + vfclose (fp); + + free_int (cache, -1); + vfree (entry); + return d; +} + +int dump_constraint_list (Constraint_list *CL, char *file, char *mode) +{ + return safe_dump_constraint_list (CL, file, mode, NULL); +} + + +FILE* display_constraint_list (Constraint_list *CL, FILE *fp, char *tag) +{ + Sequence *S=CL->S; + int b,c,l,s1,r1,s2,r2,w2,n; + + n=0; + for (s1=0; s1nseq; s1++) + { + fprintf (fp, "SEQUENCE %d\n", s1); + + r1=1; + while (CL->residue_index[s1][r1]) + { + for (b=1; bresidue_index[s1][r1][0]; b+=ICHUNK) + { + s2=CL->residue_index[s1][r1][b+SEQ2]; + r2=CL->residue_index[s1][r1][b+R2]; + w2=CL->residue_index[s1][r1][b+WE]; + fprintf ( fp, "\t%sS1:%5d - R1:%5d S2:%5d R2:%5d W:%5d\n", tag,s1,r1, s2, r2,w2); + } + r1++; + } + + } + return fp; +} + + + +/*********************************************************************/ +/* */ +/* LIST EXTENTION */ +/* */ +/* */ +/*********************************************************************/ + + + + + +Constraint_list * evaluate_constraint_list_reference ( Constraint_list *CL) +{ + static CLIST_TYPE *entry; + int a, b, c, s1, s2, r1, r2; + int ***max_res; + + if ( CL->M) + { + CL->max_value=CL->max_ext_value=20; + + } + else + { + Sequence *S=CL->S; + + + CL->max_value=CL->max_ext_value=0; + max_res=vcalloc ( (CL->S)->nseq, sizeof (int**)); + + for ( a=0; a< (CL->S)->nseq; a++) + { + max_res[a]=vcalloc ( strlen ((CL->S)->seq[a])+1, sizeof (int*)); + for ( b=0; b<=(CL->S)->len[a]; b++) + { + max_res[a][b]=vcalloc ( (CL->S)->nseq+1, sizeof (int)); + } + } + + + for (s1=0; s1nseq; s1++) + { + for ( r1=1; r1<=S->len[s1]; r1++) + { + + for (a=1; aresidue_index[s1][r1][0]; a+=ICHUNK) + { + int s2=CL->residue_index[s1][r1][a+SEQ2]; + int r2=CL->residue_index[s1][r1][a+R2]; + int w2=CL->residue_index[s1][r1][a+WE]; + if ( w2==UNDEFINED || ( (CL->moca) && (CL->moca)->forbiden_residues && ((CL->moca)->forbiden_residues[s1][r1]==UNDEFINED || (CL->moca)->forbiden_residues[s2][r2]==UNDEFINED))); + else + { + max_res[s1][r1][s2]+=w2; + max_res[s2][r2][s1]+=w2; + CL->max_value=MAX(w2, CL->max_value); + } + } + } + } + + for ( a=0; a< (CL->S)->nseq; a++) + for ( b=1; b<=(CL->S)->len[a]; b++) + { + for ( c=0; c< (CL->S)->nseq; c++) + { + max_res[a][b][(CL->S)->nseq]+= max_res[a][b][c]; + } + CL->max_ext_value=MAX(max_res[a][b][c],CL->max_ext_value); + } + + for ( a=0; a< (CL->S)->nseq; a++) + { + for ( b=0; b<=(CL->S)->len[a]; b++) + vfree ( max_res[a][b]); + vfree (max_res[a]); + } + CL->max_ext_value=MAX(1,CL->max_ext_value); + vfree ( max_res); + } + + if (CL->normalise) + { + + CL->nomatch=(CL->nomatch*CL->normalise)/CL->max_ext_value; + } + + return CL; +} + +/*********************************************************************/ +/* */ +/* ENTRY MANIPULATION */ +/* */ +/* */ +/*********************************************************************/ +Constraint_list * add_list_entry2list (Constraint_list *CL, int n_para, ...) +{ + int a; + int *entry; + int field, val; + va_list ap; + + if (n_para>LIST_N_FIELDS) + { + myexit (fprintf_error ( stderr, "Too Many Fields in List")); + } + + va_start (ap,n_para); + entry=vcalloc (CL->entry_len+1, sizeof (int)); + + for ( a=0; aS)->nseq; s++) + { + while ((CL->residue_index[s][r])) + { + for (; lresidue_index[s][r][0];) + { + + entry[SEQ1]=s; + entry[R1]=r; + entry[SEQ2]=CL->residue_index[s][r][l+SEQ2]; + entry[R2]= CL->residue_index[s][r][l+R2]; + entry[WE]= CL->residue_index[s][r][l+WE]; + entry[CONS]=CL->residue_index[s][r][l+CONS]; + entry[MISC]=CL->residue_index[s][r][l+MISC]; + entry[INDEX]=l; + l+=ICHUNK; + return entry; + } + l=1; + r++; + } + r=0; + } + s=0; + r=0; + l=1; + + return NULL; +} +#ifdef FAFAFA +int next_entry (Constraint_list *CL, int *s, int*r, int *l); +int *extract_entry (Constraint_list *CL) +{ + static int s=0; + static int r=1; + static int l=1; + static int *entry; + int v; + + if (!entry)entry=vcalloc (100, sizeof (int)); + if (!CL){s=0;r=1;l=1; return NULL;} + + + while ((v=next_entry (CL, &s, &r, &l))) + { + if (v==1) + + { + + entry[SEQ1]=s; + entry[R1]=r; + entry[SEQ2]=CL->residue_index[s][r][l-ICHUNK+SEQ2]; + entry[R2]= CL->residue_index[s][r][l-ICHUNK+R2]; + entry[WE]= CL->residue_index[s][r][l-ICHUNK+WE]; + entry[CONS]=CL->residue_index[s][r][l-ICHUNK+CONS]; + entry[MISC]=CL->residue_index[s][r][l-ICHUNK+MISC]; + entry[INDEX]=l-ICHUNK; + return entry; + } + } + s=0; r=1; l=1; + return NULL; +} +int next_entry (Constraint_list *CL, int *s, int*r,int *l) +{ + Sequence *S=CL->S; + + if (s[0]>=S->nseq)return 0; + else if (!CL->residue_index[s[0]][r[0]]) + { + r[0]=1; + l[0]=1; + s[0]++; + return -1; + } + else if ( l[0]>=CL->residue_index[s[0]][r[0]][0]) + { + r[0]++; + l[0]=1; + return -1; + } + else + { + + l[0]+=ICHUNK; + return 1; + } +} +#endif + +int CLisCompacted (Constraint_list *CL, char *t) +{ + int s1, r1, s2, r2,ps2,pr2,b,c; + Sequence *S=CL->S; + + for (s1=0; s1nseq; s1++) + for (r1=1; r1<=S->len[s1]; r1++) + { + for (b=1; bresidue_index[s1][r1][0]; b+=ICHUNK) + { + s2=CL->residue_index[s1][r1][b+SEQ2]; + r2=CL->residue_index[s1][r1][b+R2]; + + if (b>1) + { + if (s2==ps2 && r2==pr2) + { + + HERE ("%s -- NOT COMPACTED",t); + exit(0); + } + else if ( s2<=ps2 && r2residue_index[s1][r1][0]; c++) + { + fprintf (stderr, "%5d ",CL->residue_index[s1][r1][c]); + } + + exit(0); + } + } + ps2=s2; + pr2=r2; + } + } + return 1; +} + +int checkCL (Constraint_list *CL, char *t) +{ + int fail=0; + int a, b; + + for (a=0; a<(CL->S)->nseq; a++) + for (b=1; b<=(CL->S)->len[a]; b++) + { + HERE ("%s %4d ==> %d",t,CL->residue_index[a][b][0], CL->residue_index[a][b][0]%ICHUNK); + } + + + if (!CL){HERE ("CL is Not declared");fail=1;} + else if ( !CL->S){HERE ("S is not declared in CL");fail=1;} + else if ( !CL->residue_index){HERE ("residue index is not declared");fail=1;} + else if (read_array_size_new (CL->residue_index)!=(CL->S)->nseq){HERE ("CL not well declared (S)");fail=1;} + else + { + for (a=0; a<(CL->S)->nseq; a++) + { + int s=(CL->S)->len[a]+1; + int j=read_array_size_new (CL->residue_index[a]); + if (s!=j)fail=1; + + } + if (fail) + { + for (a=0; a<(CL->S)->nseq; a++) + { + int s=(CL->S)->len[a]+1; + int j=read_array_size_new (CL->residue_index[a]); + if (s!=j)fail=1; + HERE ("\t %s %d %d",(CL->S)->name[a], s-1,j); + } + } + + if ( fail) + { + HERE ("******** CHECKED CL: %s ******", t); + exit (0); + } + } + return 1; +} + +Constraint_list *add_entry2list( CLIST_TYPE *entry, Constraint_list *CL) +{ + //adds an entry and its mirror to the list + //if INDEX is set the entry replaces the entry with a similar index + //otherwise the entry (and its mirror) are added + int s1=entry[SEQ1]; + int s2=entry[SEQ2]; + int r1=entry[R1]; + int r2=entry[R2]; + + if (entry[INDEX])return add_entry2list2(entry, CL); + + entry[SEQ1]=s2; + entry[SEQ2]=s1; + entry[R1]=r2; + entry[R2]=r1; + add_entry2list2 (entry, CL); + + entry[SEQ1]=s1; + entry[SEQ2]=s2; + entry[R1]=r1; + entry[R2]=r2; + add_entry2list2 (entry, CL); + return CL; +} + + +int get_entry_index (int *entry, Constraint_list *CL); +Constraint_list *insert_entry (CLIST_TYPE *entry, Constraint_list *CL, int i); +Constraint_list *update_entry (CLIST_TYPE *entry, Constraint_list *CL, int i); +Constraint_list *reset_entry (CLIST_TYPE *entry, Constraint_list *CL, int i); +Constraint_list *remove_entry (CLIST_TYPE *entry, Constraint_list *CL, int i); +Constraint_list *add_entry2list2 (CLIST_TYPE *entry, Constraint_list *CL) +{ + //adds an entry to the list + int s2=entry[SEQ2]; + int r2=entry[R2]; + + int i=CL->residue_index[entry[SEQ1]][entry[R1]][0]; + if (entry[INDEX]){return reset_entry (entry, CL, entry[INDEX]); } + else if (i==1){insert_entry (entry, CL,1);} + else + { + i=get_entry_index(entry,CL); + if (i<0)insert_entry (entry,CL,-i); + else update_entry (entry, CL, i); + } + return CL; +} + + +static int *sent; +static Constraint_list *sCL; +int get_entry_index_serial (int *entry, Constraint_list *CL); +int get_entry_index_dico (int *entry, Constraint_list *CL); +int get_entry_index (int *entry, Constraint_list *CL) +{ + int s1=entry[SEQ1]; + int r1=entry[R1]; + int *r= CL->residue_index[s1][r1]; + + + return get_entry_index_dico (entry, CL); +} +int get_entry_index_serial (int *entry, Constraint_list *CL) +{ + //return the index of an entry + //positive value: the entry exists on position i + //negative value: the entry must be created on poistion -i + int s1=entry[SEQ1]; + int r1=entry[R1]; + int s2=entry[SEQ2]; + int r2=entry[R2]; + int a; + int *r= CL->residue_index[s1][r1]; + + static int tot; + static int pr; + if (r[0]==1)return -1;//corresponding entry undeclared->must be inserted + else + { + for (a=1; ar2)return -a; + else if (r[a+SEQ2]>s2)return -a; + } + } + return -a; +} + +int get_entry_index_dico (int *entry, Constraint_list *CL) +{ + //return the index of an entry + //positive value: the entry exists on position i + //negative value: the entry must be created on poistion -i + int s1=entry[SEQ1]; + int r1=entry[R1]; + int s2=entry[SEQ2]; + int r2=entry[R2]; + int dir; + int delta; + int i; + int *r= CL->residue_index[s1][r1]; + int ps2, pr2, ns2,nr2,p,n; + static int tot; + static int pr; + + if (r[0]==1)return -1;//corresponding entry undeclared->must be inserted + dir=1; + i=1; + delta=((r[0]-1)/ICHUNK); + delta=MAX(1,(delta/2)); + + while (1==1) + { + pr++; + tot++; + i+=(delta*dir*ICHUNK); + i=MAX(i,1); + i=MIN(i,(r[0])); + if (i1) + { + ps2=r[i-ICHUNK+SEQ2]; + pr2=r[i-ICHUNK+R2]; + p=(s2>ps2 || (s2==ps2 && r2>pr2))?1:0; + } + if (iresidue_index[entry[SEQ1]][entry[R1]]; + int s; + + i+=ICHUNK; + s=r[0]-i; + if (bsizeresidue_index[entry[SEQ1]][entry[R1]]=vrealloc(r,r[0]*sizeof (int)); + CL->ne--; + return CL; +} + +Constraint_list *insert_entry (CLIST_TYPE *entry, Constraint_list *CL, int i) +{ + //insert entry right after i; + static char *buf; + static int bsize; + int a, *from, *to; + int *r=CL->residue_index[entry[SEQ1]][entry[R1]]; + int s; + //inserts a new entry between i-1 and i + + r=vrealloc (r, (r[0]+ICHUNK)*sizeof (int)); + CL->residue_index[entry[SEQ1]][entry[R1]]=r; + CL->ne++; + + s=r[0]-i; + if (bsizeresidue_index[entry[SEQ1]][entry[R1]]; + memcpy (r+i, entry, ICHUNK*sizeof (int)); + return CL; +} +Constraint_list *update_entry (CLIST_TYPE *entry, Constraint_list *CL, int i) +{ + int s1=entry[SEQ1]; + int s2=entry[SEQ2]; + int r1=entry[R1]; + int r2=entry[R2]; + + CL->residue_index[s1][r1][i+SEQ2]=entry[SEQ2]; + CL->residue_index[s1][r1][i+R2] =entry[R2]; + CL->residue_index[s1][r1][i+WE] =MAX(entry[WE],CL->residue_index[s1][r1][i+WE]); + CL->residue_index[s1][r1][i+CONS]+=entry[CONS]; + CL->residue_index[s1][r1][i+MISC]=entry[MISC]; + return CL; +} + +/*********************************************************************/ +/* */ +/* SEARCH IN LIST (ARRAY AND FILE) */ +/* */ +/* */ +/*********************************************************************/ + + + +CLIST_TYPE *main_search_in_list_constraint ( int *key,int *p,int k_len,Constraint_list *CL) +{ + + + static CLIST_TYPE *l=NULL; + int a, s1, s2, r1, r2, ni; + + if (!l)l=vcalloc (CL->entry_len+1, sizeof (int)); + for (a=0; aentry_len; a++)l[a]=key[a]; + + l[INDEX]=1; + + s1=key[SEQ1]; + r1=key[R1]; + s2=key[SEQ2]; + r2=key[R2]; + ni=CL->residue_index[s1][r1][0]; + for (a=1; aresidue_index[s1][r1][a+SEQ2]==s2 && CL->residue_index[s1][r1][a+R2]==r2) + { + l[SEQ1]=s1; + l[R1]=r1; + l[SEQ2]=s2; + l[R2]=r2; + l[WE]=CL->residue_index[s1][r1][a+WE]; + l[INDEX]=a; + return l; + } + } + return NULL; +} + +CLIST_TYPE return_max_constraint_list ( Constraint_list *CL, int field) +{ + return constraint_list2max (CL); +} + + +/*********************************************************************/ +/* */ +/* */ +/* LIST SORTING */ +/* */ +/* */ +/* */ +/*********************************************************************/ +Constraint_list *sort_constraint_list_inv (Constraint_list *CL, int start, int len) +{ + return sort_constraint_list (CL, start, len); + return CL; +} + +Constraint_list *invert_constraint_list (Constraint_list *CL, int start,int len) +{ + int a, b, c; + CLIST_TYPE tp; + + return CL; +} + +Constraint_list * sort_constraint_list(Constraint_list *CL, int start, int len) +{ + + int max=0; + Sequence *S=CL->S; + int b,l,s1,r1,s2,r2,w2; + for (s1=0; s1nseq; s1++) + { + for (r1=1; r1<=S->len[s1]; r1++) + { + int nE=(CL->residue_index[s1][r1][0]-1)/ICHUNK; + int sizE=sizeof(int)*ICHUNK; + int *start=CL->residue_index[s1][r1]+1; + qsort ((void*)start,nE,sizE,compare_constraint_list_entry); + } + } + return CL; +} + + +int compare_constraint_list_entry4bsearch ( const void*vx, const void*vy) +{ + int a; + const int *x=vx, *y=vy; + for (a=0; a<3; a++) + { + if (x[a]y[a]) return 1; + } + return 0; +} +int compare_constraint_list_entry ( const void*vx, const void*vy) +{ + int a; + const int *x=vx, *y=vy; + for (a=0; ay[a]) return 1; + } + return 0; +} +/*********************************************************************/ +/* */ +/* LIST PARSING */ +/* */ +/* */ +/*********************************************************************/ +Constraint_list* fork_read_n_constraint_list(char **fname,int n_list, char *in_mode,char *mem_mode,char *weight_mode, char *type,FILE *local_stderr, Constraint_list *CL, char *seq_source); +Constraint_list* nfork_read_n_constraint_list(char **fname,int n_list, char *in_mode,char *mem_mode,char *weight_mode, char *type,FILE *local_stderr, Constraint_list *CL, char *seq_source); + +Constraint_list* read_n_constraint_list(char **fname,int n_list, char *in_mode,char *mem_mode,char *weight_mode, char *type,FILE *local_stderr, Constraint_list *CL, char *seq_source) +{ + + if ( get_nproc()==1 || n_list<=2)return nfork_read_n_constraint_list(fname,n_list, in_mode,mem_mode,weight_mode,type,local_stderr, CL, seq_source); + else if ( strstr (CL->multi_thread, "methods")) + return fork_read_n_constraint_list(fname,n_list, in_mode,mem_mode,weight_mode,type,local_stderr, CL, seq_source); + else + return nfork_read_n_constraint_list(fname,n_list, in_mode,mem_mode,weight_mode,type,local_stderr, CL, seq_source); +} +Constraint_list* fork_read_n_constraint_list(char **fname,int n_list, char *in_mode,char *mem_mode,char *weight_mode, char *type,FILE *local_stderr, Constraint_list *CL, char *seq_source) +{ + int a, b; + Sequence *S; + char **tmp_list; + int*proclist; + int nproc, ns; + + nproc=get_nproc(); + + proclist=vcalloc (MAX_N_PID, sizeof (int)); + tmp_list=vcalloc (n_list+1, sizeof (char*)); + for (a=0; aS) && (S=read_seq_in_n_list (fname, n_list,type,seq_source))==NULL) + { + myexit (fprintf_error ( stderr, "NO SEQUENCE WAS SPECIFIED")); + } + else if (CL->S==NULL) + { + CL->S=S; + } + + /*CHECK IF THERE IS A MATRIX AND GET RID OF OTHER METHODS*/ + for (b=0, a=0; a< n_list; a++)if (is_matrix(fname[a]) ||is_matrix(fname[a]+1) )b=a+1; + + if ( b) + { + if ( b==1); + else sprintf ( fname[0], "%s", fname[b-1]); + n_list=1; + return nfork_read_n_constraint_list(fname,n_list, in_mode,mem_mode,weight_mode, type,local_stderr, CL, seq_source); + } + + if (!CL)CL=declare_constraint_list ( S,NULL, NULL, 0,(strm(mem_mode, "disk"))?tmpfile():NULL, NULL); + + if (CL->ne) + { + dump_constraint_list(CL,tmp_list[n_list], "w"); + CL->ne=0; + } + + CL->local_stderr=local_stderr; + fprintf ( local_stderr, "\n\tMulti Core Mode: %d processors:\n", nproc); + for (ns=0,a=0; a< n_list; a++) + { + int pid; + ns++; + pid=vvfork (NULL); + if ( pid==0) + { + int in; + initiate_vtmpnam (NULL); + CL->local_stderr=vfopen("/dev/null", "w"); + in=CL->ne; + CL=read_constraint_list (CL, fname[a], in_mode, mem_mode,weight_mode); + if (CL->ne>in)dump_constraint_list(CL,tmp_list[a], "w"); + myexit (EXIT_SUCCESS); + } + else + { + + //set_pid (pid); + fprintf ( local_stderr, "\n\t--- Process Method/Library/Aln %s", fname[a], ns); + proclist[pid]=a; + if (ns>=nproc) + { + b=proclist[vwait(NULL)]; + fprintf (local_stderr, "\n\txxx Retrieved %s",fname[a]); + if (tmp_list[b] && check_file_exists (tmp_list[b])) + { + CL=undump_constraint_list(CL,tmp_list[b]); + } + ns--; + } + } + } + + while (ns) + { + int pid2; + pid2=vwait(NULL); + a=proclist[pid2]; + fprintf (local_stderr, "\n\txxx Retrieved %s",fname[a]); + if (tmp_list[a] && check_file_exists (tmp_list[a])) + { + CL=undump_constraint_list (CL,tmp_list[a]); + } + ns--; + } + fprintf ( local_stderr, "\n\n\tAll Methods Retrieved\n"); + + if (tmp_list[n_list] && check_file_exists (tmp_list[n_list])) + { + CL=undump_constraint_list(CL,tmp_list[n_list]); + } + + CL->local_stderr=local_stderr; + + vfree (proclist); + vfree (tmp_list); + return CL; +} +Constraint_list* nfork_read_n_constraint_list(char **fname,int n_list, char *in_mode,char *mem_mode,char *weight_mode, char *type,FILE *local_stderr, Constraint_list *CL, char *seq_source) +{ + int a, b; + Sequence *S; + + + if (!(CL->S) && (S=read_seq_in_n_list (fname, n_list,type,seq_source))==NULL) + { + fprintf ( stderr, "\nNO SEQUENCE WAS SPECIFIED[FATAL]\n"); + myexit(EXIT_FAILURE); + } + else if (CL->S==NULL) + { + CL->S=S; + } + + /*CHECK IF THERE IS A MATRIX AND GET RID OF OTHER METHODS*/ + for (b=0, a=0; a< n_list; a++)if (is_matrix(fname[a]) ||is_matrix(fname[a]+1) )b=a+1; + + if ( b) + { + if ( b==1); + else sprintf ( fname[0], "%s", fname[b-1]); + n_list=1; + + } + + if (!CL)CL=declare_constraint_list ( S,NULL, NULL, 0,(strm(mem_mode, "disk"))?tmpfile():NULL, NULL); + CL->local_stderr=local_stderr; + fprintf ( CL->local_stderr,"\nREAD/MAKE LIBRARIES:[%d]\n",n_list ); + + CL=read_constraint_list (CL, fname[0], in_mode, mem_mode,weight_mode); + for ( a=1; a< n_list; a++) + { + CL=read_constraint_list (CL, fname[a], in_mode, mem_mode,weight_mode); + } + CL->local_stderr=local_stderr; + + return CL; +} +Constraint_list* read_constraint_list(Constraint_list *CL,char *in_fname,char *in_mode, char *mem_mode,char *weight_mode) +{ + Sequence *SL=NULL, *TS=NULL; + int a; + Constraint_list *SUBCL=NULL; + static char *read_mode; + char *fname; + + fname=in_fname; + if ( !read_mode)read_mode=vcalloc ( STRING, sizeof (char)); + + if ( is_lib_list (in_fname))sprintf ( read_mode, "lib_list"); + else if ( in_mode)sprintf (read_mode, "%s", in_mode); + else if ( fname[0]=='A'){sprintf ( read_mode, "aln");fname++;} + else if ( fname[0]=='L'){sprintf ( read_mode, "lib");fname++;} + else if ( fname[0]=='M'){sprintf ( read_mode, "method");fname++;} + else if ( fname[0]=='S'){sprintf ( read_mode, "sequence");return CL;} + else if ( fname[0]=='P'){sprintf ( read_mode, "pdb") ;return CL;} + else if ( fname[0]=='R'){sprintf ( read_mode, "profile") ;return CL;} + else if ( fname[0]=='X'){sprintf ( read_mode, "matrix");++fname;} + else if ( fname[0]=='W'){sprintf ( read_mode, "structure");fname++;} + else + { + fprintf ( stderr, "\nERROR: The descriptor %s could not be identified as a file or a method.[FATAL]\nIf it is a method file please indicate it with M%s\n", fname, fname); + myexit (EXIT_SUCCESS); + } + + fprintf (CL->local_stderr, "\n\t%s [%s]\n", fname, read_mode); + + + if ( strm (read_mode, "lib_list")) + { + int n, a; + char **l; + l=read_lib_list (fname, &n); + for ( a=0; aS, fname,weight_mode,mem_mode); + } + else if (strm(read_mode, "matrix")) + { + CL->residue_index=NULL; + CL->extend_jit=0; + CL->M=read_matrice ( fname); + } + else if ( strm ( read_mode, "structure")) + { + if ( CL->ne>0) + { + fprintf ( stderr, "\nERROR: Wstructure must come before Mmethod or Aaln [FATAL:%s]",PROGRAM); + myexit (EXIT_FAILURE); + } + + if ( !(CL->STRUC_LIST)) + { + CL->STRUC_LIST=declare_sequence (1,1,10000); + (CL->STRUC_LIST)->nseq=0; + } + SL=CL->STRUC_LIST; + + if ( check_file_exists(fname)) + { + TS=main_read_seq ( fname); + for (a=0; anseq; a++)sprintf (SL->name[SL->nseq++], "%s", TS->name[a]); + free_sequence (TS, TS->nseq); + } + else + { + sprintf (SL->name[SL->nseq++], "%s", fname); + } + } + else if (strm (read_mode, "aln")) + { + CL=aln_file2constraint_list ( fname,CL,weight_mode); + } + else + { + SUBCL=read_constraint_list_file(SUBCL, fname); + } + + + if (SUBCL) + { + CL=merge_constraint_list (SUBCL, CL, "default"); + free_constraint_list_full (SUBCL); + } + + return CL; +} + +#define is_seq_source(Symbol,Mode,SeqMode) (Symbol==Mode && (SeqMode==NULL || strm (SeqMode, "ANY") || (SeqMode[0]!='_' && strchr (SeqMode,Symbol)) || (SeqMode[0]=='_' && !strchr (SeqMode,Symbol)))) +Sequence * read_seq_in_n_list(char **fname, int n, char *type, char *SeqMode) +{ + int nseq=0; + int a, b; + Alignment *A; + char **sequences=NULL; + char **seq_name=NULL; + Sequence *S=NULL; + Sequence *S1; + char mode; + + + + /*THE TYPE OF EACH FILE MUST BE INDICATED*/ + /*SeqMode indicates the type of file that can be used as sequence sources*/ + /* + ANY: any mode + SL: only sequences from Libraries and Sequences + _A: anything BUT sequences from A(lignments) + */ + + if ( n==0) + { + myexit (fprintf_error ( stderr, "NO in FILE")); + } + else + { + for ( a=0; a< n ; a++) + { + static char *buf; + char *lname; + if (buf)vfree (buf); + + + buf=name2type_name(fname[a]);mode=buf[0];lname=buf+1; + + if (is_seq_source ('A', mode, SeqMode)) + { + + + A=main_read_aln (lname,NULL); + + S1=aln2seq(A); + S1=seq2unique_name_seq (S1); + if ((S=merge_seq ( S1, S))==NULL){fprintf ( stderr, "\nERROR: Sequence Error in %s [FATAL:%s]\n",lname, PROGRAM); myexit(EXIT_FAILURE);} + free_aln (A); + free_sequence (S1, S1->nseq); + } + else if ( is_seq_source ('R', mode, SeqMode)) + { + S=add_prf2seq (lname, S); + + } + else if (is_seq_source ('P', mode, SeqMode)) + { + int i; + + S1=get_pdb_sequence (lname); + if (S1==NULL) + { + add_warning ( stderr, "\nWarning: Could not use PDB: %s", lname); + } + else + { + if ((S=merge_seq ( S1, S))==NULL){fprintf ( stderr, "\nERROR: Sequence Error in %s [FATAL:%s]\n",lname, PROGRAM); myexit(EXIT_FAILURE);} + i=name_is_in_list (S1->name[0], S->name, S->nseq, 100); + (S->T[i])->P=fill_P_template (S->name[i], lname, S); + } + free_sequence (S1, S1->nseq); + } + else if ( mode=='M'); + else if ( mode=='X'); + else if ( mode=='W'); + + else if (is_seq_source ('S', mode, SeqMode)) + { + /*1 Try with my routines (read t_coffee and MSF)*/ + if ( (A=main_read_aln ( lname, NULL))!=NULL) + { + + S1=aln2seq(A); + free_aln(A); + } + else + { + S1=main_read_seq (lname); + } + + for ( b=0; b< S1->nseq; b++)ungap(S1->seq[b]); + S1=seq2unique_name_seq (S1); + + + if ((S=merge_seq ( S1, S))==NULL){fprintf ( stderr, "\nSequence Error in %s [FATAL:%s]\n",lname,PROGRAM); myexit(EXIT_FAILURE);} + + free_sequence (S1,S1->nseq); + + } + else if (is_seq_source ('L', mode, SeqMode)) + { + + read_seq_in_list (lname,&nseq,&sequences,&seq_name); + S1=fill_sequence_struc ( nseq, sequences, seq_name); + + for ( b=0; b< S1->nseq; b++)sprintf ( S1->file[b], "%s", lname); + nseq=0;free_char (sequences, -1); free_char ( seq_name, -1); + sequences=NULL; + seq_name=NULL; + S1=seq2unique_name_seq (S1); + + if ((S=merge_seq( S1, S))==NULL){fprintf ( stderr, "\nSequence Error in %s [FATAL:%s]\n",lname,PROGRAM); myexit(EXIT_FAILURE);} + free_sequence(S1, S1->nseq); + } + + else if ( !strchr ( "ALSMXPRWG", mode)) + { + myexit (fprintf_error ( stderr, "%s is neither a file nor a method [FATAL:%s]\n", lname)); + } + } + + S=remove_empty_sequence (S); + + + if ( type && type[0] )sprintf ( S->type, "%s", type); + else S=get_sequence_type (S); + + if ( strm (S->type, "PROTEIN_DNA")) + { + for ( a=0; a< S->nseq; a++) + { + if (strm ( get_string_type ( S->seq[a]), "DNA") ||strm ( get_string_type ( S->seq[a]), "RNA") ); + else if ( strm ( get_string_type ( S->seq[a]), "PROTEIN")) + { + S->seq[a]=thread_aa_seq_on_dna_seq (S->seq[a]); + S->len[a]=strlen (S->seq[a]); + S->max_len=MAX(S->max_len, S->len[a]); + } + } + } + + + + return S; + } + + + + return NULL; +} + +int read_cpu_in_list ( char *fname) +{ + FILE *fp; + int c; + int cpu=0; + + fp=vfopen ( fname, "r"); + while ( (c=fgetc(fp))!='#'); + while ( (c=fgetc(fp))!='C' && c!=EOF); + if ( c=='C')fscanf( fp, "PU %d\n", &cpu); + vfclose ( fp); + return cpu; +} +char * expand_constraint_list_file ( char *file) +{ + char *new_file; + FILE *IN, *OUT; + int a, b, c, n; + char **list; + static char *buf; + + if (!token_is_in_file (file,"+BLOCK+"))return file; + + new_file=vtmpnam (NULL); + IN=vfopen ( file,"r"); + OUT=vfopen (new_file, "w"); + + while ( (c=fgetc (IN))!=EOF) + { + ungetc (c, IN); + buf=vfgets (buf, IN); + if ( !strstr (buf, "+BLOCK+")) + fprintf (OUT, "%s", buf); + else + { + list=string2list (buf); + n=atoi (list[2]); + + for (a=0; a< n; a++) + { + fprintf ( OUT, "%5d %5d ",atoi(list[3])+a, atoi(list[4])+a); + for (b=5; bentry_len+1, sizeof (int)); + HERE ("cncn: making artificial lib");//Keep this warning alive + S=CL->S; + + fprintf ( stderr, "\n"); + for (a=0; a< S->nseq-1; a++) + { + fprintf ( stderr, "[%d-%d]", a, CL->ne); + for ( b=a+1; b< S->nseq; b++) + { + + l1=MIN(S->len[a], S->len[b]); + l1=MIN(10, l1); + for (c=0; cS); + entry=vcalloc ( CL->entry_len+1, sizeof (int)); + + fp=vfopen(fname,"r"); + while ((c=fgetc(fp))!='#' && c!=EOF){line+=(c=='\n')?1:0;} + + ungetc (c, fp); + while ((buf=vfgets ( buf, fp))!=NULL) + { + line++; + if (buf[0]=='!')continue; + else if (buf[0]=='#') + { + sscanf ( buf, "#%d %d", &s1, &s2); + s1--; s2--; + if (s1>NS->nseq || s2>NS->nseq)error=1; + } + else + { + cons=misc=r1=r2=we=0; + x=sscanf (buf, "%d %d %d %d %d",&r1,&r2,&we,&cons,&misc); + + if (r1>NS->len[s1] || r2>NS->len[s2] || x<3)error=1; + else + { + + entry[SEQ1]=index[s1][0]; + entry[SEQ2]=index[s2][0]; + entry[R1]=index[s1][r1]; + entry[R2]=index[s2][r2]; + entry[WE]=we; + entry[CONS]=cons; + entry[MISC]=misc; + if (entry[SEQ1]>-1 && entry[SEQ2]>-1 && entry[R1]>0 && entry[R2]>0 && entry[WE]>0) + add_entry2list (entry, CL); + } + } + if (error)printf_exit (EXIT_FAILURE,stderr,"Parsing Error [L:%d F:%s S:%s]",line,in_fname,buf); + } + vfclose (fp); + + if (!keepNS)free_sequence (NS,-1); + vfree (entry); + vfree (buf); + free_int (index, -1); + return CL; +} + +int read_seq_in_list ( char *fname, int *nseq, char ***sequences, char ***seq_name) +{ + int a; + int seq_len, sn; + + FILE *fp; + char name[1000]; + char *sequence; + static int max_nseq; + static int *sn_list; + int list_nseq; + int lline; + + fp=vfopen (fname, "r"); + fp=skip_commentary_line_in_file ('!', fp); + fscanf (fp, "%d\n", &max_nseq); + for ( lline=0,a=0; aS || CL->residue_index)return fp; + if ( !fp)fp=stdout; + + + fp=save_list_header (fp,CL); + + + for ( a=0; a< (CL->S)->nseq; a++) + { + for ( b=a; b<(CL->S)->nseq; b++) + { + + if ( a==b && !CL->do_self)continue; + fp=save_extended_constraint_list_pair(CL, mode, (CL->S)->name[a], (CL->S)->name[b], fp); + } + } + fprintf (fp, "! SEQ_1_TO_N\n"); + return fp; +} + + +FILE * save_extended_constraint_list_pair ( Constraint_list *CL, char *mode, char* seq1, char * seq2,FILE *fp) +{ + int a, b, t; + int s1, s2, score; + char *p; + + + if ((p=strstr (mode, "THR"))!=NULL)t=atoi(p+3); + else t=0; + + s1=name_is_in_list (seq1,(CL->S)->name, (CL->S)->nseq, 100); + s2=name_is_in_list (seq2,(CL->S)->name, (CL->S)->nseq, 100); + + if ( s1==-1) + { + fprintf ( stderr, "Output Error: %s is not a sequence [FATAL:%s]\n", seq1, PROGRAM); + crash (""); + } + if ( s2==-1) + { + fprintf ( stderr, "Output Error: %s is not a sequence [FATAL:%s]\n", seq2, PROGRAM); + crash (""); + } + + if ( strstr (mode, "pair"))fprintf (fp, "# 1 2\n"); + else if ( strstr (mode, "lib"))fprintf (fp, "# %d %d\n", s1+1, s2+1); + + for ( a=0; a<(CL->S)->len[s1]; a++) + { + for ( b=0; b<(CL->S)->len[s2]; b++) + { + if ( a>=b && s1==s2)continue; + if ( strstr (mode, "pc"))score=residue_pair_extended_list_pc (CL, s1,a+1, s2, b+1); + else if ( strstr (mode, "raw"))score=residue_pair_extended_list_raw (CL, s1,a+1, s2, b+1); + else + score=CL->evaluate_residue_pair (CL, s1,a+1, s2, b+1); + + if (score<=t) continue; + fprintf (fp, "%5d %5d %5d \n", a+1, b+1, score); + + } + } + return fp; +} + + +/*********************************************************************/ +/* */ +/* LIST OUTPUT */ +/* */ +/* */ +/*********************************************************************/ +#ifdef MMMMMMMM +FILE *save_extended_constraint_list ( Constraint_list *CL,Sequence *S, char *fname) +{ + int a, b, c, d; + int *tr, *ns; + int **pos0, **l_s; + int epsilon=0; + Alignment *A; + FILE *fp; + + fp=vfopen (fname, "w"); + fp=save_sub_list_header(fp, S->nseq, S->name, CL); + + tr=vcalloc (S->nseq+1, sizeof (int)); + for ( b=0,a=0; a< S->nseq; a++) + { + int i; + if ( (i=name_is_in_list(S->name[a],(CL->S)->name,(CL->S)->nseq, 100))==-1) + { + printf_exit (EXIT_FAILURE, stderr, "\nERROR: Sequence %s is not part of the sequence dataset [FATAL:%s]", S->name[a], PROGRAM); + + } + else + { + tr[a]=i; + } + } + + A=declare_aln (S); + pos0=vcalloc ( S->nseq, sizeof (int*)); + for (a=0; anseq; a++) + { + int l; + l=strlen (S->seq[a]); + A->seq_al[a]=S->seq[a]; + pos0[a]=vcalloc (l+1, sizeof (int)); + for (b=0; bnseq-1; a++) + for ( b=a+1; bnseq; b++) + { + int pos_i, pos_j, s; + l_s[0]=tr[a];l_s[1]=tr[b]; + for ( pos_i=0; pos_i< S->len[a]; pos_i++) + for (pos_j=0; pos_jlen[b]; pos_j++) + { + s=(CL->get_dp_cost) ( A, pos0, ns[0], l_s[0], i-1, pos0, ns[1], l_s[1],pos_j-1, CL); + if (s>epsilon)fprintf (fp, "%d %d %d", i, j, s); + } + } + return fp; +} +#endif + +FILE * save_constraint_list ( Constraint_list *CL,int start, int len, char *fname, FILE *fp,char *mode, Sequence *S) +{ + int a, b; + static int* translation; + + + if ( fp==NULL) + { + if ( translation!=NULL)vfree(translation); + translation=vcalloc ( (CL->S)->nseq+1, sizeof (int)); + for ( b=0,a=0; a< (CL->S)->nseq; a++) + { + if ( name_is_in_list((CL->S)->name[a],S->name,S->nseq, 100)==-1) + { + (CL->S)->len[a]=-1; + translation [a]=-1; + } + else + { + translation[a]=b++; + } + } + + } + if (strm2(mode, "lib","ascii")) + { + if ( fp==NULL)fp=vfopen ( fname, "w"); + fp=save_list_header (fp,CL); + fp=save_constraint_list_ascii(fp, CL, 0, CL->ne, translation); + } + + else + { + + myexit(fprintf (stderr,"\nUNKOWN MODE FOR OUTPUT: %s", mode)); + } + return fp; +} + +FILE * save_sub_list_header ( FILE *OUT, int n, char **name, Constraint_list *CL) +{ + int a,b; + int nseq=0; + + + + for ( a=0; a<(CL->S)->nseq; a++) + for ( b=0; bS)->name[a])) + nseq+=((CL->S)->len[a]!=-1); + + fprintf ( OUT, "! TC_LIB_FORMAT_01\n%d\n",nseq); + for ( a=0; aS)->nseq; b++) + if (strm (name[a] , (CL->S)->name[b])) + if ((CL->S)->len[b]!=-1) fprintf ( OUT, "%s %d %s\n", (CL->S)->name[b], (CL->S)->len[b],(CL->S)->seq[b]); + + return OUT; +} +FILE * save_list_header ( FILE *OUT,Constraint_list *CL) +{ + int a; + int nseq=0; + + for ( a=0; a<(CL->S)->nseq; a++)nseq+=((CL->S)->len[a]!=-1); + + + fprintf ( OUT, "! TC_LIB_FORMAT_01\n%d\n",nseq); + for ( a=0; a<(CL->S)->nseq; a++) + if ((CL->S)->len[a]!=-1) + { + fprintf ( OUT, "%s %d %s\n", (CL->S)->name[a], (CL->S)->len[a],(CL->S)->seq[a]); + + } + return OUT; +} + +FILE *save_list_footer (FILE *OUT,Constraint_list *CL) +{ + if ( CL->cpu)fprintf (OUT, "! CPU %d\n",get_time()); + fprintf (OUT, "! SEQ_1_TO_N\n"); + return OUT; +} + +FILE * save_constraint_list_ascii ( FILE *OUT,Constraint_list *CL, int start,int len, int *translation) +{ + int a, b, s1, s2, r1, r2, w2,x1, x2; + + if (len==start && CL->cpu!=-1) + { + fprintf (OUT, "! CPU %d\n",get_time()); + return OUT; + } + else + { + Sequence *S=CL->S; + int ***cacheI=vcalloc (S->nseq, sizeof (int**)); + int **cacheR=vcalloc (S->nseq, sizeof (int*)); + int *tot=vcalloc ( S->nseq, sizeof (int)); + int *max=vcalloc ( S->nseq, sizeof (int)); + for (a=0;anseq; a++) + { + cacheI[a]=vcalloc (S->len[a], sizeof (int*)); + cacheR[a]=vcalloc (S->len[a], sizeof (int)); + } + for (a=0; anseq; a++)max[a]=S->len[a]; + + for (s1=0; s1nseq; s1++) + { + for (r1=1; r1<=S->len[s1]; r1++) + { + for (b=1; bresidue_index[s1][r1][0]; b+=ICHUNK) + { + + s2=CL->residue_index[s1][r1][b+SEQ2]; + if (tot[s2]>=max[s2]) + { + max[s2]+=100; + cacheI[s2]=vrealloc (cacheI[s2], max[s2]*sizeof (int*)); + cacheR[s2]=vrealloc (cacheR[s2], max[s2]*sizeof (int*)); + } + + cacheI[s2][tot[s2]]=CL->residue_index[s1][r1]+b; + cacheR[s2][tot[s2]]=r1; + tot[s2]++; + } + } + + for (s2=0;s2nseq; s2++) + { + int x1=translation[s1]; + int x2=translation[s2]; + if (tot[s2] && x1!=-1 && x2!=-1 && x1nseq; a++) + { + vfree (cacheI[a]); + vfree (cacheR[a]); + } + vfree (cacheI); vfree (cacheR); + vfree (tot); + vfree (max); + } + + return save_list_footer (OUT, CL); + +} + + +/*********************************************************************/ +/* */ +/* LIST CONVERTION */ +/* */ +/* */ +/*********************************************************************/ + + + +Constraint_list * extend_constraint_list ( Constraint_list *CL) +{ + Sequence *S; + int **cache; + int tot=0; + char *tmp; + FILE *fp; + int a,e,b,c; + int s1, r1, s2, r2,w2, s3, r3, w3; + + static int *entry; + if (!CL || !CL->residue_index || !CL->S)return CL; + S=CL->S; + + tmp=vtmpnam (NULL); + fp=vfopen (tmp, "w"); + cache=declare_int (S->nseq, S->max_len+1); + if (!entry)entry=vcalloc ( CL->entry_len+1, sizeof (int)); + for (s1=0; s1< S->nseq; s1++) + { + for ( r1=1; r1<=S->len[s1]; r1++) + { + + cache[s1][r1]=1; + + + for ( a=1; aresidue_index[s1][r1][0]; a+=ICHUNK) + { + + s2=CL->residue_index[s1][r1][a+SEQ2]; + r2=CL->residue_index[s1][r1][a+R2]; + w2=CL->residue_index[s1][r1][a+WE]; + cache[s2][r2]=w2; + } + + for ( a=1; aresidue_index[s1][r1][0]; a+=ICHUNK) + { + s2=CL->residue_index[s1][r1][a+SEQ2]; + r2=CL->residue_index[s1][r1][a+R2]; + w2=CL->residue_index[s1][r1][a+WE]; + + for (b=1; bresidue_index[s2][r2][0]; b+=ICHUNK) + { + s3=CL->residue_index[s2][r2][b+SEQ2]; + r3=CL->residue_index[s2][r2][b+R2]; + w3=CL->residue_index[s2][r2][b+WE]; + + if (!cache[s3][r3] && s3>s1) + { + int ts,tr; + + entry[SEQ1]=s1; + entry[R1]=r1; + entry[SEQ2]=s3; + entry[R2]=r3; + entry[WE]=MIN(w2, w3); + entry [CONS]=1; + tot++;c++; + for (e=0; eentry_len; e++)fprintf ( fp, "%d ", entry[e]); + + entry[SEQ1]=s3; + entry[R1]=r3; + entry[SEQ2]=s1; + entry[R2]=r1; + for (e=0; eentry_len; e++)fprintf ( fp, "%d ", entry[e]); + } + } + } + cache[s1][r1]=0; + for ( a=1; aresidue_index[s1][r1][0]; a+=ICHUNK) + { + s2=CL->residue_index[s1][r1][a+SEQ2]; + r2=CL->residue_index[s1][r1][a+R2]; + cache[s2][r2]=0; + } + } + } + vfclose (fp); + CL=undump_constraint_list(CL, tmp); + free_int (cache, -1); + return CL; +} + +Constraint_list * nfork_relax_constraint_list (Constraint_list *CL); +Constraint_list * fork_relax_constraint_list (Constraint_list *CL); +Constraint_list * relax_constraint_list (Constraint_list *CL) +{ + + if (!CL || !CL->S || !CL->residue_index) return CL; + + + if ( get_nproc()==1)return nfork_relax_constraint_list (CL); + else if (strstr ( CL->multi_thread, "relax"))return fork_relax_constraint_list (CL); + else return nfork_relax_constraint_list (CL); +} + + +Constraint_list * fork_relax_constraint_list (Constraint_list *CL) +{ + int a, s1, s2, r1, r2,j; + + int thr=10; + FILE *fp; + char **pid_tmpfile; + int sjobs, njobs; + int **sl; + Sequence *S; + int in; + + static int **hasch; + static int max_len; + int norm1, norm2; + int t_s1, t_s2, t_r1, t_r2,x; + float score; + int np; + + njobs=get_nproc(); + + if (!CL || !CL->residue_index)return CL; + fprintf ( CL->local_stderr, "\nLibrary Relaxation: Multi_proc [%d]\n ", get_nproc()); + + if ( !hasch || max_len!=(CL->S)->max_len) + { + max_len=(CL->S)->max_len; + if ( hasch) free_int ( hasch, -1); + hasch=declare_int ( (CL->S)->nseq, (CL->S)->max_len+1); + } + + S=CL->S; + in=CL->ne; + + sl=n2splits (njobs, (CL->S)->nseq); + pid_tmpfile=vcalloc (njobs, sizeof (char*)); + + for (sjobs=0,j=0;jlocal_stderr,s1,sl[0][1],1, "Relax Library"); + for (r1=1; r1len[s1]; r1++) + { + norm1=0; + + for (x=1; x< CL->residue_index[s1][r1][0]; x+=ICHUNK) + { + t_s1=CL->residue_index[s1][r1][x+SEQ2]; + t_r1=CL->residue_index[s1][r1][x+R2]; + hasch[t_s1][t_r1]=CL->residue_index[s1][r1][x+WE]; + norm1++; + } + for ( a=1; aresidue_index[s1][r1][0]; a+=ICHUNK) + { + score=0; + norm2=0; + s2=CL->residue_index[s1][r1][a+SEQ2]; + r2=CL->residue_index[s1][r1][a+R2]; + for (x=1; x< CL->residue_index[s2][r2][0]; x+=ICHUNK) + { + t_s2=CL->residue_index[s2][r2][x+SEQ2]; + t_r2=CL->residue_index[s2][r2][x+R2]; + norm2++; + + if (t_s2==s1 && t_r2==r1)score+=CL->residue_index[s2][r2][x+WE]; + else if (hasch[t_s2][t_r2]) + { + score+=MIN((((float)hasch[t_s2][t_r2])),(((float)CL->residue_index[s2][r2][x+WE]))); + } + } + norm2=MIN(norm1,norm2); + score=((norm2)?score/norm2:0); + fprintf (fp, "%d ",(int)(score)); + } + for (x=1; x< CL->residue_index[s1][r1][0]; x+=ICHUNK) + { + t_s1=CL->residue_index[s1][r1][x+SEQ2]; + t_r1=CL->residue_index[s1][r1][x+R2]; + hasch[t_s1][t_r1]=0; + } + } + } + vfclose (fp); + myexit (EXIT_SUCCESS); + } + else + { + sjobs++; + } + } + + while (sjobs>=0){vwait(NULL); sjobs--;}//wait for all jobs to complete + for (j=0; jlen[s1]; r1++) + for ( a=1; aresidue_index[s1][r1][0]; a+=ICHUNK) + { + if (!(fscanf ( fp, "%d ", &CL->residue_index[s1][r1][a+WE]))) + { + printf_exit (EXIT_FAILURE,stderr, "Could not complete relaxation cycle"); + } + } + vfclose (fp); + remove (pid_tmpfile[j]); + } + + CL=filter_constraint_list (CL,WE,thr); + fprintf ( CL->local_stderr, "\nRelaxation Summary: [%d]--->[%d]\n", in,CL->ne); + vfree (pid_tmpfile); + free_int (sl, -1); + return CL; +} + + +Constraint_list * nfork_relax_constraint_list (Constraint_list *CL) +{ + int s1, r1, s2, r2, a; + Sequence *S=CL->S; + char *tmp; + FILE *fp; + int thr=10; + int nne; + static int **hasch; + static int max_len; + int norm1, norm2; + int t_s1, t_s2, t_r1, t_r2,x; + float score; + + tmp=vtmpnam(NULL); + if (!CL || !CL->residue_index)return CL; + + fprintf ( CL->local_stderr, "\nLibrary Relaxation:[%d] ", CL->ne); + nne=CL->ne; + + fp=vfopen (tmp, "w"); + + if ( !hasch || max_len!=(CL->S)->max_len) + { + max_len=(CL->S)->max_len; + if ( hasch) free_int ( hasch, -1); + hasch=declare_int ( (CL->S)->nseq, (CL->S)->max_len+1); + } + + + for (s1=0; s1< S->nseq; s1++) + { + output_completion (CL->local_stderr,s1,S->nseq,1, "Relax Library"); + for ( r1=1; r1<=S->len[s1]; r1++) + { + norm1=0; + + for (x=1; x< CL->residue_index[s1][r1][0]; x+=ICHUNK) + { + t_s1=CL->residue_index[s1][r1][x+SEQ2]; + t_r1=CL->residue_index[s1][r1][x+R2]; + hasch[t_s1][t_r1]=CL->residue_index[s1][r1][x+WE]; + norm1++; + } + + for ( a=1; aresidue_index[s1][r1][0]; a+=ICHUNK) + { + score=0; + norm2=0; + s2=CL->residue_index[s1][r1][a+SEQ2]; + r2=CL->residue_index[s1][r1][a+R2]; + + for (x=1; x< CL->residue_index[s2][r2][0]; x+=ICHUNK) + { + t_s2=CL->residue_index[s2][r2][x+SEQ2]; + t_r2=CL->residue_index[s2][r2][x+R2]; + norm2++; + + if (t_s2==s1 && t_r2==r1)score+=CL->residue_index[s2][r2][x+WE]; + else if (hasch[t_s2][t_r2]) + { + score+=MIN((((float)hasch[t_s2][t_r2])),(((float)CL->residue_index[s2][r2][x+WE]))); + } + } + norm2=MIN(norm1,norm2); + score=((norm2)?score/norm2:0); + fprintf (fp, "%d ",(int)(score)); + } + + for (x=1; x< CL->residue_index[s1][r1][0]; x+=ICHUNK) + { + t_s1=CL->residue_index[s1][r1][x+SEQ2]; + t_r1=CL->residue_index[s1][r1][x+R2]; + hasch[t_s1][t_r1]=0; + } + } + } + vfclose (fp); + fp=vfopen (tmp, "r"); + + for (s1=0; s1< S->nseq; s1++) + { + for ( r1=1; r1<=S->len[s1]; r1++) + { + + for ( a=1; aresidue_index[s1][r1][0]; a+=ICHUNK) + { + + fscanf (fp, "%d ", &CL->residue_index[s1][r1][a+WE]); + } + } + } + vfclose (fp); + filter_constraint_list (CL,WE,thr); + fprintf ( CL->local_stderr, "--->[%d]\n", CL->ne); + return CL; +} + + +// relax constraint list for gene prediction +Constraint_list * expand_constraint_list_4gp (Constraint_list *CL, int T) +{ + int *L; + int chunck=500; + int max=500; + int n=0; + int s1, s2, r1, r2,a,b,c,d,w; + Sequence *S; + int *entry; + + entry=vcalloc (CL->entry_len+1, sizeof (int)); + + S=CL->S; + for (a=0; anseq; a++)//loop sequences + { + for (b=1; b<=S->len[a];b++) + { + for (c=1; cresidue_index[a][b][0];c+=ICHUNK) + { + + + s2=a; + r2=b; + s1=CL->residue_index[a][b][c+SEQ2];; + r1=CL->residue_index[a][b][c+R2]; + w=residue_pair_extended_list_4gp (CL,s1, r1,s2, r2); + if (w>T) + { + entry[SEQ2]=s2; + entry[SEQ1]=s1; + entry[R1]=r2; + entry[R2]=r1; + entry[WE]=w; + add_entry2list (entry, CL); + } + for (d=c+3; dresidue_index[a][b][0]; d+=ICHUNK) + { + s2=CL->residue_index[a][b][d]; + r2=CL->residue_index[a][b][d+1]; + w=residue_pair_extended_list_4gp (CL,s1, r1,s2, r2); + if (w>T) + { + entry[SEQ2]=s2; + entry[SEQ1]=s1; + entry[R1]=r2; + entry[R2]=r1; + entry[WE]=w; + } + } + } + } + } + vfree (entry); + return CL; +} + + +Constraint_list * nfork_relax_constraint_list_4gp (Constraint_list *CL); +Constraint_list * fork_relax_constraint_list_4gp (Constraint_list *CL); +Constraint_list * relax_constraint_list_4gp (Constraint_list *CL) +{ + if ( get_nproc()==1)return nfork_relax_constraint_list_4gp (CL); + else if (strstr ( CL->multi_thread, "relax"))return fork_relax_constraint_list_4gp (CL); + else return nfork_relax_constraint_list_4gp (CL); +} + +Constraint_list * fork_relax_constraint_list_4gp (Constraint_list *CL) +{ + int a, s1, s2, r1, r2,n; + int score; + int thr; + int chunk, npid, job,pid; + FILE *fp; + char **pid_tmpfile; + int * pid_list; + int in; + + return nfork_relax_constraint_list_4gp(CL); + + #ifdef ladygaga + + in=CL->ne; + if (!CL || !CL->L)return CL; + + + + if ((chunk=CL->ne/get_nproc())==0)chunk=get_nproc(); + + + pid_tmpfile=vcalloc ((CL->ne/chunk)+1, sizeof (char*)); + pid_list =vcalloc (MAX_N_PID, sizeof (int *)); + + for (npid=0,job=0; jobne; job+=chunk) + { + pid_tmpfile[npid]=vtmpnam(NULL); + pid=vvfork (NULL); + if (pid==0) + { + int s,e; + + initiate_vtmpnam (NULL); + s=job; + e=MIN((s+chunk),CL->ne); + fp=vfopen (pid_tmpfile[npid], "w"); + for (a=s; aL[a*CL->entry_len+SEQ1]; + s2=CL->L[a*CL->entry_len+SEQ2]; + + r1=CL->L[a*CL->entry_len+R1]; + r2=CL->L[a*CL->entry_len+R2]; + score=residue_pair_extended_list_4gp (CL,s1, r1,s2, r2); + CL->L[a*CL->entry_len+WE]=score; + fprintf (fp, "%d %d ", a, score); + } + vfclose (fp); + myexit (EXIT_SUCCESS); + } + else + { + pid_list[pid]=npid; + //set_pid (pid); + npid++; + } + } + + for (a=0; aL[i*CL->entry_len+WE]=score;j++;} + vfclose (fp); + remove(pid_tmpfile[pid_list[pid]]); + } + + vfree (pid_list); + vfree (pid_tmpfile); + + thr=0; + + for (n=0,a=0; a< CL->ne; a++) + { + score=CL->L[a*CL->entry_len+WE]; + + if (score<=thr); + else + { + CL->L[n*CL->entry_len+SEQ1]=CL->L[a*CL->entry_len+SEQ1]; + CL->L[n*CL->entry_len+SEQ2]=CL->L[a*CL->entry_len+SEQ2]; + CL->L[n*CL->entry_len+R1]=CL->L[a*CL->entry_len+R1]; + CL->L[n*CL->entry_len+R2]=CL->L[a*CL->entry_len+R2]; + CL->L[n*CL->entry_len+WE]=score; + n++; + } + + } + + CL->L=vrealloc (CL->L, n*CL->entry_len*sizeof (int)); + CL->ne=n; + s return CL; + #endif +} +Constraint_list * nfork_relax_constraint_list_4gp (Constraint_list *CL) +{ + int thr=10; + int s,r,a,t_s,t_r,l; + static int *entry; + Sequence *S=CL->S; + char *tmp; + FILE *fp; + int th=0; + + tmp=vtmpnam(NULL); + entry=vcalloc (CL->entry_len, sizeof (int)); + + if (!CL || !CL->residue_index)return CL; + + fp=vfopen (tmp, "w"); + for (s=0; s< S->nseq; s++) + { + for ( r=1; r<=S->len[s]; r++) + { + entry[SEQ1]=s; + entry[R1]=r; + + for ( a=1; aresidue_index[s][r][0]; a+=ICHUNK) + { + + t_s=CL->residue_index[s][r][a+SEQ2]; + t_r=CL->residue_index[s][r][a+WE]; + fprintf (fp, "%d ",residue_pair_extended_list_pc (CL,s, r,t_s, t_r)); + } + } + } + vfclose (fp); + fp=vfopen (tmp, "r"); + + for (s=0; s< S->nseq; s++) + { + for ( r=1; r<=S->len[s]; r++) + { + entry[SEQ1]=s; + entry[R1]=r; + + for ( a=1; aresidue_index[s][r][0]; a+=ICHUNK) + { + fscanf (fp, "%d ", &CL->residue_index[s][r][a+WE]); + } + } + } + vfree (entry); + vfclose (fp); + return filter_constraint_list (CL,WE,th); +} + +int constraint_list2max ( Constraint_list *CL) +{ + int max=0; + Sequence *S=CL->S; + int b,l,s1,r1,s2,r2,w2; + for (s1=0; s1nseq; s1++) + { + for (r1=1; r1<=S->len[s1]; r1++) + { + for (b=1; bresidue_index[s1][r1][0]; b+=ICHUNK) + { + s2=CL->residue_index[s1][r1][b+SEQ2]; + r2=CL->residue_index[s1][r1][b+R2]; + w2=CL->residue_index[s1][r1][b+WE]; + max=MAX(w2,max); + } + } + } + return max; +} +int constraint_list2ne ( Constraint_list *CL) +{ + int max=0; + Sequence *S; + int b,l,s1,r1,s2,r2,w2; + if (!CL || !CL->residue_index || !CL->S)return 0; + + S=CL->S; + for (s1=0; s1nseq; s1++) + { + for (r1=1; r1<=S->len[s1]; r1++) + { + max+=CL->residue_index[s1][r1][0]-1; + } + } + return max/ICHUNK; +} +float constraint_list2connectivity (Constraint_list *CL) +{ + float **mat; + float tot=0; + float ntot=0; + int s1, s2,r1,b; + Sequence *S=CL->S; + + mat=declare_float (S->nseq, S->nseq); + for (s1=0; s1nseq; s1++) + for ( r1=1;r1<=S->len[s1]; r1++) + { + for (b=1; bresidue_index[s1][r1][0]; b+=ICHUNK) + { + mat[s1][CL->residue_index[s1][r1][b+SEQ2]]++; + } + } + for (s1=0; s1nseq; s1++) + for ( s2=0; s2nseq; s2++) + { + if ( s1==s2)continue; + mat[s1][s2]*=(float)2; + mat[s1][s2]/=(float)(S->len[s1]+S->len[s2]); + tot+=mat[s1][s2]; + ntot++; + } + free_float (mat, -1); + tot=(float)tot/(float)(ntot); + return tot; +} +int constraint_list2avg ( Constraint_list *CL) +{ + + int max=0, n=0; + Sequence *S=CL->S; + int b,l,s1,r1,s2,r2,w2; + for (s1=0; s1nseq; s1++) + { + for (r1=1; r1<=S->len[s1]; r1++) + { + for (b=1; bresidue_index[s1][r1][0]; b+=ICHUNK) + { + s2=CL->residue_index[s1][r1][b+SEQ2]; + r2=CL->residue_index[s1][r1][b+R2]; + w2=CL->residue_index[s1][r1][b+WE]; + max+=w2; + n++; + } + } + } + return (n==0)?0:max/n; +} + + +Constraint_list * filter_constraint_list (Constraint_list *CL,int field, int T) +{ + int s1,r1,b,c,d; + Sequence *S; + static int *buf; + static int bs; + + if (!CL || !CL->residue_index || !CL->S)return CL; + S=CL->S; + CL->ne=0; + for (s1=0; s1nseq; s1++) + { + for ( r1=1; r1<=S->len[s1]; r1++) + { + int *r=CL->residue_index[s1][r1]; + for (d=1,b=1; bT) + { + if (d!=b)for (c=0; cne++; + } + } + r[0]=d; + CL->residue_index[s1][r1]=vrealloc (r, d*sizeof(int));; + } + } + + return CL; +} + + +Constraint_list * shrink_constraint_list (Constraint_list *CL) +{ + int a, b, n, tot; + Constraint_list *CL2; + Alignment *A, *B; + int *ns, **ls; + + if (!CL || !CL->S || !CL->residue_index) return CL; + + ns=vcalloc (2, sizeof (int)); + ls=declare_int ((CL->S)->nseq, 2); + + A=seq2aln (CL->S,NULL, RM_GAP); + B=seq2aln (CL->S,NULL, RM_GAP); + CL2=declare_constraint_list (CL->S,NULL, NULL, 0,NULL, NULL); + n=(CL->S)->nseq; + tot=((n*n)-n)/2; + fprintf ( CL->local_stderr, "\n\n\tSHRINK Constraint List [%d element(s)]", CL->ne); + for (n=0,a=0; a<(CL->S)->nseq-1; a++) + for (b=a+1; b<(CL->S)->nseq; b++, n++) + { + output_completion (CL->local_stderr,n, tot, 100, "slow_pair"); + ns[0]=ns[1]=1; + ls[0][0]=a; + ls[1][0]=b; + ungap (A->seq_al[a]); + ungap (A->seq_al[b]); + linked_pair_wise (A, ns, ls, CL); + B->seq_al[0]=A->seq_al[a]; + B->seq_al[1]=A->seq_al[b]; + sprintf (B->name[0], "%s", A->name[a]); + sprintf (B->name[1], "%s", A->name[b]); + B->nseq=2; + B->len_aln=strlen (B->seq_al[0]); + CL2=aln2constraint_list (B, CL2, "sim"); + } + CL->ne=CL2->ne; + return CL; +} + + +Constraint_list *aln_file2constraint_list (char *alname, Constraint_list *CL,char *weight_mode) +{ + Alignment *A; + A=main_read_aln ( alname, NULL); + CL=aln2constraint_list (A, CL, weight_mode); + free_aln (A); + return CL; +} + +int *seqpair2weight (int s1, int s2, Alignment *A,Constraint_list *CL, char *weight_mode, int *weight) +{ + int *col; + int a,c, ref_weight; + + + if ( !weight)weight=vcalloc (MAX(2,A->len_aln), sizeof (int)); + + weight[0]=FORBIDEN; + if ( weight_mode==NULL || strcmp (weight_mode, "no")==0 || is_number (weight_mode)) + { + + if (is_number (weight_mode))ref_weight=atoi(weight_mode); + else ref_weight=1; + weight[1]=ref_weight; + + } + else if ( strstr ( weight_mode, "cons")) + { + ref_weight=weight[1]=1000; + } + else if ( strstr ( weight_mode, "OW")) + { + int ow; + sscanf ( weight_mode, "OW%d", &ow); + weight[1]=ow*get_seq_sim ( A->seq_al[s1], A->seq_al[s2], "-", NULL); + + } + else if ( strstr ( weight_mode, "len")) + { + weight[1]=A->len_aln; + } + else if ( strstr (weight_mode, "winsim")) + { + weight=get_seq_winsim ( A->seq_al[s1], A->seq_al[s2], "-", weight_mode+6, weight); + } + else if ( strstr ( weight_mode, "sim") || strstr (weight_mode, "default")) + { + char *sim_mode; + if ( strstr(weight_mode, "sim"))sim_mode=strstr(weight_mode, "sim")+3; + else sim_mode=NULL; + ref_weight=get_seq_sim ( A->seq_al[s1], A->seq_al[s2], "-", sim_mode); + if (ref_weight == 0) + ref_weight = 1; + weight[1]=ref_weight; + + } + else if ( strstr ( weight_mode, "subset")) + { + ref_weight=get_seq_sim ( A->seq_al[s1], A->seq_al[s2], "-",NULL); + weight[1]=ref_weight; + } + else if ( strstr ( weight_mode, "cdna")) + { + ref_weight=get_seq_sim ( A->seq_al[s1], A->seq_al[s2], "-", weight_mode+4); + col=vcalloc ( A->len_aln+1, sizeof (int)); + if (A->cdna_cache) + for ( a=0; a<=A->len_aln; a++)col[a]=A->cdna_cache[0][a]; + else + for ( a=0; a<=A->len_aln; a++)col[a]=1; + for ( c=0; c< A->len_aln; c++)weight[c]=ref_weight*col[c]; + vfree (col); + } + + else if ( strstr (weight_mode, "overaln")) + { + ref_weight=get_seq_sim ( A->seq_al[s1], A->seq_al[s2], "-","idmat"); + //weight=pw_aln2clean_aln_weight (A->seq_al[s1], A->seq_al[s2], ref_weight,0, 0, 0, 0, NULL); + printf_exit (EXIT_FAILURE, stderr,"ERROR: mode overaln not currently supported [FATAL:%s]", PROGRAM); + } + else + { + fprintf ( stderr, "\nERROR: Weight Mode %s is unknown [FATAL:%s]", weight_mode, PROGRAM); + crash (""); + } + return weight; +} + + +Constraint_list *aln2constraint_list (Alignment *A, Constraint_list *CL,char *in_weight_mode) +{ + int a, b, c; + int *weight=NULL; + int s1, s2; + int fixed_nres1, fixed_nres2; + int do_pdb=0; + int pdb_weight=0; + int set_misc; + char*alp=NULL; + char *p, *s; + char weight_mode [100]; + int *cache; + int top=1; + int *entry; + int **fixed; + entry=vcalloc (CL->entry_len+1, sizeof (int)); + + + //MSA are now read as one to all (+ extra bits if needed) libraries + //if ( atoigetenv ("TOP4TC")){HERE ("TOP=1");top=1;} + + sprintf ( weight_mode , "%s", (!in_weight_mode || strm (in_weight_mode, "default"))?"sim":in_weight_mode); + + if ( !A)return CL; + if (strstr (weight_mode, "extend")) + { + extend_seqaln(NULL, A); + extend_seqaln(CL->S,NULL); + if (CL->S!=A->S)extend_seqaln(A->S,NULL); + } + + fixed=fix_aln_seq_new (A, (CL->S)); + + if ( !CL) + { + Sequence *S; + S=aln2seq (A); + CL=declare_constraint_list (S,NULL, NULL, 0,NULL, NULL); + CL->S=S; + } + + cache=vcalloc (A->len_aln, sizeof (int)); + + if ( (p=strstr (weight_mode, "_subset_"))) + { + alp=strchr (weight_mode, '_')+1; + p[0]='\0'; + } + + for ( a=0; anseq-1; a++) + { + if ((s1=fixed[a][0])==-1)continue; + + for (set_misc=0,b=a+1; b< A->nseq; b++) + { + + int use_pair; + int nres1=0; + int nres2=0; + + if ((s2=fixed[b][0])==-1)continue; + + weight=seqpair2weight (a, b, A, CL, weight_mode, weight); + for (c=0; c< A->len_aln; c++) + { + int isgap1, isgap2; + isgap1=is_gap(A->seq_al[a][c]); + isgap2=is_gap(A->seq_al[b][c]); + nres1+=!isgap1; + nres2+=!isgap2; + + if (cache[c]==-1 && top)continue; + if (!isgap1)cache[c]=1; + if (cache[c] && b==A->nseq-1)cache[c]=-1; + + use_pair=1; + use_pair=use_pair && !is_gap(A->seq_al[a][c]); + use_pair=use_pair && !is_gap(A->seq_al[b][c]); + use_pair=use_pair && A->seq_al[b][c]!=UNDEFINED_RESIDUE; + use_pair=use_pair && A->seq_al[a][c]!=UNDEFINED_RESIDUE; + use_pair=use_pair && !(do_pdb && pdb_weight==0); + use_pair=use_pair && ((weight[0]==FORBIDEN)?weight[1]:weight[c]); + + if (alp)use_pair=use_pair && is_in_set (A->seq_al[b][c], alp) && is_in_set (A->seq_al[a][c], alp); + + if (use_pair) + { + + if ((fixed_nres1=fixed[a][nres1])<0)continue; + if ((fixed_nres2=fixed[b][nres2])<0)continue; + + entry[SEQ1]=s1; + entry[SEQ2]=s2; + entry[R1]=fixed_nres1; + entry[R2]=fixed_nres2; + entry[CONS]=1; + if (do_pdb)entry[WE]=(NORM_F/MAXID)*pdb_weight; + else entry[WE]=(NORM_F/MAXID)*((weight[0]==FORBIDEN)?weight[1]:weight[c]); + add_entry2list (entry, CL); + } + } + } + } + vfree (entry); + vfree (cache); + vfree (weight); + free_int (fixed, -1); + + if (strstr (weight_mode, "extend")) + { + unextend_seqaln(NULL, A); + unextend_seqaln(CL->S,NULL); + if (A->S!=CL->S)unextend_seqaln(A->S,NULL); + + + + } + if (A->A) + { + return aln2constraint_list (A->A, CL, weight_mode); + } + else + { + return CL; + } +} + + + + + + +int **list2residue_total_weight ( Constraint_list *CL) +{ + /*Returns + tot_weight[nseq][maxlen] + where each residue is associated with the total of its weights in CL + ####IMPORTANT + + -the numbering of the residues goes from 1 to L: + -the numbering of the sequences goes from 0 to N-1: + */ + + int **tot_weight; + + int max=0; + Sequence *S=CL->S; + int a,b,s1,r1,s2,r2,w2; + + + if ( !CL || !CL->S || (CL->S)->nseq==0)return NULL; + S=CL->S; + tot_weight=declare_int2 (S->nseq, S->len, 1); + for (s1=0; s1nseq; s1++) + { + for (r1=1; r1<=S->len[s1]; r1++) + { + for (b=1; bresidue_index[s1][r1][0]; b+=ICHUNK) + { + s2=CL->residue_index[s1][r1][b+SEQ2]; + r2=CL->residue_index[s1][r1][b+R2]; + w2=CL->residue_index[s1][r1][b+WE]; + tot_weight[s1][r1]+=w2; + tot_weight[s2][r2]+=w2; + } + } + } + for (a=0; a<(CL->S)->nseq; a++) + for (b=0; b<(CL->S)->len[a]; b++) + tot_weight[a][b]/=(CL->S)->nseq; + + return tot_weight; +} + + + + +/*********************************************************************/ +/* */ +/* LIST FUNCTIONS */ +/* */ +/* */ +/*********************************************************************/ + +Constraint_list *merge_constraint_list ( Constraint_list *SL, Constraint_list *ML, char *mode) +{ + + int **cache=NULL; + int s1,r1,s2,r2,a,b; + int *entry; + + entry=vcalloc (ICHUNK+10, sizeof (int)); + + for (a=0;aS!= ML->S)cache=fix_seq_seq((SL->S),(ML->S)); + + if (!ML || !SL)return ML; + for (s1=0; s1<(SL->S)->nseq; s1++) + { + if (cache && cache[s1][0]==-1)continue; + for (r1=1; r1<=((SL)->S)->len[s1]; r1++) + { + entry[SEQ1]=(cache)?cache[s1][0]:s1; + entry[R1]=(cache)?cache[s1][r1]:r1; + if (entry[R1]<=0)continue; + b=(SL->freeze)?SL->freeze[s1][r1]:1; + for (;bresidue_index[s1][r1][0]; b+=ICHUNK) + { + s2=SL->residue_index[s1][r1][b+SEQ2]; + r2=SL->residue_index[s1][r1][b+R2]; + entry[SEQ2]=(cache)?cache[s2][0]:s2; + if ( entry[SEQ2]==-1)continue; + else + { + entry[R2]=(cache)?cache[s2][r2]:r2; + if (entry[R2]<=0)continue; + else + { + entry[WE]=SL->residue_index[s1][r1][b+WE]; + entry[CONS]=SL->residue_index[s1][r1][b+CONS]; + entry[MISC]=SL->residue_index[s1][r1][b+MISC]; + } + add_entry2list2(entry, ML); + } + } + } + } + vfree (entry); + if ( cache)free_int (cache, -1); + return ML; +} + + + + +int ** seq2defined_residues ( Sequence *S, Constraint_list *CL) +{ + int **seq_count; + int s1,r1,s2,r2,l,a,b; + + seq_count=declare_int (S->nseq, S->max_len+1); + for (s1=0; s1nseq; s1++) + { + for ( r1=1; r1<=S->len[s1]; r1++) + { + for (a=1; aresidue_index[s1][r1][0]; a+=ICHUNK) + { + int s2=CL->residue_index[s1][r1][a+SEQ2]; + int r2=CL->residue_index[s1][r1][a+R2]; + seq_count[s1][r1]++; + seq_count[s2][r2]++; + } + } + } + return seq_count; +} + +int ** aln2defined_residues ( Alignment *A, Constraint_list *CL) +{ + + int **seq_count; + int **aln_count; + int **pos; + int a,ra, b; + + pos=aln2pos_simple(A, A->nseq); + seq_count=seq2defined_residues(CL->S, CL); + aln_count=declare_int (A->nseq, A->len_aln); + for (a=0; a< A->nseq; a++) + { + ra=name_is_in_list(A->name[a], (CL->S)->name, (CL->S)->nseq, 100); + if ( ra==-1) continue; + for ( b=0; blen_aln; b++) + if (pos[a][b]>0 && seq_count[ra][pos[a][b]]>0)aln_count[a][b]=1; + } + + free_int (seq_count, -1); + free_int (pos,-1); + return aln_count; +} + +/*********************************************************************/ +/* */ +/* DEBUG CONSTRAINT_LIST */ +/* */ +/* */ +/*********************************************************************/ + + +/*********************************************************************/ +/* */ +/* PRUNE CONSTRAINT_LIST */ +/* */ +/* */ +/*********************************************************************/ + + +char * list2prune_list ( Sequence *S, int **sm) +{ + int a, b, c; + int **mat, *used, *keep; + int nk=0, n=0; + int ns=4; + char *file; + FILE *fp; + + n=S->nseq; + + if (get_string_variable("prune_lib_mode")) + ns=atoi(get_string_variable("prune_lib_mode")); + + + if (ns==0)ns=n; + else if (ns<0)ns=-(n*ns)/100; + else if (ns>=n)ns=n; + + + HERE ("NS=%d", ns); + + + keep=vcalloc (n, sizeof (int)); + used=vcalloc (n, sizeof (int)); + mat=declare_int (n, n); + file=vtmpnam (NULL); + + //1-Identify the seed sequence: the one on average the further away from the rest + for (a=0; anseq; b++) + if (keep[a]!=b) + { + fprintf ( fp, "\n2 %d %d", keep[a], b); + } + } + vfclose (fp); + vfree (keep); vfree (used);free_int (mat, -1); + + return file; +} + + + + +/*********************************************************************/ +/* */ +/* WEIGHT CONSTRAINT_LIST */ +/* */ +/* */ +/*********************************************************************/ + +Constraint_list *weight_constraint_list(Constraint_list * CL, char *seq_weight) + +{ + Weights *W; + + + + if ( CL->ne==0){return CL;} + else if ( strm(seq_weight, "t_coffee")) {W=compute_t_coffee_weight(CL);} + else if (check_file_exists (seq_weight)) + { + W=read_seq_weight ((CL->S)->name, (CL->S)->nseq, seq_weight); + } + else + { + int a; + W=declare_weights((CL->S)->nseq); + sprintf ( W->mode, "no_seq_weight"); + for ( a=0; a<(CL->S)->nseq; a++) + { + sprintf ( W->seq_name[a], "%s", (CL->S)->name[a]); + W->SEQ_W[a]=1; + } + CL->W=W; + return CL; + } + CL=re_weight_constraint_list (CL,W); + + CL->W=W; + + + return CL; + + +} + + + +Weights* compute_t_coffee_weight(Constraint_list * CL) +{ + int a, b; + float p, d; + Weights *W; + int nseq; + + nseq=(CL->S)->nseq; + W=declare_weights(nseq); + sprintf ( W->mode, "t_coffee"); + for ( a=0; a< nseq; a++) + { + sprintf ( W->seq_name[a], "%s", (CL->S)->name[a]); + W->SEQ_W[a]=1; + } + + for (a=0; a< (CL->S)->nseq-1; a++) + for ( b=a+1; b< (CL->S)->nseq; b++) + { + if ( b==a){d=1;} + else if ( !(CL->S)->len[b] || !(CL->S)->len[a])d=1; + else + { + d=((float)(CL->DM)->similarity_matrix[a][b]/MAXID)*10; + } + p=pow(d,3); + + W->SEQ_W[a]+=p; + W->SEQ_W[b]+=p; + + } + + for ( p=0,b=0; b< (CL->S)->nseq; b++) + { + if ((CL->S)->len[b]==0)W->SEQ_W[b]=0; + else W->SEQ_W[b]=2/W->SEQ_W[b]; + p+=W->SEQ_W[b]; + } + for ( b=0; b< (CL->S)->nseq; b++) + { + W->SEQ_W[b]=W->SEQ_W[b]*((float)W->nseq/p); + } + + + return W; +} + +Constraint_list *set_weight4constraint_list(Constraint_list * CL,int w) +{ + int a, s, r; + Sequence *S; + + if ( !CL || !CL->S || !CL->residue_index)return CL; + S=CL->S; + for (s=0; snseq; s++) + { + for ( r=1; r<=S->len[s]; r++) + { + for (a=1; aresidue_index[s][r][0]; a+=ICHUNK) + { + CL->residue_index[s][r][a+WE]*=w; + } + } + } + CL=evaluate_constraint_list_reference (CL); + return CL; +} +Constraint_list *re_weight_constraint_list(Constraint_list * CL,Weights *W) +{ + + float w; + float *weight; + int sA, sB; + int s,r,a,b; + Sequence *S=CL->S; + + + weight=W->SEQ_W; + + for (s=0; snseq; s++) + { + for ( r=1; r<=S->len[s]; r++) + { + for (a=1; aresidue_index[s][r][0]; a+=ICHUNK) + { + int t_s=CL->residue_index[s][r][a]; + CL->residue_index[s][r][a+WE]*=MIN(weight[s], weight[t_s]); + } + } + } + CL=evaluate_constraint_list_reference (CL); + return CL; +} + +Distance_matrix* cl2distance_matrix (Constraint_list *CL, Alignment *A, char *in_mode, char *in_sim_mode, int print) +{ + + char mode[100]; + char sim_mode [100]; + + + + if ( !CL)return NULL; + sprintf ( mode, "%s", (CL && in_mode==NULL)?CL->distance_matrix_mode:in_mode); + sprintf ( sim_mode, "%s", (CL && in_sim_mode==NULL)?CL->distance_matrix_sim_mode:in_sim_mode); + + if ( !CL->DM ||!strm ((CL->DM)->mode, mode) || !strm ((CL->DM)->sim_mode, sim_mode) || A ) + { + return seq2distance_matrix (CL, A, mode, sim_mode, print); + } + else + { + + return CL->DM; + } +} + + +Distance_matrix *seq2distance_matrix (Constraint_list *CL, Alignment *A,char *mode, char *sim_mode, int print) +{ + /*Compute the distance matrix associated with the Constraint List and the sequences*/ + /*Computation only occurs if the similiraty matrix is undefined : CL->similarity_matrix*/ + /*Undefine CL->similarity_matrix to force computation*/ + + int a, b; + Alignment *B; + Constraint_list *NCL; + float score=0; + int *ns; + int **l_s; + float id; + int max_name=0; + int id_score; + static float **g_matrix; + float ref=0; + int n_coor=0; + Distance_matrix *DM; + int **sim_table=NULL; + + //mode: computation mode + //sim_mode: mode for computing the similarity + + //Composite modes + + if (strm (mode, "ktup2")) + { + B=seq2aln ( CL->S, NULL, 1); + B=very_fast_aln (B, B->nseq,NULL); + sprintf ( CL->distance_matrix_mode, "aln"); + DM=cl2distance_matrix (CL, B, NULL, NULL, 1); + sprintf ( CL->distance_matrix_mode, "ktup2"); + sprintf ( DM->mode, "%s", mode); + sprintf ( DM->sim_mode, "%s", sim_mode); + free_aln (B); + return DM; + } + + if ( !CL) return NULL; + else + { + for ( max_name=0,a=0; a< (CL->S)->nseq; a++)max_name=MAX(strlen ((CL->S)->name[a]), max_name); + + + if ( CL->DM)DM=CL->DM; + else + { + DM=vcalloc ( 1, sizeof (Distance_matrix)); + DM->nseq=(CL->S)->nseq; + DM->similarity_matrix=declare_int ( (CL->S)->nseq, (CL->S)->nseq); + DM->distance_matrix =declare_int ( (CL->S)->nseq, (CL->S)->nseq); + DM->score_similarity_matrix=declare_int ( (CL->S)->nseq, (CL->S)->nseq); + } + + sprintf ( DM->mode, "%s", mode); + sprintf ( DM->sim_mode, "%s", sim_mode); + + NCL=duplicate_constraint_list_soft (CL); + NCL->pw_parameters_set=1; + + if (!A) + { + if ( CL->tree_aln)B=CL->tree_aln; + else B=seq2aln ( NCL->S, NULL, 1); + } + else + { + B=copy_aln (A, NULL); + B=reorder_aln (B, (CL->S)->name, (CL->S)->nseq); + } + + if ( strm (mode, "very_fast")) + { + sprintf ( NCL->dp_mode, "very_fast_pair_wise"); + NCL->evaluate_residue_pair=evaluate_matrix_score; + if ( strm ((CL->S)->type, "DNA") ||strm ((CL->S)->type, "RNA") ) + { + NCL->M=read_matrice ("idmat"); + NCL->gop=-10; + NCL->gep=-1; + CL->ktup=6; + } + else + { + NCL->M=read_matrice ("blosum62mt"); + NCL->gop=get_avg_matrix_mm (NCL->M, AA_ALPHABET)*10; + NCL->gep=-1; + CL->ktup=2; + } + NCL->use_fragments=1; + CL->diagonal_threshold=6; + } + + else if ( strm (mode, "ktup")) + { + + NCL->ktup=6; + sim_table=ktup_dist_mat((CL->S)->seq,(CL->S)->nseq,NCL->ktup, (CL->S)->type); + } + + + else if (strm (mode, "aln")) + { + + sim_table=aln2sim_mat (A, sim_mode); + } + else if ( strm (mode, "fast") || strm ("idscore", mode)) + { + sprintf ( NCL->dp_mode, "myers_miller_pair_wise"); + NCL->evaluate_residue_pair=evaluate_matrix_score; + if ( strm ((CL->S)->type, "DNA") || strm ((CL->S)->type, "RNA")) + { + NCL->M=read_matrice ("idmat"); + NCL->gop=-10; + NCL->gep=-1; + } + else + { + NCL->M=read_matrice ("blosum62mt"); + NCL->gop=get_avg_matrix_mm (NCL->M, AA_ALPHABET)*10; + NCL->gep=-1; + } + } + else if ( strm (mode, "cscore")) + { + if (!CL || !CL->residue_index || CL->ne==0) + return seq2distance_matrix (CL, A,"idscore",sim_mode, print); + } + else if ( strm (mode, "geometric") ); + else if (strm (mode, "slow")); + else if (strm (mode, "clustalw")); + else if (strm (mode, "no")) + print=1; + else if (strm (mode, "random")) + print=1; + else + { + fprintf ( stderr, "\nError: %s is an unknown distance_matrix_mode [FATAL:%s]", mode,PROGRAM); + crash (""); + } + + //Special Geometric Mode + if ( strm (NCL->distance_matrix_mode, "geometric")) + { + free_arrayN(g_matrix, 2); + g_matrix=declare_float ((CL->S)->nseq, 3); + n_coor=MIN(3,((CL->S)->nseq)); + + for ( a=0; a<(CL->S)->nseq; a++) + { + for (b=0; bS)->seq[a], (CL->S)->seq[b], "pam250mt", -10, -1, "fasta_pair_wise"); + g_matrix[a][b]=get_seq_sim ( B->seq_al[0], B->seq_al[1], "-", NULL); + free_aln(B);B=NULL; + } + } + ref=(float)sqrt((double)(10000*n_coor)); + } + + + ns=vcalloc ( 2, sizeof(int)); + l_s=declare_int ( 2, 1); + ns[0]=ns[1]=1; + l_s[0][0]=0; + l_s[1][0]=1; + + if (CL->local_stderr && print>0)fprintf ( (CL->local_stderr), "\nCOMPUTE PAIRWISE SIMILARITY [dp_mode: %s] [distance_matrix_mode: %s][Similarity Measure: %s] \n", NCL->dp_mode,mode, sim_mode); + + for (a=0; a< (CL->S)->nseq; a++) + { + if (CL->local_stderr && print>0)fprintf ( (CL->local_stderr), "\n\tSeq: %s", (CL->S)->name[a]); + for ( b=a; b< (CL->S)->nseq; b++) + { + if ( b==a){DM->similarity_matrix[a][b]=MAXID;} + else + { + l_s[0][0]=a; + l_s[1][0]=b; + if ( !strm(mode, "ktup2") && ! strm (mode, "geometric")) + { + ungap ( B->seq_al[a]); + ungap ( B->seq_al[b]); + } + + if ( strm (mode, "slow")) + { + + B->score_aln=pair_wise (B, ns, l_s,NCL); + + id=get_seq_sim ( B->seq_al[a], B->seq_al[b], "-", sim_mode); + if ( CL->residue_index) + { + score=(int)(((float)B->score_aln)/(B->len_aln*SCORE_K)); + score=(int)(CL->normalise)?((score*MAXID)/(CL->normalise)):(score); + } + else if ( CL->M)score=id; + + + if ( score>MAXID)score=(CL->residue_index)?sub_aln2sub_aln_score (B, CL, CL->evaluate_mode, ns, l_s):id; + + } + else if ( strm2 (mode,"fast", "very_fast")) + { + B->score_aln=pair_wise (B, ns, l_s,NCL); + id=get_seq_sim ( B->seq_al[a], B->seq_al[b], "-", sim_mode); + score=(int)(id)*SCORE_K; + } + else if ( strm (mode, "cscore")) + { + ungap ( B->seq_al[a]); + ungap ( B->seq_al[b]); + score=(int)linked_pair_wise (B, ns, l_s, NCL); + + + score/=(B->len_aln*SCORE_K); + id=score/SCORE_K; + } + else if ( strm (mode, "idscore")) + { + score=id=idscore_pairseq (B->seq_al[a], B->seq_al[b], NCL->gop, NCL->gep, NCL->M, sim_mode); + //HERE ("%s %d %d ->%d", sim_mode, a, b, (int)id); + } + else if (strm (mode, "ktup")) + { + id=sim_table[a][b]; + score=id*SCORE_K; + + } + else if (strm (mode, "aln")) + { + score=id=sim_table[a][b]; + score*=SCORE_K; + } + + else if ( strm (mode, "geometric")) + { + id=get_geometric_distance (g_matrix,n_coor, a, b, "euclidian"); + id=MAXID*(1-((id/ref))); + score=(int)(id)*SCORE_K; + } + else if ( strm (mode, "no")) + { + id=100; + score=id*SCORE_K; + } + else if ( strm (mode, "random")) + { + id=rand()%100; + score=id*SCORE_K; + } + else + { + id=B->score_aln=pair_wise (B, ns, l_s,NCL); + score=id*SCORE_K; + } + /*Sim mat*/ + DM->similarity_matrix[a][b]=DM->similarity_matrix[b][a]=(int)(id); + /*Dist mat*/ + DM->distance_matrix[a][b]=DM->distance_matrix[b][a]=MAXID-(int)(id); + /*Score mat*/ + + + DM->score_similarity_matrix[a][b]=DM->score_similarity_matrix[b][a]=(int)score; + id_score=id; + if (CL->local_stderr && print>1) fprintf (CL->local_stderr, "\n\t%-*s %-*s identity=%3d%% score=%3d", max_name,(CL->S)->name[a], max_name,(CL->S)->name[b], id_score, (int)score); + } + } + } + vfree (ns); + free_int(l_s, -1); + + } + + + if (CL->local_stderr) fprintf (CL->local_stderr, "\n"); + free_constraint_list (NCL); + + + + if (!CL->tree_aln) + { + free_aln (B); + } + + free_int (sim_table, -1); + + + + return DM; +} +/*********************************************************************/ +/* */ +/* RNA FUNCTIONS */ +/* */ +/* */ +/*********************************************************************/ +char * seq2rna_lib ( Sequence *S, char *name) +{ + int a; + FILE *fp; + + + if (!name)name=vtmpnam (NULL); + fp=vfopen (name, "w"); + for ( a=0; anseq; a++) + { + + fprintf (fp, "%s\n", rna_struc2rna_lib(S->name[a], S->seq[a], NULL)); + } + vfclose (fp); + + return name; +} + +Constraint_list *read_rna_lib ( Sequence *S, char *fname) +{ + Constraint_list *R; + char **list; + int n=0,a; + + + if (check_file_exists (fname)) + { + + list=read_lib_list ( fname, &n); + } + else + { + X_template *F; + + list=vcalloc (S->nseq, sizeof (char*)); + for ( a=0; anseq; a++) + { + if ((F=seq_has_template (S, a, "_F_"))) + { + list[n++]=F->template_file; + } + } + } + + R=declare_constraint_list ( S,NULL, NULL, 0,NULL, NULL); + + for (a=0; a< n; a++) + { + + if (list[a])R=read_constraint_list_file (R, list[a]); + } + + + return R; +} + +Constraint_list * rna_lib_extension ( Constraint_list *CL, Constraint_list *R) +{ + CLIST_TYPE *entry=NULL; + int a,b,c,d,e,n1,n2, ne,s1,r1,s2,r2,w2; + int *list1; + int *list2; + Sequence *S=CL->S; + static char *tmp; + FILE *fp; + + list1=vcalloc ( 100, sizeof (int)); + list2=vcalloc ( 100, sizeof (int)); + + if (!tmp) tmp=vtmpnam (NULL); + fp=vfopen (tmp, "w"); + entry=vcalloc ( 100, sizeof (int)); + for (s1=0; s1nseq; s1++) + { + for (r1=1; r1<=S->len[s1]; r1++) + { + entry[SEQ1]=s1; + for (c=1; cresidue_index[s1][r1][0]; c+=ICHUNK) + { + s2=CL->residue_index[s1][r1][c+SEQ2]; + r2=CL->residue_index[s1][r1][c+R2]; + w2=CL->residue_index[s1][r1][c+WE]; + entry[SEQ2]=s2; + entry[WE]=w2; + + n1=n2=0; + list1[n1++]=r1; + for (b=1; bresidue_index[s1][r1][0]; b+=ICHUNK) + { + list1[n1++]=R->residue_index[s1][r1][b+R2]; + } + list2[n2++]=r2; + + for (b=1; bresidue_index[s2][r2][0]; b+=ICHUNK) + { + list2[n2++]=R->residue_index[s2][r2][b+R2]; + } + + for (b=1; bentry_len; e++) fprintf (fp, "%d ", entry[e]); + } + } + } + } + + vfclose (fp); + return undump_constraint_list (CL,tmp); +} + +char *** produce_method_file ( char *method) +{ + static char ***list; + int n=0; + FILE *fp; + + if (!list)list=declare_arrayN(3, sizeof (char),1000,2, 100); + + + /* + sprintf (list[n][0], "t_coffee"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE t_coffee\n"); + fprintf ( fp, "ADDRESS built_in"); + fprintf ( fp, "ALN_MODE any\n"); + fprintf ( fp, "OUT_MODE L\n"); + fprintf ( fp, "IN_FLAG no_name\n"); + fprintf ( fp, "OUT_FLAG no_name\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + + vfclose (fp);} + */ + /*Space holder method to analyze very large dATASETS*/ + sprintf (list[n][0], "test_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE test_pair\n"); + fprintf ( fp, "DOC Fast alignmnents on the best diagonals\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG no_name\n"); + fprintf ( fp, "OUT_FLAG no_name\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + vfclose (fp);} + + sprintf (list[n][0], "fast_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE fast_pair\n"); + fprintf ( fp, "DOC Fast alignmnents on the best diagonals\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG no_name\n"); + fprintf ( fp, "OUT_FLAG no_name\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + if (strm (retrieve_seq_type(), "DNA") || strm (retrieve_seq_type(), "RNA")) + { + fprintf ( fp, "MATRIX dna_idmat\n"); + fprintf ( fp, "GOP -50\n"); + fprintf ( fp, "GEP -1\n"); + } + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + vfclose (fp);} + + sprintf (list[n][0], "exon3_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE exon3_pair\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG no_name\n"); + fprintf ( fp, "OUT_FLAG no_name\n"); + fprintf ( fp, "SEQ_TYPE G\n"); + fprintf ( fp, "MATRIX exon2mt\n"); + fprintf ( fp, "GOP 0\n"); + fprintf ( fp, "GEP -1\n"); + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + vfclose (fp);} + + sprintf (list[n][0], "exon2_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE exon2_pair\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG no_name\n"); + fprintf ( fp, "OUT_FLAG no_name\n"); + fprintf ( fp, "SEQ_TYPE G\n"); + fprintf ( fp, "MATRIX exon2mt\n"); + fprintf ( fp, "GOP -10\n"); + fprintf ( fp, "GEP -1\n"); + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + vfclose (fp);} + + sprintf (list[n][0], "exon_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE exon_pair\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG no_name\n"); + fprintf ( fp, "OUT_FLAG no_name\n"); + fprintf ( fp, "SEQ_TYPE G\n"); + fprintf ( fp, "MATRIX exon2mt\n"); + fprintf ( fp, "GOP -10\n"); + fprintf ( fp, "GEP -1\n"); + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + vfclose (fp);} + + + sprintf (list[n][0], "blastr_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE slow_pair\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG no_name\n"); + fprintf ( fp, "OUT_FLAG no_name\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "EXTEND_SEQ 1\n"); + fprintf ( fp, "MATRIX blosumR\n"); + fprintf ( fp, "GOP -20\n"); + fprintf ( fp, "GEP 0\n"); + fprintf ( fp, "WEIGHT extend_sim\n"); + + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + vfclose (fp);} + + sprintf (list[n][0], "promo_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE slow_pair\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG no_name\n"); + fprintf ( fp, "OUT_FLAG no_name\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "EXTEND_SEQ 1\n"); + fprintf ( fp, "MATRIX promoter_tf1\n"); + fprintf ( fp, "GOP -40\n"); + fprintf ( fp, "GEP 0\n"); + fprintf ( fp, "WEIGHT extend_sim\n"); + + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + vfclose (fp);} + + sprintf (list[n][0], "clean_slow_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC regular dynamic Programming\n"); + fprintf ( fp, "EXECUTABLE slow_pair\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG no_name\n"); + fprintf ( fp, "OUT_FLAG no_name\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "WEIGHT clean\n"); + if ( strm ( retrieve_seq_type(), "DNA") || strm (retrieve_seq_type(), "RNA")) + { + fprintf ( fp, "MATRIX dna_idmat\n"); + fprintf ( fp, "GOP -10\n"); + fprintf ( fp, "GEP -1\n"); + } + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + vfclose (fp);} + + sprintf (list[n][0], "slow_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC regular dynamic Programming\n"); + fprintf ( fp, "EXECUTABLE slow_pair\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG no_name\n"); + fprintf ( fp, "OUT_FLAG no_name\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + if ( strm ( retrieve_seq_type(), "DNA") || strm (retrieve_seq_type(), "RNA")) + { + fprintf ( fp, "MATRIX dna_idmat\n"); + fprintf ( fp, "GOP -10\n"); + fprintf ( fp, "GEP -1\n"); + } + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + vfclose (fp);} + + sprintf (list[n][0], "biphasic_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC bi-phasic dynamic Programming\n"); + fprintf ( fp, "EXECUTABLE biphasic_pair\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG no_name\n"); + fprintf ( fp, "OUT_FLAG no_name\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + if ( strm ( retrieve_seq_type(), "DNA") || strm (retrieve_seq_type(), "RNA")) + { + fprintf ( fp, "MATRIX dna_idmat\n"); + fprintf ( fp, "GOP -10\n"); + fprintf ( fp, "GEP -1\n"); + } + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + vfclose (fp);} + + sprintf (list[n][0], "proba_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC Probabilistic pairwise alignment\n"); + fprintf ( fp, "EXECUTABLE proba_pair\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG no_name\n"); + fprintf ( fp, "OUT_FLAG no_name\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + if ( strm ( retrieve_seq_type(), "DNA") || strm (retrieve_seq_type(), "RNA")) + { + fprintf ( fp, "GOP %d\n",CODE4DNA);//code for DNA + } + else + { + fprintf ( fp, "GOP %d\n",CODE4PROTEINS);//Code for Proteins + } + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + vfclose (fp);} + + + sprintf (list[n][0], "best_pair4prot"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC Combination of the best template methods\n"); + fprintf ( fp, "EXECUTABLE best_pair4prot\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG no_name\n"); + fprintf ( fp, "OUT_FLAG no_name\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + if (strm (retrieve_seq_type(), "DNA") || strm (retrieve_seq_type(), "RNA")) + { + printf_exit (EXIT_FAILURE, stderr, "\nERROR: The mode best_pair4prot is only suited for Proteins [FATAL:%s]\n", PROGRAM); + } + vfclose (fp);} + + + sprintf (list[n][0], "best_pair4rna"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC Combination of the best template methods\n"); + fprintf ( fp, "EXECUTABLE best_pair4rna\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG no_name\n"); + fprintf ( fp, "OUT_FLAG no_name\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + // if (strm(retrieve_seq_type(), "RNA")) + // { + // printf_exit (EXIT_FAILURE, stderr, "\nERROR: The mode best_pair4rna is only suited for RNA [FATAL:%s]\n", PROGRAM); + // } + vfclose (fp);} + + + //Llaign ID PAIR + sprintf (list[n][0], "lalign_id_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC local alignment reporting the N best pairwise local alignments\n"); + fprintf ( fp, "EXECUTABLE lalign_id_pair\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG no_name\n"); + fprintf ( fp, "OUT_FLAG no_name\n"); + if ( strm (retrieve_seq_type(), "DNA") || strm (retrieve_seq_type(), "RNA")) + { + fprintf ( fp, "MATRIX dna_idmat\n"); + fprintf ( fp, "GOP -10\n"); + fprintf ( fp, "GEP -1\n"); + } + else + { + fprintf ( fp, "MATRIX blosum50mt\n"); + fprintf ( fp, "GOP -10\n"); + fprintf ( fp, "GEP -4\n"); + } + fprintf ( fp, "MAXID 100\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + vfclose (fp);} + + sprintf (list[n][0], "align_pdbpair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE align_pdb_pair\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG no_name\n"); + fprintf ( fp, "OUT_FLAG no_name\n"); + fprintf ( fp, "SEQ_TYPE P\n"); + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + vfclose (fp);} + + sprintf (list[n][0], "lalign_pdbpair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE lalign_pdb_pair\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG no_name\n"); + fprintf ( fp, "OUT_FLAG no_name\n"); + fprintf ( fp, "SEQ_TYPE P\n"); + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + vfclose (fp);} + + sprintf (list[n][0], "ktup_msa"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE ktup_msa\n"); + fprintf ( fp, "ALN_MODE multiple\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG no_name\n"); + fprintf ( fp, "OUT_FLAG no_name\n"); + fprintf ( fp, "SEQ_TYPE s\n"); + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + vfclose (fp);} + + sprintf (list[n][0], "seq_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE seq_pair\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG no_name\n"); + fprintf ( fp, "OUT_FLAG no_name\n"); + fprintf ( fp, "SEQ_TYPE s\n"); + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + vfclose (fp);} + + sprintf (list[n][0], "extern_pdbpair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE tc_P_generic_method.pl\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE A\n"); + fprintf ( fp, "IN_FLAG no_name\n"); + fprintf ( fp, "OUT_FLAG no_name\n"); + fprintf ( fp, "SEQ_TYPE P\n"); + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + vfclose (fp);} + + sprintf (list[n][0], "externprofile_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE tc_R_generic_method\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE A\n"); + fprintf ( fp, "IN_FLAG no_name\n"); + fprintf ( fp, "OUT_FLAG no_name\n"); + fprintf ( fp, "SEQ_TYPE R\n"); + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + vfclose (fp);} + + sprintf (list[n][0], "thread_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + /*This runs thread_pair@EP@EXECUTABLE2@threpg*/ + fprintf ( fp, "EXECUTABLE thread_pair\n"); + fprintf ( fp, "EXECUTABLE2 t_coffee\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG -infile=\n"); + fprintf ( fp, "IN_FLAG2 -pdbfile1=\n"); + fprintf ( fp, "OUT_FLAG -outfile=\n"); + fprintf ( fp, "SEQ_TYPE Ps\n"); + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + vfclose (fp);} + + sprintf (list[n][0], "fugue_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + /*This runs thread_pair@EP@EXECUTABLE2@threpg*/ + fprintf ( fp, "EXECUTABLE thread_pair\n"); + fprintf ( fp, "EXECUTABLE2 fugueali\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG -infile=\n"); + fprintf ( fp, "IN_FLAG2 -pdbfile1=\n"); + fprintf ( fp, "OUT_FLAG -outfile=\n"); + fprintf ( fp, "SEQ_TYPE Ps\n"); + fprintf ( fp, "ADDRESS %s\n", FUGUE_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", FUGUE_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "pdb_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE pdb_pair\n"); + fprintf ( fp, "EXECUTABLE2 t_coffee\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG -pdbfile1=\n"); + fprintf ( fp, "IN_FLAG2 -pdbfile2=\n"); + fprintf ( fp, "OUT_FLAG -outfile=\n"); + fprintf ( fp, "SEQ_TYPE P\n"); + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + vfclose (fp);} + + sprintf (list[n][0], "hh_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE profile_pair\n"); + fprintf ( fp, "EXECUTABLE2 hhalign\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG -profile1=\n"); + fprintf ( fp, "IN_FLAG2 -profile2=\n"); + fprintf ( fp, "OUT_FLAG -outfile=\n"); + fprintf ( fp, "SEQ_TYPE R\n"); + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + fprintf ( fp, "SUPPORTED NO"); + vfclose (fp);} + + sprintf (list[n][0], "profile_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE profile_pair\n"); + fprintf ( fp, "EXECUTABLE2 clustalw\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG -profile1=\n"); + fprintf ( fp, "IN_FLAG2 -profile2=\n"); + fprintf ( fp, "OUT_FLAG -outfile=\n"); + fprintf ( fp, "SEQ_TYPE R\n"); + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + fprintf ( fp, "SUPPORTED NO"); + vfclose (fp);} + + + //Switch to TM_align if SAP is not installed + //Intercept sap + if (method && strm (method, "sap_pair") && !check_program_is_installed (SAP_4_TCOFFEE,NULL,NULL,SAP_ADDRESS,INSTALL)) + { + static int issued; + if (!issued) + { + add_warning (stderr, "\n******************** WARNING: ****************************************\nSAP is not installed\nTMalign will be used instead\ntmalign is FASTER than SAP and *almost* as accurate\n**********************************************************************\n"); + issued=1; + } + + sprintf (list[n][0], "sap_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++; + + fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC: TM-Align: pairwise structural aligner [%s]\n", TMALIGN_ADDRESS); + fprintf ( fp, "EXECUTABLE pdb_pair\n"); + fprintf ( fp, "EXECUTABLE2 TMalign\n" ); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG -pdbfile1=\n"); + fprintf ( fp, "IN_FLAG2 -pdbfile2=\n"); + fprintf ( fp, "OUT_FLAG -outfile=\n"); + fprintf ( fp, "ADDRESS %s\n", TMALIGN_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", TMALIGN_4_TCOFFEE); + fprintf ( fp, "SEQ_TYPE P\n"); + vfclose (fp); + } + else + { + + sprintf (list[n][0], "sap_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++; + if (method==NULL || strm (method, list[n-1][0])) + { + fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC: sap: pairwise structural aligner [%s]\n", SAP_ADDRESS); + fprintf ( fp, "EXECUTABLE sap_pair\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG no_name\n"); + fprintf ( fp, "OUT_FLAG no_name\n"); + fprintf ( fp, "WEIGHT 100\n"); + fprintf ( fp, "SEQ_TYPE P\n"); + fprintf ( fp, "ADDRESS %s\n", SAP_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", SAP_4_TCOFFEE); + vfclose (fp); + } + } + sprintf (list[n][0], "sara_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++; + if (method==NULL || strm (method, list[n-1][0])){ + fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC: SARA: pairwise structural RNA aligner [%s]\n", ADDRESS_BUILT_IN); + fprintf ( fp, "EXECUTABLE rna_pair\n"); + fprintf ( fp, "EXECUTABLE2 runsara.py\n" ); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG -pdbfile1=\n"); + fprintf ( fp, "IN_FLAG2 -pdbfile2=\n"); + fprintf ( fp, "OUT_FLAG -outfile=\n"); + fprintf ( fp, "SEQ_TYPE P\n"); + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + vfclose (fp); + } + + sprintf (list[n][0], "daliweb_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC: Dalilite: pairwise structural aligner [%s]\n", DALILITEc_ADDRESS); + fprintf ( fp, "EXECUTABLE pdbid_pair\n"); + fprintf ( fp, "EXECUTABLE2 daliweb\n" ); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG -pdbfile1=\n"); + fprintf ( fp, "IN_FLAG2 -pdbfile2=\n"); + fprintf ( fp, "OUT_FLAG -outfile=\n"); + fprintf ( fp, "SEQ_TYPE P\n"); + fprintf ( fp, "ADDRESS %s\n", DALILITEc_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", DALILITEc_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "dali_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC: Dalilite: pairwise structural aligner [%s]\n", DALILITEc_ADDRESS); + fprintf ( fp, "EXECUTABLE pdb_pair\n"); + fprintf ( fp, "EXECUTABLE2 DaliLite\n" ); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG -pdbfile1=\n"); + fprintf ( fp, "IN_FLAG2 -pdbfile2=\n"); + fprintf ( fp, "OUT_FLAG -outfile=\n"); + fprintf ( fp, "SEQ_TYPE P\n"); + fprintf ( fp, "ADDRESS %s\n", DALILITEc_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", DALILITEc_4_TCOFFEE); + vfclose (fp);} + + + sprintf (list[n][0], "mustang_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC: Mustang: pairwise structural aligner [%s]\n", MUSTANG_ADDRESS); + fprintf ( fp, "EXECUTABLE pdb_pair\n"); + fprintf ( fp, "EXECUTABLE2 mustang\n" ); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG -pdbfile1=\n"); + fprintf ( fp, "IN_FLAG2 -pdbfile2=\n"); + fprintf ( fp, "OUT_FLAG -outfile=\n"); + fprintf ( fp, "SEQ_TYPE P\n"); + fprintf ( fp, "ADDRESS %s\n", MUSTANG_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", MUSTANG_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "TMalign_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC: TM-Align: pairwise structural aligner [%s]\n", TMALIGN_ADDRESS); + fprintf ( fp, "EXECUTABLE pdb_pair\n"); + fprintf ( fp, "EXECUTABLE2 TMalign\n" ); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG -pdbfile1=\n"); + fprintf ( fp, "IN_FLAG2 -pdbfile2=\n"); + fprintf ( fp, "OUT_FLAG -outfile=\n"); + fprintf ( fp, "ADDRESS %s\n", TMALIGN_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", TMALIGN_4_TCOFFEE); + fprintf ( fp, "SEQ_TYPE P\n"); + vfclose (fp);} + + sprintf (list[n][0], "cdna_fast_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE cdna_fast_pair\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG no_name\n"); + fprintf ( fp, "OUT_FLAG no_name\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + vfclose (fp);} + + sprintf (list[n][0], "cdna_cfast_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE cdna_cfast_pair\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG no_name\n"); + fprintf ( fp, "OUT_FLAG no_name\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + vfclose (fp);} + + sprintf (list[n][0], "blastp_msa"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC: BLAST multiple Aligner [%s]\n", NCBIBLAST_ADDRESS); + fprintf ( fp, "EXECUTABLE seq_msa\n"); + fprintf ( fp, "EXECUTABLE2 blastp\n" ); + fprintf ( fp, "ALN_MODE multiple\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG -infile=\n"); + fprintf ( fp, "OUT_FLAG -outfile=\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", NCBIBLAST_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", NCBIBLAST_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "blastp_o2a"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC: BLAST multiple Aligner [%s]\n", NCBIBLAST_ADDRESS); + fprintf ( fp, "EXECUTABLE seq_msa\n"); + fprintf ( fp, "EXECUTABLE2 blastp\n" ); + fprintf ( fp, "ALN_MODE o2a\n"); + fprintf ( fp, "OUT_MODE fL\n"); + fprintf ( fp, "IN_FLAG -infile=\n"); + fprintf ( fp, "OUT_FLAG -outfile=\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", NCBIBLAST_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", NCBIBLAST_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "clustalw2_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC: clustalw [%s]\n", CLUSTALW2_ADDRESS); + fprintf ( fp, "EXECUTABLE clustalw\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "IN_FLAG %sINFILE=\n",CWF); + fprintf ( fp, "OUT_FLAG %sOUTFILE=\n",CWF); + fprintf ( fp, "PARAM %sOUTORDER=INPUT %sNEWTREE=SCRATCH_FILE %salign\n",CWF,CWF,CWF); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", CLUSTALW2_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", CLUSTALW2_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "clustalw2_msa"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC clustalw[%s]\n", CLUSTALW2_ADDRESS); + fprintf ( fp, "EXECUTABLE clustalw2\n"); + fprintf ( fp, "ALN_MODE multiple\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "IN_FLAG %sINFILE=\n",CWF); + fprintf ( fp, "OUT_FLAG %sOUTFILE=\n", CWF); + fprintf ( fp, "PARAM %sOUTORDER=INPUT %sNEWTREE=SCRATCH_FILE %salign\n",CWF,CWF,CWF); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", CLUSTALW2_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", CLUSTALW2_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "clustalw_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC: clustalw [%s]\n", CLUSTALW_ADDRESS); + fprintf ( fp, "EXECUTABLE clustalw\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "IN_FLAG %sINFILE=\n", CWF); + fprintf ( fp, "OUT_FLAG %sOUTFILE=\n",CWF); + fprintf ( fp, "PARAM %sOUTORDER=INPUT %sNEWTREE=SCRATCH_FILE %salign\n",CWF,CWF,CWF); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", CLUSTALW_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", CLUSTALW_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "clustalw_msa"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC clustalw[%s]\n", CLUSTALW_ADDRESS); + fprintf ( fp, "EXECUTABLE clustalw\n"); + fprintf ( fp, "ALN_MODE multiple\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "IN_FLAG %sINFILE=\n", CWF); + fprintf ( fp, "OUT_FLAG %sOUTFILE=\n", CWF); + fprintf ( fp, "PARAM %sOUTORDER=INPUT %sNEWTREE=SCRATCH_FILE %salign\n",CWF,CWF,CWF); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", CLUSTALW_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", CLUSTALW_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "mafftdef_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE mafft\n"); + fprintf ( fp, "DOC Mafft [%s]\n", MAFFT_ADDRESS); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "PARAM1 \n"); + fprintf ( fp, "IN_FLAG &bnsp\n"); + fprintf ( fp, "OUT_FLAG >\n"); + fprintf ( fp, "PARAM &bnsp2>/dev/null\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", MAFFT_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", MAFFT_4_TCOFFEE); + vfclose (fp);} + + + sprintf (list[n][0], "mafftdef_msa"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE mafft\n"); + fprintf ( fp, "DOC Mafft [%s]\n", MAFFT_ADDRESS); + fprintf ( fp, "ALN_MODE multiple\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, " \n"); + fprintf ( fp, "IN_FLAG &bnsp\n"); + fprintf ( fp, "OUT_FLAG >\n"); + fprintf ( fp, "PARAM &bnsp2>/dev/null\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", MAFFT_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", MAFFT_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "mafft_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE mafft\n"); + fprintf ( fp, "DOC Mafft [%s]\n", MAFFT_ADDRESS); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "PARAM1 --localpair --maxiterate 1000 \n"); + fprintf ( fp, "IN_FLAG &bnsp\n"); + fprintf ( fp, "OUT_FLAG >\n"); + fprintf ( fp, "PARAM &bnsp2>/dev/null\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", MAFFT_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", MAFFT_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "mafft_msa"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE mafft\n"); + fprintf ( fp, "DOC Mafft [%s]\n", MAFFT_ADDRESS); + fprintf ( fp, "ALN_MODE multiple\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "PARAM1 --localpair --maxiterate 1000 \n"); + fprintf ( fp, "IN_FLAG &bnsp\n"); + fprintf ( fp, "OUT_FLAG >\n"); + fprintf ( fp, "PARAM &bnsp2>/dev/null\n"); + fprintf ( fp, "PARAM \n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", MAFFT_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", MAFFT_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "mafftjtt_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC Mafft [%s]\n", MAFFT_ADDRESS); + fprintf ( fp, "EXECUTABLE mafft \n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "IN_FLAG &bnsp\n"); + fprintf ( fp, "OUT_FLAG >\n"); + fprintf ( fp, "PARAM1 --jtt 250 --localpair --maxiterate 1000 \n"); + fprintf ( fp, "PARAM &bnsp2>/dev/null\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", MAFFT_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", MAFFT_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "mafftjtt_msa"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC Mafft [%s]\n", MAFFT_ADDRESS); + fprintf ( fp, "EXECUTABLE mafft \n"); + + fprintf ( fp, "ALN_MODE multiple\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "IN_FLAG &bnsp\n"); + fprintf ( fp, "OUT_FLAG >\n"); + fprintf ( fp, "PARAM1 --jtt 250 --localpair --maxiterate 1000 \n"); + fprintf ( fp, "PARAM &bnsp2>/dev/null\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", MAFFT_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", MAFFT_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "mafftgins_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE mafft\n"); + fprintf ( fp, "DOC Mafft [%s]\n", MAFFT_ADDRESS); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "PARAM1 --globalpair --maxiterate 1000 \n"); + fprintf ( fp, "IN_FLAG &bnsp\n"); + fprintf ( fp, "OUT_FLAG >\n"); + fprintf ( fp, "PARAM &bnsp2>/dev/null\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", MAFFT_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", MAFFT_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "mafftgins_msa"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE mafft\n"); + fprintf ( fp, "DOC Mafft [%s]\n", MAFFT_ADDRESS); + fprintf ( fp, "ALN_MODE multiple\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "PARAM1 --globalpair --maxiterate 1000 \n"); + fprintf ( fp, "IN_FLAG &bnsp\n"); + fprintf ( fp, "OUT_FLAG >\n"); + fprintf ( fp, "PARAM &bnsp2>/dev/null\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", MAFFT_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", MAFFT_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "dialigntx_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC dialign-tx [%s]\n", DIALIGNTX_ADDRESS); + fprintf ( fp, "EXECUTABLE dialign-tx\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE aln\n"); + if ( isdir (DIALIGNTX_DIR)) + fprintf ( fp, "PARAM1 %s \n", DIALIGNTX_DIR); + else + fprintf ( fp, "PARAM1 %s \n", get_mcoffee_4_tcoffee()); + fprintf ( fp, "IN_FLAG &bnsp\n"); + fprintf ( fp, "OUT_FLAG &bnsp\n"); + fprintf ( fp, "PARAM >/dev/null&bnsp2>/dev/null\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", DIALIGNTX_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", DIALIGNTX_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "dialigntx_msa"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC dialign-tx [%s]\n", DIALIGNTX_ADDRESS); + fprintf ( fp, "EXECUTABLE dialign-tx\n"); + fprintf ( fp, "ALN_MODE multiple\n"); + fprintf ( fp, "OUT_MODE aln\n"); + if ( isdir (DIALIGNTX_DIR)) + fprintf ( fp, "PARAM1 %s \n", DIALIGNTX_DIR); + else + fprintf ( fp, "PARAM1 %s \n", get_mcoffee_4_tcoffee()); + fprintf ( fp, "IN_FLAG &bnsp\n"); + fprintf ( fp, "OUT_FLAG &bnsp\n"); + fprintf ( fp, "PARAM >/dev/null&bnsp2>/dev/null\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", DIALIGNTX_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", DIALIGNTX_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "dialignt_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC dialign-tx [%s]\n", DIALIGNT_ADDRESS); + fprintf ( fp, "EXECUTABLE dialign-tx\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE aln\n"); + if ( isdir (DIALIGNT_DIR)) + fprintf ( fp, "PARAM1 %s \n", DIALIGNT_DIR); + else + fprintf ( fp, "PARAM1 %s \n", get_mcoffee_4_tcoffee()); + fprintf ( fp, "IN_FLAG &bnsp\n"); + fprintf ( fp, "OUT_FLAG &bnsp\n"); + fprintf ( fp, "PARAM >/dev/null&bnsp2>/dev/null\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", DIALIGNT_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", DIALIGNT_4_TCOFFEE); + + vfclose (fp);} + + sprintf (list[n][0], "dialignt_msa"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC dialign-tx [%s]\n", DIALIGNT_ADDRESS); + fprintf ( fp, "EXECUTABLE dialign-tx\n"); + fprintf ( fp, "ALN_MODE multiple\n"); + fprintf ( fp, "OUT_MODE aln\n"); + if ( isdir (DIALIGNT_DIR)) + fprintf ( fp, "PARAM1 %s \n", DIALIGNT_DIR); + else + fprintf ( fp, "PARAM1 %s \n", get_mcoffee_4_tcoffee()); + fprintf ( fp, "IN_FLAG &bnsp\n"); + fprintf ( fp, "OUT_FLAG &bnsp\n"); + fprintf ( fp, "PARAM >/dev/null&bnsp2>/dev/null\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", DIALIGNT_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", DIALIGNT_4_TCOFFEE); + + vfclose (fp);} + + sprintf (list[n][0], "poa_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC Partial Order Graph Alignment [%s]\n", POA_ADDRESS); + fprintf ( fp, "EXECUTABLE poa\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "PARAM1 -toupper \n"); + fprintf ( fp, "IN_FLAG -read_fasta&bnsp\n"); + fprintf ( fp, "OUT_FLAG -clustal&bnsp\n"); + if (file_exists (POA_DIR, POA_FILE1)) + fprintf ( fp, "PARAM %s/%s&bnsp2>/dev/null\n",POA_DIR,POA_FILE1); + else + fprintf ( fp, "PARAM %s/%s&bnsp2>/dev/null\n", get_mcoffee_4_tcoffee(), POA_FILE1); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", POA_ADDRESS); + fprintf ( fp, "PROGRAM %s\n",POA_4_TCOFFEE); + + vfclose (fp);} + + sprintf (list[n][0], "poa_msa"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC Partial Order Graph Alignment [%s]\n", POA_ADDRESS); + fprintf ( fp, "EXECUTABLE poa\n"); + fprintf ( fp, "ALN_MODE multiple\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "PARAM1 -toupper \n"); + fprintf ( fp, "IN_FLAG -read_fasta&bnsp\n"); + fprintf ( fp, "OUT_FLAG -clustal&bnsp\n"); + if (file_exists (POA_DIR, POA_FILE1)) + fprintf ( fp, "PARAM %s/%s&bnsp2>/dev/null\n",POA_DIR,POA_FILE1); + else + fprintf ( fp, "PARAM %s/%s&bnsp2>/dev/null\n", get_mcoffee_4_tcoffee(), POA_FILE1); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", POA_ADDRESS); + fprintf ( fp, "PROGRAM %s\n",POA_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "probcons_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC probcons [%s]\n", PROBCONS_ADDRESS); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "IN_FLAG &bnsp\n"); + fprintf ( fp, "OUT_FLAG >\n"); + fprintf ( fp, "PARAM &bnsp2>/dev/null\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + if ( strm (retrieve_seq_type(), "DNA") || strm (retrieve_seq_type(), "RNA"))fprintf ( fp, "EXECUTABLE probconsRNA\n"); + else fprintf ( fp, "EXECUTABLE probcons\n"); + fprintf ( fp, "ADDRESS %s\n", PROBCONS_ADDRESS); + fprintf ( fp, "PROGRAM %s\n",PROBCONS_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "probcons_msa"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC probcons [%s]\n", PROBCONS_ADDRESS); + fprintf ( fp, "ALN_MODE multiple\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "IN_FLAG &bnsp\n"); + fprintf ( fp, "OUT_FLAG >\n"); + fprintf ( fp, "PARAM &bnsp2>/dev/null\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + if ( strm (retrieve_seq_type(), "DNA") || strm (retrieve_seq_type(), "RNA"))fprintf ( fp, "EXECUTABLE probconsRNA\n"); + else fprintf ( fp, "EXECUTABLE probcons\n"); + fprintf ( fp, "ADDRESS %s\n", PROBCONS_ADDRESS); + fprintf ( fp, "PROGRAM %s\n",PROBCONS_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "probconsRNA_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC probcons [%s]\n", PROBCONSRNA_ADDRESS); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "IN_FLAG &bnsp\n"); + fprintf ( fp, "OUT_FLAG >\n"); + fprintf ( fp, "PARAM &bnsp2>/dev/null\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "EXECUTABLE probconsRNA\n"); + fprintf ( fp, "ADDRESS %s\n", PROBCONSRNA_ADDRESS); + fprintf ( fp, "PROGRAM %s\n",PROBCONSRNA_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "probconsRNA_msa"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC probcons [%s]\n", PROBCONSRNA_ADDRESS); + fprintf ( fp, "ALN_MODE multiple\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "IN_FLAG &bnsp\n"); + fprintf ( fp, "OUT_FLAG >\n"); + fprintf ( fp, "PARAM &bnsp2>/dev/null\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "EXECUTABLE probconsRNA\n"); + fprintf ( fp, "ADDRESS %s\n", PROBCONSRNA_ADDRESS); + fprintf ( fp, "PROGRAM %s\n",PROBCONSRNA_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "muscle_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC Muscle [%s]\n", MUSCLE_ADDRESS); + fprintf ( fp, "EXECUTABLE muscle\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "IN_FLAG -in&bnsp\n"); + fprintf ( fp, "OUT_FLAG -out&bnsp\n"); + fprintf ( fp, "PARAM -quiet&bnsp-maxmb&bnsp0&bnsp>/dev/null\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", MUSCLE_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", MUSCLE_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "muscle_msa"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC Muscle [%s]\n", MUSCLE_ADDRESS); + fprintf ( fp, "EXECUTABLE muscle\n"); + fprintf ( fp, "ALN_MODE multiple\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "IN_FLAG -in&bnsp\n"); + fprintf ( fp, "OUT_FLAG -out&bnsp\n"); + fprintf ( fp, "PARAM -quiet&bnsp-maxmb&bnsp0&bnsp>/dev/null\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", MUSCLE_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", MUSCLE_4_TCOFFEE); + vfclose (fp);} + + + + sprintf (list[n][0], "mus4_msa"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC Muscle [%s]\n", MUS4_ADDRESS); + fprintf ( fp, "EXECUTABLE mus4\n"); + fprintf ( fp, "ALN_MODE multiple\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "IN_FLAG --input&bnsp\n"); + fprintf ( fp, "OUT_FLAG --output&bnsp\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", MUS4_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", MUS4_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "mus4_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC Mus4 [%s]\n", MUS4_ADDRESS); + fprintf ( fp, "EXECUTABLE mus4\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "IN_FLAG --input&bnsp\n"); + fprintf ( fp, "OUT_FLAG --output&bnsp\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", MUS4_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", MUS4_4_TCOFFEE); + vfclose (fp);} + + + + sprintf (list[n][0], "t_coffee_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE t_coffee\n"); + fprintf ( fp, "DOC T-Coffee [%s]\n", TCOFFEE_ADDRESS); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "IN_FLAG -infile&bnsp\n"); + fprintf ( fp, "OUT_FLAG -outfile&bnsp\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", TCOFFEE_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", TCOFFEE_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "t_coffee_msa"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE t_coffee\n"); + fprintf ( fp, "DOC T-Coffee [%s]\n", TCOFFEE_ADDRESS); + fprintf ( fp, "ALN_MODE multiple\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "IN_FLAG -infile&bnsp\n"); + fprintf ( fp, "OUT_FLAG -outfile&bnsp\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", TCOFFEE_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", TCOFFEE_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "pcma_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC PCMA [%s]\n", PCMA_ADDRESS); + fprintf ( fp, "EXECUTABLE pcma\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "IN_FLAG -infile=\n"); + fprintf ( fp, "OUT_FLAG -outfile=\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", PCMA_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", PCMA_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "pcma_msa"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC PCMA [%s]\n", PCMA_ADDRESS); + fprintf ( fp, "EXECUTABLE pcma\n"); + fprintf ( fp, "ALN_MODE multiple\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "IN_FLAG -infile=\n"); + fprintf ( fp, "OUT_FLAG -outfile=\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", PCMA_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", PCMA_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "kalign_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE kalign\n"); + fprintf ( fp, "DOC kalign [%s]\n", KALIGN_ADDRESS); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "IN_FLAG -i&bnsp\n"); + fprintf ( fp, "OUT_FLAG -o&bnsp\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", KALIGN_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", KALIGN_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "kalign_msa"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE kalign\n"); + fprintf ( fp, "DOC kalign [%s]\n", KALIGN_ADDRESS); + fprintf ( fp, "ALN_MODE multiple\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "IN_FLAG -i&bnsp\n"); + fprintf ( fp, "OUT_FLAG -o&bnsp\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", KALIGN_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", KALIGN_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "amap_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE amap\n"); + fprintf ( fp, "DOC amap [%s]\n", AMAP_ADDRESS); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "IN_FLAG &bnsp\n"); + fprintf ( fp, "OUT_FLAG >\n"); + fprintf ( fp, "PARAM &bnsp2>/dev/null\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", AMAP_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", AMAP_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "amap_msa"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE amap\n"); + fprintf ( fp, "DOC amap [%s]\n", AMAP_ADDRESS); + fprintf ( fp, "ALN_MODE multiple\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "IN_FLAG &bnsp\n"); + fprintf ( fp, "OUT_FLAG >\n"); + fprintf ( fp, "PARAM &bnsp2>/dev/null\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", AMAP_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", AMAP_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "proda_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC proda [%s]\n", PRODA_ADDRESS); + fprintf ( fp, "EXECUTABLE proda\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "IN_FLAG &bnsp\n"); + fprintf ( fp, "OUT_FLAG >\n"); + fprintf ( fp, "PARAM &bnsp2>/dev/null\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", PRODA_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", PRODA_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "proda_msa"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC proda [%s]\n", PRODA_ADDRESS); + fprintf ( fp, "EXECUTABLE proda\n"); + fprintf ( fp, "ALN_MODE multiple\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "IN_FLAG &bnsp\n"); + fprintf ( fp, "OUT_FLAG >\n"); + fprintf ( fp, "PARAM &bnsp2>/dev/null\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", PRODA_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", PRODA_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "prank_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC prank [%s]\n", PRANK_ADDRESS); + fprintf ( fp, "EXECUTABLE tc_generic_method.pl\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "PARAM -method=%s -mode=seq_msa -tmpdir=%s\n",(getenv("PRANK_4_TCOFFEE"))?getenv("PRANK_4_TCOFFEE"):PRANK_4_TCOFFEE, get_tmp_4_tcoffee()); + fprintf ( fp, "IN_FLAG -infile=\n"); + fprintf ( fp, "OUT_FLAG -outfile=\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", PRANK_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", PRANK_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "prank_msa"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC prank [%s]\n", PRANK_ADDRESS); + fprintf ( fp, "EXECUTABLE tc_generic_method.pl\n"); + fprintf ( fp, "ALN_MODE multiple\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "PARAM -method=%s -mode=seq_msa -tmpdir=%s\n",(getenv("PRANK_4_TCOFFEE"))?getenv("PRANK_4_TCOFFEE"):PRANK_4_TCOFFEE, get_tmp_4_tcoffee()); + fprintf ( fp, "IN_FLAG -infile=\n"); + fprintf ( fp, "OUT_FLAG -outfile=\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", PRANK_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", PRANK_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "fsa_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC fsa [%s]\n", FSA_ADDRESS); + fprintf ( fp, "EXECUTABLE fsa\n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "IN_FLAG &bnsp\n"); + fprintf ( fp, "OUT_FLAG >\n"); + fprintf ( fp, "PARAM &bnsp2>/dev/null\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", FSA_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", FSA_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "fsa_msa"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC fsa [%s]\n", FSA_ADDRESS); + fprintf ( fp, "EXECUTABLE fsa\n"); + fprintf ( fp, "ALN_MODE multiple\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "IN_FLAG &bnsp\n"); + fprintf ( fp, "OUT_FLAG >\n"); + fprintf ( fp, "PARAM &bnsp2>/dev/null\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", FSA_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", FSA_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "tblastx_msa"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC tblastx [%s]\n", NCBIBLAST_ADDRESS); + fprintf ( fp, "EXECUTABLE tc_generic_method.pl\n"); + fprintf ( fp, "ALN_MODE multiple\n"); + fprintf ( fp, "PARAM -mode=tblastx_msa\n"); + fprintf ( fp, "OUT_MODE L\n"); + fprintf ( fp, "IN_FLAG -infile=\n"); + fprintf ( fp, "OUT_FLAG -outfile=\n"); + fprintf ( fp, "PARAM &bnsp2>/dev/null\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", NCBIBLAST_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", NCBIBLAST_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "tblastpx_msa"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC tblastpx [%s]\n", NCBIBLAST_ADDRESS); + fprintf ( fp, "EXECUTABLE tc_generic_method.pl\n"); + fprintf ( fp, "ALN_MODE multiple\n"); + fprintf ( fp, "PARAM -mode=tblastpx_msa\n"); + fprintf ( fp, "OUT_MODE L\n"); + fprintf ( fp, "IN_FLAG -infile=\n"); + fprintf ( fp, "OUT_FLAG -outfile=\n"); + fprintf ( fp, "PARAM &bnsp2>/dev/null\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", NCBIBLAST_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", NCBIBLAST_4_TCOFFEE); + vfclose (fp);} + + + + + sprintf (list[n][0], "em"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++; + if (method==NULL || lstrstr (method,"em@")) + { + + fp=vfopen (list[n-1][1], "w"); + if (method) + { + char **l2; + l2=string2list2 ( method, "@"); + fprintf ( fp, "PARAM -method=%s -mode=seq_msa -tmpdir=%s\n",l2[2], get_tmp_4_tcoffee()); + fprintf ( fp, "ALN_MODE %s\n", l2[3]); + free_char (l2, -1); + } + fprintf ( fp, "EXECUTABLE tc_generic_method.pl\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "IN_FLAG -infile=\n"); + fprintf ( fp, "OUT_FLAG -outfile=\n"); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", ADDRESS_BUILT_IN); + fprintf ( fp, "PROGRAM %s\n", PROGRAM_BUILT_IN); + vfclose (fp); + } + + sprintf (list[n][0], "consan_pair"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "DOC consan (sfold) RNA pairwise sequence aligner [%s]\n", CONSAN_ADDRESS); + fprintf ( fp, "EXECUTABLE fasta_seq2consan_aln.pl \n"); + fprintf ( fp, "ALN_MODE pairwise\n"); + fprintf ( fp, "OUT_MODE aln\n"); + fprintf ( fp, "IN_FLAG -i&bnsp\n"); + fprintf ( fp, "OUT_FLAG -o&bnsp\n"); + fprintf ( fp, "PARAM -d&bnsp%s&bnsp2>/dev/null\n",get_mcoffee_4_tcoffee()); + fprintf ( fp, "SEQ_TYPE S\n"); + fprintf ( fp, "ADDRESS %s\n", CONSAN_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", CONSAN_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "RNAplfold"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE RNAplfold \n"); + fprintf ( fp, "ALN_MODE predict\n"); + fprintf ( fp, "SEQ_TYPE RNA\n"); + fprintf ( fp, "ADDRESS %s\n", RNAPLFOLD_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", RNAPLFOLD_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "HMMtop"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE HMMtop \n"); + fprintf ( fp, "ALN_MODE predict\n"); + fprintf ( fp, "SEQ_TYPE PROTEIN\n"); + fprintf ( fp, "ADDRESS %s\n", HMMTOP_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", HMMTOP_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "GOR4"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE GORIV \n"); + fprintf ( fp, "ALN_MODE predict\n"); + fprintf ( fp, "SEQ_TYPE PROTEIN\n"); + fprintf ( fp, "ADDRESS %s\n", GOR4_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", GOR4_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "wublast_client"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE wublast.pl \n"); + fprintf ( fp, "ALN_MODE predict\n"); + fprintf ( fp, "SEQ_TYPE PROTEIN\n"); + fprintf ( fp, "ADDRESS %s\n", EBIWUBLASTc_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", EBIWUBLASTc_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "blastpgp_client"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE blastpgp.pl \n"); + fprintf ( fp, "ALN_MODE predict\n"); + fprintf ( fp, "SEQ_TYPE PROTEIN\n"); + + fprintf ( fp, "ADDRESS %s\n", EBIBLASTPGPc_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", EBIBLASTPGPc_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "ncbi_netblast"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE blastcl3 \n"); + fprintf ( fp, "ALN_MODE predict\n"); + fprintf ( fp, "SEQ_TYPE PROTEIN\n"); + + fprintf ( fp, "ADDRESS %s\n", NCBIWEBBLAST_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", NCBIWEBBLAST_4_TCOFFEE); + vfclose (fp);} + + sprintf (list[n][0], "local_ncbiblast"); + sprintf (list[n][1], "%s", vtmpnam(NULL)); + n++;if (method==NULL || strm (method, list[n-1][0])){fp=vfopen (list[n-1][1], "w"); + fprintf ( fp, "EXECUTABLE blastall \n"); + fprintf ( fp, "ALN_MODE predict\n"); + fprintf ( fp, "SEQ_TYPE PROTEIN\n"); + + fprintf ( fp, "ADDRESS %s\n", NCBIBLAST_ADDRESS); + fprintf ( fp, "PROGRAM %s\n", NCBIBLAST_4_TCOFFEE); + vfclose (fp);} + + list[n]=NULL; + return list; +} + + +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/util_declare.c b/binaries/src/tcoffee/t_coffee_source/util_declare.c new file mode 100644 index 0000000..71b5edd --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/util_declare.c @@ -0,0 +1,1942 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" +#include "dp_lib_header.h" + +void free_pair_wise() +{ + //Free static allocated memory + free_proba_pair_wise(); +} + +/************************************************************************/ +/* */ +/* CONSTRAINT_LIST */ +/* */ +/* */ +/************************************************************************/ +int *** duplicate_residue_index (int ***r) +{ + int a,b,c; + int d1,d2,d3; + + int ***nr; + + d1=read_array_size_new(r); + nr=vcalloc ( d1, sizeof (int**)); + for (a=0; anseq, sizeof (int**)); + for ( a=0; anseq; a++) + { + r[a]=vcalloc (S->len[a]+2, sizeof (int*));//The empty terminator makes a scan possible without knowing len + for ( b=0; b<=S->len[a]; b++) + { + r[a][b]=vcalloc ( 1, sizeof (int)); + r[a][b][0]=1; + } + } + return r; +} + +Constraint_list * declare_constraint_list_simple ( Sequence *S) +{ + return declare_constraint_list (S, NULL, NULL, 0, NULL, NULL); +} + +Constraint_list * declare_constraint_list ( Sequence *S, char *name, int *L, int ne,FILE *fp, int **M) + { + Constraint_list *CL; + + CL=vcalloc (1, sizeof ( Constraint_list)); + + + CL->S=S; + CL->M=M; + + if ( name!=NULL) + { + sprintf ( CL->list_name, "%s", name); + + } + CL->cpu=1; + CL->fp=fp; + if (L) + { + HERE ("The USE of L is now Deprecated with Constraint Lists"); + exit (0); + } + CL->ne=ne; + CL->entry_len=LIST_N_FIELDS; + CL->el_size=sizeof (CLIST_TYPE); + CL->matrices_list=declare_char(20,20); + + + CL->weight_field=WE; + if ( S)CL->seq_for_quadruplet=vcalloc ( S->nseq, sizeof (int)); + CL->Prot_Blast=vcalloc ( 1, sizeof ( Blast_param)); + CL->DNA_Blast=vcalloc ( 1, sizeof ( Blast_param)); + CL->Pdb_Blast=vcalloc ( 1, sizeof ( Blast_param)); + CL->TC=vcalloc (1, sizeof (TC_param)); + + //New data structure + CL->residue_index=declare_residue_index (S); + + + + return CL; + } + +Constraint_list *free_constraint_list4lib_computation (Constraint_list *CL) +{ + if (!CL)return NULL; + + free_arrayN(CL->residue_index, 3); + free_int (CL->M, -1); + + vfree (CL); + return CL; +} +Constraint_list *duplicate_constraint_list4lib_computation (Constraint_list *CL) +{ + Constraint_list *SCL; + SCL=vcalloc (1, sizeof ( Constraint_list)); + SCL[0]=CL[0]; + SCL->S=CL->S; + SCL->RunName=CL->RunName; + + SCL->max_L_len=0; + SCL->M=NULL; + SCL->ne=0; + + return SCL; +} +Constraint_list *duplicate_constraint_list_soft (Constraint_list *CL) +{ + /*Duplication that does not copy the long lists*/ + return copy_constraint_list (CL,SOFT_COPY); +} +Constraint_list *duplicate_constraint_list (Constraint_list *CL) + { + /*Duplicate everything in the constraint_list*/ + return copy_constraint_list (CL,HARD_COPY); + } +Constraint_list *copy_constraint_list (Constraint_list *CL, int mode) + { + Constraint_list *NCL; + Sequence *S; + int a, b; + + + + /*Sequences*/ + + + S=(mode==HARD_COPY)?duplicate_sequence (CL->S):CL->S; + + + if (mode==HARD_COPY) + NCL=declare_constraint_list (S, NULL, NULL,0, NULL, NULL); + else + { + NCL=vcalloc ( 1, sizeof (Constraint_list)); + NCL[0]=CL[0]; + } + + + NCL->copy_mode=mode; + if (mode==SOFT_COPY)NCL->pCL=CL; + NCL->S=S; + /*master*/ + if (mode==HARD_COPY && CL->master) + {NCL->master=vcalloc ( S->nseq, sizeof(int)); + for ( a=0; a< S->nseq; a++) + NCL->master[a]=CL->master[a]; + } + else if (mode==SOFT_COPY) + { + NCL->seq_for_quadruplet=CL->seq_for_quadruplet; + } + NCL->o2a_byte=CL->o2a_byte; + + /*struc List*/ + NCL->STRUC_LIST=(mode==HARD_COPY)?duplicate_sequence (CL->STRUC_LIST):CL->STRUC_LIST; + sprintf ( NCL->align_pdb_param_file, "%s", CL->align_pdb_param_file); + sprintf ( NCL->align_pdb_hasch_mode, "%s", CL->align_pdb_hasch_mode); + + + NCL->W=(mode==HARD_COPY)?duplicate_weights (CL->W):CL->W; + NCL->DM=(mode==HARD_COPY)?duplicate_distance_matrix (CL->DM):CL->DM; + NCL->ktupDM=(mode==HARD_COPY)?duplicate_distance_matrix (CL->ktupDM):CL->ktupDM; + NCL->RunName=CL->RunName; + + if ( mode==HARD_COPY && CL->translation){NCL->translation=vcalloc ((CL->S)->nseq, sizeof (int)); for ( a=0; a< (CL->S)->nseq; a++)NCL->translation[a]=CL->translation[a];} + else{NCL->translation=CL->translation;} + + NCL->out_aln_format=(mode==HARD_COPY)?duplicate_char (CL->out_aln_format, -1, -1):CL->out_aln_format; + NCL->n_out_aln_format=CL->n_out_aln_format; + + /*Packing Sequence: To use with domain analysis*/ + NCL->packed_seq_lu=(mode==HARD_COPY)?duplicate_int (CL->packed_seq_lu, -1, -1):CL->packed_seq_lu; + /*DATA*/ + if (CL->fp)(mode==HARD_COPY)?NCL->fp=vtmpfile():CL->fp; + + if ( mode==HARD_COPY) + { + NCL->residue_index=duplicate_residue_index (NCL->residue_index); + } + else NCL->residue_index=CL->residue_index; + + + if ( mode==HARD_COPY) + { + NCL->M=copy_int ( CL->M,NCL->M,-1, -1); + } + else + NCL->M=CL->M; + + + /*List Information*/ + NCL->ne=CL->ne; + sprintf ( NCL->list_name, "%s", CL->list_name); + NCL->entry_len=CL->entry_len; + NCL->el_size=CL->el_size; + + /*Normalisation information*/ + NCL->filter_lib=CL->filter_lib; + NCL->normalise=CL->normalise; + NCL->overweight=CL->overweight; + NCL->max_ext_value=CL->max_ext_value; + NCL->max_value=CL->max_value; + + /*Pair wise alignment method*/ + NCL->pw_parameters_set=CL->pw_parameters_set; + NCL->gop=CL->gop; + NCL->f_gop=CL->f_gop; + NCL->gep=CL->gep; + NCL->f_gep=CL->f_gep; + + NCL->nomatch=CL->nomatch; + + NCL->TG_MODE=CL->TG_MODE; + NCL->F_TG_MODE=CL->F_TG_MODE; + + sprintf ( NCL->dp_mode, "%s", CL->dp_mode); + NCL->maximise=CL->maximise; + sprintf ( NCL->matrix_for_aa_group, "%s", CL->matrix_for_aa_group); + sprintf ( NCL->method_matrix, "%s", CL->method_matrix); + + NCL->diagonal_threshold=CL->diagonal_threshold; + NCL->ktup=CL->ktup; + + NCL->use_fragments=CL->use_fragments; + NCL->fasta_step=CL->fasta_step; + NCL->lalign_n_top=CL->lalign_n_top; + NCL->sw_min_dist=CL->sw_min_dist; + NCL->matrices_list=(mode==HARD_COPY)?duplicate_char (CL->matrices_list, -1, -1):CL->matrices_list; + NCL->n_matrices=CL->n_matrices; + + sprintf (NCL->distance_matrix_mode, "%s", CL->distance_matrix_mode); + sprintf (NCL->distance_matrix_sim_mode, "%s", CL->distance_matrix_sim_mode); + + sprintf (NCL->tree_mode, "%s", CL->tree_mode); + NCL->tree_aln=(mode==HARD_COPY)?copy_aln (CL->tree_aln, NULL):CL->tree_aln; + /*Functions used for dynamic programming and Evaluation*/ + NCL->no_overaln=CL->no_overaln; + NCL->profile_mode=CL->profile_mode; + sprintf ( NCL->profile_comparison, "%s",CL->profile_comparison); + NCL->get_dp_cost=CL->get_dp_cost; + NCL->evaluate_residue_pair=CL->evaluate_residue_pair; + NCL->pair_wise=CL->pair_wise; + + NCL->weight_field=CL->weight_field; + NCL->max_n_pair=CL->max_n_pair; + + /*threading parameters*/ + NCL->Prot_Blast=(mode==HARD_COPY)?duplicate_blast_param ( CL->Prot_Blast):CL->Prot_Blast; + NCL->DNA_Blast =(mode==HARD_COPY)?duplicate_blast_param ( CL->DNA_Blast):CL->DNA_Blast; + NCL->Pdb_Blast =(mode==HARD_COPY)?duplicate_blast_param ( CL->Pdb_Blast):CL->Pdb_Blast; + NCL->TC =(mode==HARD_COPY)?duplicate_TC_param ( CL->TC):CL->TC; + + /*Split parameters*/ + NCL->split=CL->split; + NCL->split_nseq_thres= CL->split_nseq_thres; + NCL->split_score_thres= CL->split_score_thres; + /*Structural status*/ + NCL->check_pdb_status=CL->check_pdb_status; + /*log*/ + sprintf ( NCL->method_log, "%s",CL->method_log); + sprintf ( NCL->evaluate_mode, "%s",CL->evaluate_mode); + /* Gene Prediction*/ + sprintf ( NCL->genepred_score, "%s",CL->genepred_score); + + /*Parameters for domain extraction*/ + NCL->moca=(mode==HARD_COPY)?duplicate_moca ( CL->moca):CL->moca; + + + + /*Functions for hiding forbiden pairs of residues*/ + /* Copy only for soft_copy*/ + if (mode==SOFT_COPY) + { + NCL->forbiden_pair_list=CL->forbiden_pair_list; + } + /*extention properties:*/ + NCL->nseq_for_quadruplet=CL->nseq_for_quadruplet; + if (mode==HARD_COPY && CL->seq_for_quadruplet) + {NCL->seq_for_quadruplet=vcalloc ( S->nseq, sizeof(int)); + for ( a=0; a< S->nseq; a++) + NCL->seq_for_quadruplet[a]=CL->seq_for_quadruplet[a]; + } + else if (mode==SOFT_COPY) + { + NCL->seq_for_quadruplet=CL->seq_for_quadruplet; + } + + /*extention properties: Do only a soft copy*/ + /* Not To be copied yet */ + if ( mode==SOFT_COPY) + { + NCL->extend_jit=CL->extend_jit; + NCL->extend_threshold=CL->extend_threshold; + sprintf ( NCL->extend_clean_mode, "%s", CL->extend_clean_mode); + sprintf ( NCL->extend_compact_mode, "%s", CL->extend_compact_mode); + } + + /*Lookup table parameteres*/ + NCL->chunk= CL->chunk; + /* Do NOT copy NCL->seq_indexed, NCL->start_index, NCL->max_L_len, NCL->chunk*/ + /* + if ( mode==SOFT_COPY) + { + NCL->seq_indexed=CL->seq_indexed; + NCL->start_index=CL->start_index; + NCL->end_index=CL->start_index; + NCL->max_L_len=CL->max_L_len; + } + */ + /*PDB STRUCTURE ALIGNMENTS*/ + /* Do only a soft copy */ + if ( mode==SOFT_COPY) + { + NCL->T=CL->T; + } + /*MISC*/ + NCL->cpu=CL->cpu; + NCL->local_stderr=CL->local_stderr; + sprintf (NCL->multi_thread, "%s", CL->multi_thread); + + return NCL; + } +Constraint_list *free_constraint_list_full (Constraint_list *CL) +{ + free_sequence (free_constraint_list (CL), -1); + return NULL; +} +Sequence *free_constraint_list (Constraint_list *CL) + { + Sequence *S; + int a, b; + Constraint_list *pCL; + + + /*Prepare the selective freeing of the CL data structure: + If the CL has been obtained from copy, every pointer that is identical to the parent CL (CL->pCL) + will not be saved. + */ + + + if ( !CL)return NULL; + else S=CL->S; + + if ( CL->copy_mode==SOFT_COPY && !CL->pCL) + {vfree(CL); return S;} + else if ( CL->copy_mode==SOFT_COPY) + { + + pCL=CL->pCL; + CL->residue_index=NULL; + + if ( CL->M ==pCL->M )CL->M=NULL; + + if (CL->start_index ==pCL->start_index )CL->start_index=NULL; + if (CL->end_index ==pCL->end_index )CL->end_index=NULL; + + if ( CL->fp ==pCL->fp )CL->fp=NULL; + if ( CL->matrices_list ==pCL->matrices_list )CL->matrices_list=NULL; + + + if ( CL->STRUC_LIST ==pCL->STRUC_LIST )CL->STRUC_LIST=NULL; + if ( CL->W ==pCL->W )CL->W=NULL; + if ( CL->DM ==pCL->DM )CL->DM=NULL; + if ( CL->ktupDM ==pCL->ktupDM )CL->ktupDM=NULL; + + + if ( CL->translation ==pCL->translation )CL->translation=NULL; + if ( CL->moca ==pCL->moca )CL->moca=NULL; + if ( CL->Prot_Blast ==pCL->Prot_Blast )CL->Prot_Blast=NULL; + if ( CL->DNA_Blast ==pCL->DNA_Blast )CL->DNA_Blast=NULL; + if ( CL->Pdb_Blast ==pCL->Pdb_Blast )CL->Pdb_Blast=NULL; + if ( CL->seq_for_quadruplet ==pCL->seq_for_quadruplet )CL->seq_for_quadruplet=NULL; + if ( CL->TC ==pCL->TC )CL->TC=NULL; + + } + + + /*End of selective freeing of the CL data structure*/ + + + + if ( CL->residue_index)free_arrayN(CL->residue_index, 3); + + if ( CL->M)free_int (CL->M, -1); + if ( CL->fp)vfclose (CL->fp); + if ( CL->matrices_list)free_char(CL->matrices_list,-1); + + + if ( CL->start_index)free_int ( CL->start_index,-1); + if ( CL->end_index)free_int ( CL->end_index,-1); + + + + + if ( CL->STRUC_LIST)free_sequence ( CL->STRUC_LIST, (CL->STRUC_LIST)->nseq); + if ( CL->W)free_weights (CL->W); + + CL->DM=free_distance_matrix (CL->DM); + CL->ktupDM=free_distance_matrix (CL->ktupDM); + + if ( CL->translation)vfree(CL->translation); + if ( CL->moca)free_moca (CL->moca); + if ( CL->Prot_Blast)free_blast_param ( CL->Prot_Blast); + if ( CL->DNA_Blast) free_blast_param ( CL->DNA_Blast); + if ( CL->Pdb_Blast) free_blast_param ( CL->Pdb_Blast); + if ( CL->TC) free_TC_param ( CL->TC); + + if (CL->seq_for_quadruplet)vfree (CL->seq_for_quadruplet); + + vfree(CL); + return S; + } + +Distance_matrix * free_distance_matrix ( Distance_matrix *DM) +{ + if (!DM)return NULL; + free_int ( DM->similarity_matrix,-1); + free_int ( DM->distance_matrix,-1); + free_int ( DM->score_similarity_matrix,-1); + vfree (DM); + return NULL; +} +Distance_matrix * duplicate_distance_matrix ( Distance_matrix *DMin) +{ + Distance_matrix *DM; + if (!DMin) return NULL; + + DM=vcalloc ( 1, sizeof (Distance_matrix)); + DM->similarity_matrix=duplicate_int ( DMin->similarity_matrix, -1, -1); + DM->distance_matrix=duplicate_int ( DMin->distance_matrix, -1, -1); + DM->score_similarity_matrix=duplicate_int ( DMin->score_similarity_matrix, -1, -1); + return DM; +} + +/************************************************************************/ +/* */ +/* MOCA Functions */ +/* */ +/* */ +/************************************************************************/ +Moca * duplicate_moca ( Moca *m) + { + Moca *nm; + + if ( m==NULL)return m; + + nm=vcalloc ( 1, sizeof (Moca)); + + nm->moca_scale=m->moca_scale; + nm->evaluate_domain=m->evaluate_domain; + nm->moca_threshold=m->moca_threshold; + nm->cache_cl_with_domain=m->cache_cl_with_domain; + if ( m->forbiden_residues)nm->forbiden_residues=copy_int (m->forbiden_residues,nm->forbiden_residues, -1, -1); + nm->make_nol_aln=m->make_nol_aln; + + + return nm; + } +Moca * free_moca ( Moca *m) + { + if ( m->forbiden_residues)free_int ( m->forbiden_residues, -1); + vfree ( m); + return NULL; + } +/************************************************************************/ +/* */ +/* TC_param Functions */ +/* */ +/* */ +/************************************************************************/ +TC_param * duplicate_TC_param ( TC_param*B) +{ + TC_param *N; + N=vcalloc (1, sizeof ( TC_param)); + memcpy(B, N, sizeof(TC_param)); + return N; + } +TC_param * free_TC_param ( TC_param*B) +{ + vfree (B); + return NULL; +} +/************************************************************************/ +/* */ +/* Blast_param Functions */ +/* */ +/* */ +/************************************************************************/ +Blast_param * duplicate_blast_param ( Blast_param*B) +{ + Blast_param *N; + N=vcalloc (1, sizeof ( Blast_param)); + sprintf ( N->blast_server, "%s", B->blast_server); + sprintf ( N->db, "%s", B->db); + N->min_id=B->min_id; + N->max_id=B->min_id; + N->min_cov=B->min_cov; + return N; +} +Blast_param * free_blast_param ( Blast_param*B) +{ + vfree (B); + return NULL; +} + +/************************************************************************/ +/* */ +/* PDB Functions */ +/* */ +/* */ +/************************************************************************/ +Structure* declare_structure ( int n, char **array) + { + Structure *S; + int a; + + S=vcalloc (1, sizeof (Structure)); + S->n_fields=1; + S->nseq=n; + + S->struc=vcalloc ( n, sizeof (int**)); + S->len=vcalloc ( n, sizeof (int)); + for ( a=0; a< n; a++) + { + S->len[a]=strlen(array[a]); + S->struc[a]=declare_int ( strlen ( array[a])+2, 1); + } + return S; + } + +Structure *extend_structure ( Structure *S) + { + int a, b; + + + for ( a=0; a< S->nseq; a++) + { + for ( b=0; b< S->len[a]; b++) + S->struc[a][b]=vrealloc ( S->struc[a][b],( S->n_fields+1)*sizeof (int)); + } + S->n_fields++; + return S; + } +Sequence * reset_sequence_len (Sequence *S) +{ + int min,max,a,l; + + if ( !S || !S->nseq)return 0; + max=min=strlen (S->seq[0]); + for (a=0; anseq; a++) + { + l=strlen (S->seq[a]); + min=MIN(l,min); + max=MAX(l,max); + S->len[a]=l; + } + S->max_len=max; + S->min_len=min; + return S; +} +Sequence * declare_sequence ( int min, int max, int nseq) + { + Sequence *LS; + + + + LS=vcalloc (1, sizeof ( Sequence)); + + LS->seq_comment=declare_char ( nseq,COMMENT_SIZE); + LS->aln_comment=declare_char ( nseq,COMMENT_SIZE); + + LS->file=declare_char( nseq,STRING+1); + LS->seq=declare_char ( nseq, max+1); + LS->name=declare_char( nseq,MAXNAMES+1); + + LS->len=vcalloc ( nseq, sizeof (int)); + LS->max_len=max; + LS->min_len=min; + LS->nseq=nseq; + LS->max_nseq=nseq; + LS->type=vcalloc(30, sizeof (char)); + LS->T=declare_arrayN(2, sizeof (Template), nseq, 1); + + + LS->dc=declare_int (nseq, 2); + return LS; + } +Sequence * realloc_sequence (Sequence *OUT, int new_nseq, int max_len) + { + + + if ( new_nseqmax_nseq)return OUT; + + OUT->min_len =MIN(OUT->min_len,max_len); + OUT->max_len =MAX(OUT->max_len,max_len); + OUT->seq_comment =new_realloc_char ( OUT->seq_comment, new_nseq,COMMENT_SIZE); + OUT->aln_comment =new_realloc_char ( OUT->aln_comment, new_nseq,COMMENT_SIZE); + + OUT->seq =new_realloc_char ( OUT->seq, new_nseq,OUT->max_len+1); + OUT->name =new_realloc_char ( OUT->name, new_nseq,MAXNAMES+1); + + + OUT->file =new_realloc_char ( OUT->file, new_nseq,STRING+1); + OUT->len =vrealloc ( OUT->len, (new_nseq+1)*sizeof (int)); + + OUT->T=(Template**)realloc_arrayN (2, (void **)OUT->T,sizeof (Template), new_nseq, 1); + OUT->dc=(int **)realloc_arrayN (2, (void **)OUT->dc,sizeof (int), new_nseq, 2); + + OUT->max_nseq=new_nseq; + return OUT; + } + +Sequence * duplicate_sequence (Sequence *S ) + { + Sequence *LS; + int a, b; + + + if (S==NULL)return S; + LS=declare_sequence (S->min_len, S->max_len, S->nseq); + for (b=0, a=0; anseq; a++) + { + if (S->seq && S->seq[a]) + { + + sprintf ( LS->file[b], "%s", S->file[a]); + if ( S->seq_comment && S->seq_comment[a])sprintf ( LS->seq_comment[b], "%s", S->seq_comment[a]); + if ( S->aln_comment && S->aln_comment[a])sprintf ( LS->aln_comment[b], "%s", S->aln_comment[a]); + if ( S->seq && S->seq[a])sprintf ( LS->seq[b], "%s", S->seq[a]); + if ( S->name&& S->name[a])sprintf ( LS->name[b], "%s", S->name[a]); + LS->dc[b][0]=S->dc[a][0]; + LS->dc[b][1]=S->dc[a][1]; + LS->len[b]=S->len[a]; + LS->T[b][0]=S->T[a][0]; + + b++; + + } + } + + LS->max_len=S->max_len; + LS->min_len=S->min_len; + LS->nseq=b; + + if (S->W)LS->W=duplicate_weights (S->W); + sprintf ( LS->type, "%s", S->type); + sprintf ( LS->template_file, "%s", S->template_file); + LS->max_nseq=S->nseq; + + return LS; + } + +void free_sequence ( Sequence *LS, int nseq) + { + + + if ( !LS) return; + + + free_char ( LS->file, -1); + free_char ( LS->seq_comment, -1); + free_char ( LS->aln_comment, -1); + free_char ( LS->seq, -1); + free_char ( LS->name,-1); + free_int (LS->dc, -1); + free_arrayN((void*)LS->T, 2); + vfree (LS->type); + vfree (LS->len); + free_weights (LS->W); + + vfree (LS); + + } +/************************************************************************/ +/* */ +/* Weights Functions */ +/* */ +/* */ +/************************************************************************/ +Weights* declare_weights ( int nseq) + { + Weights *W; + + W=vcalloc ( 1, sizeof ( Weights)); + W->comments=vcalloc ( 1000, sizeof (char)); + W->nseq=nseq; + W->mode=vcalloc (FILENAMELEN, sizeof (char)); + W->seq_name= declare_char ( W->nseq*2, 200); + W->PW_SD=declare_float ( W->nseq, W->nseq); + W->PW_ID=declare_float ( W->nseq, W->nseq); + W->SEQ_W=vcalloc ( W->nseq, sizeof ( float)); + return W; + } +Weights* duplicate_weights (Weights *W) + { + Weights *NW; + int a, b, c; + + NW=declare_weights (W->nseq); + sprintf ( NW->comments, "%s", W->comments); + sprintf ( NW->mode, "%s", W->mode); + for (a=0, c=0; a< W->nseq; a++) + { + if ( W->seq_name[a]) + { + sprintf ( NW->seq_name[c], "%s", W->seq_name[a]); + NW->SEQ_W[c]=W->SEQ_W[a]; + for(b=0; b< W->nseq; b++) + { + NW->PW_SD[c][b]=W->PW_SD[a][b]; + NW->PW_ID[c][b]=W->PW_ID[a][b]; + } + c++; + } + } + return NW; + } +Weights* free_weights ( Weights* W) + { + + if ( !W)return NULL; + + vfree(W->comments); + + + vfree(W->mode); + + free_char(W->seq_name, -1); + free_float(W->PW_SD,-1); + free_float(W->PW_ID, -1); + vfree(W->SEQ_W); + vfree(W); + return NULL; + } + + +Alignment* copy_aln ( Alignment *A, Alignment *B) + { + int a, b; + int nnseq; + int nlen; + /* c[100]=10;*/ + + + + if ( A==NULL){free_aln(B); return NULL;} + + nnseq=MAX(A->nseq, A->max_n_seq); + nlen=A->len_aln+1; + if (B) + B=realloc_alignment2 (B, nnseq, nlen); + else + B=declare_aln2 (nnseq, nlen); + B->S=A->S; + + + /*SIZES*/ + B->max_len=A->max_len; + B->min_len=A->min_len; + B->declared_len=nlen; + B->max_n_seq=nnseq; + + B->nseq=A->nseq; + B->len_aln=A->len_aln; + + +/*sequence Information*/ + if ( A->generic_comment) + { + vfree(B->generic_comment); + B->generic_comment=vcalloc (strlen(A->generic_comment)+1, sizeof (char)); + sprintf ( B->generic_comment, "%s", A->generic_comment); + } + if ( (A->S)==NULL){vfree (B->len); B->len=vcalloc ( A->max_n_seq, sizeof (int));} + ga_memcpy_int ( A->len, B->len, B->nseq); + + B->seq_comment=copy_char ( A->seq_comment, B->seq_comment, -1,-1); + B->aln_comment=copy_char ( A->aln_comment, B->aln_comment, -1,-1); + + B->name=copy_char ( A->name, B->name, -1,-1); + + B->file=copy_char ( A->file, B->file, -1,-1); + B->tree_order=copy_char ( A->tree_order, B->tree_order, -1,-1); + B->expanded_order=A->expanded_order; + free_char ( B->seq_al, -1); + B->seq_al=declare_char(B->max_n_seq, B->declared_len); + // HERE ("A: MAX_NSEQ=%d %d %d %d",B->nseq, B->max_n_seq, B->declared_len, B->len_aln); + // HERE ("B: MAX_NSEQ=%d %d %d %d",A->nseq, A->max_n_seq, A->declared_len, A->len_aln); + for ( a=0; a< nnseq; a++) + { + if (A->seq_al[a]) + { + for ( b=0; b< A->len_aln; b++) + B->seq_al[a][b]=A->seq_al[a][b]; + } + } + + + + B->order=copy_int ( A->order, B->order, -1, -1); + B->S=A->S; + if (A->seq_cache) + { + B->seq_cache=copy_int ( A->seq_cache, B->seq_cache,-1,-1); + } + + if (A->cdna_cache) + { + B->cdna_cache=copy_int ( A->cdna_cache, B->cdna_cache,-1,-1); + } + + B->P=copy_profile (A->P); + + B->Dp_result=A->Dp_result; + +/*Score*/ + + if ( (A->S)==NULL){vfree (B->score_seq); B->score_seq=vcalloc ( A->max_n_seq, sizeof (int));} + ga_memcpy_int( A->score_seq,B->score_seq,B->nseq); + B->score_res=A->score_res; + + B->score_aln=A->score_aln; + B->score=A->score; + B->ibit=A->ibit; + B->cpu=A->cpu; + B->finished=A->finished; + +/*Output Options*/ + B->output_res_num=A->output_res_num; + B->residue_case=A->residue_case; + B->expand=A->expand; + + B->CL=A->CL; + B->random_tag=A->random_tag; + +/*Make the function Recursive */ + if ( A->A) + { + B->A=copy_aln (A->A, NULL); + } + else B->A=NULL; + + return B; + } + +Alignment* shrink_aln ( Alignment *A, int nseq, int *list) + { + Alignment *B=NULL; + int a,seq; + + B=copy_aln (A, B); + for ( a=0; a< nseq; a++) + { + seq=list[a]; + sprintf ( A->seq_comment[a], "%s",B->seq_comment[seq]); + sprintf ( A->aln_comment[a], "%s",B->aln_comment[seq]); + + sprintf ( A->seq_al [a], "%s",B->seq_al [seq]); + A->order[a][0]=B->order[seq][0]; + A->order[a][1]=B->order[seq][1]; + A->order[a][2]=B->order[seq][2]; + A->order[a][3]=B->order[seq][3]; + A->order[a][4]=B->order[seq][4]; + + A->score_seq[a]=B->score_seq[seq]; + A->len[a]=B->len[seq]; + } + A->nseq=nseq; + A->len_aln=strlen (A->seq_al[0]); + free_aln (B); + return A; + } +Alignment* extract_sub_aln2 ( Alignment *B, int ns, char **ls) + { + int *list; + Alignment *A; + + list=name_array2index_array(ls, ns, B->name, B->nseq); + A=extract_sub_aln ( B,ns, list); + vfree (list); + return A; + } +Alignment* extract_sub_aln ( Alignment *B, int nseq, int *list) + { + Alignment *A=NULL; + int a,b,n,seq; + + A=declare_aln2(nseq, B->len_aln+1); + for ( n=0,a=0; a< nseq; a++) + { + seq=list[a]; + if ( seq==-1)continue; + else n++; + sprintf ( A->seq_comment[a], "%s",B->seq_comment[seq]); + sprintf ( A->aln_comment[a], "%s",B->aln_comment[seq]); + sprintf ( A->name[a], "%s",B->name[seq]); + + + for (b=0; b<=B->len_aln; b++)A->seq_al [a][b]=B->seq_al [seq][b]; + A->order[a][0]=B->order[seq][0]; + A->order[a][1]=B->order[seq][1]; + A->order[a][2]=B->order[seq][2]; + A->order[a][3]=B->order[seq][3]; + A->order[a][4]=B->order[seq][4]; + + A->score_seq[a]=B->score_seq[seq]; + A->len[a]=B->len[seq]; + } + A->nseq=n; + A->len_aln=B->len_aln; + return A; + } + +Alignment *declare_aln2 ( int nseq, int len) + { + Sequence *S; + Alignment *A; + + S=vcalloc ( 1, sizeof ( Sequence)); + S->nseq=nseq; + S->max_len=len; + + A=declare_aln (S); + A->S=NULL; + vfree(S); + return A; + } + + + +Alignment *declare_aln ( Sequence *S){return declare_Alignment(S);} + +Alignment *declare_Alignment ( Sequence *S) + { + Alignment *LA; + int a; + + /*ordre: + [x][0]= which is the xth seq of aln + [x][1]= how many deleted residues before the first one + */ + + + LA=vcalloc (1, sizeof ( Alignment)); + aln_stack (LA, DECLARE_ALN); + if ( S==NULL) + { + LA->declared_len=MAX_LEN_ALN; + LA->max_n_seq=MAX_N_SEQ; + } + else + { + LA->declared_len=2*S->max_len+1; + LA->max_n_seq=S->nseq+1; + } + LA->S=S; + + + LA->seq_comment=declare_char (LA->max_n_seq, COMMENT_SIZE); + LA->aln_comment=declare_char (LA->max_n_seq, COMMENT_SIZE); + + + LA->seq_al=declare_char ( LA->max_n_seq,LA->declared_len ); + LA->name=declare_char (LA->max_n_seq, MAXNAMES+1); + + + LA->file=declare_char (LA->max_n_seq, STRING); + LA->tree_order=declare_char (LA->max_n_seq, STRING); + LA->order= declare_int (LA->max_n_seq , 5); + //order[a][0]: sequence index in S + //order[a][1]: offset of the sequence + //order[a][2]: used by sw_gotoh_pair_wise + //order[a][3]: used by sw_gotoh_pair_wise + //order[a][4]: weight, -1 + LA->score_seq= vcalloc (LA->max_n_seq, sizeof (int)); + + for ( a=0; a< LA->max_n_seq; a++)LA->order[a][0]=a; + + LA->len_aln=0; + LA->score_aln=0; + LA->len=vcalloc (LA->max_n_seq, sizeof (int)); + + if (S && S->name)for ( a=0; anseq; a++) + { + sprintf ( LA->name[a], "%s", S->name[a]); + + } + + return LA; + + } +Alignment * realloc_aln ( Alignment *A, int new_len){return realloc_alignment(A, new_len);} +Alignment * realloc_alignment ( Alignment *A, int new_len) + { + if (A==NULL)A=declare_Alignment (NULL); + + return realloc_alignment2( A, A->max_n_seq,new_len); + } + +Alignment * realloc_aln2 ( Alignment *A, int n_nseq, int n_len){return realloc_alignment2(A, n_nseq, n_len);} + + + +Alignment * realloc_alignment2 ( Alignment *A, int n_nseq, int n_len) + { + int a; + int len, nseq; + int delta_len, delta_nseq; + + if ( A==NULL) A=declare_Alignment(NULL); + + n_len++; + n_nseq++; + + len=A->declared_len; + nseq=A->max_n_seq; + + n_len=MAX(len, n_len); + n_nseq=MAX(nseq,n_nseq); + delta_nseq=MAX(0,n_nseq-nseq); + delta_len =MAX(0,n_len-len); + + if ( delta_nseq<=0 && delta_len<=0)return A; + + + else + { + A->len =vrealloc( A->len , sizeof (int)*n_nseq); + for (a=nseq; a< n_nseq; a++)A->len[a]=0; + + A->declared_len =n_len; + A->max_n_seq =n_nseq; + + + A->seq_comment=new_realloc_char ( A->seq_comment, n_nseq, -1); + A->aln_comment=new_realloc_char ( A->aln_comment, n_nseq, -1); + + A->name =new_realloc_char ( A->name, n_nseq, -1); + + + A->file =new_realloc_char ( A->file, n_nseq, -1); + + A->tree_order =new_realloc_char ( A->tree_order, n_nseq, -1); + A->seq_al =new_realloc_char ( A->seq_al, n_nseq, n_len); + A->order =new_realloc_int ( A->order, n_nseq, -1); + + if ( A->seq_cache) A->seq_cache=new_realloc_int ( A->seq_cache, n_nseq,n_len); + if ( A->cdna_cache)A->cdna_cache=new_realloc_int ( A->cdna_cache, n_nseq,n_len); + + + A->score_seq =vrealloc( A->score_seq, sizeof (int)*(n_nseq)); + for ( a=nseq; a< n_nseq; a++)A->score_seq[a]=0; + + + + } + return A; + } + + +long aln_stack (Alignment *A, int mode) +{ + static long *list; + static int size; + static int max_size; + + + if (A==NULL) return 0; + else if ( mode==DECLARE_ALN) + { + if ( size==max_size) + { + max_size+=1000; + list=vrealloc (list, max_size*sizeof (long)); + } + list[size++]=(long)A; + return 0; + } + else if (mode==FREE_ALN) + { + int a, b; + for (a=0; aseq_al=free_char (A->seq_al, -1); + A->seq_comment=free_char (A->seq_comment, -1); + A->aln_comment=free_char (A->aln_comment, -1); + A->name=free_char (A->name, -1); + A->expanded_order=free_char (A->expanded_order, -1); + + A->order=free_int (A->order, -1); + A->seq_cache=free_int (A->seq_cache, -1); + A->cdna_cache=free_int (A->cdna_cache, -1); + A->score_res=free_int (A->score_res, -1); + free_sequence (A->S, -1); + A->S=NULL; + return A; + +} +Sequence* free_Alignment ( Alignment *LA) + { + /* Does not free the A->S field (sequences of A)*/ + + Sequence *S; + //aln_stack checks the alignment has not already been freed + if ( LA==NULL || !aln_stack(LA,FREE_ALN)){return NULL;} + + S=LA->S; + free_char ( LA->file, -1); + free_char ( LA->seq_al, -1); + free_int ( LA->seq_cache, -1); + free_int ( LA->cdna_cache, -1); + free_char ( LA->name,-1); + + free_char ( LA->tree_order,-1); + vfree ( LA->generic_comment); + free_char ( LA->seq_comment, -1); + free_char ( LA->aln_comment, -1); + + free_int ( LA->order, -1); + + vfree ( LA->score_seq); + vfree ( LA->len); + + free_profile (LA->P); + if ( LA->A){free_Alignment (LA->A);LA->A=NULL;} + + + vfree ( LA); + return S; + } + +Alignment * update_aln_random_tag ( Alignment *A) +{ + static int tag; + if ( !A) return A; + + A->random_tag=++tag; + return A; +} + +Profile *copy_profile (Profile *P1) +{ + + Profile *P; + + if ( !P1) return NULL; + P=declare_profile ( P1->alphabet, P1->max_len); + P->count=copy_int (P1->count, P->count, -1, -1); + P->count2=copy_int (P1->count2, P->count2, -1, -1); + P->count3=copy_int (P1->count3, P->count3, -1, -1); + + return P; + +} + + +Profile *declare_profile(char *alphabet, int len) +{ + Profile *P; + P=vcalloc ( 1, sizeof ( Profile)); + P->alp_size=strlen(alphabet); + P->max_len=len; + P->alphabet=vcalloc ( strlen (alphabet)+2, sizeof (char)); + sprintf ( P->alphabet, "%s", alphabet); + + P->count=declare_int( P->alp_size+2, len); + P->count2=declare_int(100, len); + P->count3=declare_int(100, len); + + return P; +} +Profile * free_profile ( Profile *P) +{ + if (!P) return NULL; + else + { + vfree (P->alphabet); + free_int ( P->count, -1); + free_int ( P->count2, -1); + vfree (P); + } + return NULL; +} + + +/************************************************************************/ +/* */ +/* ALLOCATION */ +/* */ +/* */ +/************************************************************************/ + + +double alloc_mem; +double max_mem; +double tot_mem; +Memcontrol *memlast; + +FILE* print_mem_usage (FILE *fp, char *comment) +{ + fprintf ( fp, "# %s Memory Usage: Current= %.3f Mb, Max= %.3f Mb\n", comment,(float)((float)alloc_mem/(1024*1024)),(float)((float)tot_mem/(1024*1024)) ); + return fp; +} +void set_max_mem (int m) +{ + max_mem=m*1024*1024; +} + +int verify_memory (int s) +{ + alloc_mem+=s; + + tot_mem=(alloc_mem>tot_mem)?alloc_mem:tot_mem; + + if (max_mem && alloc_mem>max_mem) + { + fprintf (stderr, "\n%s Requires Too Much Memory: %d Megabytes [FATAL:%s]\n", PROGRAM,(int)(alloc_mem/1024*1024),PROGRAM); + fprintf (stderr, "Tip: Rerun your Job with a smaller dataset\n"); + + myexit (EXIT_FAILURE); + } + else + return 1; + return 0; + +} + +int my_assert ( void *p, int index) +{ + static int warning; + + if (!warning) + { + fprintf ( stderr, "\n****************************************************************\n"); + fprintf ( stderr, "\n DEBUG MODE [Rebuild For Better Performances] \n"); + fprintf ( stderr, "\n*****************************************************************\n"); + warning=1; + } + + if ( !is_dynamic_memory(p)) return 1; + else if ( read_array_size_new (p)<=index) + { + fprintf ( stderr, "\nFaulty Allocation: Size=%d Access=%d\n", read_array_size (p,0),index); + return 0; + } + else + { + return 1; + } +} + + + +void * vmalloc ( size_t size) + { + void * x; + Memcontrol *M; + + verify_memory (size+2*sizeof (Memcontrol)); + + if ( size==0) + return NULL; /*crash ("\n0 bytes in vmalloc\n");*/ + else + { + + x= malloc (size + 2*sizeof (Memcontrol)); + //x=dlmalloc (size + 2*sizeof (Memcontrol)); + if ( x==NULL) + { + printf_exit (EXIT_FAILURE,stderr, "\nFAILED TO ALLOCATE REQUIRED MEMORY (vmalloc)\n"); + + } + else + { + M=x; + M[0].size=size; + M[0].size_element=0; + sprintf ( M[0].check, "dy"); + M+=2; + x=M; + return x; + } + } + return NULL;} + + + +void *vcalloc (size_t nobj, size_t size) +{ + return sub_vcalloc (nobj,size, MEMSET0); +} +void *vcalloc_nomemset ( size_t nobj, size_t size) +{ + return sub_vcalloc (nobj, size, NO_MEMSET0); +} +void *sub_vcalloc ( size_t nobj, size_t size, int MODE) + { + void *x; + Memcontrol *M; + + if ( nobj<=0 || size<=0)return NULL;/*crash ("\n0 bytes in vmalloc\n");*/ + else x=vmalloc (nobj*size); + + + M=x;M-=2;M[0].size_element=size;M+=2;x=M; + + if ( x==NULL) + { + crash ( "\nFAILED TO ALLOCATE REQUIRED MEMORY (vcalloc)\n"); + return NULL; + } + else + { + if ( MODE==MEMSET0) + { + x=memset (x,0, nobj*size); + } + else + { + if (nobj)x=memset (x, 0, size); + } + return x; + } + } + +void *vrealloc ( void *p, size_t size) + { + void *x; + Memcontrol *M; + size_t i_size; + int a; + + + if ( p==NULL) + { + x=vmalloc (size); + memset (x, 0, size); + + return x; + } + else + { + M=p; + M-=2; + i_size=M[0].size; + p=M; + + + if ( size<=0){return NULL;vfree (p);return NULL;} + else + { + verify_memory (size - i_size); + x=realloc ( p, size+2*sizeof(Memcontrol)); + + if ( x==NULL){crash ( "\nFAILED TO ALLOCATE REQUIRED MEMORY (realloc)\n");return NULL;} + M=x; + M[0].size=size; + M+=2; + x=M; + for ( a=i_size; a< size; a++)((char*)x)[a]=0; + return x; + } + } + return NULL; + } +void vfree ( void *p) + { + Memcontrol *M; + size_t size; + + if ( !p)return; + else + { + M=p; + M-=2; + size=M[0].size; + + p=M; + free(p); + + verify_memory (-(size+2*sizeof(Memcontrol))); + } + } +void vfree_all (void *p) +{ + Memcontrol *n; + while (memlast) + { + n=memlast->p; + vfree (memlast+2); + memlast=n; + } +} +/*********************************************************************/ +/* */ +/* SIZES */ +/* */ +/* */ +/*********************************************************************/ +#define WRITE_SIZE(type,function)\ +void function ( int x, type *array, int os)\ + {\ + fprintf(stderr, "\nwrite_size is a deprecated function [Warning:%s]\n", PROGRAM);return;\ + } +WRITE_SIZE(short,write_size_short) +WRITE_SIZE(char,write_size_char) +WRITE_SIZE(int,write_size_int) +WRITE_SIZE(float,write_size_float) +WRITE_SIZE(double,write_size_double) + +#define READ_ARRAY_SIZE(type, function)\ +int function (void *array, size_t size)\ + {\ + return read_array_size (array, size);\ + } +READ_ARRAY_SIZE(short,read_size_short) +READ_ARRAY_SIZE(char,read_size_char) +READ_ARRAY_SIZE(int,read_size_int) +READ_ARRAY_SIZE(float,read_size_float) +READ_ARRAY_SIZE(double,read_size_double) + + +int read_array_size_new (void *array) +{ + return read_array_size ( array, 0); +} +int read_array_size (void *array, size_t size) + { + Memcontrol *p; + if (array==NULL)return 0; + p=(Memcontrol *)array; + p-=2; + if ( p[0].size_element ==0 && size==0) + { + fprintf ( stderr, "\nERROR in read_array_size: trying to read the size of a malloced block"); + } + else if ( size ==0) return (int)p[0].size/p[0].size_element; + + return (int)p[0].size/size; + + } +int is_dynamic_memory ( void *array) +{ + Memcontrol *p; + if (array==NULL)return 0; + p=(Memcontrol *)array; + p-=2; + if ( strm (p[0].check, "dy"))return 1; + return 0; +} + +/************************************************************************/ +/* */ +/* DECLARE 2d ARRAYS */ +/* */ +/* */ +/************************************************************************/ + +void * free_arrayN(void *p, int n) +{ + int a, s; + void **i; + + + if ( p==NULL) return NULL; + else if ( n==1)vfree ((void *)p); + else + { + i=(void**)p; + s=read_array_size ( (void *)p, sizeof ( void *)); + for ( a=0; a< s; a++)free_arrayN ((void *)i[a], n-1); + vfree (p); + } + return NULL; +} + +void * declare_arrayNnomemset (int ndim, size_t size, ...) +{ + va_list ap; + int *array; + void **p; + int a; + + va_start (ap, size); + + array=vcalloc (ndim, sizeof (int)); + for ( a=0; a< ndim; a++) + { + array[a]=va_arg (ap,int); + if ( array[a]<0){va_end(ap);return NULL;} + + } + va_end (ap); + + if ( ndim==2) + { + + p=vcalloc_nomemset (array[0], sizeof ( void*)); + for (a=0; a< array[0]; a++) + { + p[a]=vcalloc_nomemset (array[1], size); + } + } + else + { + p=declare_arrayN2nomemset (ndim, array, size); + } + vfree (array); + return p; +} + +void *declare_arrayN2nomemset ( int ndim, int *A, size_t size) +{ + int a; + void **p; + + if ( ndim>1) + { + p=vcalloc_nomemset (A[0], sizeof (void*)); + for ( a=0; a1) + { + p=vcalloc_nomemset (A[0], sizeof (void*)); + for ( a=0; a1) + { + o=read_array_size (p,sizeof (void*)); + if (A[0]>o)p=vrealloc (p, sizeof (void*)*A[0]); + n=(A[0]==-1)?o:A[0]; + for ( a=0; ao)p=vrealloc (p, size*A[0]); + } + return p; +} + + + +void ** realloc_array (void **array,size_t size, int first, int second, int ext1, int ext2) +{ + int a; + int d1, d2; + if ( array==NULL)return declare_array (((first==-1)?0:first)+ext1, ((second==-1)?0:second)+ext2, size); + else if ( first==-1) + { + first=read_array_size (array, sizeof (void *)); + } + if (second==-1)second=read_array_size(array[0], size); + + d1=first+ext1; + d2=second+ext2; + + for ( a=d1; a0) + { + array=vrealloc ( array, (sizeof (Alignment*))*(first+ext1)); + for ( a=first; a=(first+ext1);a--)free_Alignment (array[a]); + array=vrealloc ( array, (sizeof (Alignment*))*(first+ext1)); + } + return array; + } + +/************************************************************************/ +/* */ +/* free 2d ARRAYS */ +/* */ +/* */ +/************************************************************************/ +#define FREE_ARRAY(type,wf,rf,function) \ +type ** function (type **array, int first)\ + {\ + return free_arrayN((void*)array, 2);\ + } +FREE_ARRAY(short,write_size_short,read_size_short,free_short) +FREE_ARRAY(char,write_size_char,read_size_char,free_char) +FREE_ARRAY(int,write_size_int,read_size_int,free_int) +FREE_ARRAY(float,write_size_float,read_size_float,free_float) +FREE_ARRAY(double,write_size_double,read_size_double,free_double) + + + +Alignment ** free_aln_array (Alignment **array) + { + int a; + int len; + + + if ( array==NULL)return NULL; + len=read_array_size ( array, sizeof (Alignment *)); + for ( a=1; a< len; a++)free_Alignment(array[a]); + vfree ( array); + return NULL; + } + +Fname *declare_fname (int size) + { + Fname *F; + + size+=strlen (get_home_4_tcoffee())+FILENAMELEN+1; + + F=vcalloc ( 1, sizeof (Fname)); + F->name =vcalloc ( size, sizeof (char)); + F->path =vcalloc ( size, sizeof (char)); + F->suffix=vcalloc ( size, sizeof (char)); + F->full=vcalloc ( size, sizeof (char)); + return F; + } + +Fname *free_fname ( Fname *F) + { + vfree (F->name); + vfree (F->path); + vfree (F->suffix); + return NULL; + } +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/util_domain_constraints_list.c b/binaries/src/tcoffee/t_coffee_source/util_domain_constraints_list.c new file mode 100644 index 0000000..a96c756 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/util_domain_constraints_list.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" + +/*********************************************************************/ +/* */ +/* MISCEANELLOUS */ +/* */ +/* */ +/*********************************************************************/ +int ** get_undefined_list (Constraint_list *CL) + { + int **list; + int a; + CLIST_TYPE x; + int *e; + list=declare_int ( (CL->S)->nseq+1, (CL->S)->max_len+1); + + + while (e=extract_entry (CL)) + { + x=e[WE]; + list[e[SEQ1]][e[R1]]=(x==UNDEFINED); + list[e[SEQ2]][e[R2]]=(x==UNDEFINED); + } + return list; + } + + + +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/util_domain_dp.c b/binaries/src/tcoffee/t_coffee_source/util_domain_dp.c new file mode 100644 index 0000000..598c934 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/util_domain_dp.c @@ -0,0 +1,569 @@ +#include +#include +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" + +#include "dp_lib_header.h" + +int domain_pair_wise (Alignment *A,int*in_ns, int **in_l_s,Constraint_list *CL ) + { +/*******************************************************************************/ +/* SEQ_DOMAIN DP */ +/* */ +/* makes DP between the the ns[0] sequences and the ns[1] */ +/* */ +/* for MODE, see the function get_dp_cost */ +/*******************************************************************************/ + + int scale, gop, gep, maximise; + int a, b, i, j,l,x; + int best_j; + + int lenal[2], len; + int sub; + int match; + + int *ns, **l_s; + + + int *f; + int *pf; + + int *dd; + int *dd_len; + + int * e; + int *pe; + int * e_len; + int *pe_len; + + int fop; + int **pos0; + + int **al=NULL; + int **pos_al=NULL; + + + + int ala,LEN; + char *buffer; + char *char_buf; + + +/*trace back variables */ + TRACE_TYPE *buf_trace=NULL; + TRACE_TYPE **trace; + TRACE_TYPE k; + TRACE_TYPE *tr; + int **result_aln; + int nseq; +/*Test Varaibles*/ + int score; + +/*Prepare l_s and ns*/ + + + ns=vcalloc( 2, sizeof (int)); + l_s=vcalloc ( 2, sizeof (int*)); + + ns[0]=in_ns[1]; + ns[1]=in_ns[0]; + + l_s[0]=in_l_s[1]; + l_s[1]=in_l_s[0]; + lenal[0]=strlen (A->seq_al[l_s[0][0]]); + lenal[1]=strlen (A->seq_al[l_s[1][0]]); + len=lenal[0]+lenal[1]+2; +/********************************/ +gop=(CL->gop)*SCORE_K; +gep=(CL->gep)*SCORE_K; +maximise=CL->maximise; +scale=(lenal[1]*SCORE_K*(CL->moca)->moca_scale); +/*******************************/ + + + +/*DO MEMORY ALLOCATION FOR DP*/ + + + + + + buf_trace=vcalloc ( len, sizeof (TRACE_TYPE)); + buffer=vcalloc ( 2*len, sizeof (char)); + + al =declare_int (2, 2*len); + pos_al=declare_int (2, 2*len); + result_aln=declare_int (1,len); + char_buf= vcalloc (2*len, sizeof (char)); + + f =vcalloc (len, sizeof (int)); + pf =vcalloc (len, sizeof (int)); + e =vcalloc (len, sizeof (int)); + pe =vcalloc (len, sizeof (int)); + e_len =vcalloc (len, sizeof (int)); + pe_len =vcalloc (len, sizeof (int)); + dd =vcalloc (len, sizeof (int)); + dd_len=vcalloc (len, sizeof (int)); + + + trace=declare_int (lenal[0]+2, lenal[1]+2); + +/*END OF MEMORY ALLOCATION*/ + + + /* + 0(s) +(dd) + \ | + \ | + \ | + \ | + \ | + \ | + \| + -(e)----O + */ + + pos0=aln2pos_simple ( A,-1, ns, l_s); + + for ( i=0; i<=lenal[0]+1; i++) + { + tr=trace[i]; + + + for ( sub=0,j=0; j<=lenal[1]; j++) + { + if (i==0 && j==0){tr[j]=1;pe[j]=dd[j]=gop;} + else if (i==0) {e[j]=pe[j]=dd[j]=gop;dd_len[j]=e_len[j]=pe_len[j]=f[j]=pf[j]=0;tr[j]=-1;} + else if (j==0) + { + for (f[j]=pf[0],best_j=0,a=1; a<=lenal[1]; a++) + { + if (f[j]!=MAX(pf[a]+scale,f[j])) + { + f[j]=pf[a]+scale; + best_j=a; + } + } + + + dd [j]=e[j]=pe[j]=gop; + dd_len[j]=e_len[j]=0; + tr [j]=best_j; + + } + else if (i>lenal[0]); + else + { + sub=(CL->get_dp_cost) (A, pos0, ns[0], l_s[0], i-1, pos0, ns[1], l_s[1],j-1,CL); + + + + match=pf[j-1]+sub; + if (a_better_than_b(pf[j]+gop, pe[j]+gep,maximise)) + { + e [j]=pf[j]+gop; + e_len[j]=1; + } + else + { + e [j]=pe [j]+gep; + e_len[j]=pe_len[j]+1; + } + + + if (a_better_than_b(f[j-1]+gop, dd[j-1]+gep,maximise)) + { + dd [j]=f[j-1]+gop; + dd_len[j]=1; + } + else + { + dd [j]=dd [j-1]+gep; + dd_len[j]=dd_len[j-1]+1 ; + } + + + + if ( sub!=UNDEFINED) + { + + f[j] =best_int(4,maximise,&fop,e[j],match,dd[j],f[0]); + fop-=1; + + if (fop==-1)fop= e_len[j]*fop; + else if (fop==1 )fop=dd_len[j]*fop; + else if (fop==2 )fop=UNDEFINED; + + + + } + else + { + dd[j]=e[j]=match=-10000; + f[j]=f[0]; + fop=UNDEFINED; + } + pe [j] =e [j]; + pf [j-1]=f [j-1]; + pe_len[j] =e_len[j]; + tr[j] =fop; + } + + } + + pf [j-1]=f [j-1]; + pe [j] =e [j]; + pe_len[j] =e_len[j]; + } + score=f[0]; + i=lenal[0]+1; + j=0; + ala=0; + + + while (i!=0) + { + + + k=trace[i][j]; + if (j==0 && i<=lenal[0]) + { + + pos_al[0][ala]=i; + pos_al[1][ala]=j; + al[0][ala]=MATCH; + al[1][ala]=UNALIGNED; + i--; + j=k; + ala++; + } + else if ( j==0 && i>lenal[0]) + { + j=k; + i--; + + } + else if (k==0) + { + pos_al[0][ala]=i; + pos_al[1][ala]=j; + al[0][ala]=MATCH; + al[1][ala]=MATCH; + i--; + j--; + + ala++; + } + else if (k!=UNDEFINED && k<0 && i>0) + { + for (x=0; x< -k && i>0; x++) + { + pos_al[0][ala]=i; + pos_al[1][ala]=j; + al[0][ala]=MATCH; + al[1][ala]=GAP; + i--; + ala++; + } + } + else if (k!=UNDEFINED && k>0 && j>0) + { + for ( x=0; x< k && j>0; x++) + { + pos_al[0][ala]=i; + pos_al[1][ala]=j; + al[0][ala]=GAP; + al[1][ala]=MATCH; + j--; + ala++; + } + } + else if ( k==UNDEFINED){j=0;} + + } + + + LEN=ala; + + invert_list_int ( pos_al[0], LEN); + invert_list_int ( pos_al[1], LEN); + invert_list_int ( al[0], LEN); + invert_list_int ( al[1], LEN); + + + /*O: TARGET SEQUENCE (long)*/ + /*1: PATTERN SEQUENCE (short)*/ + + + + for ( b=0; b0) + { + result_aln=realloc_int ( result_aln, read_size_int ( result_aln,sizeof (int*)),len, 1, 0); + nseq++; + l=0; + for ( b=0; b0)nseq++; + + + + + A=domain_match_list2aln ( A,ns,l_s,result_aln,nseq,lenal[1]); + + + vfree (f); + vfree (pf); + vfree (e); + vfree (pe); + vfree (e_len); + vfree (pe_len); + vfree (dd_len); + vfree (dd); + free_int (pos0, -1); + vfree (buffer); + vfree (char_buf); + vfree (buf_trace); + free_int ( pos_al, -1); + pos_al=NULL; + + free_int ( al, -1); + + free_int (trace,-1); + free_int ( result_aln, -1); + return score; + } + + +Alignment *domain_match_list2aln ( Alignment *A,int *ns,int **l_s,int **ml, int nseq, int len) + { + + /* + function documentation: start + + This function edits the alignment given the results obtained by DP + ns: ns[0]->number of sequences serarched (TARGET) + ns[1]->number of sequences in the pattern (PATTERN SEQ) + l_s: + l_s[0]->list of sequences in the TARGET... + + nseq: number of occurences of PATTERN in TARGET + len: length of the PATTERN + + ml: detail of the nseq matches + ml[x][y]=k-> residue k of TARGET matches residue y of pattern + -> k=-1 means a gap; + + NOTE: This implementation can only match ONE target sequence with the PATTERN + The Pattern can either be one sequence or a profile. + + function documentation: end + */ + + + + + int a, b, c, d, e; + Alignment *B=NULL; + int **new_ml; + int *max_ml; + int *start_ml; + int tot_nseq; + int max_len,seq; + char *buf; + + if ( len==0 || nseq==0) + { + A->nseq=0; + A->len_aln=0; + } + else + { + B=copy_aln(A, B); + /*1 Extract the sequence used as a pattern, put it on the top*/ + + + A=shrink_aln (A, ns[1], l_s[1]); + A=realloc_aln2(A, ns[1]+ns[0]*nseq,len+A->len_aln+1); + + + + new_ml =declare_int ( nseq, 3*len); + max_ml =vcalloc ( nseq, sizeof (int)); + for ( a=0; a=0) + { + new_ml[c][b]=ml[c][a]; + if ( max_ml[c]<0) start_ml[c]=max_ml[c]=ml[c][a]; + for ( d=a+1; d=0){ max_ml[c]= ml[c][d];break;}} + if (max_ml[c]!=new_ml[c][b]) + { + new_ml[c][b+1]=max_ml[c]-new_ml[c][b]-1; + } + max_len=MAX( max_len, new_ml[c][b+1]); + } + else + { + new_ml[c][b]=ml[c][a]; + new_ml[c][b+1]=0; + } + } + + for ( c=0; c< nseq; c++){new_ml[c][b+2]=max_len;} + } + + tot_nseq=ns[1]+ns[0]*nseq; + + for ( a=0, b=0; a< len ;a++) + { + + /*1: Place the Match Column*/ + for ( c=0; c< ns[1]; c++) + { + A->seq_al[c][b]=B->seq_al[l_s[1][c]][a]; + A->seq_al[c][b+1]='\0'; + } + for ( e=0,c=ns[1]; cseq_al[c+d][b]=B->seq_al[l_s[0][d]][new_ml[e][3*a]]; + else + A->seq_al[c+d][b]='-'; + A->seq_al[c+d][b+1]='\0'; + + } + b++; + + /*2: Add the Gaps before the next_column*/ + if ( new_ml[0][3*a+2]>0) + { + for ( c=0; c< ns[1]; c++) + { + buf=generate_null(new_ml[0][3*a+2]); + strcat ( A->seq_al[c],buf); + vfree (buf); + } + for (e=0,c=ns[1];c< tot_nseq; c+=ns[0], e++) + { + buf=extract_char (B->seq_al[l_s[0][0]], new_ml[e][3*a]+1, new_ml[e][3*a+1]); + strcat ( A->seq_al[c],buf); + vfree (buf); + buf=generate_null(new_ml[e][3*a+2]-new_ml[e][3*a+1]); + strcat ( A->seq_al[c],buf); + + vfree (buf); + + } + } + b+=new_ml[0][3*a+2]; + } + + for (e=0,a=ns[1]; a< tot_nseq; a+=ns[0],e++) + { + for ( b=0; border[a+b][0]=B->order[seq][0]; + A->order[a+b][1]=B->order[seq][1]; + for ( c=0; corder[a+b][1]+=!is_gap(B->seq_al[seq][c]); + sprintf ( A->name[a+b], "Repeat_%d", a+b); + } + } + + free_aln(B); + A->nseq=tot_nseq; + A->len_aln=strlen ( A->seq_al[0]); + + } + return A; + } +Alignment * domain_seq2domain (Constraint_list *CL,int scale,int gop,int gep,Alignment *SEQ_DOMAIN, Alignment *TARGET) + { + static Alignment *A; + int *n_groups; + int **group_list; + int a,b,c; + + A=copy_aln (TARGET, A); + A=stack_aln( A, SEQ_DOMAIN); + + + n_groups=vcalloc ( 2, sizeof (int)); + group_list=declare_int (2, A->nseq); + + n_groups[0]=TARGET->nseq; + n_groups[1]=SEQ_DOMAIN->nseq; + for (c=0, a=0; a< 2; a++) + { + for (b=0; b< n_groups[a]; b++, c++) + { + group_list[a][b]=c; + } + } + A->score_aln=domain_pair_wise (A, n_groups, group_list,CL); + + SEQ_DOMAIN=copy_aln (A, SEQ_DOMAIN); + vfree (n_groups); + free_int (group_list,-1); + return SEQ_DOMAIN; + } + + +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/util_domain_dp_drivers.c b/binaries/src/tcoffee/t_coffee_source/util_domain_dp_drivers.c new file mode 100644 index 0000000..972eb3c --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/util_domain_dp_drivers.c @@ -0,0 +1,681 @@ +#include +#include +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" +#include "dp_lib_header.h" + +/******************************************************************/ +/* MOCA DRIVER */ +/* */ +/* */ +/******************************************************************/ +Constraint_list *prepare_cl_for_moca ( Constraint_list *CL) + { + int a, b, c; + int tot_l, l; + char **name, **seq; + Sequence *NS=NULL; + + /*Prepare the constraint list*/ + CL->do_self=1; + CL->get_dp_cost=moca_slow_get_dp_cost; + CL->evaluate_residue_pair=moca_residue_pair_extended_list; + + /*Prepare the moca parameters*/ + (CL->moca)->evaluate_domain=evaluate_moca_domain; + (CL->moca)->cache_cl_with_domain=cache_cl_with_moca_domain; + (CL->moca)->make_nol_aln=make_moca_nol_aln; + + /*Prepare the packing of the sequences*/ + for ( a=0, b=1; a< (CL->S)->nseq; a++)b+=strlen ( (CL->S)->seq[a])+1; + + seq =declare_char ( 1,b+1); + name=declare_char( 1,30); + CL->packed_seq_lu =declare_int ( b, 2); + + + for (tot_l=1,a=0; a< (CL->S)->nseq; a++) + { + strcat (seq[0], (CL->S)->seq[a]); + strcat (seq[0], "X"); + l=strlen((CL->S)->seq[a]); + for ( c=1; c<= l; c++, tot_l++) + { + CL->packed_seq_lu[tot_l][0]=a; + CL->packed_seq_lu[tot_l][1]=c; + } + CL->packed_seq_lu[tot_l++][0]=UNDEFINED; + } + sprintf ( name[0], "catseq"); + NS=fill_sequence_struc(1, seq, name); + CL->S=add_sequence (NS, CL->S, 0); + free_char( seq, -1); + free_char(name, -1); + free_sequence (NS, NS->nseq); + + + return CL; + } + +Alignment ** moca_aln ( Constraint_list *CL) + { + /* + function documentation: start + + Alignment ** moca_aln ( Constraint_list *CL) + + This function inputs CL and outputs a series of local multiple alignments + contained in aln_list; + + The terminator of aln_list is set to NULL; + + function documentation: end + */ + + + static int max_n_domains=1000; + int n_domains=0; + + Alignment **aln_list; + + + + aln_list=vcalloc (max_n_domains, sizeof (Alignment *)); + if ((CL->moca)->moca_interactive)aln_list[n_domains++]=extract_domain ( CL); + else + { + while ( (aln_list[n_domains++]=extract_domain ( CL))!=NULL) + { + if ((CL->moca)->moca_len)break; + if ( n_domains==max_n_domains) + { + n_domains+=1000; + aln_list=vrealloc (aln_list, max_n_domains*sizeof (Alignment*)); + } + } + } + return aln_list; + } + +Alignment * extract_domain ( Constraint_list *CL) + { + /* + function documentation: start + Alignment * extract_domain ( Constraint_list *CL) + + given a CL, this function extracts the next best scoring local multiple alignment + It returns a CL where the aligned residues have been indicated in (CL->moca)->forbiden_residues; + + the local alignment is extracted with the dp function indicated by + CL->dp_mode: (gotoh_sw_pair_wise) + Evaluation: + CL->get_dp_cost=slow_get_dp_cost; + CL->evaluate_residue_pair=sw_residue_pair_extended_list; + Continuation: + (CL->moca)->evaluate_domain=evaluate_moca_domain; + Cache of CL: + (CL->moca)->cache_cl_with_domain=cache_cl_with_moca_domain; + Domain post processing: + (CL->moca)->make_nol_aln=make_moca_nol_aln; + function documentation: end + */ + int min_start, max_start, start,min_len, max_len, len, score; + int step; + Alignment *C=NULL; + Alignment *RESULT=NULL; + Alignment *EA=NULL; + + + + + /*CASE 1: Non Automatic Domain Extraction*/ + if ((CL->moca)->moca_interactive) + { + return interactive_domain_extraction (CL); + } + else if ((CL->moca)->moca_len) + { + while ((C=extract_domain_with_coordinates (C,(CL->moca)->moca_start,(CL->moca)->moca_len,CL))->nseq==0)(CL->moca)->moca_scale=(CL->moca)->moca_scale*0.9; + RESULT=copy_aln ( C, RESULT); + unpack_seq_aln (RESULT, CL); + output_format_aln ("mocca_aln",RESULT,EA=fast_coffee_evaluate_output(RESULT, CL),"stdout"); + free_aln(EA); + + return RESULT; + } + else if ( !(CL->moca)->moca_len) + { + analyse_sequence (CL); + myexit (EXIT_FAILURE); + } + + /*CASE 2: Automatic Domain Extraction: Find Coordinates*/ + + + start=500; + + step=10; + min_start=0; + max_start=strlen ((CL->S)->seq[0]); + min_len=20; + max_len=strlen ((CL->S)->seq[0]); + + C=extract_domain_with_coordinates (C,13,30,CL); + C->output_res_num=1; + print_aln (C); + + (CL->moca)->moca_scale=-180; + C=add_seq2aln (CL,C, CL->S); + print_aln (C); + + (CL->moca)->moca_scale=-160; + C=add_seq2aln (CL,C, CL->S); + print_aln (C); + + myexit (EXIT_FAILURE); + + while ( step>0) + { + C=approximate_domain (min_start,max_start,step,min_len,max_len, step,&start, &len, &score, CL); + min_start=start-step; + max_start=start+step; + min_len=len-step; + max_len=len+step; + step=step/2; + } + + C=extract_domain_with_coordinates (C,start-10, len+20,CL); + C->output_res_num=1; + print_aln (C); + + myexit (EXIT_FAILURE); + return C; + + + } +Alignment * interactive_domain_extraction ( Constraint_list *CL) + { + int LEN=0; + int START=1; + int SCALE=2; + int GOPP=3; + + int iteration=0; + char *choice; + int a,b, c; + int index; + char *s; + char last_start[100]; + char out_format[100]; + Alignment *RESULT=NULL; + Alignment *PREVIOUS=NULL; + Alignment *C=NULL; + Alignment *EA=NULL; + + int **parameters; + + + choice=vcalloc ( 100, sizeof (char)); + parameters=declare_int (10000, 4); + + parameters[0][START]=(CL->moca)->moca_start; + parameters[0][LEN]= (CL->moca)->moca_len; + parameters[0][SCALE]=(CL->moca)->moca_scale; + parameters[0][GOPP]=CL->gop; + iteration=0; + sprintf ( last_start, "%d", (CL->moca)->moca_start); + sprintf ( out_format, "mocca_aln"); + + print_moca_interactive_choices (); + while ( !strm4 (choice, "Q","X", "q", "x" )) + { + c=choice[0]; + + if (c=='b' || c=='B') + { + iteration-=atoi(choice+1)+1; + + if (iteration<0)iteration=1; + } + else + { + iteration++; + parameters[iteration][START]=parameters[iteration-1][START]; + parameters[iteration][LEN]=parameters[iteration-1][LEN]; + parameters[iteration][SCALE]=parameters[iteration-1][SCALE]; + parameters[iteration][GOPP]=parameters[iteration-1][GOPP]; + + if ( c=='>')parameters[iteration][LEN]=atoi(choice+1); + else if ( c=='|') + { + sprintf ( last_start, "%s", choice); + parameters[iteration][START]=0; + s=strrchr(choice, ':'); + + if (s==NULL) + { + parameters[iteration][START]=atoi(choice+1); + } + else + { + + s[0]='\0'; + + if((index=name_is_in_list (choice+1,(CL->S)->name,(CL->S)->nseq,100))==-1) + { + fprintf ( stderr, "\n\tERROR: %s NOT in Sequence Set",choice+1); + continue; + } + + for ( a=0; a< index; a++) + { + parameters[iteration][START]+=(CL->S)->len[a]+1; + } + parameters[iteration][START]+=atoi(s+1)-1; + } + + } + else if ( c=='C'||c=='c')parameters[iteration][SCALE]=atoi(choice+1); + else if ( c=='G'||c=='g') + { + parameters[iteration][GOPP]=atoi(choice+1); + CL->gop=parameters[iteration][GOPP]; + } + else if ( c=='F'||c=='f') + { + sprintf ( out_format, "%s", choice+1); + } + else if ( c=='S'||c=='s') + { + if (choice[1]=='\0')sprintf ( choice, "default.domain_aln.%d", iteration); + output_format_aln (out_format,RESULT,EA=fast_coffee_evaluate_output(RESULT, CL),choice+1); + fprintf (stderr, "\tOutput file [%15s] in [%10s] format\n",choice+1,out_format); + free_aln (EA); + } + else if (c=='\0') + { + if ( parameters[iteration][SCALE]>0) + { + fprintf ( stderr, "\nWARNING: THRESHOLD RESET to 0"); + parameters[iteration][SCALE]=0; + } + + (CL->moca)->moca_scale=parameters[iteration][SCALE]; + CL->gop=parameters[iteration][GOPP]; + + C=extract_domain_with_coordinates (C,parameters[iteration][START],parameters[iteration][LEN],CL); + + if ( C==NULL) + { + fprintf ( stderr, "\nERROR: ILLEGAL COORDINATES! SEQUENCE BOUNDARY CROSSED\n"); + for ( b=1,a=0; a< (CL->S)->nseq-1; a++) + { + + fprintf ( stderr, "\n\t%15s=> Abs:[%d %d] Rel:[0 %d]", (CL->S)->name[a],b, b+(CL->S)->len[a]-1,(CL->S)->len[a]); + b+=(CL->S)->len[a]; + } + fprintf ( stderr, "\n"); + } + else if (parameters[iteration][START]==0 && parameters[iteration][LEN]==0) + { + fprintf ( stderr, "\n\tEnter the following parameters:\n\n\t\tSTART value: |x [Return]\n\t\tLENgth value: >y [Return]\n\t\ttype [Return]\n\n"); + fprintf ( stderr, "\n\n\tSTART is measured on the total length of the concatenated sequences\n\tx and y are positive integers\n\n"); + } + + else if ( C->nseq==0) + { + fprintf ( stderr, "\nNO MATCH FOUND: LOWER THE SCALE (C)\n"); + } + else + { + RESULT=copy_aln ( C, RESULT); + unpack_seq_aln (RESULT, CL); + RESULT->output_res_num=1; + + output_format_aln (out_format,RESULT,EA=fast_coffee_evaluate_output(RESULT, CL),"stdout"); + free_aln(EA); + PREVIOUS=copy_aln ( RESULT, PREVIOUS); + free_aln (C); + print_moca_interactive_choices (); + + } + } + + fprintf ( stderr, "\t[ITERATION %3d][START=%s][LEN=%3d][GOPP=%3d][SCALE=%4d]\t",iteration,last_start,parameters[iteration][LEN],parameters[iteration][GOPP],parameters[iteration][SCALE]); + a=0; + fprintf ( stderr, "Your Choice: "); + while ( (c=fgetc(stdin))!='\n')choice[a++]=c; + choice[a]=0; + } + } + + if (!RESULT)myexit(EXIT_SUCCESS); + if ( RESULT)RESULT->output_res_num=0; + return RESULT; + } + +int print_moca_interactive_choices () +{ + fprintf ( stderr, "\n**************************************************************"); + fprintf ( stderr, "\n******************** MOCCA: %s ***********",VERSION); + fprintf ( stderr, "\n**************************************************************"); + + +fprintf ( stderr, "\nMENU: Type Flag[number] and Return: ex |10"); + +fprintf ( stderr, "\n\t|x -->Set the START to x"); +fprintf ( stderr, "\n\t 100 start=100 on concatenated sequences"); +fprintf ( stderr, "\n\t human:100 start=100 on human sequence"); +fprintf ( stderr, "\n\t>x -->Set the LEN to x"); +fprintf ( stderr, "\n\tGx -->Set the Gap Opening Penalty to x"); +fprintf ( stderr, "\n\tCx -->Set the sCale to x"); +fprintf ( stderr, "\n\tSname -->Save the Alignment "); +fprintf ( stderr, "\n\tFformat -->Save the Alignment Format"); + +fprintf ( stderr, "\n\treturn -->Compute the Alignment"); + +fprintf ( stderr, "\n\tX -->eXit\n\n"); + +return 0; +} + +Alignment * approximate_domain ( int min_start, int max_start, int step_start,int min_len, int max_len, int step_len, int *best_start, int *best_len, int *best_score, Constraint_list *CL) + { + Alignment *C=NULL; + int start; + int len; + int score; + + /*1 Extract the first*/ + best_score[0]=UNDEFINED; + best_start[0]=min_start; + best_len[0]=min_len; + + for (start=min_start; start< max_start; start+=step_start) + { + for ( len=min_len; lenmoca)->evaluate_domain)(C, CL); + fprintf ( stderr, "\nSTART=%d LEN=%3d SCORE=%5d [%d]",start,len,score, C->nseq); + + + if ( best_score[0]==UNDEFINED)best_score[0]=score; + if ( score>best_score[0]) + { + best_score[0]=score; + best_start[0]=start; + best_len[0]=len; + } + } + } + + C=extract_domain_with_coordinates (C,best_start[0], best_len[0],CL); + C->output_res_num=1; + return C; + } +int measure_domain_length ( Constraint_list *CL,Alignment *IN, int start, int min_len, int max_len, int step) + { + Alignment *C=NULL; + int score, best_score,best_len,a, b, l; + int *score_matrix, *len_matrix; + int n_val, best_val; + + score_matrix=vcalloc ( max_len, sizeof (int)); + len_matrix=vcalloc ( max_len, sizeof (int)); + + + l=strlen ( (CL->S)->seq[0]); + + min_len=MAX(0, min_len); + min_len=MIN(l-start, min_len); + + if ( !IN)C=extract_domain_with_coordinates (C,start,min_len, CL); + else + { + C=copy_aln (IN, C); + C->len_aln=min_len; + for ( a=0; a< C->nseq; a++)C->seq_al[a][min_len]='\0'; + C=add_seq2aln (CL,C, CL->S); + } + + best_score= score=((CL->moca)->evaluate_domain)(C, CL); + + + min_len=MAX(0, min_len); + for ( best_len=best_val=n_val=0,b=min_len; blen_aln=min_len; + for ( a=0; a< C->nseq; a++)C->seq_al[a][b]='\0'; + C=add_seq2aln (CL,C, CL->S); + } + if ( C->len_aln>0 )score=((CL->moca)->evaluate_domain)(C, CL); + else score=-1; + + if ( score< -3000)break; + + fprintf ( stderr, "\n\t%d %d=>%d (%d, %d)[%d]",start, b, score, C->nseq, C->len_aln, step); + score_matrix[n_val]=score; + len_matrix [n_val]=b; + if ( score>best_score) + { + best_score=score; + best_len=b; + best_val=n_val; + } + } + free_aln(C); + + for ( a=best_val; abest_score/2)best_len=len_matrix[a]; + else break; + } + vfree ( score_matrix); + vfree ( len_matrix); + + return best_len; + } + +Alignment *extract_domain_with_coordinates ( Alignment *RESULT,int start, int len, Constraint_list *CL) +{ + int a; + char *buf; + Alignment *SEQ_DOMAIN=NULL; + + + + + + /*ADJUST THE DIRECTION OF THE DOMAIN: len<0:left and len>0:right*/ + + if (len>0); + else if (len<0) + { + len=len*-1; + start=start-len+1; + } + + /*CHECK THAT THE BOUNDARY CONDITIONS*/ + + + if (start<0 || (!CL->packed_seq_lu && (start+len)>strlen((CL->S)->seq[0])) ||(CL->packed_seq_lu && (start+len)>strlen((CL->S)->seq[(CL->S)->nseq-1])) )return NULL; + else + { + for ( a=start; a< start+len; a++) + { + if ((CL->moca)->forbiden_residues && (CL->moca)->forbiden_residues[0][a+1]==UNDEFINED) + { + fprintf ( stderr, "*"); + return NULL; + } + } + } + + /*EXTRACT THE DOMAIN*/ + + SEQ_DOMAIN=add_seq2aln (CL,SEQ_DOMAIN, CL->S); + buf=extract_char (SEQ_DOMAIN->seq_al[0], start, len); + + for (a=0; aseq_al[0], "%s", buf); + SEQ_DOMAIN->order[0][1]=start; + SEQ_DOMAIN=add_seq2aln (CL,SEQ_DOMAIN, CL->S); + + + + return SEQ_DOMAIN; +} + + + + +int get_starting_point ( Constraint_list *CL) +{ + int a; + + + int l; + + + + + + int **seq; + int start; + int *entry=NULL; + + l=strlen ( (CL->S)->seq[0]); + + seq=declare_int ( l, 2); + + + + while (entry=extract_entry (CL)) + { + seq[entry[R1]][1]=entry[R1]; + seq[entry[R2]][1]=entry[R2]; + if ((CL->moca) && (CL->moca)->forbiden_residues && ((CL->moca)->forbiden_residues[0][entry[R1]]==UNDEFINED||(CL->moca)->forbiden_residues[0][entry[R2]]==UNDEFINED ))continue; + else + { + seq[entry[R1]][0]+=entry[MISC]; + seq[entry[R2]][0]+=entry[MISC]; + } + } + + sort_int_inv ( seq, 2, 0, 0, l-1); + fprintf ( stderr, "\nStart=%d %d", seq[0][1], seq[0][0]); + start=seq[0][1]; + + + free_int ( seq, -1); + return start; + + +} + + +int * analyse_sequence ( Constraint_list *CL) +{ + int a, p; + int len, start, n_dots; + int left, right, tw, r, w; + int best_tw, best_start=0, best_len=0; + int l; + int max_len=200; + + + l=strlen (( CL->S)->seq[0]); + + for ( best_tw=UNDEFINED,start=0; startresidue_index[0][p+start+1][0]; + + for ( a=1; aresidue_index[0][p+start+1][a+R2]; + w=CL->residue_index[0][p+start+1][a+WE]; + + if (rright)tw+=w; + } + } + + if ( tw> best_tw || best_tw==UNDEFINED) + { + best_tw=tw; + best_start=start; + best_len=len; + } + } + } + fprintf ( stderr, "\nStart=%d Len=%d", best_start, best_len); + return NULL; +} + +/*********************************COPYRIGHT NOTICE**********************************/ +/*© Centre National de la Recherche Scientifique (CNRS) */ +/*and */ +/*Cedric Notredame */ +/*Fri Aug 8 19:03:27 MDT 2003. */ +/*All rights reserved.*/ +/*NOTICE: |*/ +/* This file is an integral part of the */ +/* T-COFFEE Software. */ +/* Its content is protected and all */ +/* the conditions mentioned in the licensing */ +/* agreement of the software apply to this file.*/ +/*............................................... |*/ +/* If you need some more information, or if you */ +/* wish to obtain a full license, please contact: */ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/*********************************COPYRIGHT NOTICE**********************************/ +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/util_dp_cdna_fasta_nw.c b/binaries/src/tcoffee/t_coffee_source/util_dp_cdna_fasta_nw.c new file mode 100644 index 0000000..526a190 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/util_dp_cdna_fasta_nw.c @@ -0,0 +1,974 @@ +#include +#include +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" +#include "dp_lib_header.h" + + +int cfasta_cdna_pair_wise (Alignment *A,int*ns, int **l_s,Constraint_list *CL) + { + +/*TREATMENT OF THE TERMINAL GAP PENALTIES*/ +/*TG_MODE=0---> gop and gep*/ +/*TG_MODE=1---> --- gep*/ +/*TG_MODE=2---> --- ---*/ + int maximise; + +/*VARIABLES FOR THE MULTIPLE SEQUENCE ALIGNMENT*/ + int **tot_diag; + + int *diag; + int ktup; + static int n_groups; + static char **group_list; + int score, new_score; + int n_chosen_diag=0; + int step; + int max_n_chosen_diag; + int l0, l1; + Alignment *B; + /********Prepare Penalties******/ + + maximise=CL->maximise; + ktup=CL->ktup; + + /********************************/ + if ( !group_list) + { + + group_list=make_group_aa (&n_groups, CL->matrix_for_aa_group); + } + B=dna_aln2_3frame_cdna_aln(A, ns, l_s); + l0=strlen(B->seq_al[0]); + l1=strlen(B->seq_al[3]); + tot_diag=evaluate_diagonals_cdna ( B, ns, l_s, CL, maximise,n_groups,group_list, ktup); + + max_n_chosen_diag=100; + n_chosen_diag=step=10 ; + n_chosen_diag=MIN(n_chosen_diag, max_n_chosen_diag); + + + diag=extract_N_diag (l0,l1, tot_diag, n_chosen_diag,2); + score =make_fasta_cdna_pair_wise ( A,B, ns, l_s, CL, diag); + + + new_score=0; + vfree ( diag); + + while (new_score!=score && n_chosen_diag< max_n_chosen_diag ) + { + + score=new_score; + ungap_sub_aln ( A, ns[0], l_s[0]); + ungap_sub_aln ( A, ns[1], l_s[1]); + + + n_chosen_diag+=step; + n_chosen_diag=MIN(n_chosen_diag, max_n_chosen_diag); + + diag =extract_N_diag (l0,l1, tot_diag, n_chosen_diag,3); + new_score=make_fasta_cdna_pair_wise ( A, B,ns, l_s, CL, diag); + vfree ( diag); + } + + score=new_score; + free_int (tot_diag, -1); + free_aln(B); + return score; + } + + +int fasta_cdna_pair_wise (Alignment *A,int*ns, int **l_s,Constraint_list *CL) + { +/*TREATMENT OF THE TERMINAL GAP PENALTIES*/ +/*TG_MODE=0---> gop and gep*/ +/*TG_MODE=1---> --- gep*/ +/*TG_MODE=2---> --- ---*/ + + + int maximise; + int l0, l1; +/*VARIABLES FOR THE MULTIPLE SEQUENCE ALIGNMENT*/ + int **tot_diag; + int *diag; + int ktup; + static int n_groups; + static char **group_list; + int score; + Alignment *B; + + /********Prepare Penalties******/ + + + maximise=CL->maximise; + ktup=CL->ktup; + /********************************/ + + + + if ( !group_list) + { + + group_list=make_group_aa (&n_groups, CL->matrix_for_aa_group); + } + + B=dna_aln2_3frame_cdna_aln(A, ns, l_s); + B->nseq=6; + + l0=strlen ( B->seq_al[0]); + l1=strlen ( B->seq_al[3]); + + + tot_diag=evaluate_diagonals_cdna( B, ns, l_s, CL, maximise,n_groups,group_list, ktup); + + + diag=extract_N_diag (l0, l1, tot_diag,20,1); + score=make_fasta_cdna_pair_wise ( A,B, ns, l_s, CL, diag); + + free_aln(B); + free_int (tot_diag, -1); + vfree (diag); + return score; + } + +Dp_Model* initialize_dna_dp_model (Constraint_list *CL) + { + Dp_Model *M; + int a, b, c,d; + int f0, f1; + int deltaf1, deltaf0,deltatype; + int type, type1, type0; + + M=vcalloc ( 1, sizeof (Dp_Model)); + + for (M->nstate=0,f0=0; f0<3; f0++) + for ( f1=0; f1<3; f1++)M->nstate+=3; + + M->UM=M->nstate++; + M->START=M->nstate++; + M->END =M->nstate++; + + M->TG_MODE=CL->TG_MODE; + M->F_TG_MODE=0; + M->gop=CL->gop*SCORE_K; + M->gep=CL->gep*SCORE_K; + + + + M->f_gop=CL->f_gop*SCORE_K; + M->f_gep=CL->f_gep*SCORE_K; + + + M->bounded_model=declare_int (M->nstate+1, M->nstate+1); + M->model=declare_int (M->nstate+1, M->nstate+1); + for ( a=0; a<=M->nstate; a++) + for ( b=0; b<= M->nstate; b++) + M->model[a][b]=UNDEFINED; + M->model_properties=declare_int ( M->nstate, 10); + + a=0; + M->TYPE=a++;M->F0=a++;M->F1=a++; M->LEN_I=a++; M->LEN_J=a++; M->DELTA_I=a++;M->DELTA_J=a++;M->EMISSION=a++;M->TERM_EMISSION=a++; + a=M->nstate; + M->NON_CODING=a++; M->INSERTION=a++; M->DELETION=a++; M->CODING0=a++; M->CODING1=a++;M->CODING2=a++; + + + for ( a=0,f0=0; f0<3; f0++) + for ( f1=0; f1<3; f1++, a+=3) + { + M->model_properties[a+0][M->TYPE]=M->CODING0; + M->model_properties[a+0][M->F0]=f0; + M->model_properties[a+0][M->F1]=f1; + M->model_properties[a+0][M->LEN_I]=1; + M->model_properties[a+0][M->LEN_J]=1; + M->model_properties[a+0][M->DELTA_I]=-1; + M->model_properties[a+0][M->DELTA_J]= 0; + M->model_properties[a+0][M->EMISSION]=0; + M->model_properties[a+0][M->TERM_EMISSION]=0; + + M->model_properties[a+1][M->TYPE]=M->DELETION; + M->model_properties[a+1][M->F0]=f0; + M->model_properties[a+1][M->F1]=f1; + M->model_properties[a+1][M->LEN_I]=1; + M->model_properties[a+1][M->LEN_J]=0; + M->model_properties[a+1][M->DELTA_I]=-1; + M->model_properties[a+1][M->DELTA_J]=+1; + M->model_properties[a+1][M->EMISSION]=M->gep; + M->model_properties[a+1][M->TERM_EMISSION]=(M->TG_MODE==2)?0:M->gep; + + M->model_properties[a+2][M->TYPE]=M->INSERTION; + M->model_properties[a+2][M->F0]=f0; + M->model_properties[a+2][M->F1]=f1; + M->model_properties[a+2][M->LEN_I]=0; + M->model_properties[a+2][M->LEN_J]=1; + M->model_properties[a+2][M->DELTA_I]= 0; + M->model_properties[a+2][M->DELTA_J]=-1; + M->model_properties[a+2][M->EMISSION]=M->gep; + M->model_properties[a+2][M->TERM_EMISSION]=(M->TG_MODE==2)?0:M->gep; + } + + /*UM" Unmatched State*/ + M->model_properties[a][M->TYPE]=M->NON_CODING; + M->model_properties[a][M->F0]=0; + M->model_properties[a][M->F1]=0; + M->model_properties[a][M->LEN_I]=1; + M->model_properties[a][M->LEN_J]=1; + M->model_properties[a][M->DELTA_I]=-1; + M->model_properties[a][M->DELTA_J]=0; + M->model_properties[a][M->EMISSION]=M->f_gep; + M->model_properties[a][M->TERM_EMISSION]=(M->F_TG_MODE==2)?0:M->f_gep; + + + M->model_properties[M->START][M->TYPE]=M->NON_CODING; + M->model_properties[a+1][M->F0]=0; + M->model_properties[a+1][M->F1]=0; + M->model_properties[a+1][M->LEN_I]=0; + M->model_properties[a+1][M->LEN_J]=0; + M->model_properties[a+1][M->DELTA_I]=0 ; + M->model_properties[a+1][M->DELTA_J]=0; + M->model_properties[a+1][M->EMISSION]=0; + M->model_properties[a+1][M->TERM_EMISSION]=0; + + M->model_properties[M->END][M->TYPE]=M->NON_CODING; + M->model_properties[a+2][M->F0]=0; + M->model_properties[a+2][M->F1]=0; + M->model_properties[a+2][M->LEN_I]=0; + M->model_properties[a+2][M->LEN_J]=0; + M->model_properties[a+2][M->DELTA_I]=0 ; + M->model_properties[a+2][M->DELTA_J]=0; + M->model_properties[a+2][M->EMISSION]=0; + M->model_properties[a+2][M->TERM_EMISSION]=0; + + /*1: SET THE INDEL PENALTIES*/ + + + for ( a=0; a< M->START; a++) + { + deltaf0=M->model_properties[M->START][M->F0]-M->model_properties[a][M->F0]; + deltaf1=M->model_properties[M->START][M->F1]-M->model_properties[a][M->F1]; + if ( deltaf0==0 && deltaf1==0)deltatype=0; + else if ( deltaf0<=0 && deltaf1<=0)deltatype=1; + else deltatype=-1; + type=M->model_properties[a][M->TYPE]; + + if ( type==M->NON_CODING) M->model[a][M->END]=M->model[M->START][a]=(M->F_TG_MODE==0)?M->f_gop:0; + else if ( type==M->CODING0 && deltatype==0)M->model[a][M->END]=M->model[M->START][a]=ALLOWED; + else if ( type==M->CODING0 && deltatype==1)M->model[a][M->END]=M->model[M->START][a]=(M->F_TG_MODE==0)?M->f_gop:0; + else if ( type==M->INSERTION && deltatype==0)M->model[a][M->END]=M->model[M->START][a]=(M->TG_MODE==0)?M->gop:0; + else if ( type==M->INSERTION && deltatype==1)M->model[a][M->END]=M->model[M->START][a]=(M->TG_MODE==0)?M->gop:0+(M->F_TG_MODE==0)?M->f_gop:0; + else if ( type==M->DELETION && deltatype==0)M->model[a][M->END]=M->model[M->START][a]=(M->TG_MODE==0)?M->gop:0; + else if ( type==M->DELETION && deltatype==1)M->model[a][M->END]=M->model[M->START][a]=(M->TG_MODE==0)?M->gop:0+(M->F_TG_MODE==0)?M->f_gop:0; + else M->model[a][M->END]=M->model[M->START][a]=UNDEFINED; + + /* + if (type==M->NON_CODING ||M->model_properties[a][M->F0] ||M->model_properties[a][M->F1]) M->model[M->START][a]=M->model[a][M->END]=(M->F_TG_MODE==0)?M->f_gop:0; + else if (type==M->INSERTION || type==M->DELETION)M->model[M->START][a]=M->model[a][M->END]=( M->TG_MODE==0)?M->gop:0; + else M->model[M->START][a]=M->model[a][M->END]=ALLOWED; + */ + + for ( b=0; b< M->START; b++) + { + + deltaf0=M->model_properties[a][M->F0]-M->model_properties[b][M->F0]; + deltaf1=M->model_properties[a][M->F1]-M->model_properties[b][M->F1]; + type0=M->model_properties[a][M->TYPE]; + type1=M->model_properties[b][M->TYPE]; + + if ( deltaf0==0 && deltaf1==0)deltatype=0; + else if ( deltaf0<=0 && deltaf1<=0)deltatype=1; + else deltatype=-1; + + + + if ( type0==M->NON_CODING && type1==M->NON_CODING )M->model[a][b]=UNDEFINED; + else if ( type0==M->NON_CODING && type1==M->CODING0 )M->model[a][b]=ALLOWED ; + else if ( type0==M->NON_CODING && type1==M->INSERTION )M->model[a][b]=M->gop; + else if ( type0==M->NON_CODING && type1==M->DELETION )M->model[a][b]=M->gop; + + else if ( type0==M->CODING0 && type1==M->NON_CODING )M->model[a][b]=M->f_gop; + else if ( type0==M->CODING0 && type1==M->CODING0 && deltatype==0 )M->model[a][b]=ALLOWED; + else if ( type0==M->CODING0 && type1==M->CODING0 && deltatype==1 )M->model[a][b]=M->f_gop; + else if ( type0==M->CODING0 && type1==M->INSERTION && deltatype==0 )M->model[a][b]=M->gop; + else if ( type0==M->CODING0 && type1==M->INSERTION && deltatype==1 )M->model[a][b]=M->gop+M->f_gop; + else if ( type0==M->CODING0 && type1==M->DELETION && deltatype==0 )M->model[a][b]=M->gop; + else if ( type0==M->CODING0 && type1==M->DELETION && deltatype==1 )M->model[a][b]=M->gop+M->f_gop; + + else if ( type0==M->INSERTION && type1==M->NON_CODING )M->model[a][b]=M->f_gop; + else if ( type0==M->INSERTION && type1==M->CODING0 && deltatype==0 )M->model[a][b]=ALLOWED; + else if ( type0==M->INSERTION && type1==M->CODING0 && deltatype==1 )M->model[a][b]=M->f_gop; + else if ( type0==M->INSERTION && type1==M->INSERTION && deltatype==0 )M->model[a][b]=ALLOWED; + else if ( type0==M->INSERTION && type1==M->INSERTION && deltatype==1 )M->model[a][b]=M->f_gop; + else if ( type0==M->INSERTION && type1==M->DELETION && deltatype==0 )M->model[a][b]=M->gop; + else if ( type0==M->INSERTION && type1==M->DELETION && deltatype==1 )M->model[a][b]=M->gop+M->f_gop; + + else if ( type0==M->DELETION && type1==M->NON_CODING )M->model[a][b]=M->f_gop; + else if ( type0==M->DELETION && type1==M->CODING0 && deltatype==0 )M->model[a][b]=ALLOWED; + else if ( type0==M->DELETION && type1==M->CODING0 && deltatype==1 )M->model[a][b]=M->f_gop; + else if ( type0==M->DELETION && type1==M->INSERTION && deltatype==0 )M->model[a][b]=M->gop; + else if ( type0==M->DELETION && type1==M->INSERTION && deltatype==1 )M->model[a][b]=M->gop+M->f_gop; + else if ( type0==M->DELETION && type1==M->DELETION && deltatype==0 )M->model[a][b]=ALLOWED; + else if ( type0==M->DELETION && type1==M->DELETION && deltatype==1 )M->model[a][b]=M->f_gop; + + else {M->model[a][b]=UNDEFINED;} + + } + } + + + /*2 SET THE FRAMESHIFT PENALTIES + + for ( a=0; a< M->START; a++) + { + type=M->model_properties[a][M->TYPE]; + + for ( b=0; b< M->START; b++) + { + deltaf0=M->model_properties[a][M->F0]-M->model_properties[b][M->F0]; + deltaf1=M->model_properties[a][M->F1]-M->model_properties[b][M->F1]; + + + + + if (b==M->UM) M->model[a][b]+=M->f_gop; + else if (a==M->UM) M->model[a][b]+=ALLOWED; + else if (deltaf1==0 && deltaf0==0)M->model[a][b]+=ALLOWED; + else if (deltaf1<=0 && deltaf0<=0)M->model[a][b]+=M->f_gop; + else M->model[a][b]=UNDEFINED; + } + + } + M->model[M->UM][M->UM]=UNDEFINED; + */ + + + for (c=0,a=0, d=0; a< M->START; a++) + for ( b=0; bSTART; b++, d++) + { + if (M->model[a][b]!=UNDEFINED) + { + M->bounded_model[b][1+M->bounded_model[b][0]++]=a; + c++; + } + } + return M; + } +int make_fasta_cdna_pair_wise (Alignment *B,Alignment *A,int*in_ns, int **l_s,Constraint_list *CL, int *diag) + { + int a,c,p,k; + Dp_Result *DPR; + static Dp_Model *M; + int l0, l1; + int len_i, len_j; + int f0=0, f1=0; + int deltaf0, deltaf1, delta; + int nr1, nr2; + int ala, alb, aa0, aa1; + int type; + + char **al; + int **tl_s; + int *tns; + /*DEBUG*/ + int debug_cdna_fasta=0; + Alignment *DA; + int score; + int state,prev_state; + int t, e; + int a1, a2; + + + l0=strlen ( B->seq_al[l_s[0][0]]); + l1=strlen ( B->seq_al[l_s[1][0]]); + + al=declare_char (2, l0+l1+1); + B=realloc_aln2 (B,B->nseq,l0+l1+1); + + + free_int (B->cdna_cache, -1); + B->cdna_cache=declare_int(1, l0+l1+1); + + if ( !M)M=initialize_dna_dp_model (CL); + + + M->diag=diag; + + tl_s=declare_int (2, 2);tns=vcalloc(2, sizeof(int));tl_s[0][0]=0;tl_s[1][0]=3;tns[0]=tns[1]=1; + DPR=make_fast_dp_pair_wise (A,tns, tl_s,CL,M); + vfree(tns);free_int(tl_s, -1); + + + + /*new_trace_back*/ + a=p=0; + aa0=aa1=ala=alb=0; + while ( (k=DPR->traceback[a++])!=M->START); + while ( (k=DPR->traceback[a++])!=M->END) + { + + f0=M->model_properties[k][M->F0]; + f1=M->model_properties[k][M->F1]; + + len_i=M->model_properties[k][M->LEN_I]; + len_j=M->model_properties[k][M->LEN_J]; + + type=M->model_properties[k][M->TYPE]; + + + + if (type==M->CODING0) + { + deltaf0=(aa0*3+f0)-ala; + deltaf1=(aa1*3+f1)-alb; + + delta=MAX(deltaf0, deltaf1); + + for (nr1=0, nr2=0,c=0; cseq_al[l_s[0][0]][ala++]; + else al[0][p]='-'; + + if (nr2seq_al[l_s[1][0]][alb++]; + else al[1][p]='-'; + + B->cdna_cache[0][p]=M->NON_CODING; + if ( is_gap(al[1][p]) && is_gap(al[0][p]))p--; + else if ( debug_cdna_fasta)fprintf (stderr, "\nUM: %c %c", al[0][p], al[1][p]); + } + for ( c=0; c< 3; c++, p++) + { + if ( c==0)B->cdna_cache[0][p]=M->CODING0; + else if ( c==1)B->cdna_cache[0][p]=M->CODING1; + else if ( c==2)B->cdna_cache[0][p]=M->CODING2; + if (alaseq_al[l_s[0][0]][ala++]; + else al[0][p]='-'; + + if (albseq_al[l_s[1][0]][alb++]; + else al[1][p]='-'; + + if ( is_gap(al[1][p]) && is_gap(al[0][p]))p--; + else if ( debug_cdna_fasta)fprintf (stderr, "\n%d: %c %c",k, al[0][p], al[1][p]); + } + } + + aa0+=len_i; + aa1+=len_j; + } + + deltaf0=(aa0*3+f0)-ala; + deltaf1=(aa1*3+f1)-alb; + delta=MAX(deltaf0, deltaf1); + for (nr1=0, nr2=0,c=0; cseq_al[l_s[0][0]][ala++]; + else al[0][p]='-'; + + if (nr2seq_al[l_s[1][0]][alb++]; + else al[1][p]='-'; + + B->cdna_cache[0][p]=M->NON_CODING; + if ( is_gap(al[1][p]) && is_gap(al[0][p]))p--; + else if ( debug_cdna_fasta)fprintf (stderr, "\nUM: %c %c", al[0][p], al[1][p]); + } + + + /*End New traceback*/ + + + + + al[0][p]='\0'; + al[1][p]='\0'; + + + sprintf( B->seq_al[l_s[0][0]], "%s", al[0]); + sprintf( B->seq_al[l_s[1][0]], "%s", al[1]); + B->len_aln=strlen (al[0]); + B->nseq=2; + + + + + if ( debug_cdna_fasta) + { + fprintf ( stderr, "\nA-A=%d, %d", CL->M['a'-'A']['a'-'A'], CL->M['a'-'A']['a'-'A'] *SCORE_K); + for ( a=1; agop, M->gep, M->TG_MODE); + fprintf ( stderr, "\nF_GOP=%d F_GEP=%d F_TG_MODE=%d", M->gop, M->gep, M->F_TG_MODE); + + DA=copy_aln (B, NULL); + DA=realloc_aln2 (DA,6,(DA->len_aln+1)); + + + for ( a=0; alen_aln; a++) + { + + fprintf ( stderr, "\n%d", DA->cdna_cache[0][a]); + if (DA->cdna_cache[0][a]>=M->CODING0)DA->seq_al[DA->nseq][a]=DA->cdna_cache[0][a]-M->nstate+'0'; + else DA->seq_al[DA->nseq][a]=DA->cdna_cache[0][a]-M->nstate+'0'; + + if (DA->cdna_cache[0][a]==M->CODING0) + { + DA->seq_al[DA->nseq+1][a]=translate_dna_codon (DA->seq_al[0]+a,'*'); + DA->seq_al[DA->nseq+2][a]=translate_dna_codon (DA->seq_al[1]+a,'*'); + } + else + { + DA->seq_al[DA->nseq+1][a]='-'; + DA->seq_al[DA->nseq+2][a]='-'; + } + + } + DA->nseq+=3; + print_aln (DA); + + free_aln(DA); + score=0; + + + for (prev_state=M->START,a=0; a< DA->len_aln;) + { + state=DA->cdna_cache[0][a]; + t=M->model[prev_state][state]; + if ( DA->cdna_cache[0][a]==M->CODING0) + { + a1=translate_dna_codon (A->seq_al[0]+a,'x'); + a2=translate_dna_codon (A->seq_al[1]+a,'x'); + + if ( a1!='x' && a2!='x') + { + e=CL->M[a1-'A'][a2-'A']*SCORE_K; + } + } + else if ( DA->cdna_cache[0][a]>M->CODING0); + else + { + e=M->model_properties[B->cdna_cache[0][a]][M->EMISSION]; + } + if ( e==UNDEFINED || t==UNDEFINED) fprintf ( stderr, "\nPROBLEM %d\n", a); + + fprintf ( stderr, "\n[%c..%c: %d(e)+%d(t)=%d]", A->seq_al[0][a], A->seq_al[1][a], e,t,e+t); + score+=e+t; + prev_state=state; + + if (B->cdna_cache[0][a]==M->NON_CODING)a++; + else a+=3; + + } + + } + + for ( a=0; alen_aln; a++) + { + + if ( B->cdna_cache[0][a]CODING0)B->cdna_cache[0][a]=0; + else B->cdna_cache[0][a]=1; + } + + free_char ( al, -1); + return DPR->score; + + } + + + +Dp_Result * make_fast_dp_pair_wise (Alignment *A,int*ns, int **l_s, Constraint_list *CL,Dp_Model *M) + { + + /*SIZE VARIABLES*/ + + int ndiag; + int l0, l1, len_al,len_diag; + static int max_len_al, max_len_diag; + static int mI, mJ; + + + /*EVALUATION*/ + int **mat; + int a1, a2; + + /*DP VARIABLES*/ + static int *Mat, *LMat, *trace; + int a, i, j,l; + int state, cur_state, prev_state; + int pos_i, pos_j; + int last_i=0, last_j=0; + int prev_i, prev_j; + int len_i, len_j, len; + int t, e, em; + + int prev_score; + int pc, best_pc; + + int *prev; + int model_index; + /*TRACEBACK*/ + Dp_Result *DPR; + int k=0, next_k; + int new_i, new_j; + + + ndiag=M->diag[0]; + + l0=strlen (A->seq_al[l_s[0][0]]); + l1=strlen (A->seq_al[l_s[1][0]]); + len_al =l0+l1+1; + len_diag=ndiag+4; + + if ( (len_al>max_len_al || len_diag>max_len_diag)) + { + + vfree (Mat); + vfree (LMat); + vfree(trace); + max_len_diag=max_len_al=0; + } + + if (max_len_al==0) + { + max_len_al=len_al; + max_len_diag=len_diag; + mI=max_len_al*max_len_diag; + mJ=max_len_diag; + + + Mat =vcalloc ( M->nstate*max_len_al*max_len_diag, sizeof (int)); + LMat =vcalloc ( M->nstate*max_len_al*max_len_diag, sizeof (int)); + trace=vcalloc ( M->nstate*max_len_al*max_len_diag, sizeof (int)); + + } + + prev=vcalloc ( M->nstate, sizeof (int)); + DPR=vcalloc ( 1, sizeof ( Dp_Result)); + DPR->traceback=vcalloc (max_len_al, sizeof (int)); + +/*PREPARE THE EVALUATION*/ + if (ns[0]+ns[1]>2) + { + fprintf ( stderr, "\nERROR: function make_fasta_cdna_pair_wise can only handle two sequences at a time [FATAL:%s]",PROGRAM); + crash (""); + } + mat=CL->M; + +/*INITIALIZATION OF THE DP MATRICES*/ + + for (i=0; i<=l0;i++) + { + for (j=0; j<=ndiag;j++) + { + for ( state=0; statenstate; state++) + { + Mat [state*mI+i*mJ+j]=UNDEFINED; + LMat [state*mI+i*mJ+j]=UNDEFINED; + trace [state*mI+i*mJ+j]=M->START; + } + } + } + + M->diag[0]=0; + + for (i=0; i<=l0; i++) + for ( j=0; j<=ndiag; j++) + { + pos_j=M->diag[j]-l0+i; + pos_i=i; + if (!(pos_j==0 || pos_i==0))continue; + if ( pos_j<0 || pos_i<0)continue; + if ( pos_i==0 && pos_j==0) + { + for ( a=0; a< M->nstate; a++) + { + Mat [a*mI+i*mJ+j]=0; + LMat [a*mI+i*mJ+j]=0; + trace[a*mI+i*mJ+j]=M->START; + } + } + else + { + l=MAX(pos_i,pos_j); + for ( state=0; stateSTART; state++) + { + if (pos_j==0 && M->model_properties[state][M->LEN_J])continue; + if (pos_i==0 && M->model_properties[state][M->LEN_I])continue; + + + t=M->model[M->START][state]; + e=M->model_properties[state][M->TERM_EMISSION]; + Mat [state*mI+i*mJ+j]=t+e*l; + LMat [state*mI+i*mJ+j]=l; + trace [state*mI+i*mJ+j]=M->START; + } + } + } + +/*DYNAMIC PROGRAMMING: Forward Pass*/ + + + + for (i=1; i<=l0;i++) + { + for (j=1; j<=ndiag;j++) + { + pos_j=M->diag[j]-l0+i; + pos_i=i; + + if (pos_j<=0 || pos_j>l1 )continue; + last_i=i; + last_j=j; + + for (cur_state=0; cur_stateSTART; cur_state++) + { + if (M->model_properties[cur_state][M->DELTA_J]) + { + prev_j=j+M->model_properties[cur_state][M->DELTA_J]; + prev_i=i+M->model_properties[cur_state][M->DELTA_I]*FABS((M->diag[j]-M->diag[prev_j])); + } + else + { + prev_j=j; + prev_i=i+M->model_properties[cur_state][M->DELTA_I]; + } + len_i=FABS((i-prev_i)); + len_j=FABS((M->diag[prev_j]-M->diag[j])); + len=MAX(len_i, len_j); + a1=A->seq_al[M->model_properties[cur_state][M->F0] ][pos_i-1]; + a2=A->seq_al[M->model_properties[cur_state][M->F1]+3][pos_j-1]; + + if (M->model_properties[cur_state][M->TYPE]==M->CODING0) + { + if ( a1=='o' || a2=='o')em=-(mat['w'-'A']['w'-'A'])*SCORE_K; + else if (a1=='x' || a2=='x')em=UNDEFINED; + else if ( a1==0 || a2==0)exit (0); + else + { + em=(mat[a1-'A'][a2-'A'])*SCORE_K; + } + } + else + { + em=M->model_properties[cur_state][M->EMISSION]; + } + + + + for (pc=best_pc=UNDEFINED, model_index=1; model_index<=M->bounded_model[cur_state][0]; model_index++) + { + prev_state=M->bounded_model[cur_state][model_index]; + + if(prev_i<0 || prev_j<0 ||prev_i>l0 || prev_j>ndiag || len==UNDEFINED)prev_score=UNDEFINED; + else prev_score=Mat[prev_state*mI+prev_i*mJ+prev_j]; + t=M->model[prev_state][cur_state]; + e=em; + + if (prev_score==UNDEFINED || len==UNDEFINED)e=UNDEFINED; + else if (len==0|| e==UNDEFINED)e=UNDEFINED; + else e=e*len; + + if (is_defined_int(3,prev_score,e, t)) + { + pc=prev_score+t+e; + } + else pc=UNDEFINED; + + /*Identify the best previous score*/ + if (best_pc==UNDEFINED || (pc>best_pc && pc!=UNDEFINED)) + { + prev[cur_state]=prev_state; + best_pc=pc; + + } + } + + Mat[cur_state*mI+i*mJ+j]=best_pc; + + + + if ( Mat[cur_state*mI+i*mJ+j]==UNDEFINED) + { + LMat[cur_state*mI+i*mJ+j]=UNDEFINED; + trace[cur_state*mI+i*mJ+j]=UNDEFINED; + continue; + } + + else if ( prev[cur_state]==cur_state) + { + LMat [cur_state*mI+i*mJ+j]= LMat [cur_state*mI+prev_i*mJ+prev_j]+len; + trace[cur_state*mI+i*mJ+j]= trace[cur_state*mI+prev_i*mJ+prev_j]; + } + else + { + LMat[cur_state*mI+i*mJ+j]=len; + trace[cur_state*mI+i*mJ+j]=prev[cur_state]; + } + } + } + } + + + i=last_i; + j=last_j; + for (pc=best_pc=UNDEFINED, state=0; stateSTART; state++) + { + t=M->model[state][M->END]; + e=M->model_properties[state][M->TERM_EMISSION]; + l=LMat[state*mI+i*mJ+j]; + + + if (!is_defined_int(4,t,e,Mat[state*mI+i*mJ+j],l))Mat[state*mI+i*mJ+j]=UNDEFINED; + else Mat[state*mI+i*mJ+j]+=t+e*(l); + pc=Mat[state*mI+i*mJ+j]; + + + if (best_pc==UNDEFINED || (pc>best_pc && pc!=UNDEFINED)) + { + k=state; + best_pc=pc; + } + } + DPR->score=best_pc; + +/*TRACEBACK*/ + + + e=0; + len=0; + + + while (k!=M->START) + { + next_k=trace[k*mI+i*mJ+j]; + new_i=i; + new_j=j; + l=LMat[k*mI+i*mJ+j]; + + for (a=0; a< l; a++) + { + DPR->traceback[len++]=k; + } + new_i+=M->model_properties[k][M->DELTA_I]*l; + + + if ( M->model_properties[k][M->DELTA_J]) + { + while ( next_k!=M->START && FABS((M->diag[j]-M->diag[new_j]))!=l)new_j+=M->model_properties[k][M->DELTA_J]; + } + + i=new_i; + j=new_j; + k=next_k; + } + DPR->len=len; + DPR->traceback[DPR->len++]=M->START; + invert_list_int (DPR->traceback,DPR->len); + DPR->traceback[DPR->len]=M->END; + + vfree (prev); + + return DPR; + + + } + + + +int ** evaluate_diagonals_cdna ( Alignment *B, int *ns, int **l_s, Constraint_list *CL,int maximise,int n_groups, char **group_list, int ktup) + { + int f1, f2, c; + int **diag; + char *s1, *s2; + int p1, p2; + int **tot_diag; + int n_tot_diag; + int l0, l1; + + + + + + + if ( ns[0]!=1 || ns[1]!=1) + { + fprintf ( stderr, "\nERROR 2 SEQUENCES ONLY [FATAL:%s", PROGRAM); + crash (""); + } + + + + + + l0=strlen ( B->seq_al[0]); + l1=strlen ( B->seq_al[3]); + n_tot_diag=(l0+l1-1); + + tot_diag=declare_int ( n_tot_diag+1, 2); + for ( c=0; c<= n_tot_diag; c++)tot_diag[c][0]=c; + + for (f1=0; f1< 3; f1++) + { + for ( f2=0; f2< 3; f2++) + { + s1=B->seq_al[f1]; + s2=B->seq_al[3+f2]; + + + p1=strlen (s1); + p2=strlen (s2); + + + diag=evaluate_diagonals_for_two_sequences( s1, s2, maximise,NULL,ktup); + for (c=1; c<=(p1+p2-1); c++) + { + tot_diag[diag[c][0]][1]+=diag[c][1]*diag[c][1]; + } + free_int (diag, -1); + + } + } + + + + sort_int (tot_diag+1, 2, 1,0, n_tot_diag-1); + + return tot_diag; + + } + + + + +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/util_dp_clean_maln.c b/binaries/src/tcoffee/t_coffee_source/util_dp_clean_maln.c new file mode 100644 index 0000000..10a3d23 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/util_dp_clean_maln.c @@ -0,0 +1,384 @@ +#include +#include +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" +#include "dp_lib_header.h" + +Alignment *clean_maln ( Alignment *A, Alignment *I, int T, int n_it) + { + Alignment *C=NULL; + int a, b; + int in_una, in_aln, in_gap, gap, una, aln; + int Sstart,Rstate, Sstate; + int n_segment=0; + int **segment_list; + + + add_warning ( stderr, "\nWARNING: -clean_aln is not supported anymore [PROGRAM:%s]\n", PROGRAM); + return A; + + + + /*Initialization*/ + a=0; + in_una=a++;in_gap=a++;in_aln=a++; aln=a++;gap=a++;una=a++; + segment_list=declare_int ( A->len_aln*A->nseq, 3); + + + /*1: Identify the segments*/ + C=copy_aln(A, C); + for ( a=0; a< A->nseq; a++) + { + Sstate=in_aln; + for ( b=0; blen_aln; b++) + { + if (is_gap(A->seq_al[a][b]))Rstate=gap; + else if ( I->seq_al[a][b]<=T){Rstate=una;} + else if ( I->seq_al[a][b]==NO_COLOR_RESIDUE)Rstate=una; + else Rstate=aln; + + if (Rstate==una)C->seq_al[a][b]='-'; + + if (Sstate==in_aln) + { + if ( Rstate==gap) + {Sstate=in_gap; + Sstart=b; + } + else if ( Rstate==una) + { + Sstate=in_una; + Sstart=b; + } + else if ( Rstate==aln) + Sstate=in_aln; + } + else if ( Sstate==in_gap) + { + if ( Rstate==gap); + else if ( Rstate==una)Sstate=in_una; + else if ( Rstate==aln)Sstate=in_aln; + } + else if ( Sstate==in_una) + { + if ( Rstate==gap); + else if ( Rstate==una); + else if ( Rstate==aln) + { + segment_list[n_segment][0]=a; + segment_list[n_segment][1]=Sstart; + segment_list[n_segment][2]=b-Sstart; + Sstate=in_aln; + n_segment++; + } + } + } + if (Sstate==in_una) + { + segment_list[n_segment][0]=a; + segment_list[n_segment][1]=Sstart; + segment_list[n_segment][2]=b-Sstart; + Sstate=in_aln; + n_segment++; + } + } + + /*2 Realign the segments*/ + + for ( b=0; b< n_it; b++) + { + for ( a=0; a< n_segment; a++) + { + HERE ("1"); + A=realign_segment ( segment_list[a][0], segment_list[a][1], segment_list[a][2], A, C); + + } + } + free_aln (C); + free_int ( segment_list, -1); + make_fast_generic_dp_pair_wise (NULL, NULL, NULL, NULL); + + return A; + } +Alignment *realign_segment (int seq, int start, int len,Alignment *A, Alignment *C) + { + Alignment *S1=NULL, *S2=NULL, *S3=NULL; + int *ns, **ls; + int a,b; + static Constraint_list *CL; + + + /*1 Prepare the Constraint list*/ + if ( !CL) + { + CL=vcalloc ( 1, sizeof (Constraint_list)); + CL->extend_jit=0; + CL->pw_parameters_set=1; + CL->M=read_matrice ("blosum62mt"); + CL->gop=-20; + CL->gep=-1; + CL->evaluate_residue_pair=evaluate_matrix_score; + sprintf ( CL->dp_mode, "myers_miller_pair_wise"); + } + + S1=copy_aln(A,S1); + S1=extract_aln (S1,0,start); + S2=copy_aln(A,S2); + S2=extract_aln (S2, start, start+len); + S3=copy_aln(A,S3); + S3=extract_aln (S3, start+len,A->len_aln); + + + /*for (a=0; anseq; a++){S2->order[a][1]=0;S2->order[a][0]=a;}*/ + + + ungap ( S2->seq_al[seq]); + CL->S=A->S;/*aln2seq(S2);*/ + /*3 Prepare Sequence Presentation*/ + ns=vcalloc (2, sizeof (int)); + ls=declare_int (2,S2->nseq); + + ns[0]=A->nseq-1; + for ( a=0,b=0; a< S2->nseq; a++)if (a!=seq)ls[0][b++]=a; + ns[1]=1; + ls[1][0]=seq; + + pair_wise (S2, ns, ls, CL); + + A=realloc_aln (A, strlen (S1->seq_al[0])+ strlen (S2->seq_al[0])+ strlen (S3->seq_al[0])+1); + for ( a=0; a< A->nseq; a++) + { + sprintf ( A->seq_al[a], "%s%s%s", S1->seq_al[a], S2->seq_al[a], S3->seq_al[a]); + } + + free_aln (S1); + free_aln (S2); + free_aln (S3); + vfree(ns);free_int(ls, -1); + + return A; + } +Alignment *realign_segment_old (int seq, int start, int len,Alignment *A, Alignment *C) + { + Alignment *S=NULL; + int *ns, **ls; + char *sub_seq; + static Dp_Model *M=NULL; + static Constraint_list *CL=NULL; + Dp_Result *R=NULL; + int a,b, c; + + + /*1 Prepare the Constraint list*/ + if ( !CL) + { + CL=vcalloc ( 1, sizeof (Constraint_list)); + CL->extend_jit=0; + CL->pw_parameters_set=1; + CL->M=read_matrice ("blosum62mt"); + CL->gop=-20; + CL->gep=-1; + CL->evaluate_residue_pair=evaluate_matrix_score; + + } + S=copy_aln(C,S); + S=extract_aln (S, start, start+len); + S->len_aln=strlen(S->seq_al[0]); + sub_seq=extract_char (A->seq_al[seq], start, len); + + ungap(sub_seq); + + sprintf ( S->seq_al[seq],"%s", sub_seq); + CL->S=aln2seq(S); + + + + /*2 Prepare the Model*/ + M=initialize_seg2prf_model((start==0)?2:0,(start+len==A->len_aln)?2:0,CL); + M->diag=vcalloc ( 2*len+1, sizeof (int)); + M->diag[0]=len+strlen (sub_seq)-1; + for ( a=1; a<=M->diag[0]; a++)M->diag[a]=a; + + /*3 Prepare Sequence Presentation*/ + ns=vcalloc (2, sizeof (int)); + ls=declare_int (2,A->nseq); + + ns[0]=A->nseq-1; + for ( a=0,b=0; a< A->nseq; a++)if (a!=seq)ls[0][b++]=a; + ns[1]=1; + ls[1][0]=seq; + + if ( strlen (sub_seq)!=len) + { + + + R=make_fast_generic_dp_pair_wise(S, ns, ls, M); + + for (c=0, b=1,a=start; a< start+len; b++,a++) + { + if (R->traceback[b]==0) + { + A->seq_al[seq][a]=sub_seq[c]; + C->seq_al[seq][a]=sub_seq[c]; + c++; + } + else + { + A->seq_al[seq][a]='-'; + C->seq_al[seq][a]='-'; + } + } + } + + free_dp_model (M); + free_aln (S); + free_dp_result (R); + vfree(sub_seq); + vfree(ns); + free_int (ls, -1); + free_sequence (CL->S, (CL->S)->nseq); + + + return A; + } + +Dp_Model * initialize_seg2prf_model(int left_tg_mode, int right_tg_mode, Constraint_list *CL) + { + + Dp_Model *M; + int a, b, c,d; + + M=vcalloc ( 1, sizeof (Dp_Model)); + M->nstate=2; + M->START=M->nstate++; + M->END =M->nstate++; + + M->TG_MODE=1; + M->F_TG_MODE=0; + M->gop=CL->gop*SCORE_K; + M->gep=CL->gep*SCORE_K; + + M->bounded_model=declare_int (M->nstate+1, M->nstate+1); + M->model=declare_int (M->nstate+1, M->nstate+1); + for ( a=0; a<=M->nstate; a++) + for ( b=0; b<= M->nstate; b++) + M->model[a][b]=UNDEFINED; + + a=0; + M->TYPE=a++;M->LEN_I=a++; M->LEN_J=a++; M->DELTA_I=a++;M->DELTA_J=a++; M->CODING0=a++;M->DELETION=a++; + M->model_properties=declare_int ( M->nstate, 10); + + a=0; + M->EMISSION=a++;M->TERM_EMISSION=a++;M->START_EMISSION=a++; + M->model_emission_function=vcalloc(M->nstate, sizeof (int (**)(Alignment*, int **, int, int*, int, int **, int, int*, int, struct Constraint_list *))); + for ( a=0; a< M->nstate; a++) + M->model_emission_function[a]=vcalloc(3, sizeof (int (*)(Alignment*, int **, int, int*, int, int **, int, int*, int, struct Constraint_list *))); + + + /*Substitution*/ + M->model_properties[0][M->TYPE]=M->CODING0; + M->model_properties[0][M->LEN_I]=1; + M->model_properties[0][M->LEN_J]=1; + M->model_properties[0][M->DELTA_I]=-1; + M->model_properties[0][M->DELTA_J]= 0; + + M->model_emission_function[0][M->EMISSION] =cw_profile_get_dp_cost; + M->model_emission_function[0][M->START_EMISSION]=get_start_gep_cost; + M->model_emission_function[0][M->TERM_EMISSION] =get_start_gep_cost; + + /*Deletions*/ + M->model_properties[1][M->TYPE]=M->DELETION; + M->model_properties[1][M->LEN_I]=1; + M->model_properties[1][M->LEN_J]=0; + M->model_properties[1][M->DELTA_I]=-1; + M->model_properties[1][M->DELTA_J]=+1; + M->model_emission_function[1][M->EMISSION]=get_gep_cost; + + if (left_tg_mode ==2) + M->model_emission_function[1][M->START_EMISSION]=get_start_gep_cost; + else M->model_emission_function[1][M->START_EMISSION]=get_gep_cost; + + if (right_tg_mode ==2) + M->model_emission_function[1][M->TERM_EMISSION]=get_term_gep_cost; + else M->model_emission_function[1][M->TERM_EMISSION]=get_gep_cost; + + /*Transitions*/ + M->model[0][M->END]=M->model[M->START][0]=ALLOWED; + M->model[0][1]=M->gop; + M->model[0][0]=ALLOWED; + + M->model[1][M->END]= (right_tg_mode==0)?0:-M->gop; + M->model[M->START][1]=( left_tg_mode==0)?M->gop:0; + M->model[1][1]=ALLOWED; + M->model[1][0]=ALLOWED; + + + + + /*Prune the model*/ + + for (c=0,a=0, d=0; a< M->START; a++) + for ( b=0; bSTART; b++, d++) + { + if (M->model[a][b]!=UNDEFINED) + { + M->bounded_model[b][1+M->bounded_model[b][0]++]=a; + c++; + } + } + M->CL=CL; + + return M; + } + +int get_gep_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) +{ + return CL->gep*SCORE_K; +} + +int get_start_gep_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) +{ + return 0; +} +int get_term_gep_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) +{ + return CL->gep*SCORE_K*-1; +} + + + + +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/util_dp_drivers.c b/binaries/src/tcoffee/t_coffee_source/util_dp_drivers.c new file mode 100644 index 0000000..220b7c0 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/util_dp_drivers.c @@ -0,0 +1,4596 @@ +#include +#include +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" +#include "dp_lib_header.h" + +int count_threshold_nodes (Alignment *A, NT_node P, int t); +int set_node_score (Alignment *A, NT_node P, char *mode); +char *split_nodes_nseq (Alignment *A, NT_node P, int max_nseq, char *list); +char *split_nodes_idmax (Alignment *A, NT_node P, int max_id, char *list); +/******************************************************************/ +/* MAIN DRIVER */ +/* */ +/* */ +/******************************************************************/ +int method_uses_structure(TC_method *M) +{ + if ( strchr (M->seq_type, 'P'))return 1; + else return 0; +} +Constraint_list *profile2list (Job_TC *job, int nprf) +{ + int a,b, s1, s2, r1, r2,w2; + Constraint_list *CL, *RCL; + Sequence *S; + Alignment *A1, *A2; + int *iA1, *iA2; + TC_method *M; + int ***RI, ***NRI; + Sequence *RS; + int Rne; + + int *seqlist; + int **cache; + static int *entry; + + + if (!entry)entry=vcalloc ( ICHUNK+3, sizeof (int)); + + CL=(job->io)->CL; + //1- buffer CL + + RS=CL->S; + RI=CL->residue_index; + Rne=CL->ne; + M=(job->param)->TCM; + + + + + + + //Index + seqlist=string2num_list ((job->param)->seq_c)+1; + A1=seq2profile(CL->S, seqlist[1]); + A2=seq2profile(CL->S, seqlist[2]); + + S=merge_seq (A1->S, NULL ); + S=merge_seq (A2->S, S); + + iA1=get_name_index (A1->name,A1->nseq, S->name, S->nseq); + iA2=get_name_index (A2->name,A2->nseq, S->name, S->nseq); + cache=vcalloc ( S->nseq, sizeof (int*)); + for (a=0; anseq; a++)cache[iA1[a]]=seq2inv_pos (A1->seq_al[a]); + for (a=0; anseq; a++)cache[iA2[a]]=seq2inv_pos (A2->seq_al[a]); + + //Declare local CL + CL->S=S; + CL->residue_index=declare_residue_index(S); + CL->ne=0; + + //Compute lib + for (a=0; anseq; a++) + for ( b=0; bnseq; b++) + { + char buf[1000]; + sprintf ( buf, "2 %d %d",iA1[a], iA2[b]); + job=print_lib_job (job, "param->seq_c=%s", buf); + CL=seq2list (job); + } + + //restaure CL; + CL->S=RS; + NRI=CL->residue_index; + CL->residue_index=RI; + CL->ne=Rne; + + + + //incorporate new lib + entry[SEQ1]=seqlist[1]; + entry[SEQ2]=seqlist[2]; + for (a=0; anseq; a++) + { + s1=iA1[a]; + + for (r1=1; r1<=S->len[s1];r1++) + { + for (b=1; bnseq); + return (job->io)->CL=CL; +} + +Constraint_list *seq2list ( Job_TC *job) + { + char *mode; + Alignment *A=NULL; + Constraint_list *PW_CL; + Constraint_list *RCL=NULL; + + int full_prf, nprf; + int *seqlist; + + + Sequence *S, *STL; + Constraint_list *CL; + + + char *seq; + char *weight; + TC_method *M; + + + M=(job->param)->TCM; + mode=M->executable; + weight=M->weight; + + PW_CL=M->PW_CL; + + CL=(job->io)->CL; + seq=(job->param)->seq_c; + + + + S=(CL)?CL->S:NULL; + STL=(CL)?CL->STRUC_LIST:NULL; + + seqlist=string2num_list (seq)+1; + + + +/*Proteins*/ + + + if ( strncmp (CL->profile_comparison, "full", 4)==0) + { + full_prf=1; + if ( CL->profile_comparison[4])nprf=atoi ( CL->profile_comparison+4); + else + nprf=0; + } + else + { + full_prf=0; + } + + if ((method_uses_structure (M)) && profile2P_template_file (CL->S, seqlist[1]) && profile2P_template_file (CL->S, seqlist[2])) + { + RCL=profile2list (job, nprf); + } + else if ( strm (mode, "ktup_msa")) + { + RCL=hasch2constraint_list (CL->S, CL); + } + else if ( strm (mode, "test_pair") || strm ( mode,"fast_pair") || strm (mode, "ifast_pair") \ + || strm ( mode, "diag_fast_pair")|| strm (mode, "idiag_fast_pair")\ + || strm ( mode, "blast_pair") || strm (mode, "lalign_blast_pair") \ + || strm ( mode, "viterbi_pair") || strm (mode, "slow_pair") || strm(mode, "glocal_pair") || strm (mode, "biphasic_pair") \ + || strm ( mode, "islow_pair") || strm (mode, "tm_slow_pair") || strm (mode, "r_slow_pair") \ + || strm ( mode, "lalign_id_pair")|| strm (mode, "tm_lalign_id_pair") || strm (mode , "lalign_len_pair") \ + || strm (mode, "prrp_aln") || strm ( mode, "test_pair") \ + || strm (mode, "cdna_fast_pair") || strm (mode, "diaa_slow_pair") || strm (mode, "monoaa_slow_pair")\ + || strncmp (mode,"cdna_fast_pair",14)==0 \ + ) + { + + A=fast_pair (job); + RCL=aln2constraint_list ((A->A)?A->A:A, CL,weight); + } + + else if ( strm ( mode, "subop1_pair") || strm ( mode, "subop2_pair") ) + { + A=fast_pair (job); + RCL=A->CL; + } + else if ( strm ( mode, "proba_pair") ) + { + A=fast_pair (job); + RCL=A->CL; + } + else if ( strm ( mode, "best_pair4prot")) + { + RCL=best_pair4prot (job); + } + else if ( strm ( mode, "best_pair4rna")) + { + RCL=best_pair4rna (job); + } + else if ( strm ( mode, "exon2_pair")) + { + char weight2[1000]; + + A=fast_pair (job); + sprintf ( weight2, "%s_subset_objOBJ-",weight); + RCL=aln2constraint_list (A, CL,weight2); + } + else if ( strm ( mode, "exon_pair")) + { + A=fast_pair (job); + RCL=aln2constraint_list (A, CL,weight); + + } + else if ( strm ( mode, "exon3_pair")) + { + char weight2[1000]; + + A=fast_pair (job); + sprintf ( weight2, "%s_subset_objOBJ-",weight); + RCL=aln2constraint_list (A, CL,weight2); + } + +/*STRUCTURAL METHODS*/ + + else if ( strm (mode, "seq_msa")) + { + RCL=seq_msa(M, seq, CL); + } +/*STRUCTURAL METHODS*/ + else if (strm (mode, "profile_pair") || strm (mode, "hh_pair")) + { + RCL=profile_pair (M, seq, CL); + } + + else if ( strm (mode, "sap_pair")) + { + RCL=sap_pair (seq, weight, CL); + } + else if ( strm (mode, "thread_pair")) + { + RCL=thread_pair (M,seq, CL); + } + else if ( strm (mode, "pdb_pair")) + { + RCL=pdb_pair (M,seq, CL); + } + else if (strm (mode, "rna_pair")) + { + RCL=rna_pair(M, seq, CL); + } + else if ( strm (mode, "pdbid_pair")) + { + RCL=pdbid_pair (M,seq, CL); + } + else if ( strm (mode, "fugue_pair")) + { + RCL=thread_pair (M,seq, CL); + } + else if ( strm (mode, "lsqman_pair")) + { + RCL=lsqman_pair(seq, CL); + } + else if ( strm ( mode, "align_pdb_pair")) + { + RCL=align_pdb_pair ( seq,"gotoh_pair_wise", CL->align_pdb_hasch_mode,CL->align_pdb_param_file,CL, job); + } + else if ( strm ( mode, "lalign_pdb_pair")) + { + RCL=align_pdb_pair ( seq,"sim_pair_wise_lalign", CL->align_pdb_hasch_mode,CL->align_pdb_param_file,CL, job); + } + else if ( strm ( mode, "align_pdb_pair_2")) + { + RCL=align_pdb_pair_2 ( seq, CL); + } + else + { + fprintf ( CL->local_stderr, "\nERROR: THE FUNCTION %s DOES NOT EXIST [FATAL:%s]\n", mode, PROGRAM);crash(""); + } + add_method_output2method_log (NULL,NULL, (A&&A->len_aln)?A:NULL,RCL, NULL); + RCL=(RCL==NULL)?CL:RCL; + + + vfree ( seqlist-1); + free_aln (A); + return RCL; + } + +Constraint_list *method2pw_cl (TC_method *M, Constraint_list *CL) + { + char *mode; + Constraint_list *PW_CL=NULL; + Sequence *S; + char mat[100], *m; + char group_mat[100]; + + + + mode=M->executable; + PW_CL=copy_constraint_list ( CL, SOFT_COPY); + PW_CL->pw_parameters_set=1; + + + + S=(PW_CL)?PW_CL->S:NULL; + + /*DNA or Protein*/ + m=PW_CL->method_matrix; + if ( strm ((PW_CL->S)->type, "PROTEIN")) + { + + sprintf ( mat, "%s", (strm(m, "default"))?"blosum62mt":m); + sprintf (group_mat, "vasiliky"); + PW_CL->ktup=2; + + } + else if ( strm ((PW_CL->S)->type, "DNA") || strm ((PW_CL->S)->type, "RNA") ) + { + + sprintf(group_mat, "idmat"); + sprintf ( mat, "%s", (strm(m, "default"))?"dna_idmat":m); + PW_CL->ktup=5; + + } + if ( M->matrix[0])sprintf ( mat, "%s", M->matrix); + + PW_CL->M=read_matrice (mat); + + + if ( M->gop!=UNDEFINED) {PW_CL->gop=M->gop;} + else + { + PW_CL->gop= get_avg_matrix_mm (PW_CL->M, AA_ALPHABET)*10; + } + + if ( M->gep!=UNDEFINED)PW_CL->gep=M->gep; + else PW_CL->gep=-1; + + if (M->extend_seq ==1) PW_CL->extend_seq=1; + if (M->reverse_seq==1)PW_CL->reverse_seq=1; + + + if ( strm2 ( mode,"fast_pair", "ifast_pair")) + { + PW_CL->maximise=1; + PW_CL->TG_MODE=1; + PW_CL->use_fragments=0; + if ( !PW_CL->use_fragments)PW_CL->diagonal_threshold=0; + else PW_CL->diagonal_threshold=6; + + sprintf (PW_CL->dp_mode, "fasta_pair_wise"); + sprintf (PW_CL->matrix_for_aa_group,"%s", group_mat); + + if ( strm ( mode, "fast_pair")) + { + PW_CL->residue_index=NULL; + + PW_CL->get_dp_cost=slow_get_dp_cost; + PW_CL->evaluate_residue_pair=evaluate_matrix_score; + PW_CL->extend_jit=0; + } + } + else if ( strm2 ( mode,"diag_fast_pair","idiag_fast_pair")) + { + PW_CL->residue_index=NULL; + PW_CL->maximise=1; + PW_CL->TG_MODE=1; + PW_CL->S=CL->S; + + PW_CL->use_fragments=1; + PW_CL->diagonal_threshold=3; + + sprintf (PW_CL->dp_mode, "fasta_pair_wise"); + PW_CL->ktup=1; + sprintf (PW_CL->matrix_for_aa_group,"%s", group_mat); + + PW_CL->get_dp_cost=slow_get_dp_cost; + PW_CL->evaluate_residue_pair=evaluate_matrix_score; + + PW_CL->extend_jit=0; + } + else if ( strm ( mode,"blast_pair")) + { + PW_CL->residue_index=NULL; + PW_CL->maximise=1; + PW_CL->TG_MODE=1; + + PW_CL->use_fragments=0; + + PW_CL->pair_wise=gotoh_pair_wise; + PW_CL->evaluate_residue_pair=evaluate_blast_profile_score; + sprintf (PW_CL->matrix_for_aa_group,"%s", group_mat); + PW_CL->extend_jit=0; + } + else if ( strm ( mode,"lalign_blast_pair")) + { + PW_CL->residue_index=NULL; + PW_CL->maximise=1; + PW_CL->TG_MODE=1; + + PW_CL->use_fragments=0; + PW_CL->pair_wise=sim_pair_wise_lalign; + PW_CL->evaluate_residue_pair=evaluate_blast_profile_score; + PW_CL->lalign_n_top=10; + + sprintf (PW_CL->matrix_for_aa_group,"%s", group_mat); + PW_CL->extend_jit=0; + } + else if ( strm ( mode,"viterbi_pair")) + { + PW_CL->maximise=1; + PW_CL->TG_MODE=1; + PW_CL->use_fragments=0; + sprintf (PW_CL->dp_mode, "viterbi_pair_wise"); + PW_CL->residue_index=NULL; + PW_CL->get_dp_cost=slow_get_dp_cost; + PW_CL->evaluate_residue_pair=evaluate_matrix_score; + PW_CL->extend_jit=0; + } + else if ( strm ( mode,"glocal_pair")) + { + PW_CL->maximise=1; + PW_CL->TG_MODE=1; + PW_CL->use_fragments=0; + sprintf (PW_CL->dp_mode, "glocal_pair_wise"); + sprintf (PW_CL->matrix_for_aa_group,"%s", group_mat); + + PW_CL->residue_index=NULL; + PW_CL->get_dp_cost=slow_get_dp_cost; + PW_CL->evaluate_residue_pair=evaluate_matrix_score; + PW_CL->extend_jit=0; + } + else if ( strm ( mode,"test_pair")) + { + PW_CL->maximise=1; + PW_CL->TG_MODE=1; + PW_CL->use_fragments=0; + sprintf (PW_CL->dp_mode, "test_pair_wise"); + } + else if ( strm ( mode,"sticky_pair")) + { + PW_CL->maximise=1; + PW_CL->TG_MODE=1; + PW_CL->use_fragments=0; + PW_CL->residue_index=NULL; + PW_CL->get_dp_cost=cw_profile_get_dp_cost; + PW_CL->evaluate_residue_pair=evaluate_matrix_score; + PW_CL->extend_jit=0; + sprintf (PW_CL->dp_mode, "gotoh_pair_wise_lgp_sticky"); + sprintf (PW_CL->matrix_for_aa_group,"%s", group_mat); + } + + else if ( strm ( mode,"slow_pair")|| strm (mode, "islow_pair" ) ) + { + + PW_CL->maximise=1; + PW_CL->TG_MODE=1; + PW_CL->use_fragments=0; + sprintf (PW_CL->dp_mode, "myers_miller_pair_wise"); + sprintf (PW_CL->matrix_for_aa_group,"%s", group_mat); + + if ( strm ( "islow_pair", mode)) + { + PW_CL->get_dp_cost=slow_get_dp_cost; + PW_CL->evaluate_residue_pair=residue_pair_extended_list; + PW_CL->extend_jit=1; + } + else if ( strm ("slow_pair", mode) ) + { + PW_CL->residue_index=NULL; + PW_CL->get_dp_cost=cw_profile_get_dp_cost; + PW_CL->evaluate_residue_pair=evaluate_matrix_score; + PW_CL->extend_jit=0; + } + } + else if ( strm (mode, "subop1_pair")) + { + + PW_CL->maximise=1; + PW_CL->TG_MODE=1; + PW_CL->use_fragments=0; + sprintf (PW_CL->dp_mode, "subop1_pair_wise"); + sprintf (PW_CL->matrix_for_aa_group,"%s", group_mat); + PW_CL->residue_index=NULL; + PW_CL->get_dp_cost=slow_get_dp_cost; + PW_CL->evaluate_residue_pair=evaluate_matrix_score; + PW_CL->extend_jit=0; + } + else if ( strm (mode, "biphasic_pair")) + { + PW_CL->maximise=1; + PW_CL->TG_MODE=1; + PW_CL->use_fragments=0; + sprintf (PW_CL->dp_mode, "biphasic_pair_wise"); + sprintf (PW_CL->matrix_for_aa_group,"%s", group_mat); + PW_CL->residue_index=NULL; + PW_CL->get_dp_cost=cw_profile_get_dp_cost; + PW_CL->evaluate_residue_pair=evaluate_matrix_score; + PW_CL->extend_jit=0; + } + else if ( strm (mode, "proba_pair")) + { + + PW_CL->maximise=1; + PW_CL->TG_MODE=1; + PW_CL->use_fragments=0; + sprintf (PW_CL->dp_mode, "proba_pair_wise"); + sprintf (PW_CL->matrix_for_aa_group,"%s", group_mat); + PW_CL->residue_index=NULL; + PW_CL->get_dp_cost=slow_get_dp_cost; + PW_CL->evaluate_residue_pair=evaluate_matrix_score; + PW_CL->extend_jit=0; + } + + else if ( strm (mode, "diaa_slow_pair")) + { + + PW_CL->maximise=1; + PW_CL->TG_MODE=1; + PW_CL->use_fragments=0; + sprintf (PW_CL->dp_mode, "gotoh_pair_wise_lgp"); + sprintf (PW_CL->matrix_for_aa_group,"%s", group_mat); + PW_CL->residue_index=NULL; + PW_CL->get_dp_cost=slow_get_dp_cost; + PW_CL->evaluate_residue_pair=evaluate_diaa_matrix_score; + PW_CL->extend_jit=0; + } + else if ( strm (mode, "r_slow_pair")) + { + PW_CL->maximise=1; + PW_CL->TG_MODE=1; + PW_CL->use_fragments=0; + sprintf (PW_CL->dp_mode, "gotoh_pair_wise_lgp"); + sprintf (PW_CL->matrix_for_aa_group,"%s", group_mat); + PW_CL->residue_index=NULL; + PW_CL->get_dp_cost=slow_get_dp_cost; + PW_CL->evaluate_residue_pair=evaluate_matrix_score; + PW_CL->extend_jit=0; + PW_CL->reverse_seq=1; + } + else if ( strm (mode, "tm_slow_pair")) + { + PW_CL->maximise=1; + PW_CL->TG_MODE=1; + PW_CL->use_fragments=0; + sprintf (PW_CL->dp_mode, "myers_miller_pair_wise"); + sprintf (PW_CL->matrix_for_aa_group,"%s", group_mat); + PW_CL->residue_index=NULL; + PW_CL->get_dp_cost=slow_get_dp_cost; + PW_CL->evaluate_residue_pair=evaluate_tm_matrix_score; + PW_CL->extend_jit=0; + } + else if ( strm (mode, "monoaa_slow_pair")) + { + + PW_CL->maximise=1; + PW_CL->TG_MODE=1; + PW_CL->use_fragments=0; + sprintf (PW_CL->dp_mode, "gotoh_pair_wise_lgp"); + sprintf (PW_CL->matrix_for_aa_group,"%s", group_mat); + PW_CL->residue_index=NULL; + PW_CL->get_dp_cost=slow_get_dp_cost; + PW_CL->evaluate_residue_pair=evaluate_monoaa_matrix_score; + PW_CL->extend_jit=0; + } + else if ( strm (mode, "subop2_pair")) + { + + PW_CL->maximise=1; + PW_CL->TG_MODE=1; + PW_CL->use_fragments=0; + sprintf (PW_CL->dp_mode, "subop2_pair_wise"); + sprintf (PW_CL->matrix_for_aa_group,"%s", group_mat); + PW_CL->residue_index=NULL; + PW_CL->get_dp_cost=slow_get_dp_cost; + PW_CL->evaluate_residue_pair=evaluate_matrix_score; + PW_CL->extend_jit=0; + } + + else if (strm ( mode, "exon2_pair")) + { + int a; + PW_CL->maximise=1; + PW_CL->TG_MODE=1; + + PW_CL->use_fragments=0; + sprintf (PW_CL->dp_mode, "myers_miller_pair_wise"); + sprintf (PW_CL->matrix_for_aa_group,"%s", group_mat); + PW_CL->residue_index=NULL; + + for ( a=0; a<60; a++) + { + PW_CL->M['x'-'A'][a]=0; + PW_CL->M[a]['x'-'A']=0; + PW_CL->M['X'-'A'][a]=0; + PW_CL->M[a]['X'-'A']=0; + } + PW_CL->evaluate_residue_pair=evaluate_matrix_score; + PW_CL->extend_jit=0; + } + else if (strm ( mode, "exon3_pair")) + { + int a; + PW_CL->maximise=1; + PW_CL->TG_MODE=1; + + PW_CL->use_fragments=0; + sprintf (PW_CL->dp_mode, "myers_miller_pair_wise"); + sprintf (PW_CL->matrix_for_aa_group,"%s", group_mat); + PW_CL->residue_index=NULL; + + for ( a=0; a<60; a++) + { + PW_CL->M['x'-'A'][a]=0; + PW_CL->M[a]['x'-'A']=0; + PW_CL->M['X'-'A'][a]=0; + PW_CL->M[a]['X'-'A']=0; + } + PW_CL->evaluate_residue_pair=evaluate_matrix_score; + PW_CL->extend_jit=0; + } + else if (strm ( mode, "exon_pair")) + { + int a; + PW_CL->maximise=1; + PW_CL->TG_MODE=1; + + PW_CL->use_fragments=0; + sprintf (PW_CL->dp_mode, "myers_miller_pair_wise"); + sprintf (PW_CL->matrix_for_aa_group, "%s",group_mat); + PW_CL->residue_index=NULL; + + for ( a=0; a<60; a++) + { + PW_CL->M['x'-'A'][a]=0; + PW_CL->M[a]['x'-'A']=0; + PW_CL->M['X'-'A'][a]=0; + PW_CL->M[a]['X'-'A']=0; + } + PW_CL->evaluate_residue_pair=evaluate_matrix_score; + PW_CL->extend_jit=0; + } + else if ( strm ( mode , "lalign_len_pair")) + { + PW_CL->residue_index=NULL; + PW_CL->maximise=1; + PW_CL->TG_MODE=1; + PW_CL->use_fragments=0; + PW_CL->pair_wise=sim_pair_wise_lalign; + PW_CL->evaluate_residue_pair=evaluate_matrix_score; + PW_CL->get_dp_cost=slow_get_dp_cost; + PW_CL->lalign_n_top=CL->lalign_n_top; + sprintf (PW_CL->matrix_for_aa_group,"%s", group_mat); + PW_CL->extend_jit=0; + } + else if ( strm ( mode , "lalign_id_pair")) + { + PW_CL->residue_index=NULL; + PW_CL->maximise=1; + PW_CL->TG_MODE=1; + PW_CL->use_fragments=0; + PW_CL->pair_wise=sim_pair_wise_lalign; + PW_CL->evaluate_residue_pair=evaluate_matrix_score; + PW_CL->get_dp_cost=slow_get_dp_cost; + PW_CL->lalign_n_top=CL->lalign_n_top; + sprintf (PW_CL->matrix_for_aa_group,"%s", group_mat); + PW_CL->extend_jit=0; + } + else if ( strm ( mode , "tm_lalign_id_pair")) + { + PW_CL->residue_index=NULL; + PW_CL->maximise=1; + PW_CL->TG_MODE=1; + PW_CL->use_fragments=0; + PW_CL->pair_wise=sim_pair_wise_lalign; + PW_CL->evaluate_residue_pair=evaluate_tm_matrix_score; + PW_CL->get_dp_cost=slow_get_dp_cost; + PW_CL->lalign_n_top=CL->lalign_n_top; + sprintf (PW_CL->matrix_for_aa_group,"%s", group_mat); + PW_CL->extend_jit=0; + } +/*CDNA*/ + else if ( strm ( mode, "cdna_cfast_pair")) + { + PW_CL->residue_index=NULL; + PW_CL->maximise=1; + PW_CL->TG_MODE=1; + PW_CL->S=CL->S; + PW_CL->use_fragments=0; + sprintf (PW_CL->dp_mode, "cfasta_cdna_pair_wise"); + + PW_CL->M=read_matrice (strcpy ( mat, "blosum62mt")); + PW_CL->extend_jit=0; + + PW_CL->f_gop=CL->f_gop; + PW_CL->f_gep=CL->f_gep; + PW_CL->get_dp_cost=get_dp_cost; + PW_CL->evaluate_residue_pair=evaluate_cdna_matrix_score; + PW_CL->ktup=1; + } + else if ( strm ( mode, "cdna_fast_pair") || strncmp (mode,"cdna_fast_pair",14)==0) + { + + PW_CL->residue_index=NULL; + PW_CL->maximise=1; + PW_CL->TG_MODE=1; + PW_CL->use_fragments=0; + sprintf (PW_CL->dp_mode, "fasta_cdna_pair_wise"); + + PW_CL->extend_jit=0; + PW_CL->gop=-5; + PW_CL->gep=-1; + PW_CL->f_gop=-15; + PW_CL->f_gep=0; + + PW_CL->get_dp_cost=get_dp_cost; + PW_CL->evaluate_residue_pair=evaluate_cdna_matrix_score; + PW_CL->ktup=1; + } + else + { + free_constraint_list (PW_CL); + PW_CL=NULL; + } + + + if (!strm (CL->method_evaluate_mode, "default")) + { + choose_extension_mode (CL->method_evaluate_mode, PW_CL); + } + return PW_CL; + } +/******************************************************************/ +/* MULTIPLE ALIGNMENTS */ +/* */ +/* */ +/******************************************************************/ +Alignment * compute_prrp_aln (Alignment *A, Constraint_list *CL) + { + char *tmpseq=NULL; + char *tmpaln=NULL; + char command[10000]; + Sequence *S; + + tmpseq=vtmpnam(NULL); + tmpaln=vtmpnam(NULL); + + + A=seq2aln ( CL->S, A, 1); + output_gotoh_seq (tmpseq, A); + sprintf ( command, "prrp -E/dev/null -o%s -F9 %s >/dev/null", tmpaln, tmpseq); + my_system (command); + if (!check_file_exists(tmpaln)){return NULL;} + S=get_fasta_sequence (tmpaln, NULL); + + S->contains_gap=0; + A=seq2aln(S, A,0); + free_sequence (S, S->nseq); + + return A; + } + +Alignment *seq2clustalw_aln (Sequence *S) +{ + return aln2clustalw_aln (seq2aln (S, NULL,RM_GAP), NULL); +} + +Alignment * aln2clustalw_aln (Alignment *B, Constraint_list *CL) +{ + char *seq=NULL,*aln=NULL, command[1000]; + + output_fasta_seq (seq=vtmpnam (NULL), B); + sprintf ( command, "clustalw -infile=%s -outorder=input -outfile=%s %s", seq, aln=vtmpnam (NULL), TO_NULL_DEVICE); + my_system (command); + + if (!check_file_exists(aln)) + return NULL; + else{B->nseq=0;return main_read_aln(aln,B);} +} +Alignment * compute_tcoffee_aln_quick (Alignment *A, Constraint_list *CL) + { + char *tmpseq=NULL; + char *tmpaln=NULL; + char command[10000]; + + + tmpseq=vtmpnam(NULL); + tmpaln=vtmpnam(NULL); + + if ( CL)A=seq2aln ( CL->S, A, 1); + output_fasta_seq (tmpseq, A); + + sprintf ( command, "t_coffee -seq %s -very_fast -outfile %s -quiet ",tmpseq,tmpaln); + + my_system (command); + if (!check_file_exists(tmpaln))return NULL; + A->nseq=0; + A=main_read_aln(tmpaln,A); + + vremove( tmpseq); + vremove (tmpaln); + return A; + } + +Alignment * compute_clustalw_aln (Alignment *A, Constraint_list *CL) + { + char *tmpseq=NULL; + char *tmpaln=NULL; + char command[10000]; + + + tmpseq=vtmpnam(NULL); + tmpaln=vtmpnam(NULL); + + A=seq2aln ( CL->S, A, 1); + output_fasta_seq (tmpseq, A); + + sprintf ( command, "clustalw %sinfile=%s %soutfile=%s %s",CWF, tmpseq,CWF, tmpaln,TO_NULL_DEVICE); + + my_system (command); + if (!check_file_exists(tmpaln))return NULL; + A->nseq=0; + A=main_read_aln(tmpaln,A); + + vremove( tmpseq); + vremove (tmpaln); + return A; + } + +Alignment * realign_block ( Alignment *A, int col1, int col2, char *pg) +{ + /*Uses pg: (pg -infile= -outfile= to realign the block [col1 col2[ + Only guaranteed if pg can handle empty sequences + set pg to NULL to use the default program + */ + + + Alignment *L, *M, *R; + char *seq_name; + char *aln_name; + char command[1000], script[1000]; + + + + seq_name=vtmpnam(NULL); + aln_name=vtmpnam (NULL); + + L=copy_aln (A, NULL); + M=copy_aln (A, NULL); + R=copy_aln (A, NULL); + + L=extract_aln ( L, 0, col1); + M=extract_aln ( M, col1, col2); + R=extract_aln ( R, col2, A->len_aln); + output_fasta_seq (seq_name, M); + + sprintf ( script, "%s", (pg==NULL)?"t_coffee":pg); + + sprintf ( command, "%s -infile=%s -outfile=%s %s", script,seq_name, aln_name, TO_NULL_DEVICE); + my_system ( command); + free_aln (M); + M=main_read_aln (aln_name, NULL); + + + M=reorder_aln (M, L->name,L->nseq); + L=aln_cat (L, M); + L=aln_cat (L, R); + A=copy_aln (L, A); + free_aln (L);free_aln (M); free_aln (R); + + return A; +} + + + + + +/******************************************************************/ +/* DNA */ +/* */ +/* */ +/******************************************************************/ + + +/******************************************************************/ +/* STRUCTURES */ +/* */ +/* */ +/******************************************************************/ + + + + + +Constraint_list * align_pdb_pair_2 (char *seq, Constraint_list *CL) + { + char *tmp_name=NULL; + int s1, s2; + + + static char *command; + static char *program; + + tmp_name=vtmpnam ( NULL); + + if ( !program)program=vcalloc ( LONG_STRING, sizeof (char)); + if ( !command)command=vcalloc ( LONG_STRING, sizeof (char)); + +#ifndef ALIGN_PDB_4_TCOFFEE + if ( getenv ( "ALIGN_PDB_4_TCOFFEE")==NULL)crash ("ALIGN_PDB_4_TCOFFEE IS NOT DEFINED"); + else sprintf ( program, "%s", (getenv ( "ALIGN_PDB_4_TCOFFEE"))); +#else + if ( getenv ( "ALIGN_4_TCOFFEE")==NULL)sprintf (program, "%s", ALIGN_PDB_4_TCOFFEE); + else sprintf ( program, "%s", (getenv ( "ALIGN_PDB_4_TCOFFEE"))); +#endif + + atoi(strtok (seq,SEPARATORS)); + s1=atoi(strtok (NULL,SEPARATORS)); + s2=atoi(strtok (NULL,SEPARATORS)); + + sprintf ( command , "%s -in P%s P%s -gapopen=-40 -max_delta=2.5 -gapext=0 -scale=0 -hasch_mode=hasch_ca_trace_bubble -maximum_distance=10 -output pdb_constraint_list -outfile stdout> %s%s",program, (CL->S)->file[s1], (CL->S)->file[s2], get_cache_dir(),tmp_name); + + my_system ( command); + CL=read_constraint_list_file(CL, tmp_name); + + + vremove ( tmp_name); + + + return CL; + } + +Constraint_list *align_pdb_pair (char *seq_in, char *dp_mode,char *evaluate_mode, char *file, Constraint_list *CL, Job_TC *job) + { + int s1, s2; + char seq[1000]; + char name1[1000]; + char name2[1000]; + + + Constraint_list *PWCL; + Alignment *F; + + sprintf ( seq, "%s",seq_in); + atoi(strtok (seq,SEPARATORS)); + s1=atoi(strtok (NULL,SEPARATORS)); + s2=atoi(strtok (NULL,SEPARATORS)); + + + + sprintf (name1, "%s%s_%s.%s.align_pdb", get_cache_dir(),(CL->S)->name[s1], (CL->S)->name[s2], dp_mode); + sprintf (name2, "%s%s_%s.%s.align_pdb", get_cache_dir(),(CL->S)->name[s2], (CL->S)->name[s1], dp_mode); + + + if ( check_file_exists (name1) && is_lib(name1))CL=read_constraint_list_file(CL,name1); + else if ( check_file_exists (name2) && is_lib(name2))CL=read_constraint_list_file(CL,name2); + else + { + PWCL=set_constraint_list4align_pdb ( CL,s1,dp_mode, evaluate_mode, NULL); + PWCL=set_constraint_list4align_pdb ( CL,s2,dp_mode, evaluate_mode, NULL); + ((job->param)->TCM)->PW_CL=PWCL; + F=fast_pair (job); + output_constraints (name1, "100", F); + CL=aln2constraint_list (F, CL, "100"); + free_aln (F); + } + return CL; + } + +Constraint_list * profile_pair (TC_method *M , char *in_seq, Constraint_list *CL) + { + + char seq[1000]; + int a, s1, s2; + char *result,*prf1_file, *prf2_file; + Alignment *F=NULL, *A1, *A2; + FILE *fp; + char command[10000]; + char *param; + + if ( M->executable2[0]=='\0') + fprintf ( stderr, "\nERROR: profile_pair requires a method: thread_pair@EP@executable2@ [FATAL:%s]\n", PROGRAM); + + + sprintf ( seq, "%s", in_seq); + atoi(strtok (seq,SEPARATORS)); + s1=atoi(strtok (NULL,SEPARATORS)); + s2=atoi(strtok (NULL,SEPARATORS)); + + A1=seq2R_template_profile(CL->S,s1); + A2=seq2R_template_profile(CL->S,s2); + + + prf1_file=vtmpnam (NULL); + fp=vfopen (prf1_file, "w"); + if ( A1) + { + fprintf (fp, ">%s\n%s\n",(CL->S)->name[s1], aln2cons_seq_mat(A1, "blosum62mt")); + for ( a=0; a< A1->nseq; a++)fprintf (fp, ">prf_seq1_%d\n%s\n", a, A1->seq_al[a]); + } + else + { + fprintf ( fp, ">%s\n%s\n", (CL->S)->name[s1], (CL->S)->seq[s1]); + } + vfclose (fp); + + prf2_file=vtmpnam (NULL); + fp=vfopen (prf2_file, "w"); + if (A2) + { + fprintf (fp, ">%s\n%s\n",(CL->S)->name[s2], aln2cons_seq_mat(A2, "blosum62mt")); + for ( a=0; a< A2->nseq; a++)fprintf (fp, ">prf_seq2_%d\n%s\n", a, A2->seq_al[a]); + } + else + { + fprintf ( fp, ">%s\n%s\n", (CL->S)->name[s2], (CL->S)->seq[s2]); + } + vfclose (fp); + + result=vtmpnam (NULL); + if ( M->param) + { + param=vcalloc(strlen (M->param)+1, sizeof (char)); + sprintf ( param, "%s", M->param); + param=substitute ( param, " ", ""); + param=substitute ( param, "\n", ""); + } + + sprintf ( command, "tc_generic_method.pl -mode=profile_pair -method=%s %s%s %s%s %s%s -param=%s -tmpdir=%s", M->executable2,M->in_flag,prf1_file, M->in_flag2,prf2_file,M->out_flag, result, param, get_tmp_4_tcoffee()); + + my_system ( command); + + + + if ( !check_file_exists (result)) + { + fprintf ( stderr, "\n\tprofile_pair/%s failed:\n\t%s\n",M->executable2, command); + myexit (EXIT_FAILURE); + } + else if ( is_lib (result)) + { + CL=read_constraint_list_file(CL,result); + } + else if ( is_aln (result)) + { + F=main_read_aln (result, NULL); + char *name1, *name2; + name1=(CL->S)->name[s1]; + name2=(CL->S)->name[s2]; + + fp=vfopen (result, "w"); + for ( a=0; a< F->nseq; a++) + if (strm ( F->name[a], name1) || strm (F->name[a], name2)) + fprintf ( fp, ">%s\n%s\n", F->name[a], F->seq_al[a]); + vfclose (fp); + free_aln (F); + F=main_read_aln (result, NULL); + CL=aln2constraint_list (F, CL, "sim"); + free_aln (F); + } + return CL; + } +Constraint_list * pdbid_pair (TC_method *M , char *in_seq, Constraint_list *CL) + { + + char seq[1000]; + + int s1, s2; + char *result, *pdb1, *pdb2; + Alignment *F=NULL; + char *command; + + + if ( M->executable2[0]=='\0') + { + fprintf ( stderr, "\nERROR: pdbid_pair requires a structural alignment method: pdb_pair@EP@EXECUTABLE2@ [FATAL:%s]\n", PROGRAM); + myexit (EXIT_FAILURE); + } + sprintf ( seq, "%s", in_seq); + + + atoi(strtok (seq,SEPARATORS)); + s1=atoi(strtok (NULL,SEPARATORS)); + s2=atoi(strtok (NULL,SEPARATORS)); + + pdb1=seq2P_pdb_id(CL->S,s1); + pdb2=seq2P_pdb_id(CL->S,s2); + + if (!is_pdb_name (pdb1) || !is_pdb_name(pdb2)) + { + return CL; + } + + + result=vtmpnam (NULL); + command = vcalloc ( 1000, sizeof (char)); + + sprintf ( command, "tc_generic_method.pl -mode=pdbid_pair -method=%s %s%s %s%s %s%s -email=%s -cache=%s -tmpdir=%s", M->executable2,M->in_flag,pdb1, M->in_flag2,pdb2,M->out_flag, result,getenv ("EMAIL"),get_cache_dir(), get_tmp_4_tcoffee()); + my_system ( command); + vfree (command); + if (file_is_empty (result))return CL; + else + { + F=main_read_aln (result, NULL); + + if ( !F) + { + fprintf ( stderr, "\n\tpdb_pair/%s failed:\n\t%s\n",M->executable2, command); + } + else + { + + sprintf ( F->name[0],"%s", (CL->S)->name[s1]); + sprintf ( F->name[1],"%s", (CL->S)->name[s2]); + CL=aln2constraint_list (F, CL, "sim"); + } + free_aln (F); + } + return CL; + } + +Constraint_list * pdb_pair (TC_method *M , char *in_seq, Constraint_list *CL) + { + + char seq[1000]; + int s1, s2; + char *result, *pdb1,*pdb1_file, *pdb2, *pdb2_file; + Alignment *F=NULL; + + + char command[10000]; + + if ( M->executable2[0]=='\0') + { + fprintf ( stderr, "\nERROR: pdb_pair requires a structural alignment method: pdb_pair@EP@EXECUTABLE2@ [FATAL:%s]\n", PROGRAM); + myexit (EXIT_FAILURE); + } + + sprintf ( seq, "%s", in_seq); + + + atoi(strtok (seq,SEPARATORS)); + s1=atoi(strtok (NULL,SEPARATORS)); + s2=atoi(strtok (NULL,SEPARATORS)); + + pdb1=seq2P_template_file(CL->S,s1); + pdb2=seq2P_template_file(CL->S,s2); + if ( !pdb1 || !pdb2) return CL; + + + pdb1_file=vtmpnam (NULL); + pdb2_file=vtmpnam (NULL); + + + + sprintf ( command, "extract_from_pdb -infile %s -atom ALL -chain FIRST -nodiagnostic > %s", pdb1, pdb1_file); + my_system (command); + + + + sprintf ( command, "extract_from_pdb -infile %s -atom ALL -chain FIRST -nodiagnostic > %s", pdb2, pdb2_file); + my_system (command); + + + result=vtmpnam (NULL); + + sprintf ( command, "tc_generic_method.pl -mode=pdb_pair -method=%s %s%s %s%s %s%s -tmpdir=%s", M->executable2,M->in_flag,pdb1_file, M->in_flag2,pdb2_file,M->out_flag, result, get_tmp_4_tcoffee()); + my_system ( command); + + F=main_read_aln (result, NULL); + + if ( !F) + { + fprintf ( stderr, "\n\tpdb_pair/%s failed:\n\t%s\n",M->executable2, command); + } + else + { + + sprintf ( F->name[0],"%s", (CL->S)->name[s1]); + sprintf ( F->name[1],"%s", (CL->S)->name[s2]); + CL=aln2constraint_list (F, CL, "sim"); + } + + + free_aln (F); + return CL; + } + +Constraint_list * seq_msa (TC_method *M , char *in_seq, Constraint_list *CL) +{ + char seq[1000]; + char db[1000]; + char *infile, *outfile; + int a, n, s; + Alignment *F=NULL; + FILE *fp; + char command[1000]; + static char *db_file; + + + if (!db_file) + { + db_file=vtmpnam (NULL); + fp=vfopen (db_file, "w"); + for (a=0; a<(CL->S)->nseq; a++)fprintf ( fp, ">%s\n%s\n", (CL->S)->name[a], (CL->S)->seq[a]); + vfclose (fp); + } + + infile=vtmpnam (NULL); + outfile=vtmpnam (NULL); + + sprintf ( seq, "%s", in_seq); + + n=atoi(strtok (seq,SEPARATORS)); + + fp=vfopen (infile, "w"); + for ( a=0; a%s\n%s\n", (CL->S)->name[s], (CL->S)->seq[s]); + } + vfclose (fp); + + if (strstr (M->executable2, "blast"))sprintf ( db, " -database=%s", db_file); + else db[0]='\0'; + + sprintf ( command, "t_coffee -other_pg tc_generic_method.pl -mode=%s -method=%s %s %s%s %s %s%s -tmpdir=%s %s %s", M->executable, M->executable2, M->param1,M->in_flag,infile,M->param2,M->out_flag,outfile,get_tmp_4_tcoffee(),db,M->param); + + + + + //HERE ("%s", command);exit (0); + //sprintf ( command, "t_coffee -other_pg tc_generic_method.pl -mode=seq_msa -method=%s %s%s %s%s -tmpdir=%s %s", M->executable2, M->in_flag, infile, M->out_flag, outfile, get_tmp_4_tcoffee(), M->param); + my_system (command); + + + if ( strm (M->out_mode, "aln") || strm (M->out_mode, "A")) + { + F=main_read_aln (outfile, NULL); + if ( !F) + { + fprintf ( stderr, "\n\tseq_msa/%s failed:\n\t%s\n", M->executable2,command); + } + else + { + CL=aln2constraint_list (F, CL, "sim"); + } + free_aln (F); + } + else if ( strm (M->out_mode, "fL")|| strm (M->out_mode, "lib")) + { + Constraint_list *NCL; + NCL=read_constraint_list_file(CL,outfile); + if ( !NCL) + { + fprintf ( stderr, "\n\tseq_msa/%s failed:\n\t%s\n", M->executable2,command); + } + else + { + CL=NCL; + } + } + return CL; +} +Constraint_list * thread_pair (TC_method *M , char *in_seq, Constraint_list *CL) + { + + char seq[1000]; + int s1, s2; + + if ( M->executable2[0]=='\0') + { + fprintf ( stderr, "\nERROR: thread_pair requires a threading method: pdb_pair@EP@EXECUTABLE2@ [FATAL:%s]\n", PROGRAM); + myexit (EXIT_FAILURE); + } + + sprintf ( seq, "%s", in_seq); + atoi(strtok (seq,SEPARATORS)); + s1=atoi(strtok (NULL,SEPARATORS)); + s2=atoi(strtok (NULL,SEPARATORS)); + + CL=thread_pair2(M,s1, s2, CL); + CL=thread_pair2(M,s2, s1, CL); + + return CL; + } + + + +Constraint_list* thread_pair2 ( TC_method *M, int s1, int s2, Constraint_list *CL) + { + char *result, *pep, *pdb, *pdb1; + Alignment *F=NULL; + Sequence *STL; + FILE *fp; + char command[10000]; + + STL=(CL)?CL->STRUC_LIST:NULL; + + + if ( !(CL->S) || !((CL->S)->T[s1]) || !((CL->S)->T[s1])->P || !seq2P_template_file(CL->S,s1))return CL; + else pdb1=seq2P_template_file(CL->S,s1); + + + pdb=vtmpnam (NULL); + result=vtmpnam (NULL); + pep=vtmpnam (NULL); + + sprintf ( command, "extract_from_pdb -infile %s -atom ALL -chain FIRST -nodiagnostic > %s", pdb1, pdb); + my_system (command); + + + + fp=vfopen (pep, "w"); + fprintf ( fp, ">%s\n%s\n",(CL->S)->name[s2],(CL->S)->seq[s2] ); + vfclose (fp); + sprintf ( command, "tc_generic_method.pl -mode=thread_pair -method=%s %s%s %s%s %s%s -tmpdir=%s", M->executable2,M->in_flag,pep, M->in_flag2,pdb,M->out_flag, result, get_tmp_4_tcoffee()); + my_system ( command); + F=main_read_aln (result, NULL); + + if ( !F) + { + fprintf ( stderr, "\n\tthread_pair/%s failed:\n\t%s\n", M->executable2,command); + } + else + { + sprintf ( F->name[0],"%s", (CL->S)->name[s1]); + sprintf ( F->name[1],"%s", (CL->S)->name[s2]); + CL=aln2constraint_list (F, CL, "sim"); + } + + + free_aln (F); + return CL; + } + +Constraint_list * lsqman_pair ( char *in_seq, Constraint_list *CL) + { + FILE *fp; + static CLIST_TYPE *entry; + char command[STRING]; + char seq[1000]; + int s1, s2; + char *seq_file, *lsqman_result, *tmp_name1; + Alignment *F=NULL; + int n_failure=0; + + sprintf ( seq, "%s", in_seq); + + + if ( !entry)entry=vcalloc ( LIST_N_FIELDS, sizeof ( CLIST_TYPE )); + + atoi(strtok (seq,SEPARATORS)); + s1=atoi(strtok (NULL,SEPARATORS)); + s2=atoi(strtok (NULL,SEPARATORS)); + + + tmp_name1=vcalloc (100, sizeof (char)); + sprintf ( tmp_name1, "%s_%s.lsqman_aln", (CL->S)->name[s1], (CL->S)->name[s2]); + if ( check_file_exists ( tmp_name1) && (F=main_read_aln(tmp_name1, NULL))!=NULL) + { + free_aln(F); + lsqman_result=tmp_name1; + } + + else + { + seq_file=vtmpnam (NULL); + lsqman_result=tmp_name1; + fp=vfopen (seq_file, "w"); + fprintf ( fp, ">%s\n%s\n",(CL->S)->name[s1],(CL->S)->seq[s2] ); + vfclose (fp); + sprintf ( command, "%s -pdb %s -pep %s > %s%s", LSQMAN_4_TCOFFEE, (CL->S)->name[s1], seq_file,get_cache_dir(), lsqman_result); + + while (!F) + { + my_system ( command); + F=main_read_aln (lsqman_result, NULL); + if ( !F) + { + fprintf ( stderr, "\n\tlsqman failed: will be retried"); + if ( n_failure==0)fprintf ( stderr, "\n\t%s", command); + n_failure++; + if ( n_failure==10) + { + fprintf ( stderr, "\nCould not run Fugue: will replace it with slow_pair\n"); + vremove (lsqman_result); + return NULL; + } + } + free_aln (F); + } + vremove( seq_file); + + } + + + F=main_read_aln(lsqman_result, NULL); + /*sprintf ( F->name[0],"%s", (CL->S)->name[s1]); + sprintf ( F->name[1],"%s", (CL->S)->name[s2]); + */ + CL=aln2constraint_list (F, CL, "100"); + free_aln (F); + return CL; + } + +Constraint_list * sap_pair (char *seq, char *weight, Constraint_list *CL) + { + register int a; + FILE *fp; + char full_name[FILENAMELEN]; + char *tmp_pdb1, *tmp_pdb2; + char *sap_seq1, *sap_seq2; + char *sap_lib, *tmp_name, *tmp_name1, *tmp_name2; + char *buf=NULL; + int s1, s2, r1=0, r2=0; + int sim=0, tot=0, score=0; + + char program[STRING]; + char *string1, *string2, *string3, *string4, *string5; + int max_struc_len=10000; + char *template1, *template2; + int c; + + /*check_program_is_installed ( "sap" ,SAP_4_TCOFFEE, "SAP_4_TCOFFEE",MAIL, IS_FATAL);*/ + + + atoi(strtok (seq,SEPARATORS)); + s1=atoi(strtok (NULL,SEPARATORS)); + s2=atoi(strtok (NULL,SEPARATORS)); + + template1=seq2T_value(CL->S,s1, "template_name", "_P_"); + template2=seq2T_value(CL->S,s2, "template_name", "_P_"); + + + if (!template1 || !template2) return CL; + + + declare_name (string1); + declare_name (string2); + declare_name (string3); + declare_name (string4); + declare_name (string5); + +#ifndef SAP_4_TCOFFEE + if ( getenv ( "SAP_4_TCOFFEE")==NULL)crash ("SAP_4_TCOFFEE IS NOT DEFINED"); + else sprintf ( program, "%s", (getenv ( "SAP_4_TCOFFEE"))); +#else + if ( getenv ( "SAP_4_TCOFFEE")==NULL)sprintf (program, "%s", SAP_4_TCOFFEE); + else sprintf ( program, "%s", (getenv ( "SAP_4_TCOFFEE"))); +#endif + + + + tmp_name1=vcalloc (100, sizeof (char)); + sprintf ( tmp_name1, "%s_%s.sap_results",template1,template2); + tmp_name2=vcalloc (100, sizeof (char)); + sprintf ( tmp_name2, "%s_%s.sap_results",template2,template1); + + + + if (is_sap_file (tmp_name1)) + { + tmp_name=tmp_name1; + } + else if ( is_sap_file (tmp_name2)) + { + tmp_name=tmp_name2; + SWAP (s1, s2); + } + else + { + char local1[100]; + char local2[100]; + char cdir[1000]; + + tmp_name=tmp_name1; + + tmp_pdb1=normalize_pdb_file(seq2P_template_file(CL->S,s1),(CL->S)->seq[s1], vtmpnam (NULL)); + tmp_pdb2=normalize_pdb_file(seq2P_template_file(CL->S,s2),(CL->S)->seq[s2], vtmpnam (NULL)); + sprintf ( full_name, "%s%s", get_cache_dir (), tmp_name); + + //pb: sap crashes when file names are too long + //solution: create shorter names + //To ease server, create files in tmp dir + + getcwd (cdir, sizeof(char)*1000); + chdir (get_cache_dir()); + + sprintf (local1, "%d_1.%d.sap_tmp", getpid(), rand()%10000); + sprintf (local2, "%d_2.%d.sap_tmp", getpid(), rand()%10000); + printf_system ("cp %s %s", tmp_pdb1, local1); + printf_system ("cp %s %s", tmp_pdb2, local2); + printf_system ("%s %s %s >%s 2>/dev/null::IGNORE_FAILURE::",program,local1,local2, full_name); + printf_system ("rm %s", local1); + printf_system ("rm %s", local2); + chdir (cdir); + + if ( !check_file_exists (full_name) || !is_sap_file(full_name)) + { + add_warning ( stderr, "SAP failed to align: %s against %s [%s:WARNING]\n", seq2P_template_file(CL->S,s1),seq2P_template_file(CL->S,s2), PROGRAM); + if ( check_file_exists (full_name))add2file2remove_list (full_name); + return CL; + } + if ( flag_file2remove_is_on())add2file2remove_list (full_name); + remove ("super.pdb"); + } + + + + sap_seq1=vcalloc (max_struc_len, sizeof (char)); + sap_seq2=vcalloc (max_struc_len, sizeof (char)); + + fp=find_token_in_file ( tmp_name, NULL, "Percent"); + fp=find_token_in_file ( tmp_name, fp , "Percent"); + while ( (c=fgetc (fp))!='\n' && c!=EOF)fprintf ( fp, "%c", c); + while ((buf=vfgets (buf, fp))) + { + + if ( !strstr (buf, "eighted") && !strstr (buf, "RMSd")) + { + remove_charset (buf, "!alnum"); + r1=buf[0]; + r2=buf[strlen(buf)-1]; + } + else + continue; + + sim+=(r1==r2)?1:0; + if ( tot>max_struc_len) + {max_struc_len+=max_struc_len; + sap_seq1=vrealloc ( sap_seq1, sizeof(char)*max_struc_len); + sap_seq2=vrealloc ( sap_seq2, sizeof(char)*max_struc_len); + } + sap_seq1[tot]=r1; + sap_seq2[tot]=r2; + tot++; + } + sim=(sim*100)/tot; + + if ( is_number (weight))score=atoi(weight); + else if ( strstr ( weight, "OW")) + { + int ow; + sscanf ( weight, "OW%d", &ow); + score=sim*ow; + } + else + { + score=sim; + } + + + vfclose (fp); + sap_seq1[tot]=sap_seq2[tot]='\0'; + + + fp=vfopen ( sap_lib=vtmpnam(NULL), "w"); + fprintf (fp, "! TC_LIB_FORMAT_01\n"); + fprintf (fp, "2\n"); + fprintf (fp, "%s %d %s\n", (CL->S)->name[s2],(int)strlen (sap_seq1), sap_seq1); + fprintf (fp, "%s %d %s\n", (CL->S)->name[s1],(int)strlen (sap_seq2), sap_seq2); + fprintf (fp, "#1 2\n"); + + + + //HERE ("\n%s\n%s\n%s\n\n%s\n%s\n%s", (CL->S)->name[s1],(CL->S)->seq[s1], sap_seq1, (CL->S)->name[s2],(CL->S)->seq[s2], sap_seq2);exit (0); + for ( a=0; a< tot; a++) + { + fprintf (fp, "%d %d %d 1 0\n", a+1, a+1, score); + } + + fprintf (fp, "! CPU 0\n"); + fprintf (fp, "! SEQ_1_TO_N\n"); + vfclose (fp); + + CL=read_constraint_list_file(CL,sap_lib); + vremove (sap_lib); + + vfree ( string1);vfree ( string2);vfree ( string3);vfree ( string4);vfree ( string5); + vfree (sap_seq1); vfree(sap_seq2);vfree (tmp_name1); vfree(tmp_name2); + vfree (buf); + return CL; + } + + + +Constraint_list *rna_pair (TC_method *M , + char *in_seq, + Constraint_list *CL) +{ + char seq[1000]; + int s1, s2; + char *result, *pdb1, *pdb2, *pdb1_file, *pdb2_file; + Alignment *F=NULL; + + + + char command[10000]; + + if ( M->executable2[0]=='\0') + { + fprintf ( stderr, "\nERROR: rna_pair requires a structural alignment method: rna_pair@EP@EXECUTABLE2@ [FATAL:%s]\n", PROGRAM); + myexit (EXIT_FAILURE); + } + + sprintf ( seq, "%s", in_seq); + + + atoi(strtok (seq,SEPARATORS)); + s1=atoi(strtok (NULL,SEPARATORS)); + s2=atoi(strtok (NULL,SEPARATORS)); + + pdb1=seq2P_template_file(CL->S,s1); + pdb1_file=vtmpnam (NULL); + sprintf ( command, "extract_from_pdb -infile %s -atom ALL -chain FIRST -nodiagnostic > %s", pdb1, pdb1_file); + my_system (command); + // + pdb2=seq2P_template_file(CL->S,s2); + pdb2_file=vtmpnam (NULL); + sprintf ( command, "extract_from_pdb -infile %s -atom ALL -chain FIRST -nodiagnostic > %s", pdb2, pdb2_file); + my_system (command); + + result=vtmpnam (NULL); + + sprintf ( command, "tc_generic_method.pl -mode=rna_pair -method=%s %s%s %s%s %s%s -tmpdir=%s", M->executable2,M->in_flag,pdb1_file, M->in_flag2,pdb2_file,M->out_flag, result, get_tmp_4_tcoffee()); + + my_system ( command); + + F=main_read_aln (result, NULL); + + + if ( !F) + { + fprintf ( stderr, "\n\trna_pair/%s failed:\n\t%s\n",M->executable2, command); + } + else + { + sprintf ( F->name[0],"%s", (CL->S)->name[s1]); + sprintf ( F->name[1],"%s", (CL->S)->name[s2]); + CL=aln2constraint_list (F, CL, "sim"); + } + + + free_aln (F); + return CL; +} + + +/******************************************************************/ +/* GENERIC PAIRWISE METHODS */ +/* */ +/* */ +/******************************************************************/ + + + +Constraint_list * best_pair4rna(Job_TC *job) +{ + int n,a; + + + static char *seq; + Alignment *A; + Constraint_list *PW_CL; + Constraint_list *CL, *RCL; + char *seq_in; + Sequence *S; + TC_method *M, *sara_pairM, *proba_pairM; + int*seqlist; + + int s1, s2; + Template *T1, *T2; + int ml=0; + struct X_template *r1, *r2, *p1, *p2; + static int **blosum; + + if (!seq)seq=vcalloc (100, sizeof (char)); + + A=(job->io)->A; + M=(job->param)->TCM; + CL=(job->io)->CL; + S=CL->S; + for (a=0; anseq; a++)ml=MAX(ml, strlen (S->name[a])); + + + if ( !strm ( retrieve_seq_type(), "RNA") && !strm ( retrieve_seq_type(), "DNA")) + printf_exit (EXIT_FAILURE, stderr, "ERROR: RNA Sequences Only with best4rna_pair [FATAL:%s]\n",PROGRAM); + + + seq_in=(job->param)->seq_c; + sprintf (seq, "%s", seq_in); + seqlist=string2num_list (seq); + n=seqlist[1]; + if ( n!=2){fprintf ( stderr, "\nERROR: best_pair can only handle two seq at a time [FATAL]\n");myexit (EXIT_FAILURE);} + s1=seqlist[2]; + s2=seqlist[3]; + + T1=S->T[s1]; + T2=S->T[s2]; + r1=T1->R; + r2=T2->R; + p1=T1->P; + p2=T2->P; + + PW_CL=((job->param)->TCM)->PW_CL; + CL=(job->io)->CL; + + if (!blosum)blosum=read_matrice ("blosum62mt"); + +// id=idscore_pairseq (S->seq[s1], S->seq[s2],-10,-1,blosum, "sim"); + + + proba_pairM=method_file2TC_method(method_name2method_file ("proba_pair")); + proba_pairM->PW_CL=method2pw_cl(proba_pairM, CL); + + sara_pairM=method_file2TC_method(method_name2method_file ("sara_pair")); + sara_pairM->PW_CL=method2pw_cl(sara_pairM, CL); + + if ( p1 && p2) + { + //Avoid Structural Tem + T1->R=NULL; + T2->R=NULL; + fprintf ( stderr, "\n\t%-*s %-*s: Structure Based Alignment\n", ml,S->name[s1], ml,S->name[s2]); + (job->param)->TCM=sara_pairM; + } + else + { + fprintf ( stderr, "\n\t%-*s %-*s: Direct Sequence Alignment\n", ml,S->name[s1], ml,S->name[s2]); + (job->param)->TCM=proba_pairM; + } + + RCL=seq2list (job); + T1->R=r1; + T2->R=r2; + + return RCL; +} + +Constraint_list * best_pair4prot (Job_TC *job) +{ + int n,a; + + + static char *seq; + Alignment *A; + Constraint_list *PW_CL; + Constraint_list *CL, *RCL; + char *seq_in; + Sequence *S; + TC_method *M, *sap_pairM, *proba_pairM; + int*seqlist; + + int id, s1, s2; + Template *T1, *T2; + int ml=0; + struct X_template *r1, *r2, *p1, *p2; + static int **blosum; + + if (!seq)seq=vcalloc (100, sizeof (char)); + + A=(job->io)->A; + M=(job->param)->TCM; + CL=(job->io)->CL; + S=CL->S; + for (a=0; anseq; a++)ml=MAX(ml, strlen (S->name[a])); + + + if ( strm ( retrieve_seq_type(), "DNA") ||strm ( retrieve_seq_type(), "RNA") )printf_exit (EXIT_FAILURE, stderr, "ERROR: Protein Sequences Only with bestprot_pair [FATAL:%s]\n",PROGRAM); + + + seq_in=(job->param)->seq_c; + sprintf (seq, "%s", seq_in); + seqlist=string2num_list (seq); + n=seqlist[1]; + if ( n!=2){fprintf ( stderr, "\nERROR: best_pair can only handle two seq at a time [FATAL]\n");myexit (EXIT_FAILURE);} + s1=seqlist[2]; + s2=seqlist[3]; + + T1=S->T[s1]; + T2=S->T[s2]; + r1=T1->R; + r2=T2->R; + p1=T1->P; + p2=T2->P; + + PW_CL=((job->param)->TCM)->PW_CL; + CL=(job->io)->CL; + + if (!blosum)blosum=read_matrice ("blosum62mt"); + + id=idscore_pairseq (S->seq[s1], S->seq[s2],-10,-1,blosum, "sim"); + + + proba_pairM=method_file2TC_method(method_name2method_file ("proba_pair")); + proba_pairM->PW_CL=method2pw_cl(proba_pairM, CL); + + sap_pairM=method_file2TC_method(method_name2method_file ("sap_pair")); + sap_pairM->PW_CL=method2pw_cl(sap_pairM, CL); + + if ( id>80) + { + //Hide The Template + T1->R=NULL; + T2->R=NULL; + fprintf ( stderr, "\n\t%-*s %-*s: Direct Sequence Alignment\n", ml,S->name[s1], ml,S->name[s2]); + (job->param)->TCM=proba_pairM; + } + else if ( p1 && p2) + { + //Avoid Structural Tem + T1->R=NULL; + T2->R=NULL; + fprintf ( stderr, "\n\t%-*s %-*s: Structure Based Alignment\n", ml,S->name[s1], ml,S->name[s2]); + (job->param)->TCM=sap_pairM; + } + else if ( r1 || r2) + { + fprintf ( stderr, "\n\tt%-*s %-*s: PSIBLAST Profile Alignment\n", ml,S->name[s1], ml,S->name[s2]); + (job->param)->TCM=proba_pairM; + } + else + { + fprintf ( stderr, "\n\t%-*s %-*s: Direct Sequence Alignment (No Profile)\n", ml,S->name[s1], ml,S->name[s2]); + (job->param)->TCM=proba_pairM; + } + + RCL=seq2list (job); + T1->R=r1; + T2->R=r2; + + return RCL; +} + + +Alignment * fast_pair (Job_TC *job) + { + int s, n,a; + int score; + static int **l_s; + static int *ns; + char seq[1000]; + Alignment *A; + Constraint_list *PW_CL; + Constraint_list *CL; + char *seq_in; + Sequence *S; + TC_method *M; + int*seqlist; + char **buf; + + A=(job->io)->A; + + M=(job->param)->TCM; + PW_CL=((job->param)->TCM)->PW_CL; + CL=(job->io)->CL; + seq_in=(job->param)->seq_c; + + + sprintf (seq, "%s", seq_in); + seqlist=string2num_list (seq); + n=seqlist[1]; + if ( n!=2){fprintf ( stderr, "\nERROR: fast_pw_aln can only handle two seq at a time [FATAL]\n");myexit (EXIT_FAILURE);} + + S=(CL)->S; + + if (!A) {A=declare_aln (CL->S);} + if ( !ns) + { + ns=vcalloc ( 2, sizeof (int)); + l_s=declare_int (2,(CL->S)->nseq); + } + buf=vcalloc ( S->nseq, sizeof (char*)); + + for ( a=0; a< n; a++) + { + s=seqlist[a+2]; + if ( strm (M->seq_type, "G")) + { + buf[s]=S->seq[s]; + S->seq[s]=((((S->T[s])->G)->VG)->S)->seq[0]; + } + else + buf[s]=S->seq[s]; + + + sprintf ( A->seq_al[a], "%s",S->seq[s]); + sprintf ( A->name[a], "%s", (CL->S)->name[s]); + A->order[a][0]=s; + } + + A->S=CL->S; + PW_CL->S=CL->S; + A->CL=CL; + A->nseq=n; + ns[0]=ns[1]=1; + l_s[0][0]=0; + l_s[1][0]=1; + + //Preprocessing of the sequences + if (PW_CL->reverse_seq) + { + invert_string2(A->seq_al[0]); + invert_string2(A->seq_al[1]); + invert_string2 ((CL->S)->seq[A->order[0][0]]); + invert_string2 ((CL->S)->seq[A->order[1][0]]); + } + if (PW_CL->extend_seq)//use te alphabet extension for nucleic acids + { + + extend_seqaln (A->S,NULL); + extend_seqaln (NULL,A); + } + + score=pair_wise ( A, ns, l_s, PW_CL); + //PostProcessing of the sequences + if (PW_CL->reverse_seq) + { + + invert_string2(A->seq_al[0]); + invert_string2(A->seq_al[1]); + invert_string2 ((CL->S)->seq[A->order[0][0]]); + invert_string2 ((CL->S)->seq[A->order[1][0]]); + } + if (PW_CL->extend_seq) + { + unextend_seqaln (A->S,NULL); + unextend_seqaln (NULL,A); + } + A->nseq=n; + + for ( a=0; anseq; a++) + { + if ( !buf[a] || buf[a]==S->seq[a]); + else S->seq[a]=buf[a]; + } + vfree (buf);vfree (seqlist); + return A; + + } +Alignment * align_two_aln ( Alignment *A1, Alignment *A2, char *in_matrix, int gop, int gep, char *in_align_mode) + { + Alignment *A=NULL; + Constraint_list *CL; + Sequence *S; + int a; + int *ns; + int **ls; + static char *matrix; + static char *align_mode; + + if (!matrix)matrix=vcalloc ( 100, sizeof (char)); + if (!align_mode)align_mode=vcalloc ( 100, sizeof (char)); + + + + sprintf ( matrix, "%s", in_matrix); + sprintf ( align_mode, "%s", in_align_mode); + + CL=vcalloc ( 1, sizeof (Constraint_list)); + CL->pw_parameters_set=1; + CL->M=read_matrice (matrix); + CL->matrices_list=declare_char (10, 10); + + CL->evaluate_residue_pair=evaluate_matrix_score; + CL->get_dp_cost=consensus_get_dp_cost; + CL->normalise=1; + + CL->extend_jit=0; + CL->maximise=1; + CL->gop=gop; + CL->gep=gep; + CL->TG_MODE=2; + sprintf (CL->matrix_for_aa_group, "vasiliky"); + CL->use_fragments=0; + CL->ktup=5; + if ( !CL->use_fragments)CL->diagonal_threshold=0; + else CL->diagonal_threshold=6; + + sprintf (CL->dp_mode, "%s", align_mode); + + A=copy_aln (A1, A); + A=stack_aln (A, A2); + CL->S=fill_sequence_struc(A->nseq, A->seq_al,A->name); + + ns=vcalloc ( 2, sizeof(int)); + ls=declare_int ( 2,A->nseq); + ns[0]=A1->nseq; + ns[1]=A2->nseq; + for ( a=0; anseq; + + A->score_aln=pair_wise (A, ns, ls,CL); + + vfree (ns); + free_int (ls, -1); + S=free_constraint_list (CL); + free_sequence (S,-1); + A->S=NULL; + return A; + } + +static int align_two_seq_keep_case; +void toggle_case_in_align_two_sequences(int value) +{ + align_two_seq_keep_case=value; +} +Alignment * align_two_sequences ( char *seq1, char *seq2, char *in_matrix, int gop, int gep, char *in_align_mode) + { + static Alignment *A; + Constraint_list *CL; + Sequence *S; + + int *ns; + int **l_s; + + char **seq_array; + char **name_array; + static char *matrix; + static int **M; + + static char *align_mode; + + if (!matrix)matrix=vcalloc ( 100, sizeof (char)); + if (!align_mode)align_mode=vcalloc ( 100, sizeof (char)); + sprintf ( align_mode, "%s", in_align_mode); + + CL=vcalloc ( 1, sizeof (Constraint_list)); + + CL->pw_parameters_set=1; + + CL->matrices_list=declare_char (10, 10); + + + if ( !strm (matrix, in_matrix)) + { + sprintf ( matrix,"%s", in_matrix); + M=CL->M=read_matrice (matrix); + + } + else + { + CL->M=M; + } + + if (strstr (in_align_mode, "cdna")) + CL->evaluate_residue_pair=evaluate_cdna_matrix_score; + else + CL->evaluate_residue_pair=evaluate_matrix_score; + + CL->get_dp_cost=get_dp_cost; + CL->extend_jit=0; + CL->maximise=1; + CL->gop=gop; + CL->gep=gep; + CL->TG_MODE=2; + sprintf (CL->matrix_for_aa_group, "vasiliky"); + CL->use_fragments=0; + CL->ktup=3; + if ( !CL->use_fragments)CL->diagonal_threshold=0; + else CL->diagonal_threshold=6; + + sprintf (CL->dp_mode, "%s", align_mode); + + seq_array=declare_char ( 2, MAX(strlen(seq1), strlen (seq2))+1); + sprintf (seq_array[0], "%s",seq1); + sprintf (seq_array[1],"%s", seq2); + ungap_array(seq_array,2); + if (align_two_seq_keep_case !=KEEP_CASE)string_array_lower(seq_array,2); + + name_array=declare_char (2, STRING); + sprintf ( name_array[0], "A"); + sprintf ( name_array[1], "B"); + + + ns=vcalloc ( 2, sizeof(int)); + l_s=declare_int ( 2, 1); + ns[0]=ns[1]=1; + l_s[0][0]=0; + l_s[1][0]=1; + + + + CL->S=fill_sequence_struc(2, seq_array, name_array); + + A=seq2aln(CL->S, NULL, 1); + + ungap (A->seq_al[0]); + ungap (A->seq_al[1]); + + + + A->score_aln=pair_wise (A, ns, l_s,CL); + + vfree (ns); + free_int (l_s, -1); + free_char (name_array, -1);free_char ( seq_array,-1); + + CL->M=NULL; + S=free_constraint_list (CL); + free_sequence (S,-1); + A->S=NULL; + return A; + } + + +NT_node make_root_tree ( Alignment *A,Constraint_list *CL,int gop, int gep,Sequence *S, char *tree_file,int maximise) +{ + NT_node **T=NULL; + T=make_tree (A, CL, gop, gep,S,tree_file,maximise); + (T[3][0])->nseq=S->nseq; + return T[3][0]; +} +NT_node ** make_tree ( Alignment *A,Constraint_list *CL,int gop, int gep,Sequence *S, char *tree_file,int maximise) + { + int a, b, ra, rb; + NT_node **T=NULL; + int **distances; + int out_nseq; + char **out_seq_name; + char **out_seq; + + + if ( !CL || !CL->tree_mode || !CL->tree_mode[0]) + { + fprintf ( stderr, "\nERROR: No CL->tree_mode specified (make_tree::util_dp_drivers.c [FATAL:%s]", PROGRAM); + myexit (EXIT_FAILURE); + } + else + fprintf (CL->local_stderr , "\nMAKE GUIDE TREE \n\t[MODE=%s][",CL->tree_mode); + + + if ( A->nseq==2) + { + int tot_node; + char *tmp; + FILE *fp; + fprintf (CL->local_stderr, "---Two Sequences Only: Make Dummy Pair-Tree ---]"); + tmp=vtmpnam (NULL); + fp=vfopen (tmp,"w"); + fprintf ( fp, "(%s:0.1, %s:0.1):0.1;\n",S->name[0], S->name[1]); + vfclose (fp); + T=read_tree (tmp, &tot_node, (CL->S)->nseq,(CL->S)->name); + + return T; + } + else if ( strm (CL->tree_mode, "cwph")) + { + return seq2cw_tree ( S, tree_file); + } + + else if (strm ( CL->tree_mode, "upgma") || strm ( CL->tree_mode, "nj")) + { + out_nseq=S->nseq; + out_seq_name=S->name; + out_seq=S->seq; + + CL->DM=cl2distance_matrix (CL, NOALN,NULL,NULL,0); + + if ( CL->S!=S) + { + /*Shrink the distance matrix so that it only contains the required sequences*/ + distances=declare_int (S->nseq, S->nseq); + for (a=0; a< S->nseq; a++) + { + ra=name_is_in_list ((S)->name[a],(CL->S)->name, (CL->S)->nseq, 100); + for ( b=0; b< S->nseq; b++) + { + rb=name_is_in_list ((S)->name[b],(CL->S)->name, (CL->S)->nseq, 100); + distances[a][b]=(CL->DM)->score_similarity_matrix[ra][rb]; + } + } + } + else + { + distances=duplicate_int ( (CL->DM)->score_similarity_matrix, -1, -1); + } + + + + distances=sim_array2dist_array (distances, MAXID*SCORE_K); + distances=normalize_array (distances, MAXID*SCORE_K, 100); + if ( strm (CL->tree_mode, "order")) + { + for ( a=0; a< S->nseq; a++) + for ( b=0; b< S->nseq; b++) + distances[b][a]=100; + T=make_nj_tree (A,distances,gop,gep,out_seq,out_seq_name,out_nseq, tree_file, CL->tree_mode); + } + else if ( strm (CL->tree_mode, "nj")) + { + T=make_nj_tree (A,distances,gop,gep,out_seq,out_seq_name,out_nseq, tree_file, CL->tree_mode); + } + else if ( strm (CL->tree_mode, "upgma")) + T=make_upgma_tree (A,distances,gop,gep,out_seq,out_seq_name,out_nseq, tree_file, CL->tree_mode); + else + { + printf_exit (EXIT_FAILURE, stderr, "ERROR: %s is an unknown tree computation mode [FATAL:%s]", CL->tree_mode, PROGRAM); + } + free_int (distances, out_nseq); + + } + + fprintf (CL->local_stderr , "DONE]\n"); + return T; + } + + +Alignment *recompute_local_aln (Alignment *A, Sequence *S,Constraint_list *CL, int scale, int gep) + { + int **coor; + int a; + Alignment *B; + + sort_constraint_list (CL, 0, CL->ne); + coor=declare_int (A->nseq, 3); + for ( a=0; a< A->nseq; a++) + { + coor[a][0]=A->order[a][0]; + coor[a][1]=A->order[a][1]+1; + coor[a][2]=strlen(S->seq[A->order[a][0]])-coor[a][1]; + } + B=stack_progressive_nol_aln_with_seq_coor(CL,0,0,S,coor,A->nseq); + A=copy_aln ( B, A); + + free_Alignment(B); + return A; + } + + +Alignment *stack_progressive_nol_aln_with_seq_coor(Constraint_list *CL,int gop, int gep,Sequence *S, int **seq_coor, int nseq) + { + + static int ** local_coor1; + static int ** local_coor2; + if ( local_coor1!=NULL)free_int (local_coor1, -1); + if ( local_coor2!=NULL)free_int (local_coor2, -1); + + local_coor1=get_nol_seq ( CL,seq_coor, nseq, S); + local_coor2=minimise_repeat_coor ( local_coor1, nseq, S); + + return stack_progressive_aln_with_seq_coor(CL,gop, gep,S, local_coor2,nseq); + } + + +Alignment *stack_progressive_aln_with_seq_coor (Constraint_list*CL,int gop, int gep, Sequence *S, int **coor, int nseq) + { + Alignment *A=NULL; + + A=seq_coor2aln (S,NULL, coor, nseq); + + return stack_progressive_aln ( A,CL, gop, gep); + } + +Alignment *est_progressive_aln(Alignment *A, Constraint_list *CL, int gop, int gep) + { + int a,n; + int**group_list; + int *n_groups; + char *seq; + n_groups=vcalloc ( 2, sizeof (int)); + group_list=declare_int ( 2, A->nseq); + + n=A->nseq; + + n_groups[0]=1; + n_groups[1]=1; + group_list[0][0]=0; + group_list[0][1]=1; + + group_list[1][0]=1; + fprintf ( stderr, "\n"); + for ( a=1; aseq_al[1], "%s", A->seq_al[a]); + fprintf ( stderr, "\t[%30s]->[len=%5d]", A->name[a],(int)strlen ( A->seq_al[0])); + pair_wise ( A,n_groups, group_list, CL); + + seq=dna_aln2cons_seq(A); + + sprintf ( A->seq_al[0], "%s", seq); + vfree (seq); + fprintf ( stderr, "\n"); + } + + A->nseq=1; + return A; + } + +void analyse_seq ( Alignment *A, int s) + { + int a, b, c; + int r; + + int len=0; + + + int state=0; + int pstate=-1; + float score=0; + + for ( a=0; a< A->len_aln; a++) + { + for ( b=0, c=0; b< s; b++) + if ( !is_gap(A->seq_al[b][a])){c=1; break;} + + r=!is_gap(A->seq_al[s][a]); + + if ( r && c) state=1; + else if ( !r && !c) state=2; + else if ( !r && c) state=3; + else if ( r && !c) state=4; + + if ( state !=pstate) + { + score+=len*len; + len=0; + } + len+=r; + pstate=state; + } + score=score/(float)(((A->S)->len[s]*(A->S)->len[s])); + fprintf ( stderr, "[%.2f]", score); + + return; + } + +Alignment *realign_aln ( Alignment*A, Constraint_list *CL) +{ + int a, b, c; + int *ns, **ls; + A=reorder_aln (A, (CL->S)->name,(CL->S)->nseq); + + ns=vcalloc (2, sizeof(int)); + ls=declare_int ( 2, A->nseq); + + for (a=0; a< A->nseq; a++) + { + ns[0]=A->nseq-1; + for (c=0,b=0; bnseq; b++)if (b!=a)ls[0][c++]=b; + ungap_sub_aln ( A, ns[0], ls[0]); + + ns[1]=1; + ls[1][0]=a; + ungap_sub_aln ( A, ns[1], ls[1]); + A->score_aln=pair_wise (A, ns, ls,CL); + } + + vfree (ns); free_int (ls, -1); + return A; +} + +Alignment *realign_aln_random_bipart ( Alignment*A, Constraint_list *CL) +{ + int *ns; + int **l_s; + + int a,g; + + ns=vcalloc (2, sizeof (int)); + l_s=declare_int (2,A->nseq); + + for ( a=0; a< A->nseq; a++) + { + g=rand()%2; + l_s[g][ns[g]++]=a; + } + + fprintf ( stderr, "\n"); + ungap_sub_aln ( A, ns[0], l_s[0]); + ungap_sub_aln ( A, ns[1], l_s[1]); + + /* //Display Groups + for (a=0;a<2; a++) + for (b=0; bscore_aln=pair_wise (A, ns, l_s,CL); + + vfree(ns);free_int(l_s, -1); + return A; +} +Alignment *realign_aln_random_bipart_n ( Alignment*A, Constraint_list *CL, int n) +{ + int *ns; + int **ls; + int *used; + + int a,b,c, p; + + if (n>=A->nseq)n=A->nseq/2; + used=vcalloc (A->nseq, sizeof (int)); + c=0; + while (cnseq; + if (!used[p]){used[p]=1;c++;} + } + ns=vcalloc (2, sizeof (int)); + ls=declare_int (2,A->nseq); + for (a=0; a<2; a++) + { + for (b=0; bnseq; b++) + if (used[b]==a)ls[a][ns[a]++]=b; + } + ungap_sub_aln ( A, ns[0], ls[0]); + ungap_sub_aln ( A, ns[1], ls[1]); + + + A->score_aln=pair_wise (A, ns, ls,CL); + vfree(ns);free_int(ls, -1);vfree (used); + return A; +} +int ** seq2ecl_mat (Constraint_list *CL); +int ** seq2ecl_mat (Constraint_list *CL) + +{ + int a, b, n; + + Alignment *A; + int *ns, **ls; + int **dm; + + ns=vcalloc (2, sizeof (int)); + ls=declare_int ((CL->S)->nseq, 2); + + A=seq2aln (CL->S,NULL, RM_GAP); + n=(CL->S)->nseq; + dm=declare_int (n, n); + for (a=0; a<(CL->S)->nseq-1; a++) + for (b=a+1; b<(CL->S)->nseq; b++) + { + ns[0]=ns[1]=1; + ls[0][0]=a; + ls[1][0]=b; + ungap (A->seq_al[a]); + ungap (A->seq_al[b]); + dm[a][b]=dm[b][a]=linked_pair_wise (A, ns, ls, CL); + } + + return dm; +} +Alignment *realign_aln_clust ( Alignment*A, Constraint_list *CL) +{ + int *ns; + int **ls; + + int a, b, c,n; + static int **rm, **dm, **target; + int score; + + + + if (!A) + { + free_int (dm, -1); free_int (rm, -1);free_int (target, -1); + dm=rm=target=NULL; + } + + + if (!rm)rm=seq2ecl_mat(CL); + if (!dm)dm=declare_int (A->nseq, A->nseq); + if (!target)target=declare_int (A->nseq*A->nseq, 3); + + ns=vcalloc (2, sizeof (int)); + ls=declare_int (2,A->nseq); + + + for (a=0; anseq-1; a++) + for (b=a+1; bnseq; b++) + { + ns[0]=2; + ls[0][0]=a; + ls[0][1]=b; + score=sub_aln2ecl_raw_score (A, CL, ns[0], ls[0]); + dm[a][b]=dm[b][a]=MAX(0,(rm[a][b]-score)); + } + for (n=0,a=0; anseq; a++) + { + for (b=a; bnseq; b++, n++) + { + + target[n][0]=a; + target[n][1]=b; + for ( c=0; cnseq; c++) + { + if (c!=a && c!=b)target[n][2]+=dm[a][c]+dm[b][c]; + } + } + } + sort_int_inv (target,3, 2, 0, n-1); + + for (a=0; anseq; a++) + { + if (target[a][0]==target[a][1]) + { + ns[0]=1; + ls[0][0]=target[a][0]; + } + else + { + ns[0]=2; + ls[0][0]=target[a][0]; ls[0][1]=target[a][1]; + } + + for (ns[1]=0,b=0; bnseq; b++) + { + if (b!=target[a][0] && b!=target[a][1])ls[1][ns[1]++]=b; + } + + ungap_sub_aln (A, ns[0], ls[0]); + ungap_sub_aln (A, ns[1], ls[1]); + + A->score_aln=pair_wise (A, ns, ls,CL); + fprintf ( stderr, "\nSEQ: %d %d SCORE=%d\n",target[a][0],target[a][1], aln2ecl_raw_score(A, CL)); + } + return A; +} + +int get_best_group ( int **used, Constraint_list *CL); +int seq_aln_thr1(Alignment *A, int **used, int threshold, Constraint_list *CL); +int seq_aln_thr2( Alignment*A, int **used, int threshold, int g, Constraint_list *CL); + +int get_best_group ( int **used, Constraint_list *CL) +{ + int a,b,c,d,n, tot,stot, best_tot, best_seq, nseq; + int ns[2]; + int *ls[2]; + + best_seq=0; + nseq=((CL->S)->nseq); + tot=best_tot=0; + for (a=0; aDM)->similarity_matrix[ls[0][c]][ls[1][d]]; + } + if (n>0)stot/=n; + tot+=stot; + } + if (tot>best_tot) + { + best_tot=tot; + best_seq=a; + } + } + return best_seq; +} + + + +Alignment * seq2aln_group (Alignment *A, int N, Constraint_list *CL) +{ + + NT_node P; + int a; + + char *list, **list2; + Alignment *F; + + + fprintf (CL->local_stderr, "\n##### DPA ##### Compute Fast Alignment"); + A=iterative_tree_aln (A,1, CL); + fprintf (CL->local_stderr, "\n##### DPA ##### Identify Nodes"); + P=make_root_tree (A, CL, CL->gop, CL->gep,CL->S,NULL, 1); + set_node_score (A, P, "idmat_sim"); + fprintf (CL->local_stderr, "\n##### DPA ##### Split Nodes"); + list=split_nodes_nseq (A,P,N, list=vcalloc (P->nseq*200, sizeof (char))); + + list2=string2list (list); + fprintf (CL->local_stderr, "\n##### DPA ##### Save Nodes"); + + F=A; + for (a=1; aA=main_read_aln(list2[a], NULL); + A=A->A; + } + fprintf (CL->local_stderr, "\n##### DPA ##### Finished"); + vfree (list); free_char (list2, -1); + + A=F; + while (A) + { + A=A->A; + } + + return F; +} + + + + +Alignment * seq_aln ( Alignment*A, int n,Constraint_list *CL) +{ + + int **used, a, t,n1, nseq; + + + n1=nseq=(CL->S)->nseq; + used=declare_int (nseq, nseq+3); + + + for (a=0; a< nseq; a++) + { + used[a][1]=1; + used[a][2]=a; + } + + + for (t=50; t>=0 && nseq>1; t-=5) + { + nseq=seq_aln_thr1 (A, used,t, CL); + } + + vfree (used); + return A; +} + +int seq_aln_thrX(Alignment *A, int **used, int threshold, Constraint_list *CL) +{ + int n=0,a; + seq_aln_thr1(A,used,threshold,CL); + for ( a=0; a< (CL->S)->nseq; a++) + n+=(used[a][1]>0)?1:0; + + return n; +} +int seq_aln_thr1(Alignment *A, int **used, int threshold, Constraint_list *CL) +{ + int a,g, nseq, n_groups; + nseq=(CL->S)->nseq; + + g=get_best_group(used, CL); + + used[g][0]=1; + + + + while ( seq_aln_thr2 (A, used, threshold,g, CL)!=0) + { + g=get_best_group (used, CL); + used[g][0]=1; + } + + for (n_groups=0,a=0; a< nseq; a++) + if ( used[a][1]!=0) + { + n_groups++; + used[a][0]=0; + } + return n_groups; +} + + +int seq_aln_thr2( Alignment*A, int **used, int threshold, int g, Constraint_list *CL) +{ + int a, b,c,d; + int ns[2], *ls[2]; + int nseq, n_members; + double sim; + + n_members=0; + + nseq=((CL->S)->nseq); + used[g][0]=1; + ns[0]=used[g][1]; + ls[0]=used[g]+2; + + for ( a=0; a< nseq; a++) + { + if (used[a][0]!=0); + else + { + ns[1]=used[a][1]; + ls[1]=used[a]+2; + + ungap_sub_aln (A, ns[0], ls[0]); + ungap_sub_aln (A, ns[1], ls[1]); + + A->score_aln=pair_wise (A, ns, ls,CL); + + for (sim=0,b=0; bseq_al[ls[0][b]], A->seq_al[ls[1][c]], NULL,"idmat_sim2"); + } + } + sim/=(double)(ns[0]*ns[1]); + if (sim>=threshold) + { + + used[g][1]+=ns[1]; + for (d=0; d0)used[g][0]=-1; + return n_members; +} +/****************************************************************************/ +/* */ +/* */ +/* Alignment Methods */ +/* */ +/* */ +/****************************************************************************/ + +Alignment * tsp_aln (Alignment *A, Constraint_list *CL, Sequence *S) +{ + int a, b ; + int ** distances; + int *ns, **ls; + int **used; + + A=reorder_aln (A, (CL->S)->name,(CL->S)->nseq); + ns=vcalloc (2, sizeof (int)); + ls=declare_int (2, (CL->S)->nseq); + used=declare_int ( A->nseq, 2); + + + CL->DM=cl2distance_matrix (CL, NOALN,NULL,NULL,0); + distances=declare_int (A->nseq+1, A->nseq+1); + distances=duplicate_int ( (CL->DM)->score_similarity_matrix, -1, -1); + + for (a=0; a< A->nseq; a++) + { + used[a][0]=a; + for (b=0; b< A->nseq; b++) + { + used[a][1]+=distances[a][b]; + } + } + + sort_int_inv (used,2,1,0,(CL->S)->nseq-1); + + ls[0][ns[0]++]=used[0][0]; + ns[1]=1; + + for (a=1; a< S->nseq; a++) + { + fprintf ( stderr, "\n%s %d", (CL->S)->name[used[a][0]], used[a][1]); + ls[1][0]=used[a][0]; + pair_wise ( A,ns,ls, CL); + ls[0][ns[0]++]=used[a][0]; + } + + A->nseq=(CL->S)->nseq; + return A; + +} + +Alignment *stack_progressive_aln(Alignment *A, Constraint_list *CL, int gop, int gep) + { + int a,n; + int**group_list; + int *n_groups; + char dp_mode[100]; + + + sprintf ( dp_mode, "%s", CL->dp_mode); + sprintf (CL->dp_mode, "gotoh_pair_wise"); + + n_groups=vcalloc ( 2, sizeof (int)); + group_list=declare_int ( 2, A->nseq); + + n=A->nseq; + + for ( a=0; aseq_al[a]); + for ( a=1; a[%d]", a,(int)strlen ( A->seq_al[0])); + } + fprintf (stderr, "\n"); + vfree(n_groups); + free_int ( group_list, -1); + sprintf (CL->dp_mode, "%s",dp_mode); + + return A; + } +Alignment *realign_aln_clust ( Alignment*A, Constraint_list *CL); +Alignment *realign_aln_random_bipart_n ( Alignment*A, Constraint_list *CL, int n); +Alignment *iterate_aln ( Alignment*A, int nit, Constraint_list *CL) +{ + int it; + int mode=1; + int score, iscore, delta; + fprintf ( CL->local_stderr, "Iterated Refinement: %d cycles START: score= %d\n", nit,iscore=aln2ecl_raw_score (A, CL) ); + + + if ( nit==-1)nit=A->nseq*2; + if ( A->len_aln==0)A=very_fast_aln (A, A->nseq, CL); + A=reorder_aln (A,(CL->S)->name, A->nseq); + + for (it=0; it< nit; it++) + { + //CL->local_stderr=output_completion (CL->local_stderr,it, nit,1, ""); + if (mode==0)A=realign_aln (A, CL); + else if (mode ==1)A=realign_aln_random_bipart (A, CL); + else if (mode ==2)A=realign_aln_clust (A, CL); + else if (mode ==3)A=realign_aln_random_bipart_n (A, CL,2); + + + score=aln2ecl_raw_score (A, CL); + delta=iscore-score; + fprintf (CL->local_stderr, "\n\tIteration Cycle: %d Score=%d Improvement= %d", it+1,score, delta); + } + fprintf ( CL->local_stderr, "\nIterated Refinement: Completed Improvement=%d\n", delta); + return A; +} + +int get_next_best (int seq, int nseq, int *used, int **dm); +int get_next_best (int seq, int nseq, int *used, int **dm) +{ + int a,set, d, bd, bseq; + + for (set=0,a=0; a< nseq; a++) + { + if (used[a] || seq==a)continue; + d=dm[seq][a]; + if (set==0 || d>bd) + { + bseq=a; + bd=d; + set=1; + } + } + return bseq; +} +Alignment * full_sorted_aln (Alignment *A, Constraint_list *CL) +{ + int a,b; + A=sorted_aln_seq (0, A, CL); + print_aln(A); + for (a=1; anseq; a++) + { + A=A->A=copy_aln (A, NULL); + for (b=0; bnseq; b++)ungap(A->seq_al[b]); + A=sorted_aln_seq (a, A, CL); + print_aln(A); + } + return A; +} +Alignment * sorted_aln (Alignment *A, Constraint_list *CL) +{ + return sorted_aln_seq (-1, A, CL); +} +Alignment * sorted_aln_seq (int new_seq, Alignment *A, Constraint_list *CL) +{ + int a, b=0, nseq; + int *ns, **ls, **score, *used, **dm; + int old_seq; + + dm=(CL->DM)->score_similarity_matrix; + nseq=(CL->S)->nseq; + score=declare_int (nseq, 3); + used=vcalloc (nseq, sizeof (int)); + ls=declare_int (2, nseq); + ns=vcalloc (2, sizeof (int)); + + + if ( new_seq==-1) + { + for (a=0; ascore_aln=pair_wise (A, ns, ls,CL); + + } + return A; +} + +Alignment * ungap_aln4tree (Alignment *A); +Alignment * ungap_aln4tree (Alignment *A) +{ + int t, n, max_sim, sim; + Alignment *B; + + + + n=35; + max_sim=60; + + t=A->len_aln/10; + + B=copy_aln (A, NULL); + B=ungap_aln_n(B, n); + return B; + + sim=aln2sim (B, "idmat"); + while (B->len_alnmax_sim && n>0) + { + n-=10; + B=copy_aln (A, B); + B=ungap_aln_n(B, n); + sim=aln2sim (B, "idmat"); + } + if ( B->len_alnmax_sim)B=copy_aln (A, B); + return B; +} + + + +Alignment * iterative_tree_aln (Alignment *A,int n, Constraint_list *CL) +{ + NT_node **T=NULL; + int a; + + T=make_tree (A, CL, CL->gop, CL->gep,CL->S,NULL, 1); + tree_aln ((T[3][0])->left,(T[3][0])->right,A,(CL->S)->nseq, CL); + for ( a=0; a< n; a++) + { + + Alignment *B; + + B=copy_aln (A, NULL); + B=ungap_aln_n (B, 20); + sprintf ( CL->distance_matrix_mode, "aln"); + + CL->DM=cl2distance_matrix ( CL,B,NULL,NULL, 1); + free_aln (B); + + degap_aln (A); + T=make_tree (A, CL, CL->gop, CL->gep,CL->S,NULL, 1); + + tree_aln ((T[3][0])->left,(T[3][0])->right,A,(CL->S)->nseq, CL); + } + return A; +} + +Alignment *profile_aln (Alignment *A, Constraint_list *CL) +{ + int a,nseq,nseq2; + int **ls, *ns; + nseq=A->nseq; + nseq2=2*nseq; + ls=declare_int (2, nseq2); + ns=vcalloc (2, sizeof (int)); + + A=realloc_aln2(A,nseq2, A->len_aln); + for (a=0; a< nseq; a++) + ls[0][ns[0]++]=a; + for ( a=0; aseq_al[a+nseq], "%s", (CL->S)->seq[a]); + sprintf (A->name[a+nseq], "%s", (CL->S)->name[a]); + A->order[a+nseq][0]=a; + } + + ns[1]=1; + for (a=0; ascore_aln=pair_wise (A, ns, ls,CL); + + ls[0][ns[0]++]=a+nseq; + } + for (a=0; a< nseq; a++) + { + sprintf (A->seq_al[a], "%s", A->seq_al[a+nseq]); + } + A->nseq=nseq; + return A; +} + +Alignment * iterative_aln ( Alignment*A, int n,Constraint_list *CL) +{ + int *ns,**ls, **score, **dm; + int a,b, nseq, max; + ls=declare_int (2, A->nseq); + ns=vcalloc (2, sizeof (int)); + ls[0][ns[0]++]=0; + + + + + + nseq=(CL->S)->nseq; + score=declare_int (nseq,2); + dm=(CL->DM)->score_similarity_matrix; + for (a=0; aS)->name[score[a][0]],A->name[score[a][0]], score[a][1]); + ns[1]=1; + ls[1][0]=score[a][0]; + ungap_sub_aln ( A, ns[0], ls[0]); + ungap_sub_aln ( A, ns[1], ls[1]); + A->score_aln=pair_wise (A, ns, ls,CL); + ls[0][ns[0]++]=a; + } + + return A; +} +Alignment *simple_progressive_aln (Sequence *S, NT_node **T, Constraint_list *CL, char *mat) +{ + int a; + Alignment *A; + + + A=seq2aln (S, NULL, RM_GAP); + + if ( !CL) + { + + CL=declare_constraint_list (S, NULL, NULL, 0, NULL, NULL); + sprintf ( CL->dp_mode, "myers_miller_pair_wise"); + sprintf ( CL->tree_mode, "nj"); + sprintf ( CL->distance_matrix_mode, "idscore"); + CL=choose_extension_mode ("matrix", CL); + CL->gop=-10; + CL->gep=-1; + if (mat)CL->M=read_matrice (mat); + CL->pw_parameters_set=1; + CL->local_stderr=stderr; + } + + if ( !T)T=make_tree (A, CL, CL->gop, CL->gep,S, NULL,MAXIMISE); + for ( a=0; a< A->nseq; a++)ungap (A->seq_al[a]); + + tree_aln ((T[3][0])->left,(T[3][0])->right,A,(CL->S)->nseq, CL); + A=reorder_aln ( A,A->tree_order,A->nseq); + + return A; +} + +Alignment *very_fast_aln ( Alignment*A, int nseq, Constraint_list *CL) +{ +char command[10000]; +char *tmp_seq; +char *tmp_aln; +FILE *fp; + +if ( CL && CL->local_stderr)fp=CL->local_stderr; +else fp=stderr; + + fprintf (fp, "\n[Computation of an Approximate MSA..."); + tmp_seq= vtmpnam (NULL); + tmp_aln= vtmpnam (NULL); + output_fasta_seq ((tmp_seq=vtmpnam (NULL)), A); + sprintf ( command, "t_coffee -infile=%s -special_mode quickaln -outfile=%s %s -outorder=input", tmp_seq, tmp_aln, TO_NULL_DEVICE); + my_system ( command); + A->nseq=0; + A=main_read_aln (tmp_aln,A); + fprintf (fp, "]\n"); + return A; +} + +static NT_node* SNL; +NT_node* tree_aln ( NT_node LT, NT_node RT, Alignment*A, int nseq, Constraint_list *CL) +{ + int a; + + + + A->ibit=0; + if ( strm ((CL->TC)->use_seqan, "NO")) + { + static char *tmp; + NT_node *T; + if (!tmp)tmp=vtmpnam(NULL); + if ( CL && CL->dp_mode && strstr (CL->dp_mode, "collapse"))dump_constraint_list (CL, tmp, "w"); + T=local_tree_aln (LT, RT, A, nseq, CL); + + if ( CL && CL->dp_mode && strstr (CL->dp_mode, "collapse")) + { + empty_constraint_list (CL); + undump_constraint_list (CL, tmp); + + } + return T; + } + else return seqan_tree_aln (LT, RT, A, nseq, CL); + +} + +NT_node* seqan_tree_aln ( NT_node LT, NT_node RT, Alignment*A, int nseq, Constraint_list *CL) + { + + + Alignment *B; + + + char *tree, *lib, *seq, *new_aln; + + + //Output tree + tree=vtmpnam (NULL); + print_newick_tree (LT->parent, tree); + + + //Output seq + main_output_fasta_seq (seq=vtmpnam (NULL),B=seq2aln (CL->S,NULL,RM_GAP), NO_HEADER); + free_aln (B); + + //Output lib + new_aln=vtmpnam (NULL); + vfclose (save_constraint_list ( CL, 0, CL->ne,lib=vtmpnam(NULL), NULL, "ascii",CL->S)); + + fprintf (CL->local_stderr, "\n********* USE EXTERNAL ALIGNER: START:\n\tCOMMAND: %s -lib %s -seq %s -usetree %s -outfile %s\n", (CL->TC)->use_seqan,lib, seq, tree, new_aln); + printf_system ( "%s -lib %s -seq %s -usetree %s -outfile %s", (CL->TC)->use_seqan,lib, seq, tree, new_aln); + fprintf (CL->local_stderr, "\n********* USE EXTERNAL ALIGNER: END\n"); + + + main_read_aln (new_aln, A); + return tree2ao (LT,RT, A, A->nseq, CL); + + + + } +NT_node rec_local_tree_aln ( NT_node P, Alignment*A, Constraint_list *CL, int print); +NT_node* local_tree_aln ( NT_node l, NT_node r, Alignment*A,int nseq, Constraint_list *CL) +{ + int a; + NT_node P, *NL; + int **min=NULL; + + if (!r && !l) return NULL; + else if (!r)P=l; + else if (!l)P=r; + else P=r->parent; + + fprintf ( CL->local_stderr, "\nPROGRESSIVE_ALIGNMENT [Tree Based]\n"); + for ( a=0; alocal_stderr,"Group %4d: %s\n",a+1, A->name[a]); + //1: make sure the Alignment and the Sequences are labeled the same way + if (CL->translation)vfree (CL->translation); + CL->translation=vcalloc ( (CL->S)->nseq, sizeof (int)); + for ( a=0; a< (CL->S)->nseq; a++) + CL->translation[a]=name_is_in_list ( (CL->S)->name[a], (CL->S)->name, (CL->S)->nseq, MAXNAMES); + A=reorder_aln (A, (CL->S)->name,(CL->S)->nseq); + A->nseq=(CL->S)->nseq; + + //2 Make sure the tree is in the same order + recode_tree (P, (CL->S)); + index_tree_node(P); + initialize_scoring_scheme (CL); + + if ( get_nproc()>1 && strstr (CL->multi_thread, "msa")) + { + int max_fork; + + max_fork=get_nproc()/2;//number of nodes forked, one node =>two jobs + tree2nnode (P); + NL=tree2node_list (P, NULL); + min=declare_int (P->node+1,3); + for (a=0; a<=P->node; a++) + { + NT_node N; + N=NL[a]; + min[a][0]=a; + if (!N); + else if (N && N->nseq==1)min[a][1]=0; + else + { + min[a][1]=MIN(((N->left)->nseq),((N->right)->nseq))*A->nseq+MAX(((N->left)->nseq),((N->right)->nseq));//sort on min and break ties on max + min[a][2]=MIN(((N->left)->nseq),((N->right)->nseq)); + } + } + sort_int_inv (min,3, 1, 0, P->node); + for (a=0; a<=P->node && a1)(NL[min[a][0]])->fork=1; + } + } + free_int (min, -1); + rec_local_tree_aln (P, A,CL, 1); + for (a=0; anseq; a++)sprintf (A->tree_order[a], "%s", (CL->S)->name[P->lseq[a]]); + A->len_aln=strlen (A->seq_al[0]); + + fprintf ( CL->local_stderr, "\n\n"); + + return NULL; +} + +NT_node rec_local_tree_aln ( NT_node P, Alignment*A, Constraint_list *CL,int print) +{ + NT_node R,L; + int score; + + + if (!P || P->nseq==1) return NULL; + R=P->right;L=P->left; + + if (P->fork ) + { + int s, pid1, pid2; + char *tmp1, *tmp2; + tmp1=vtmpnam (NULL); + tmp2=vtmpnam (NULL); + + pid1=vvfork(NULL); + if (pid1==0) + { + if (print==1) + if (L->nseq>R->nseq)print=1; + + initiate_vtmpnam (NULL); + rec_local_tree_aln (L, A, CL, print); + dump_msa (tmp1,A, L->nseq, L->lseq); + myexit (EXIT_SUCCESS); + } + else + { + pid2=vvfork(NULL); + if (pid2==0) + { + if (print==1) + if (L->nseq>R->nseq)print=0; + + + initiate_vtmpnam (NULL); + rec_local_tree_aln (R, A, CL, print); + dump_msa (tmp2, A, R->nseq, R->lseq); + myexit (EXIT_SUCCESS); + } + } + vwaitpid (pid1, &s, 0); + vwaitpid (pid2, &s, 0); + + + undump_msa (A,tmp1); + undump_msa (A,tmp2); + } + else + { + rec_local_tree_aln (L, A, CL, print); + rec_local_tree_aln (R, A, CL, print); + } + + P->score=A->score_aln=score=profile_pair_wise (A,L->nseq, L->lseq,R->nseq,R->lseq,CL); + score=node2sub_aln_score (A, CL, CL->evaluate_mode,P); + A->len_aln=strlen (A->seq_al[P->lseq[0]]); + + if (print)fprintf(CL->local_stderr, "\n\tGroup %4d: [Group %4d (%4d seq)] with [Group %4d (%4d seq)]-->[Len=%5d][PID:%d]%s",P->index,R->index,R->nseq,L->index,L->nseq, A->len_aln,getpid(),(P->fork==1)?"[Forked]":"" ); + + return P; +} + + + +NT_node* tree2ao ( NT_node LT, NT_node RT, Alignment*A, int nseq, Constraint_list *CL) + { + int *n_s; + int ** l_s; + int a, b; + + static int n_groups_done, do_split=0; + int nseq2align=0; + int *translation; + + + NT_node P=NULL; + + + + + if (n_groups_done==0) + { + if (SNL)vfree(SNL); + SNL=vcalloc ( (CL->S)->nseq, sizeof (NT_node)); + + if (CL->translation)vfree(CL->translation); + CL->translation=vcalloc ( (CL->S)->nseq, sizeof (int)); + + for ( a=0; a< (CL->S)->nseq; a++) + CL->translation[a]=name_is_in_list ( (CL->S)->name[a], (CL->S)->name, (CL->S)->nseq, MAXNAMES); + + n_groups_done=(CL->S)->nseq; + A=reorder_aln (A, (CL->S)->name,(CL->S)->nseq); + A->nseq=nseq; + } + + translation=CL->translation; + n_s=vcalloc (2, sizeof ( int)); + l_s=declare_int ( 2, nseq); + + + if ( RT->parent !=LT->parent)fprintf ( stderr, "Tree Pb [FATAL:%s]", PROGRAM); + else P=RT->parent; + + if ( LT->leaf==1 && RT->leaf==0) + tree2ao ( RT->left, RT->right,A, nseq,CL); + + else if ( RT->leaf==1 && LT->leaf==0) + tree2ao ( LT->left, LT->right,A,nseq,CL); + + else if (RT->leaf==0 && LT->leaf==0) + { + tree2ao ( LT->left, LT->right,A,nseq,CL); + tree2ao ( RT->left, RT->right,A,nseq,CL); + } + + if ( LT->leaf==1 && RT->leaf==1) + { + /*1 Identify the two groups of sequences to align*/ + + nseq2align=LT->nseq+RT->nseq; + n_s[0]=LT->nseq; + for ( a=0; a< LT->nseq; a++)l_s[0][a]=translation[LT->lseq[a]]; + if ( LT->nseq==1)LT->group=l_s[0][0]; + + n_s[1]=RT->nseq; + for ( a=0; a< RT->nseq; a++)l_s[1][a]=translation[RT->lseq[a]]; + if ( RT->nseq==1)RT->group=l_s[1][0]; + + + P->group=n_groups_done++; + + if (nseq2align==nseq) + { + for (b=0, a=0; a< n_s[0]; a++, b++)sprintf ( A->tree_order[b],"%s", (CL->S)->name[l_s[0][a]]); + for (a=0; a< n_s[1] ; a++, b++)sprintf ( A->tree_order[b], "%s",(CL->S)->name[l_s[1][a]]); + n_groups_done=0; + } + } + if (P->parent)P->leaf=1; + if ( LT->isseq==0)LT->leaf=0; + if ( RT->isseq==0)RT->leaf=0; + + if (RT->isseq){SNL[translation[RT->lseq[0]]]=RT;RT->score=100;} + if (LT->isseq){SNL[translation[LT->lseq[0]]]=LT;LT->score=100;} + + do_split=split_condition (nseq2align,A->score_aln,CL); + if (CL->split && do_split) + { + + for (a=0; a< P->nseq; a++)SNL[CL->translation[P->lseq[a]]]=NULL; + SNL[CL->translation[RT->lseq[0]]]=P; + + } + + vfree ( n_s); + free_int ( l_s, 2); + return SNL; + + } + +NT_node* tree_realn ( NT_node LT, NT_node RT, Alignment*A, int nseq, Constraint_list *CL) + { + int *n_s; + int ** l_s; + int a, b; + int score; + static int n_groups_done; + int nseq2align=0; + int *translation; + + + NT_node P=NULL; + + + + + if (n_groups_done==0) + { + if (SNL)vfree(SNL); + SNL=vcalloc ( (CL->S)->nseq, sizeof (NT_node)); + + if (CL->translation)vfree(CL->translation); + CL->translation=vcalloc ( (CL->S)->nseq, sizeof (int)); + + for ( a=0; a< (CL->S)->nseq; a++) + CL->translation[a]=name_is_in_list ( (CL->S)->name[a], (CL->S)->name, (CL->S)->nseq, MAXNAMES); + if (nseq>2)fprintf ( CL->local_stderr, "\nPROGRESSIVE_ALIGNMENT [Tree Based]\n"); + else fprintf ( CL->local_stderr, "\nPAIRWISE_ALIGNMENT [No Tree]\n"); + n_groups_done=(CL->S)->nseq; + A=reorder_aln (A, (CL->S)->name,(CL->S)->nseq); + A->nseq=nseq; + } + + translation=CL->translation; + n_s=vcalloc (2, sizeof ( int)); + l_s=declare_int ( 2, nseq); + + + if ( nseq==2) + { + n_s[0]=n_s[1]=1; + l_s[0][0]=name_is_in_list ((CL->S)->name[0],(CL->S)->name, (CL->S)->nseq, MAXNAMES); + l_s[1][0]=name_is_in_list ((CL->S)->name[1],(CL->S)->name, (CL->S)->nseq, MAXNAMES); + A->score_aln=score=pair_wise (A, n_s, l_s,CL); + + vfree ( n_s); + free_int ( l_s, 2); + return SNL; + } + else + { + if ( RT->parent !=LT->parent)fprintf ( stderr, "Tree Pb [FATAL:%s]", PROGRAM); + else P=RT->parent; + + if ( LT->leaf==1 && RT->leaf==0) + tree_realn ( RT->left, RT->right,A, nseq,CL); + + else if ( RT->leaf==1 && LT->leaf==0) + tree_realn ( LT->left, LT->right,A,nseq,CL); + + else if (RT->leaf==0 && LT->leaf==0) + { + tree_realn ( LT->left, LT->right,A,nseq,CL); + tree_realn ( RT->left, RT->right,A,nseq,CL); + } + + if ( LT->leaf==1 && RT->leaf==1 && (RT->nseq+LT->nseq)nseq; a++) + { + s=translation[LT->lseq[a]]; + list[s]=1; + } + for (a=0; anseq; a++) + { + s=translation[RT->lseq[a]]; + list[s]=1; + } + for (a=0; ascore=A->score_aln=score=pair_wise (A, n_s, l_s,CL); + id2=sub_aln2sim (A, n_s, l_s, "idmat_sim"); + + + + + if (nseq2align==nseq) + { + for (b=0, a=0; a< n_s[0]; a++, b++)sprintf ( A->tree_order[b],"%s", (CL->S)->name[l_s[0][a]]); + for (a=0; a< n_s[1] ; a++, b++)sprintf ( A->tree_order[b], "%s",(CL->S)->name[l_s[1][a]]); + n_groups_done=0; + } + } + if (P->parent)P->leaf=1; + //Recycle the tree + if ( LT->isseq==0)LT->leaf=0; + if ( RT->isseq==0)RT->leaf=0; + + if (RT->isseq){SNL[translation[RT->lseq[0]]]=RT;RT->score=100;} + if (LT->isseq){SNL[translation[LT->lseq[0]]]=LT;LT->score=100;} + + vfree ( n_s); + free_int ( l_s, 2); + return SNL; + } + + + } + + + +Alignment* profile_tree_aln ( NT_node P,Alignment*A,Constraint_list *CL, int threshold) +{ + int *ns, **ls, a, sim; + NT_node LT, RT, D, UD; + Alignment *F; + static NT_node R; + static int n_groups_done; + + + //first pass + //Sequences must be in the same order as the tree sequences + if (!P->parent) + { + R=P; + n_groups_done=P->nseq+1; + } + + LT=P->left; + RT=P->right; + + if (LT->leaf==0)A=delayed_tree_aln1 (LT, A,CL, threshold); + if (RT->leaf==0)A=delayed_tree_aln1 (RT, A,CL, threshold); + + ns=vcalloc (2, sizeof (int)); + ls=declare_int ( 2,R->nseq); + + if ( LT->nseq==1) + { + ls[0][ns[0]++]=LT->lseq[0]; + LT->group=ls[0][0]+1; + } + else + node2seq_list (LT,&ns[0], ls[0]); + + if ( RT->nseq==1) + { + ls[1][ns[1]++]=RT->lseq[0]; + RT->group=ls[1][0]+1; + } + else + node2seq_list (RT,&ns[1], ls[1]); + + + P->group=++n_groups_done; + fprintf (CL->local_stderr, "\n\tGroup %4d: [Group %4d (%4d seq)] with [Group %4d (%4d seq)]-->",P->group,RT->group, ns[1],LT->group, ns[0]); + + P->score=A->score_aln=pair_wise (A, ns, ls,CL); + sim=sub_aln2sim(A, ns, ls, "idmat_sim1"); + + if ( simaligned=1; + D->aligned=0; + + fprintf (CL->local_stderr, "[Delayed (Sim=%4d). Kept Group %4d]",sim,UD->group); + + + ungap_sub_aln (A, ns[0],ls[0]); + ungap_sub_aln (A, ns[1],ls[1]); + A->nseq=MAX(ns[0],ns[1]); + + F=A; + while (F->A)F=F->A; + F->A=main_read_aln (output_fasta_sub_aln (NULL, A, ns[(D==LT)?0:1], ls[(D==LT)?0:1]), NULL); + if ( P==R) + { + F=F->A; + F->A=main_read_aln (output_fasta_sub_aln (NULL, A, ns[(D==LT)?1:0], ls[(D==LT)?1:0]), NULL); + } + if (F->A==NULL) + { + printf_exit (EXIT_FAILURE, stderr, "\nError: Empty group"); + } + } + else + { + LT->aligned=1; RT->aligned=1; + fprintf (CL->local_stderr, "[Score=%4d][Len=%5d]",sub_aln2sub_aln_score (A, CL, CL->evaluate_mode,ns, ls), (int)strlen ( A->seq_al[ls[0][0]])); + A->nseq=ns[0]+ns[1]; + if (P==R) + { + F=A; + while (F->A)F=F->A; + F->A=main_read_aln (output_fasta_sub_aln2 (NULL, A, ns, ls), NULL); + } + } + P->nseq=0; + for (a=0; anseq;a++)P->lseq[P->nseq++]=LT->lseq[a]; + for (a=0; anseq;a++)P->lseq[P->nseq++]=RT->lseq[a]; + + P->aligned=1; + + vfree ( ns); + free_int ( ls,-1); + return A; +}//////////////////////////////////////////////////////////////////////////////////////// +// +// Frame Tree Aln +// +//////////////////////////////////////////////////////////////////////////////////////// + +//Alignment *frame_tree_aln (Alignment *A, Constraint_list *CL) +//{ + + +//////////////////////////////////////////////////////////////////////////////////////// +// +// Delayed Tree Aln +// +//////////////////////////////////////////////////////////////////////////////////////// +int delayed_pair_wise (Alignment *A, int *ns, int **ls,Constraint_list *CL); +NT_node* delayed_tree_aln_mode1 ( NT_node LT, NT_node RT, Alignment*A, int nseq, Constraint_list *CL); +NT_node* delayed_tree_aln_mode2 ( NT_node LT, NT_node RT, Alignment*A, int nseq, Constraint_list *CL); +int paint_nodes2aligned ( NT_node P,char **list, int n); + +int reset_visited_nodes ( NT_node P); +int reset_visited_nodes2 ( NT_node P); +Alignment * make_delayed_tree_aln (Alignment *A,int n, Constraint_list *CL) +{ + NT_node **T=NULL; + int a; + + T=make_tree (A, CL, CL->gop, CL->gep,CL->S,NULL, 1); + delayed_tree_aln_mode1 ((T[3][0])->left,(T[3][0])->right,A,(CL->S)->nseq, CL); + + for ( a=0; a< n; a++) + { + + sprintf ( CL->distance_matrix_mode, "aln"); + CL->DM=cl2distance_matrix ( CL,A,NULL,NULL, 1); + degap_aln (A); + T=make_tree (A, CL, CL->gop, CL->gep,CL->S,NULL, 1); + delayed_tree_aln_mode1 ((T[3][0])->left,(T[3][0])->right,A,(CL->S)->nseq, CL); + } + + return A; +} +NT_node* delayed_tree_aln_mode1 ( NT_node LT, NT_node RT, Alignment*A, int nseq, Constraint_list *CL) +{ + NT_node P; + + + + P=LT->parent;P->nseq=nseq; + paint_nodes2aligned (P, NULL, 0); + + A=delayed_tree_aln1 (P, A, CL,50); + A=delayed_tree_aln2 (P, A, CL, 0); + return NULL; +} + +NT_node* delayed_tree_aln_mode2 ( NT_node LT, NT_node RT, Alignment*A, int nseq, Constraint_list *CL) +{ + NT_node P; + + int thr=50; + + P=LT->parent;P->nseq=nseq; + + A=delayed_tree_aln1 (P, A, CL,thr); + thr-=10; + while (thr>=0) + { + A=delayed_tree_aln2 (P, A, CL, thr); + thr-=10; + } + return NULL; +} + +Alignment* delayed_tree_aln1 ( NT_node P,Alignment*A,Constraint_list *CL, int threshold) +{ + int *ns, **ls, a, sim; + NT_node LT, RT, D, UD; + + static NT_node R; + static int n_groups_done; + + + //first pass + //Sequences must be in the same order as the tree sequences + if (!P->parent) + { + R=P; + n_groups_done=P->nseq+1; + } + + LT=P->left; + RT=P->right; + + if (LT->leaf==0)A=delayed_tree_aln1 (LT, A,CL, threshold); + if (RT->leaf==0)A=delayed_tree_aln1 (RT, A,CL, threshold); + + ns=vcalloc (2, sizeof (int)); + ls=declare_int ( 2,R->nseq); + + + node2seq_list (LT,&ns[0], ls[0]); + if ( LT->nseq==1)LT->group=LT->lseq[0]+1; + + node2seq_list (RT,&ns[1], ls[1]); + if ( RT->nseq==1)RT->group=RT->lseq[0]+1; + + + P->group=++n_groups_done; + + + if ( ns[0]==0 || ns[1]==0) + { + fprintf (CL->local_stderr, "\n\tF-Group %4d: [Group %4d (%4d seq)] with [Group %4d (%4d seq)]-->Skipped",P->group,RT->group, ns[1],LT->group, ns[0]); + + LT->aligned=(ns[0]==0)?0:1; + RT->aligned=(ns[1]==0)?0:1; + } + else + { + fprintf (CL->local_stderr, "\n\tF-Group %4d: [Group %4d (%4d seq)] with [Group %4d (%4d seq)]-->",P->group,RT->group, ns[1],LT->group, ns[0]); + P->score=A->score_aln=pair_wise (A, ns, ls,CL); + sim=sub_aln2max_sim(A, ns, ls, "idmat_sim1"); + + + if ( simaligned=1; + D->aligned=0; + + fprintf (CL->local_stderr, "[Delayed (Sim=%4d). Kept Group %4d]",sim,UD->group); + + ungap_sub_aln (A, ns[0],ls[0]); + ungap_sub_aln (A, ns[1],ls[1]); + A->nseq=MAX(ns[0],ns[1]); + } + else + { + LT->aligned=1; RT->aligned=1; + fprintf (CL->local_stderr, "[Score=%4d][Len=%5d]",sub_aln2sub_aln_score (A, CL, CL->evaluate_mode,ns, ls), (int)strlen ( A->seq_al[ls[0][0]])); + A->nseq=ns[0]+ns[1]; + } + P->nseq=0; + for (a=0; anseq;a++)P->lseq[P->nseq++]=LT->lseq[a]; + for (a=0; anseq;a++)P->lseq[P->nseq++]=RT->lseq[a]; + + P->aligned=1; + } + vfree ( ns); + free_int ( ls,-1); + return A; +} + +Alignment* delayed_tree_aln2 ( NT_node P,Alignment*A,Constraint_list *CL, int thr) +{ + + NT_node LT, RT, D; + + static NT_node R; + + + LT=P->left; + RT=P->right; + if (!P->parent) + { + R=P; + fprintf (CL->local_stderr, "\n"); + } + if (!LT->aligned && !RT->aligned) + { + printf_exit (EXIT_FAILURE, stderr, "ERROR: Unresolved Node On Groups %d [FATAL:%s]\n", P->group,PROGRAM); + } + else if (!LT->aligned || !RT->aligned) + { + int *ns, **ls, sim; + ns=vcalloc (2, sizeof (int)); + ls=declare_int (2, R->nseq); + + node2seq_list (R,&ns[0], ls[0]); + + D=(!LT->aligned)?LT:RT; + D->aligned=1; + node2seq_list (D,&ns[1], ls[1]); + + fprintf (CL->local_stderr, "\tS-Delayed Group %4d: [Group %4d (%4d seq)] with [Group %4d (%4d seq)]-->",P->group,D->group, ns[1],R->group, ns[0]); + P->score=A->score_aln=pair_wise (A, ns, ls,CL); + sim=sub_aln2max_sim(A, ns, ls, "idmat_sim1"); + if (simlocal_stderr, " [Further Delayed]\n"); + ungap_sub_aln (A, ns[0],ls[0]); + ungap_sub_aln (A, ns[1],ls[1]); + D->aligned=0; + } + else + { + fprintf (CL->local_stderr, "[Score=%4d][Len=%5d][thr=%d]\n",sub_aln2sub_aln_score (A, CL, CL->evaluate_mode,ns, ls), (int)strlen ( A->seq_al[ls[0][0]]), thr); + D->aligned=1; + } + vfree (ns);free_int (ls, -1); + } + else + { + ; + } + + if (LT->leaf==0)A=delayed_tree_aln2 (LT, A,CL, thr); + if (RT->leaf==0)A=delayed_tree_aln2 (RT, A,CL, thr); + + return A; +} + +int delayed_pair_wise (Alignment *A, int *ns, int **ls,Constraint_list *CL) +{ + int s,s1, s2, a, b; + int **sim; + + + pair_wise (A, ns, ls, CL); + + sim=fast_aln2sim_list (A, "sim3", ns, ls); + + sort_int_inv ( sim,3, 2,0, ns[0]*ns[1]-1); + + for (a=0; a< 2; a++) + for ( b=0; b< ns[a]; b++) + A->order[ls[a][b]][4]=-1; + + for (a=0; a< 10 && sim[a][0]!=-1; a++) + { + s1=sim[a][0]; + s2=sim[a][1]; + A->order[s1][4]=0; + A->order[s2][4]=0; + } + + ungap_sub_aln (A, ns[0],ls[0]); + ungap_sub_aln (A, ns[1],ls[1]); + + s=pair_wise (A, ns, ls, CL); + + for (a=0; a< 2; a++) + for ( b=0; b< ns[a]; b++) + A->order[ls[a][b]][4]=0; + + free_int (sim, -1); + return s; +} + +int node2seq_list2 (NT_node P, int *ns, int *ls) +{ + + if ( !P || P->visited ) return ns[0]; + else P->visited=1; + + if ( P->isseq) + { + ls[ns[0]++]=P->lseq[0]; + } + + if (P->left && (P->left) ->aligned)node2seq_list2 (P->left, ns,ls); + if (P->right && (P->right)->aligned)node2seq_list2 (P->right,ns,ls); + if (P->aligned && P->parent)node2seq_list2 (P->parent,ns,ls); + + + return ns[0]; +} + +int node2seq_list (NT_node P, int *ns, int *ls) +{ + + if ( P->isseq && P->aligned) + { + ls[ns[0]++]=P->lseq[0]; + } + else + { + if (P->left && (P->left) ->aligned)node2seq_list (P->left, ns,ls); + if (P->right && (P->right)->aligned)node2seq_list (P->right,ns,ls); + } + return ns[0]; +} +int paint_nodes2aligned ( NT_node P,char **list, int n) +{ + int r=0; + if ( P->leaf) + { + if ( list==NULL) + P->aligned=1; + else if ( name_is_in_list ( P->name, list, n, 100)!=-1) + P->aligned=1; + else + P->aligned=0; + return P->aligned; + } + else + { + r+=paint_nodes2aligned (P->left, list, n); + r+=paint_nodes2aligned (P->right, list, n); + } + return r; +} + +int reset_visited_nodes ( NT_node P) +{ + while (P->parent)P=P->parent; + return reset_visited_nodes2 (P); +} +int reset_visited_nodes2 ( NT_node P) +{ + int r=0; + if (P->left)r+=reset_visited_nodes2(P->left); + if (P->right)r+=reset_visited_nodes2(P->right); + r+=P->visited; + P->visited=0; + return r; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// +// DPA_MSA +// +//////////////////////////////////////////////////////////////////////////////////////// + +Alignment* dpa_msa2 ( NT_node P,Alignment*A,Constraint_list *CL); +Alignment *dpa_align_node (NT_node P,Alignment*A,Constraint_list *CL); +char *node2profile_list (NT_node P,Alignment*A,Constraint_list *CL, char *list); +char * output_node_aln (NT_node P, Alignment *A, char *name); +int node2nleaf ( NT_node P); + +Alignment* dpa_aln (Alignment*A,Constraint_list *CL) +{ + NT_node P; + + A=iterative_tree_aln (A,1, CL); + P=make_root_tree (A, CL, CL->gop, CL->gep,CL->S,NULL, 1); + degap_aln (A); + while (!P->leaf) + A=dpa_msa2(P, A, CL); + return A; +} + +int node2nleaf ( NT_node P) +{ + int n=0; + if ( P->leaf) return 1; + else + { + n+=node2nleaf ( P->left); + n+=node2nleaf ( P->right); + } + return n; +} +Alignment* dpa_msa2 ( NT_node P,Alignment*A,Constraint_list *CL) +{ + int maxnseq=20; + int n, n_l, n_r; + n=node2nleaf (P); + + + if ( n>maxnseq) + { + n_l=node2nleaf (P->left); + n_r=node2nleaf (P->right); + if (n_l>n_r) + { + return dpa_msa2 (P->left, A, CL); + } + else + { + return dpa_msa2 (P->right, A, CL); + } + } + A=dpa_align_node (P, A, CL); + P->leaf=1; + return A; +} + +Alignment *dpa_align_node (NT_node P,Alignment*A,Constraint_list *CL) +{ + + char *list, *tmp_aln; + int a, b; + Alignment *B; + + + list=vcalloc ( P->nseq*100, sizeof (char)); + list=node2profile_list (P,A, CL, list); + + printf_system ( "t_coffee -profile %s -outfile=%s -dp_mode gotoh_pair_wise_lgp -msa_mode iterative_tree_aln -quiet", list,tmp_aln=vtmpnam (NULL)); + B=main_read_aln (tmp_aln, NULL); + A=realloc_aln (A, B->len_aln+1); + for ( a=0; a< B->nseq; a++) + if ( (b=name_is_in_list (B->name[a], A->name, A->nseq, 100))!=-1) + sprintf (A->seq_al[b], "%s", B->seq_al[a]); + A->len_aln=B->len_aln; + free_aln (B); + vfree (list); + return A; +} +char *node2profile_list (NT_node P,Alignment*A,Constraint_list *CL, char *list) +{ + if (!P->leaf) + { + list=node2profile_list (P->left, A, CL, list); + list=node2profile_list (P->right, A, CL, list); + } + else + { + + list=strcatf (list," %s", output_node_aln (P, A, NULL)); + if ( !P->isseq)P->leaf=0; + } + return list; +} +char * output_node_aln (NT_node P, Alignment *A, char *name) +{ + FILE *fp; + int a; + if (name==NULL) name=vtmpnam (NULL); + fp=vfopen (name, "w"); + + for (a=0; a< P->nseq; a++) + fprintf ( fp, ">%s\n%s", A->name[P->lseq[a]], A->seq_al[P->lseq[a]]); + vfclose (fp); + return name; +} +//////////////////////////////////////////////////////////////////////////////////////// +// +// NEW_DPA_MSA +// +//////////////////////////////////////////////////////////////////////////////////////// + +Alignment * new_dpa_aln (Alignment *A,Constraint_list *CL) +{ + NT_node P; + + char *tmp_aln; + char *list; + + A=make_delayed_tree_aln (A,1, CL); + P=make_root_tree (A, CL, CL->gop, CL->gep,CL->S,NULL, 1); + set_node_score (A, P, "idmat_sim"); + + + list=split_nodes_nseq (A,P,15, list=vcalloc (P->nseq*200, sizeof (char))); + printf_system ( "t_coffee -profile %s -outfile=%s -dp_mode gotoh_pair_wise_lgp -msa_mode iterative_tree_aln", list,tmp_aln=vtmpnam (NULL)); + return main_read_aln (tmp_aln, NULL); +} + +char *split_nodes_nseq (Alignment *A, NT_node P, int nseq, char *list) +{ + int a,n; + + n=P->nseq; + a=100; + while ( n>=nseq) + { + a--; + n=count_threshold_nodes (A, P, a); + } + + return split_nodes_idmax (A, P, a,list); +} +char *split_nodes_idmax (Alignment *A, NT_node P, int t, char *list) +{ + if (P->isseq || P->score>=t) + { + list=strcatf (list," %s", output_node_aln (P, A, NULL)); + } + else if ( P->scoreleft,t, list); + list=split_nodes_idmax (A, P->right,t,list); + } + return list; +} +int count_threshold_nodes (Alignment *A, NT_node P, int t) +{ + int s=0; + + if (P->isseq || P->score>=t) + { + s=1; + } + else if ( P->scoreleft,t); + s+=count_threshold_nodes (A, P->right,t); + } + + return s; +} +int set_node_score (Alignment *A, NT_node P, char *mode) +{ + int a; + int ns[2], *ls[2]; + + if (P->isseq) return 0; + for (a=0; a<2; a++) + { + NT_node N; + N=(a==0)?P->left:P->right; + ns[a]=N->nseq; + ls[a]=N->lseq; + } + P->score=sub_aln2max_sim(A, ns, ls,mode); + set_node_score (A,P->left, mode); + set_node_score (A,P->right, mode); + return 1; +} +///////////////////////////////////////////////////////////////////////////////////////// +int split_condition (int nseq, int score, Constraint_list *CL) +{ + int cond1=1, cond2=1; + + + if ( CL->split_nseq_thres)cond1 =(nseq<=CL->split_nseq_thres)?1:0; + if ( CL->split_score_thres)cond2=(score>=CL->split_score_thres)?1:0; + + return (cond1 && cond2); +} +int profile_pair_wise (Alignment *A, int n1, int *l1, int n2, int *l2, Constraint_list *CL) +{ + static int *ns; + static int **ls; + + if (!ns) + { + ns=vcalloc (2, sizeof (int)); + ls=vcalloc (2, sizeof (int*)); + } + ns[0]=n1; + ls[0]=l1; + ns[1]=n2; + ls[1]=l2; + return pair_wise (A, ns, ls, CL); +} +int pair_wise (Alignment *A, int*ns, int **l_s,Constraint_list *CL ) + { + /* + CL->maximise + CL->gop; + CL->gep + CL->TG_MODE; + */ + int score; + + int glocal; + Pwfunc function; + + + + /*Make sure evaluation functions update their cache if needed*/ + A=update_aln_random_tag (A); + + if (! CL->pw_parameters_set) + { + fprintf ( stderr, "\nERROR pw_parameters_set must be set in pair_wise [FATAL]\n" );crash(""); + } + + + function=get_pair_wise_function(CL->pair_wise, CL->dp_mode,&glocal); + if ( CL->get_dp_cost==NULL)CL->get_dp_cost=get_dp_cost; + + if (strlen ( A->seq_al[l_s[0][0]])==0 || strlen ( A->seq_al[l_s[1][0]])==0) + score=empty_pair_wise ( A, ns, l_s, CL, glocal); + else + score=function ( A, ns, l_s, CL); + + return score; + } + +int empty_pair_wise ( Alignment *A, int *ns, int **l_s, Constraint_list *CL, int glocal) +{ + int n=0, a, b; + int *l=NULL; + char *string; + int l0, l1, len; + + if ( glocal==GLOBAL) + { + l0=strlen (A->seq_al[l_s[0][0]]); + l1=strlen (A->seq_al[l_s[1][0]]); + len=MAX(l1,l0); + + if ( len==0)return 0; + else if (l0>l1){n=ns[1];l=l_s[1];} + else if (l0seq_al[l[a]], "%s", string); + A->score=A->score_aln=0; + A->len_aln=len; + vfree ( string); + return 0; + } + else if ( glocal==LALIGN) + { + A->A=declare_aln (A->S); + (A->A)->len_aln=0; + for ( a=0; a< 2; a++) + for ( b=0; bseq_al[l_s[a][b]][0]='\0'; + (A->A)->score_aln=(A->A)->score=0; + return 0; + } + else return 0; +} + + + + +Pwfunc get_pair_wise_function (Pwfunc pw,char *dp_mode, int *glocal) + { + /*Returns a function and a mode (Glogal, Local...)*/ + + + + int a; + static int npw; + static Pwfunc *pwl; + static char **dpl; + static int *dps; + + /*The first time: initialize the list of pairwse functions*/ + if ( npw==0) + { + pwl=vcalloc ( 100, sizeof (Pwfunc)); + dpl=declare_char (100, 100); + dps=vcalloc ( 100, sizeof (int)); + + pwl[npw]=fasta_cdna_pair_wise; + sprintf (dpl[npw], "fasta_cdna_pair_wise"); + dps[npw]=GLOBAL; + npw++; + + pwl[npw]=cfasta_cdna_pair_wise; + sprintf (dpl[npw], "cfasta_cdna_pair_wise"); + dps[npw]=GLOBAL; + npw++; + + pwl[npw]=idscore_pair_wise; + sprintf (dpl[npw], "idscore_pair_wise"); + dps[npw]=GLOBAL; + npw++; + + pwl[npw]=gotoh_pair_wise; + sprintf (dpl[npw], "gotoh_pair_wise"); + dps[npw]=GLOBAL; + npw++; + + pwl[npw]=gotoh_pair_wise_lgp; + sprintf (dpl[npw], "gotoh_pair_wise_lgp"); + dps[npw]=GLOBAL; + npw++; + + + pwl[npw]=proba_pair_wise; + sprintf (dpl[npw], "proba_pair_wise"); + dps[npw]=GLOBAL; + npw++; + + pwl[npw]=biphasic_pair_wise; + sprintf (dpl[npw], "biphasic_pair_wise"); + dps[npw]=GLOBAL; + npw++; + + pwl[npw]=subop1_pair_wise; + sprintf (dpl[npw], "subop1_pair_wise"); + dps[npw]=GLOBAL; + npw++; + + pwl[npw]=subop2_pair_wise; + sprintf (dpl[npw], "subop2_pair_wise"); + dps[npw]=GLOBAL; + npw++; + + pwl[npw]=myers_miller_pair_wise; + sprintf (dpl[npw], "myers_miller_pair_wise"); + dps[npw]=GLOBAL; + npw++; + + pwl[npw]=test_pair_wise; + sprintf (dpl[npw], "test_pair_wise"); + dps[npw]=GLOBAL; + npw++; + + pwl[npw]=fasta_gotoh_pair_wise; + sprintf (dpl[npw], "fasta_pair_wise"); + dps[npw]=GLOBAL; + npw++; + pwl[npw]=cfasta_gotoh_pair_wise; + sprintf (dpl[npw], "cfasta_pair_wise"); + dps[npw]=GLOBAL; + npw++; + + pwl[npw]=very_fast_gotoh_pair_wise; + sprintf (dpl[npw], "very_fast_pair_wise"); + dps[npw]=GLOBAL; + npw++; + + pwl[npw]=gotoh_pair_wise_sw; + sprintf (dpl[npw], "gotoh_pair_wise_sw"); + dps[npw]=LOCAL; + npw++; + + pwl[npw]=cfasta_gotoh_pair_wise_sw; + sprintf (dpl[npw], "cfasta_sw_pair_wise"); + dps[npw]=LOCAL; + npw++; + + pwl[npw]=gotoh_pair_wise_lalign; + sprintf (dpl[npw], "gotoh_pair_wise_lalign"); + dps[npw]=LALIGN; + npw++; + + pwl[npw]=sim_pair_wise_lalign; + sprintf (dpl[npw], "sim_pair_wise_lalign"); + dps[npw]=LALIGN; + npw++; + + pwl[npw]=domain_pair_wise; + sprintf (dpl[npw], "domain_pair_wise"); + dps[npw]=MOCCA; + npw++; + + pwl[npw]=gotoh_pair_wise; + sprintf (dpl[npw], "ssec_pair_wise"); + dps[npw]=GLOBAL; + npw++; + + pwl[npw]=ktup_pair_wise; + sprintf (dpl[npw], "ktup_pair_wise"); + dps[npw]=LOCAL; + npw++; + + pwl[npw]=precomputed_pair_wise; + sprintf (dpl[npw], "precomputed_pair_wise"); + dps[npw]=GLOBAL; + npw++; + + pwl[npw]=myers_miller_pair_wise; + sprintf (dpl[npw], "default"); + dps[npw]=GLOBAL; + npw++; + + pwl[npw]=viterbi_pair_wise; + sprintf (dpl[npw], "viterbi_pair_wise"); + dps[npw]=GLOBAL; + npw++; + + pwl[npw]=viterbiL_pair_wise; + sprintf (dpl[npw], "viterbiL_pair_wise"); + dps[npw]=GLOBAL; + npw++; + + pwl[npw]=viterbiD_pair_wise; + sprintf (dpl[npw], "viterbiD_pair_wise"); + dps[npw]=GLOBAL; + npw++; + + pwl[npw]=seq_viterbi_pair_wise; + sprintf (dpl[npw], "seq_viterbi_pair_wise"); + dps[npw]=GLOBAL; + npw++; + + pwl[npw]=pavie_pair_wise; + sprintf (dpl[npw], "pavie_pair_wise"); + dps[npw]=GLOBAL; + npw++; + + pwl[npw]=glocal_pair_wise; + sprintf (dpl[npw], "glocal_pair_wise"); + dps[npw]=GLOBAL; + npw++; + + pwl[npw]=linked_pair_wise; + sprintf (dpl[npw], "linked_pair_wise"); + dps[npw]=GLOBAL; + npw++; + + pwl[npw]=linked_pair_wise_collapse; + sprintf (dpl[npw], "linked_pair_wise_collapse"); + dps[npw]=GLOBAL; + npw++; + + + /* + pwl[npw]=viterbiDGL_pair_wise; + sprintf (dpl[npw], "viterbiDGL_pair_wise"); + dps[npw]=GLOBAL; + npw++; + */ + } + + for ( a=0; a< npw; a++) + { + if ( (dp_mode && strm (dpl[a], dp_mode)) || pwl[a]==pw) + { + pw=pwl[a]; + if (dp_mode)sprintf (dp_mode,"%s", dpl[a]); + glocal[0]=dps[a]; + return pw; + } + } + fprintf ( stderr, "\n[%s] is an unknown mode for dp_mode[FATAL]\n", dp_mode); + crash ( "\n"); + return NULL; + } + + +/*******************************************************************************/ +/* */ +/* */ +/* Util Functions */ +/* */ +/* */ +/*******************************************************************************/ + +char *build_consensus ( char *seq1, char *seq2, char *dp_mode) + { + Alignment *A; + char *buf; + int a; + char c1, c2; + static char *mat; + + + if ( !mat) mat=vcalloc ( STRING, sizeof (char)); + + + A=align_two_sequences (seq1, seq2, strcpy(mat,"idmat"), 0, 0,dp_mode); + buf=vcalloc ( A->len_aln+1, sizeof (char)); + + for ( a=0; a< A->len_aln; a++) + { + c1=A->seq_al[0][a]; + c2=A->seq_al[1][a]; + if (is_gap(c1) && is_gap(c2))buf[a]='-'; + else if (is_gap(c1))buf[a]=c2; + else if (is_gap(c2))buf[a]=c1; + else if (c1!=c2){vfree (buf);buf=NULL;free_aln(A);return NULL;} + else buf[a]=c1; + } + buf[a]='\0'; + free_sequence (free_aln (A), -1); + return buf; + } + + + +#ifdef FASTAL + +combine_profile () Comobine two profiles into one, using the edit sequence produce by the DP + edit_sequence () insert the gaps using the + +int fastal (int argv, char **arg) +{ + Sequence *S; + int a, b; + SeqHasch *H=NULL; + int ktup=2; + + S=get_fasta_sequence (arg[1], NULL); + + + + for (a=0; anseq-1; a++) + { + for (b=a+1; bnseq; b++) + { + mat[b][a]=mat[a][b]addrand()%100; + } + } + + int_dist2nj_tree (s, S->name, S->nseq, tree_name); + T=main_read_tree (BT); + =fastal_tree_aln (T->L,T->R,S); +} + + + + +NT_node fastal_tree_aln ( NT_node P, Sequence *S) +{ + int score; + + + if (!P || P->nseq==1) return NULL; + R=P->right;L=P->left; + + fastal_tree_aln (P->left,S); + fastal_tree_aln (P->right,S); + fastal_pair_wise (P); + return P; +} + + +NT_node fastal_pair_wise (NT_node P) +{ + //X- 1 + //-X 2 + //XX 3 + //-- 4 + + tb=fastal_align_profile ((P->right)->prf, (P->left)->prf); + + l=strlen (tb); + for (a=0; a< l; a++) + { + pr1=pr2=0; + if (tb[a]== 1 || tb[a] ==3)pr1=1; + if (tb[a]== 2 || tb[a] ==3)pr2=1; + + for (b=0; b<20; b++) + P->prf[a][b]=((pr1==1)?(P->right)->prf[ppr1][b]:0) + ((pr2==1)?(P->left)->prf[ppr2][b]:0); + ppr1+=pr1; + ppr2+=pr2; + } + free_int ((P->left)->prf, -1); + free_int ((P->right)->prf, -1); +} +#endif +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/util_dp_est.c b/binaries/src/tcoffee/t_coffee_source/util_dp_est.c new file mode 100644 index 0000000..5a80f1f --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/util_dp_est.c @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" +#include "dp_lib_header.h" + + + +int evaluate_est_order (Sequence *S, char *concat, Constraint_list *CL, int ktuple) + { + int a; + static char *alphabet; + int *hasched_seq, *hasched_seq1, *hasched_seq2; + int *lu_seq, *lu_seq1, *lu_seq2; + int pos_ktup1, pos_ktup2; + double score=0; + int n_ktup; + int n_dots=0; + + if ( !alphabet)alphabet=get_alphabet ( concat, alphabet); + n_ktup=(int)pow ( (double)alphabet[0]+1, (double)ktuple); + + hasch_seq (concat,&hasched_seq, &lu_seq,ktuple, alphabet); + hasched_seq1=hasched_seq2=hasched_seq; + lu_seq1=lu_seq2=lu_seq; + + + + for ( a=1; a< n_ktup; a++) + { + pos_ktup1=lu_seq1[a]; + + while (TRUE) + { + + if (!pos_ktup1)break; + pos_ktup2=lu_seq2[a]; + while (pos_ktup2) + { + score+=abs ((int)(pos_ktup1-pos_ktup2)); + pos_ktup2=hasched_seq2[pos_ktup2]; + n_dots++; + } + pos_ktup1=hasched_seq1[pos_ktup1]; + } + } + + score=(score/(double)(n_dots*strlen(concat)))*100000; + vfree ( hasched_seq); + vfree(lu_seq); + + + return score; + } + +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/util_dp_fasta_nw.c b/binaries/src/tcoffee/t_coffee_source/util_dp_fasta_nw.c new file mode 100644 index 0000000..4ea1989 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/util_dp_fasta_nw.c @@ -0,0 +1,1831 @@ +#include +#include +#include +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" +#include "dp_lib_header.h" + + +int commonsextet( int *table, int *pointt ); +void makecompositiontable( int *table, int *pointt ); +int *code_seq (char *seq, char *type); +int * makepointtable( int *pointt, int *n, int ktup ); + +static int tsize; + +/** +* calculates the number of common tuples +*/ +int commonsextet( int *table, int *pointt ) +{ + int value = 0; + int tmp; + int point; + static int *memo = NULL; + static int *ct = NULL; + static int *cp; + + if( !memo ) + { + memo = vcalloc( tsize+1, sizeof( int ) ); + ct = vcalloc( tsize+1, sizeof( int ) ); + } + + cp = ct; + while( ( point = *pointt++ ) != END_ARRAY ) + { + tmp = memo[point]++; + if( tmp < table[point] ) + value++; + if( tmp == 0 ) + { + *cp++ = point; + } + } + *cp = END_ARRAY; + + cp = ct; + while( *cp != END_ARRAY ) + memo[*cp++] = 0; + + return( value ); +} + +/** +* calculates how many of each tuple exist +*/ +void makecompositiontable( int *table, int *pointt ) +{ + int point; + + while( ( point = *pointt++ ) != END_ARRAY ) + { + table[point]++; + } +} + +int *code_seq (char *seq, char *type) +{ + static int *code; + static int *aa, ng; + int a, b, l; + + + if (!aa) + { + char **gl; + if ( strm (type, "DNA") || strm (type, "RNA")) + { + gl=declare_char (4,5); + sprintf ( gl[ng++], "Aa"); + sprintf ( gl[ng++], "Gg"); + sprintf ( gl[ng++], "TtUu"); + sprintf ( gl[ng++], "Cc"); + } + else + { + + gl=make_group_aa ( &ng, "mafft"); + } + aa=vcalloc ( 256, sizeof (int)); + for ( a=0; amaximise=1; + sprintf ( CL->matrix_for_aa_group, "vasiliky"); + CL->M=read_matrice ("blosum62mt"); + CL->evaluate_residue_pair=evaluate_cdna_matrix_score; + CL->get_dp_cost=slow_get_dp_cost; + type=get_string_type(seq1); + + if ( strm (type, "CDNA")) + CL->evaluate_residue_pair= evaluate_matrix_score; + else if ( strm(type, "PROTEIN")) + CL->evaluate_residue_pair=evaluate_matrix_score; + else if ( strm (type, "DNA") || strm (type, "RNA")) + CL->evaluate_residue_pair= evaluate_matrix_score; + vfree(type); + } + else + { + in_cl=1; + } + + + + + if ( !gl) + { + gl=make_group_aa (&ng, CL->matrix_for_aa_group); + ns=vcalloc (2, sizeof (int)); + ns[0]=ns[1]=1; + l_s=declare_int (2, 2); + l_s[0][0]=0; + l_s[1][0]=1; + } + + + A=strings2aln (2, "A",seq1,"B", seq2); + ungap(A->seq_al[0]); + ungap(A->seq_al[1]); + + CL->S=A->S; + + diag=evaluate_diagonals ( A,ns, l_s, CL,maximise, ng, gl, ktup); + free_sequence (A->S, (A->S)->nseq); + free_aln (A); + if (!in_cl) + { + free_int (CL->M, -1); + vfree (CL); + } + + + return diag; + } + + +int ** evaluate_diagonals ( Alignment *A, int *ns, int **l_s, Constraint_list *CL,int maximise,int n_groups, char **group_list, int ktup) + { + int **tot_diag; + + + + if ( CL->residue_index) + { + tot_diag=evaluate_diagonals_with_clist ( A, ns, l_s, CL, maximise,n_groups,group_list, ktup); + } + else if ( CL->use_fragments) + { + + tot_diag=evaluate_segments_with_ktup ( A, ns, l_s, CL, maximise,n_groups,group_list, ktup); + } + else + { + + tot_diag=evaluate_diagonals_with_ktup ( A, ns, l_s, CL, maximise,n_groups,group_list, ktup); + } + + return tot_diag; + } +int ** evaluate_segments_with_ktup ( Alignment *A, int *ns, int **l_s, Constraint_list *CL,int maximise,int n_groups, char **group_list, int ktup) + { + /* + Reads in an alignmnet A, with two groups of sequences marked. + 1-Turn each group into a conscensus, using the group list identifier. + -if the group list is left empty original symbols are used + 2-hash groupc the two sequences + 3-score each diagonal, sort the list and return it (diag_list) + */ + + char *seq1, *seq2, *alphabet=NULL; + int a,b,l1, l2, n_ktup,pos_ktup1, pos_ktup2, **pos; + int *hasched_seq1, *hasched_seq2,*lu_seq1,*lu_seq2; + int n_diag, **diag, current_diag, **dot_list, n_dots, cost; + int l,delta_diag, delta_res; + + + pos=aln2pos_simple ( A,-1, ns, l_s); + seq1=aln2cons_seq (A, ns[0], l_s[0], n_groups, group_list); + seq2=aln2cons_seq (A, ns[1], l_s[1], n_groups, group_list); + + + + alphabet=get_alphabet (seq1,alphabet); + alphabet=get_alphabet (seq2,alphabet); + + + + l1=strlen ( seq1); + l2=strlen ( seq2); + + n_diag=l1+l2-1; + diag=declare_int ( n_diag+2, 3); + n_ktup=(int)pow ( (double)alphabet[0]+1, (double)ktup); + + hasch_seq(seq1, &hasched_seq1, &lu_seq1,ktup, alphabet); + hasch_seq(seq2, &hasched_seq2, &lu_seq2,ktup, alphabet); + + + + /*EVALUATE THE DIAGONALS*/ + for ( a=0; a<= n_diag; a++)diag[a][0]=a; + for ( n_dots=0,a=1; a<= n_ktup; a++) + { + pos_ktup1=lu_seq1[a]; + while (TRUE) + { + if (!pos_ktup1)break; + pos_ktup2=lu_seq2[a]; + while (pos_ktup2) + { + n_dots++; + pos_ktup2=hasched_seq2[pos_ktup2]; + } + pos_ktup1=hasched_seq1[pos_ktup1]; + } + } + + if ( n_dots==0) + { + vfree (seq1); + vfree (seq2); + vfree (alphabet); + vfree (hasched_seq1); + vfree (hasched_seq2); + vfree (lu_seq1); + vfree (lu_seq2); + free_int (diag, -1); + return evaluate_segments_with_ktup (A,ns,l_s,CL,maximise,n_groups, group_list,ktup-1); + } + + dot_list=declare_int ( n_dots,3); + + for ( n_dots=0,a=1; a<= n_ktup; a++) + { + pos_ktup1=lu_seq1[a]; + while (TRUE) + { + if (!pos_ktup1)break; + pos_ktup2=lu_seq2[a]; + while (pos_ktup2) + { + current_diag=(pos_ktup2-pos_ktup1+l1); + dot_list[n_dots][0]=current_diag; + dot_list[n_dots][1]=pos_ktup1; + dot_list[n_dots][2]=pos_ktup2; + pos_ktup2=hasched_seq2[pos_ktup2]; + n_dots++; + } + pos_ktup1=hasched_seq1[pos_ktup1]; + } + } + + + + hsort_list_array ((void **)dot_list, n_dots, sizeof (int), 3, 0, 3); + current_diag= (int)dot_list[0][0]; + + for ( b=0; b< ktup; b++)diag[current_diag][2]+=(CL->get_dp_cost) ( A, pos, ns[0], l_s[0], dot_list[0][1]+b-1, pos,ns[1], l_s[1], dot_list[0][2]+b-1, CL); + + + for ( l=0,a=1; a< n_dots; a++) + { + + delta_diag=dot_list[a][0]-dot_list[a-1][0]; + delta_res =dot_list[a][1]-dot_list[a-1][1]; + + for ( cost=0, b=0; b< ktup; b++)cost++; + + /*=(CL->get_dp_cost) ( A, pos, ns[0], l_s[0], dot_list[a][1]+b-1, pos,ns[1], l_s[1], dot_list[a][2]+b-1, CL);*/ + + + + if (delta_diag!=0 || FABS(delta_res)>5) + { + + l=0; + diag[current_diag][1]=best_of_a_b(diag[current_diag][2], diag[current_diag][1], 1); + if ( diag[current_diag][2]<0); + else diag[current_diag][1]= MAX(diag[current_diag][1],diag[current_diag][2]); + diag[current_diag][2]=0; + current_diag=dot_list[a][0]; + } + l++; + diag[current_diag][2]+=cost; + + } + diag[current_diag][1]=best_of_a_b(diag[current_diag][2], diag[current_diag][1], 1); + sort_int (diag+1, 3, 1,0, n_diag-1); + + + vfree (seq1); + vfree (seq2); + vfree (alphabet); + vfree (hasched_seq1); + vfree (hasched_seq2); + vfree (lu_seq1); + vfree (lu_seq2); + free_int (pos, -1); + free_int (dot_list, -1); + return diag; + } + + + + + +int ** evaluate_diagonals_with_clist ( Alignment *A, int *ns, int **l_s, Constraint_list *CL,int maximise,int n_groups, char **group_list, int ktup) + { + + /* + Reads in an alignmnent A, with two groups of sequences marked. + Weight the diagonals with the values read in the constraint list + */ + + int l1, l2,n_diag, s1, s2, r1=0, r2=0; + int a, b, c, d; + int **diag; + int **code; + int **pos; + static int *entry; + + + if ( !entry)entry=vcalloc ( CL->entry_len+1, CL->el_size); + l1=strlen (A->seq_al[l_s[0][0]]); + l2=strlen (A->seq_al[l_s[1][0]]); + + n_diag=l1+l2-1; + diag=declare_int ( n_diag+2, 3); + for ( a=0; a<= n_diag; a++)diag[a][0]=a; + + A->S=CL->S; + code=seq2aln_pos (A, ns, l_s); + pos =aln2pos_simple ( A,-1, ns, l_s); + + + for (a=0; aorder[l_s[0][a]][0]; + for (b=0; border[l_s[1][b]][0]; + for (r1=1; r1<=(A->S)->len[s1]; r1++) + { + int e; + for (e=1; eresidue_index[s1][r1][0]; e+=ICHUNK) + { + if (CL->residue_index[s1][r1][e+SEQ2]==s2) + { + r2=CL->residue_index[s1][r1][e+R2]; + diag[(r2-r1+l1)][1]+=(CL->get_dp_cost) ( A, pos, ns[0], l_s[0],r1-1, pos,ns[1], l_s[1], r2-1, CL); + } + } + } + } + } + + sort_int (diag+1, 2, 1,0, n_diag-1); + + free_int (code,-1); + free_int (pos, -1); + return diag; + } + +int * flag_diagonals (int l1, int l2, int **sorted_diag, float T, int window) + { + int a, b, up, low,current_diag,n_diag; + int * slopes; + int *diag_list; + double mean; + double sd; + int use_z_score=1; + + + n_diag=l1+l2-1; + mean=return_mean_int ( sorted_diag, n_diag+1, 1); + + sd =return_sd_int ( sorted_diag, n_diag+1, 1, (int)mean); + + if ( T==0) + { + use_z_score=1; + T=(((double)sorted_diag[n_diag][1]-mean)/sd)/25; + } + + + diag_list=vcalloc (l1+l2+1, sizeof (int)); + slopes=vcalloc ( n_diag+1, sizeof (int)); + + for ( a=n_diag; a>0; a--) + { + current_diag=sorted_diag[a][0]; + + + if ( !use_z_score && sorted_diag[a][1]>T) + { + up=MAX(1,current_diag-window); + low=MIN(n_diag, current_diag+window); + for ( b=up; b<=low; b++)slopes[b]=1; + } + else if (use_z_score && ((double)sorted_diag[a][1]-mean)/sd>T) + { + up=MAX(1,current_diag-window); + low=MIN(n_diag, current_diag+window); + for ( b=up; b<=low; b++)slopes[b]=1; + } + else break; + } + + for ( a=1, b=0; a<=n_diag; a++) + { + b+=slopes[a]; + } + + slopes[1]=1; + slopes[l1+l2-1]=1; + slopes[l2]=1; + for (a=0; a<= (l1+l2-1); a++) + if ( slopes[a]){diag_list[++diag_list[0]]=a;} + + vfree (slopes); + + return diag_list; + } +int * extract_N_diag (int l1, int l2, int **sorted_diag, int n_chosen_diag, int window) + { + int a, b, up, low,current_diag,n_diag; + int * slopes; + int *diag_list; + + + n_diag=l1+l2-1; + + diag_list=vcalloc (l1+l2+1, sizeof (int)); + slopes=vcalloc ( n_diag+1, sizeof (int)); + + + for ( a=n_diag; a>0 && a>(n_diag-n_chosen_diag); a--) + { + current_diag=sorted_diag[a][0]; + up=MAX(1,current_diag-window); + low=MIN(n_diag, current_diag+window); + + for ( b=up; b<=low; b++)slopes[b]=1; + } + + /*flag bottom right*/ + up=MAX(1,1-window);low=MIN(n_diag,1+window); + for ( a=up; a<=low; a++) slopes[a]=1; + + /*flag top left */ + up=MAX(1,(l1+l2-1)-window);low=MIN(n_diag,(l1+l2-1)+window); + for ( a=up; a<=low; a++) slopes[a]=1; + + + /*flag MAIN DIAG SEQ1*/ + up=MAX(1,l1-window);low=MIN(n_diag,l1+window); + for ( a=up; a<=low; a++) slopes[a]=1; + + /*flag MAIN DIAG SEQ2*/ + up=MAX(1,l2-window);low=MIN(n_diag,l2+window); + for ( a=up; a<=low; a++) slopes[a]=1; + + + for (a=0; a<= (l1+l2-1); a++) + if ( slopes[a]){diag_list[++diag_list[0]]=a;} + + vfree (slopes); + return diag_list; + } + + + + +int cfasta_gotoh_pair_wise (Alignment *A,int*ns, int **l_s,Constraint_list *CL) + { +/*TREATMENT OF THE TERMINAL GAP PENALTIES*/ +/*TG_MODE=0---> gop and gep*/ +/*TG_MODE=1---> --- gep*/ +/*TG_MODE=2---> --- ---*/ + + + int maximise; + +/*VARIABLES FOR THE MULTIPLE SEQUENCE ALIGNMENT*/ + int **tot_diag; + + int *diag; + int ktup; + static int n_groups; + static char **group_list; + int score, new_score; + int n_chosen_diag=20; + int step; + int max_n_chosen_diag; + int l1, l2; + /********Prepare Penalties******/ + + + maximise=CL->maximise; + ktup=CL->ktup; + + /********************************/ + + + + + if ( !group_list) + { + + group_list=make_group_aa (&n_groups, CL->matrix_for_aa_group); + } + + l1=strlen (A->seq_al[l_s[0][0]]); + l2=strlen (A->seq_al[l_s[1][0]]); + + if ( !CL->fasta_step) + { + step=MIN(l1,l2); + step=(int) log ((double)MAX(step, 1)); + step=MAX(step, 20); + } + else + { + step=CL->fasta_step; + } + + + tot_diag=evaluate_diagonals ( A, ns, l_s, CL, maximise,n_groups,group_list, ktup); + + + max_n_chosen_diag=strlen (A->seq_al[l_s[0][0]])+strlen (A->seq_al[l_s[1][0]])-1; + /*max_n_chosen_diag=(int)log10((double)(l1+l2))*10;*/ + + n_chosen_diag+=step; + n_chosen_diag=MIN(n_chosen_diag, max_n_chosen_diag); + + + diag=extract_N_diag (strlen (A->seq_al[l_s[0][0]]),strlen (A->seq_al[l_s[1][0]]), tot_diag, n_chosen_diag, 0); + + + score =make_fasta_gotoh_pair_wise ( A, ns, l_s, CL, diag); + + new_score=0; + vfree ( diag); + + + while (new_score!=score && n_chosen_diag< max_n_chosen_diag ) + { + + + score=new_score; + + ungap_sub_aln ( A, ns[0], l_s[0]); + ungap_sub_aln ( A, ns[1], l_s[1]); + + + n_chosen_diag+=step; + n_chosen_diag=MIN(n_chosen_diag, max_n_chosen_diag); + + + diag =extract_N_diag (strlen (A->seq_al[l_s[0][0]]),strlen (A->seq_al[l_s[1][0]]), tot_diag, n_chosen_diag, 0); + new_score=make_fasta_gotoh_pair_wise ( A, ns, l_s, CL, diag); + + vfree ( diag); + + } + + score=new_score; + free_int (tot_diag, -1); + + return score; + } + +int fasta_gotoh_pair_wise (Alignment *A,int*ns, int **l_s,Constraint_list *CL) + { +/*TREATMENT OF THE TERMINAL GAP PENALTIES*/ +/*TG_MODE=0---> gop and gep*/ +/*TG_MODE=1---> --- gep*/ +/*TG_MODE=2---> --- ---*/ + + + int maximise; + +/*VARIABLES FOR THE MULTIPLE SEQUENCE ALIGNMENT*/ + int **tot_diag; + int *diag; + int ktup; + float diagonal_threshold; + static int n_groups; + static char **group_list; + int score; + /********Prepare Penalties******/ + + + maximise=CL->maximise; + ktup=CL->ktup; + diagonal_threshold=CL->diagonal_threshold; + /********************************/ + + + + if ( !group_list) + { + group_list=make_group_aa (&n_groups, CL->matrix_for_aa_group); + } + + + tot_diag=evaluate_diagonals ( A, ns, l_s, CL, maximise,n_groups,group_list, ktup); + + if ( !CL->fasta_step) + { + diag=flag_diagonals (strlen(A->seq_al[l_s[0][0]]),strlen(A->seq_al[l_s[1][0]]), tot_diag,diagonal_threshold,0); + } + + else + { + + diag=extract_N_diag (strlen (A->seq_al[l_s[0][0]]),strlen (A->seq_al[l_s[1][0]]), tot_diag,CL->fasta_step,0); + + } + score=make_fasta_gotoh_pair_wise ( A, ns, l_s, CL, diag); + + free_int (tot_diag, -1); + vfree (diag); + return score; + } +int very_fast_gotoh_pair_wise (Alignment *A,int*ns, int **l_s,Constraint_list *CL) + { +/*TREATMENT OF THE TERMINAL GAP PENALTIES*/ +/*TG_MODE=0---> gop and gep*/ +/*TG_MODE=1---> --- gep*/ +/*TG_MODE=2---> --- ---*/ + + + int maximise; +/*VARIABLES FOR THE MULTIPLE SEQUENCE ALIGNMENT*/ + int **tot_diag; + int *diag; + int ktup; + static int n_groups; + static char **group_list; + int score; + /********Prepare Penalties******/ + + + maximise=CL->maximise; + ktup=CL->ktup; + /********************************/ + + + if ( !group_list) + { + + group_list=make_group_aa (&n_groups, CL->matrix_for_aa_group); + } + + CL->use_fragments=0; + tot_diag=evaluate_diagonals ( A, ns, l_s, CL, maximise,n_groups,group_list, ktup); + + /*Note: 20 diagonals. 5 shadows on each side: tunned on Hom39, 2/2/04 */ + diag=extract_N_diag (strlen (A->seq_al[l_s[0][0]]),strlen (A->seq_al[l_s[1][0]]), tot_diag,20,5); + score=make_fasta_gotoh_pair_wise ( A, ns, l_s, CL, diag); + free_int (tot_diag, -1); + vfree (diag); + return score; + } +int make_fasta_gotoh_pair_wise (Alignment *A,int*ns, int **l_s,Constraint_list *CL, int *diag) + { +/*TREATMENT OF THE TERMINAL GAP PENALTIES*/ +/*TG_MODE=0---> gop and gep*/ +/*TG_MODE=1---> --- gep*/ + /*TG_MODE=2---> --- ---*/ + + + int TG_MODE, gop, l_gop, gep,l_gep, maximise; + +/*VARIABLES FOR THE MULTIPLE SEQUENCE ALIGNMENT*/ + int a, b,c,k, t; + int l1, l2,eg, ch, sub,score=0, last_i=0, last_j=0, i, delta_i, j, pos_j, ala, alb, LEN, n_diag, match1, match2; + int su, in, de, tr; + + int **C, **D, **I, **trace, **pos0, **LD; + int lenal[2], len; + char *buffer, *char_buf; + char **aln, **al; + + /********Prepare Penalties******/ + gop=CL->gop*SCORE_K; + gep=CL->gep*SCORE_K; + TG_MODE=CL->TG_MODE; + maximise=CL->maximise; + + + /********************************/ + + + n_diag=diag[0]; + + + + l1=lenal[0]=strlen (A->seq_al[l_s[0][0]]); + l2=lenal[1]=strlen (A->seq_al[l_s[1][0]]); + + if ( getenv ("DEBUG_TCOFFEE"))fprintf ( stderr, "\n\tNdiag=%d%% ", (diag[0]*100)/(l1+l2)); + + /*diag: + diag[1..n_diag]--> flaged diagonal in order; + diag[0]=0--> first diagonal; + diag[n_diag+1]=l1+l2-1; + */ + + /*numeration of the diagonals strats from the bottom right [1...l1+l2-1]*/ + /*sequence s1 is vertical and seq s2 is horizontal*/ + /*D contains the best Deletion in S2==>comes from diagonal N+1*/ + /*I contains the best insertion in S2=> comes from diagonal N-1*/ + + + + + + C=declare_int (lenal[0]+lenal[1]+1, n_diag+2); + D=declare_int (lenal[0]+lenal[1]+1, n_diag+2); + LD=declare_int (lenal[0]+lenal[1]+1, n_diag+2); + I=declare_int (lenal[0]+lenal[1]+1, n_diag+2); + trace=declare_int (lenal[0]+lenal[1]+1, n_diag+2); + + + al=declare_char (2,lenal[0]+lenal[1]+lenal[1]+1); + + len= MAX(lenal[0],lenal[1])+1; + buffer=vcalloc ( 2*len, sizeof (char)); + char_buf= vcalloc (2*len, sizeof (char)); + + pos0=aln2pos_simple ( A,-1, ns, l_s); + C[0][0]=0; + + t=(TG_MODE==0)?gop:0; + for ( j=1; j<= n_diag; j++) + { + l_gop=(TG_MODE==0)?gop:0; + l_gep=(TG_MODE==2)?0:gep; + + + + if ( (diag[j]-lenal[0])<0 ) + { + trace[0][j]=UNDEFINED; + continue; + } + C[0][j]=(diag[j]-lenal[0])*l_gep +l_gop; + D[0][j]=(diag[j]-lenal[0])*l_gep +l_gop+gop; + } + D[0][j]=D[0][j-1]+gep; + + + t=(TG_MODE==0)?gop:0; + for ( i=1; i<=lenal[0]; i++) + { + l_gop=(TG_MODE==0)?gop:0; + l_gep=(TG_MODE==2)?0:gep; + + C[i][0]=C[i][n_diag+1]=t=t+l_gep; + I[i][0]=D[i][n_diag+1]=t+ gop; + + for ( j=1; j<=n_diag; j++) + { + C[i][j]=C[i][0]; + D[i][j]=I[i][j]=I[i][0]; + } + + for (eg=0, j=1; j<=n_diag; j++) + { + + pos_j=diag[j]-lenal[0]+i; + if (pos_j<=0 || pos_j>l2 ) + { + trace[i][j]=UNDEFINED; + continue; + } + sub=(CL->get_dp_cost) ( A, pos0, ns[0], l_s[0], i-1, pos0, ns[1], l_s[1],pos_j-1, CL ); + + /*1 identify the best insertion in S2:*/ + l_gop=(i==lenal[0])?((TG_MODE==0)?gop:0):gop; + l_gep=(i==lenal[0])?((TG_MODE==2)?0:gep):gep; + len=(j==1)?0:(diag[j]-diag[j-1]); + if ( a_better_than_b(I[i][j-1], C[i][j-1]+l_gop, maximise))eg++; + else eg=1; + I[i][j]=best_of_a_b (I[i][j-1], C[i][j-1]+l_gop, maximise)+len*l_gep; + + /*2 Identify the best deletion in S2*/ + l_gop=(pos_j==lenal[1])?((TG_MODE==0)?gop:0):gop; + l_gep=(pos_j==lenal[1])?((TG_MODE==2)?0:gep):gep; + + len=(j==n_diag)?0:(diag[j+1]-diag[j]); + delta_i=((i-len)>0)?(i-len):0; + + if ( a_better_than_b(D[delta_i][j+1],C[delta_i][j+1]+l_gop, maximise)){LD[i][j]=LD[delta_i][j+1]+1;} + else {LD[i][j]=1;} + D[i][j]=best_of_a_b (D[delta_i][j+1],C[delta_i][j+1]+l_gop, maximise)+len*l_gep; + + + /*Identify the best way*/ + /* + score=C[i][j]=best_int ( 3, maximise, &fop, I[i][j], C[i-1][j]+sub, D[i][j]); + fop-=1; + if ( fop<0)trace[i][j]=fop*eg; + else if ( fop>0 ) {trace[i][j]=fop*LD[i][j];} + else if ( fop==0) trace[i][j]=0; + */ + + su=C[i-1][j]+sub; + in=I[i][j]; + de=D[i][j]; + + /*HERE ("%d %d %d", su, in, de);*/ + if (su>=in && su>=de) + { + score=su; + tr=0; + } + else if (in>=de) + { + score=in; + tr=-eg; + } + else + { + score=de; + tr=LD[i][j]; + } + trace[i][j]=tr; + C[i][j]=score; + + + last_i=i; + last_j=j; + } + } + + + /* + [0][Positive] + ^ ^ + | / + | / + | / + | / + |/ + [Neg]<-------[*] + */ + + + i=last_i; + j=last_j; + + + + ala=alb=0; + match1=match2=0; + while (!(match1==l1 && match2==l2)) + { + + + if ( match1==l1) + { + len=l2-match2; + for ( a=0; a< len; a++) + { + al[0][ala++]=0; + al[1][alb++]=1; + match2++; + } + k=0; + break; + + /*k=-(j-1);*/ + + } + else if ( match2==l2) + { + len=l1-match1; + for ( a=0; a< len; a++) + { + al[0][ala++]=1; + al[1][alb++]=0; + match1++; + } + k=0; + break; + /*k= n_diag-j;*/ + } + else + { + k=trace[i][j]; + } + + + if ( k==0) + { + if ( match2==l2 || match1==l1); + else + { + + al[0][ala++]=1; + al[1][alb++]=1; + i--; + match1++; + match2++; + } + } + else if ( k>0) + { + + len=diag[j+k]-diag[j]; + for ( a=0; adeclared_len<=LEN)A=realloc_aln2 ( A,A->max_n_seq, 2*LEN); + aln=A->seq_al; + + for ( c=0; c< 2; c++) + { + for ( a=0; a< ns[c]; a++) + { + ch=0; + for ( b=0; b< LEN; b++) + { + if (al[c][b]==1) + char_buf[b]=aln[l_s[c][a]][ch++]; + else + char_buf[b]='-'; + } + char_buf[b]='\0'; + sprintf (aln[l_s[c][a]],"%s", char_buf); + } + } + + + A->len_aln=LEN; + A->nseq=ns[0]+ns[1]; + + free_int (pos0, -1); + free_int (C, -1); + free_int (D, -1); + free_int (I, -1); + free_int (trace, -1); + free_int (LD, -1); + free_char ( al, -1); + vfree(buffer); + vfree(char_buf); + + + return score; + } + +int hasch_seq(char *seq, int **hs, int **lu,int ktup,char *alp) + { + static int a[10]; + + int i,j,l,limit,code,flag; + char residue; + + int alp_lu[10000]; + int alp_size; + + alp_size=alp[0]; + alp++; + + + + for ( i=0; i< alp_size; i++) + { + alp_lu[(int)alp[i]]=i; + } + + + + l=strlen (seq); + limit = (int) pow((double)(alp_size+1),(double)ktup); + hs[0]=vcalloc ( l+1,sizeof (int)); + lu[0]=vcalloc ( limit+1, sizeof(int)); + + + if ( l==0)myexit(EXIT_FAILURE); + + for (i=1;i<=ktup;i++) + a[i] = (int) pow((double)(alp_size+1),(double)(i-1)); + + + for(i=1;i<=(l-ktup+1);++i) + { + code=0; + flag=FALSE; + for(j=1;j<=ktup;++j) + { + if (is_gap(seq[i+j-2])){flag=TRUE;break;} + else residue=alp_lu[(int)seq[i+j-2]]; + code+=residue*a[j]; + } + + if ( flag)continue; + ++code; + + if (lu[0][code])hs[0][i]=lu[0][code]; + lu[0][code]=i; + } + return 0; + } + + + +/*********************************************************************/ +/* */ +/* KTUP_DP */ +/* */ +/* */ +/*********************************************************************/ + +/**************Hasch DAta Handling*******************************************************/ + +struct Hasch_data * free_ktup_hasch_data (struct Hasch_data *d); +struct Hasch_data * declare_ktup_hasch_data (struct Hasch_entry *e); +struct Hasch_data * allocate_ktup_hasch_data (struct Hasch_data *e, int action); + +struct Hasch_data +{ + int *list; +}; +typedef struct Hasch_data Hasch_data; +struct Hasch_data * free_ktup_hasch_data (struct Hasch_data *d) +{ + return allocate_ktup_hasch_data (d, FREE); +} +struct Hasch_data * declare_ktup_hasch_data (struct Hasch_entry *e) +{ + e->data=allocate_ktup_hasch_data (NULL,DECLARE); + return e->data; +} + +struct Hasch_data * allocate_ktup_hasch_data (struct Hasch_data *e, int action) +{ + static struct Hasch_data **heap; + static int heap_size, free_heap, a; + + if ( action == 100) + { + fprintf ( stderr, "\nHeap size: %d, Free Heap: %d", heap_size, free_heap); + return NULL; + } + else if ( action==DECLARE) + { + if ( free_heap==0) + { + free_heap=100; + heap_size+=free_heap; + heap=vrealloc (heap,heap_size*sizeof (struct Hasch_entry *)); + for ( a=0; alist=vcalloc ( 10, sizeof (int)); + (heap[a])->list[0]=10; + } + } + return heap[--free_heap]; + } + else if ( action==FREE) + { + heap[free_heap++]=e; + e->list[1]=0; + return NULL; + } + return NULL; +} + + +/**************Hasch DAta Handling*******************************************************/ + +int precomputed_pair_wise (Alignment *A,int*ns, int **l_s,Constraint_list *CL) + { + int l1, l2, a, b, c; + int nid=0, npos=0, id; + int r1, r2, s1, s2; + + l1=strlen(A->seq_al[l_s[0][0]]); + l2=strlen(A->seq_al[l_s[1][0]]); + if (l1!=l2) + { + fprintf ( stderr, "\nERROR: improper use of the function precomputed pairwise:[FATAL:%s]", PROGRAM); + crash (""); + } + else if ( l1==0) + { + A->score_aln=A->score=0; + return 0; + } + + for (npos=0, nid=0, a=0; a< ns[0]; a++) + { + s1=l_s[0][a]; + + for (b=0; b< ns[1]; b++) + { + s2=l_s[1][b]; + for ( c=0; cseq_al[s1][c]; + r2=A->seq_al[s2][c]; + if ( is_gap(r1) || is_gap(r2)); + else + { + npos++; + nid+=(r1==r2); + } + } + } + } + id=(npos==0)?0:((nid*100)/npos); + A->score=A->score_aln=id; + return A->score; + } +int ktup_comparison_str ( char *seq1, char *seq2, const int ktup); +int ktup_comparison_hasch ( char *i_seq1, char *i_seq2, const int ktup); +int ktup_pair_wise (Alignment *A,int*ns, int **l_s,Constraint_list *CL) + { + static char **gl; + static int ng; + char *seq1; + char *seq2; + + int min_len=10; + + + + if ( !gl) + gl=make_group_aa (&ng, "vasiliky"); + + + if ( ns[0]>1)seq1=sub_aln2cons_seq_mat (A, ns[0], l_s[0],"blosum62mt"); + else + { + seq1=vcalloc ( strlen (A->seq_al[l_s[0][0]])+1, sizeof (char)); + sprintf ( seq1, "%s",A->seq_al[l_s[0][0]]); + } + if ( ns[1]>1)seq2=sub_aln2cons_seq_mat (A, ns[1], l_s[1],"blosum62mt"); + else + { + seq2=vcalloc ( strlen (A->seq_al[l_s[1][0]])+1, sizeof (char)); + sprintf ( seq2, "%s",A->seq_al[l_s[1][0]]); + } + + if ( strlen (seq1)score=A->score_aln=aln2sim(B, "idmat"); + free_aln (B); + return A->score; + } + else + { + + string_convert (seq1, ng, gl); + string_convert (seq2, ng, gl); + A->score=A->score_aln=ktup_comparison (seq1,seq2, CL->ktup); + } + + vfree (seq1); vfree (seq2); + return A->score; + } +int ktup_comparison( char *seq2, char *seq1, const int ktup) +{ + return ktup_comparison_hasch ( seq2, seq1, ktup); +} +int ktup_comparison_str ( char *seq2, char *seq1, const int ktup) +{ + int a,l1, l2,c1, c2, end, start; + char *s1, *s2; + double score=0; + int max_dist=-1; + + if ( max_dist==-1)max_dist=MAX((strlen (seq1)),(strlen (seq2))); + l1=strlen (seq1)-ktup; + l2=strlen (seq2); + + + for ( a=0; a< l1; a++) + { + c1=seq1[a+ktup];seq1[a+ktup]='\0'; + s1=seq1+a; + + start=((a-max_dist)<0)?0:a-max_dist; + end=((a+max_dist)>=l2)?l2:a+max_dist; + + c2=seq2[end];seq2[end]='\0'; + s2=seq2+start; + + score+=(strstr(s2, s1)!=NULL)?1:0; + + seq1[a+ktup]=c1; + seq2[end]=c2; + } + score/=(l1==0)?1:l1; + score=((log(0.1+score)-log(0.1))/(log(1.1)-log(0.1))); + + return score*100; + +} +int ktup_comparison_hasch ( char *i_seq1, char *i_seq2, const int ktup) +{ + /*Ktup comparison adapted from Rob Edgar, NAR, vol32, No1, 381, 2004*/ + /*1: hasch sequence 1 + 2: Count the number of seq2 ktup found in seq1 + */ + + char c; + int key; + + static HaschT*H1; + static char *pseq; + Hasch_entry *e; + char *s; + int l, ls; + int p, a, max_dist=-1; + double score=0; + + + + if (!strm (i_seq1, pseq)) + { + if (H1) + { + hdestroy (H1, declare_ktup_hasch_data, free_ktup_hasch_data); + string2key (NULL, NULL); + } + H1=hasch_sequence ( i_seq1, ktup); + vfree (pseq);pseq=vcalloc ( strlen (i_seq1)+1, sizeof (char)); + sprintf ( pseq, "%s", i_seq1); + } + + ls=l=strlen (i_seq2); + s=i_seq2; + p=0; + while (ls>ktup) + { + c=s[ktup];s[ktup]='\0'; + key=string2key (s, NULL); + e=hsearch (H1,key,FIND, declare_ktup_hasch_data, free_ktup_hasch_data); + + if ( e==NULL); + else if ( max_dist==-1)score++; + else + { + for ( a=1; a<=(e->data)->list[1]; a++) + if (FABS((p-(e->data)->list[a]))<=max_dist) + {score++; break;} + } + s[ktup]=c;s++;p++;ls--; + } + score/=(l-ktup); + score=(log(0.1+score)-log(0.1))/(log(1.1)-log(0.1)); + + if ( score>100) score=100; + return (int)(score*100); +} + +HaschT* hasch_sequence ( char *seq1, int ktup) +{ + char c; + int key, offset=0, ls; + HaschT *H; + Hasch_entry *e; + + H=hcreate ( strlen (seq1), declare_ktup_hasch_data, free_ktup_hasch_data); + ls=strlen (seq1); + while (ls>=(ktup)) + { + c=seq1[ktup];seq1[ktup]='\0'; + key=string2key (seq1, NULL); + e=hsearch (H,key,FIND, declare_ktup_hasch_data, free_ktup_hasch_data); + + if (e==NULL) + { + e=hsearch (H,key,ADD,declare_ktup_hasch_data,free_ktup_hasch_data); + (e->data)->list[++(e->data)->list[1]+1]=offset; + } + else + { + if ((e->data)->list[0]==((e->data)->list[1]+2)){(e->data)->list[0]+=10;(e->data)->list=vrealloc ((e->data)->list,(e->data)->list[0]*sizeof (int));} + (e->data)->list[++(e->data)->list[1]+1]=offset; + } + seq1[ktup]=c;seq1++;ls--; + offset++; + } + return H; +} + + + +char *dayhoff_translate (char *seq1) +{ +int l, a, c; +l=strlen (seq1); + for ( a=0; a< l; a++) + { + c=tolower(seq1[a]); + if ( strchr ("agpst", c))seq1[a]='a'; + else if (strchr ("denq", c))seq1[a]='d'; + else if (strchr ("fwy", c))seq1[a]='f'; + else if (strchr ("hkr", c))seq1[a]='h'; + else if (strchr ("ilmv", c))seq1[a]='i'; + } +return seq1; +} + +int ** evaluate_diagonals_with_ktup ( Alignment *A, int *ns, int **l_s, Constraint_list *CL,int maximise,int n_groups, char **group_list, int ktup) +{ + /*Ktup comparison as in Rob Edgar, NAR, vol32, No1, 381, 2004*/ + char character; + int key,ls; + HaschT*H1, *H2; + Hasch_entry *e1, *e2; + char *s, *sb, *seq1, *seq2; + int l1, l2; + int score=0; + int **diag,n_diag, ktup1, ktup2,a,b,c,d, **pos; + int n_dots=0; + + pos=aln2pos_simple ( A,-1, ns, l_s); + + seq1=aln2cons_maj (A, ns[0], l_s[0], n_groups, group_list); + seq2=aln2cons_maj (A, ns[1], l_s[1], n_groups, group_list); + l1=strlen (seq1); + l2=strlen (seq2); + n_diag=l1+l2-1; + + + diag=declare_int (n_diag+2, 3); + for ( a=0; a=(ktup)) + { + character=s[ktup];s[ktup]='\0'; + key=string2key (s, NULL); + e1=hsearch (H1,key,FIND,declare_ktup_hasch_data, free_ktup_hasch_data); + e2=hsearch (H2,key,FIND,declare_ktup_hasch_data, free_ktup_hasch_data); + if ( !e2 || !e1); + else + { + + for (b=2; b<(e1->data)->list[1]+2; b++) + for (c=2; c<(e2->data)->list[1]+2; c++) + { + + ktup1=(e1->data)->list[b]; + ktup2=(e2->data)->list[c]; + diag[(ktup2-ktup1)+l1][2]++; + for (score=0, d=0; dget_dp_cost) ( A, pos, ns[0], l_s[0], ktup1+d, pos,ns[1], l_s[1], ktup2+d, CL); + diag[(ktup2-ktup1)+l1][1]+=score; + n_dots++; + } + (e1->data)->list[1]=(e2->data)->list[1]=0; + } + s[ktup]=character;s++;ls--; + } + + sort_int (diag+1, 2, 1,0,n_diag-1); + + hdestroy (H1,declare_ktup_hasch_data, free_ktup_hasch_data); hdestroy (H2,declare_ktup_hasch_data, free_ktup_hasch_data); + vfree (seq1); vfree (seq2);vfree (sb);free_int (pos, -1); + return diag; +} + /*********************************************************************/ +/* */ +/* OLD FUNCTIONS */ +/* */ +/* */ +/*********************************************************************/ +int ** evaluate_diagonals_with_ktup_1 ( Alignment *A, int *ns, int **l_s, Constraint_list *CL,int maximise,int n_groups, char **group_list, int ktup) + { + /* + Reads in an alignmnent A, with two groups of sequences marked. + 1-Turn each group into a conscensus, using the group list identifier. + -if the group list is left empty original symbols are used + 2-hasch the two sequences + 3-score each diagonal, sort the list and return it (diag_list) + + diag_list: + + */ + + char *seq1, *seq2, *alphabet=NULL; + int a,b,l1, l2, n_ktup,pos_ktup1, pos_ktup2, **pos; + int *hasched_seq1, *hasched_seq2,*lu_seq1,*lu_seq2; + int n_diag, **diag, current_diag, n_dots; + static char *buf; + pos=aln2pos_simple ( A,-1, ns, l_s); + + + seq1=aln2cons_seq (A, ns[0], l_s[0], n_groups, group_list); + seq2=aln2cons_seq (A, ns[1], l_s[1], n_groups, group_list); + + + + + alphabet=get_alphabet (seq1,alphabet); + alphabet=get_alphabet (seq2,alphabet); + + l1=strlen ( seq1); + l2=strlen ( seq2); + + n_diag=l1+l2-1; + diag=declare_int ( n_diag+2, 3); + n_ktup=(int)pow ( (double)alphabet[0]+1, (double)ktup); + + + hasch_seq(seq1, &hasched_seq1, &lu_seq1,ktup, alphabet); + hasch_seq(seq2, &hasched_seq2, &lu_seq2,ktup, alphabet); + + + + + /*EVALUATE THE DIAGONALS*/ + for ( a=0; a<= n_diag; a++)diag[a][0]=a; + for ( n_dots=0,a=1; a<= n_ktup; a++) + { + pos_ktup1=lu_seq1[a]; + while (TRUE) + { + if (!pos_ktup1)break; + pos_ktup2=lu_seq2[a]; + while (pos_ktup2) + { + current_diag=(pos_ktup2-pos_ktup1+l1); + for ( b=0; b< ktup; b++) + { + diag[current_diag][1]+=(CL->get_dp_cost) ( A, pos, ns[0], l_s[0], pos_ktup1+b-1, pos,ns[1], l_s[1], pos_ktup2+b-1, CL); + n_dots++; + + } + diag[current_diag][2]++; + pos_ktup2=hasched_seq2[pos_ktup2]; + } + pos_ktup1=hasched_seq1[pos_ktup1]; + } + + } + if ( n_dots==0) + { + if ( !buf) + { + buf=vcalloc ( 30, sizeof (30)); + sprintf ( buf, "abcdefghijklmnopqrstuvwxyz"); + } + vfree ( hasched_seq1); + vfree ( hasched_seq2); + vfree (lu_seq1); + vfree (lu_seq2); + return evaluate_diagonals_with_ktup ( A,ns,l_s, CL,maximise,1,&buf,1); + } + + + sort_int (diag+1, 2, 1,0, n_diag-1); + vfree (seq1); + vfree (seq2); + vfree (alphabet); + vfree ( hasched_seq1); + vfree ( hasched_seq2); + vfree (lu_seq1); + vfree (lu_seq2); + free_int (pos, -1); + return diag; + } +///////////////////////////////////////////////////////////////// + +Constraint_list * hasch2constraint_list (Sequence*S, Constraint_list *CL) +{ + int a,b,c, n; + SeqHasch h,*H=NULL; + int *entry; + int ktup=2; + + + entry=vcalloc ( CL->entry_len+1, sizeof (int)); + + for (a=0; anseq; a++) + { + H=seq2hasch (a, S->seq[a],ktup,H); + } + + n=1; + while (H[n]) + { + h=H[n]; + + for (a=0; an-2; a+=2) + { + for (b=a+2; bn; b+=2) + { + + if (h->l[a]==h->l[b])continue; + else + { + for (c=0; cl[a]; + entry[SEQ2]=h->l[b]; + entry[R1]=h->l[a+1]+c; + entry[R2]=h->l[b+1]+c; + entry[WE]=100; + add_entry2list (entry,CL); + } + } + } + } + n++; + } + + return CL; +} +SeqHasch *cleanhasch (SeqHasch *H) +{ + int n=1; + SeqHasch *N; + N=vcalloc (2, sizeof (SeqHasch)); + N[0]=H[0]; + + while (H[n]) + { + (H[n])->n=0; + vfree ((H[n])->l); + (H[n])->l=NULL; + n++; + } + vfree (H); + return N; +} +int hasch2sim (SeqHasch *H, int nseq) +{ + int n=1; + + int a,cs, ps, ns; + int id=0, tot=0; + + while (H[n]) + { + for (ps=-1,ns=0,a=0; a<(H[n])->n; a+=2) + { + //HERE ("%d--[%d %d]",n, (H[n])->l[a], (H[n])->l[a+1]); + cs=(H[n])->l[a]; + if (cs!=ps)ns++; + ps=cs; + } + n++; + if (ns==nseq)id++; + tot++; + } + + return (id*MAXID)/tot; +} +SeqHasch * seq2hasch (int i,char *seq, int ktup, SeqHasch *H) +{ + int a,b,l, n=0; + SeqHasch h; + + + if (!H) + { + H=vcalloc (2, sizeof (SeqHasch)); + H[0]=vcalloc (1, sizeof (hseq)); + n=1; + } + else + { + n=0; + while (H[++n]); + } + + l=strlen (seq); + for (a=0; ahl[r]) h->hl[r]=vcalloc (1, sizeof (hseq)); + h=h->hl[r]; + } + if (!h->l) + { + + h->n=2; + h->l=vcalloc (2, sizeof (int)); + H=vrealloc (H,(n+2)*sizeof (SeqHasch)); + H[n]=h; + n++; + } + else + { + h->n+=2; + h->l=vrealloc (h->l, (h->n)*sizeof (int)); + } + + h->l[h->n-2]=i; + h->l[h->n-1]=a; + } + return H; +} + +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/util_dp_fasta_sw.c b/binaries/src/tcoffee/t_coffee_source/util_dp_fasta_sw.c new file mode 100644 index 0000000..e6f38db --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/util_dp_fasta_sw.c @@ -0,0 +1,64 @@ +#include +#include +#include +#include + + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" + +#include "dp_lib_header.h" + +int cfasta_gotoh_pair_wise_sw (Alignment *A,int*ns, int **l_s,Constraint_list *CL) + { + fprintf ( stderr, "\ncfasta_gotoh_pair_wise_sw not implemented yet\n"); + myexit (EXIT_FAILURE); + return 0; + + } + +int fasta_gotoh_pair_wise_sw (Alignment *A,int*ns, int **l_s,Constraint_list *CL) + { + fprintf ( stderr, "\nfasta_gotoh_pair_wise_sw not implemented yet\n"); + myexit (EXIT_FAILURE); + return 0; + } + +int make_fasta_gotoh_pair_wise_sw (Alignment *A,int*ns, int **l_s,Constraint_list *CL, int *diag) + { + fprintf ( stderr, "\nmake_fasta_gotoh_pair_wise_sw not implemented yet\n"); + myexit (EXIT_FAILURE); + return 0; + } + + +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/util_dp_generic_fasta_nw.c b/binaries/src/tcoffee/t_coffee_source/util_dp_generic_fasta_nw.c new file mode 100644 index 0000000..8df5c9b --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/util_dp_generic_fasta_nw.c @@ -0,0 +1,378 @@ +#include +#include +#include +#include +#include + + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" +#include "dp_lib_header.h" + + + +/*********************************************************************************/ +/* */ +/* */ +/* Generic DP */ +/* */ +/* */ +/*********************************************************************************/ + + +Dp_Result * make_fast_generic_dp_pair_wise (Alignment *A, int*ns, int **l_s,Dp_Model *M) + { + + /*SIZE VARIABLES*/ + + int ndiag; + int l0, l1, len_al,len_diag; + static int max_len_al, max_len_diag; + static int mI, mJ; + /*Evaluation*/ + int **pos0; + + + + /*DP VARIABLES*/ + static int *Mat, *LMat, *trace; + int a, i, j,l; + int state, cur_state, prev_state; + int pos_i=0, pos_j=0; + int last_i=0, last_j=0; + int prev_i, prev_j; + int len_i, len_j, len; + int t, e, em; + + int prev_score; + int pc, best_pc; + + int *prev; + int model_index; + /*TRACEBACK*/ + Dp_Result *DPR; + int k=0, next_k; + int new_i, new_j; + + + /*Cleqanning CALL*/ + if ( A==NULL) + { + max_len_al=0; max_len_diag=0;mI=0;mJ=0; + vfree (Mat); vfree(LMat);vfree(trace); + Mat=trace=LMat=NULL; + return NULL; + } + + ndiag=M->diag[0]; + + l0=strlen (A->seq_al[l_s[0][0]]); + l1=strlen (A->seq_al[l_s[1][0]]); + len_al =l0+l1+1; + len_diag=ndiag+4; + + + + if ( (len_al>max_len_al || len_diag>max_len_diag)) + { + + vfree (Mat); + vfree (LMat); + vfree(trace); + max_len_diag=max_len_al=0; + } + + if (max_len_al==0) + { + max_len_al=len_al; + max_len_diag=len_diag; + mI=max_len_al*max_len_diag; + mJ=max_len_diag; + + + Mat =vcalloc ( M->nstate*max_len_al*max_len_diag, sizeof (int)); + LMat =vcalloc ( M->nstate*max_len_al*max_len_diag, sizeof (int)); + trace=vcalloc ( M->nstate*max_len_al*max_len_diag, sizeof (int)); + + } + + prev=vcalloc ( M->nstate, sizeof (int)); + DPR=vcalloc ( 1, sizeof ( Dp_Result)); + DPR->traceback=vcalloc (max_len_al, sizeof (int)); + +/*PREPARE THE EVALUATION*/ + + + pos0=aln2pos_simple ( A,-1, ns, l_s); + +/*INITIALIZATION OF THE DP MATRICES*/ + + for (i=0; i<=l0;i++) + { + for (j=0; j<=ndiag+1;j++) + { + for ( state=0; statenstate; state++) + { + Mat [state*mI+i*mJ+j]=UNDEFINED; + LMat [state*mI+i*mJ+j]=UNDEFINED; + trace [state*mI+i*mJ+j]=M->START; + } + } + } + + M->diag[0]=1; + M->diag[ndiag+1]=M->diag[ndiag]; + + for (i=0; i<=l0; i++) + for ( j=0; j<=ndiag+1; j++) + { + pos_j=M->diag[j]-l0+i; + pos_i=i; + if (!(pos_j==0 || pos_i==0))continue; + if ( pos_j<0 || pos_i<0)continue; + if ( pos_i==0 && pos_j==0) + { + for ( a=0; a< M->nstate; a++) + { + Mat [a*mI+i*mJ+j]=0; + LMat [a*mI+i*mJ+j]=0; + trace[a*mI+i*mJ+j]=M->START; + } + } + else + { + l=MAX(pos_i,pos_j); + for ( state=0; stateSTART; state++) + { + if (pos_j==0 && M->model_properties[state][M->LEN_J])continue; + if (pos_i==0 && M->model_properties[state][M->LEN_I])continue; + + + t=M->model[M->START][state]; + e=((M->model_emission_function)[state][M->START_EMISSION])(A, pos0, ns[0], l_s[0], pos_i-1, pos0, ns[1], l_s[1],pos_j-1,M->CL); + /*e=((M->get_dp_cost_list)[M->model_properties[state][M->START_EMISSION]])(A, pos0, ns[0], l_s[0], pos_i-1, pos0, ns[1], l_s[1],pos_j-1,M->CL);*/ + + Mat [state*mI+i*mJ+j]=t+e*l; + LMat [state*mI+i*mJ+j]=l; + trace [state*mI+i*mJ+j]=M->START; + } + } + } + +/*DYNAMIC PROGRAMMING: Forward Pass*/ + + /*Diagonals: + M->diag[0]=Number of diagonals being considered + M->diag[1]=First diagonal being considered + Diagonals are numbered 1...L0+l1-1 + 1 is the bottom-left diag + */ + + for (i=1; i<=l0;i++) + { + for (j=1; j<=ndiag;j++) + { + pos_j=M->diag[j]-l0+i; + pos_i=i; + + if (pos_j<=0 || pos_j>l1 )continue; + last_i=i; + last_j=j; + + for (cur_state=0; cur_stateSTART; cur_state++) + { + if (M->model_properties[cur_state][M->DELTA_J]) + { + prev_j=j+M->model_properties[cur_state][M->DELTA_J]; + prev_i=i+M->model_properties[cur_state][M->DELTA_I]*FABS((M->diag[j]-M->diag[prev_j])); + + } + else + { + prev_j=j; + prev_i=i+M->model_properties[cur_state][M->DELTA_I]; + } + + + len_i=FABS((i-prev_i)); + len_j=FABS((M->diag[prev_j]-M->diag[j])); + len=MAX(len_i, len_j); + + em=((M->model_emission_function[cur_state][M->EMISSION]))(A, pos0, ns[0], l_s[0], pos_i-1, pos0, ns[1], l_s[1],pos_j-1,M->CL); + /*em=((M->get_dp_cost_list)[M->model_properties[cur_state][M->EMISSION]])(A, pos0, ns[0], l_s[0], pos_i-1, pos0, ns[1], l_s[1],pos_j-1,M->CL);*/ + + for (pc=best_pc=UNDEFINED, model_index=1; model_index<=M->bounded_model[cur_state][0]; model_index++) + { + prev_state=M->bounded_model[cur_state][model_index]; + + if(prev_i<0 || prev_j<0 ||prev_i>l0 || prev_j>ndiag || len==UNDEFINED)prev_score=UNDEFINED; + else prev_score=Mat[prev_state*mI+prev_i*mJ+prev_j]; + t=M->model[prev_state][cur_state]; + e=em; + + if (prev_score==UNDEFINED || len==UNDEFINED)e=UNDEFINED; + else if (len==0|| e==UNDEFINED)e=UNDEFINED; + else e=e*len; + + if (is_defined_int(3,prev_score,e, t)) + { + pc=prev_score+t+e; + } + else pc=UNDEFINED; + + /*Identify the best previous score*/ + if (best_pc==UNDEFINED || (pc>best_pc && pc!=UNDEFINED)) + { + prev[cur_state]=prev_state; + best_pc=pc; + + } + } + + Mat[cur_state*mI+i*mJ+j]=best_pc; + + + + if ( Mat[cur_state*mI+i*mJ+j]==UNDEFINED) + { + LMat[cur_state*mI+i*mJ+j]=UNDEFINED; + trace[cur_state*mI+i*mJ+j]=UNDEFINED; + continue; + } + + else if ( prev[cur_state]==cur_state) + { + LMat [cur_state*mI+i*mJ+j]= LMat [cur_state*mI+prev_i*mJ+prev_j]+len; + trace[cur_state*mI+i*mJ+j]= trace[cur_state*mI+prev_i*mJ+prev_j]; + } + else + { + LMat[cur_state*mI+i*mJ+j]=len; + trace[cur_state*mI+i*mJ+j]=prev[cur_state]; + } + } + } + } + + + i=last_i; + j=last_j; + for (pc=best_pc=UNDEFINED, state=0; stateSTART; state++) + { + t=M->model[state][M->END]; + e=( M->model_emission_function[state][M->TERM_EMISSION])(A, pos0, ns[0], l_s[0], pos_i-1, pos0, ns[1], l_s[1],pos_j-1,M->CL); + + /*e=((M->get_dp_cost_list)[M->model_properties[state][M->TERM_EMISSION]])(A, pos0, ns[0], l_s[0], pos_i-1, pos0, ns[1], l_s[1],pos_j-1,M->CL);*/ + + l=LMat[state*mI+i*mJ+j]; + + + if (!is_defined_int(4,t,e,Mat[state*mI+i*mJ+j],l))Mat[state*mI+i*mJ+j]=UNDEFINED; + else Mat[state*mI+i*mJ+j]+=t+e*(l); + pc=Mat[state*mI+i*mJ+j]; + + + if (best_pc==UNDEFINED || (pc>best_pc && pc!=UNDEFINED)) + { + k=state; + best_pc=pc; + } + } + DPR->score=best_pc; + +/*TRACEBACK*/ + + + e=0; + len=0; + + + while (k!=M->START) + { + next_k=trace[k*mI+i*mJ+j]; + + new_i=i; + new_j=j; + l=LMat[k*mI+i*mJ+j]; + for (a=0; a< l; a++) + { + DPR->traceback[len++]=k; + } + new_i+=M->model_properties[k][M->DELTA_I]*l; + + + if ( M->model_properties[k][M->DELTA_J]) + { + while ( next_k!=M->START && FABS((M->diag[j]-M->diag[new_j]))!=l)new_j+=M->model_properties[k][M->DELTA_J]; + } + + i=new_i; + j=new_j; + k=next_k; + } + DPR->len=len; + DPR->traceback[DPR->len++]=M->START; + invert_list_int (DPR->traceback,DPR->len); + DPR->traceback[DPR->len]=M->END; + + vfree (prev); + free_int (pos0, -1); + return DPR; + + + } + + +Constraint_list* free_dp_model (Dp_Model *D) + { + Constraint_list *CL; + + if ( !D)return NULL; + CL=D->CL; + vfree (D->diag); + free_int (D->model, -1); + free_int (D->model_properties, -1); + free_int (D->bounded_model, -1); + + vfree (D); + return CL; + } + +Dp_Result * free_dp_result (Dp_Result *D ) + { + if (!D) return NULL; + vfree ( D->traceback); + vfree (D); + return NULL; + } + +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/util_dp_gotoh_nw.c b/binaries/src/tcoffee/t_coffee_source/util_dp_gotoh_nw.c new file mode 100644 index 0000000..2af7edc --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/util_dp_gotoh_nw.c @@ -0,0 +1,2413 @@ +#include +#include +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" +#include "dp_lib_header.h" + +#define addE(i,j,d,s,list,n)\ + if (list)\ + {\ + int max_n; \ + Memcontrol *ppp; \ + if (!list[0])\ + {\ + list[0]=vcalloc ( 1000, sizeof (int*));\ + }\ + \ + ppp=(Memcontrol*)list[0]; \ + ppp-=2; \ + max_n=ppp[0].size/sizeof(int*);\ + if (n[0]>=max_n){max_n+=1000;list[0]=vrealloc (list[0], max_n*sizeof (int*));} \ + if (!list[0][n[0]])list[0][n[0]]=vcalloc (7, sizeof (int)); \ + list[0][n[0]][0]=i; \ + list[0][n[0]][1]=j; \ + list[0][n[0]][3]=d; \ + list[0][n[0]][2]=s; \ + n[0]++; \ + } \ + +int cl2pair_list_ecl ( Alignment *A, int *ns, int **ls, Constraint_list *CL, int ***list_in, int *n_in); + + + +/*******************************************************************************/ +/* idscore_pairseq: measure the % id without delivering thze aln*/ +/* */ +/* makes DP between the the ns[0] sequences and the ns[1] */ +/* */ +/* for MODE, see the function get_dp_cost */ +/*******************************************************************************/ +int idscore_pairseq (char *s1, char *s2, int gop, int gep, int **m, char *comp_mode) +{ + int **I, **D, **M, *P; + int i, j,l1, l2, l,score, id, igop,match; + + + l1=strlen (s1); l2=strlen (s2); + lower_string (s1); lower_string (s2); + + I=declare_int (6,l2+1);D=declare_int (6,l2+1);M=declare_int (6,l2+1); + for (j=0; j<=l2; j++) + { + D[0][j]=gep*j;M[0][j]=2*gep*j;D[4][j]=0; + } + + for (i=1; i<=l1; i++) + { + + I[1][0]=i*gep; + M[1][0]=2*i*gep; + + for (j=1; j<=l2; j++) + { + score=m[s1[i-1]-'a'][s2[j-1]-'a']; + id=(s1[i-1]==s2[j-1])?1:0; + + igop=(i==l1 || j==l2)?0:gop; + + if ((D[0][j]+gep)>(M[0][j]+igop+gep)) {D[1][j]=D[0][j]+gep; D[3][j]=D[2][j]; D[5][j]=D[4][j];} + else {D[1][j]=M[0][j]+igop+gep; D[3][j]=M[2][j]; D[5][j]=M[4][j];} + + if ( (I[1][j-1]+gep)>(M[1][j-1]+igop+gep)){I[1][j]=I[1][j-1]+gep; I[3][j]=I[3][j-1]; I[5][j]=I[5][j-1];} + else {I[1][j]=M[1][j-1]+igop+gep; I[3][j]=M[3][j-1]; I[5][j]=M[5][j-1];} + + match=M[0][j-1]+score; + if (I[1][j]>match && I[1][j]>D[1][j]) {M[1][j]=I[1][j] ; M[3][j]=I[3][j]; M[5][j]=I[5][j];} + else if (D[1][j]>match) {M[1][j]=D[1][j] ; M[3][j]=D[3][j]; M[5][j]=D[5][j];} + else {M[1][j]=match ; M[3][j]=M[2][j-1]+id; M[5][j]=M[4][j-1]+1;} + } + P=I[0]; I[0]=I[1]; I[1]=P; + P=I[2]; I[2]=I[3]; I[3]=P; + P=I[4]; I[4]=I[5]; I[5]=P; + + P=D[0]; D[0]=D[1]; D[1]=P; + P=D[2]; D[2]=D[3]; D[3]=P; + P=D[4]; D[4]=D[5]; D[5]=P; + + P=M[0]; M[0]=M[1]; M[1]=P; + P=M[2]; M[2]=M[3]; M[3]=P; + P=M[4]; M[4]=M[5]; M[5]=P; + } + + + + + if ( strstr (comp_mode, "sim2")) + { + l=MIN(l1,l2); + score=(l==0)?0:(M[2][l2]*100)/l; + } + else if ( strstr (comp_mode, "sim3")) + { + l=MAX(l1,l2); + score=(l==0)?0:(M[2][l2]*100)/l; + } + else if ( strstr (comp_mode, "cov")) + { + l=MAX(l1,l2); + score=(l==0)?0:((M[4][l2]*100)/l); + } + else + { + //default: simple sim + l=M[4][l2]; + score=(l==0)?0:(M[2][l2]*100)/l; + } + + free_int (I, -1); + free_int (D, -1); + free_int (M, -1); + + return score; +} + +int test_pair_wise (Alignment *A, int *ns, int **l_s, Constraint_list *CL) +{ + int a,l0, l1, n; + char buf[VERY_LONG_STRING]; + char *gap, *seq; + + l0=strlen (A->seq_al[l_s[0][0]]); + l1=strlen (A->seq_al[l_s[1][0]]); + + n=(l0<5)?l0/2:5; + gap=generate_null(l1-n); + for (a=0;aseq_al[l_s[0][a]]; + sprintf (buf, "%s%s",seq, gap); + sprintf (seq, "%s", buf); + } + vfree (gap); + gap=generate_null(l0-n); + + for (a=0;aseq_al[l_s[1][a]]; + sprintf (buf, "%s%s",seq, gap); + sprintf (seq, "%s", buf); + } + vfree(gap); + + + A->len_aln=strlen (A->seq_al[l_s[0][0]]); + A->score=A->score_aln=100; + return 100; +} + +int idscore_pair_wise (Alignment *A,int*ns, int **l_s,Constraint_list *CL) +{ + + A->score_aln=A->score=idscore_pairseq (A->seq_al[l_s[0][0]], A->seq_al[l_s[1][0]], CL->gop, CL->gep,CL->M, "sim3"); + return A->score_aln; +} +int dp_max (int *trace, int n, ...); +int dp_max (int *trace, int n, ...) +{ + va_list ap; + int a, v, t, best_v=0; + + va_start (ap, n); + for (a=0; a< n; a++) + { + t=va_arg (ap, int); + v=va_arg (ap, int); + + if (a==0) + { + best_v=v; + trace[0]=t; + } + else + { + if (v>best_v) + { + best_v=v; + trace[0]=t; + } + } + } + + return best_v; +} +int is_tied (int *trace, int n, ...); +int is_tied(int *trace, int n, ...) +{ + va_list ap; + int a, v, t, best_v=0; + int nties=0; + + va_start (ap, n); + for (a=0; a< n; a++) + { + t=va_arg (ap, int); + v=va_arg (ap, int); + + if (a==0) + { + best_v=v; + trace[0]=t; + } + else + { + if (v>best_v) + { + best_v=v; + trace[0]=t; + } + } + } + va_end(ap); + va_start (ap,n); + for (a=0; aseq_al[l_s[0][0]]); + l2=strlen (A->seq_al[l_s[1][0]]); + + n=1; + M1=n++;D1=n++;I1=n++;M2=n++; + t=declare_arrayN(3, sizeof (int),n, l1+1, l2+1); + m=declare_arrayN(3, sizeof (int),n, l1+1, l2+1); + + + gop=CL->gop*SCORE_K; + gep=CL->gep*SCORE_K; + tgop=gop; + unmatch=gep; + + pos0=aln2pos_simple ( A,-1, ns, l_s); + + + for (j=1; j<=l2; j++) + { + m[D1][0][j]=gep*j; + + m[M1][0][j]=2*gep*j; + m[M2][0][j]=4*gep*j; + } + + + for (i=1; i<=l1; i++) + { + m[I1][i][0]=i*gep; + m[M2][i][0]=4*i*gep; + m[M1][i][0]=2*i*gep; + + for ( j=1; j<=l2; j++) + { + rgop=(i==l1 || j==1)?0:gop; + rgop=gop; + sub=(CL->get_dp_cost) (A, pos0, ns[0], l_s[0], i-1, pos0, ns[1], l_s[1],j-1,CL); + m[M1][i][j]=dp_max (&trace,4,M1,m[M1][i-1][j-1],I1, m[I1][i-1][j-1],D1,m[D1][i-1][j-1],M2,m[M2][i-1][j-1])+sub; + t[M1][i][j]=trace; + + m[D1][i][j]=dp_max (&trace,3, M1,m[M1][i][j-1]+rgop,D1, m[D1][i][j-1]+gep, M2, m[M2][i][j-1]); + t[D1][i][j]=trace; + + m[I1][i][j]=dp_max (&trace,3, M1,m[M1][i-1][j]+rgop, I1, m[I1][i-1][j]+gep, M2, m[M2][i-1][j]); + t[I1][i][j]=trace; + + m[M2][i][j]=dp_max (&trace,4,M1,m[M1][i-1][j-1]+tgop,I1, m[I1][i-1][j-1]+tgop,D1,m[D1][i-1][j-1]+tgop,M2,m[M2][i-1][j-1])+unmatch; + t[M2][i][j]=trace; + + } + + } + score=dp_max (&trace,4, M1,m[M1][l1][l2],D1,m[D1][l1][l2],I1, m[I1][l1][l2],M2,m[M2][l1][l2]); + LEN=0;i=l1;j=l2; + al=declare_char (2, l1+l2+1); + + + trace=t[trace][i][j]; + while (!(i==0 &&j==0)) + { + + ntrace=t[trace][i][j]; + if (i==0) + { + al[0][LEN]=0; + al[1][LEN]=1; + j--; + LEN++; + } + else if ( j==0) + { + al[0][LEN]=1; + al[1][LEN]=0; + i--; + LEN++; + } + else if ( trace==M1) + { + al[0][LEN]=1; + al[1][LEN]=1; + i--; j--; + LEN++; + } + else if ( trace==M2) + { + al[0][LEN]=1; + al[1][LEN]=0; + LEN++; + + al[0][LEN]=0; + al[1][LEN]=1; + LEN++; + + i--; j--; + + } + else if ( trace==D1) + { + al[0][LEN]=0; + al[1][LEN]=1; + j--; + LEN++; + } + else if ( trace == I1) + { + al[0][LEN]=1; + al[1][LEN]=0; + i--; + LEN++; + } + trace=ntrace; + + } + + invert_list_char ( al[0], LEN); + invert_list_char ( al[1], LEN); + if ( A->declared_len<=LEN)A=realloc_aln2 ( A,A->max_n_seq, 2*LEN); + + aln=A->seq_al; + char_buf= vcalloc (LEN+1, sizeof (char)); + for ( c=0; c< 2; c++) + { + for ( a=0; a< ns[c]; a++) + { + int ch=0; + for ( b=0; b< LEN; b++) + { + if (al[c][b]==1) + char_buf[b]=aln[l_s[c][a]][ch++]; + else + char_buf[b]='-'; + } + char_buf[b]='\0'; + sprintf (aln[l_s[c][a]],"%s", char_buf); + } + } + + + A->len_aln=LEN; + A->nseq=ns[0]+ns[1]; + free_arrayN((void *)m, 3); + free_arrayN((void *)t, 3); + vfree (char_buf); + free_char (al, -1); + return score; +} + +int ** aln2local_penalties (Alignment *A, int n, int *ls, Constraint_list *CL, int **lg); +int ** aln2local_penalties (Alignment *A, int n, int *ls, Constraint_list *CL, int **lg) +{ + //adapted from gap_count in MAFFT V 5.5 + int p,s,l, c1, c2; + int gep,gop; + int open=3, close=4, gap=5; + + gop=CL->gop*SCORE_K; + gep=CL->gep*SCORE_K; + + l=strlen (A->seq_al[ls[0]]); + + if (!lg) + { + lg=declare_int (6, l); + } + + if ( read_array_size_new (lg[0])seq_al[ls[s]][p]; + + if (c1!='-' && c2=='-')lg[open][p]++; + if (c1=='-' && c2!='-')lg[close][p]++; + if ( c1=='-')lg[gap][p]++; + c1=c2; + } + } + + for (p=0; p gives low quality results + lg[GEP][p]=gep;//(1-((float)lg[gap][p]/(float)n))*gep; + lg[open][p]=lg[close][p]=lg[gap][p]=0; + + } + + return lg; +} +int free_gotoh_pair_wise_lgp() +{ + return gotoh_pair_wise_lgp (NULL, NULL, NULL, NULL); +} +int gotoh_pair_wise_lgp ( Alignment *A, int *ns, int **l_s, Constraint_list *CL) +{ + int i,j, li, lj, n, sub, trace,ntrace, a, b, c, score; + int I, J; + int M1, I1, D1, LEN; + char **al, *char_buf, **aln; + int **pos0, **pos; + Alignment *Aln; + + int gop[2], gcp[2], gep[2]; + static int ***gpl, ***t, ***m; + static int max_li, max_lj; + + + + //gotoh_pair_wise ( A, ns, l_s,CL); + //ungap_sub_aln (A, ns[0], l_s[0]); + //ungap_sub_aln (A, ns[1], l_s[1]); + + if (!A) + { + free_arrayN((void**)gpl, 3); + free_arrayN((void**)t, 3); + free_arrayN((void**)m, 3); + max_li=max_lj=0; + return 0; + } + + I=0;J=1; + + + li=strlen (A->seq_al[l_s[I][0]]); + lj=strlen (A->seq_al[l_s[J][0]]); + + if ( !gpl)gpl=vcalloc ( 2, sizeof (int**)); + gpl[I]=aln2local_penalties (A,ns[I], l_s[I], CL,gpl[I]); + gpl[J]=aln2local_penalties (A,ns[J], l_s[J], CL,gpl[J]); + + + n=1; + M1=n++;D1=n++;I1=n++; + + if ( li>max_li ||lj>max_lj ) + { + free_arrayN((void**)t, 3); + free_arrayN((void**)m, 3); + + + max_li=li; + max_lj=lj; + t=declare_arrayN(3, sizeof (int),n, max_li+1, max_lj+1); + m=declare_arrayN(3, sizeof (int),n, max_li+1, max_lj+1); + + } + pos0=aln2pos_simple ( A,-1, ns, l_s); + + //Compatibility with Macro + Aln=A; + pos=pos0; + + for (j=1; j<=lj; j++) + { + gep[J]=gpl[J][GEP][j-1]; + m[D1][0][j]=gep[J]*j; + m[I1][0][j]=m[D1][0][j]-1; + m[M1][0][j]=m[D1][0][j]-1; + } + + //D1: gap in sequence I + //I1: gap in sequence J + + + for (i=1; i<=li; i++) + { + gep[I]=gpl[I][GEP][i-1]; + gop[I]=gpl[I][GOP][i-1]; + gcp[I]=gpl[I][GCP][i-1]; + + m[I1][i][0]=i*gep[I]; + m[D1][i][0]= m[I1][i][0]-1; + m[M1][i][0]= m[I1][i][0]-1; + + + + gop[I]=(i==1 || i==li )?0:gop[I]; + gcp[I]=(i==1 || i==li )?0:gcp[I]; + + + for ( j=1; j<=lj; j++) + { + + gep[J]=gpl[J][GEP][j-1]; + gop[J]=gpl[J][GOP][j-1]; + gcp[J]=gpl[J][GCP][j-1]; + + //gep[J]=gep[I]=(gep[J]+gep[I])/2; + //gop[J]=gop[I]=(gop[J]+gop[I])/2; + //gcp[J]=gcp[I]=(gcp[J]+gcp[I])/2; + + + gop[J]=(j==1 || j==lj )?0:gop[J]; + gcp[J]=(j==1 || j==lj )?0:gcp[J]; + + + //sub=(CL->get_dp_cost) (A, pos0, ns[0], l_s[0], i-1, pos0, ns[1], l_s[1],j-1,CL); + sub=TC_SCORE((i-1), (j-1)); + + m[M1][i][j]=dp_max (&trace,3,M1,m[M1][i-1][j-1],I1, m[I1][i-1][j-1]+gcp[I],D1,m[D1][i-1][j-1]+gcp[J])+sub; + t[M1][i][j]=trace; + + + m[D1][i][j]=dp_max (&trace,2, M1,m[M1][i][j-1]+gop[J]+gep[J],D1, m[D1][i][j-1]+gep[J]); + t[D1][i][j]=trace; + + + m[I1][i][j]=dp_max (&trace,2, M1,m[M1][i-1][j]+gop[I]+gep[I],I1, m[I1][i-1][j]+gep[I]); + t[I1][i][j]=trace; + + } + + } + score=dp_max (&trace,3, M1,m[M1][li][lj],D1,m[D1][li][lj],I1, m[I1][li][lj]); + + LEN=0;i=li;j=lj; + al=declare_char (2, li+lj); + + + trace=t[trace][i][j]; + while (!(i==0 &&j==0)) + { + + ntrace=t[trace][i][j]; + + + if (i==0) + { + al[0][LEN]=0; + al[1][LEN]=1; + j--; + LEN++; + } + else if ( j==0) + { + al[0][LEN]=1; + al[1][LEN]=0; + i--; + LEN++; + } + else if ( trace==M1) + { + al[0][LEN]=1; + al[1][LEN]=1; + i--; j--; + LEN++; + } + else if ( trace==D1) + { + al[0][LEN]=0; + al[1][LEN]=1; + j--; + LEN++; + } + else if ( trace == I1) + { + al[0][LEN]=1; + al[1][LEN]=0; + i--; + LEN++; + } + trace=ntrace; + + } + + invert_list_char ( al[0], LEN); + invert_list_char ( al[1], LEN); + if ( A->declared_len<=LEN)A=realloc_aln ( A,2*LEN+1); + + aln=A->seq_al; + char_buf= vcalloc (LEN+1, sizeof (char)); + for ( c=0; c< 2; c++) + { + for ( a=0; a< ns[c]; a++) + { + int ch=0; + for ( b=0; b< LEN; b++) + { + if (al[c][b]==1) + char_buf[b]=aln[l_s[c][a]][ch++]; + else + char_buf[b]='-'; + } + char_buf[b]='\0'; + sprintf (aln[l_s[c][a]],"%s", char_buf); + } + } + + + A->len_aln=LEN; + A->nseq=ns[0]+ns[1]; + vfree (char_buf); + free_char (al, -1); + free_int (pos0, -1); + return score; +} +/*******************************************************************************/ +/* GLOCAL 2 */ +/* */ +/* makes DP between the the ns[0] sequences and the ns[1] */ +/* */ +/* for MODE, see the function get_dp_cost */ +/*******************************************************************************/ +int glocal2_pair_wise (Alignment *IN,int*ns, int **ls,Constraint_list *CL) +{ + int a, b, s=0; + Alignment *A, *R,*L; + char *seq, *buf; + + buf=vcalloc (1000, sizeof (char)); + seq=vcalloc (1000, sizeof (char)); + + A=copy_aln (IN,NULL); + L=copy_aln (IN,NULL); + R=copy_aln (IN,NULL); + + gotoh_pair_wise_sw (A, ns, ls, CL); + + HERE ("1"); + for (a=0; a<2; a++) + { + for (b=0; bseq_al[s]); + + seq[A->order[s][2]]='\0'; + sprintf (L->seq_al[s], "%s", seq); + sprintf (R->seq_al[s], "%s", seq+A->order[s][3]+1); + } + } + HERE ("2"); + print_sub_aln (A, ns, ls); + gotoh_pair_wise(L, ns, ls, CL); + print_sub_aln (L, ns, ls); + gotoh_pair_wise(R, ns, ls, CL); + print_sub_aln (R, ns, ls); + + IN=realloc_aln (IN, A->len_aln+L->len_aln+R->len_aln+1); + for (a=0; a<2; a++) + { + for (b=0; bseq_al[s], "%s%s%s",L->seq_al[s], A->seq_al[s], R->seq_al[s]); + } + } + IN->len_aln=strlen (IN->seq_al[s]); + + print_sub_aln (IN, ns, ls); + vfree (seq); vfree (buf); + free_aln (A); free_aln (L);free_aln (R); + return IN->score_aln; +} + + +int gotoh_pair_wise (Alignment *A,int*ns, int **l_s,Constraint_list *CL) + { +/*******************************************************************************/ +/* NEEDLEMAN AND WUNSCH (GOTOH) */ +/* */ +/* makes DP between the the ns[0] sequences and the ns[1] */ +/* */ +/* for MODE, see the function get_dp_cost */ +/*******************************************************************************/ + + +/*TREATMENT OF THE TERMINAL GAP PENALTIES*/ +/*TG_MODE=0---> gop and gep*/ +/*TG_MODE=1---> --- gep*/ +/*TG_MODE=2---> --- ---*/ + + + int TG_MODE; + int l_gop, l_gep; + int gop, gep; + int maximise; +/*VARIANLES FOR THE MULTIPLE SEQUENCE ALIGNMENT*/ + int a, b, i, j; + + int *cc; + int *dd,*ddg; + int e, eg; + + int lenal[2], len; + int t, c=0,s, ch; + int sub; + int fop; + int score=0; + int **pos0; + static char **al; + char **aln; + int ala, alb,LEN; + char *buffer; + char *char_buf; +/*trace back variables */ + static int **trace; + static int **bit; + int *bi; + int *tr; + int dim; + int ibit=0; + int k; + int sample=0;//road==0, random tie; road=1: upper road; road=2 lower road; + /********Prepare penalties*******/ + gop=CL->gop*SCORE_K; + gep=CL->gep*SCORE_K; + TG_MODE=CL->TG_MODE; + maximise=CL->maximise; + + +/********************************/ +/*CLEAN UP AFTER USE*/ + if ( A==NULL) + { + free_int (trace,-1); + free_int (bit, -1); + trace=NULL; + bit=NULL; + + free_char (al,-1); + al=NULL; + return 0; + } + +/*DO MEMORY ALLOCATION FOR DP*/ + + + sample=atoigetenv ("SAMPLE_DP_4_TCOFFEE"); + + lenal[0]=strlen (A->seq_al[l_s[0][0]]); + lenal[1]=strlen (A->seq_al[l_s[1][0]]); + len= MAX(lenal[0],lenal[1])+1; + + buffer=vcalloc ( 2*len, sizeof (char)); + al=declare_char (2, 2*len); + + char_buf= vcalloc (2*len, sizeof (char)); + + + dd = vcalloc (len, sizeof (int)); + + + cc = vcalloc (len, sizeof (int)); + ddg=vcalloc (len, sizeof (int)); + + + + + + dim=(trace==NULL)?0:read_size_int ( trace,sizeof (int*)); + trace =realloc_int ( trace,dim,dim,MAX(0,len-dim), MAX(0,len-dim)); + bit =realloc_int ( bit,dim,dim,MAX(0,len-dim), MAX(0,len-dim)); + +/*END OF MEMORY ALLOCATION*/ + + + /* + 0(s) +(dd) + \ | + \ | + \ | + \ | + \ | + \ | + \| + -(e)----O + */ + + pos0=aln2pos_simple ( A,-1, ns, l_s); + + + cc[0]=0; + tr=trace[0]; + bi=bit[0]; + tr[0]=1; + for ( j=1; j<=lenal[1]; j++)tr[j]=-1; + + t=(TG_MODE==0)?gop:0; + + + for (cc[0]=0,j=1; j<=lenal[1]; j++) + { + + l_gop=(TG_MODE==0)?gop:0; + l_gep=(TG_MODE==2)?0:gep; + + cc[j]=t=t+l_gep; + dd[j]= t+ gop; + } + + t=(TG_MODE==0)?gop:0; + + for (i=1; i<=lenal[0];i++) + { + tr=trace[i]; + bi=bit[i]; + s=cc[0]; + + l_gop=(TG_MODE==0)?gop:0; + l_gep=(TG_MODE==2)?0:gep; + + + + cc[0]=c=t=t+l_gep; + e=t+ gop; + tr[0]=1; + + + + for (eg=0,j=1; j<=lenal[1];j++) + { + + sub=(CL->get_dp_cost) (A, pos0, ns[0], l_s[0], i-1, pos0, ns[1], l_s[1],j-1,CL); + + /*get the best Insertion*/ + l_gop=(i==lenal[0] || i==1 )?((TG_MODE==0)?gop:0):gop; + l_gep=(i==lenal[0] || i==1)?((TG_MODE==2)?0:gep):gep; + + + if ( a_better_than_b ( e,c+l_gop, maximise))eg++; + else eg=1; + e=best_of_a_b (e, c+l_gop, maximise)+l_gep; + + /*Get the best deletion*/ + l_gop=(j==lenal[1] || j==1)?((TG_MODE==0)?gop:0):gop; + l_gep=(j==lenal[1] || j==1)?((TG_MODE==2)?0:gep):gep; + + + if ( a_better_than_b ( dd[j], cc[j]+l_gop, maximise))ddg[j]++; + else ddg[j]=1; + dd[j]=best_of_a_b( dd[j], cc[j]+l_gop,maximise)+l_gep; + + + + c=best_int(3,maximise,&fop, e, s+sub,dd[j]); + + + if (sample==1) + { + int rr[3]; + int nn=0; + int fop2; + int ind; + if (c==e)rr[nn++]=0; + if (c==(s+sub))rr[nn++]=1; + if (c==dd[j])rr[nn++]=2; + ind=rand()%(nn); + fop=rr[ind]; + if (nn>1) + { + // HERE ("NN=%d index=%d",nn, ind); + //HERE ("%d ->%d", fop, fop2); + //HERE ("%d %d %d", e, s+sub,dd[j]); + ; + } + } + else if (sample==0) + { + /*Chose Substitution for tie breaking*/ + if ( fop==0 && (s+sub)==e)fop=1; + else if ( fop==2 && (s+sub)==dd[j])fop=1; + /*Chose Deletion for tie breaking*/ + else if ( fop==2 && e==dd[j])fop=2; + } + else if (sample==-1) + { + + if ( fop==0 && (s+sub)==e)fop=1; + else if ( fop==1 && (s+sub)==dd[j])fop=2; + /*Chose Deletion for tie breaking*/ + else if ( fop==2 && e==dd[j])fop=1; + } + bi[j]=0; + if (c==e){bi[j]++;} + if (c==(s+sub)){bi[j]++;} + if (c==(dd[j])){bi[j]++;} + //bi[j]--; + + + fop-=1; + s=cc[j]; + cc[j]=c; + + + + + + if ( fop<0) + {tr[j]=(TRACE_TYPE)fop*eg; + } + else if ( fop>0) + {tr[j]=(TRACE_TYPE)fop*ddg[j]; + } + else if (fop==0) + {tr[j]=(TRACE_TYPE)0; + } + fop= -2; + } + + } + + score=c; + + i=lenal[0]; + j=lenal[1]; + ala=alb=0; + + if (!A->ibit)A->ibit=1; //set the bit counter on + while (i>=0 && j>=0 && ((i+j)!=0)) + { + if ( i==0) + k=-1; + else if ( j==0) + k=1; + else if ( j==0 && i==0) + k=1; + else + { + k=trace[i][j]; + A->ibit*=bit[i][j]; + } + + + if (k==0) + { + + al[0][ala++]=1; + al[1][alb++]=1; + i--; + j--; + } + else if (k>0) + { + + for ( a=0; a< k; a++) + { + al[0][ala++]=1; + al[1][alb++]=0; + i--; + } + } + else if (k<0) + { + + for ( a=0; a>k; a--) + { + al[0][ala++]=0; + al[1][alb++]=1; + j--; + } + } + } + + LEN=ala; + c=LEN-1; + + + + invert_list_char ( al[0], LEN); + invert_list_char ( al[1], LEN); + if ( A->declared_len<=LEN)A=realloc_aln2 ( A,A->max_n_seq, 2*LEN); + aln=A->seq_al; + + for ( c=0; c< 2; c++) + { + for ( a=0; a< ns[c]; a++) + { + ch=0; + for ( b=0; b< LEN; b++) + { + if (al[c][b]==1) + char_buf[b]=aln[l_s[c][a]][ch++]; + else + char_buf[b]='-'; + } + char_buf[b]='\0'; + sprintf (aln[l_s[c][a]],"%s", char_buf); + } + } + + + A->len_aln=LEN; + A->nseq=ns[0]+ns[1]; + + + vfree ( cc); + vfree (dd); + vfree (ddg); + vfree (buffer); + vfree (char_buf); + + free_char ( al, -1); + free_int (pos0, -1); + + + + + return score; + } + + +int get_transition_cost (Alignment *A, int **posi, int ni, int *li, int i, int **posj, int nj, int *lj, int j,Constraint_list *CL); +int gotoh_pair_wise_lgp_sticky ( Alignment *A, int *ns, int **l_s, Constraint_list *CL) +{ + int i,j, li, lj, n, sub, trace,ntrace, a, b, c, score; + int I, J; + int M1, I1, D1, LEN; + char **al, *char_buf, **aln; + int **pos0; + + int gop[2], gcp[2], gep[2]; + static int ***gpl, ***t, ***m; + static int max_li, max_lj; + + + + //gotoh_pair_wise ( A, ns, l_s,CL); + //ungap_sub_aln (A, ns[0], l_s[0]); + //ungap_sub_aln (A, ns[1], l_s[1]); + + I=0;J=1; + + + li=strlen (A->seq_al[l_s[I][0]]); + lj=strlen (A->seq_al[l_s[J][0]]); + + if ( !gpl)gpl=vcalloc ( 2, sizeof (int**)); + gpl[I]=aln2local_penalties (A,ns[I], l_s[I], CL,gpl[I]); + gpl[J]=aln2local_penalties (A,ns[J], l_s[J], CL,gpl[J]); + + + n=1; + M1=n++;D1=n++;I1=n++; + + if ( li>max_li ||lj>max_lj ) + { + free_arrayN((void**)t, 3); + free_arrayN((void**)m, 3); + + + max_li=li; + max_lj=lj; + t=declare_arrayN(3, sizeof (int),n, max_li+1, max_lj+1); + m=declare_arrayN(3, sizeof (int),n, max_li+1, max_lj+1); + + } + pos0=aln2pos_simple ( A,-1, ns, l_s); + + + for (j=1; j<=lj; j++) + { + gep[J]=gpl[J][GEP][j-1]; + m[D1][0][j]=gep[J]*j; + m[I1][0][j]=m[D1][0][j]-1; + m[M1][0][j]=m[D1][0][j]-1; + } + + //D1: gap in sequence I + //I1: gap in sequence J + + + for (i=1; i<=li; i++) + { + gep[I]=gpl[I][GEP][i-1]; + gop[I]=gpl[I][GOP][i-1]; + gcp[I]=gpl[I][GCP][i-1]; + + m[I1][i][0]=i*gep[I]; + m[D1][i][0]= m[I1][i][0]-1; + m[M1][i][0]= m[I1][i][0]-1; + + + + gop[I]=(i==1 || i==li )?0:gop[I]; + gcp[I]=(i==1 || i==li )?0:gcp[I]; + + + for ( j=1; j<=lj; j++) + { + int transition; + + gep[J]=gpl[J][GEP][j-1]; + gop[J]=gpl[J][GOP][j-1]; + gcp[J]=gpl[J][GCP][j-1]; + + //gep[J]=gep[I]=(gep[J]+gep[I])/2; + //gop[J]=gop[I]=(gop[J]+gop[I])/2; + //gcp[J]=gcp[I]=(gcp[J]+gcp[I])/2; + + + gop[J]=(j==1 || j==lj )?0:gop[J]; + gcp[J]=(j==1 || j==lj )?0:gcp[J]; + + + sub=(CL->get_dp_cost) (A, pos0, ns[0], l_s[0], i-1, pos0, ns[1], l_s[1],j-1,CL); + transition=get_transition_cost (A, pos0, ns[0], l_s[0], i-1, pos0, ns[1], l_s[1],j-1,CL); + + m[M1][i][j]=dp_max (&trace,3,M1,m[M1][i-1][j-1]+transition,I1, m[I1][i-1][j-1]+gcp[I],D1,m[D1][i-1][j-1]+gcp[J])+sub; + t[M1][i][j]=trace; + + + m[D1][i][j]=dp_max (&trace,2, M1,m[M1][i][j-1]+gop[J]+gep[J],D1, m[D1][i][j-1]+gep[J]); + t[D1][i][j]=trace; + + + m[I1][i][j]=dp_max (&trace,2, M1,m[M1][i-1][j]+gop[I]+gep[I],I1, m[I1][i-1][j]+gep[I]); + t[I1][i][j]=trace; + + } + + } + score=dp_max (&trace,3, M1,m[M1][li][lj],D1,m[D1][li][lj],I1, m[I1][li][lj]); + + LEN=0;i=li;j=lj; + al=declare_char (2, li+lj); + + + trace=t[trace][i][j]; + while (!(i==0 &&j==0)) + { + + ntrace=t[trace][i][j]; + + + if (i==0) + { + al[0][LEN]=0; + al[1][LEN]=1; + j--; + LEN++; + } + else if ( j==0) + { + al[0][LEN]=1; + al[1][LEN]=0; + i--; + LEN++; + } + else if ( trace==M1) + { + al[0][LEN]=1; + al[1][LEN]=1; + i--; j--; + LEN++; + } + else if ( trace==D1) + { + al[0][LEN]=0; + al[1][LEN]=1; + j--; + LEN++; + } + else if ( trace == I1) + { + al[0][LEN]=1; + al[1][LEN]=0; + i--; + LEN++; + } + trace=ntrace; + + } + + invert_list_char ( al[0], LEN); + invert_list_char ( al[1], LEN); + if ( A->declared_len<=LEN)A=realloc_aln ( A,2*LEN+1); + + aln=A->seq_al; + char_buf= vcalloc (LEN+1, sizeof (char)); + for ( c=0; c< 2; c++) + { + for ( a=0; a< ns[c]; a++) + { + int ch=0; + for ( b=0; b< LEN; b++) + { + if (al[c][b]==1) + char_buf[b]=aln[l_s[c][a]][ch++]; + else + char_buf[b]='-'; + } + char_buf[b]='\0'; + sprintf (aln[l_s[c][a]],"%s", char_buf); + } + } + + + A->len_aln=LEN; + A->nseq=ns[0]+ns[1]; + vfree (char_buf); + free_char (al, -1); + free_int (pos0, -1); + return score; +} +int get_transition_cost (Alignment *A, int **posi, int ni, int *li, int i, int **posj, int nj, int *lj, int j,Constraint_list *CL) +{ + /*counts the number of identical transitions between position i-1, i and j-1..j*/ + float t=0; + int a,s; + Sequence *S; + + if (i==0 || j==0)return 0; + + for (a=0; aseq[li[a]][i-1]==S->seq[li[a]][i-1])t++; + } + + for (a=0; aseq[li[a]][j-1]==S->seq[li[a]][j-1])t++; + } + + t=(t*10)/(float)(ni+nj); + return t; +} +/*******************************************************************************/ +/* idscore_pairseq: measure the % id without delivering thze aln*/ +/* */ +/* makes DP between the the ns[0] sequences and the ns[1] */ +/* */ +/* for MODE, see the function get_dp_cost */ +/*******************************************************************************/ + +int cl2pair_list ( Alignment *A, int *ns, int **ls, Constraint_list *CL, int ***list_in, int *n_in, int mode, int ndiag); +int cl2pair_list_ref ( Alignment *A, int *ns, int **ls, Constraint_list *CL, int ***list_in, int *n_in); +int cl2pair_list_ecf ( Alignment *A, int *ns, int **ls, Constraint_list *CL, int ***list_in, int *n_in); +int cl2pair_list_diag ( Alignment *A, int *ns, int **ls, Constraint_list *CL, int ***list_in, int *n_in, int add); +int cl2list_borders (Alignment *A, int *ns, int **ls, Constraint_list *CL, int ***list_in, int *n_in); +int cl2diag_cap (Alignment *A, int *ns, int **ls, Constraint_list *CL, int ***list_in, int *n_in); //add one element at the end of each segment so that they can be joined +int** cl2sorted_diagonals ( Alignment *A, int *ns, int **ls, Constraint_list *CL); +int** cl2sorted_diagonals_mat ( Alignment *A, int *ns, int **ls, Constraint_list *CL); +int** cl2sorted_diagonals_cs ( Alignment *A, int *ns, int **ls, Constraint_list *CL); +int list2nodup_list (Alignment *A, int *ns, int **ls, Constraint_list *CL, int ***list_in, int *n_in); +int fill_matrix ( Alignment *A, int *ns, int **ls, Constraint_list *CL, int ***list_in, int *n_in); + +int list2nodup_list ( Alignment *A, int *ns, int **ls, Constraint_list *CL, int ***list_in, int *n_in) +{ + int **list; + int n, a, b, c; + + list=list_in[0]; + n=n_in[0]; + + if ( !A)return 0; + + + sort_list_int (list,7, 1, 0, n-1); + for (b=a=1; aseq_al[ls[0][0]]); + l2=strlen (A->seq_al[ls[1][0]]); + + for (p1=0; p1<=l1; p1++) + { + if (p1==0 || p1==l1) + { + for (p2=0; p2<=l2; p2++) + { + addE(p1,p2,((l1-(p1))+(p2)),((CL->gep)*SCORE_K*p2), list_in, n_in); + } + } + else + { + for (a=0; a<2; a++) + { + p2=(a==0)?0:l2; + addE(p1,p2,((l1-(p1))+(p2)),((CL->gep)*SCORE_K*p1), list_in, n_in); + } + } + } + + return read_array_size (list_in[0], sizeof (int*)); +} + +int cl2diag_cap (Alignment *A, int *nns, int **ls, Constraint_list *CL, int ***list, int *n) +{ + int *sortseq; + + int in, a, b, al1, al2; + int max_n; + int cap=0; + int k=0; + + static int **ll; + static int max_ll; + int nll=0; + + int ns=0; + int nt=0; + int i,j,si,sj,ti,tj; + + if ( !A)vfree (ll);max_ll=0; + + al1=strlen (A->seq_al[ls[0][0]]); + al2=strlen (A->seq_al[ls[1][0]]); + + sortseq=vcalloc (7, sizeof (int)); + sortseq[0]=3;sortseq[1]=0;sortseq[2]=-1; + sort_list_int2 (list[0], sortseq,4, 0, n[0]-1); + vfree(sortseq); + in=n[0]; + + + if (!ll){max_ll=100;ll=vcalloc(max_ll,sizeof(int*));} + + for (a=0; a=max_ll){max_ll+=1000;ll=vrealloc (ll, max_ll*sizeof (int*));} + ll[nll++]=list[0][a]; + list[0][a][6]=_START; + } + + if (i==al1 || j==al2); + else if ( i==ni || j==nj); + else if ( ni-i!=1 || nj-j!=1) + { + if (nll>=max_ll){max_ll+=1000;ll=vrealloc (ll, max_ll*sizeof (int*));} + ll[nll++]=list[0][a]; + list[0][a][6]=_TERM; + } + } + + sortseq=vcalloc (7, sizeof (int)); + sortseq[0]=0;sortseq[1]=1;sortseq[2]=-1; + sort_list_int2 (ll, sortseq,4, 0,nll-1); + vfree (sortseq); + + for (a=0; aci){nl++;ci=si;} + d=MIN((si-ti), (sj-tj)); + if (d<=0); + else if (best_d==-1 || best_d>d){best_d=d; best_s=b;} + } + if (best_d==-1)continue; + + si=ll[best_s][0]; + sj=ll[best_s][1]; + + for (i=ti, j=tj; (i<=si && j<=sj); i++, j++)//extend the top diagonal + { + addE(i,j,(al1-i+j),cap, list,n); + } + + for (i=si, j=sj; (i>=ti && j>=tj); i--, j--)//extend the bottom diagonal + { + addE(i,j,(al1-i+j),cap, list,n); + } + } + + for (a=0; aS || !CL->residue_index) return 0; + + + if ( get_nproc()==1)return nfork_cl2pair_list_ecl_pc(A,ns,ls,CL,list_in,n_in); + else if (strstr ( CL->multi_thread, "pairwise"))return fork_cl2pair_list_ecl_pc(A,ns,ls,CL,list_in,n_in); + else return nfork_cl2pair_list_ecl_pc(A,ns,ls,CL,list_in,n_in); +} + + +int fork_cl2pair_list_ecl_pc ( Alignment *A, int *ns, int **ls, Constraint_list *CL, int ***list_in, int *n_in) +{ + int p1, p2,diag, si, s, r, t_s, t_r,t_w, t_s2, t_r2, t_w2; + int a, b, l1, l2; + int **pos; + + int nused; + int *used_list; + int *sl2,*sl1, **inv_pos; + + + + float nscore, score, tot, filter, avg=0, new=0; + float **used; + float *norm; + + //variables for fork + FILE *fp; + char **pid_tmpfile; + int sjobs, njobs,j; + int **sl; + + + if ( !A) return 0; + + + + pos=aln2pos_simple ( A,-1, ns, ls); + inv_pos=vcalloc ((CL->S)->nseq, sizeof (int*)); + for (a=0; aseq_al[ls[1][a]]); + + l1=strlen (A->seq_al[ls[0][0]]); + l2=strlen (A->seq_al[ls[1][0]]); + sl1=vcalloc ((CL->S)->nseq, sizeof (int)); + sl2=vcalloc ((CL->S)->nseq, sizeof (int)); + + for (a=0;a0 && si0 && aresidue_index[s][r][0];a+=ICHUNK) + { + t_s=CL->residue_index[s][r][a+SEQ2]; + t_r=CL->residue_index[s][r][a+R2]; + t_w=CL->residue_index[s][r][a+WE]; + if (sl1[t_s])continue;//do not extend within a profile + + norm[p1]++; + for (b=0; bresidue_index[t_s][t_r][0];) + { + if (b==0){t_s2=t_s;t_r2=t_r;t_w2=t_w;b++;} + else + { + t_s2=CL->residue_index[t_s][t_r][b+SEQ2]; + t_r2=CL->residue_index[t_s][t_r][b+R2]; + t_w2=CL->residue_index[t_s][t_r][b+WE]; + b+=ICHUNK; + } + if (sl2[t_s2]) + { + p2=inv_pos[t_s2][t_r2]; + score=MIN(((float)t_w/(float)NORM_F),((float)t_w2/(float)NORM_F)); + + if (!used[p2][1] && score>0) + { + used_list[nused++]=p2; + } + + tot+=score; + used[p2][0]+=score; + used[p2][1]++; + } + } + } + } + filter=0.01; + for (a=0; afilter && p1!=0 && p2!=0 && p1!=l1 && p2!=l2) + { + score=((norm[p1]>0)?score/norm[p1]:0)*NORM_F; + fprintf (fp, "%d %d %d %f ", p1, p2, ((l1-(p1))+(p2)), score); + } + } + } + vfclose (fp); + myexit (EXIT_SUCCESS); + } + else + { + sjobs++; + } + } + while (sjobs>=0){vwait(NULL); sjobs--;}//wait for all jobs to complete + for (j=0; jS)->nseq, sizeof (int*)); + for (a=0; aseq_al[ls[1][a]]); + + l1=strlen (A->seq_al[ls[0][0]]); + l2=strlen (A->seq_al[ls[1][0]]); + sl1=vcalloc ((CL->S)->nseq, sizeof (int)); + sl2=vcalloc ((CL->S)->nseq, sizeof (int)); + + norm=vcalloc ( l1+1, sizeof (float)); + + + for (a=0;a0 && si0 && aresidue_index[s][r][0];a+=ICHUNK) + { + t_s=CL->residue_index[s][r][a+SEQ2]; + t_r=CL->residue_index[s][r][a+R2]; + t_w=CL->residue_index[s][r][a+WE]; + if (sl1[t_s])continue;//do not extend within a profile + + norm[p1]++; + for (b=0; bresidue_index[t_s][t_r][0];) + { + if (b==0){t_s2=t_s;t_r2=t_r;t_w2=t_w;b++;} + else + { + t_s2=CL->residue_index[t_s][t_r][b+SEQ2]; + t_r2=CL->residue_index[t_s][t_r][b+R2]; + t_w2=CL->residue_index[t_s][t_r][b+WE]; + b+=ICHUNK; + } + + if (sl2[t_s2]) + { + p2=inv_pos[t_s2][t_r2]; + score=MIN(((float)t_w/(float)NORM_F),((float)t_w2/(float)NORM_F)); + + if (!used[p2][1] && score>0) + { + used_list[nused++]=p2; + } + + tot+=score; + used[p2][0]+=score; + used[p2][1]++; + } + } + } + } + //FILTER: Keep in the graph the edges where (p1->p2/(Sum (P1->x))>0.01 + filter=0.01; + + for (a=0; afilter && p1!=0 && p2!=0 && p1!=l1 && p2!=l2) + { + score=((norm[p1]>0)?score/norm[p1]:0)*NORM_F; + addE (p1,p2,((l1-(p1))+(p2)),score,list_in, n_in); + } + } + } + free_float (used, -1); + vfree (used_list); + free_int (inv_pos, -1); + free_int (pos, -1); + vfree (sl2);vfree (sl1); + vfree(norm); + return n_in[0]; +} + + + + +int list2linked_pair_wise ( Alignment *A, int *ns, int **l_s, Constraint_list *CL, int **list, int n, char ***al, int *len); +int linked_pair_wise ( Alignment *A, int *ns, int **ls, Constraint_list *CL) +{ + int n=0; + static int **list=NULL; + int score, a; + char **al; + int len=0; + int invert=0; + int tr0,tr1; + + if ( !A)free_int (list, -1); + if ( !CL->residue_index)return myers_miller_pair_wise (A, ns,ls,CL); + + + tr0=ns[0]*strlen (A->seq_al[ls[0][0]]); + tr1=ns[1]*strlen (A->seq_al[ls[1][0]]); + + if (tr0>tr1) + { + int *ins; + int **ils; + int a,b,c; + invert=1; + ins=vcalloc (2, sizeof(int)); + ils=declare_int (2, (CL->S)->nseq); + + for ( a=0; a<2; a++) + { + ins[a]=ns[a]; + for (b=0; bS)->nseq); + + for ( a=0; a<2; a++) + { + ins[a]=ns[a]; + for (b=0; bseq_al[l_s[0][0]]); + l2=strlen (A->seq_al[l_s[1][0]]); + al=declare_char (2,l1+l2+1); + tb[0]=al; + + + //Penalties: max score is NORM_F + //Penalties must be negative + igop=CL->gop; + gep=igep=CL->gep; + + if (n>max_size) + { + max_size=n; + + vfree (MI);vfree (MJ); vfree (MM); + free_int (slist, -1); + + slist=declare_int (n,3); + + MI=vcalloc (5*n, sizeof (long)); + MJ=vcalloc (5*n, sizeof (long)); + MM=vcalloc (5*n, sizeof (long)); + + } + else + { + for (a=0; a=(LIN(MM,pi,0)+gop))?'i':'m'; + + + LIN(MJ,a,0)=MAX(LIN(MJ,pj,0),(LIN(MM,pj,0)+gop))+delta_j*gep; + LIN(MJ,a,1)=pj; + LIN(MJ,a,2)=0; + LIN(MJ,a,3)=delta_j; + + LIN(MJ,a,4)=(LIN(MJ,pj,0)>=LIN(MM,pj,0)+gop)?'j':'m'; + + + + if (a>1 && (ls=list[a][0]-list[ij][0])==(list[a][1]-list[ij][1])) + { + LIN(MM,a,0)=MAX3(LIN(MM,ij,0),LIN(MI,ij,0),LIN(MJ,ij,0))+list[a][2]-(ls*CL->nomatch); + + LIN(MM,a,1)=ij; + LIN(MM,a,2)=ls; + LIN(MM,a,3)=ls; + if ( LIN(MM,ij,0)>=LIN(MI,ij,0) && LIN(MM,ij,0)>=LIN(MJ,ij,0))LIN(MM,a,4)='m'; + else if ( LIN(MI,ij,0) >= LIN(MJ,ij,0))LIN(MM,a,4)='i'; + else LIN(MM,a,4)='j'; + + } + else + { + LIN(MM,a,0)=UNDEFINED; + LIN(MM,a,1)=-1; + } + } + + a=start_trace; + if (LIN(MM,a,0)>=LIN(MI,a,0) && LIN(MM,a,0) >=LIN(MJ,a,0))MT2=MM; + else if ( LIN(MI,a,0)>=LIN(MJ,a,0))MT2=MI; + else MT2=MJ; + + score=MAX3(LIN(MM,a,0), LIN(MI,a,0), LIN(MJ,a,0)); + + i=l1; + j=l2; + + + while (!(i==0 &&j==0)) + { + int next_a; + l=MAX(LIN(MT2,a,2),LIN(MT2,a,3)); + // HERE ("%c from %c %d %d SCORE=%d [%d %d] [%2d %2d]", T2[a][5],T2[a][4], T2[a][2], T2[a][3], T2[a][0], gop, gep, i, j); + if (i==0) + { + while ( j>0) + { + al[0][LEN]=0; + al[1][LEN]=1; + j--; LEN++; + } + } + else if (j==0) + { + while ( i>0) + { + al[0][LEN]=1; + al[1][LEN]=0; + i--; LEN++; + } + } + + else if (l==0) {HERE ("L=0 i=%d j=%d",l, i, j);exit (0);} + else + { + for (b=0; bdeclared_len<=LEN)A=realloc_aln ( A,2*LEN+1); + aln=A->seq_al; + char_buf= vcalloc (LEN+1, sizeof (char)); + + for ( c=0; c< 2; c++) + { + for ( a=0; a< ns[c]; a++) + { + int ch=0; + for ( b=0; b< LEN; b++) + { + if (al[c][b]==1) + char_buf[b]=aln[l_s[c][a]][ch++]; + else + char_buf[b]='-'; + } + char_buf[b]='\0'; + sprintf (aln[l_s[c][a]],"%s", char_buf); + } + } + + A->len_aln=LEN; + A->nseq=ns[0]+ns[1]; + + vfree (char_buf); + len[0]=LEN; + return score; +} + + + + +//linked_pair_wise_collapse +//Collapses the CL as it proceeds during the progressive alignment +//Cannot be parralelized + + +void display_ns (Alignment *A,Constraint_list *CL, int *ns, int **ls, char *txt); +int cl2pair_list_collapse ( Alignment *A, int *ns, int **ls, Constraint_list *CL, int ***list_in, int *n_in); +Constraint_list* collapse_list (Alignment *A,int *ns, int **ls, char**al, int len, Constraint_list *CL); +int ns2s (int *ns, int **ls, int *is1, int *is2, int *is); +int linked_pair_wise_collapse ( Alignment *A, int *ns, int **ls, Constraint_list *CL) +{ + int n=0; + static int **list=NULL; + int score, a; + char **al; + int len=0; + + + if ( !A)free_int (list, -1); + if ( !CL->residue_index)return myers_miller_pair_wise (A, ns,ls,CL); + + /*Prepare the list*/ + + + cl2pair_list_collapse (A, ns, ls, CL, &list, &n); + + cl2diag_cap (A, ns, ls, CL, &list, &n); + cl2list_borders (A, ns, ls, CL, &list, &n); + list2nodup_list (A, ns, ls, CL, &list, &n); + + /*Do the DP*/ + score=list2linked_pair_wise (A, ns, ls, CL, list, n, &al,&len); + CL=collapse_list (A,ns, ls, al, len, CL); + free_char (al, -1); + /*Free the list*/ + return score; +} + + +Constraint_list* collapse_list (Alignment *A,int *ns, int **ls, char **al, int len, Constraint_list *CL) +{ + int s1, s2,s, cs1, cs2, cr1, cr2,l,ll; + int **lu; + int a,b,c,d; + static char *add; + static int *p; + FILE *fp; + + if (!add) + { + add=vtmpnam (NULL); + p=vcalloc ( 100, sizeof (int)); + } + + lu=declare_int (2, len+1); + for (a=0; a<2; a++) + for (c=0,b=0; bname[s1], (CL->S)->name, (CL->S)->nseq, 100); + s2=name_is_in_list (A->name[s2], (CL->S)->name, (CL->S)->nseq, 100); + s =name_is_in_list (A->name[s ], (CL->S)->name, (CL->S)->nseq, 100); + + + CL->residue_index[s]=vrealloc (CL->residue_index[s], (len+2)*sizeof (int*)); + for (a=0; a<=len; a++) + { + if (!CL->residue_index[s][a]) + { + CL->residue_index[s][a]=vcalloc (1, sizeof (int)); + CL->residue_index[s][a][0]=1; + } + } + + fp=vfopen (add, "w"); + CL->ne=0; + for (cs1=0; cs1<(CL->S)->nseq; cs1++) + { + cr1=1; + while (CL->residue_index[cs1][cr1]) + { + for (ll=l=1; lresidue_index[cs1][cr1][0]; l+=ICHUNK) + { + cs2=CL->residue_index[cs1][cr1][l+SEQ2]; + + if (cs1==s1 || cs1==s2 || cs2==s1 || cs2==s2) + { + p[SEQ1]=cs1; + p[SEQ2]=CL->residue_index[cs1][cr1][l+SEQ2]; + p[R1] =cr1; + p[R2] =CL->residue_index[cs1][cr1][l+R2]; + p[CONS]=CL->residue_index[cs1][cr1][l+CONS]; + p[MISC]=CL->residue_index[cs1][cr1][l+MISC]; + p[WE]=CL->residue_index[cs1][cr1][l+WE]; + if (cs1==s1) + { + p[SEQ1]=s; + p[R1]=lu[0][p[R1]]; + } + else if (cs1==s2) + { + p[SEQ1]=s; + p[R1]=lu[1][p[R1]]; + } + + if (cs2==s1) + { + p[SEQ2]=s; + p[R2]=lu[0][p[R2]]; + } + else if (cs2==s2) + { + + p[SEQ2]=s; + p[R2]=lu[1][p[R2]]; + } + + if (p[SEQ1]==p[SEQ2]); + else for (d=0; dentry_len; d++)fprintf (fp, "%d ", p[d]); + } + else + { + for (d=0; dresidue_index[cs1][cr1][ll++]=CL->residue_index[cs1][cr1][d+l]; + CL->ne++; + } + } + CL->residue_index[cs1][cr1][0]=ll; + cr1++; + } + } + vfclose (fp); + CL=undump_constraint_list (CL,add); + return CL; +} + + + + +int cl2pair_list_collapse ( Alignment *A, int *ns, int **ls, Constraint_list *CL, int ***list_in, int *n_in) +{ + int si, r1,r2,t_s, t_r,t_w, t_s2, t_r2, t_w2, s1, s2; + int a, b, l1, l2; + + int nused; + int *used_list; + + float nscore, score, tot, filter, avg=0, new=0; + float **used; + int *norm; + + + + if ( !A) return 0; + + ns2s (ns, ls, &s1, &s2,NULL); + + l1=strlen (A->seq_al[s1]); + l2=strlen (A->seq_al[s2]); + used=declare_float (l2+1,2); used_list=vcalloc (l2+1, sizeof (int)); + nused=0; + norm=vcalloc (l1+2, sizeof(int)); + + s1=name_is_in_list (A->name[s1], (CL->S)->name, (CL->S)->nseq, 100); + s2=name_is_in_list (A->name[s2], (CL->S)->name, (CL->S)->nseq, 100); + + for (r1=1; r1<=l1; r1++) + { + tot=0; nused=0; + for (a=1; r1>0 && aresidue_index[s1][r1][0];a+=ICHUNK) + { + t_s=CL->residue_index[s1][r1][a+SEQ2]; + t_r=CL->residue_index[s1][r1][a+R2]; + t_w=CL->residue_index[s1][r1][a+WE]; + norm[r1]++; + for (b=0; bresidue_index[t_s][t_r][0];) + { + if (b==0){t_s2=t_s;t_r2=t_r;t_w2=t_w;b++;} + else + { + t_s2=CL->residue_index[t_s][t_r][b+SEQ2]; + t_r2=CL->residue_index[t_s][t_r][b+R2]; + t_w2=CL->residue_index[t_s][t_r][b+WE]; + b+=ICHUNK; + } + + if (t_s2==s2) + { + score=MIN(((float)t_w/(float)NORM_F),((float)t_w2/(float)NORM_F)); + + if (!used[t_r2][1] && score>0) + { + used_list[nused++]=t_r2; + } + + tot+=score; + used[t_r2][0]+=score; + used[t_r2][1]++; + } + } + } + + //FILTER: Keep in the graph the edges where (p1->p2/(Sum (P1->x))>0.01 + filter=0.01; + + for (a=0; afilter && r1!=0 && r2!=0 && r1!=l1 && r2!=l2) + { + score=((norm[r1]>0)?score/norm[r1]:0)*NORM_F; + addE (r1,r2,((l1-(r1))+(r2)),score,list_in, n_in); + } + } + } + + free_float (used, -1); + vfree (used_list); + vfree (norm); + return n_in[0]; +} +int ns2s (int *ns, int **ls, int *is1, int *is2, int *is) +{ + int a, b; + int s1, s2, s; + + s1=s2=s=-1; + + for (a=0; a< 2; a++) + for (b=0; b +#include +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" + +#include "dp_lib_header.h" + +int gotoh_pair_wise_lalign ( Alignment *A, int*ns, int **l_s,Constraint_list *CL) + { + Alignment *BUF=NULL; + Alignment *EA=NULL; + + int a; + BUF=copy_aln (A, BUF); + + + for ( a=0; alalign_n_top; a++) + { + free_aln (A); + + A=copy_aln (BUF, A); + + A->score_aln=gotoh_pair_wise_sw (A, ns, l_s, CL); + EA=fast_coffee_evaluate_output (A, CL); + + output_format_aln (CL->out_aln_format[0],A,EA,"stdout"); + CL=undefine_sw_aln ( A, CL); + } + exit (1); + return 0; + } +Constraint_list * undefine_sw_aln ( Alignment *A, Constraint_list *CL) + { + int a, b, l; + int **pos; + int r1, rs1; + int r2, rs2; + + + + pos=aln2pos_simple ( A,A->nseq); + + for ( l=0; l< A->len_aln; l++) + for ( a=0; a< A->nseq-1; a++) + { + rs1=A->order[a][0]; + r1 =pos[a][l]; + + if ( r1<=0)continue; + for ( b=a+1; b< A->nseq;b++) + { + rs2=A->order[b][0]; + r2 =pos[b][l]; + if ( r2<=0)continue; + + CL=undefine_sw_pair ( CL, rs1, r1, rs2, r2); + } + } + free_int (pos, -1); + return CL; + } +Constraint_list * undefine_sw_pair ( Constraint_list *CL, int s1, int r1, int s2, int r2) + { + int a, b; + + if ( !CL->forbiden_pair_list) + { + + CL->forbiden_pair_list=vcalloc ( (CL->S)->nseq, sizeof (int ***)); + for ( a=0; a< ((CL->S)->nseq); a++) + { + CL->forbiden_pair_list[a]=vcalloc ( (CL->S)->nseq, sizeof (int **)); + for ( b=0; b< ((CL->S)->nseq); b++) + CL->forbiden_pair_list[a][b]=vcalloc ( (CL->S)->len[a]+1, sizeof (int *)); + + } + } + if ( CL->forbiden_pair_list[s1][s2][r1]==NULL)CL->forbiden_pair_list[s1][s2][r1]=vcalloc ( (CL->S)->len[s2]+1, sizeof (int)); + CL->forbiden_pair_list[s1][s2][r1][r2]=1; + + if ( CL->forbiden_pair_list[s2][s1][r2]==NULL)CL->forbiden_pair_list[s2][s1][r2]=vcalloc ( (CL->S)->len[s1]+1, sizeof (int)); + CL->forbiden_pair_list[s2][s1][r2][r1]=1; + + return CL; + } + +int sw_pair_is_defined ( Constraint_list *CL, int s1, int r1, int s2, int r2) + { + int d; + + d=(r1-r2); + d=(d<0)?-d:d; + + + if ( s1==s2 && d<(CL->sw_min_dist)) return UNDEFINED; + else if ( ! CL->forbiden_pair_list) return 1; + else if ( CL->forbiden_pair_list[s1][s2][r1]==NULL)return 1; + else if ( CL->forbiden_pair_list[s1][s2][r1][r2]==1)return UNDEFINED; + else if ( CL->forbiden_pair_list[s1][s2][r1][r2]==0)return 1; + + else + { + crash ("ERROR in function: sw_pair_is_defined\n"); + return UNDEFINED; + } + + } + + +int gotoh_pair_wise_sw (Alignment *A, int*ns, int **l_s,Constraint_list *CL) + { +/*******************************************************************************/ +/* SMITH AND WATERMAN */ +/* */ +/* makes DP between the the ns[0] sequences and the ns[1] */ +/* */ +/* for MODE, see the function get_dp_cost */ +/*******************************************************************************/ + int a, b, d, i, j; + int last_i, last_j; + int t; + int *cc; + int *dd, *ddg; + int lenal[2], len; + + int c,s, e,eg, ch,g,h, maximise; + int sub; + + int fop; + static int **pos0; + + char **al=NULL; + char **aln=NULL; + + + int ala, alb,LEN; + char *buffer; + char *char_buf; + +/*trace back variables */ + int best_i; + int best_j; + int best_score; + + + FILE *long_trace=NULL; + TRACE_TYPE *buf_trace=NULL; + static TRACE_TYPE **trace; + TRACE_TYPE k; + TRACE_TYPE *tr; + int long_trace_flag=0; + int dim; +/********Prepare penalties*******/ + if (CL->moca) + { + g=(CL->gop+(CL->moca)->moca_scale)*SCORE_K; + h=(CL->gep+(CL->moca)->moca_scale)*SCORE_K; + } + else + { + g=(CL->gop-CL->nomatch)*SCORE_K; + h=(CL->gep-CL->nomatch)*SCORE_K; + } + fprintf ( stderr, "\n%d %d", g, h); + maximise=CL->maximise; +/********************************/ +/*CLEAN UP AFTER USE*/ + if ( A==NULL) + { + free_int (trace,-1); + trace=NULL; + if ( al)free_char (al,-1); + al=NULL; + return 0; + } +/*DO MEMORY ALLOCATION FOR SW DP*/ + + lenal[0]=strlen (A->seq_al[l_s[0][0]]); + lenal[1]=strlen (A->seq_al[l_s[1][0]]); + len= (( lenal[0]>lenal[1])?lenal[0]:lenal[1])+1; + buf_trace=vcalloc ( len, sizeof (TRACE_TYPE)); + buffer=vcalloc ( 2*len, sizeof (char)); + al=declare_char (2, 2*len); + + char_buf= vcalloc (2*len, sizeof (char)); + dd= vcalloc (len, sizeof (int)); + cc= vcalloc (len, sizeof (int)); + ddg=vcalloc (len, sizeof (int)); + + + if ( len>=MAX_LEN_FOR_DP) + { + long_trace_flag=1; + long_trace=vtmpfile(); + } + else + { + dim=(trace==NULL)?0:read_size_int ( trace,sizeof (int*)); + trace =realloc_int ( trace,dim,dim,len-dim, len-dim); + } + +/*END OF MEMORY ALLOCATION*/ + + + /* + 0(s) +(dd) + \ | + \ | + \ | + \ | + \ | + \ | + \| + -(e)----O + */ + + + pos0=aln2pos_simple ( A,-1, ns, l_s); + + + + cc[0]=0; + + best_score=0; + best_i=0; + best_j=0; + + tr=(long_trace_flag)?buf_trace:trace[0]; + tr[0]=(TRACE_TYPE)UNDEFINED; + + t=g; + for ( j=1; j<=lenal[1]; j++) + { + cc[j]=t=t+h; + dd[j]=t+g; + tr[j]=(TRACE_TYPE)UNDEFINED; + } + if (long_trace_flag)fwrite (buf_trace, sizeof ( TRACE_TYPE),lenal[1]+1, long_trace); + + + t=g; + for (i=1; i<=lenal[0];i++) + { + tr=(long_trace_flag)?buf_trace:trace[i]; + s=cc[0]; + cc[0]=c=t=t+h; + e=t+g; + tr[0]=(TRACE_TYPE)UNDEFINED; + + for (eg=0,j=1; j<=lenal[1];j++) + { + + sub=(CL->get_dp_cost) (A, pos0, ns[0], l_s[0], i-1, pos0, ns[1], l_s[1],j-1,CL); + + /*get the best Insertion*/ + if ( a_better_than_b ( e, c+g, maximise)) + eg++; + else + eg=1; + e=best_of_a_b (e, c+g, maximise)+h; + + /*Get the best deletion*/ + if ( a_better_than_b ( dd[j], cc[j]+g, maximise)) + ddg[j]++; + else + ddg[j]=1; + dd[j]=best_of_a_b( dd[j], cc[j]+g, maximise)+h; + + /*Chose Substitution for tie breaking*/ + if ( sub!=UNDEFINED)c=best_int(4,maximise,&fop, e, (s+sub), dd[j],0); + else + { + c=0; + fop=3; + dd[j]=e=0; + eg=ddg[j]=0; + } + + if ( c>best_score) + { + best_i=i; + best_j=j; + best_score=c; + } + fop-=1; + s=cc[j]; + cc[j]=c; + + + if ( fop==-1) + {tr[j]=(TRACE_TYPE)fop*eg; + } + else if ( fop==1) + {tr[j]=(TRACE_TYPE)fop*ddg[j]; + } + else if (fop==0) + {tr[j]=(TRACE_TYPE)0; + } + else if ( fop==2) + { + tr[j]=(TRACE_TYPE)UNDEFINED; + } + + fop= -2; + } + if (long_trace_flag) + { + fwrite ( buf_trace, sizeof (TRACE_TYPE), lenal[1]+1, long_trace); + } + } + + + + + if (best_i==0 ||best_j==0 ) + { + vfree (buf_trace); + vfree (buffer); + free_char ( al,-1); + vfree ( char_buf); + vfree ( dd); + vfree ( cc); + vfree ( ddg); + free_int (pos0, -1); + A->len_aln=0; + aln=A->seq_al; + + for ( c=0; c< 2; c++) + { + for ( a=0; a< ns[c]; a++) + { + aln[l_s[c][a]][0]='\0'; + } + } + if ( long_trace_flag)fclose ( long_trace); + + return UNDEFINED; + } + else + { + i=last_i=best_i; + j=last_j=best_j; + } + ala=alb=0; + + + while (i>0 && j>0) + { + if ( i==0 || j==0)k=UNDEFINED; + /* k=-1; + else if ( j==0) + k=1; + else if ( j==0 && i==0) + k=1;*/ + else + { + if (long_trace_flag) + { + fseek ( long_trace, sizeof (TRACE_TYPE)*((lenal[1]+1)*(i)+j),SEEK_SET); + fread ( &k, sizeof (TRACE_TYPE), 1, long_trace); + } + else + { + + k=trace[i][j]; + } + } + + if ( k==UNDEFINED){i=j=0;} + if (k==0) + { + + al[0][ala++]=1; + al[1][alb++]=1; + + + + i--; + j--; + last_i=i; + last_j=j; + + } + else if (k==(TRACE_TYPE)UNDEFINED) + { + i=0; + j=0; + + } + else if (k>0) + { + + for ( a=0; a< k; a++) + { + al[0][ala++]=1; + al[1][alb++]=0; + i--; + } + last_i=i; + last_j=j; + } + else if (k<0) + { + + for ( a=0; a>k; a--) + { + al[0][ala++]=0; + al[1][alb++]=1; + j--; + } + last_i=i; + last_j=j; + } + } + + LEN=ala; + c=LEN-1; + + + + invert_list_char ( al[0], LEN); + invert_list_char ( al[1], LEN); + + if ( A->declared_len<=LEN)realloc_alignment ( A, 2*LEN); + + + aln=A->seq_al; + + for ( c=0; c<2; c++) + for ( a=0; aorder[l_s[c][a]][2]=(c==0)?last_i:last_j; + A->order[l_s[c][a]][3]=(c==1)?best_i:best_j; + + e=(c==0)?last_i:last_j; + for ( d=0; dorder[l_s[c][a]][1]+=1-is_gap(aln[l_s[c][a]][d]); + } + } + + + for ( c=0; c< 2; c++) + { + for ( a=0; a< ns[c]; a++) + { + aln[l_s[c][a]]+=(c==0)?last_i:last_j; + ch=0; + for ( b=0; b< LEN; b++) + { + + if (al[c][b]==1) + char_buf[b]=aln[l_s[c][a]][ch++]; + else + char_buf[b]='-'; + } + char_buf[b]='\0'; + aln[l_s[c][a]]-=(c==0)?last_i:last_j; + sprintf (aln[l_s[c][a]],"%s", char_buf); + } + } + + + A->len_aln=LEN; + + free_int (pos0, -1); + vfree ( cc); + vfree (dd); + vfree (ddg); + vfree (buffer); + vfree (char_buf); + vfree (buf_trace); + if ( long_trace_flag)fclose (long_trace); + + + return best_score; + } + + +/*******************************************************************************/ +/* AUTOMATIC GEP+SCALE PENALTY FOR SW */ +/* */ +/* */ +/* */ +/* */ +/*******************************************************************************/ + +Alignment * add_seq2aln (Constraint_list *CL, Alignment *IN,Sequence *S) + { + int *n_groups; + int **group_list; + int a; + static int series=0; + + + + + int ste; /*sequence to extract, last one if they are packed*/ + + + + + + if (CL->packed_seq_lu){ste=S->nseq-1;} + else{ste=0;} + + if ( IN==NULL) + { + IN=realloc_aln2(IN, 1, strlen (S->seq[ste])+1); + IN->S=S; + IN->nseq=1; + + + + sprintf ( IN->seq_al[0], "%s", S->seq[ste]); + sprintf (IN->name[0], "%s_%d_1", S->name[ste],series); + IN->order[0][0]=ste; + IN->order[0][1]=0; + + IN->len_aln=strlen ( IN->seq_al[0]); + series++; + + } + else + { + + IN=realloc_aln2 ( IN, IN->nseq+1,MAX(strlen ( S->seq[ste])+1, IN->len_aln+1)); + n_groups=vcalloc ( 2, sizeof (int)); + group_list=declare_int (2,IN->nseq+1); + + n_groups[0]=IN->nseq; + for ( a=0; anseq; a++)group_list[0][a]=a; + + n_groups[1]=1; + group_list[1][0]=IN->nseq; + sprintf (IN->name[IN->nseq], "%s_%d_%d",S->name[ste],series,IN->nseq+1); + sprintf (IN->seq_al[IN->nseq], "%s",S->seq[ste]); + IN->order[IN->nseq][0]=ste; + IN->order[IN->nseq][1]=0; + IN->nseq++; + + + pair_wise ( IN, n_groups, group_list,CL); + + } + + return IN; + + } + + +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/util_dp_mm_nw.c b/binaries/src/tcoffee/t_coffee_source/util_dp_mm_nw.c new file mode 100644 index 0000000..32a6459 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/util_dp_mm_nw.c @@ -0,0 +1,371 @@ +#include +#include +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" +#include "dp_lib_header.h" + + +/*******************************************************************************/ +/* myers and Miller */ +/* */ +/* makes DP between the the ns[0] sequences and the ns[1] */ +/* */ +/* for MODE, see the function get_dp_cost */ +/*******************************************************************************/ + +#define gap(k) ((k) <= 0 ? 0 : g+h*(k)) /* k-symbol indel cost */ +static int *sapp; /* Current script append ptr */ +static int last; /* Last script op appended */ + /* Append "Delete k" op */ +#define DEL(k) \ +{ if (last < 0) \ + last = sapp[-1] -= (k); \ + else \ + last = *sapp++ = -(k); \ +} + /* Append "Insert k" op */ +#define INS(k) \ +{ if (last < 0) \ + { sapp[-1] = (k); *sapp++ = last; } \ + else \ + last = *sapp++ = (k); \ +} + +#define REP { last = *sapp++ = 0; } /* Append "Replace" op */ +int myers_miller_pair_wise (Alignment *A,int *ns, int **l_s,Constraint_list *CL ) + { + int **pos; + int a,b, i, j, l,l1, l2, len; + int *S; + char ** char_buf; + int score; + + + /********Prepare Penalties******/ + + /********************************/ + + + pos=aln2pos_simple ( A,-1, ns, l_s); + + + l1=strlen (A->seq_al[l_s[0][0]]); + l2=strlen (A->seq_al[l_s[1][0]]); + S=vcalloc (l1+l2+1, sizeof (int)); + last=0; + sapp=S; + + score=diff (A,ns, l_s, 0, l1, 0, l2, 0, 0, CL, pos); + diff (NULL,ns, l_s, 0, l1, 0, l2, 0, 0, CL, pos); + + + + i=0;j=0;sapp=S; len=0; + while (!(i==l1 && j==l2)) + { + if (*sapp==0){i++; j++;len++;} + else if ( *sapp<0){i-=*sapp;len-=*sapp;} + else if ( *sapp>0){j+=*sapp;len+=*sapp;} + sapp++; + } + + + + A=realloc_aln2 ( A,A->max_n_seq,len+1); + char_buf=declare_char (A->max_n_seq,len+1); + + i=0;j=0;sapp=S; len=0; + while (!(i==l1 && j==l2)) + { + + if (*sapp==0) + { + for (b=0; b< ns[0]; b++) + char_buf[l_s[0][b]][len]=A->seq_al[l_s[0][b]][i]; + for (b=0; b< ns[1]; b++) + char_buf[l_s[1][b]][len]=A->seq_al[l_s[1][b]][j]; + i++; j++;len++; + } + else if ( *sapp>0) + { + l=*sapp; + for ( a=0; aseq_al[l_s[1][b]][j]; + } + } + else if ( *sapp<0) + { + l=-*sapp; + for ( a=0; aseq_al[l_s[0][b]][i];; + for (b=0; b< ns[1]; b++) + char_buf[l_s[1][b]][len]='-'; + } + } + + sapp++; + } + + + A->len_aln=len; + A->nseq=ns[0]+ns[1]; + + for ( a=0; a< ns[0]; a++){char_buf[l_s[0][a]][len]='\0'; sprintf ( A->seq_al[l_s[0][a]], "%s", char_buf[l_s[0][a]]);} + for ( a=0; a< ns[1]; a++){char_buf[l_s[1][a]][len]='\0'; sprintf ( A->seq_al[l_s[1][a]], "%s", char_buf[l_s[1][a]]);} + + + vfree (S); + free_char ( char_buf, -1); + l1=strlen (A->seq_al[l_s[0][0]]); + l2=strlen (A->seq_al[l_s[1][0]]); + if ( l1!=l2) exit(1); + + free_int (pos, -1); + return score; + } + + +int diff (Alignment *A, int *ns, int **l_s, int s1, int M,int s2, int N , int tb, int te, Constraint_list *CL, int **pos) + { + static int *CC; + static int *DD; + /* Forward cost-only vectors */ + static int *RR; + static int *SS; + /* Reverse cost-only vectors */ + int midi, midj, type; /* Midpoint, type, and cost */ + int midc; + +/*TREATMENT OF THE TERMINAL GAP PENALTIES*/ +/*TG_MODE=0---> gop and gep*/ +/*TG_MODE=1---> --- gep*/ +/*TG_MODE=2---> --- ---*/ + + + + + + + + if ( !CC) + { + int L; + L=M+N+1; + + CC=vcalloc (L, sizeof (int)); + DD=vcalloc (L, sizeof (int)); + RR=vcalloc (L, sizeof (int)); + SS=vcalloc (L, sizeof (int)); + } + + if ( A==NULL) + { + vfree(CC); + vfree(DD); + vfree(RR); + vfree(SS); + CC=DD=RR=SS=NULL; + return 0; + } + + { + int i, j; + int c, e, d, s,ma; + int t, g,h,m; + + + + g=CL->gop*SCORE_K; + h=CL->gep*SCORE_K; + m=g+h; + + if (N <= 0){if (M > 0) DEL(M);return gap(M);} + if (M <= 1) + { + + if (M <= 0) + {INS(N); + return gap(N); + } + + + if (tb > te) tb = te; + midc = (tb+h) + gap(N); + midj = 0; + + for (j = 1; j <= N; j++) + { + + c = gap(j-1) +(CL->get_dp_cost) (A, pos, ns[0], l_s[0],s1, pos, ns[1], l_s[1],j-1+s2,CL)+ gap(N-j); + + if (c > midc) + { midc = c; + midj = j; + } + } + if (midj == 0) + {DEL(1) INS(N)} + else + {if (midj > 1) INS(midj-1); + REP; + if (midj < N) INS(N-midj); + } + + return midc; + } +/* Divide: Find optimum midpoint (midi,midj) of cost midc */ + + + midi = M/2; /* Forward phase: */ + CC[0] = 0; /* Compute C(M/2,k) & D(M/2,k) for all k */ + t = tb; + for (j = 1; j <= N; j++) + { CC[j] = t = t+h; + DD[j] = t+g; + } + t = tb; + for (i = 1; i <= midi; i++) + { + s = CC[0]; + CC[0] = c = t = t+h; + e = t+g; + + for (j = 1; j <= N; j++) + { + + + if ((c = c + m) > (e = e + h)) e = c; + if ((c = CC[j] + m) > (d = DD[j] + h)) d = c; + + ma=c = s + (CL->get_dp_cost) (A, pos, ns[0], l_s[0],i-1+s1, pos, ns[1], l_s[1],j-1+s2,CL); + + if (e > c) c = e; + if (d > c) c = d; + + + s = CC[j]; + CC[j] = c; + DD[j] = d; + } + } + DD[0] = CC[0]; + + RR[N] = 0; /* Reverse phase: */ + t = te; + + + for (j = N-1; j >= 0; j--) + { RR[j] = t = t+h; + SS[j] = t+g; + } + t = te; + for (i = M-1; i >= midi; i--) + { s = RR[N]; + RR[N] = c = t = t+h; + e = t+g; + for (j = N-1; j >= 0; j--) + { + if ((c = c + m) > (e = e + h)) e = c; + if ((c = RR[j] + m) > (d = SS[j] + h)) d = c; + + ma=c = s + (CL->get_dp_cost) (A, pos, ns[0], l_s[0],i+s1, pos, ns[1], l_s[1],j+s2,CL); + + if (e > c) c = e; + if (d > c) c = d; + + + s = RR[j]; + RR[j] = c; + SS[j] = d; + + } + } + SS[N] = RR[N]; + midc = CC[0]+RR[0]; /* Find optimal midpoint */ + midj = 0; + type = 1; + for (j = 0; j <= N; j++) + if ((c = CC[j] + RR[j]) >= midc) + if (c > midc || (CC[j] != DD[j] && RR[j] == SS[j])) + { + midc = c; + midj = j; + } + for (j = N; j >= 0; j--) + if ((c = DD[j] + SS[j] - g) > midc) + {midc = c; + midj = j; + type = 2; + } + } +/* Conquer: recursively around midpoint */ + + if (type == 1) + { + + diff (A,ns, l_s, s1,midi, s2, midj, tb, CL->gop*SCORE_K, CL, pos); + diff (A,ns, l_s, s1+midi,M-midi, s2+midj, N-midj, CL->gop*SCORE_K,te, CL, pos); + } + else + { + diff (A,ns, l_s, s1,midi-1, s2, midj, tb,0, CL, pos); + DEL(2); + diff (A,ns, l_s, s1+midi+1, M-midi-1,s2+midj, N-midj,0,te, CL, pos); + } + return midc; + } + + + + + + + + + + + + + + + +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/util_dp_sim.c b/binaries/src/tcoffee/t_coffee_source/util_dp_sim.c new file mode 100644 index 0000000..c02d6d9 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/util_dp_sim.c @@ -0,0 +1,1163 @@ +#include +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" +#include "dp_lib_header.h" +/* extern char name0[], name1[]; */ +/* extern int match, mismh; */ + + + +static Constraint_list *CL; +static int * ns; +static int **l_s; +static Alignment *Aln; +static int **pos; +static int *seqc0, *seqc1; +static int min0,min1,max0,max1,mins; + +static void* sim_vcalloc( size_t nobj, size_t size); +static void sim_free_all (); +static int sim_reset_static_variable (); +static int big_pass(int *A,int *B,int M,int N,int K, int nseq) ; +static int locate(int *A,int *B,int nseq); +static int small_pass(int *A,int *B,int count,int nseq); +static int no_cross (); +static int diff_sim( int *A,int *B,int M,int N,int tb,int te); +int calcons(int *aa0,int n0,int *aa1,int n1,int *res,int *nc,int *nident, Alignment *A, int *ns, int **l_s, Constraint_list *CL); + + + +#define SIM_GAP -1 +#define min(x,y) ((x)<=(y) ? (x) : (y)) +//#define TC_SCORE_SIM(x,y) TC_SCORE (x,y) + +static int q, r; /* gap penalties */ +static int qr; /* qr = q + r */ + + + +typedef struct ONE { int COL ; struct ONE *NEXT ;} pair, *pairptr; +pairptr *row, z, z1; /* for saving used aligned pairs */ + + +#define PAIRNULL (pairptr)NULL +static int tt; + +typedef struct SIM_NODE + { int SIM_SCORE; + int SIM_STARI; + int SIM_STARJ; + int SIM_ENDI; + int SIM_ENDJ; + int SIM_TOP; + int SIM_BOT; + int SIM_LEFT; + int SIM_RIGHT; } vertex, +#ifdef FAR_PTR + far *vertexptr; +#else + *vertexptr; +#endif + +vertexptr *LIST; /* an array for saving k best scores */ +vertexptr low = 0; /* lowest score node in LIST */ +vertexptr most = 0; /* latestly accessed node in LIST */ +static int numnode; /* the number of nodes in LIST */ + +static int *CC, *DD; /* saving matrix scores */ +static int *RR, *SS, *EE, *FF; /* saving start-points */ +static int *HH, *WW; /* saving matrix scores */ +static int *II, *JJ, *XX, *YY; /* saving start-points */ +static int m1, mm, n1, nn; /* boundaries of recomputed area */ +static int rl, cl; /* left and top boundaries */ +static int lmin; /* minimum score in LIST */ +static int flag; /* indicate if recomputation necessary*/ + +/* DIAG() assigns value to x if (ii,jj) is never used before */ +#define DIAG(ii, jj, x, value) \ +{ for ( tt = 1, z = row[(ii)]; z != PAIRNULL; z = z->NEXT ) \ + if ( z->COL == (jj) ) \ + { tt = 0; break; } \ + if ( tt ) \ + x = ( value ); \ +} + +/* replace (ss1, xx1, yy1) by (ss2, xx2, yy2) if the latter is large */ +#define ORDER(ss1, xx1, yy1, ss2, xx2, yy2) \ +{ if ( ss1 < ss2 ) \ + { ss1 = ss2; xx1 = xx2; yy1 = yy2; } \ + else \ + if ( ss1 == ss2 ) \ + { if ( xx1 < xx2 ) \ + { xx1 = xx2; yy1 = yy2; } \ + else \ + if ( xx1 == xx2 && yy1 < yy2 ) \ + yy1 = yy2; \ + } \ +} + +/* The following definitions are for function diff() */ + +static int zero = 0; /* int type zero */ +#define gap(k) ((k) <= 0 ? 0 : q+r*(k)) /* k-symbol indel score */ + +static int *sapp; /* Current script append ptr */ +static int last; /* Last script op appended */ + +static int I, J; /* current positions of A ,B */ +static int no_mat; /* number of matches */ +static int no_mis; /* number of mismatches */ +static int al_len; /* length of alignment */ + /* Append "Delete k" op */ +#define DEL(k) \ +{ I += k;\ + al_len += k;\ + if (last < 0)\ + last = sapp[-1] -= (k);\ + else\ + last = *sapp++ = -(k);\ +} + /* Append "Insert k" op */ +#define INS(k) \ +{ J += k;\ + al_len += k;\ + if (last < 0)\ + { sapp[-1] = (k); *sapp++ = last; } \ + else\ + last = *sapp++ = (k);\ +} + + /* Append "Replace" op */ +#define REP \ +{ last = *sapp++ = 0;\ + al_len += 1;\ +} + + +/* +int sim_pair_wise_lalign (Alignment *in_A, int *in_ns, int **in_l_s,Constraint_list *in_CL) +{ + if ( in_ns[0]==1 && in_ns[1]==1) + return sim_pair_wise_lalign (in_A, in_ns, in_l_s,in_CL); + else + */ + + + + + +int sim_pair_wise_lalign (Alignment *in_A, int *in_ns, int **in_l_s,Constraint_list *in_CL) +/* SIM(A,B,M,N,K,V,Q,R) reports K best non-intersecting alignments of + the segments of A and B in order of similarity scores, where + V[a][b] is the score of aligning a and b, and -(Q+R*i) is the score + of an i-symbol indel. +*/ +{ + int endi, endj, stari, starj; /* endpoint and startpoint */ + int score; /* the max score in LIST */ + int count; /* maximum size of list */ + int i; + int *S; /* saving operations for diff */ + int nc, nident; /* for display */ + vertexptr cur; /* temporary pointer */ + vertexptr findmax(); /* return the largest score node */ + double percent; + int t1, t2, g1, g2, r1, r2; + int a, b, c, d, e; +/*cedric was here 11/2/99*/ + int CEDRIC_MAX_N_ALN=999; + int CEDRIC_THRESHOLD=50; + int *A, *B; + int M, N, K, maxl; + int nseq; + int R, Q; + Alignment *DA; + + + DA=in_A; + + Aln=copy_aln (in_A, NULL); + + + + l_s=in_l_s; + ns=in_ns; + CL=in_CL; + K=CL->lalign_n_top; + + M=strlen (Aln->seq_al[l_s[0][0]]); + N=strlen (Aln->seq_al[l_s[1][0]]); + maxl=M+N+1; + + pos=aln2pos_simple (Aln,-1, ns, l_s); + + seqc0=(int*)sim_vcalloc (maxl+1,sizeof (int)); + A=(int*)sim_vcalloc (maxl+1,sizeof (int)); + for ( a=0; agop, -CL->gop)*SCORE_K; + R=MAX(CL->gep, -CL->gep)*SCORE_K; + + + + if ( K==CEDRIC_MAX_N_ALN)K--; + else if ( K<0) + { + + CEDRIC_THRESHOLD=-K; + K=CEDRIC_MAX_N_ALN; + } + + /* allocate space for all vectors */ + + CC = ( int * ) sim_vcalloc(N+1, sizeof(int)); + DD = ( int * ) sim_vcalloc(N+1, sizeof(int)); + RR = ( int * ) sim_vcalloc(N+1, sizeof(int)); + SS = ( int * ) sim_vcalloc(N+1, sizeof(int)); + EE = ( int * ) sim_vcalloc(N+1, sizeof(int)); + FF = ( int * ) sim_vcalloc(N+1, sizeof(int)); + + HH = ( int * ) sim_vcalloc(M + 1, sizeof(int)); + WW = ( int * ) sim_vcalloc(M + 1, sizeof(int)); + II = ( int * ) sim_vcalloc(M + 1, sizeof(int)); + JJ = ( int * ) sim_vcalloc(M + 1, sizeof(int)); + XX = ( int * ) sim_vcalloc(M + 1, sizeof(int)); + YY = ( int * ) sim_vcalloc(M + 1, sizeof(int)); + S = ( int * ) sim_vcalloc(min(M,N)*5/4+1, sizeof (int)); + row = ( pairptr * ) sim_vcalloc( (M + 1), sizeof(pairptr)); + + + /* set up list for each row */ + if (nseq == 2) for ( i = 1; i <= M; i++ ) row[i]= PAIRNULL; + else { + z = ( pairptr )sim_vcalloc (M,(int)sizeof(pair)); + for ( i = 1; i <= M; i++,z++) { + row[i] = z; + z->COL = i; + z->NEXT = PAIRNULL; + } + } + + + q = Q; + r = R; + qr = q + r; + + LIST = ( vertexptr * ) sim_vcalloc( K, sizeof(vertexptr)); + for ( i = 0; i < K ; i++ ) + LIST[i] = ( vertexptr )sim_vcalloc( 1, sizeof(vertex)); + + + numnode = lmin = 0; + big_pass(A,B,M,N,K,nseq); + + + + /* Report the K best alignments one by one. After each alignment is + output, recompute part of the matrix. First determine the size + of the area to be recomputed, then do the recomputation */ + + + for ( count = K - 1; count >= 0; count-- ) + { if ( numnode == 0 ) + { + + padd_aln (in_A); + /*fatal("The number of alignments computed is too large");*/ + sim_free_all(); + return 1; + } + + cur = findmax(); /* Return a pointer to a node with max score*/ + score = cur->SIM_SCORE; + if ( K==CEDRIC_MAX_N_ALN && scoreSIM_STARI; + starj = ++cur->SIM_STARJ; + endi = cur->SIM_ENDI; + endj = cur->SIM_ENDJ; + m1 = cur->SIM_TOP; + mm = cur->SIM_BOT; + n1 = cur->SIM_LEFT; + nn = cur->SIM_RIGHT; + rl = endi - stari + 1; + cl = endj - starj + 1; + I = stari - 1; + J = starj - 1; + sapp = S; + last = 0; + al_len = 0; + no_mat = 0; + no_mis = 0; + diff_sim(&A[stari]-1, &B[starj]-1,rl,cl,q,q); + + + min0 = stari; + min1 = starj; + max0 = stari+rl-1; + max1 = starj+cl-1; + calcons(A+1,M,B+1,N,S,&nc,&nident, Aln,ns, l_s, CL); + percent = (double)nident*100.0/(double)nc; + + + + /*Min0: index of the last residue before the first in a 1..N+1 numerotation*/ + + + + if (!DA->A)DA->A=copy_aln(Aln, DA->A); + DA->A=realloc_alignment (DA->A,nc+1); + + + DA=DA->A; + DA->A=NULL; + + for ( c=0; c< 2; c++) + { + for ( a=0; a< ns[c]; a++) + { + e=(c==0)?min0:min1; + for ( d=0; dorder[l_s[c][a]][1]+=1-is_gap(Aln->seq_al[l_s[c][a]][d]); + } + } + } + + + for ( t1=min0,t2=min1,a=0; aM)?0:1; + g2=(r2==SIM_GAP || r2>N)?0:1; + t1+=g1; + t2+=g2; + for (b=0; bseq_al[l_s[0][b]][a]=(g1)?Aln->seq_al[l_s[0][b]][A[t1-1]]:'-'; + for (b=0; bseq_al[l_s[1][b]][a]=(g2)?Aln->seq_al[l_s[1][b]][B[t2-1]]:'-'; + } + for (b=0; bseq_al[l_s[0][b]][a]='\0';} + for (b=0; bseq_al[l_s[1][b]][a]='\0';} + + DA->nseq=ns[0]+ns[1]; + DA->len_aln=nc; + DA->score=percent; + DA->score_aln=score; + fflush(stdout); + + + if ( count ) + { flag = 0; + locate(A,B,nseq); + if ( flag ) + small_pass(A,B,count,nseq); + } + } + padd_aln (in_A); + + sim_free_all(); + free_int (pos, -1); + free_aln (Aln); + + + + return 1; + +} +int sim_reset_static_variable () +{ + CC=DD=RR=SS=EE=FF=HH=WW=II=JJ=XX=YY=sapp=NULL; + min0=min1=max0=max1=mins=q=r=qr=tt=numnode=m1=n1=nn=rl=cl=lmin=flag=zero=last=I=J=no_mat=no_mis=al_len=0; + most=low=NULL;/*Very important: cause a bug if not reset*/ + LIST=NULL; /*Very important: cause a bug if not reset*/ + return 0; +} +/* A big pass to compute K best classes */ + + +int big_pass(int *A,int *B,int M,int N,int K, int nseq) +{ register int i, j; /* row and column indices */ + register int c; /* best score at current point */ + register int f; /* best score ending with insertion */ + register int d; /* best score ending with deletion */ + register int p; /* best score at (i-1, j-1) */ + register int ci, cj; /* end-point associated with c */ + register int di, dj; /* end-point associated with d */ + register int fi, fj; /* end-point associated with f */ + register int pi, pj; /* end-point associated with p */ + + int addnode(); /* function for inserting a node */ + + + /* Compute the matrix and save the top K best scores in LIST + CC : the scores of the current row + RR and EE : the starting point that leads to score CC + DD : the scores of the current row, ending with deletion + SS and FF : the starting point that leads to score DD */ + /* Initialize the 0 th row */ + for ( j = 1; j <= N ; j++ ) + { CC[j] = 0; + RR[j] = 0; + EE[j] = j; + DD[j] = - (q); + SS[j] = 0; + FF[j] = j; + } + for ( i = 1; i <= M; i++) + { c = 0; /* Initialize column 0 */ + f = - (q); + ci = fi = i; + if ( nseq == 2 ) + { p = 0; + pi = i - 1; + cj = fj = pj = 0; + } + else + { p = CC[i]; + pi = RR[i]; + pj = EE[i]; + cj = fj = i; + } + for ( j = (nseq == 2 ? 1 : (i+1)) ; j <= N ; j++ ) + { f = f - r; + c = c - qr; + ORDER(f, fi, fj, c, ci, cj) + c = CC[j] - qr; + ci = RR[j]; + cj = EE[j]; + d = DD[j] - r; + di = SS[j]; + dj = FF[j]; + ORDER(d, di, dj, c, ci, cj) + c = 0; + + DIAG(i, j, c, p+TC_SCORE(A[i-1],B[j-1])) /* diagonal */ + + if ( c <= 0 ) + { c = 0; ci = i; cj = j; } + else + { ci = pi; cj = pj; } + ORDER(c, ci, cj, d, di, dj) + ORDER(c, ci, cj, f, fi, fj) + p = CC[j]; + CC[j] = c; + pi = RR[j]; + pj = EE[j]; + RR[j] = ci; + EE[j] = cj; + DD[j] = d; + SS[j] = di; + FF[j] = dj; + if ( c > lmin ) /* add the score into list */ + lmin = addnode(c, ci, cj, i, j, K, lmin); + } + } +return 1; +} + +/* Determine the left and top boundaries of the recomputed area */ + +int locate(int *A,int *B,int nseq) +{ register int i, j; /* row and column indices */ + register int c; /* best score at current point */ + register int f; /* best score ending with insertion */ + register int d; /* best score ending with deletion */ + register int p; /* best score at (i-1, j-1) */ + register int ci, cj; /* end-point associated with c */ + register int di=0, dj=0; /* end-point associated with d */ + register int fi, fj; /* end-point associated with f */ + register int pi, pj; /* end-point associated with p */ + int cflag, rflag; /* for recomputation */ + int addnode(); /* function for inserting a node */ + int limit; /* the bound on j */ + + /* Reverse pass + rows + CC : the scores on the current row + RR and EE : the endpoints that lead to CC + DD : the deletion scores + SS and FF : the endpoints that lead to DD + + columns + HH : the scores on the current columns + II and JJ : the endpoints that lead to HH + WW : the deletion scores + XX and YY : the endpoints that lead to WW + */ + for ( j = nn; j >= n1 ; j-- ) + { CC[j] = 0; + EE[j] = j; + DD[j] = - (q); + FF[j] = j; + if ( nseq == 2 || j > mm ) + RR[j] = SS[j] = mm + 1; + else + RR[j] = SS[j] = j; + } + + for ( i = mm; i >= m1; i-- ) + { c = p = 0; + f = - (q); + ci = fi = i; + pi = i + 1; + cj = fj = pj = nn + 1; + + if ( nseq == 2 || n1 > i ) + limit = n1; + else + limit = i + 1; + for ( j = nn; j >= limit ; j-- ) + { f = f - r; + c = c - qr; + ORDER(f, fi, fj, c, ci, cj) + c = CC[j] - qr; + ci = RR[j]; + cj = EE[j]; + d = DD[j] - r; + di = SS[j]; + dj = FF[j]; + ORDER(d, di, dj, c, ci, cj) + c = 0; + DIAG(i, j, c, p+TC_SCORE(A[i-1],B[j-1])) /* diagonal */ + + if ( c <= 0 ) + { c = 0; ci = i; cj = j; } + else + { ci = pi; cj = pj; } + ORDER(c, ci, cj, d, di, dj) + ORDER(c, ci, cj, f, fi, fj) + p = CC[j]; + CC[j] = c; + pi = RR[j]; + pj = EE[j]; + RR[j] = ci; + EE[j] = cj; + DD[j] = d; + SS[j] = di; + FF[j] = dj; + if ( c > lmin ) + flag = 1; + } + if ( nseq == 2 || i < n1 ) + { HH[i] = CC[n1]; + II[i] = RR[n1]; + JJ[i] = EE[n1]; + WW[i] = DD[n1]; + XX[i] = SS[n1]; + YY[i] = FF[n1]; + } + } + + for ( rl = m1, cl = n1; ; ) + { for ( rflag = cflag = 1; ( rflag && m1 > 1 ) || ( cflag && n1 > 1 ) ; ) + { if ( rflag && m1 > 1 ) /* Compute one row */ + { rflag = 0; + m1--; + c = p = 0; + f = - (q); + ci = fi = m1; + pi = m1 + 1; + cj = fj = pj = nn + 1; + + for ( j = nn; j >= n1 ; j-- ) + { f = f - r; + c = c - qr; + ORDER(f, fi, fj, c, ci, cj) + c = CC[j] - qr; + ci = RR[j]; + cj = EE[j]; + d = DD[j] - r; + di = SS[j]; + dj = FF[j]; + ORDER(d, di, dj, c, ci, cj) + c = 0; + DIAG(m1, j, c, TC_SCORE(A[m1-1],B[j-1])) /* diagonal */ + + if ( c <= 0 ) + { c = 0; ci = m1; cj = j; } + else + { ci = pi; cj = pj; } + ORDER(c, ci, cj, d, di, dj) + ORDER(c, ci, cj, f, fi, fj) + p = CC[j]; + CC[j] = c; + pi = RR[j]; + pj = EE[j]; + RR[j] = ci; + EE[j] = cj; + DD[j] = d; + SS[j] = di; + FF[j] = dj; + if ( c > lmin ) + flag = 1; + if ( ! rflag && ( (ci > rl && cj > cl) || (di > rl && dj > cl) + || (fi > rl && fj > cl) ) ) + rflag = 1; + } + HH[m1] = CC[n1]; + II[m1] = RR[n1]; + JJ[m1] = EE[n1]; + WW[m1] = DD[n1]; + XX[m1] = SS[n1]; + YY[m1] = FF[n1]; + if ( ! cflag && ( (ci > rl && cj > cl) || (di > rl && dj > cl) + || (fi > rl && fj > cl )) ) + cflag = 1; + } + + if ( nseq == 1 && n1 == (m1 + 1) && ! rflag ) + cflag = 0; + if ( cflag && n1 > 1 ) /* Compute one column */ + { cflag = 0; + n1--; + c = 0; + f = - (q); + cj = fj = n1; + if ( nseq == 2 || mm < n1 ) + { p = 0; + ci = fi = pi = mm + 1; + pj = n1 + 1; + limit = mm; + } + else + { p = HH[n1]; + pi = II[n1]; + pj = JJ[n1]; + ci = fi = n1; + limit = n1 - 1; + } + for ( i = limit; i >= m1 ; i-- ) + { f = f - r; + c = c - qr; + ORDER(f, fi, fj, c, ci, cj) + c = HH[i] - qr; + ci = II[i]; + cj = JJ[i]; + d = WW[i] - r; + di = XX[i]; + dj = YY[i]; + ORDER(d, di, dj, c, ci, cj) + c = 0; + DIAG(i, n1, c, p+TC_SCORE(A[i-1], B[n1-1])) + + + + if ( c <= 0 ) + { c = 0; ci = i; cj = n1; } + else + { ci = pi; cj = pj; } + ORDER(c, ci, cj, d, di, dj) + ORDER(c, ci, cj, f, fi, fj) + p = HH[i]; + HH[i] = c; + pi = II[i]; + pj = JJ[i]; + II[i] = ci; + JJ[i] = cj; + WW[i] = d; + XX[i] = di; + YY[i] = dj; + if ( c > lmin ) + flag = 1; + if ( ! cflag && ( (ci > rl && cj > cl) || (di > rl && dj > cl) + || (fi > rl && fj > cl )) ) + cflag = 1; + } + CC[n1] = HH[m1]; + RR[n1] = II[m1]; + EE[n1] = JJ[m1]; + DD[n1] = WW[m1]; + SS[n1] = XX[m1]; + FF[n1] = YY[m1]; + if ( ! rflag && ( (ci > rl && cj > cl) || (di > rl && dj > cl) + || (fi > rl && fj > cl) ) ) + rflag = 1; + } + } + if ( (m1 == 1 && n1 == 1) || no_cross() ) + break; + } + m1--; + n1--; +return 1; +} + +/* recompute the area on forward pass */ +int small_pass(int *A,int *B,int count,int nseq) +{ register int i, j; /* row and column indices */ + register int c; /* best score at current point */ + register int f; /* best score ending with insertion */ + register int d; /* best score ending with deletion */ + register int p; /* best score at (i-1, j-1) */ + register int ci, cj; /* end-point associated with c */ + register int di, dj; /* end-point associated with d */ + register int fi, fj; /* end-point associated with f */ + register int pi, pj; /* end-point associated with p */ + int addnode(); /* function for inserting a node */ + int limit; /* lower bound on j */ + + for ( j = n1 + 1; j <= nn ; j++ ) + { CC[j] = 0; + RR[j] = m1; + EE[j] = j; + DD[j] = - (q); + SS[j] = m1; + FF[j] = j; + } + for ( i = m1 + 1; i <= mm; i++) + { c = 0; /* Initialize column 0 */ + f = - (q); + ci = fi = i; + + if ( nseq == 2 || i <= n1 ) + { p = 0; + pi = i - 1; + cj = fj = pj = n1; + limit = n1 + 1; + } + else + { p = CC[i]; + pi = RR[i]; + pj = EE[i]; + cj = fj = i; + limit = i + 1; + } + for ( j = limit ; j <= nn ; j++ ) + { f = f - r; + c = c - qr; + ORDER(f, fi, fj, c, ci, cj) + c = CC[j] - qr; + ci = RR[j]; + cj = EE[j]; + d = DD[j] - r; + di = SS[j]; + dj = FF[j]; + ORDER(d, di, dj, c, ci, cj) + c = 0; + DIAG(i, j, c, p+TC_SCORE(A[i-1], B[j-1])) /* diagonal */ + //checked + + if ( c <= 0 ) + { c = 0; ci = i; cj = j; } + else + { ci = pi; cj = pj; } + ORDER(c, ci, cj, d, di, dj) + ORDER(c, ci, cj, f, fi, fj) + p = CC[j]; + CC[j] = c; + pi = RR[j]; + pj = EE[j]; + RR[j] = ci; + EE[j] = cj; + DD[j] = d; + SS[j] = di; + FF[j] = dj; + if ( c > lmin ) /* add the score into list */ + lmin = addnode(c, ci, cj, i, j, count, lmin); + } + } +return 1; +} + +/* Add a new node into list. */ + +int addnode(c, ci, cj, i, j, K, cost) int c, ci, cj, i, j, K, cost; +{ int found; /* 1 if the node is in LIST */ + register int d; + + found = 0; + if ( most != 0 && most->SIM_STARI == ci && most->SIM_STARJ == cj ) + found = 1; + else + for ( d = 0; d < numnode ; d++ ) + { most = LIST[d]; + if ( most->SIM_STARI == ci && most->SIM_STARJ == cj ) + { found = 1; + break; + } + } + if ( found ) + { if ( most->SIM_SCORE < c ) + { most->SIM_SCORE = c; + most->SIM_ENDI = i; + most->SIM_ENDJ = j; + } + if ( most->SIM_TOP > i ) most->SIM_TOP = i; + if ( most->SIM_BOT < i ) most->SIM_BOT = i; + if ( most->SIM_LEFT > j ) most->SIM_LEFT = j; + if ( most->SIM_RIGHT < j ) most->SIM_RIGHT = j; + } + else + { if ( numnode == K ) /* list full */ + most = low; + else + most = LIST[numnode++]; + most->SIM_SCORE = c; + most->SIM_STARI = ci; + most->SIM_STARJ = cj; + most->SIM_ENDI = i; + most->SIM_ENDJ = j; + most->SIM_TOP = most->SIM_BOT = i; + most->SIM_LEFT = most->SIM_RIGHT = j; + } + if ( numnode == K ) + { if ( low == most || ! low ) + { for ( low = LIST[0], d = 1; d < numnode ; d++ ) + if ( LIST[d]->SIM_SCORE < low->SIM_SCORE ) + low = LIST[d]; + } + return ( low->SIM_SCORE ) ; + } + else + return cost; +} + +/* Find and remove the largest score in list */ + +vertexptr findmax() +{ vertexptr cur; + register int i, j; + + for ( j = 0, i = 1; i < numnode ; i++ ) + if ( LIST[i]->SIM_SCORE > LIST[j]->SIM_SCORE ) + j = i; + cur = LIST[j]; + if ( j != --numnode ) + { LIST[j] = LIST[numnode]; + LIST[numnode] = cur; + } + most = LIST[0]; + if ( low == cur ) low = LIST[0]; + return ( cur ); +} + +/* return 1 if no node in LIST share vertices with the area */ + +int no_cross() +{ vertexptr cur; + register int i; + + for ( i = 0; i < numnode; i++ ) + { cur = LIST[i]; + if ( cur->SIM_STARI <= mm && cur->SIM_STARJ <= nn && cur->SIM_BOT >= m1-1 && + cur->SIM_RIGHT >= n1-1 && ( cur->SIM_STARI < rl || cur->SIM_STARJ < cl )) + { if ( cur->SIM_STARI < rl ) rl = cur->SIM_STARI; + if ( cur->SIM_STARJ < cl ) cl = cur->SIM_STARJ; + flag = 1; + break; + } + } + if ( i == numnode ) + return 1; + else + return 0; +} + +/* diff(A,B,M,N,tb,te) returns the score of an optimum conversion between + A[1..M] and B[1..N] that begins(ends) with a delete if tb(te) is zero + and appends such a conversion to the current script. */ + +int diff_sim( int *A,int *B,int M,int N,int tb,int te) + +{ int midi, midj, type; /* Midpoint, type, and cost */ + int midc; + + { + register int i, j; + register int c, e, d, s; + int t; + + + /* Boundary cases: M <= 1 or N == 0 */ + + if (N <= 0) + { if (M > 0) DEL(M) + return - gap(M); + } + if (M <= 1) + { if (M <= 0) + { INS(N); + return - gap(N); + } + if (tb > te) tb = te; + midc = - (tb + r + gap(N) ); + midj = 0; + + for (j = 1; j <= N; j++) + { for ( tt = 1, z = row[I+1]; z != PAIRNULL; z = z->NEXT ) + if ( z->COL == j+J ) + { tt = 0; break; } + if ( tt ) + { c = TC_SCORE (A[0],B[j-1]) - ( gap(j-1) + gap(N-j) ); + //checked + + if (c > midc) + { midc = c; + midj = j; + } + } + } + if (midj == 0) + { INS(N) DEL(1) } + else + { if (midj > 1) INS(midj-1) + REP + if ( A[1] == B[midj] ) + no_mat += 1; + else + no_mis += 1; + /* mark (A[I],B[J]) as used: put J into list row[I] */ + I++; J++; + + + z = ( pairptr )sim_vcalloc(1,sizeof(pair)); + z->COL = J; + z->NEXT = row[I]; + row[I] = z; + if (midj < N) INS(N-midj) + } + return midc; + } + + /* Divide: Find optimum midpoint (midi,midj) of cost midc */ + + midi = M/2; /* Forward phase: */ + CC[0] = 0; /* Compute C(M/2,k) & D(M/2,k) for all k */ + t = -q; + for (j = 1; j <= N; j++) + { CC[j] = t = t-r; + DD[j] = t-q; + } + t = -tb; + for (i = 1; i <= midi; i++) + { s = CC[0]; + CC[0] = c = t = t-r; + e = t-q; + + for (j = 1; j <= N; j++) + { if ((c = c - qr) > (e = e - r)) e = c; + if ((c = CC[j] - qr) > (d = DD[j] - r)) d = c; + DIAG(i+I, j+J, c, s+TC_SCORE(A[i-1], B[j-1])) + //checked + + if (c < d) c = d; + if (c < e) c = e; + s = CC[j]; + CC[j] = c; + DD[j] = d; + } + } + DD[0] = CC[0]; + + RR[N] = 0; /* Reverse phase: */ + t = -q; /* Compute R(M/2,k) & S(M/2,k) for all k */ + for (j = N-1; j >= 0; j--) + { RR[j] = t = t-r; + SS[j] = t-q; + } + t = -te; + for (i = M-1; i >= midi; i--) + { s = RR[N]; + RR[N] = c = t = t-r; + e = t-q; + + for (j = N-1; j >= 0; j--) + { if ((c = c - qr) > (e = e - r)) e = c; + if ((c = RR[j] - qr) > (d = SS[j] - r)) d = c; + DIAG(i+1+I, j+1+J, c, s+TC_SCORE (A[i],B[j])) /*not -1 on purpose*/ + + if (c < d) c = d; + if (c < e) c = e; + s = RR[j]; + RR[j] = c; + SS[j] = d; + } + } + SS[N] = RR[N]; + + midc = CC[0]+RR[0]; /* Find optimal midpoint */ + midj = 0; + type = 1; + for (j = 0; j <= N; j++) + if ((c = CC[j] + RR[j]) >= midc) + if (c > midc || (CC[j] != DD[j] && RR[j] == SS[j])) + { midc = c; + midj = j; + } + for (j = N; j >= 0; j--) + if ((c = DD[j] + SS[j] + q) > midc) + { midc = c; + midj = j; + type = 2; + } + } + + /* Conquer: recursively around midpoint */ + + if (type == 1) + { diff_sim(A,B,midi,midj,tb,q); + diff_sim(A+midi,B+midj,M-midi,N-midj,q,te); + } + else + { diff_sim(A,B,midi-1,midj,tb,zero); + DEL(2); + diff_sim(A+midi+1,B+midj,M-midi-1,N-midj,zero,te); + } + return midc; +} + + + + +int calcons(int *aa0,int n0,int *aa1,int n1,int *res,int *nc,int *nident, Alignment *A, int *ns, int **l_s, Constraint_list *CL) +{ + int i0, i1; + int op, nid, lenc, nd; + int *sp0, *sp1; + int *rp; + int a, b, id_col, tot_col, r0, r1; + + min0--; min1--; + + sp0 = seqc0+mins; + sp1 = seqc1+mins; + rp = res; + lenc = nid = op = 0; + i0 = min0; + i1 = min1; + + while (i0 < max0 || i1 < max1) { + if (op == 0 && *rp == 0) { + op = *rp++; + *sp0 = aa0[i0++]; + *sp1 = aa1[i1++]; + + + for (id_col=tot_col=0,a=0; a< ns[0]; a++) + for ( b=0; b< ns[1]; b++) + { + r0=Aln->seq_al[l_s[0][a]][*sp0-1]; + r1=Aln->seq_al[l_s[1][a]][*sp1-1]; + + if ( !is_gap(r0) && r1==r0)id_col++; + if ( !is_gap(r0) && !is_gap(r1))tot_col++; + } + nid+=(tot_col)?(id_col/tot_col):0; + lenc++; + sp0++; sp1++; + } + else { + if (op==0) op = *rp++; + if (op>0) { + *sp0++ = SIM_GAP; + *sp1++ = aa1[i1++]; + op--; + lenc++; + } + else { + *sp0++ = aa0[i0++]; + *sp1++ = SIM_GAP; + op++; + lenc++; + } + } + } + + *nident = nid; + *nc = lenc; + + nd = 0; + return mins+lenc+nd; +} + +/*Memory management */ +struct Mem + { + void *p; + struct Mem *next; + }; + +typedef struct Mem Mem; + +Mem *first_mem; +Mem *last_mem; + +void *sim_vcalloc ( size_t nobj, size_t size) +{ + void *p; + Mem *new_mem; + + p=vcalloc (nobj, size); + + + new_mem=vcalloc (1, sizeof (Mem)); + if ( last_mem==NULL)first_mem=last_mem=new_mem; + else + { + last_mem->next=new_mem; + last_mem=new_mem; + } + last_mem->p=p; + return p; +} + +void sim_free_all() +{ + Mem *p1, *p2; + p1=first_mem; + + + while (p1) + { + p2=p1->next; + vfree(p1->p); + vfree(p1); + p1=p2; + } + first_mem=last_mem=NULL; + sim_reset_static_variable(); +} + +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/util_dp_ssec_pwaln.c b/binaries/src/tcoffee/t_coffee_source/util_dp_ssec_pwaln.c new file mode 100644 index 0000000..86405a4 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/util_dp_ssec_pwaln.c @@ -0,0 +1,476 @@ +#include +#include +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" +#include "dp_lib_header.h" + +int ssec_pwaln_maln (Alignment *A, int *ns, int **ls, Constraint_list *CL) + { + + static Dp_Model *M=NULL; + Dp_Result *R=NULL; + int a, ndiag; + int Sa,Sb,St, Da, Db, Dt, Ia, Ib, It; + int ala, alb, s,b; + + a=0; + Sa=a++;Da=a++;Ia=a++; + Sb=a++;Db=a++;Ib=a++; + St=a++;Dt=a++;It=a++; + + if ( strm (CL->matrices_list[0], "analyse")) + { + for ( a=0; a< CL->n_matrices; a++) + { + + rescale_two_mat(CL->matrices_list[1],CL->matrices_list[2],1000, 100, AA_ALPHABET); + exit (0); + } + } + + + + /*2 Prepare the Model*/ + M=initialize_sseq_model(2,2,CL); + ndiag=strlen (A->seq_al[0])+strlen (A->seq_al[1])-1; + M->diag=vcalloc (ndiag+1, sizeof (int)); + M->diag[0]=ndiag-1; + for ( a=1; a<=M->diag[0]; a++)M->diag[a]=a; + + /*3 Prepare Sequence Presentation*/ + R=make_fast_generic_dp_pair_wise(A, ns, ls, M); + + + ala=alb=0; + + A=realloc_aln2(A,A->nseq, R->len+1); + for (b=1; blen;b++) + { + if (R->traceback[b]==Sa || R->traceback[b]==Sb ||R->traceback[b]==St ) + { + for (s=0; sseq_al[ls[0][s]][b-1]=(CL->S)->seq[A->order[ls[0][s]][0]][ala]; + ala++; + for (s=0; sseq_al[ls[1][s]][b-1]=(CL->S)->seq[A->order[ls[1][s]][0]][alb]; + alb++; + } + else if ( R->traceback[b]==Da || R->traceback[b]==Db ||R->traceback[b]==Dt ) + { + for (s=0; sseq_al[ls[0][s]][b-1]=(CL->S)->seq[A->order[ls[0][s]][0]][ala]; + ala++; + for (s=0; sseq_al[ls[1][s]][b-1]='-'; + } + else if ( R->traceback[b]==Ia || R->traceback[b]==Ib ||R->traceback[b]==It ) + { + for (s=0; sseq_al[ls[0][s]][b-1]='-'; + + for (s=0; sseq_al[ls[1][s]][b-1]=(CL->S)->seq[A->order[ls[1][s]][0]][alb]; + alb++; + } + } + for (s=0; sseq_al[ls[0][s]][b-1]='\0'; + for (s=0; sseq_al[ls[1][s]][b-1]='\0'; + + A->len_aln=strlen (A->seq_al[ls[0][0]]); + R->Dp_model=M; + A->Dp_result=R; + return A->score; + } + +Dp_Model * initialize_sseq_model(int left_tg_mode, int right_tg_mode, Constraint_list *CL) + { + + Dp_Model *M; + int a, b, c,d; + int Sa,Sb,St, Da, Db, Dt, Ia, Ib, It; + int tgop=CL->gep*3; + + + + + M=vcalloc ( 1, sizeof (Dp_Model)); + + M->nstate=9; + M->START=M->nstate++; + M->END =M->nstate++; + + M->model_comments=declare_char (M->nstate+1, 100); + M->bounded_model=declare_int (M->nstate+1, M->nstate+1); + M->model=declare_int (M->nstate+1, M->nstate+1); + for ( a=0; a<=M->nstate; a++) + for ( b=0; b<= M->nstate; b++) + M->model[a][b]=UNDEFINED; + + + M->model_properties=declare_int ( M->nstate, 10); + + a=0; + M->TYPE=a++;M->LEN_I=a++; M->LEN_J=a++; M->DELTA_I=a++;M->DELTA_J=a++;M->EMISSION=a++;M->TERM_EMISSION=a++;M->START_EMISSION=a++; + M->CODING0=a++;M->DELETION=a++; + M->model_properties=declare_int ( M->nstate, 10); + + a=0; + M->EMISSION=a++;M->TERM_EMISSION=a++;M->START_EMISSION=a++; + M->model_emission_function=vcalloc(M->nstate, sizeof (int (**)(Alignment*, int **, int, int*, int, int **, int, int*, int, struct Constraint_list *))); + for ( a=0; a< M->nstate; a++) + M->model_emission_function[a]=vcalloc(3, sizeof (int (*)(Alignment*, int **, int, int*, int, int **, int, int*, int, struct Constraint_list *))); + + + + a=0; + + Sa=a++;Da=a++;Ia=a++; + Sb=a++;Db=a++;Ib=a++; + St=a++;Dt=a++;It=a++; + + + sprintf ( M->model_comments[M->START], "START"); + sprintf ( M->model_comments[M->END], "END"); + + /*ALPHA*/ + /*Substitution in Alpha*/ + if (CL->matrices_list[0][0])sprintf ( M->model_comments[Sa], "Substitution %s", CL->matrices_list[0]); + M->model_properties[Sa][M->TYPE]=Sa; + M->model_properties[Sa][M->LEN_I]=1; + M->model_properties[Sa][M->LEN_J]=1; + M->model_properties[Sa][M->DELTA_I]=-1; + M->model_properties[Sa][M->DELTA_J]= 0; + + M->model_emission_function[Sa][M->EMISSION] =get_alpha_sub_cost; + M->model_emission_function[Sa][M->START_EMISSION]=get_ssec_no_cost; + M->model_emission_function[Sa][M->TERM_EMISSION] =get_ssec_no_cost; + + /*Deletions*/ + if (CL->matrices_list[0][0])sprintf ( M->model_comments[Da], "Deletion %s", CL->matrices_list[0]); + M->model_properties[Da][M->TYPE]=Da; + M->model_properties[Da][M->LEN_I]=1; + M->model_properties[Da][M->LEN_J]=0; + M->model_properties[Da][M->DELTA_I]=-1; + M->model_properties[Da][M->DELTA_J]=+1; + + + M->model_emission_function[Da][M->EMISSION] =get_alpha_gep_cost; + M->model_emission_function[Da][M->START_EMISSION]=get_alpha_start_gep_cost; + M->model_emission_function[Da][M->TERM_EMISSION] =get_alpha_term_gep_cost; + + + /*Insertion*/ + if (CL->matrices_list[0][0])sprintf ( M->model_comments[Ia], "Insertion %s", CL->matrices_list[0]); + M->model_properties[Ia][M->TYPE]=Ia; + M->model_properties[Ia][M->LEN_I]=0; + M->model_properties[Ia][M->LEN_J]=1; + M->model_properties[Ia][M->DELTA_I]=0; + M->model_properties[Ia][M->DELTA_J]=-1; + + M->model_emission_function[Ia][M->EMISSION] =get_alpha_gep_cost; + M->model_emission_function[Ia][M->START_EMISSION]=get_alpha_start_gep_cost; + M->model_emission_function[Ia][M->TERM_EMISSION] =get_alpha_term_gep_cost; + +/*BETA*/ + /*Substitution in Beta*/ + if (CL->matrices_list[1][0])sprintf ( M->model_comments[Sb], "Substitution %s", CL->matrices_list[1]); + M->model_properties[Sb][M->TYPE]=Sb; + M->model_properties[Sb][M->LEN_I]=1; + M->model_properties[Sb][M->LEN_J]=1; + M->model_properties[Sb][M->DELTA_I]=-1; + M->model_properties[Sb][M->DELTA_J]= 0; + + M->model_emission_function[Sb][M->EMISSION] =get_beta_sub_cost; + M->model_emission_function[Sb][M->START_EMISSION]=get_ssec_no_cost; + M->model_emission_function[Sb][M->TERM_EMISSION] =get_ssec_no_cost; + + + /*Deletions*/ + if (CL->matrices_list[1][0])sprintf ( M->model_comments[Db], "Deletion %s", CL->matrices_list[1]); + M->model_properties[Db][M->TYPE]=Db; + M->model_properties[Db][M->LEN_I]=1; + M->model_properties[Db][M->LEN_J]=0; + M->model_properties[Db][M->DELTA_I]=-1; + M->model_properties[Db][M->DELTA_J]=+1; + + M->model_emission_function[Db][M->EMISSION] =get_beta_gep_cost; + M->model_emission_function[Db][M->START_EMISSION]=get_beta_start_gep_cost; + M->model_emission_function[Db][M->TERM_EMISSION] =get_beta_term_gep_cost; + + + /*Insertion*/ + + if (CL->matrices_list[1][0])sprintf ( M->model_comments[Ib], "Insertion %s", CL->matrices_list[1]); + M->model_properties[Ib][M->TYPE]=Ib; + M->model_properties[Ib][M->LEN_I]=0; + M->model_properties[Ib][M->LEN_J]=1; + M->model_properties[Ib][M->DELTA_I]=0; + M->model_properties[Ib][M->DELTA_J]=-1; + + + + M->model_emission_function[Ib][M->EMISSION] =get_beta_gep_cost; + M->model_emission_function[Ib][M->START_EMISSION]=get_beta_start_gep_cost; + M->model_emission_function[Ib][M->TERM_EMISSION] =get_beta_term_gep_cost; + + /*TURNS*/ + /*Substitution in Turn*/ + if (CL->matrices_list[2][0])sprintf ( M->model_comments[St], "Substitution %s", CL->matrices_list[2]); + M->model_properties[St][M->TYPE]=St; + M->model_properties[St][M->LEN_I]=1; + M->model_properties[St][M->LEN_J]=1; + M->model_properties[St][M->DELTA_I]=-1; + M->model_properties[St][M->DELTA_J]= 0; + + M->model_emission_function[St][M->EMISSION] =get_turn_sub_cost; + M->model_emission_function[St][M->START_EMISSION]=get_ssec_no_cost; + M->model_emission_function[St][M->TERM_EMISSION] =get_ssec_no_cost; + + + /*Deletions*/ + if (CL->matrices_list[2][0])sprintf ( M->model_comments[Dt], "Deletion %s", CL->matrices_list[2]); + M->model_properties[Dt][M->TYPE]=Dt; + M->model_properties[Dt][M->LEN_I]=1; + M->model_properties[Dt][M->LEN_J]=0; + M->model_properties[Dt][M->DELTA_I]=-1; + M->model_properties[Dt][M->DELTA_J]=+1; + + M->model_emission_function[Dt][M->EMISSION] =get_turn_gep_cost; + M->model_emission_function[Dt][M->START_EMISSION]=get_turn_start_gep_cost; + M->model_emission_function[Dt][M->TERM_EMISSION] =get_turn_term_gep_cost; + /*Insertion*/ + if (CL->matrices_list[2][0])sprintf ( M->model_comments[It], "Insertion %s", CL->matrices_list[2]); + M->model_properties[It][M->TYPE]=It; + M->model_properties[It][M->LEN_I]=0; + M->model_properties[It][M->LEN_J]=1; + M->model_properties[It][M->DELTA_I]=0; + M->model_properties[It][M->DELTA_J]=-1; + + M->model_emission_function[It][M->EMISSION] =get_turn_gep_cost; + M->model_emission_function[It][M->START_EMISSION]=get_turn_start_gep_cost; + M->model_emission_function[It][M->TERM_EMISSION] =get_turn_term_gep_cost; + + +/*Transitions*/ + + M->model[M->START][Sa]=ALLOWED; + M->model[M->START][Sb]=ALLOWED; + M->model[M->START][St]=ALLOWED; + M->model[M->START][Db]=M->model[M->START][Ib]=(CL->TG_MODE==0)?CL->gop*SCORE_K:0; + M->model[M->START][Da]=M->model[M->START][Ia]=(CL->TG_MODE==0)?CL->gop*SCORE_K:0; + M->model[M->START][Dt]=M->model[M->START][It]=(CL->TG_MODE==0)?CL->gop*SCORE_K:0; + + + M->model[Sa][M->END]=ALLOWED; + M->model[Sb][M->END]=ALLOWED; + M->model[St][M->END]=ALLOWED; + M->model[Ia][M->END]=M->model[Da][M->END]=(CL->TG_MODE==0)?0:CL->gop*SCORE_K*(-1); + M->model[Ib][M->END]=M->model[Db][M->END]=(CL->TG_MODE==0)?0:CL->gop*SCORE_K*(-1); + M->model[It][M->END]=M->model[Dt][M->END]=(CL->TG_MODE==0)?0:CL->gop*SCORE_K*(-1); + + for ( a=0; a< M->nstate; a++)M->model[a][a]=ALLOWED; + + M->model[Sa][Ia]=M->model[Sa][Da]=CL->gop*SCORE_K; + M->model[Sa][Ib]=M->model[Sa][Db]=CL->gop*SCORE_K+tgop*SCORE_K; + M->model[Sa][It]=M->model[Sa][Dt]=CL->gop*SCORE_K+tgop*SCORE_K; + M->model[Sa][Sb]=M->model[Sa][St]=tgop*SCORE_K; + + M->model[Sb][Ib]=M->model[Sb][Db]=CL->gop*SCORE_K; + M->model[Sb][Ia]=M->model[Sb][Da]=CL->gop*SCORE_K+tgop*SCORE_K; + M->model[Sb][It]=M->model[Sb][Dt]=CL->gop*SCORE_K+tgop*SCORE_K; + M->model[Sb][Sa]=M->model[Sb][St]=tgop*SCORE_K; + + M->model[St][It]=M->model[St][Dt]=CL->gop*SCORE_K; + M->model[St][Ia]=M->model[St][Da]=CL->gop*SCORE_K+tgop*SCORE_K; + M->model[St][Ib]=M->model[St][Db]=CL->gop*SCORE_K+tgop*SCORE_K; + M->model[St][Sa]=M->model[St][Sb]=tgop*SCORE_K; + + M->model[Ia][Sa]=M->model[Da][Sa]=ALLOWED; + M->model[Ia][Sb]=M->model[Da][Sb]=tgop*SCORE_K; + M->model[Ia][St]=M->model[Da][St]=tgop*SCORE_K; + + M->model[Ib][Sa]=M->model[Db][Sa]=tgop*SCORE_K; + M->model[Ib][Sb]=M->model[Db][Sb]=ALLOWED; + M->model[Ib][St]=M->model[Db][St]=tgop*SCORE_K; + + M->model[It][Sa]=M->model[Dt][Sa]=tgop*SCORE_K; + M->model[It][Sb]=M->model[Dt][Sb]=tgop*SCORE_K; + M->model[It][St]=M->model[Dt][St]=ALLOWED; + + + + /*Prune the model*/ + + for (c=0,a=0, d=0; a< M->START; a++) + for ( b=0; bSTART; b++, d++) + { + if (M->model[a][b]!=UNDEFINED) + { + M->bounded_model[b][1+M->bounded_model[b][0]++]=a; + c++; + } + } + M->CL=CL; + + return M; + } + + + + + +int get_alpha_sub_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) +{ + static int **mat; + int s1, r1, s2, r2; + float score; + + + if (!mat && CL->matrices_list[0][0])mat=read_matrice (CL->matrices_list[0]); + else if ( !CL->matrices_list[0][0])return UNDEFINED; + + + + + s1=A->order[list1[0]][0]; + r1=pos1[list1[0]][col1]; + s2=A->order[list2[0]][0]; + r2=pos1[list2[0]][col2]; + + if ( r1<0 || r2<0)return 0; + + score=mat[(CL->S)->seq[s1][r1-1]-'A'][(CL->S)->seq[s2][r2-1]-'A']*SCORE_K; + return (int)score; + +} +int get_beta_sub_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) +{ + static int **mat; + int s1, r1, s2, r2; + float score; + + if (!mat && CL->matrices_list[1][0])mat=read_matrice (CL->matrices_list[1]); + else if ( !CL->matrices_list[1][0])return UNDEFINED; + + + + s1=A->order[list1[0]][0]; + r1=pos1[list1[0]][col1]; + s2=A->order[list2[0]][0]; + r2=pos1[list2[0]][col2]; + if ( r1<0 || r2<0)return 0; + + score=mat[(CL->S)->seq[s1][r1-1]-'A'][(CL->S)->seq[s2][r2-1]-'A']*SCORE_K; + return (int)score; + +} +int get_turn_sub_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) +{ + static int **mat; + int s1, r1, s2, r2; + float score; + + + + if (!mat && CL->matrices_list[2][0])mat=read_matrice (CL->matrices_list[2]); + else if ( !CL->matrices_list[2][0])return UNDEFINED; + + + s1=A->order[list1[0]][0]; + r1=pos1[list1[0]][col1]; + s2=A->order[list2[0]][0]; + r2=pos1[list2[0]][col2]; + + + if ( r1<0 || r2<0)return 0; + score=mat[(CL->S)->seq[s1][r1-1]-'A'][(CL->S)->seq[s2][r2-1]-'A']*SCORE_K; + return (int)score; + +} + +int get_turn_gep_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) +{ + return (CL->gep) *SCORE_K; +} +int get_turn_start_gep_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) +{ + return ((CL->TG_MODE)==2)?0:get_turn_gep_cost(A,pos1, ns1, list1, col1, pos2, ns2, list2, col2, CL); +} +int get_turn_term_gep_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) +{ + return ((CL->TG_MODE)==2)?-get_turn_gep_cost(A,pos1, ns1, list1, col1, pos2, ns2, list2, col2, CL):0; +} + + +int get_alpha_gep_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) +{ + return (CL->gep)*SCORE_K; +} +int get_alpha_start_gep_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) +{ + return ((CL->TG_MODE)==2)?0:get_alpha_gep_cost(A,pos1, ns1, list1, col1, pos2, ns2, list2, col2, CL); +} +int get_alpha_term_gep_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) +{ + return ((CL->TG_MODE)==2)?-get_alpha_gep_cost(A,pos1, ns1, list1, col1, pos2, ns2, list2, col2, CL):0; +} + + +int get_beta_gep_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) +{ + return (CL->gep)*SCORE_K; +} +int get_beta_start_gep_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) +{ + return ((CL->TG_MODE)==2)?0:get_beta_gep_cost(A,pos1, ns1, list1, col1, pos2, ns2, list2, col2, CL); +} +int get_beta_term_gep_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) +{ + return ((CL->TG_MODE)==2)?-get_beta_gep_cost(A,pos1, ns1, list1, col1, pos2, ns2, list2, col2, CL):0; +} + + +int get_ssec_no_cost (Alignment *A, int**pos1, int ns1, int*list1, int col1, int**pos2, int ns2, int*list2, int col2, Constraint_list *CL) +{ + return 0; +} + + + + +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/util_dp_suboptimal_nw.c b/binaries/src/tcoffee/t_coffee_source/util_dp_suboptimal_nw.c new file mode 100644 index 0000000..c4a09b9 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/util_dp_suboptimal_nw.c @@ -0,0 +1,1725 @@ +#include +#include +#include +#include +#include +#include +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" + + + + +//Values as provided in Probcons V1.1 +static float EXP_UNDERFLOW_THRESHOLD = -4.60f; +static float LOG_UNDERFLOW_THRESHOLD = 7.50f; +//static float LOG_ZERO = -FLT_MAX; +static float LOG_ZERO=-200000004008175468544.000000; +static float LOG_ONE = 0.0f; +//DNA Alignment Models +static float DNAinitDistrib2Default[] ={ 0.9588437676f, 0.0205782652f, 0.0205782652f }; +static float DNAgapOpen2Default[] = { 0.0190259293f, 0.0190259293f }; +static float DNAgapExtend2Default[] = { 0.3269913495f, 0.3269913495f }; + +static char DNAalphabetDefault[] = "ACGUTN"; +static float DNAemitSingleDefault[6] = {0.2270790040f, 0.2422080040f, 0.2839320004f, 0.2464679927f, 0.2464679927f, 0.0003124650f}; + +static float DNAemitPairsDefault[6][6] = { + { 0.1487240046f, 0.0184142999f, 0.0361397006f, 0.0238473993f, 0.0238473993f, 0.0000375308f }, + { 0.0184142999f, 0.1583919972f, 0.0275536999f, 0.0389291011f, 0.0389291011f, 0.0000815823f }, + { 0.0361397006f, 0.0275536999f, 0.1979320049f, 0.0244289003f, 0.0244289003f, 0.0000824765f }, + { 0.0238473993f, 0.0389291011f, 0.0244289003f, 0.1557479948f, 0.1557479948f, 0.0000743985f }, + { 0.0238473993f, 0.0389291011f, 0.0244289003f, 0.1557479948f, 0.1557479948f, 0.0000743985f }, + { 0.0000375308f, 0.0000815823f, 0.0000824765f, 0.0000743985f, 0.0000743985f, 0.0000263252f } +}; +//RNA Alignment Models + +static float RNAinitDistrib2Default[] = { 0.9615409374f, 0.0000004538f, 0.0000004538f, 0.0192291681f, 0.0192291681f }; +static float RNAgapOpen2Default[] = { 0.0082473317f, 0.0082473317f, 0.0107844425f, 0.0107844425f }; +static float RNAgapExtend2Default[] = { 0.3210460842f, 0.3210460842f, 0.3298229277f, 0.3298229277f }; + +static char RNAalphabetDefault[] = "ACGUTN"; +static float RNAemitSingleDefault[6] = {0.2270790040f, 0.2422080040f, 0.2839320004f, 0.2464679927f, 0.2464679927f, 0.0003124650f}; + +static float RNAemitPairsDefault[6][6] = { + { 0.1487240046f, 0.0184142999f, 0.0361397006f, 0.0238473993f, 0.0238473993f, 0.0000375308f }, + { 0.0184142999f, 0.1583919972f, 0.0275536999f, 0.0389291011f, 0.0389291011f, 0.0000815823f }, + { 0.0361397006f, 0.0275536999f, 0.1979320049f, 0.0244289003f, 0.0244289003f, 0.0000824765f }, + { 0.0238473993f, 0.0389291011f, 0.0244289003f, 0.1557479948f, 0.1557479948f, 0.0000743985f }, + { 0.0238473993f, 0.0389291011f, 0.0244289003f, 0.1557479948f, 0.1557479948f, 0.0000743985f }, + { 0.0000375308f, 0.0000815823f, 0.0000824765f, 0.0000743985f, 0.0000743985f, 0.0000263252f } +}; + +//Protein Alignment Models +static float initDistrib2Default[] = { 0.6814756989f, 8.615339902e-05f, 8.615339902e-05f, 0.1591759622f, 0.1591759622 }; +static float gapOpen2Default[] = { 0.0119511066f, 0.0119511066f, 0.008008334786f, 0.008008334786 }; +static float gapExtend2Default[] = { 0.3965826333f, 0.3965826333f, 0.8988758326f, 0.8988758326 }; + +static char alphabetDefault[] = "ARNDCQEGHILKMFPSTWYV"; +static float emitSingleDefault[20] = { + 0.07831005f, 0.05246024f, 0.04433257f, 0.05130349f, 0.02189704f, + 0.03585766f, 0.05615771f, 0.07783433f, 0.02601093f, 0.06511648f, + 0.09716489f, 0.05877077f, 0.02438117f, 0.04463228f, 0.03940142f, + 0.05849916f, 0.05115306f, 0.01203523f, 0.03124726f, 0.07343426f +}; + +static float emitPairsDefault[20][20] = { + {0.02373072f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00244502f, 0.01775118f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00210228f, 0.00207782f, 0.01281864f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00223549f, 0.00161657f, 0.00353540f, 0.01911178f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00145515f, 0.00044701f, 0.00042479f, 0.00036798f, 0.01013470f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00219102f, 0.00253532f, 0.00158223f, 0.00176784f, 0.00032102f, 0.00756604f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00332218f, 0.00268865f, 0.00224738f, 0.00496800f, 0.00037956f, 0.00345128f, 0.01676565f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00597898f, 0.00194865f, 0.00288882f, 0.00235249f, 0.00071206f, 0.00142432f, 0.00214860f, 0.04062876f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00114353f, 0.00132105f, 0.00141205f, 0.00097077f, 0.00026421f, 0.00113901f, 0.00131767f, 0.00103704f, 0.00867996f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00318853f, 0.00138145f, 0.00104273f, 0.00105355f, 0.00094040f, 0.00100883f, 0.00124207f, 0.00142520f, 0.00059716f, 0.01778263f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00449576f, 0.00246811f, 0.00160275f, 0.00161966f, 0.00138494f, 0.00180553f, 0.00222063f, 0.00212853f, 0.00111754f, 0.01071834f, 0.03583921f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00331693f, 0.00595650f, 0.00257310f, 0.00252518f, 0.00046951f, 0.00312308f, 0.00428420f, 0.00259311f, 0.00121376f, 0.00157852f, 0.00259626f, 0.01612228f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00148878f, 0.00076734f, 0.00063401f, 0.00047808f, 0.00037421f, 0.00075546f, 0.00076105f, 0.00066504f, 0.00042237f, 0.00224097f, 0.00461939f, 0.00096120f, 0.00409522f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00165004f, 0.00090768f, 0.00084658f, 0.00069041f, 0.00052274f, 0.00059248f, 0.00078814f, 0.00115204f, 0.00072545f, 0.00279948f, 0.00533369f, 0.00087222f, 0.00116111f, 0.01661038f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00230618f, 0.00106268f, 0.00100282f, 0.00125381f, 0.00034766f, 0.00090111f, 0.00151550f, 0.00155601f, 0.00049078f, 0.00103767f, 0.00157310f, 0.00154836f, 0.00046718f, 0.00060701f, 0.01846071f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00631752f, 0.00224540f, 0.00301397f, 0.00285226f, 0.00094867f, 0.00191155f, 0.00293898f, 0.00381962f, 0.00116422f, 0.00173565f, 0.00250962f, 0.00312633f, 0.00087787f, 0.00119036f, 0.00180037f, 0.01346609f, 0.0f, 0.0f, 0.0f, 0.0f}, + {0.00389995f, 0.00186053f, 0.00220144f, 0.00180488f, 0.00073798f, 0.00154526f, 0.00216760f, 0.00214841f, 0.00077747f, 0.00248968f, 0.00302273f, 0.00250862f, 0.00093371f, 0.00107595f, 0.00147982f, 0.00487295f, 0.01299436f, 0.0f, 0.0f, 0.0f}, + {0.00039119f, 0.00029139f, 0.00021006f, 0.00016015f, 0.00010666f, 0.00020592f, 0.00023815f, 0.00038786f, 0.00019097f, 0.00039549f, 0.00076736f, 0.00028448f, 0.00016253f, 0.00085751f, 0.00015674f, 0.00026525f, 0.00024961f, 0.00563625f, 0.0f, 0.0f}, + {0.00131840f, 0.00099430f, 0.00074960f, 0.00066005f, 0.00036626f, 0.00070192f, 0.00092548f, 0.00089301f, 0.00131038f, 0.00127857f, 0.00219713f, 0.00100817f, 0.00054105f, 0.00368739f, 0.00047608f, 0.00102648f, 0.00094759f, 0.00069226f, 0.00999315f, 0.0f}, + {0.00533241f, 0.00169359f, 0.00136609f, 0.00127915f, 0.00119152f, 0.00132844f, 0.00178697f, 0.00194579f, 0.00071553f, 0.01117956f, 0.00914460f, 0.00210897f, 0.00197461f, 0.00256159f, 0.00135781f, 0.00241601f, 0.00343452f, 0.00038538f, 0.00148001f, 0.02075171f} +}; + + +static int suboptimal_pair_wise ( Alignment *A, int *ns, int **ls, Constraint_list *CL, int mode); +static int *** forward_so_dp ( Alignment *A, int *ns, int **ls, int **pos,int I, int J, int gop, int gep,int gop2, int gep2,Constraint_list *CL); +static int *** backward_so_dp ( Alignment *A, int *ns, int **ls,int **pos,int I, int J, int gop, int gep,int gop2, int gep2,Constraint_list *CL); +static int *** forward_so_dp_biphasic ( Alignment *A, int *ns, int **ls, int **pos,int I, int J, int gop, int gep,int gop2, int gep2,Constraint_list *CL); +static int *** backward_so_dp_biphasic ( Alignment *A, int *ns, int **ls,int **pos,int I, int J, int gop, int gep,int gop2, int gep2,Constraint_list *CL); +static int *** forward_so_dp_glocal ( Alignment *A, int *ns, int **ls, int **pos,int I, int J, int gop, int gep,int gop2, int gep2,Constraint_list *CL); +static int *** backward_so_dp_glocal ( Alignment *A, int *ns, int **ls,int **pos,int I, int J, int gop, int gep,int gop2, int gep2,Constraint_list *CL); + +static int match=0; +static int ins=1; +static int del=2; +static int umatch=3; +static int ins2=3; +static int del2=4; +float ** get_emitPairs (char *mat, char *alp, float **p, float *s); +int subop1_pair_wise ( Alignment *A, int *ns, int **ls, Constraint_list *CL) +{ + return suboptimal_pair_wise ( A, ns, ls, CL, 1); +} + +int subop2_pair_wise ( Alignment *A, int *ns, int **ls, Constraint_list *CL) +{ + return suboptimal_pair_wise ( A, ns, ls, CL, 3); +} + + + +int suboptimal_pair_wise ( Alignment *A, int *ns, int **ls, Constraint_list *CL, int mode) +{ + int ***F=NULL; + int ***B=NULL; + int **pos0; + int gop, gep,gop2, gep2; + int i, I, j, J, n, s1, s2; + char *seqI, *seqJ; + int id; + int *entry; + float opt, min, score, nscore, thres; + int l1, l2, set; + + + gop=CL->gop*SCORE_K; + gep=CL->gep*SCORE_K; + + /*gop2=CL->gop*10*SCORE_K;*/ + gop2=CL->gop*2*SCORE_K; + gep2=0; + + //Values Adapted from Probcons 1.1 + gop=-132; + gep=-27; + + gop2=-144; + gep2=-3; + + ungap(A->seq_al[ls[0][0]]); + ungap(A->seq_al[ls[1][0]]); + + seqI=A->seq_al[ls[0][0]]; + seqJ=A->seq_al[ls[1][0]]; + + I=strlen (seqI); J=strlen (seqJ); + pos0=aln2pos_simple ( A,-1, ns, ls); + l1=strlen (A->seq_al[ls[0][0]]); + l2=strlen (A->seq_al[ls[1][0]]); + + if ( mode==1) + { + F=forward_so_dp (A, ns, ls, pos0,I, J,gop, gep,gop2, gep2,CL); + B=backward_so_dp (A, ns, ls, pos0,I, J,gop, gep,gop2, gep2, CL); + } + else if ( mode ==2) + { + F=forward_so_dp_glocal (A, ns, ls, pos0,I, J,gop, gep,gop2, gep2,CL); + B=backward_so_dp_glocal (A, ns, ls, pos0,I, J,gop, gep,gop2, gep2, CL); + } + else if ( mode ==3) + { + F=forward_so_dp_biphasic (A, ns, ls, pos0,I, J,gop, gep,gop2, gep2,CL); + B=backward_so_dp_biphasic (A, ns, ls, pos0,I, J,gop, gep,gop2, gep2, CL); + } + if ( MAX5(F[match][l1][l2], F[ins][l1][l2], F[del][l1][l2],F[ins2][l1][l2], F[del2][l1][l2] )!=MAX5( B[match][1][1], B[ins][1][1], B[del][1][1], B[ins2][1][1], B[del2][1][1])) + { + HERE ("ERROR in subop_pair"); + fprintf ( stdout, "\nForward: %d", MAX3(F[match][l1][l2], F[ins][l1][l2], F[del][l1][l2])); + fprintf ( stdout, "\nBackWard: %d \n\n",MAX3( B[match][1][1], B[ins][1][1], B[del][1][1])); + } + + + for (opt=0,min=0, set=0, i=1; i<=I; i++) + for (j=1; j<=J; j++) + { + if ( F[match][i][j]==UNDEFINED)continue; + F[match][i][j]+=B[match][i][j]-(CL->get_dp_cost) (A, pos0, ns[0], ls[0], i-1, pos0, ns[1], ls[1],j-1,CL); + if (set==0) + {set=1; opt=F[match][i][j];min=F[match][i][j];} + opt=MAX(F[match][i][j],opt); + min=MIN(F[match][i][j],min); + } + + + s1=name_is_in_list (A->name[ls[0][0]], (CL->S)->name, (CL->S)->nseq, 100); + s2=name_is_in_list (A->name[ls[1][0]], (CL->S)->name, (CL->S)->nseq, 100); + + id=idscore_pairseq(seqI,seqJ,-12, -1, CL->M, "idmat"); + + entry=vcalloc ( CL->entry_len+1, CL->el_size); + entry[SEQ1]=s1;entry[SEQ2]=s2; + + thres=opt; + for ( n=0,i=1; i<=I; i++) + { + for (j=1; j<=J; j++) + { + score=F[0][i][j]; + nscore=((score-min))/(opt-min); + + if (score==opt) + { + n++; + entry[R1]=i;entry[R2]=j; + entry[WE]=id; + entry[CONS]=1; + + add_entry2list (entry,A->CL); + } + } + } + + vfree (entry); + free_int (pos0, -1); + free_arrayN (F, 3); + free_arrayN (B, 3); + + return A->score_aln; +} +/************************************************************************************************************************/ +/* */ +/* */ +/* GLOCAL */ +/* */ +/* */ +/************************************************************************************************************************/ +int *** forward_so_dp_glocal ( Alignment *A, int *ns, int **ls, int **pos0,int I, int J,int gop, int gep,int gop2, int gep2,Constraint_list *CL) +{ + int i,j; + int c; + int sub; + int ***M; + int match=0, del=1, ins=2; + + M=declare_arrayN (3, sizeof (int), 5, I+1, J+1); + + for ( i=0; i<=I; i++)for (j=0; j<=J; j++)for (c=0; c<5; c++)M[c][i][j]=-999999; + + M[match][0][0]=0; + + for (i=1; i<=I; i++){M[del] [i][0]=i*gep;M[umatch][i][0]=i*gep2+gop2;} + for (j=1; j<=J; j++){M[ins] [0][j]=j*gep;M[umatch][0][j]=j*gep2+gop2;} + + + for (i=1; i<=I; i++) + { + for ( j=1; j<=J; j++) + { + sub=(CL->get_dp_cost) (A, pos0, ns[0], ls[0], i-1, pos0, ns[1], ls[1],j-1,CL); + + M[match][i][j] =MAX4 (M[match][i-1][j-1],M[del][i-1][j-1], M[ins][i-1][j-1],M[umatch][i-1][j-1])+sub; + M[del][i][j] =MAX2 ((M[match][i-1][j]+gop), M[del][i-1][j])+gep; + M[ins][i][j] =MAX2 ((M[match][i][j-1]+gop), M[ins][i][j-1])+gep; + M[umatch][i][j]=MAX6 (M[match][i-1][j-1]+gop2, M[match][i][j-1]+gop2, M[match][i-1][j]+gop2,M[umatch][i-1][j-1], M[umatch][i-1][j], M[umatch][i][j-1])+gep2; + } + } + return M; +} +int *** backward_so_dp_glocal ( Alignment *A, int *ns, int **ls, int **pos0, int I, int J, int gop, int gep,int gop2, int gep2,Constraint_list *CL) +{ + int i,j; + int c; + int sub; + int ***M; + + + + M=declare_arrayN (3, sizeof (int), 5, I+2, J+2); + for ( i=I+1; i>=0; i--)for (j=J+1; j>=0; j--)for (c=0; c<5; c++)M[c][i][j]=-999999; + M[match][I+1][J+1]=0; + + for (i=I; i>0; i--){M[ins] [i][J+1]=i*gep;M[umatch] [i][J+1]=i*gep2+gop2;} + for (j=J; j>0; j--){M[del] [I+1][j]=j*gep;M[umatch] [I+1][j]=j*gep2+gop2;} + + for (i=I; i>0; i--) + { + for ( j=J; j>0; j--) + { + sub=(CL->get_dp_cost) (A, pos0, ns[0], ls[0], i-1, pos0, ns[1], ls[1],j-1,CL); + + M[match ][i][j] =MAX4 ((M[del][i+1][j+1]+gop), (M[ins][i+1][j+1]+gop), M[match][i+1][j+1], M[umatch][i+1][j+1]+gop2)+sub; + M[del ][i][j] =MAX2 (M[match][i+1][j], M[del][i+1][j])+gep; + M[ins ][i][j] =MAX2 (M[match][i][j+1], M[ins][i][j+1])+gep; + M[umatch][i][j] =MAX6 (M[match][i+1][j+1], M[match][i+1][j],M[match][i][j+1], M[umatch][i+1][j+1], M[umatch][i+1][j], M[umatch][i][j+1])+gep2; + + } + } + return M; +} + + + + +/************************************************************************************************************************/ +/* */ +/* */ +/* SIMPLE */ +/* */ +/* */ +/************************************************************************************************************************/ + +int *** forward_so_dp ( Alignment *A, int *ns, int **ls, int **pos0,int I, int J,int gop, int gep,int gop2, int gep2,Constraint_list *CL) +{ + int i,j; + int c; + int sub; + int ***M; + int lgop; + + + + M=declare_arrayN (3, sizeof (int), 5, I+1, J+1); + for ( i=0; i<=I; i++)for (j=0; j<=J; j++)for (c=0; c<3; c++)M[c][i][j]=-999999; + + M[match][0][0]=0; + for (i=1; i<=I; i++){M[del] [i][0]=i*gep;} + for (j=1; j<=J; j++){M[ins] [0][j]=j*gep;} + + + + for (i=1; i<=I; i++) + { + for ( j=1; j<=J; j++) + { + lgop=(i==I || j==J)?0:gop; + sub=(CL->get_dp_cost) (A, pos0, ns[0], ls[0], i-1, pos0, ns[1], ls[1],j-1,CL); + + M[match][i][j]=MAX3 (M[del][i-1][j-1], M[ins][i-1][j-1], M[match][i-1][j-1])+sub; + M[del][i][j] =MAX ((M[match][i-1][j]+lgop),M[del][i-1][j])+gep; + M[ins][i][j] =MAX ((M[match][i][j-1]+lgop), M[ins][i][j-1])+gep; + } + + } + + return M; + } +int *** backward_so_dp ( Alignment *A, int *ns, int **ls, int **pos0, int I, int J, int gop, int gep,int gop2, int gep2,Constraint_list *CL) +{ + int i,j, a, b; + + + int ***M, ***T; + + + for (a=0; a<2; a++) + for (b=0; bseq_al[ls[a][b]]); + invert_string2((CL->S)->seq[A->order[ls[a][b]][0]]); + } + T=forward_so_dp(A,ns,ls,pos0, I, J, gop, gep, gop2, gep2, CL); + for (a=0; a<2; a++) + for (b=0; bseq_al[ls[a][b]]); + invert_string2((CL->S)->seq[A->order[ls[a][b]][0]]); + } + + M=declare_arrayN (3, sizeof (int), 5, I+2, J+2); + + + for (i=0; i<=I; i++) + for (j=0; j<=J; j++) + { + M[match][i+1][j+1]=T[match][I-i][J-j]; + M[ins][i+1][j+1]=T[ins][I-i][J-j]; + M[del][i+1][j+1]=T[del][I-i][J-j]; + } + return M; +} + +/************************************************************************************************************************/ +/* */ +/* */ +/* BI-PHASIC */ +/* */ +/* */ +/************************************************************************************************************************/ +int biphasic_pair_wise ( Alignment *A, int *ns, int **ls, Constraint_list *CL) +{ + int i,j,a,b; + int c; + int sub; + int ***m, ***t; + int M1, D1, D2, I1, I2, LEN; + int I, J; + int n=1; + char **al, **aln, *char_buf; + int gop1, gop2, gep1, gep2; + int **pos0; + int score, trace, ntrace; + M1=n++; D1=n++; D2=n++; I1=n++, I2=n++; + + I=strlen (A->seq_al[ls[0][0]]); + J=strlen (A->seq_al[ls[1][0]]); + m=declare_arrayN (3, sizeof (int),n, I+1, J+1); + t=declare_arrayN (3, sizeof (int),n, I+1, J+1); + pos0=aln2pos_simple ( A,-1, ns, ls); + al=declare_char (2, I+J+1); + for ( i=0; i<=I; i++)for (j=0; j<=J; j++)for (c=0; cgop*SCORE_K*2; + gep1=CL->gep*SCORE_K/2; + + gop2=CL->gop*SCORE_K/2; + gep2=CL->gep*SCORE_K*2; + + m[M1][0][0]=0; + for (i=1; i<=I; i++){m[I1][i][0]=gep1*i;} + for (j=1; j<=J; j++){m[D1][0][j]=gep1*j;} + + for (i=1; i<=I; i++){m[I2] [i][0]=gep2*i;} + for (j=1; j<=J; j++){m[D2] [0][j]=gep2*j;} + + for (i=1; i<=I; i++) + { + for ( j=1; j<=J; j++) + { + sub=(CL->get_dp_cost) (A, pos0, ns[0], ls[0], i-1, pos0, ns[1], ls[1],j-1,CL); + m[M1][i][j]=max_int (&t[M1][i][j],D1,m[D1][i-1][j-1],I1,m[I1][i-1][j-1], M1, m[M1][i-1][j-1],D2,m[D2][i-1][j-1],I2,m[I2][i-1][j-1], -1)+sub; + + m[D1][i][j]=max_int (&t[D1][i][j],M1,(m[M1][i][j-1]+gop1),D1,m[D1][i][j-1], -1)+gep1; + m[I1][i][j]=max_int (&t[I1][i][j],M1,(m[M1][i-1][j]+gop1),I1,m[I1][i-1][j], -1)+gep1; + + m[D2][i][j]=max_int (&t[D2][i][j],M1,(m[M1][i][j-1]+gop2),D2,m[D2][i][j-1], -1)+gep2; + m[I2][i][j]=max_int (&t[I2][i][j],M1,(m[M1][i-1][j]+gop2),I2,m[I2][i-1][j], -1)+gep2; + } + } + + score=max_int (&trace,M1,m[M1][I][J],D1,m[D1][I][J],I1, m[I1][I][J],D2,m[D2][I][J],I2,m[I2][I][J], -1); + LEN=0;i=I;j=J; + + + trace=t[trace][i][j]; + while (!(i==0 &&j==0)) + { + + ntrace=t[trace][i][j]; + if (i==0) + { + al[0][LEN]=0; + al[1][LEN]=1; + j--; + LEN++; + } + else if ( j==0) + { + al[0][LEN]=1; + al[1][LEN]=0; + i--; + LEN++; + } + else if ( trace==M1) + { + al[0][LEN]=1; + al[1][LEN]=1; + i--; j--; + LEN++; + } + + else if ( trace==D1 || trace==D2) + { + al[0][LEN]=0; + al[1][LEN]=1; + j--; + LEN++; + } + else if ( trace == I1 || trace==I2) + { + al[0][LEN]=1; + al[1][LEN]=0; + i--; + LEN++; + } + trace=ntrace; + + } + + invert_list_char ( al[0], LEN); + invert_list_char ( al[1], LEN); + if ( A->declared_len<=LEN)A=realloc_aln2 ( A,A->max_n_seq, 2*LEN); + + aln=A->seq_al; + char_buf= vcalloc (LEN+1, sizeof (char)); + for ( c=0; c< 2; c++) + { + for ( a=0; a< ns[c]; a++) + { + int ch=0; + for ( b=0; b< LEN; b++) + { + if (al[c][b]==1) + char_buf[b]=aln[ls[c][a]][ch++]; + else + char_buf[b]='-'; + } + char_buf[b]='\0'; + sprintf (aln[ls[c][a]],"%s", char_buf); + } + } + + + A->len_aln=LEN; + A->nseq=ns[0]+ns[1]; + free_arrayN((void *)m, 3); + free_arrayN((void *)t, 3); + vfree (char_buf); + free_char (al, -1); + return score; + } +int *** forward_so_dp_biphasic ( Alignment *A, int *ns, int **ls, int **pos0,int I, int J,int gop1, int gep1,int gop2, int gep2,Constraint_list *CL) +{ + int i,j; + int c; + int sub; + int ***M; + int match=0, del=1, ins=2; + int lgop1, lgop2, lgep1, lgep2; + + M=declare_arrayN (3, sizeof (int), 5, I+1, J+1); + + for ( i=0; i<=I; i++)for (j=0; j<=J; j++)for (c=0; c<5; c++)M[c][i][j]=-999999; + + M[match][0][0]=0; + + for (i=1; i<=I; i++){M[del] [i][0]=gep1*i+gop1;} + for (j=1; j<=J; j++){M[ins] [0][j]=gep1*j+gop1;} + + for (i=1; i<=I; i++){M[del2] [i][0]=gep2*i+gop2;} + for (j=1; j<=J; j++){M[ins2] [0][j]=gep2*j+gop2;} + + for (i=1; i<=I; i++) + { + for ( j=1; j<=J; j++) + { + lgop1=(i==I || j==J)?gop1:gop1; + lgop2=(i==I || j==J)?gop2:gop2; + lgep1=gep1; + lgep2=gep2; + + sub=(CL->get_dp_cost) (A, pos0, ns[0], ls[0], i-1, pos0, ns[1], ls[1],j-1,CL); + M[match][i][j]=MAX5 (M[del][i-1][j-1], M[ins][i-1][j-1], M[match][i-1][j-1], M[ins2][i-1][j-1], M[del2][i-1][j-1])+sub; + + M[del ][i][j] =MAX2 ((M[match][i-1][j]+lgop1), M[del ][i-1][j])+lgep1; + M[del2][i][j] =MAX2 ((M[match][i-1][j]+lgop2), M[del2][i-1][j])+lgep2; + + M[ins ][i][j] =MAX2 ((M[match][i][j-1]+lgop1), M[ins ][i][j-1] )+lgep1; + M[ins2][i][j] =MAX2 ((M[match][i][j-1]+lgop2), M[ins2][i][j-1] )+lgep2; + } + } + return M; + } +int *** backward_so_dp_biphasic ( Alignment *A, int *ns, int **ls, int **pos0, int I, int J, int gop, int gep,int gop2, int gep2,Constraint_list *CL) +{ + int i,j, a, b; + + + int ***M, ***T; + + + for (a=0; a<2; a++) + for (b=0; bseq_al[ls[a][b]]); + invert_string2((CL->S)->seq[A->order[ls[a][b]][0]]); + } + T=forward_so_dp_biphasic(A,ns,ls,pos0, I, J, gop, gep, gop2, gep2, CL); + for (a=0; a<2; a++) + for (b=0; bseq_al[ls[a][b]]); + invert_string2((CL->S)->seq[A->order[ls[a][b]][0]]); + } + + M=declare_arrayN (3, sizeof (int), 5, I+2, J+2); + + + for (i=0; i<=I; i++) + for (j=0; j<=J; j++) + { + M[match][i+1][j+1]=T[match][I-i][J-j]; + M[ins][i+1][j+1]=T[ins][I-i][J-j]; + M[del][i+1][j+1]=T[del][I-i][J-j]; + M[ins2][i+1][j+1]=T[ins2][I-i][J-j]; + M[del2][i+1][j+1]=T[del2][I-i][J-j]; + } + free_arrayN(T,3); + return M; +} + + +int get_tot_prob (Alignment *A1,Alignment *A2, int *ns, int **ls, int nstates, float **matchProb, float **insProb, float *TmatchProb, float ***TinsProb, Constraint_list *CL); + +float * forward_proba_pair_wise ( char *seq1, char *seq2, int NumMatrixTypes, int NumInsertStates, float **transMat, float *initialDistribution,float *TmatchProb, float ***TinsProb, float **transProb); +float * backward_proba_pair_wise ( char *seq1, char *seq2, int NumMatrixTypes, int NumInsertStates, float **transMat, float *initialDistribution,float *TmatchProb, float ***TinsProb,float **transProb); +float ComputeTotalProbability (int seq1Length, int seq2Length,int NumMatrixTypes, int NumInsertStates,float *forward, float *backward) ; +int ProbabilisticModel (int NumMatrixTypes, int NumInsertStates,float *initDistribMat,float *emitSingle, float** emitPairs, float *gapOpen, float *gapExtend, float **transMat, float *initialDistribution, float **matchProb, float **insProb, float **transProb); + +Constraint_list *ProbaMatrix2CL (Alignment *A, int *ns, int **ls, int NumMatrixTypes, int NumInsertStates, float *forward, float *backward, float thr, Constraint_list *CL); + + +void free_proba_pair_wise () +{ + proba_pair_wise (NULL, NULL, NULL, NULL); +} +int proba_pair_wise ( Alignment *A, int *ns, int **ls, Constraint_list *CL) +{ + static int NumMatrixTypes; + static int NumInsertStates; + static float **transMat, **insProb, **matchProb, *initialDistribution, **transProb, **emitPairs, *emitSingle, ***TinsProb, *TmatchProb; + static int TinsProb_ml, TmatchProb_ml; + int i, j,I, J; + float *F, *B; + + int l; + float thr=0.01;//ProbCons Default + char *alphabet; + + + + //Free all the memory + if (A==NULL) + { + free_float (transMat, -1);transMat=NULL; + free_float (insProb, -1);insProb=NULL; + free_float (matchProb, -1);matchProb=NULL; + vfree (initialDistribution); initialDistribution=NULL; + free_float (transProb, -1);transProb=NULL; + free_float (emitPairs, -1);emitPairs=NULL; + vfree (emitSingle);emitSingle=NULL; + + + free_arrayN((void***)TinsProb, 3);TinsProb=NULL; + vfree (TmatchProb);TmatchProb=NULL; + TinsProb_ml=0; TmatchProb_ml=0; + + forward_proba_pair_wise (NULL, NULL, 0,0,NULL,NULL,NULL,NULL,NULL); + backward_proba_pair_wise (NULL, NULL, 0,0,NULL,NULL,NULL,NULL,NULL); + ProbaMatrix2CL(NULL, NULL, NULL, 0, 0, NULL, NULL, 0, NULL); + return 0; + } + + if (!transMat && (strm (retrieve_seq_type(), "DNA"))) + { + static float **p; + static float *s; + NumInsertStates=1; + NumMatrixTypes=3; + if (!p) + { + int l,a,b; + l=strlen (DNAalphabetDefault); + p=declare_float (l,l); + s=vcalloc (l, sizeof (float)); + for (a=0; amethod_matrix, DNAalphabetDefault,p,s); + alphabet=RNAalphabetDefault; + emitPairs=declare_float (256, 256); + emitSingle=vcalloc (256, sizeof (float)); + for (i=0; i<256; i++) + { + emitSingle[i]=1e-5; + for (j=0; j<256; j++) + emitPairs[i][j]=1e-10; + } + l=strlen (alphabet); + + for (i=0; imethod_matrix, RNAalphabetDefault,p,s); + alphabet=RNAalphabetDefault; + emitPairs=declare_float (256, 256); + emitSingle=vcalloc (256, sizeof (float)); + for (i=0; i<256; i++) + { + emitSingle[i]=1e-5; + for (j=0; j<256; j++) + emitPairs[i][j]=1e-10; + } + l=strlen (alphabet); + + for (i=0; imethod_matrix, alphabetDefault,p,s); + alphabet=alphabetDefault; + emitPairs=declare_float (256, 256); + emitSingle=vcalloc (256, sizeof (float)); + for (i=0; i<256; i++) + { + //emitSingle[i]=1e-5; + emitSingle[i]=1; + for (j=0; j<256; j++) + //emitPairs[i][j]=1e-10; + emitPairs[i][j]=1; + + } + l=strlen (alphabet); + + for (i=0; iseq_al[ls[0][0]]); + J=strlen (A->seq_al[ls[1][0]]); + //TmatchProb=vcalloc ((I+1)*(J+1), sizeof (float)); + //TinsProb=declare_arrayN (3, sizeof (float),2,NumMatrixTypes,MAX(I,J)+1); + + l=(I+1)*(J+1); + if (l>TmatchProb_ml) + { + TmatchProb_ml=l; + if (TmatchProb)TmatchProb=vrealloc(TmatchProb,TmatchProb_ml*sizeof (float)); + else TmatchProb=vcalloc ( l, sizeof (float)); + } + l=MAX(I,J)+1; + if ( l>TinsProb_ml) + { + TinsProb_ml=l; + if (TinsProb)free_arrayN (TinsProb, 3); + TinsProb=declare_arrayN (3, sizeof (float),2,NumMatrixTypes,TinsProb_ml); + } + + get_tot_prob (A,A, ns,ls,NumMatrixTypes, matchProb, insProb,TmatchProb,TinsProb, CL); + + F=forward_proba_pair_wise (A->seq_al[ls[0][0]], A->seq_al[ls[1][0]], NumMatrixTypes,NumInsertStates,transMat, initialDistribution,TmatchProb,TinsProb, transProb); + B=backward_proba_pair_wise (A->seq_al[ls[0][0]], A->seq_al[ls[1][0]], NumMatrixTypes,NumInsertStates,transMat, initialDistribution,TmatchProb,TinsProb, transProb); + A->CL=ProbaMatrix2CL(A,ns, ls,NumMatrixTypes,NumInsertStates, F, B, thr,CL); + + //free_proba_pair_wise(); + return 1; + } + +int get_tot_prob (Alignment *A1,Alignment *A2, int *ns, int **ls, int nstates, float **matchProb, float **insProb, float *TmatchProb, float ***TinsProb, Constraint_list *CL) +{ + int i, j, a, b, c,d, k, n,n1,n2, ij; + int c1, c2; + int I, J; + int ***VA1,***VA2, *observed, index; + char *ss1=NULL; + char *ss2=NULL; + int uss=0; + + //Pre-computation of the pairwise scores in order to use potential profiles + //The profiles are vectorized AND Compressed so that the actual alphabet size (proteins/DNA) does not need to be considered + + + if (ns[0]==1 && ns[1]==1 ) + { + int s1, s2; + int *nns, **nls; + Alignment *NA1, *NA2; + char *sst1; + char *sst2; + + + nns=vcalloc ( 2, sizeof (int)); + nls=vcalloc (2, sizeof (int*)); + + s1=A1->order[ls[0][0]][0]; + s2=A2->order[ls[1][0]][0]; + NA1=seq2R_template_profile (CL->S,s1); + NA2=seq2R_template_profile (CL->S,s2); + + sst1=seq2T_template_string((CL->S),s1); + sst2=seq2T_template_string((CL->S),s2); + + if (NA1 || NA2) + { + if (NA1) + { + nns[0]=NA1->nseq; + nls[0]=vcalloc (NA1->nseq, sizeof (int)); + for (a=0; anseq; a++) + nls[0][a]=a; + NA1->seq_al[NA1->nseq]=sst1; + sprintf (NA1->name[NA1->nseq], "sst1"); + } + else + { + NA1=A1; + nns[0]=ns[0]; + nls[0]=vcalloc (ns[0], sizeof (int)); + for (a=0; anseq; + nls[1]=vcalloc (NA2->nseq, sizeof (int)); + for (a=0; anseq; a++) + nls[1][a]=a; + NA2->seq_al[NA2->nseq]=sst2; + sprintf (NA2->name[NA2->nseq], "sst2"); + } + else + { + NA2=A2; + nns[1]=ns[1]; + nls[1]=vcalloc (ns[1], sizeof (int)); + for (a=0; aname[A1->nseq], "sst1"))ss1=A1->seq_al[A1->nseq]; + if (strm (A2->name[A2->nseq], "sst2"))ss2=A2->seq_al[A2->nseq]; + uss=(ss1&&ss2)?1:0; + } + else + uss=0; + + I=strlen (A1->seq_al[ls[0][0]]); + J=strlen (A2->seq_al[ls[1][0]]); + + + + //get Ins for I + for (i=1; i<=I; i++) + { + for (k=0; kseq_al[ls[0][b]][i-1]; + if (c1!='-') + { + TinsProb[0][k][i]+=insProb[c1][k]; + + n++; + } + } + if (n)TinsProb[0][k][i]/=n; + } + } + //Get Ins for J + for (j=1; j<=J; j++) + { + for (k=0; kseq_al[ls[1][b]][j-1]; + if (c2!='-') + { + TinsProb[1][k][j]+=insProb[c2][k]; + + n++; + } + } + if (n)TinsProb[1][k][j]/=n; + } + } + + observed=vcalloc ( 26, sizeof (int)); + VA1=declare_arrayN (3, sizeof (int),2,26,I); + for (i=0; iseq_al[ls[0][b]][i]); + if ( c1=='-' || c1=='.' || c1=='~')continue; + c1-='a'; + + if (!(in=observed[c1])){in=observed[c1]=++index;} + + VA1[0][in-1][i]=c1; + VA1[1][in-1][i]++; + } + + VA1[0][index][i]=-1; + for (b=0; b<26; b++)observed[b]=0; + } + + VA2=declare_arrayN (3, sizeof (int),2,26,J); + for (i=0; iseq_al[ls[1][b]][i]); + if ( c1=='-')continue; + c1-='a'; + + if (!(in=observed[c1])){in=observed[c1]=++index;} + + VA2[0][in-1][i]=c1; + VA2[1][in-1][i]++; + } + VA2[0][index][i]=-1; + for (b=0; b<26; b++)observed[b]=0; + } + vfree (observed); + + for ( ij=0,i=0; i<=I; i++) + { + for ( j=0; j<=J ; j++, ij++) + { + n=0; + TmatchProb[ij]=0; + if (i==0 || j==0); + else + { + float sfac; + if (!uss)sfac=1; + else if (ss1[i-1]!=ss2[j-1])sfac=1; + else if (ss1[i-1]==ss2[j-1])sfac=1; + else sfac=1; + + + c=0; + while (VA1[0][c][i-1]!=-1) + { + c1=VA1[0][c][i-1]+'a'; + n1=VA1[1][c][i-1]; + d=0; + while (VA2[0][d][j-1]!=-1) + { + c2=VA2[0][d][j-1]+'a'; + n2=VA2[1][d][j-1]; + TmatchProb[ij]+=matchProb[c1][c2]*(double)n1*(double)n2*sfac; + n+=n1*n2; + d++; + } + c++; + } + } + if (n)TmatchProb[ij]/=n; + } + } + + free_arrayN ((void **)VA1, 3); + free_arrayN ((void **)VA2, 3); + return 1; +} + + + + +Constraint_list *ProbaMatrix2CL (Alignment *A, int *ns, int **ls, int NumMatrixTypes, int NumInsertStates, float *forward, float *backward, float thr, Constraint_list *CL) +{ + float totalProb; + int ij, i, j,k, I, J, s1, s2; + static int *entry; + static int **list; + static int list_max; + int sim; + int list_size; + int list_n; + int old_n=0; + double v; + static float F=4; //potential number of full suboptimal alignmnents incorporated in the library + static int tot_old, tot_new; + + if (!A) + { + free_int (list, -1);list=NULL; + list_max=0; + + vfree(entry); entry=NULL; + return NULL; + } + + I=strlen (A->seq_al[ls[0][0]]); + J=strlen (A->seq_al[ls[1][0]]); + s1=name_is_in_list (A->name[ls[0][0]], (CL->S)->name, (CL->S)->nseq, 100); + s2=name_is_in_list (A->name[ls[1][0]], (CL->S)->name, (CL->S)->nseq, 100); + + list_size=I*J; + + if ( list_maxthr)//Conservative reduction of the list size to speed up the sorting + { + list[list_n][0]=i; + list[list_n][1]=j; + list[list_n][2]=(int)((float)v*(float)NORM_F); + list_n++; + } + if (v>0.01)old_n++; + } + } + + sort_int_inv (list, 3, 2, 0, list_n-1); + if (!entry)entry=vcalloc ( CL->entry_len+1, CL->el_size); + + list_n=MIN(list_n,(F*MIN(I,J))); + for (i=0; iCL); + } + tot_new+=list_n; + tot_old+=old_n; + // HERE ("LIB_SIZE NEW: %d (new) %d (old) [%.2f]", list_n, old_n, (float)tot_new/(float)tot_old); + return A->CL; +} + + + +float ComputeTotalProbability (int seq1Length, int seq2Length,int NumMatrixTypes, int NumInsertStates,float *forward, float *backward) +{ + + float totalForwardProb = LOG_ZERO; + float totalBackwardProb = LOG_ZERO; + int k; + + for (k = 0; k < NumMatrixTypes; k++) + { + LOG_PLUS_EQUALS (&totalForwardProb,forward[k + NumMatrixTypes * ((seq1Length+1) * (seq2Length+1) - 1)] + backward[k + NumMatrixTypes * ((seq1Length+1) * (seq2Length+1) - 1)]); + } + + totalBackwardProb =forward[0 + NumMatrixTypes * (1 * (seq2Length+1) + 1)] +backward[0 + NumMatrixTypes * (1 * (seq2Length+1) + 1)]; + + for (k = 0; k < NumInsertStates; k++) + { + LOG_PLUS_EQUALS (&totalBackwardProb,forward[2*k+1 + NumMatrixTypes * (1 * (seq2Length+1) + 0)] +backward[2*k+1 + NumMatrixTypes * (1 * (seq2Length+1) + 0)]); + LOG_PLUS_EQUALS (&totalBackwardProb,forward[2*k+2 + NumMatrixTypes * (0 * (seq2Length+1) + 1)] +backward[2*k+2 + NumMatrixTypes * (0 * (seq2Length+1) + 1)]); + } + return (totalForwardProb + totalBackwardProb) / 2; + } + + +float * backward_proba_pair_wise ( char *seq1, char *seq2, int NumMatrixTypes, int NumInsertStates, float **transMat, float *initialDistribution,float *matchProb, float ***insProb, float **transProb) +{ + static float *backward; + static int max_l; + + + int k, i, j,ij, i1j1, i1j, ij1,a, l, seq1Length, seq2Length, m; + char c1, c2; + char *iter1, *iter2; + + if (!seq1) + { + vfree (backward); + backward=NULL; max_l=0; + return NULL; + } + + iter1=seq1-1; + iter2=seq2-1; + seq1Length=strlen (seq1); + seq2Length=strlen (seq2); + l=(seq1Length+1)*(seq2Length+1)*NumMatrixTypes; + + if (!backward) + { + backward=vcalloc (l, sizeof (float)); + max_l=l; + } + else if (max_l= 0; i--) + { + c1 = (i == seq1Length) ? '~' : (unsigned char) iter1[i+1]; + for (j = seq2Length; j >= 0; j--) + { + c2 = (j == seq2Length) ? '~' : (unsigned char) iter2[j+1]; + + if (i < seq1Length && j < seq2Length) + { + m=((i+1)*(seq2Length+1))+j+1;//The backward and the forward are offset by 1 + float ProbXY = backward[0 + i1j1] + matchProb[m]; + + + for (k = 0; k < NumMatrixTypes; k++) + { + LOG_PLUS_EQUALS (&backward[k + ij], ProbXY + transProb[k][0]); + } + } + if (i < seq1Length) + { + for (k = 0; k < NumInsertStates; k++) + { + LOG_PLUS_EQUALS (&backward[0 + ij], backward[2*k+1 + i1j] + insProb[0][k][i+1] + transProb[0][2*k+1]); + LOG_PLUS_EQUALS (&backward[2*k+1 + ij], backward[2*k+1 + i1j] + insProb[0][k][i+1] + transProb[2*k+1][2*k+1]); + } + } + if (j < seq2Length) + { + for (k = 0; k < NumInsertStates; k++) + { + //+1 because the backward and the forward are offset by 1 + LOG_PLUS_EQUALS (&backward[0 + ij], backward[2*k+2 + ij1] + insProb[1][k][j+1] + transProb[0][2*k+2]); + LOG_PLUS_EQUALS (&backward[2*k+2 + ij], backward[2*k+2 + ij1] + insProb[1][k][j+1] + transProb[2*k+2][2*k+2]); + } + } + + ij -= NumMatrixTypes; + i1j -= NumMatrixTypes; + ij1 -= NumMatrixTypes; + i1j1 -= NumMatrixTypes; + } + } + + return backward; +} +float * forward_proba_pair_wise ( char *seq1, char *seq2, int NumMatrixTypes, int NumInsertStates, float **transMat, float *initialDistribution,float *matchProb, float ***insProb, float **transProb) +{ + static float *forward; + static int max_l; + int k, i, j,ij, i1j1, i1j, ij1, seq1Length, seq2Length, m; + char *iter1, *iter2; + int l,a; + + if (!seq1) + { + vfree (forward); + forward=NULL; max_l=0; + return NULL; + } + iter1=seq1-1; + iter2=seq2-1; + seq1Length=strlen (seq1); + seq2Length=strlen (seq2); + l=(seq1Length+1)*(seq2Length+1)*NumMatrixTypes; + + if (!forward) + { + forward=vcalloc (l, sizeof (float)); + max_l=l; + } + else if (max_l 1 || j > 1) + { + if (i > 0 && j > 0) + { + //Sum over all possible alignments + forward[0 + ij] = forward[0 + i1j1] + transProb[0][0]; + for (k = 1; k < NumMatrixTypes; k++) + { + LOG_PLUS_EQUALS (&forward[0 + ij], forward[k + i1j1] + transProb[k][0]); + } + forward[0 + ij] += matchProb[m]; + } + if ( i > 0) + { + for (k = 0; k < NumInsertStates; k++) + { + forward[2*k+1 + ij] = insProb[0][k][i] + LOG_ADD (forward[0 + i1j] + transProb[0][2*k+1],forward[2*k+1 + i1j] + transProb[2*k+1][2*k+1]); + } + } + if (j > 0) + { + for (k = 0; k < NumInsertStates; k++) + { + forward[2*k+2 + ij] = insProb[1][k][j] +LOG_ADD (forward[0 + ij1] + transProb[0][2*k+2],forward[2*k+2 + ij1] + transProb[2*k+2][2*k+2]); + } + } + } + + ij += NumMatrixTypes; + i1j += NumMatrixTypes; + ij1 += NumMatrixTypes; + i1j1 += NumMatrixTypes; + } + + } + return forward; + } +int ProbabilisticModel (int NumMatrixTypes, int NumInsertStates,float *initDistribMat,float *emitSingle, float **emitPairs, float *gapOpen, float *gapExtend, float **transMat, float *initialDistribution, float **matchProb, float **insProb, float **transProb) +{ + + + // build transition matrix + int i, j; + + + transMat[0][0] = 1; + for (i = 0; i < NumInsertStates; i++) + { + transMat[0][2*i+1] = gapOpen[2*i]; + transMat[0][2*i+2] = gapOpen[2*i+1]; + transMat[0][0] -= (gapOpen[2*i] + gapOpen[2*i+1]); + + transMat[2*i+1][2*i+1] = gapExtend[2*i]; + transMat[2*i+2][2*i+2] = gapExtend[2*i+1]; + transMat[2*i+1][2*i+2] = 0; + transMat[2*i+2][2*i+1] = 0; + transMat[2*i+1][0] = 1 - gapExtend[2*i]; + transMat[2*i+2][0] = 1 - gapExtend[2*i+1]; + } + + + + // create initial and transition probability matrices + for (i = 0; i < NumMatrixTypes; i++){ + initialDistribution[i] = (float)log ((float)initDistribMat[i]); + for (j = 0; j < NumMatrixTypes; j++) + transProb[i][j] = (float)log ((float)transMat[i][j]); + } + + // create insertion and match probability matrices + for (i = 0; i < 256; i++) + { + for (j = 0; j < NumMatrixTypes; j++) + { + insProb[i][j] = (float)log((float)emitSingle[i]); + } + for (j = 0; j < 256; j++) + { + matchProb[i][j] = (float)log((float)emitPairs[i][j]); + } + } + return 1; +} + + +int viterbi_pair_wise ( Alignment *A, int *ns, int **ls, Constraint_list *CL) +{ + int C1,c1, C2,c2; + char *alphabet, *char_buf; + char **al, **aln; + int seq1Length, seq2Length, I, J; + int i, j,ij, i1j1, i1j, ij1, k, a, b,l, LEN, r, c, m, state; + int NumMatrixTypes=5; + int NumInsertStates=2; + int *traceback; + float bestProb; + static float **transMat, **insProb, **matchProb, *initialDistribution, **transProb, **emitPairs, *emitSingle, *TmatchProb, ***TinsProb; + float *viterbi; + + ungap_sub_aln (A, ns[0],ls[0]); + ungap_sub_aln (A, ns[1],ls[1]); + + seq1Length=I=strlen (A->seq_al[ls[0][0]]); + seq2Length=J=strlen (A->seq_al[ls[1][0]]); + + if (!transMat) + { + alphabet=alphabetDefault; + emitPairs=declare_float (256, 256); + emitSingle=vcalloc (256, sizeof (float)); + for (i=0; i<256; i++) + { + emitSingle[i]=1e-5; + for (j=0; j<256; j++) + emitPairs[i][j]=1e-10; + } + l=strlen (alphabet); + + for (i=0; i 0 && j > 0) + { + for (k = 0; k < NumMatrixTypes; k++) + { + float newVal = viterbi[k + i1j1] + transProb[k][0] + TmatchProb[m]; + if (viterbi[0 + ij] < newVal) + { + viterbi[0 + ij] = newVal; + traceback[0 + ij] = k; + } + } + } + if (i > 0) + { + for (k = 0; k < NumInsertStates; k++) + { + float valFromMatch = TinsProb[0][k][i] + viterbi[0 + i1j] + transProb[0][2*k+1]; + float valFromIns = TinsProb[0][k][i] + viterbi[2*k+1 + i1j] + transProb[2*k+1][2*k+1]; + if (valFromMatch >= valFromIns){ + viterbi[2*k+1 + ij] = valFromMatch; + traceback[2*k+1 + ij] = 0; + } + else { + viterbi[2*k+1 + ij] = valFromIns; + traceback[2*k+1 + ij] = 2*k+1; + } + } + } + if (j > 0) + { + for (k = 0; k < NumInsertStates; k++){ + float valFromMatch = TinsProb[1][k][j] + viterbi[0 + ij1] + transProb[0][2*k+2]; + float valFromIns = TinsProb[1][k][j] + viterbi[2*k+2 + ij1] + transProb[2*k+2][2*k+2]; + if (valFromMatch >= valFromIns){ + viterbi[2*k+2 + ij] = valFromMatch; + traceback[2*k+2 + ij] = 0; + } + else + { + viterbi[2*k+2 + ij] = valFromIns; + traceback[2*k+2 + ij] = 2*k+2; + } + } + } + + ij += NumMatrixTypes; + i1j += NumMatrixTypes; + ij1 += NumMatrixTypes; + i1j1 += NumMatrixTypes; + } + } + + // figure out best terminating cell + bestProb = LOG_ZERO; + state = -1; + for (k = 0; k < NumMatrixTypes; k++) + { + float thisProb = viterbi[k + NumMatrixTypes * ((seq1Length+1)*(seq2Length+1) - 1)] + initialDistribution[k]; + if (bestProb < thisProb) + { + bestProb = thisProb; + state = k; + } + } + + + + // compute traceback + al=declare_char(2,seq1Length+seq2Length); + LEN=0; + r = seq1Length, c = seq2Length; + while (r != 0 || c != 0) + { + int newState = traceback[state + NumMatrixTypes * (r * (seq2Length+1) + c)]; + + if (state == 0){ c--; r--; al[0][LEN]=1;al[1][LEN]=1;} + else if (state % 2 == 1) {r--; al[0][LEN]=1;al[1][LEN]=0;} + else { c--; al[0][LEN]=0;al[1][LEN]=1;} + LEN++; + state = newState; + } + + + invert_list_char ( al[0], LEN); + invert_list_char ( al[1], LEN); + if ( A->declared_len<=LEN)A=realloc_aln2 ( A,A->max_n_seq, 2*LEN); + aln=A->seq_al; + char_buf= vcalloc (LEN+1, sizeof (char)); + for ( c=0; c< 2; c++) + { + for ( a=0; a< ns[c]; a++) + { + int ch=0; + for ( b=0; b< LEN; b++) + { + if (al[c][b]==1) + char_buf[b]=aln[ls[c][a]][ch++]; + else + char_buf[b]='-'; + } + char_buf[b]='\0'; + sprintf (aln[ls[c][a]],"%s", char_buf); + } + } + + + A->len_aln=LEN; + A->nseq=ns[0]+ns[1]; + vfree (char_buf); + free_char (al, -1); + + + + + + return (int)(bestProb*(float)1000); +} + +float ** get_emitPairs (char *mat, char *alp, float **p, float *s) + { + static char *rmat; + float k=0, t=0; + int a, b, c, l; + int **M; + + if (!rmat)rmat=vcalloc (100, sizeof (char)); + + if (!mat || !mat[0] || strm (mat, "default"))return p; + else if (strm (rmat, mat))return p; + + sprintf (rmat,"%s", mat); + + M=read_matrice (mat); + l=strlen (alp); + + k=log (2)/2; + for (a=0; a +#include +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" +#include "dp_lib_header.h" +/*********************************************************************************************/ +/* */ +/* MULTI_THREAD */ +/* */ +/*********************************************************************************************/ +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/util_graph_maln.c b/binaries/src/tcoffee/t_coffee_source/util_graph_maln.c new file mode 100644 index 0000000..03ef023 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/util_graph_maln.c @@ -0,0 +1,539 @@ +#include +#include +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" +#include "dp_lib_header.h" +int check_link (CL_node ***G, int S1, int r1, int s2, int r2); +void light_nodes (CL_node *A, int va, CL_node*B, int vb, CL_node*C,int vc, char *s); +void print_graph (CL_node *G, Sequence *S); +Sequence *Seq; +CL_node *Start; +static int cycle; + + + +Alignment * add_constraint2aln ( Alignment *A, int s1, int r1, int s2, int r2) +{ + /*Note sCL_node ***G;1 and r1 must be numbered from 0 to n-1*/ + CL_node ***G; + + + G=aln2graph(A); + G=add_constraint2graph_aln (G,s1,r1, s2, r2); + A=graph2aln (A,G[0][0],aln2seq(A)); + vfree_graph (G[0][0]); + return A; +} +Alignment * graph_aln (Alignment *A, Constraint_list *iCL, Sequence *S) +{ + CL_node ***G; + int a,start; + CLIST_TYPE *entry=NULL; + Constraint_list *CL; + Seq=S; + HERE ("Function graph_aln is deprecated"); + return A; + +} + +void print_graph (CL_node *G, Sequence *S) +{ + Alignment *A=NULL; + + if (S==NULL) S=Seq; + A=seq2aln (Seq, A, 1); + A=graph2aln (A,G, Seq); + print_aln (A); +} + +Alignment* graph2aln (Alignment *A, CL_node *G, Sequence *S) +{ + int s, l, a; + CL_node *Gi; + + /*Rewind G*/ + while ( G->p)G=G->p; + while ( G->l)G=G->l; + + l=s=0; + Gi=G; + while (Gi){Gi=Gi->r;l++;} + Gi=G; + while (Gi){Gi=Gi->c;s++;} + + A=realloc_alignment (A, l+1); + + + l=0; + while (G) + { + Gi=G; + s=0; + while ( G!=NULL) + { + + if ( G->res==-1)A->seq_al[s][l]='-'; + else if ( G->res==-2)A->seq_al[s][l]='*'; + else if ( G->res==-3)A->seq_al[s][l]='#'; + else if (G->res>=0)A->seq_al[s][l]=S->seq[G->seq][G->res]; + + G=G->c; + s++; + } + G=Gi->r; + l++; + } + + + + for ( a=0;aseq_al[a][l]='\0'; + A->len_aln=strlen (A->seq_al[0]); + A->nseq=s; + + + return A; +} +CL_node ***aln2graph (Alignment *A) +{ + int a=0, b; + static CL_node ***galn; + CL_node *N, *iN, *pN; + int res; + + if ( !galn) + { + galn=calloc ( A->nseq, sizeof (CL_node**)); + for ( a=0; a< A->nseq; a++) + { + galn[a]=calloc (A->len_aln, sizeof (CL_node*)); + } + } + pN=iN=NULL; + N=declare_cl_nodes(-1, a); + + + for ( a=0; anseq; a++) + { + iN=N; + for (res=A->order[a][1], b=0; blen_aln; b++) + { + if (blen_aln-1) + { + N->r=declare_cl_nodes(-1, a); + (N->r)->l=N; + } + if ( pN) + { + N->p=pN; + pN->c=N; + } + + N->seq=A->order[a][0]; + N->res=(is_gap(A->seq_al[a][b]))?-1:res++; + + if (N->res!=-1)galn[a][res-1]=N; + if ( pN) + { + N->p=pN; + pN->c=N; + pN=pN->r; + } + N=N->r; + } + if ( anseq-1)iN->c=declare_cl_nodes(-1, a); + pN=iN; + N=iN->c; + } + + return galn; +} +CL_node ***add_constraint2graph_aln (CL_node ***G, int s1, int r1, int s2, int r2) +{ + CL_node *S, *E, *B; + int d; + + + S=G[s1][r1]; + E=G[s2][r2]; + + + d=get_node_distance (S,E); + if (d<0){B=S;S=E;E=B;} + d=(d<0)?-d:d; + + + insert_gap_columns (E,d); + shift_segment( S,d+1,d); + + return G; + +} + + +CL_node *shift_segment ( CL_node *S, int segL, int shiftL) +{ + int a; + CL_node *E, *G; + + + if ( !shiftL)return S; + + /*find segment coordinates*/ + for (E=S, a=1; a< segL; a++)E=E->r; + + /*Shift the gaps*/ + + G=swap_gap_in_graph (S, E); + for (a=1; a< shiftL; a++)swap_gap_in_graph (S, E); + + while (G!=E)G=remove_graph_gap_column (G); + remove_graph_gap_column (E); + + return G; +} + +int is_graph_gap_column(CL_node *S) +{ + while (S->p)S=S->p; + + while (S) + { + if (S->res>=0)return 0; + S=S->c; + } + return 1; +} +CL_node * remove_graph_gap_column (CL_node *S) +{ + CL_node *R,*L, *P, *RV; + + RV=S->r; + while (S->p) + { + + S=S->p; + } + + if ( !is_graph_gap_column (S))return RV; + + + + while (S) + { + + R=S->r; + L=S->l; + P=S->p; + + if (L)L->r=S->r; + if (R)R->l=S->l; + + P=S; + S=S->c; + vfree_cl_node (P); + } + return RV; +} + +CL_node * swap_gap_in_graph ( CL_node*S, CL_node *E) +{ + /*Moves gap AFTER End to BEFORE Start + SxxxE- + -xxxxx + straightens the links in between + */ + CL_node *G, *N, *iE, *iS, *SP, *SC, *SL; + + + /*Preserve the E/S values*/ + iE=E; + iS=S; + + + /*prepare the parent/child links first*/ + + SP=S->p; + SC=S->c; + SL=S->l; + + while ( S!=E->r) + { + N=S->r; + + S->p=N->p; + if (N->p)(S->p)->c=S; + + S->c=N->c; + if (N->c)(S->c)->p=S; + + S=S->r; + } + + E=iE; + S=iS; + + /*Remove the gap*/ + G=E->r; + if ( G->res>=0)fprintf ( stderr, "\nERROR: NOT a GAP"); + + E->r=G->r; + if (E->r)(E->r)->l=E; + + /*insert the gap*/ + + G->r=S; + S->l=G; + + G->l=SL; + if (SL)SL->r=G; + + + G->p=SP; + if (SP)SP->c=G; + + G->c=SC; + if (SC)SC->p=G; + + return G; + +} + +CL_node * declare_cl_nodes ( int len, int seq) +{ + static CL_node **N; + CL_node *IN; + static int Nlen; + int a; + + if (len==-1) + { + IN=calloc ( 1, sizeof (CL_node)); + IN->res=-1; + return IN; + } + + + + if ( len>Nlen) + { + free (N); + N=calloc (len, sizeof (CL_node*)); + } + + if ( len==0)return NULL; + + for (a=0; ares=-1; + (N[a])->seq=seq; + if (a!=0)(N[a])->l=N[a-1]; + if (a!=len-1)(N[a])->r=N[a+1]; + } + + (N[0])->l=N[len-1]; + (N[len-1])->r=N[0]; + + return N[0]; +} + +CL_node *insert_gap_columns (CL_node *S, int d) +{ + CL_node *Gs,*Ge, *pGs, *Gi, *Si; + int a; + + if ( d==0)return S; + + pGs=Gi=NULL; + Si=S; + while (S->p!=NULL)S=S->p; + + while (S!=NULL) + { + Gs=declare_cl_nodes(d, S->seq); + Ge=Gs->l; + + Ge->r=S->r; + if (Ge->r)(Ge->r)->l=Ge; + + Gs->l=S; + S->r=Gs; + + if (pGs) + { + Gi=Gs; + for (a=0; a< d; a++) + { + Gs->p=pGs; + pGs->c=Gs; + Gs=Gs->r; + pGs=pGs->r; + } + pGs=Gi; + } + else + { + pGs=Gs; + } + S=S->c; + } + return Si; +} + +int get_node_distance ( CL_node *S, CL_node *E) +{ + int distance=0; + CL_node *iS,*B; + int swap=1; + + /*project the two points onto one sequence*/ + if (S->seq>E->seq){B=S;S=E;E=B;swap*=-1;} + while (S->seq!=E->seq)S=S->c; + + /*Walk from E to S */ + iS=S; + while ( iS->res<0 && iS->r!=NULL){iS=iS->r;} + if (iS->res<0 || iS->res>E->res){B=S; S=E; E=B;swap*=-1;} + + while ( S!=E) + { + S=S->r; + distance+=swap; + } + return distance; +} + + + + + + + + + +int check_graph ( CL_node *S, char *string) +{ + CL_node *iS; + static int n; + int lr; + + if ( S==NULL)S=Start; + fprintf ( stderr, "\n\tGRAPH Check %s #%d\n",string, ++n); + while ( S->p!=NULL)S=S->p; + while ( S->l!=NULL)S=S->l; + while ( S) + { + iS=S; + lr=-1; + while (iS) + { + if (iS->l && (iS->l)->seq!=iS->seq){fprintf ( stderr, "\n\t\tSEq pb");myexit(EXIT_FAILURE);} + if (iS->free==1){fprintf ( stderr, "\n\t\tFree Node read");myexit(EXIT_FAILURE);} + if (iS->res>0) + { + if (lr!=-1 && iS->res-lr!=1){fprintf ( stderr, "\n\t\tERROR: lost residues");myexit (EXIT_FAILURE);} + lr=iS->res; + } + if ( iS->r && (iS->r)->l!=iS){fprintf ( stderr, "\n\t\tERROR: left != right: [%d %d][%d %d]", iS->seq, iS->res, (iS->l)->seq, (iS->r)->res);myexit (EXIT_FAILURE);} + if ( iS->p && (iS->p)->c!=iS){fprintf ( stderr, "\n\t\tERROR: parent != child: [%d %d][%d %d]", iS->seq, iS->res, (iS->p)->seq, (iS->p)->res);myexit (EXIT_FAILURE);} + if ( iS->c && (iS->c)->p!=iS){fprintf ( stderr, "\n\t\tERROR: parent != child: [%d %d][%d %d]", iS->seq, iS->res, (iS->c)->seq, (iS->c)->res);myexit (EXIT_FAILURE);} + iS=iS->r; + } + S=S->c; + } + return 1; +} + +CL_node * vfree_graph ( CL_node *S) +{ + CL_node *Si; + + while ( S->p!=NULL)S=S->p; + while ( S->l!=NULL)S=S->l; + + while ( S) + { + Si=S->c; + while ( S) + { + + S=S->r; + if (S)vfree_cl_node (S->l); + } + S=Si; + } + return S; + +} +CL_node *vfree_cl_node ( CL_node *N) +{ + if ( N->free==1)crash("freeing free block"); + N->free=1; + free (N); + return N; +} + + +void light_nodes (CL_node *A, int va, CL_node*B, int vb, CL_node*C,int vc, char *string ) +{ + int ta=0, tb=0, tc=0; + + fprintf ( stderr, "\nCycle %d\n LIGHT NODE: %s", cycle,string); + if ( A){ta=A->res; A->res=va;fprintf ( stderr, "\nA: seq %d res %d", A->seq, A->res);} + if ( B){tb=B->res; B->res=vb;fprintf ( stderr, "\nB: seq %d res %d", B->seq, B->res);} + if ( C){tc=C->res; C->res=vc;fprintf ( stderr, "\nC: seq %d res %d", C->seq, C->res);} + print_graph (A, 0); + if ( A){A->res=ta;} + if ( B){B->res=tb;} + if ( C){C->res=tc;} +} +int check_link (CL_node ***G, int s1, int r1, int s2, int r2) +{ + CL_node *S; + CL_node *E; + + S=G[s1][r1]; + E=G[s2][r2]; + while ( S->p)S=S->p; + while ( S) + { + S=S->c; + if ( S==E)return 1; + } + return 0; +} +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/util_job_handling.c b/binaries/src/tcoffee/t_coffee_source/util_job_handling.c new file mode 100644 index 0000000..838d911 --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/util_job_handling.c @@ -0,0 +1,362 @@ +#include +#include +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "define_header.h" +#include "dp_lib_header.h" + + + +Job_TC* print_lib_job ( Job_TC *job,char *string, ...) +{ + va_list ap; + char **list; + char **value; + char **name; + int a, np, n; + + char bname[100]; + char bval[100]; + + list=string2list2(string, " ="); + n=atoi (list[0]); + + + name =vcalloc ( (n-1)/2, sizeof (char*)); + value=vcalloc ( (n-1)/2, sizeof (char*)); + + + va_start (ap, string); + for (a=1, np=0; apl=vcalloc (100, sizeof (char*));job->pl[job->np++]=(void*)job->pl; + job->jobid=njobs++; + } + + for ( a=0; a< n; a++) + { + int string=0; + if ( strstr(name[a], "control") && !job->control){job->control=vcalloc ( 1, sizeof (Job_control_TC));job->pl[job->np++]=(void*)job->control;} + else if ( strstr(name[a], "io") && !job->io){job->io=vcalloc ( 1, sizeof (Job_io_TC));job->pl[job->np++]=(void*)job->io;} + else if ( strstr(name[a], "param") && !job->param){job->param=vcalloc ( 1, sizeof (Job_param_TC));job->pl[job->np++]=(void*)job->param;} + + if ( strm (name[a], "control")) {job->control=(struct Job_control_TC*)atol(value[a]);string=0;} + else if ( strm (name[a], "control->submitF")) {(job->control) ->submitF=(struct Job_TC *(*)(struct Job_TC *))atol(value[a]);string=0;} + else if ( strm (name[a], "control->retrieveF")) {(job->control) ->retrieveF=(struct Job_TC *(*)(struct Job_TC *))atol(value[a]);string=0;} + else if ( strm (name[a], "control->mode")) {(job->control)->mode=value[a];string=1;} + + else if ( strm (name[a], "param")) {job->param=(struct Job_param_TC*)atol(value[a]);string=0;} + else if ( strm (name[a], "param->method")) {job->pl[job->np++]=((job->param)->method)=value[a];string=1;} + else if ( strm (name[a], "param->TCM")) {(job->param)->TCM= (TC_method *) atol(value[a]) ;string=0;} + else if ( strm (name[a], "param->aln_c")) {job->pl[job->np++]=(job->param)->aln_c=value[a] ;string=1;} + else if ( strm (name[a], "param->seq_c")) {job->pl[job->np++]=(job->param)->seq_c=value[a] ;string=1;} + + + else if ( strm (name[a], "io")) {job->io=(struct Job_io_TC*)atol(value[a]);string=0;} + else if ( strm (name[a], "io->out")) {job->pl[job->np++]=(job->io)->out=value[a] ;string=1;} + else if ( strm (name[a], "io->in" )) {job->pl[job->np++]=(job->io)->in =value[a] ;string=1;} + else if ( strm (name[a], "io->CL")) {(job->io)->CL=(Constraint_list*)atol (value[a]); string=0;} + else + { + fprintf ( stderr, "ERROR: print_lib_job2: %s is unknown [FATAL:%s]", name[a], PROGRAM); + myexit (EXIT_FAILURE); + } + if ( string==0) vfree ( value[a]); + } + vfree ( value); + free_arrayN ((void **)name, 2); + return job; +} + + + +/*Stack Manipulation*/ +Job_TC *queue_cat (Job_TC *P, Job_TC *C) +{ + if ( !P && !C) return NULL; + else if (!P || P->jobid==-1) + { + vfree (P); + C->p=NULL; + return C; + } + else + { + P->c=C; + if (C)C->p=P; + return queue2last(P); + } + return NULL; +} +Job_TC *free_queue (Job_TC *job) +{ + return NULL; + if (!job) return job; + else + { + job=queue2last(job); + while ( job) + { + job=free_job (job); + } + return job; + } +} +Job_TC *free_job (Job_TC *job) + { + int a; + Job_TC *p; + + if ( !job ) return job; + else + { + for ( a=job->np-1; a>=0; a--) + vfree ( job->pl[a]); + p=job->p; + job->p=job->c=NULL; + vfree (job); + return p; + } + return NULL; + } +Job_TC * queue2heap (Job_TC*job) +{ + + while (job && job->p) + job=job->p; + return job; +} +Job_TC * queue2last (Job_TC*job) +{ + + while (job && job->c) + { + job=job->c; + } + return job; +} + +int queue2n (Job_TC*job) +{ + int n=0; + + + job=queue2last (job); + while (job && job->p) + { + n++; + job=job->p; + + } + return n; +} + +Job_TC * descend_queue (Job_TC*job) +{ + + if (!job ||!job->c)return job; + else + { + (job->c)->p=job; + job=job->c; + } + return job; +} + +Job_TC* delete_job (Job_TC *job) +{ + Job_TC *p, *c; + + p=job->p; + c=job->c; + free_job (job); + + return queue_cat (p, c); +} + +Job_TC*** split_job_list (Job_TC *job, int ns) +{ + int a,u,n,nj,split; + Job_TC*** jl; + Job_TC *ljob; + //retun a pointer to ns splits for joblist + + + if (ns==0)return NULL; + job=queue2heap(job); + jl=vcalloc(ns+1, sizeof (Job_TC**)); + jl[0]=vcalloc (2, sizeof (Job_TC*)); + + nj=queue2n(job); + + if (nj==0)return NULL; + else split=(nj/ns)+1; + + n=a=u=0; + jl[a][0]=job; + while (job) + { + ljob=job; + if (n==split && ac; + } + + /*Display job details when debugging + a=0; + while (jl[a]) + { + Job_TC *start,* end; + int todo=0; + + start=job=jl[a][0]; + end=jl[a][1]; + while (job!=end){todo++;job=job->c;} + job=start; + while (job!=end) + { + HERE ("--- %d %d %s",a, job, job->param->aln_c); + job=job->c; + } + a++; + } + + a=0; + while (jl[a]){HERE ("**** %d %d ", jl [a][0], jl[a][1]);a++;} + myexit (0); + */ + return jl; +} + + + + +/*Job Control*/ +Job_TC* submit_job ( Job_TC *job) +{ + + if (!(job->control)->mode ||!(job->control)->mode[0] || 1==1) + { + return (job->control)->submitF (job); + } + else + { + fprintf ( stderr, "\n%s is an unkown mode for posting jobs [FATAL:%s]",(job->control)->mode, PROGRAM); + myexit (EXIT_FAILURE); + return NULL; + } + +} + +Job_TC* retrieve_job ( Job_TC *job) +{ + if (!(job->control)->mode ||!(job->control)->mode[0] || 1==1) + { + return (job->control)->retrieveF (job); + } + else + { + fprintf ( stderr, "\n%s is an unkown mode for posting jobs [FATAL:%s]",(job->control)->mode, PROGRAM); + myexit (EXIT_FAILURE); + return NULL; + } +} +int **n2splits (int splits, int tot) +{ + int **l; + int a,b,delta; + + if (splits==0)return NULL; + else if ( tot==0)return NULL; + else + { + + l=declare_int (splits,2); + delta=tot/splits; + + for (a=0,b=0; a +#include +#include +#include +#include +#include +#include + + +typedef struct + { + char *name; + char *path; + char *suffix; + char *full; + } +Fname; + +struct Tmpname + { + char *name; + struct Tmpname *next; + }; +/*********************************************************************/ +/* */ +/* DICHOTOMY */ +/* */ +/* */ +/*********************************************************************/ +double dichotomy (double value, double target_value, double middle, double *bottom,double *top); +/*********************************************************************/ +/* */ +/* QSORT */ +/* */ +/* */ +/*********************************************************************/ + +void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)); +/*int memcmp ( const void *a, const void * b, size_t size); +void * memcpy ( void *a, void * b, size_t size); +*/ +/*********************************************************************/ +/* */ +/* HEAPSORT */ +/* */ +/* */ +/*********************************************************************/ +FILE *hsort_file ( FILE *fp ,int n,int len, size_t size,int first_comp_field, int n_comp_fields,int (*compare)(const void *, const void*,int,int,size_t),void * (*copy)(void *,void*,size_t)); +void ** hsort_array ( void **ra,int n,int len, size_t size, int first_comp_field, int n_comp_fields,int (*compare)(const void *, const void*,int,int,size_t),void * (*copy)(void *,void*,size_t)); +/**********************************************************************/ +/* */ +/* HSORT WRAPPERS */ +/* */ +/* */ +/**********************************************************************/ +void **hsort_list_array ( void **L, int len, size_t size, int entry_len,int first_comp_field, int n_comp_fields); +FILE *hsort_list_file ( FILE *fp, int len, size_t size, int entry_len,int first_comp_field, int n_comp_fields); +int hsort_cmp ( const void *a, const void *b, int first, int clen, size_t size); +void *hsort_cpy(void*to, void *from, size_t size); + +void test_hsort_list_array(); + +/*********************************************************************/ +/* */ +/* CEDRIC BSEARCH */ +/* */ +/* */ +/*********************************************************************/ +void * bsearch_file ( const void *key,int *p,int comp_first,int comp_len, FILE *fp ,int len, int entry_len,size_t el_size, int (*compare)(const void *, const void*,int, int, size_t)); +void * bsearch_array( const void *key,int *p,int comp_first,int comp_len,void**list,int len, int entry_len,size_t el_size, int (*compare)(const void *, const void*,int, int, size_t)); + +/*********************************************************************/ +/* */ +/* MY B_SEARCH_FILE FUNCTIONS */ +/* */ +/* */ +/*********************************************************************/ +void **search_in_list_file ( void *key,int *p, int comp_len,FILE *fp, int len, size_t size, int entry_len); +void **search_in_list_array ( void *key,int *p, int comp_len,void **L , int len, size_t size, int entry_len); + +/*********************************************************************/ +/* */ +/* SORT/COMPARE/SEARCH FUNCTIONS */ +/* */ +/* */ +/*********************************************************************/ + +int **search_in_list_int ( int *key, int k_len, int **list, int ne); +void sort_float ( float **V,int N_F, int F, int left, int right); +int cmp_float ( const float **a, const float **b); +void sort_int_1D ( int *L, int n); +char** sort_string_array (char **V, int n); + +void sort_int ( int **V,int N_F, int F, int left, int right); +void sort_list_int ( int **V,int N_F, int F, int left, int right); +void sort_list_int2 ( int **V,int *list,int N_F, int left, int right); +void sort_int_inv ( int **V,int N_F, int F, int left, int right); +void sort_list_int_inv ( int **V,int N_F, int F, int left, int right); +int cmp_int ( const int**a, const int**b); +int cmp_list_int (const int**a, const int**b); +int cmp_list_int2 (const int**a, const int**b); + +int name_is_in_list ( char *name, char **name_list, int n_name, int len); +char * check_list_for_dup ( char **list, int ne); +FILE *get_number_list_in_file ( FILE *fp, int *list, int *n, int *max_len); + + +/*********************************************************************/ +/* */ +/* QUANTILE */ +/* */ +/* */ +/*********************************************************************/ +int quantile ( int argc, char *argv[]); + +int quantile_rank (int **list,int field, int n, float p); +/*********************************************************************/ +/* */ +/* DUPLICATION */ +/* */ +/* */ +/*********************************************************************/ +short * set_short ( short *, int n,...); +char * set_char ( char *, int n,...); +int * set_int ( int *, int n,...); +float * set_float ( float *, int n,...); +double * set_double( double*, int n,...); + +short * ga_memcpy_short ( short *array1, short *array2, int n); +int * ga_memcpy_int ( int *array1, int *array2, int n); +float * ga_memcpy_float ( float *array1, float *array2, int n); +double * ga_memcpy_double( double *array1, double *array2, int n); + +short ** duplicate_short ( short **array , int len, int field); +int ** duplicate_int ( int **array , int len, int field); +char ** duplicate_char ( char **array , int len, int field); +char * duplicate_string ( char *string); +float ** duplicate_float ( float **array , int len, int field); +double ** duplicate_double( double **array , int len, int field); + +short ** copy_short ( short **array1, short **array2, int len, int number_field); +char ** copy_char ( char **array1, char **array2, int len, int number_field); +int ** copy_int ( int **array1, int **array2, int len, int number_field); +float ** copy_float ( float **array1, float **array2, int len, int number_field); +double ** copy_double( double **array1, double **array2, int len, int number_field); + +/*********************************************************************/ +/* */ +/* CONCATENATION */ +/* */ +/* */ +/*********************************************************************/ +Alignment ** cat_aln_list ( Alignment **list_to_cat,int first, int end, Alignment **rec_list); + +/*********************************************************************/ +/* */ +/* NUMBER ARRAY ANALYSE */ +/* */ +/* */ +/*********************************************************************/ +int output_array_int (char *name, int **array); +int **input_array_int (char *fname); +short return_max_short (short ** array, int len_array, int field); +char return_max_char( char ** array, int len_array, int field); +int return_max_int( int ** array, int len_array, int field); +float return_max_float( float ** array, int len_array, int field); +double return_max_double( double** array, int len_array, int field); + +short return_min_short (short ** array, int len_array, int field); +char return_min_char( char ** array, int len_array, int field); +int return_min_int( int ** array, int len_array, int field); +float return_min_float( float ** array, int len_array, int field); +double return_min_double( double** array, int len_array, int field); + +short return_max_coor_short (short ** array, int len_array, int field, int *coor); +char return_max_coor_char( char ** array, int len_array, int field, int *coor); +int return_max_coor_int( int ** array, int len_array, int field, int *coor); +float return_max_coor_float( float ** array, int len_array, int field, int *coor); +double return_max_coor_double( double** array, int len_array, int field, int *coor); + +short return_min_coor_short (short ** array, int len_array, int field, int *coor); +char return_min_coor_char( char ** array, int len_array, int field, int *coor); +int return_min_coor_int( int ** array, int len_array, int field, int *coor); +float return_min_coor_float( float ** array, int len_array, int field, int *coor); +double return_min_coor_double( double** array, int len_array, int field, int *coor); + +short return_2Dmax_short (short ** array, int start, int len_array, int first_field, int number_field); +char return_2Dmax_char( char ** array, int start, int len_array, int first_field, int number_field); +int return_2Dmax_int( int ** array, int start, int len_array, int first_field, int number_field); +float return_2Dmax_float( float ** array, int start, int len_array, int first_field, int number_field); +double return_2Dmax_double( double** array, int start, int len_array, int first_field, int number_field); + +short return_2Dmin_short (short ** array, int start, int len_array, int first_field, int number_field); +char return_2Dmin_char( char ** array, int start, int len_array, int first_field, int number_field); +int return_2Dmin_int( int ** array, int start, int len_array, int first_field, int number_field); +float return_2Dmin_float( float ** array, int start, int len_array, int first_field, int number_field); +double return_2Dmin_double( double** array, int start, int len_array, int first_field, int number_field); + +short return_2Dmax_coor_short ( short ** array,int start1, int end1, int start2, int end2, int *i, int *j ); +char return_2Dmax_coor_char( char ** array, int start1, int end1, int start2, int end2, int *i, int *j); +int return_2Dmax_coor_int( int ** array, int start1, int end1, int start2, int end2, int *i, int *j); +float return_2Dmax_coor_float( float ** array, int start1, int end1, int start2, int end2, int *i, int *j); +double return_2Dmax_coor_double( double** array, int start1, int end1, int start2, int end2, int *i, int *j); + +short return_2Dmin_coor_short ( short ** array, int start1, int end1, int start2, int end2, int *i, int *j); +char return_2Dmin_coor_char( char ** array, int start1, int end1, int start2, int end2, int *i, int *j); +int return_2Dmin_coor_int( int ** array, int start1, int end1, int start2, int end2, int *i, int *j); +float return_2Dmin_coor_float( float ** array, int start1, int end1, int start2, int end2, int *i, int *j); +double return_2Dmin_coor_double( double** array, int start1, int end1, int start2, int end2, int *i, int *j); + +double return_wmean_short ( short ** array, int len, int wfield, int field); +double return_wmean_char ( char ** array, int len, int wfield, int field); +double return_wmean_int ( int ** array, int len, int wfield, int field); +double return_wmean_float ( float ** array, int len, int wfield, int field); +double return_wmean_double( double** array, int len, int wfield, int field); + +double return_mean_short ( short ** array, int len, int field); +double return_mean_char ( char ** array, int len, int field); +double return_mean_int ( int ** array, int len, int field); +double return_mean_float ( float ** array, int len, int field); +double return_mean_double ( double** array, int len, int field); + +short return_sum_short ( short ** array, int len, int field); +char return_sum_char ( char ** array, int len, int field); +int return_sum_int ( int ** array, int len, int field); +float return_sum_float ( float ** array, int len, int field); +double return_sum_double( double** array, int len, int field); + +short return_sd_short ( short ** array, int len, int field, short mean); +char return_sd_char ( char ** array, int len, int field, char mean); +int return_sd_int ( int ** array, int len, int field, int mean); +float return_sd_float ( float ** array, int len, int field, float mean); +double return_sd_double( double** array, int len, int field, double mean); + +double return_z_score ( double x, double sum, double sum2, double n); +double* return_r (double **list, int n); +short* invert_list_short ( short * array, int len ); +char* invert_list_char ( char * array, int len ); +int* invert_list_int ( int * array, int len ); +float* invert_list_float ( float * array, int len ); +double* invert_list_double( double* array, int len ); + +void swap_short ( short * array, short * array2,int len ); +void swap_char ( char * array, char * array2,int len ); +void swap_int ( int * array, int * array2,int len ); +void swap_float ( float * array, float * array2,int len ); +void swap_double( double* array, double* array2,int len ); + +short return_max_short_hor (short ** array, int len_array, int field); +char return_max_char_hor (char ** array, int len_array, int field); +int return_max_int_hor (int ** array, int len_array, int field); +float return_max_float_hor (float ** array, int len_array, int field); +double return_max_double_hor(double ** array, int len_array, int field); + +short return_min_short_hor ( short ** array, int len_array, int field); +char return_min_char_hor ( char ** array, int len_array, int field); +int return_min_int_hor ( int ** array, int len_array, int field); +float return_min_float_hor ( float ** array, int len_array, int field); +double return_min_double_hor( double** array, int len_array, int field); + +short best_short (int n, ...); +int best_int (int n, ...); +char best_char (int n, ...); +float best_float (int n, ...); +double best_double(int n, ...); + +int is_defined_short (int n, ...); +int is_defined_int (int n, ...); +int is_defined_char (int n, ...); +int is_defined_float (int n, ...); +int is_defined_double(int n, ...); + + +int max_int (int*i, ...); + +int return_maxlen ( char ** array, int number); +int return_minlen ( char ** array, int number); + +float return_mean_diff_float ( float **array, int len, int field,float mean); + + +void inverse_int ( int**array, int len, int field, int max, int min); +void inverse_float ( float**array, int len, int field, int max, int min); +void inverse_2D_float ( float **array, int start, int len, int start_field, int number_field, float max,float min); + + + + +void **recycle (void **A, int l, int cycle); + +/*********************************************************************/ +/* */ +/* SHELL INTERFACES */ +/* */ +/* */ +/*********************************************************************/ +char* getenv4debug ( const char *var); +char* get_env_variable ( const char *var, int mode); +int atoigetenv(const char *x); +void setenv_func ( char *string_name, char *string_value); +void get_pwd ( char *name); +char *pg2path (char *pg); +int pg_is_installed ( char *pg); +/*********************************************************************/ +/* */ +/* MISC */ +/* */ +/*********************************************************************/ +char *num2plot (int value, int max, int line_len); +int perl_strstr ( char *string, char *pattern); +float grep_function ( char *pattern, char *file); +void crash_if ( int val, char *s); +void crash ( char *s); +int ** make_recursive_combination_table ( int tot_n_param, int *n_param, int *nc, int**table, int field); +/*********************************************************************/ +/* */ +/* STRING PROCESSING */ +/* */ +/* */ +/*********************************************************************/ +char *strnrchr ( char *s,char x, int n); +int intlen (int n); +char * update_string (char *string1, char *string2); +char* strcatf (char *string1,char *string2, ...); +char *vcat (char *v1, char *v2); + +int strget_param ( char *string, char *param_name, char *param_value, char *format, ...); +char * lstrstr ( char *in, char *token); +char * vstrstr ( char *in, char *token); +char * estrstr ( char *in, char *token,...); +char * festrstr ( char *in, char *token,...); + +int strscanf (char *in, char *token, char *format, ...); +int strfcanf (char *file, char *token, char *format, ...); + +int match_motif ( char *string, char **motif); + +char *after_strstr (char *string, char *token); + +char ** push_string (char *val, char **stack, int *nval, int mode); +int vsrand (int val); +int *randomize_list (int *list, int len, int ncycle); +int vstrcmp (const char *s1, const char *s2); +int vstrncmp (const char *s1, const char *s2, int n); +FILE *print_array_char (FILE *out, char **array, int n, char *sep); + +char *extract_suffixe ( char *array); +char * path2filename ( char *array); +char *filename2path (char *name); +Fname* parse_fname ( char *array); + +void string_array_convert ( char **array, int n_strings, int ns, char **sl); +void string_convert( char *string, int ns, char **sl); +int convert ( char c, int ns, char **sl); +int convert2 ( char c, char *list); + +void string_array_upper ( char **string, int n); +void string_array_lower ( char **string, int n); +char *upper_string ( char *string); +char *lower_string ( char *string); +char * substitute_double ( char *string, char *token); +char * substitute ( char *string, char *token, char *replacement); +char * substitute_char ( char *string, char token, char replacement); +char * substituteN ( char *string, char *token, char *replacement, int N); +char * tild_substitute ( char *string, char *token, char *replacement); + + +char ** clean_string ( int n, char **string); + +int str_overlap ( char *string1, char *string2, char x); +int get_string_line ( int start, int n_lines, char *in, char *out); +FILE * output_string_wrap ( int wrap,char *string, FILE *fp); +char * extract_char ( char * array, int first, int len); +int check_cl4t_coffee (int argv, char **argc); + +char** break_list ( char **argv, int *argc, char *separators); +char** merge_list ( char **argv, int *argc); +int *name_array2index_array ( char **list1, int n1, char **list2, int n2); +char ** get_list_of_tokens ( char *string, char *separators, int *n_tokens); +char **ungap_array(char ** array, int n); +void ungap ( char *seq); +int seq2len (char *seq, char *pset, char *nset); +int seq2res_len (char *seq); +void remove_charset ( char *seq, char *set); +char *remove_charset_from_file (char *fname, char *set); +char *mark_internal_gaps(char *seq, char symbol); + +char *list2string (char **list, int n); +char *list2string2 (char **list, int n, char* sep); + +char ** string2list (char *string); +char ** string2list2(char *string, char *separators); +int * string2num_list( char *string); +int * string2num_list2( char *string, char *separators); +char **char_array2number ( char ** array, int n); +char *char2number ( char * array); +long atop(char *); +char *invert_string (char *string); +char *invert_string2 (char *string); +char *string2inverted_string (char *string); +/* Analyse and Compare Strings*/ +int isblanc ( char *buf); +/*int islower (char c); +int isupper (char c); +*/ +void splice_out ( char *seq, char x); +char* splice_out_seg ( char *seq,int pos, int len); + +int is_number ( char *buf); +int is_alpha_line ( char *buf); +int is_alnum_line ( char *buf); +int case_insensitive_strcmp ( char *string1, char *string2); +int get_string_sim ( char *string1, char *string2, char *ignore); + +int is_gap ( char x); +int is_gop (int p, char *s); + +int is_aa ( char x); +int is_dna ( char x); +int is_rna ( char x); +int haslower (char *s); +int hasupper (char *s); + + +char * get_alphabet ( char *seq, char *alphabet); +int is_in_set ( char r, char *list); +int array_is_in_set (char *array, char *set); +char * generate_void ( int x); +char * generate_null ( int x); +char * generate_string ( int x, char y); + + +char * translate_string (char *string, char *in, char*out); +int get_longest_string (char **array,int n, int *len, int *index); +int get_shortest_string (char **array,int n, int *len, int *index); +/*EDIT STRING*/ +char **pad_string_array ( char **array, int n, int len, char pad); +char * crop_string (char *string, int start, int end); +int get_distance2char ( char *x, char *list); + +/*********************************************************************/ +/* */ +/* TIME FUNCTIONS */ +/* */ +/* */ +/*********************************************************************/ +FILE *print_program_information (FILE *fp, char *comment); +FILE* print_cpu_usage (FILE *fp, char *comment); +void print_exit_success_message (); +void print_exit_failure_message (); + +int get_time (); +int get_ctime (); +int reset_time(); +int increase_ref_time(int increase); +/*********************************************************************/ +/* */ +/* SYSTEM CALLS */ +/* */ +/* */ +/*********************************************************************/ +int has_error_lock(); +int is_rootpid(); +int is_shellpid(int pid); +int shift_lock (int from, int to, int from_type,int to_type, int action); +char *lock2name (int pid, int type); +int release_all_locks (int pid); +char *lock (int pid, int type, int action, char *value, ...); +int check_process (const char *com,int pid,int r, int failure_handling); +int assert_pid (pid_t p); +pid_t **declare_pidtable (); +pid_t set_pid (pid_t p); +pid_t vvfork(char *mode); +pid_t vwait (pid_t *p); +int vwait_npid (int submited, int max, int min); +int kill_child_pid(int pid); + +int safe_system (const char * commande); +pid_t vwaitpid (pid_t p, int *status, int options); + +int evaluate_sys_call_io ( char *out_file, char *com, char *fonc); +//char *cvsprintf (char *r,char *format, va_list arg_ptr,... ); +void HERE (char *string, ...); +void printf_exit (int exit_code, FILE *fp, char *string, ...); +int printf_file ( char *file, char *mode, char *string, ...); +int printf_fork ( FILE *fp,char *string,...); +int printf_system (char *string, ...); +int printf_system_direct (char *string, ...); +int my_system_cl (int argc, char *argv[]); +int my_system ( char *command); +int unpack_perl_script (char *name, char ***unpacked, int n); +void unpack_all_perl_script (char *script); +/*********************************************************************/ +/* */ +/* IO FUNCTIONS */ +/* */ +/* */ +/*********************************************************************/ +void set_command_line (char *s); +FILE * print_command_line (FILE *fp ); +int getpid_ref(); +char ** standard_initialisation ( char **in_argv, int *in_argc); +char ** standard_initialisation_start ( char **in_argv, int *in_argc); +char ** standard_initialisation_end ( char **in_argv, int *in_argc); +/* +by default : dir_4_tcoffee: $HOME/.t_coffee +tmp: dir_4_tcoffee/tmp OR TMP_4_TCOFFEE +cache: idem +methods: idem +mcoffee: idem +*/ +int get_nproc (); +char *get_os(); +char *get_lockdir_4_tcoffee (); +char *get_plugins_4_tcoffee (); +char *get_home_4_tcoffee(); +char *get_dir_4_tcoffee(); +char *get_tmp_4_tcoffee(); +char *get_cache_4_tcoffee(); +char *get_methods_4_tcoffee(); +char *get_mcoffee_4_tcoffee(); + + + +void myexit (int signal); +FILE *fatal_exit ( FILE *fp, int exit_signal, char *string, ...); +int set_warning_mode ( int mode); +FILE *add_warning (FILE *fp, char *string, ...); +FILE *add_information (FILE *fp, char *string, ...); +int fprintf_error( FILE *fp, char *string, ...); + +void output_warning_list(); + +int count_n_res_in_array (char *array, int len); +int count_n_gap_in_array (char *array, int len); +int count_n_symbol_in_array ( char *array, char *array_list, int len); +char* count_strings_in_file ( char *in, char *out); +char** count_strings ( char **array, int len); +int ** count_int_strings ( int **array, int len, int s); + +int get_first_non_white_char (char *name); +int count_n_char_x_in_file(char *name, char x); +int count_n_char_in_file(char *name); +int count_n_line_in_file(char *name); +int measure_longest_line_in_file ( char *name ); +int file_cat ( char *fname1, char *fname2); +FILE* display_file_content (FILE *output, char *name); +int cat_file (char *file1, char *file2); +char ***file2list (char *name, char *sep); +char ** file2lines (char *name); +char * file2string (char *name); +int string2file ( char *file, char *mode, char *string,...); +char *chomp (char *name); +int get_cl_param (int argc, char **argv, FILE **fp,char *para_name, int *set_flag, char *type, int optional, int max_n_val,char *usage, ...); +char ** get_parameter ( char *para_name, int *np, char *fname); + +char *get_t_coffee_environement (char *file); +char *set_path_4_plugins (char *); +int add_package2_tcoffee_env (char *package); + +void dump (char *dump_file, char *dump_nature); +void dump_error_file(); +void update_error_dir(); + +FILE* stack_msg(FILE *fp); +FILE* install_msg(FILE *fp); +FILE* proxy_msg(FILE *fp); +FILE* email_msg(FILE *fp); +FILE* error_msg(FILE *fp); +FILE *proxy_msg(FILE *fp); + +char *get_proxy(); +char *get_proxy_from_env(); +int set_proxy (char *proxy); + +char *input_name (); +char *Email4cl(int input_mode, int set_mode); +char *Email(int input_mode, int set_mode); +char *input_email (); +char *get_email_from_env (); +char *get_email (); +int set_email (char *email); +int cputenv4path (char*); +int cputenv (char*, ...); +int fcputenv (char *,char *, char*, ...); +char *file_putenv (char *file); +int check_dir_getenv ( char *string); + +char* set_string_variable (char *var, char* v); +char* get_string_variable (char *var); +char* unset_string_variable (char *var); +char* store_string_variable (char *var, char * v, int mode); + +int int_variable_isset (char *var); +int set_int_variable (char *var, int v); +int get_int_variable (char *var); +int unset_int_variable (char *var); +int store_int_variable (char *var, int v, int mode); + +void check_vtmpnam (); +int flag_file2remove_is_on (); +void set_file2remove_off(); +void set_file2remove_on(); +char *set_file2remove_extension(char *extension, int mode); +char * add2file2remove_list ( char *name); + + + +FILE * vtmpfile(); +void initiate_vtmpnam (char *s); +char * vtmpnam ( char *s); +char * tmpnam_2 (char *s); +void safe_remove(char*s); +char * vremove ( char *s); +char * vremove2 ( char *s); +void error_exit (); +void clean_exit(); +void signal_exit(); +void main_exit (); +int log_function (char *fname); + +void clean_function ( ); +void sig_clean_function ( int x); +char * prepare_cache ( const char *mode); +char * get_cache_dir(); +void update_cache (); +void ignore_cache(); + +FILE * vfopen ( char *name, char *mode); +FILE * vfclose (FILE *fp); +int echo ( char *string, char *fname); + +int **get_file_block_pattern (char *fname, int *n_blocks, int max_n_line); + +int token_is_in_file (char *fname, char *token); + +FILE * find_token_in_file_nlines ( char *fname, FILE * fp, char *token, int n_line); +FILE * find_token_in_file ( char *fname, FILE * fp, char *token); +FILE * quick_find_token_in_file (FILE *fp, char *token); + +char * vfgets (char *buf, FILE *fp); + +FILE * set_fp_after_char ( FILE *fp, char x); +FILE * set_fp_id ( FILE *fp, char *id); +FILE * skip_commentary_line_in_file ( char com, FILE *fp); +char * strip_file_from_comments (char *com, char *in_file); + +int check_for_update ( char *web_address); +int url2file (char *address, char *out); +int wget (char *address, char *out); +int curl (char *address, char *out); + + +int simple_check_internet_connection (char *address); +int check_internet_connection (int mode); +int check_environement_variable_is_set ( char *variable, char *description, int fatal); +int check_program_is_installed ( char *program_name, char *current_path, char *path_variable, char *where2getit, int fatal); +FILE * display_output_filename ( FILE *io, char *type, char *format, char *name, int check_output); +FILE * display_input_filename ( FILE *io, char *type, char *format, char *name, int check_output); +int filename_is_special ( char *fname); +char *check_file_exists ( char *fname); +int my_mkdir ( char *dir); +int my_rmdir ( char *dir); + +int file_is_empty(char *fname); +int file_exists (char *path,char *fname); +int isexec (char *fname); +int isdir (char *fname); +int isdir4path (char *fname); +int rrmdir (char *fname); +char * ls_l(char *path,char *fname); + +void create_file ( char *name); +void delete_file ( char *fname); +int util_rename ( char* from, char *to); +int util_copy ( char* from, char *to); +FILE * output_completion4halfmat ( FILE *fp,int n, int tot, int n_eports, char *s); +FILE * output_completion ( FILE *fp,int n, int tot, int n_eports, char *s); +void * null_function (int a, ...); +int btoi ( int nc,...); +/*********************************************************************/ +/* */ +/* Geometric FUNCTIONS */ +/* */ +/* */ +/*********************************************************************/ + +float get_geometric_distance ( float ** matrix, int ncoor, int d1, int d2, char *mode); +/*********************************************************************/ +/* */ +/* MATHEMATICAL FUNCTIONS */ +/* */ +/* */ +/*********************************************************************/ +double log_addN ( int N, double *L); +double log_add6 (double a, double b, double c, double d, double e, double f ); +double log_add5 (double a, double b, double c, double d, double e); +double log_add4 (double a, double b, double c, double d); +double log_add3 (double a, double b, double c); +double log_add2 (double a, double b); + +float factorial_log ( int start, int end); +float M_chooses_Nlog ( int m, int N); +double factorial ( int start, int end); +double M_chooses_N ( int m, int N); +float my_int_log(int a); +/*********************************************************************/ +/* */ +/* Fast Log Additions (adapted from Probcons)*/ +/* */ +/* */ +/*********************************************************************/ +double EXP(double x); +float LOOKUP (float x); +void LOG_PLUS_EQUALS (float *x, float y); +float LOG_ADD (float x, float y); +float LOG_ADD3 (float x1, float x2, float x3); +float LOG_ADD4 (float x1, float x2, float x3, float x4); +float LOG_ADD5 (float x1, float x2, float x3, float x4, float x5); +float LOG_ADD6 (float x1, float x2, float x3, float x4, float x5, float x6); +float LOG_ADD7 (float x1, float x2, float x3, float x4, float x5, float x6, float x7); +/////////////////////////////////////////////////////////////////////////////////////////// +// Hash function +//////////////////////////////////////////////////////////////////////////////////////////// +unsigned long hash_file(char* file); //returns the hash value for key +/////////////////////////////////////////////////////////////////////////////////////////// +// Generating lists through recirsive exploration +//////////////////////////////////////////////////////////////////////////////////////////// +int **generate_array_int_list (int len, int min, int max, int step, int *n, char *filename); +char ***generate_array_string_list (int len, char ***alp, int *alp_size, int *n, char *file, int mode); +float *display_accuracy (float *count, FILE *fp); +float *counts2accuracy (float *count); + +float rates2sensitivity (int tp, int tn, int fp, int fn, float *sp, float *sn, float *sen2, float *best); +float profile2sensitivity (char *pred, char *ref, float *sp, float *sn, float *sen2, float *b); +float profile2evalue (char *pred, char *ref); +//isexec lib +#include + +unsigned long linrand(unsigned long r); +unsigned long addrand(unsigned long r); +void addrandinit(unsigned long s); + +unsigned long mult(unsigned long p,unsigned long q); + + +struct Job_TC + { + int jobid; + int status; + + struct Job_TC *c; + struct Job_TC *p; + struct Job_io_TC *io; + struct Job_control_TC *control; + + struct Job_param_TC *param; + + /*memory mangement*/ + char **pl; + int np; +}; +typedef struct Job_TC Job_TC; + +struct Job_control_TC + { + + struct Job_TC* (*submitF) (struct Job_TC*); + struct Job_TC* (*retrieveF)(struct Job_TC*); + char *mode; +}; +typedef struct Job_control_TC Job_control_TC; + +struct Job_io_TC + { + char *in; + char *out; + struct Constraint_list *CL; + struct Alignment *A; +}; +typedef struct Job_io_TC Job_io_TC; + +struct Job_param_TC +{ + char *method; + struct TC_method *TCM; + char *temp_c; + char *aln_c; + char *seq_c; + char *aln_mode; +}; +typedef struct Job_param_TC Job_param_TC; + +Job_TC* print_lib_job ( Job_TC *job,char *string, ...); +Job_TC *print_lib_job2 ( Job_TC* job, int n, char **name, char **value); + + +/*Stack Manipulation*/ +Job_TC *free_queue (Job_TC *job); +Job_TC *free_job (Job_TC *job); +Job_TC * queue2heap (Job_TC*job); +Job_TC * queue2last (Job_TC*job); +int queue2n (Job_TC*job); +Job_TC * descend_queue (Job_TC*job); +Job_TC *queue_cat (Job_TC *P, Job_TC *C); +Job_TC *delete_job (Job_TC *job); +/*Job Control*/ +struct Job_TC* submit_job ( Job_TC *job); +struct Job_TC* retrieve_job ( Job_TC *job); +Job_TC*** split_job_list (Job_TC *job, int ns); +int **n2splits (int nsplits, int nelements); +struct Dps_result + { + int njobs; + struct Dps_job **dps_job; +}; +typedef struct Dps_result Dps_result; + +struct Dps_job + { + int JobId; + struct Constraint_list *CL; + char *input_file; + char *output_file; +}; +typedef struct Dps_job Dps_job; + +struct Dps_result *seq2list_DPS (struct Constraint_list *CL,char *method, char *aln_command, char *seq_command, char *weight, Dps_result *dps_result); +struct Constraint_list * gather_results_DPS ( Dps_result *DPS, struct Constraint_list *CL); +Dps_result *declare_dps_result ( int naln, Dps_result *dps); + +#define SEQ2 0 +#define R2 1 +#define WE 2 +#define CONS 3 +#define MISC 4 +#define SEQ1 5 +#define R1 6 +#define INDEX 7 + +#define ICHUNK 5 + +#define LIST_N_FIELDS 7 +#define CLIST_TYPE int + +/*********************************************************************************************/ +/* */ +/* FUNCTIONS Typedef */ +/* */ +/*********************************************************************************************/ +typedef int (*Profile_cost_func) (int*, int *,struct Constraint_list *); +typedef int (*Col_cost_func)(Alignment*, int **, int, int*, int, int **, int, int*, int, struct Constraint_list *); +typedef int (*Pair_cost_func)(struct Constraint_list *, int, int, int, int); +typedef int (*Pwfunc) (Alignment *, int*, int **,struct Constraint_list *); + +/*********************************************************************************************/ +/* */ +/* STRUCTURES FOR PDB ANALYSIS */ +/* */ +/*********************************************************************************************/ +typedef struct + { + char *use_seqan; +} +TC_param; +typedef struct + { + char blast_server[FILENAMELEN+1]; + char db[FILENAMELEN+1]; + int min_cov; + int min_id; + int max_id; +} +Blast_param; + +typedef struct + { + int n_excluded_nb; + + float similarity_threshold; + float rmsd_threshold; + float md_threshold; + int distance_on_request; + char *comparison_io; + int print_rapdb; + float maximum_distance;/*Diameter of the bubble used to identify the Calpha Neighborhood*/ + int N_ca; /*Number of Calpha to be looked at on both side*/ + float max_delta ; /*Maximum value for delta to be positive*/ + char *local_mode; + int scale; /*Value substracted to the pdb score in the bubble mode*/ + int n_extra_param; + char **extra_param; + char *evaluate_mode; + char *color_mode; + float filter; + int filter_aln; + int irmsd_graph; + int nirmsd_graph; + + + } +Pdb_param; + +typedef struct + { + int num; + int res_num;/*Residue number from 1 to N*/ + char res[4]; + char type[4]; + float x; + float y; + float z; + } +Atom; + +typedef struct + { + + Atom*CA; + Atom *C; + Atom *N; + Atom *CB; + } +Amino_acid; + + +typedef struct + { + /*Distances used for the Neighbour mode*/ + int **nb; /*Neighbors of each Ca ( sorted by distance) given as atoms*/ + /*nb[x][0] contains the number of neighbor atoms*/ + float **d_nb; /* contains the distances between atom y=nb[x][5] and Ca x*/ + /* !!!d_nb[x][0] is empty, the array starts at +1 to folow nb*/ + int max_nb; /* Largest neigborhood*/ +} +Struct_nb; + +typedef struct + { + + int len; /*Number of Calpha Carbons*/ + int n_atom; /*Number of atoms*/ + char *name; /*Name of the sequence*/ + char *seq; /*Sequence ( Complete)*/ + Atom **structure; /*Atoms*/ + Atom **ca; /*List of pointers to the Calpha Atoms from 0 to N-1*/ + Amino_acid **peptide_chain;/*List of pointers to the Calpha Atoms from 0 to N-1*/ + + + Struct_nb *Chain; + Struct_nb *Bubble; + Struct_nb *Transversal; + + float ** ca_dist; + Pdb_param *pdb_param; +} + +Ca_trace; +/*********************************************************************************************/ +/* */ +/* MOCA: Data structure for domains and alignments */ +/* */ +/*********************************************************************************************/ +struct Moca +{ + /*Normalisation factor: value by which each constraint weight is decreased*/ + int moca_scale; + /*Functions used for domain extraction:*/ + /*Function for evaluating the score of a domain: returns 0 if not acceptable, value if OK*/ + int (*evaluate_domain)(Alignment*,struct Constraint_list *); + int moca_threshold; + + /*Function for hiding previously used residues*/ + int ** (*cache_cl_with_domain)(Alignment*, struct Constraint_list *); + int **forbiden_residues; /*List of residues already used for domain construction*/ + + + /*Function for trunkating the result into a non-overlapping alignment*/ + Alignment* (*make_nol_aln)(Alignment*, struct Constraint_list *); + + /*Parameters Coordinates of the first motif to extract*/ + int moca_start; + int moca_len; + int moca_interactive; + +}; +typedef struct Moca Moca; +/*********************************************************************************************/ +/* */ +/* CONSTRAINT LISTS */ +/* */ +/*********************************************************************************************/ +struct Distance_matrix +{ + char mode[100]; + char sim_mode[100]; + char nseq; + int **similarity_matrix; /*Pairwise ID levels: 1-10000*/ + int **score_similarity_matrix; /*Pairwise ID levels: 1-10000*/ + int **distance_matrix; /*Pairwise ID levels: 1-10000*/ +}; +typedef struct Distance_matrix Distance_matrix; +struct Constraint_list + { + /*In Case of Modif, synchronize with: + util_declare/declare_constraint_list + util_declare/cache_dp_value4constraint_list + util_declare/duplicate_constraint_list + util_declare/free_constraint_list + */ + + //Generic parameters + TC_param *TC; + + int copy_mode; + struct Constraint_list *pCL; + Sequence *S; /*Total sequences*/ + int *master; //Sequences used as master sequences + int o2a_byte; // number of one to all provided in one go. + Sequence *STRUC_LIST; /*Name of the sequences with a Structure*/ + char align_pdb_param_file[FILENAMELEN+1]; + char align_pdb_hasch_mode[FILENAMELEN+1]; + + + Weights *W; /*Sequence Weights*/ + Distance_matrix *DM; /*Accurate Distance Matrix*/ + Distance_matrix *ktupDM; /*Fast Distance Matrix*/ + Fname *RunName; + + int *translation; + char ** out_aln_format; + int n_out_aln_format; + + + /*Packing Sequence: To use with domain analysis*/ + int **packed_seq_lu; + + /*DATA*/ + FILE *fp; /*File used for i/o if disk being used*/ + //int *L; /*Array used for storing Lib if mem being used*/ + int **M; /*substitution matrix*/ + char rna_lib[FILENAMELEN+1]; /*name of a file containing the RNA libraries*/ + + /*List Information*/ + int ne; /*Number of elements in the list*/ + char list_name[1000]; /*Name of the list*/ + int entry_len; /*Size of an entry in el_size*/ + size_t el_size; /*Size of each elements in an entry in bytes*/ + + /*Normalisation information*/ + int normalise; + int max_ext_value; + int max_value; + int overweight; + int filter_lib; + + /*Pair wise alignment method*/ + int pw_parameters_set; + int gop; + int gep; + int f_gop; + int f_gep; + int nm_gop; + int nm_gep; + + int nomatch; + + int TG_MODE; + int F_TG_MODE; + + char dp_mode[FILENAMELEN+1]; + int reverse_seq;//Used for HoT + int extend_seq; //Used for RNA or Promoter Alignments + int maximise; + char matrix_for_aa_group[FILENAMELEN+1]; + char method_matrix[FILENAMELEN+1]; + float diagonal_threshold; + int ktup; + int use_fragments; + int fasta_step; + int lalign_n_top; + int sw_min_dist; + char **matrices_list; + int n_matrices; + char tree_mode[FILENAMELEN+1]; + + char distance_matrix_mode[FILENAMELEN+1]; + char distance_matrix_sim_mode[FILENAMELEN+1]; + + Alignment *tree_aln; + + /*Functions used for dynamic programming and Evaluation*/ + int no_overaln; + /*1 Function for evaluating the cost of a column*/ + Col_cost_func get_dp_cost; + Profile_cost_func profile_mode; + char profile_comparison [FILENAMELEN+1]; + + /*2 Function for evaluating the cost of a pair of residues*/ + Pair_cost_func evaluate_residue_pair; + /*3 Function for making dynamic programming*/ + Pwfunc pair_wise; + + /* + int (*get_dp_cost)(Alignment*, int **, int, int*, int, int **, int, int*, int, struct Constraint_list *); + int (*evaluate_residue_pair)(struct Constraint_list *, int, int, int, int); + int (*pair_wise)(Alignment *, int*, int **,struct Constraint_list *); + */ + + int weight_field; + int max_n_pair; /*maximum number of pairs when aligning two profiles*/ + + /*Extend a sequence against itself*/ + + /*Threading parameters*/ + Blast_param *Prot_Blast; + Blast_param *Pdb_Blast; + Blast_param *DNA_Blast; + /*Split parameters*/ + int split; + int split_nseq_thres; + int split_score_thres; + /*Check Structural Status*/ + int check_pdb_status; + /*log*/ + char method_log[1000]; + char evaluate_mode[1000]; + char method_evaluate_mode[100]; + /*Gene Prediction Parameter*/ + char genepred_score[100]; + + /*Parameters for domain extraction*/ + Moca *moca; + /*Functions for hiding forbiden pairs of residues*/ + int ****forbiden_pair_list; /* pair_list[S1][S2][L1][L2]=1 ->forbiden*/ + /* pair_list[S1][S2][L1][L2]=0 ->allowed*/ + /* pair_list[S1][S2][L1]=NULL ->all pairs S1L1, S2 allowed */ + /* S-> sequences, 0..N */ + /* L-> residues , 1..L-1 */ + + /*extention properties: copy*/ + int *seq_for_quadruplet; + int nseq_for_quadruplet; + + /*extention properties: Do Not copy*/ + int extend_jit; /*Extend only on request*/ + int extend_threshold; /*Do not extend pairs below the Theshold*/ + int do_self; /*Extend a sequence against itself*/ + char extend_clean_mode[100]; + char extend_compact_mode[100]; + + /*Lookup table parameteres*/ + /*!!!!!do not copy in duplication*/ + /*Residue Index contains residue_index[nseq][seq_len][0]->number of links*/ + /*[seq][res][x ]->target seq (0->N-1)*/ + /*[seq][res][x+1]->traget res (1->len*/ + /*[seq][res][x+2]->target weight */ + /*It is automatically recomputed when L residue_indexed is set to 0*/ + int residue_indexed; + int ***residue_index; + int ** freeze; + int residue_field; + + /*Index of the pairs of sequences within L*/ + int seq_indexed; + int **start_index; + int **end_index; + int max_L_len; + int chunk; + + + + /*PDB STRUCTURE ALIGNMENTS*/ + Ca_trace ** T; /*This structure contains the PDB trace for sequences with a known Struc T[Nseq]*/ + + /*MISC*/ + int cpu; + FILE *local_stderr; + char multi_thread[100]; + char lib_list[FILENAMELEN+1]; +}; + +typedef struct Constraint_list Constraint_list; + +struct TC_method +{ + + char executable[FILENAMELEN+1]; + char executable2[FILENAMELEN+1]; + char in_flag[FILENAMELEN+1]; + char in_flag2[FILENAMELEN+1]; + char out_flag[FILENAMELEN+1]; + char aln_mode[FILENAMELEN+1]; + char out_mode[FILENAMELEN+1]; + char seq_type[FILENAMELEN+1]; + char weight[FILENAMELEN+1]; + char matrix[FILENAMELEN+1]; + int gop; + int gep; + int minid; + int maxid; + char param[1000]; + char param1[1000]; + char param2[1000]; + int extend_seq; + int reverse_seq; + Constraint_list *PW_CL; +}; +typedef struct TC_method TC_method; + +/*********************************************************************/ +/* */ +/* PRODUCE IN LIST */ +/* */ +/* */ +/*********************************************************************/ +Constraint_list *produce_list ( Constraint_list *CL, Sequence *S, char * method,char *weight,char *mem_mode); +Job_TC* method2job_list ( char *method, Sequence *S,char *weight, char *lib_list, Distance_matrix *DM, Constraint_list *CL); + +Job_TC *job_list2multi_thread_job_list (Job_TC* ojob, char *mt, Constraint_list *CL); +Job_TC *retrieve_lib_job ( Job_TC *job); +Job_TC *submit_lib_job ( Job_TC *job); +int add_method_output2method_log (char *l, char *command,Alignment *A, Constraint_list *CL, char *iofile); + +int check_seq_type (TC_method *M, char *slist,Sequence *S); +int check_profile_seq_type (Sequence *S, int i, char t); +char **method_list2method4dna_list ( char **list, int n); +int is_in_pre_set_method_list (char *fname); +char *** display_method_names (char *mode, FILE *fp); + +char *method_name2method_file (char *method); +char *make_aln_command(TC_method *m, char *seq, char *aln); +struct TC_method* method_file2TC_method ( char *fname); +char *method_file_tag2value (char *method, char *tag); +int TC_method2method_file( struct TC_method*, char *fname ); +/*********************************************************************/ +/* */ +/* WRITE IN LIST */ +/* */ +/* */ +/*********************************************************************/ +Constraint_list * empty_constraint_list (Constraint_list *CL); +Constraint_list * unfreeze_constraint_list (Constraint_list *CL); +Constraint_list * freeze_constraint_list (Constraint_list *CL); +Constraint_list * undump_constraint_list (Constraint_list *CL, char *file); +int dump_constraint_list (Constraint_list *CL, char *file,char *mode); +int safe_dump_constraint_list (Constraint_list *CL, char *file,char *mode, Sequence *RS); +FILE* display_constraint_list (Constraint_list *CL, FILE *fp, char *tag); + + +Constraint_list *index_constraint_list ( Constraint_list *CL); +Constraint_list *index_res_constraint_list ( Constraint_list *CL, int field); +Constraint_list * progressive_index_res_constraint_list ( Alignment *A, int *ns, int **ls, Constraint_list *CL); +char ** reindex_constraint_list (char **profile, int np,char **list, int *inL, Sequence *S); +/*********************************************************************/ +/* */ +/* ENTRY MANIPULATION */ +/* */ +/* */ +/*********************************************************************/ +Constraint_list * add_list_entry2list (Constraint_list *CL, int n_para, ...); +Constraint_list * evaluate_constraint_list_reference ( Constraint_list *CL); + +int CLisCompacted (Constraint_list *CL, char *t); +int checkCL( Constraint_list *CL, char *t); +Constraint_list *add_entry2list ( CLIST_TYPE *entry, Constraint_list *CL); +Constraint_list *add_entry2list2 ( CLIST_TYPE *entry, Constraint_list *CL); +int *extract_entry (Constraint_list *CL); +/*********************************************************************/ +/* */ +/* LIST EXTENTION */ +/* */ +/* */ +/*********************************************************************/ +Constraint_list *extend_list_pair (Constraint_list *CLin,char *store_mode, int s1, int s2); +Constraint_list *extend_list (Constraint_list *CLin, char *store_mode,char *clean_mode, char *compact_mode,int do_self, Sequence *SUBSET); +void get_bounds (Constraint_list *CL, int s1, int s2, int *start, int *end); +int ** fill_pos_matrix (Constraint_list *CL, int beg, int end, int slen, int **pos, int *len, int mirrored); + +/*********************************************************************/ +/* */ +/* SEARCH IN LIST (ARRAY AND FILE) */ +/* */ +/* */ +/*********************************************************************/ +FILE * compare_list (FILE *OUT, Constraint_list *CL1,Constraint_list *CL2); +//CLIST_TYPE *search_in_list_constraint(int *key, int k_len, int **L, int ne, int ***start_index, int ***end_index); +CLIST_TYPE *main_search_in_list_constraint ( int *key,int *p,int k_len,Constraint_list *CL); +Constraint_list *sort_constraint_list_inv (Constraint_list *CL, int start, int len); +Constraint_list *invert_constraint_list (Constraint_list *CL, int start,int len); +Constraint_list * sort_constraint_list (Constraint_list *CL, int start, int len); +Constraint_list * sort_constraint_list_on_n_fields (Constraint_list *CL, int start, int len, int first_field, int n_fields); + +/*********************************************************************/ +/* */ +/* INPUT/OUTPUT */ +/* */ +/* */ +/*********************************************************************/ +Constraint_list* read_n_constraint_list(char **fname,int n_list, char *in_mode,char *mem_mode,char *weight_mode,char *type, FILE *local_stderr, Constraint_list *CL, char *seq_source); +Constraint_list* read_constraint_list(Constraint_list *CL,char *fname,char *in_mode,char *mem_mode,char *weight_mode); +Constraint_list * read_constraint_list_raw_file(Constraint_list *CL, char *fname); + +int read_cpu_in_n_list(char **fname, int n); +int read_seq_in_list ( char *fname, int *nseq, char ***sequences, char ***seq_name); + +Sequence * read_seq_in_n_list(char **fname, int n, char *type, char *SeqMode); + +int read_cpu_in_list ( char *fname); +int ** read_list ( char *fname, int **list,int *ne, int *nseq, int *cpu, char ***sequences, char ***seq_name); + +char * expand_constraint_list_file ( char *file); +Constraint_list * read_constraint_list_file(Constraint_list *CL, char *fname); +Constraint_list * fast_read_constraint_list_file(Constraint_list *CL, char *fname); + +/*********************************************************************/ +/* */ +/* EXTENDED LIST OUTPUT */ +/* */ +/* */ +/*********************************************************************/ +FILE * save_extended_constraint_list ( Constraint_list *CL, char *mode, FILE *fp) ; +FILE * save_extended_constraint_list_pair ( Constraint_list *CL, char *mode, char* seq1, char * seq2,FILE *fp); + +/*********************************************************************/ +/* */ +/* LIST OUTPUT */ +/* */ +/* */ +/*********************************************************************/ +int constraint_list2raw_file ( Constraint_list *CL, char *fname, char *fmode); +FILE * save_raw_constraint_list ( FILE *fp,Constraint_list *CL, int start,int len, int *translation); +FILE * save_constraint_list ( Constraint_list *CL,int start, int len, char *fname, FILE *fp,char *mode,Sequence *S); +FILE * save_sub_list_header ( FILE *OUT, int n, char **name, Constraint_list *CL); +FILE * save_list_header ( FILE *OUT,Constraint_list *CL); +FILE * save_list_footer (FILE *OUT,Constraint_list *CL); +FILE * save_constraint_list_ascii ( FILE *OUT,Constraint_list *CL, int start,int len, int *translation); +FILE * save_constraint_list_bin ( FILE *OUT,Constraint_list *CL, int start,int len, int *translation); + +/*********************************************************************/ +/* */ +/* LIST CONVERTION */ +/* */ +/* */ +/*********************************************************************/ +Constraint_list * expand_constraint_list (Constraint_list *CL, int T); +Constraint_list * shrink_constraint_list_indexed (Constraint_list *CL, int T); +Constraint_list * shrink_constraint_list (Constraint_list *CL); +Constraint_list * extend_constraint_list ( Constraint_list *CL); +Constraint_list * relax_constraint_list (Constraint_list *CL); +Constraint_list * relax_constraint_list_4gp (Constraint_list *CL); + +Constraint_list * expand_constraint_list_4gp (Constraint_list *CL, int T); + +Constraint_list * filter_constraint_list (Constraint_list *CL, int field, int T); +int constraint_list_is_connected ( Constraint_list *CL); +int constraint_list2avg ( Constraint_list *CL); +float constraint_list2connectivity ( Constraint_list *CL); + +int constraint_list2fraction_covered ( Constraint_list *CL); + +int *seqpair2weight (int s1, int s2, Alignment *A,Constraint_list *CL, char *weight_mode, int *weight); +Constraint_list *aln_file2constraint_list (char *alname, Constraint_list *CL,char *weight_mode); +Constraint_list *aln2constraint_list (Alignment *A, Constraint_list *CL,char *weight_mode); + +double **list2mat (Constraint_list *CL,int s1,int s2, double *min, double *max); +Constraint_list * constraint_list2bin_file(Constraint_list *clist); +FILE * bin_file2constraint_list ( Constraint_list *CL, FILE *fp, char *name); + +int **list2residue_total_weight ( Constraint_list *CL); +int **list2residue_total_extended_weight ( Constraint_list *CL); +int **list2residue_partial_extended_weight ( Constraint_list *CL); +/*******************************************************************************************/ +/* */ +/* */ +/* clean functions */ +/* */ +/* */ +/* */ +/*******************************************************************************************/ +Constraint_list *clean ( char *clean_mode,Constraint_list *C,int start, int len); +Constraint_list * clean_shadow ( Constraint_list *CL, int start, int len); + +/*********************************************************************/ +/* */ +/* LIST FUNCTIONS */ +/* */ +/* */ +/*********************************************************************/ +Constraint_list *merge_constraint_list ( Constraint_list *SL, Constraint_list *ML, char *mode); +CLIST_TYPE return_max_constraint_list ( Constraint_list *CL, int field); +Constraint_list *modify_weight( Constraint_list *CL,int start, int end, char *modify_mode); +Constraint_list *compact_list (Constraint_list *CL, char *compact_mode); +Constraint_list *rescale_list_simple (Constraint_list *CL,int start, int len,int new_min, int new_max); +Constraint_list *rescale_list (Constraint_list *CL,int start, int len,int max1, int max2); +Constraint_list* filter_list (Constraint_list *CL, int start, int len,int T); +Constraint_list *undefine_list (Constraint_list *CL); +int ** seq2defined_residues ( Sequence *S, Constraint_list *CL); +int ** aln2defined_residues ( Alignment *A, Constraint_list *CL); +/*********************************************************************/ +/* DEBUG */ +/* */ +/*********************************************************************/ +void print_CL_mem(Constraint_list *CL, char *function); +int constraint_list_is_sorted ( Constraint_list *CL); +void check_seq_pair_in_list(Constraint_list *CL,int seq1, int seq2); +/******************************************************************/ +/* NEW METHODS */ +/* */ +/* */ +/******************************************************************/ + +Constraint_list * align_coding_nucleotides (char *seq, char *method, char *weight, char *mem_mode, Constraint_list *CL); +/*********************************************************************************************/ +/* */ +/* FUNCTION FOR PRUNING THE LIST */ +/* */ +/*********************************************************************************************/ +char * list2prune_list (Sequence *S, int **sm); +/*********************************************************************************************/ +/* */ +/* FUNCTION FOR WEIGHTING THE LIST */ +/* */ +/*********************************************************************************************/ +Constraint_list *weight_constraint_list(Constraint_list * CL, char *seq_weight); +Weights* compute_t_coffee_weight(Constraint_list * CL); +Constraint_list *re_weight_constraint_list(Constraint_list * CL,Weights *W); +Constraint_list *set_weight4constraint_list(Constraint_list * CL,int w); + +Distance_matrix *cl2distance_matrix (Constraint_list *CL, Alignment *A, char *mode, char *sim_mode, int print); +Distance_matrix *seq2distance_matrix (Constraint_list *CL, Alignment *A, char *mode, char *sim_mode, int print); + +/*********************************************************************************************/ +/* */ +/* MULTI_THREAD */ +/* */ +/*********************************************************************************************/ +int run_multi_thread_file (char *fname, char *config); +/*********************************************************************/ +/* */ +/* RNA FUNCTIONS */ +/* */ +/* */ +/*********************************************************************/ +char * seq2rna_lib ( Sequence *S, char *name); +Constraint_list *read_rna_lib ( Sequence *S, char *fname); +Constraint_list *rna_lib_extension ( Constraint_list *CL, Constraint_list *R); +char *** produce_method_file ( char *method); +typedef struct + { + int p1; + int p2; + int p3; + int p4; + int t; + int f; + char mode[20];//lower, unalign + char model[20];//fsa1 fsa2 +} +OveralnP; + +//RNA + +int ** alifold_list2cov_list (Alignment *A, int **list); +int ** update_RNAfold_list (Alignment *A, int **pos, int s, int **l); +int ** vienna2list ( char *seq); +Alignment *compare_RNA_fold ( Alignment *A, Alignment *B); + +Alignment *alifold2analyze (Alignment *A, Alignment *ST, char *mode); +Alignment *alifold2cov_aln (Alignment *A, int **l, int ug); +Alignment *alifold2cov_stat (Alignment *A, int **l, int ug); +Alignment *alifold2cov_list (Alignment *A, int **l, int ug); +Alignment *alifold2cov_cache (Alignment *inA, int **l, int ug); + + +Alignment *add_alifold2aln (Alignment *A, Alignment *ST); +Alignment *aln2alifold(Alignment *A); + +//end +Alignment * aln2bootstrap (Alignment *A, int n); +Alignment * aln2sample (Alignment *A, int n); +Alignment * aln2random_aln (Alignment *A, char *mode); +Alignment *aln2scale (Alignment *A, char *offset); +Alignment* aln2case_aln (Alignment *A, char *upper, char *lower); +Alignment*aln2gap_cache (Alignment *A, int val); +Alignment *score_aln2score_ascii_aln (Alignment *A, Alignment *C); +int **aln2resindex ( Alignment *A, Alignment *B, FILE *fp); +int **index_seq_res ( Sequence *S1, Sequence *S2, int **name_index); +int **index_seq_name ( Sequence *S1, Sequence *S2); +int *get_name_index (char **l1, int n1, char **l2, int n2); + +int* get_res_index (char *seq1, char *seq2); +int * pos2list (int * pos, int len, int *nl); + int *list2pos (int *list, int nl, int len); + + +int change_residue_coordinate ( char *in_seq1, char *in_seq2, int v); + +int ** minimise_repeat_coor (int **coor, int nseq, Sequence *S); +int ** get_nol_seq( Constraint_list *CL,int **coor, int nseq, Sequence *S); + + +int compare_pos_column( int **pos1,int p1, int **pos2,int p2, int nseq); + + + +char * seq2alphabet (Sequence *S); +char *aln2alphabet (Alignment *A); +char *array2alphabet (char **array, int n, char *forbiden); + +//TM Predictions +char* alnpos2hmmtop_pred (Alignment *A, Alignment *Pred, int pos, int mode); +Alignment * aln2hmmtop_pred (Alignment *A); +char * seq2tmstruc ( char *seq); + +char * set_blast_default_values(); +char * seq2pdb ( Sequence *S); +Alignment * seq2blast ( Sequence *S); + +Sequence * seq2unique_name_seq ( Sequence *S); +Alignment * aln2unique_name_aln ( Alignment *S); +int name_list2unique_name_list (int n, char **name); +Sequence *seq2clean_seq ( Sequence *S, char *alp);//remove all alp characters from seq +char**gene2exons (char **seq, int nseq); + +int ** seq2aln_pos (Alignment *A, int *n, int **ls); +Alignment *padd_aln ( Alignment *A); +char **padd_string ( char **string, int n,char pad); + +Alignment *local_maln2global_maln (char *seq, Alignment *A); + +Alignment * seq2profile (Sequence *S, int index); + +Sequence *remove_empty_sequence (Sequence *S); +Alignment * aln2profile (Alignment * A); +Alignment * aln2collapsed_aln (Alignment * A, int n, char **string); +Alignment* remove_seq_from_aln (Alignment *A, char *seq); + +Alignment* aln2sub_aln_file (Alignment *A, int n, char **string); +Alignment* aln2sub_seq (Alignment *A, int n, char **string); + +int ** aln2inv_pos (Alignment *A); +int * seq2inv_pos ( char *seq); +int ** aln2pos_simple (Alignment *A, int n_nseq, ...); +int ** aln2pos_simple_2 (Alignment *A); +Alignment ** split_seq_in_aln_list ( Alignment **aln, Sequence *S, int l_seq, char **seq_list); + +Sequence * fill_sequence_struc ( int nseq, char **sequences, char **seq_name); + +int seq_list2in_file ( TC_method *M, Sequence *S, char *list, char *file); +int seq_list2fasta_file( Sequence *S, char *list, char *file, char *outmode); +Structure * seq2struc ( Sequence *S, Structure *ST); +Alignment *strings2aln (int nseq,...); + +Alignment * seq2aln ( Sequence *S, Alignment *A,int rm_gap); +Alignment *seq_coor2aln ( Sequence *S, Alignment *A, int **coor, int nseq); + +Alignment *stack_aln (Alignment *A, Alignment *B); +Alignment *chseqIaln(char *name, int seq_n, int start,int len,Sequence *S, int seqIaln, Alignment *A); + + +char *dna_aln2cons_seq ( Alignment *A); +char *aln2cons_seq ( Alignment *A, int ns, int *ls, int n_groups, char **group_list); +char *aln2cons_maj ( Alignment *A, int ns, int *ls, int n_groups, char **group_list); +Alignment *aln2conservation ( Alignment *A, int threshold,char *seq); + +char *sub_aln2cons_seq_mat ( Alignment *A,int ns, int *ls, char *mat_name); +char *aln2cons_seq_mat ( Alignment*A, char *mat_name); +Alignment *aln2short_aln( Alignment *A, char *list, char *new, int spacer); +Sequence *keep_residues_in_seq ( Sequence *S,char *list, char replacement); +Alignment *keep_residues_in_aln ( Alignment *A,char *list, char replacement); +Alignment *filter_keep_residues_in_aln ( Alignment *A,Alignment *ST, int use_cons, int value, char *list, char replacement); + +Alignment *aln_convert (Alignment *A, Alignment *ST, int use_cons, int value,int n, ...); +Alignment *aln2number (Alignment *A); +Alignment * filter_aln ( Alignment *A, Alignment *ST, int value); +Alignment * filter_aln_lower_upper ( Alignment *A, Alignment *ST,int use_cons, int value); +Alignment * filter_aln_upper_lower ( Alignment *A, Alignment *ST, int use_cons,int value); +Alignment * filter_aln_switchcase ( Alignment *A, Alignment *ST, int use_cons, int value); + +Alignment * STseq2STaln ( Alignment *A, Alignment *ST); +Alignment * merge_annotation ( Alignment *A, Alignment *ST, char *seq); +Alignment * filter_aln_convert ( Alignment *A, Alignment *ST, int use_cons,int value, int n_symbol,char** symbol_list); +int aln2ngap (Alignment *A); + +int * count_in_aln ( Alignment *A, Alignment *ST, int value, int n_symbol,char **symbol_list, int *table); +void count_misc (Alignment*A, Alignment *B); + +Alignment * trim_aln_with_seq ( Alignment *S, Alignment *P); +Alignment * add_align_seq2aln ( Alignment *A, char *seq, char *seq_name); +Sequence * aln2seq ( Alignment *A); +Sequence * aln2seq_main ( Alignment *A, int mode); +Alignment * thread_profile_files2aln (Alignment *A, char *template_file, Fname *F); +Alignment * expand_aln (Alignment *A); +Alignment * aln2expanded_aln (Alignment *A); +Alignment * expand_number_aln (Alignment *A,Alignment *EA); +Alignment * remove_gap_column ( Alignment *A, char *mode); +Alignment* ungap_sub_aln ( Alignment *A, int nseq, int *ls); +Sequence * ungap_seq ( Sequence *A); +Alignment * insert_gap_col (Alignment *A, int p, int l); +Alignment * unalign_residues (Alignment *A, int i1, int i2); +Alignment * unalign_aln_2 (Alignment *A, Alignment *C, int t); +Alignment * unalign_aln (Alignment *A, Alignment *C, int t); +Alignment * unalign_aln_pos (Alignment *A, int s, int p, int l); + +Alignment *degap_aln (Alignment *A); + +Alignment * ungap_aln_n ( Alignment *A, int n); +Alignment * ungap_aln ( Alignment *A); +void compress_aln ( Alignment *A); +Alignment* condense_aln (Alignment *A); + +Alignment * probabilistic_rm_aa ( Alignment *A, int pos, int len); +Alignment * aln_gap2random_aa(Alignment *A); +Alignment * make_random_aln(Alignment *A,int nseq, int len, char *alphabet); +Alignment * add_random_sequence2aln( Alignment *A, char *alphabet); + +int ** trim_aln_borders ( char **seq1, char **seq2, int nseq); +Sequence * trim_aln_seq ( Alignment *A, Alignment *B); +Sequence * trim_aln_seq_name ( Alignment *A, Alignment *B); +Sequence *get_defined_residues( Alignment *A); + + +Alignment *thread_defined_residues_on_aln ( Alignment *A, Sequence *S1); +Sequence *seq2number (Sequence *S); +Sequence * merge_seq ( Sequence *IN, Sequence *OUT); +char * seq_name2coor ( char *s, int *start, int *end, char sep); +Alignment *seq_name2removed_seq_name(Sequence *S, Alignment *NA, float **diff); +int seq_name2index (char *name, Sequence *S); + +Sequence *extract_one_seq(char *n,int start, int end, Alignment *S,int keep_name); +Sequence * extract_sub_seq( Sequence *COOR, Sequence *S); + + +Sequence * add_prf2seq (char *alnfile, Sequence *S); +int prf_in_seq ( Sequence *S); +Sequence * add_sequence ( Sequence *IN, Sequence *OUT, int i); +Sequence * trim_seq ( Sequence *A, Sequence *B); +Sequence * reorder_seq ( Sequence *A, char **name, int nseq); +Sequence * reorder_seq_2 ( Sequence *A, int **name,int field, int nseq); + +char * concatenate_seq ( Sequence *S, char *conc, int *order); +Sequence * swap_header ( Sequence *S, Sequence *H); + +Alignment *aln2jacknife (Alignment *A, int nseq, int len); +char ** name2random_subset (char **in_name, int n_in, int n_out); +Alignment * aln2random_order ( Alignment *A); +Alignment * aln2scramble_seq ( Alignment *A); + +Alignment * reorder_aln ( Alignment *A, char **name, int nseq); + +char ** rm_name_tag (char **name, int nseq, char *tag); + +/******************************************************************************/ +/* TEMPLATE MANAGEMENENT */ +/******************************************************************************/ +char * string_contains_template_tag (char *string); +Sequence * seq2template_type(Sequence *Seq); + +Sequence * vremove_seq_template_files (Sequence *S); +Sequence * display_seq_template_files (Sequence *S); +Sequence * handle_seq_template_file (Sequence *S, char *mode); +int handle_X_template_files ( X_template *T, char *mode); + + +Sequence * seq2template_seq ( Sequence *S, char *template_file, Fname *F); +char * seq2template_file (Sequence *S, char *file); +int seq2template_file2 (Sequence *S, char *file, char *mode); + +Sequence * profile_seq2template_seq ( Sequence *S, char *template_file, Fname *F); +int seq2n_X_template ( Sequence *S, char *type); + +struct X_template *fill_X_template (char *name, char *p, char *type); +FILE * display_seq_template (Sequence *S, FILE *io); +char *template_type2type_name (char *type); +char *template_type2short_type_name (char *type); + + +FILE * display_sequence_templates ( Sequence *S, int i, FILE *io); +FILE * display_X_template (struct X_template *X, FILE *io); + +struct X_template* free_X_template ( struct X_template *X); + +struct X_template *fill_P_template (char *name, char *p, Sequence *S); +struct X_template *fill_F_template (char *name, char *p, Sequence *S); +struct X_template *fill_S_template ( char *name,char *p, Sequence *S); +struct X_template *fill_R_template (char *name, char *p, Sequence *S); +struct X_template *fill_G_template (char *name, char *p, Sequence *S); +struct X_template *fill_T_template (char *name, char *p, Sequence *S); +struct X_template *fill_E_template (char *name, char *p, Sequence *S); +struct X_template *fill_U_template (char *name, char *p, Sequence *S); + +char *seq2T_value ( Sequence *S, int i, char *param_name, char *template_type); +char *profile2P_template_file (Sequence *S, int n); +Alignment * seq2R_template_profile (Sequence *S, int n); +char *seq2P_pdb_id (Sequence *S, int n); +char * seq2P_template_file (Sequence *S, int n); +char * seq2T_template_string (Sequence *S, int n); +char * seq2E_template_string (Sequence *S, int n); +int * seq2U_template (Sequence *S, int n); + +struct X_template * seq_has_template ( Sequence *S, int n, char *type); + +/******************************************************************************/ +/* ALIGNMENT MANIPULATION */ +/******************************************************************************/ + +char *aln_column2string (Alignment *A, int p); +int **fix_seq_aln (Sequence *S, Alignment*A, int **cache); +int **fix_seq_seq ( Sequence *S1, Sequence *S2); +int **fix_aln_seq_new (Alignment *S1, Sequence *S2); + +Alignment * fix_aln_seq ( Alignment *A, Sequence *S); +Alignment * rotate_aln ( Alignment *A, char *name); +Alignment * invert_aln ( Alignment *A); +char * complement_string (char *s); +Alignment * complement_aln ( Alignment *A); +Alignment * extract_nol_local_aln( Alignment *A, int start, int max_end); +Alignment * aln2block (Alignment *A, int start, int end, Alignment *B); +Alignment * alnpos2block (Alignment *A, int*pos, Alignment *B); + +Alignment * extract_aln ( Alignment *A, int start, int end); +Alignment * extract_aln2 ( Alignment *A, int start, int end, char *seq_name); +Alignment * extract_aln3 ( Alignment *A, char *filename); +Alignment * alnpos_list2block (Alignment *A, int n, char **in_list); + +Alignment * trunkate_local_aln ( Alignment *A); +int get_nol_aln_border ( Alignment *A, int start, int direction); +Alignment ** trim_local_aln ( Alignment *A, int **List, int ne, int **residue_list, Sequence *S); + +Alignment * aln_cat ( Alignment *A, Alignment *B); +Alignment * concatenate_aln ( Alignment *A, Alignment *B, char *sep); +char * extract_defined_seq ( char *in, int in_of, int in_start, int *aa_def, int dir, int *out_start, char *out_seq); +int verify_aln ( Alignment *A, Sequence *S, char * error); +Alignment * remove_end (Alignment *A); +Alignment * orthologous_concatenate_aln (Alignment *A, Sequence *S, char *mode); +Alignment * aln2N_replicate (Alignment *A, char *nn, char *name); +FILE *aln2replicate (Alignment *A, FILE *fp); + +Alignment * voronoi_concatenate_aln (Alignment *A, Sequence *S); + +Alignment *adjust_est_aln ( Alignment *PW, Alignment *M, int s); +Alignment * rename_seq_in_aln (Alignment *A, char ***list); +Sequence * rename_seq_in_seq (Sequence *A, char ***list); +/********************************************************************/ +/* */ +/* FLOAT SIMILARITIES */ +/* */ +/* */ +/* */ +/********************************************************************/ +float get_seq_fsim ( char *string1, char *string2, char *ignore, char *similarity_groups, int **matrix, int mode); +float get_seq_fsim2 ( char *string1, char *string2, char *ignore, char *in_mode); +float ** get_fsim_aln_array ( Alignment *A, char *mode); +/********************************************************************/ +/* */ +/* ALIGNMENT ANALYSES */ +/* */ +/* */ +/* */ +/********************************************************************/ +int **sim_array2dist_array ( int **p, int max); +int **dist_array2sim_array ( int **p, int max); +int **normalize_array (int **p, int max, int norm); + +int aln2most_similar_sequence ( Alignment *A, char *mode); +int aln2coverage ( Alignment *A, int ref_seq); + +double aln2entropy (Alignment *A, int *in_ls, int in_ns, float gap_threshold); +int sub_aln2sim ( Alignment *A, int *ns, int **ls, char *mode); +int sub_aln2max_sim ( Alignment *A, int *ns, int **ls, char *mode); +int aln2sim ( Alignment *A, char *mode); +int seq2idscore_sim ( char *seq1, char *seq2); + +int aln_is_aligned ( Alignment *A); +int* get_cdna_seq_winsim ( int *cache, char *string1, char *string2, char *ignore, char *mode, int *w); +int get_cdna_seq_sim ( int *cache, char *string1, char *string2, char *ignore, char *mode); + +int seq2aln2sim (char *seq1, char *seq2, char *mode_aln, char *mode_id); +int* get_seq_winsim( char *string1, char *string2, char *ignore, char *mode, int *w); +int get_seq_sim ( char *string1, char *string2, char *ignore, char *mode); +int get_seq_sim_2 ( char *string1, char *string2, char *ignore, char **gr, int ng); +int get_seq_sim_3 ( char *string1, char *string2, char *ignore, int **mat); + + +int *** get_winsim_aln_array ( Alignment *A, char *mode, int ***w); +int ** get_sim_master_aln_array ( Alignment *A,int n, char *mode); + +int ** seq2sim_mat (Sequence *S, char *mode); +int ** seq2cov_mat (Sequence *S, char *mode); +int ** seq2comp_mat (Sequence *S, char *mode, char *comp_mode); + +int logid_score (int sim, int len); +int ** fast_aln2sim_mat (Alignment *A, char *mode); +int ** fast_aln2sim_list (Alignment *A, char *mode, int *ns, int **ls); + +int ** aln2sim_mat (Alignment *A, char *mode); +int **aln2cov (Alignment *A); +int ** get_dist_aln_array ( Alignment *A, char *mode); +int ** get_raw_sim_aln_array ( Alignment *A, char *mode); +int ** get_sim_aln_array ( Alignment *A, char *mode); +int generic_get_seq_sim ( char *seq1, char *seq2, int *cache, char *mode); +Alignment * grep_seq (Alignment *S,char *field, char *mode, char *string); +Alignment* modify_seq (Alignment *S,char *field, char *string1, char *string2); + +Sequence * seq2filter (Sequence *S_in, int min, int max); +int ** get_cov_aln_array ( Alignment *A, char *mode); +int ** get_cov_master_aln_array ( Alignment *A,int n, char *mode); + + +int * get_aln_col_weight ( Alignment *A, char *mode); +int analyse_aln_column ( Alignment *B, int col); + +int sub_aln2nseq_prf ( Alignment *A, int ns, int *ls); +int **aln2count_mat (Alignment *A); +int **sub_aln2count_mat2 (Alignment *A, int ns, int *ls); +int **sub_aln2count_mat3 (char **al, int n); +int **aln2count_mat2 (Alignment *A); +char *aln2random_seq (Alignment *A, int noise1, int noise2, int noise3, int gap_noise); + +Alignment * master_trimseq( Alignment *A, Sequence *S,char *mode); +Alignment * trimseq( Alignment *A, Sequence *S, char *mode); +Alignment *simple_trimseq (Alignment *A,Alignment*K, char *mode, char *seq, int **sim); +Alignment *sim_filter (Alignment *A, char *in_mode, char *seq_list); + +Sequence * seq_weight2species_weight (Alignment *A, Sequence *S); +Alignment * aln2voronoi_weights (Alignment *A); +float ** get_weight ( Alignment *A, Sequence *S, char *mode); +float **seq2pwsim ( Alignment *A, Sequence *S, char *mode); +Alignment * trimseq( Alignment *A, Sequence *S,char *mode); +Alignment * tc_trimseq( Alignment *A, Sequence *S,char *mode); +Alignment* seq2subseq3( Alignment *A, Sequence *S,int use_aln, int lower_sim,int upper_sim, int min_nseq, int trim_direction, char *weight_mode, float ***sim_weight, int *seq_list); +Alignment* seq2subseq2( Alignment *A, Sequence *S,int use_aln, int lower_sim,int upper_sim, int max_nseq, int trim_direction, char *weight_mode, float ***weight_table, int *seq_list); +float extreme_seq (int direction, Alignment *A,float **sim_weight,int *seq_list, int *seq_index); + + +Alignment* seq2subseq1( Alignment *A, Sequence *S,int use_aln, int percent,int max_nseq,int max_diff, char *weight_mode); +/********************************************************************/ +/* */ +/* AMINO ACID FUNCTIONS */ +/* */ +/* */ +/* */ +/********************************************************************/ +char** string2alphabet (char *string, int depth, int *falp_size); +int is_in_same_group_aa ( char r1, char r2, int n_group, char **gl, char *mode); +int find_group_aa_distribution (char *col, int nseq,int n_group, char **gl, int *distrib, char *mode ); +char** make_group_aa (int *ngroup, char *mode); +char** make_group_aa_upgma (char *mat, int max_size); + + +char * test_gene2prot (Constraint_list *CL, int s1); +Alignment* gene2prot (Alignment *A); +Alignment * dna_aln2_3frame_cdna_aln(Alignment *A,int *ns,int **l_s); + +int ** get_sim_aln_array_normal_distribution ( Alignment *A, char *mode, int *STD, int *CENTER); +double normal(double x, double mean, double std); +int generic_get_seq_sim_normal_distribution ( char *seq1, char *seq2, int*cache, char *mode, int *STD, int *CENTER); +int get_seq_sim_distribution ( char *string1, char *string2, char *ignore, char *in_mode, int *STD, int *CENTER); + +Alignment *aln2clean_pw_aln (Alignment *A,OveralnP *F); +char **pw_aln2clean_pw_aln (char ** aln,OveralnP *F); +int * pw_aln2clean_aln_weight ( char *seq1, char *seq2, int w, OveralnP *F); + +float* aln2pred ( Alignment *A, Alignment*B, char *mode); +float* analyze_overaln ( Alignment *A, Alignment *B, char *mode, int f,int p1,int p2, int p3,int filter); + + +Alignment * mark_exon_boundaries (Alignment *A, Alignment *E); + +struct orp +{ + char name[100]; + char mode[100]; + int ncomp; + int nseq; + int len; + + Alignment *A; + Alignment *P; + Alignment *S; + + int *pos; + char ***motif; + float sp; + float sn; + float sen2; + float best; + int tp; + int tn; + int fp; + int fn; + + int offset; + float evalue; + struct orp *PR; +}; + +typedef struct orp ORP; + +typedef Alignment * (*filter_func) (Alignment *, Alignment*, int,int, char *); +/************************************************************************************/ +/* ALIGNMENT ANALYZE : SAR */ +/************************************************************************************/ +int display_simple_sar_analyze_pair_col (Alignment *A, Alignment *SAR, char *mode); +int **simple_sar_analyze_pair_col ( Alignment *inA, Alignment *SAR, char *mode); +int ***simple_sar_predict ( Alignment *inA, Alignment *SAR, char *mode); +int display_simple_sar_analyze_col ( Alignment *inA, Alignment *SAR, char *mode); +Alignment *sar_analyze4 (Alignment *A, Alignment *SAR, char *name);/*28/08/06*/ +Alignment *sar_analyze3 (Alignment *A, Alignment *SAR, char *name); +Alignment *sar_analyze2 (Alignment *A, Alignment *SAR, char *name); +Alignment *sar_analyze (Alignment *A, Alignment *SAR, char *name); +int aln2sar_column_list ( Alignment *A, char *filter); +float get_sar_sim (char *seq1, char *seq2); +float get_sar_sim2 (char *seq1, char *seq2); +Alignment *aln2weighted_sar_score ( Alignment *A,Alignment *B, char *weight_file, char *compound); +float seq2weighted_sar_score ( char *seq, int **weight); + +int sarset2subsarset ( Alignment *A, Alignment *S, Alignment **subA, Alignment **subS, Alignment *SUB); +int sar2subsar (Alignment *A, Alignment *S, Alignment **subA, Alignment **subS, char **slist, int nl); +int sar2subsar_file ( Alignment *A, Alignment *S, char *aln, char *sar); + +Alignment *weight2sar (Alignment *A, Alignment *SAR, char *weight_file, int limit); +Alignment * sar2simpred (Alignment *A, Alignment *SAR, char *pos, char *compound, int L,int U ); +Alignment * sar2simpred2 (Alignment *A, Alignment *SAR, char *seqlist, char *posfile, char *compound, int L1 ); + +Alignment *display_sar ( Alignment *A, Alignment *SAR, char *compound); +NT_node sar2tree (Alignment *A, char *mode); +/************************************************************************************/ +/* ALIGNMENT ANALYZE : SAR FOR OR */ +/************************************************************************************/ + +Alignment * or_scan (Alignment *A, Alignment *B, char *param); +Alignment * or_sar (Alignment *A, Alignment *B, char *param, int print); +ORP * or_loo ( Alignment *inA, Alignment *inS, char *mode, int *pos,int print); + + +ORP * combine_n_predictions (ORP **R,Alignment *A, Alignment *B); +ORP* combine_2_predictions ( ORP *IN, ORP *TO,Alignment *A, Alignment *B); +ORP * display_or_summary (ORP *CP, char *mode, FILE *fp, int print); + +Alignment * or_comp_loo ( Alignment *inA, Alignment *inS, char *mode, int *pos,int print); +int * or_comp_pos ( Alignment *inA, Alignment *inS, char *mode,int print); +float or_id_evaluate ( Alignment *A, Alignment *S, char *mode, int *pos, int print); +char* or_id_evaluate2 ( Alignment *A, Alignment *S, char *mode, int *pos, int print, float *score); +float or_loo_evaluate ( Alignment *A, Alignment *S, char *mode, int *pos, int print); +float or_loo_evaluate2 ( Alignment *A, Alignment *S, char *mode, int *pos, int print); + +Alignment * or_test ( Alignment *inA, Alignment *inS, char *mode); +Alignment * or_jack(Alignment *A, Alignment *S, char *param); +Alignment * or_predict(Alignment *A, Alignment *S, char *mode); +Alignment * or_aln2pos_aln (Alignment *A, Alignment *S, char *mode); +ORP* or_self_predict(Alignment *inA, Alignment *inS, char *mode, int *pos, int print); +Alignment * or_sim(Alignment *A, Alignment *S, char *mode); + +Alignment *display_pos (Alignment *A, Alignment *B, int *pos, char *mode); + +float evaluate_prediction (Alignment *R, Alignment *P, char *mode, int print); +ORP* new_evaluate_prediction (ORP *P, char *mode, int print); + +Alignment * aln2prediction (Alignment *A,char ***motif, int *pos); +int * aln2predictive_positions (Alignment *A, Alignment *B, char *mode, int print); +int * aln2predictive_positions_mat (Alignment *A, Alignment *B, char *mode, int print); +int * aln2predictive_positions_scan (Alignment *A, Alignment *B, char *mode, int print); +char *** compounds2motifs (Alignment *A, Alignment *B, int *pos, int depth, char *mode, int print); +char ** compound2motif (Alignment *A, Alignment *B, int *pos, int depth, int c, char *mode, int print); +double pos2sim (Alignment *A, Alignment *B, int *pos); +double sar_aln2r (Alignment *A, Alignment *B, int *pos, int print); +double sar_aln2delta (Alignment *A, Alignment *B, int *pos, int print); +Alignment * jack_sar(Alignment *A, Alignment *S, char *param); +Alignment *set_sar (Alignment *A, Alignment *S, char *param); +char * get_compound_name (int c, char *mode); +Alignment *get_prediction_target (Alignment *A, Alignment *S, char *param); +int * file2pos_list (Alignment *A, char *posfile); +ORP * declare_or_prediction ( int ncomp, int nseq, int len); +void free_orp_list ( ORP**P); +void free_orp ( ORP*P); +double evaluate_sar_score1 ( int len, int n11, int n1a, int n1b); +double evaluate_sar_score2 ( int len, int n11, int n1a, int n1b); + +Sequence * compare_sar_sequence( Sequence *S1, Sequence *S2, int depth); +Constraint_list * mask_list_with_aln (Alignment *A,int start, int len,Constraint_list *CL, int new_value); +Constraint_list* mask_list_with_aln_pair (Alignment *A,int start, int end,Constraint_list *CL,int new_value); +Constraint_list *mask_entry( Constraint_list *CL, int p, int new_value); +Constraint_list *prepare_list_and_seq4sw(Constraint_list *I, int n_seq, char **seq_name); +int ** get_undefined_list (Constraint_list *CL); +int is_never_undefined (Constraint_list *CL,int r); +int* do_analyse_list ( Constraint_list *CL); + + + +void print_list(Constraint_list *CL); +void print_pair (Constraint_list *CL,int p); +int** bin_list (Constraint_list *CL,int field, int Threshold); +void save_full_list (Constraint_list *CL, char*fname); +FILE * output_list ( Constraint_list *CL, FILE *fp); +FILE * output_pair (Constraint_list *CL,int p, FILE *fp); +NT_node ** seq2cw_tree ( Sequence *S, char *file); +NT_node ** make_nj_tree ( Alignment *A,int **distances,int gop, int gep, char **out_seq, char **out_seq_name, int out_nseq, char *tree_file, char *tree_mode); +NT_node ** make_upgma_tree ( Alignment *A,int **distances,int gop, int gep, char **out_seq, char **out_seq_name, int out_nseq, char *tree_file, char *tree_mode); + +NT_node ** int_dist2nj_tree (int **distances, char **out_seq_name, int out_nseq, char *tree_file); +NT_node ** float_dist2nj_tree (float **distances, char **out_seq_name, int out_nseq, char *tree_file); +NT_node ** dist2nj_tree (double **distances, char **out_seq_name, int out_nseq, char *tree_file); + +NT_node ** int_dist2upgma_tree (int **mat, Alignment *A, int nseq, char *fname); +NT_node upgma_merge (int **mat, NT_node *NL, int *used, int *n, int N); + +void nj_tree(char **tree_description, int nseq); +void fast_nj_tree(char **tree_description); +void slow_nj_tree(char **tree_description); + +void print_phylip_tree(char **tree_description, FILE *tree, int bootstrap); +void two_way_split(char **tree_description, FILE *tree, int start_row, int flag, int bootstrap); +void guide_tree(char *fname, double **saga_tmat, char **sag_seq_name, int saga_nseq); + + + +NT_node split2upgma_tree (Split **S, Alignment *A, int nseq, char *fname); +NT_node split_upgma_merge (Alignment *A, Split **S, NT_node *NL, int *used, int *n, int N); +float get_split_dist ( Alignment *A, NT_node L, NT_node R, Split **S) ; + +Alignment * upgma_tree_aln (Alignment*A, int nseq, Constraint_list *CL); +int ** dist_mat2best_split (int **mat, int nseq); +int upgma_node_heap (NT_node X);typedef struct Tmpname Tmpname; +struct Memcontrol + { + size_t size; + size_t size_element; + char check[3]; + struct Memcontrol *p; + struct Memcontrol *n; + }; +typedef struct Memcontrol Memcontrol; +void free_pair_wise();//Frees static memory in the pair_wise functions +/************************************************************************/ +/* */ +/* CONSTRAINT_LIST */ +/* */ +/* */ +/************************************************************************/ +int *** duplicate_residue_index (int ***r); +int *** declare_residue_index (Sequence *S); + +Constraint_list *free_constraint_list4lib_computation (Constraint_list *CL); +Constraint_list *duplicate_constraint_list4lib_computation (Constraint_list *CL); +Constraint_list * declare_constraint_list_simple ( Sequence *S); +Constraint_list * declare_constraint_list ( Sequence *S, char *name, int *L, int ne,FILE *fp, int **M); +Constraint_list *cache_dp_value4constraint_list ( char mode[],Constraint_list *CL); +Constraint_list *duplicate_constraint_list_soft (Constraint_list *CL); +Constraint_list *duplicate_constraint_list (Constraint_list *CL); +Constraint_list *copy_constraint_list (Constraint_list *CL, int mode); +Sequence * free_constraint_list (Constraint_list *CL); +Constraint_list * free_constraint_list_full (Constraint_list *CL); +Distance_matrix * free_distance_matrix ( Distance_matrix *DM); +Distance_matrix * duplicate_distance_matrix ( Distance_matrix *DMin); +/************************************************************************/ +/* */ +/* Blast_param Functions */ +/* */ +/* */ +/************************************************************************/ +Blast_param * duplicate_blast_param ( Blast_param*B); +Blast_param * free_blast_param ( Blast_param*B); +/************************************************************************/ +/* */ +/* TC_param Functions */ +/* */ +/* */ +/************************************************************************/ +TC_param * duplicate_TC_param ( TC_param*B); +TC_param * free_TC_param ( TC_param*B); +/************************************************************************/ +/* */ +/* MOCA Functions */ +/* */ +/* */ +/************************************************************************/ +Moca * duplicate_moca ( Moca *m); +Moca * free_moca ( Moca *m); +/************************************************************************/ +/* */ +/* PDB Functions */ +/* */ +/* */ +/************************************************************************/ +Structure * declare_structure ( int n, char **array); +Structure * extend_structure ( Structure *S); +/************************************************************************/ +/* */ +/* Weights Functions */ +/* */ +/* */ +/************************************************************************/ +Weights* declare_weights ( int nseq); +Weights* duplicate_weights (Weights *W); +Weights* free_weights ( Weights* W); + +FILE* print_mem_usage (FILE *fp, char *comment); +void set_max_mem (int m); +int verify_memory (int s); +int my_assert ( void *p, int index); + +void * vmalloc ( size_t size); +void * vcalloc ( size_t nobj, size_t size); +void * vcalloc_nomemset ( size_t nobj, size_t size); +void * sub_vcalloc ( size_t nobj, size_t size, int MODE); + +void * vrealloc ( void *p, size_t size); +void vfree2 ( void **p); +void vfree ( void *p); +void * free_arrayN (void *p, int ndim); +void vfree_all (); +/*********************************************************************/ +/* */ +/* SIZES */ +/* */ +/* */ +/*********************************************************************/ +void write_size_short (int x, short *array, int offset); +void write_size_char (int x, char *array, int offset); +void write_size_int (int x, int *array, int offset); +void write_size_float (int x, float *array, int offset); +void write_size_double(int x, double *array, int offset); + +int read_size_short ( void *array, size_t size ); +int read_size_char ( void *array, size_t size ); +int read_size_int ( void *array, size_t size ); +int read_size_float ( void *array, size_t size ); +int read_size_double( void *array, size_t size ); +int read_array_size_new ( void *array); +int read_array_size ( void *array, size_t size ); +int read_array_new ( void *array); +int is_dynamic_memory ( void *array); + +/*********************************************************************/ +/* */ +/* REALLOCATION */ +/* */ +/* */ +/*********************************************************************/ +void **realloc_arrayN(int ndim,void **main_array,size_t size, ...); +void **realloc_arrayN2 ( int ndim, void ** p, int *A, size_t size); + + +void ** realloc_array (void **array,size_t size, int first, int second, int ext1, int ext2); +short ** realloc_short ( short **array, int first, int second, int ext1, int ext2); +char ** realloc_char ( char **array, int first, int second, int ext1, int ext2); +int ** realloc_int ( int **array, int first, int second, int ext1, int ext2); +float ** realloc_float ( float **array, int first, int second, int ext1, int ext2); +double ** realloc_double ( double **array, int first, int second, int ext1, int ext2); +Alignment ** realloc_aln_array ( Alignment **array, int ext1); +/*The new realloc is recommended*/ +short ** new_realloc_short ( short **array, int ext1, int ext2); +char ** new_realloc_char ( char **array, int ext1, int ext2); +int ** new_realloc_int ( int **array, int ext1, int ext2); +float ** new_realloc_float ( float **array, int ext1, int ext2); +double ** new_realloc_double ( double **array, int ext1, int ext2); + + +void * declare_arrayNnomemset (int ndim, size_t size, ...); +void *declare_arrayN2nomemset ( int ndim, int *A, size_t size); + +void * declare_arrayN (int ndim, size_t size, ...); +void *declare_arrayN2 ( int ndim, int *A, size_t size); + + +void ** declare_array (int first, int second, size_t size); +short ** declare_short ( int first, int second); +char ** declare_char ( int first, int second); +int ** declare_int ( int first, int second); +int ** declare_int2 ( int first, int *second, int delta); + +float ** declare_float ( int first, int second); +double ** declare_double ( int first, int second); + +void ** declare_array_nomemset (int first, int second, size_t size); +short ** declare_short_nomemset ( int first, int second); +char ** declare_char_nomemset ( int first, int second); +int ** declare_int_nomemset ( int first, int second); +float ** declare_float_nomemset ( int first, int second); +double ** declare_double_nomemset ( int first, int second); + + +Alignment ** declare_aln_array ( int first); + +short ** free_short ( short **array, int first); +int ** free_int ( int **array, int first); +char ** free_char ( char **array, int first); +double ** free_double ( double **array, int first); +float ** free_float ( float **array, int first); +Alignment ** free_aln_array ( Alignment **array); +Alignment *free_data_in_aln (Alignment *A); + +long aln_stack (Alignment *A, int mode); + +Sequence *free_Alignment ( Alignment *A); +Sequence *free_aln ( Alignment *A); +Alignment *declare_Alignment ( Sequence *S); +Alignment *realloc_alignment ( Alignment *A, int new_len); +Alignment *realloc_alignment2 ( Alignment *A, int new_nseq, int new_len); + +Alignment *declare_aln ( Sequence *S); +Alignment *declare_aln2 (int nseq, int len); +Alignment *realloc_aln ( Alignment *A, int new_len); +Alignment *realloc_aln2 ( Alignment *A, int new_nseq, int new_len); +Alignment *update_aln_random_tag (Alignment *A); + +Alignment *copy_aln ( Alignment *A, Alignment *B); +Alignment* extract_sub_aln2 ( Alignment *A, int nseq, char **list); +Alignment* extract_sub_aln ( Alignment *A, int nseq, int *list); +Alignment* shrink_aln ( Alignment *A, int nseq, int *list); + +Profile *copy_profile (Profile *P1); +Profile *declare_profile(char *alphabet, int len); +Profile * free_profile ( Profile *P); + +Sequence * reset_sequence_len (Sequence *S); +Sequence * declare_sequence ( int min, int max, int nseq); +Sequence * realloc_sequence (Sequence *OUT, int new_nseq, int max_len); +Sequence * duplicate_sequence (Sequence *S ); +Sequence * add_sequence ( Sequence *IN, Sequence *OUT, int i); +void free_sequence ( Sequence *LS, int nseq); + + + +Fname *declare_fname (); +Fname *free_fname ( Fname *F); +/*********************************************************************************************/ +/* */ +/* STRUCTURES FOR HSEARCH */ +/* */ +/*********************************************************************************************/ +#define FIND 0 +#define ADD 1 +#define REMOVE 2 +#define DECLARE 3 +#define MARK 4 +#define UNMARK 5 +#define FREE 6 +#define FREE_STACK 7 +#define FREE_ALL 8 +#define FREE_MARK 9 +#define INFO 10 + +struct HaschT +{ + int ne; + struct Hasch_entry **p; +}; +typedef struct HaschT HaschT; + +struct Hasch_entry +{ + struct Hasch_entry *n; + struct Hasch_entry *p; + int k; + struct Hasch_data *data; + struct Hasch_data * (*free_data)(struct Hasch_data *); + struct Hasch_data * (*declare_data)(struct Hasch_entry*); + int tag; +}; +typedef struct Hasch_entry Hasch_entry; +struct Char_node +{ + struct Char_node **c; + int key; + +}; +typedef struct Char_node Char_node; + +HaschT * hcreate ( int n_elements,struct Hasch_data * declare_data(struct Hasch_entry *), struct Hasch_data *free_data(struct Hasch_data *) ); +HaschT *hdestroy (HaschT *T,struct Hasch_data * declare_data(struct Hasch_entry *), struct Hasch_data *free_data(struct Hasch_data *) ); +Hasch_entry* hsearch (HaschT *T, int k, int action, struct Hasch_data * declare_data(struct Hasch_entry *), struct Hasch_data *free_data(struct Hasch_data *) ); +Hasch_entry * extract_hasch_entry_from_list (Hasch_entry *e, struct Hasch_data * declare_data(struct Hasch_entry *), struct Hasch_data *free_data(struct Hasch_data *) ); +Hasch_entry * insert_hasch_entry_in_list (Hasch_entry *p, Hasch_entry *e, Hasch_entry *n, struct Hasch_data * declare_data(struct Hasch_entry *), struct Hasch_data *free_data(struct Hasch_data *) ); +Hasch_entry * allocate_hasch_entry (Hasch_entry *e, int action,struct Hasch_data * declare_data(struct Hasch_entry *), struct Hasch_data *free_data(struct Hasch_data *) ); + + + + + +int string2key (char *s, Char_node *n); +Char_node * declare_char_node (int action); +char * process_repeat (char *aln, char *seq, char *pdb); +char * normalize_pdb_file (char *name, char *seq,char *out_file); +Ca_trace * trim_ca_trace (Ca_trace *st, char *seq ); + +Ca_trace * read_ca_trace (char *file, char *seq_field ); +Ca_trace * simple_read_ca_trace (char *file ); +Ca_trace * hasch_ca_trace ( Ca_trace *T); +Ca_trace * hasch_ca_trace_nb ( Ca_trace *T); +Ca_trace * hasch_ca_trace_bubble ( Ca_trace *T); +Ca_trace * hasch_ca_trace_transversal ( Ca_trace *TRACE); + +float get_atomic_distance ( Atom *A, Atom*B); +float ** measure_ca_distances(Ca_trace *T); + +float** print_contacts ( char *file1, char *file2, float T); +char * map_contacts ( char *file1, char *file2, float T); +int * identify_contacts (Ca_trace *ST1,Ca_trace *ST2, float T); +Sequence *seq2contacts ( Sequence *S, float T); +char *string2contacts (char *seq,char *name,char *comment, float T); +char **struc2nb (char *name,char *seq, char *comment, float Threshold, char *atom_list, char *output); +char **struclist2nb (char *name,char *seq, char *comment, float Threshold, char *atom_list, char *output); + +typedef struct +{ Alignment *A; + Alignment *B; + Alignment *sim_A; + Sequence *S; + Structure *ST; +/*PARAMETERS*/ + char ***grep_list; + int n_greps; + + char *sim_aln; + char *alignment1_file; + char *alignment2_file; + + char *io_format; + + int n_structure; + char **struct_file; + char **struct_format; + int *n_symbol; + char ***symbol_list; + +/*LIST VARIABLES*/ + int **code_A; + int **code_B; + int n_elementsA; + int n_elementsB; + + int **end_index; + int **start_index; +/*RESULTS_VARIABLES*/ + int **tot_count; + int **pos_count; + int ***pw_tot_count; + int ***pw_pos_count; + int *glob; + int **pw_glob; +/*IO VARIABLES*/ + int n_categories; + char ***category; + char *category_list; + int *n_sub_categories; + char sep_l; + char sep_r; +/*Sims VARIABLES*/ + float **sim; + float **sim_param; + char *sim_matrix; + + int sim_n_categories; + char ***sim_category; + char *sim_category_list; + int *sim_n_sub_categories; +}Result; + + +#define MAX_N_CATEGORIES 100 +#define MAX_N_STRUC 100 + + + + +int aln_compare (int argc, char *argv[]); +int **analyse_distance ( Alignment *A, int **dis); + +Structure * read_structure (char *fname, char *format, Alignment *A,Alignment *B, Structure *ST, int n_symbols, char **symbol_table); + + +int is_in_struct_category ( int s1, int s2, int r1, int r2, Structure *ST, char **cat, int n_sub_cat); +char * get_structure_residue (int s, int r, Structure *S); +int parse_category_list ( char *category_list, char ***category, int *sub_n_categories); +int struc_matches_pattern ( char *struc, char *pattern); +float **get_aln_compare_sim ( Alignment *A, Structure *S, char **cat, int n_cat, char *matrix); +float **analyse_sim ( Alignment *A, float **dis); + +/*Output*/ +FILE *output_format (char *iof, FILE *fp, Result *R); +FILE *output_pair_wise_sequence_results (FILE *fp, Result *R); +FILE *output_sequence_results (FILE *fp, Result *R); +FILE *output_total_results (FILE *fp, Result *R); +FILE *output_header (FILE *fp, Result *R); +FILE *output_large_header ( FILE *fp, Result *R); + +/*Parameter Checking*/ +int is_a_struc_format (char *format); +void get_separating_char ( char s, char *l, char *r); +void output_informations (); + +int check_configuration4program(); +typedef struct + { + Alignment *A; + Weights *W; + Sequence *S; + int **M; + Structure *RNA_ST; + NT_node T; + Constraint_list *CL; + char format[100]; + char file[100]; + int rm_gap; + +}Sequence_data_struc; + +typedef struct + { + char **symbol_list; + int n_symbol; + char *coor_file; + int rm_gap; + int keep_case; + int keep_name; + int use_consensus; +}Action_data_struc; + +/*Control of alignment sizes*/ +int set_landscape_msa (int len); +int get_msa_line_length (int line, int aln_len); + +int seq_reformat (int argc, char **argv); + +Sequence_data_struc *read_data_structure ( char *in_format, char *in_file,Action_data_struc *RAD); +Alignment * main_read_aln ( char *name, Alignment *A); +Sequence * read_sequences ( char *name); +Sequence * read_alifold ( char *name); +Alignment *alifold2aln ( char *name); +Sequence * main_read_seq ( char *mname); +int output_format_aln ( char *format, Alignment *A, Alignment *EA,char *name); +int main_output ( Sequence_data_struc *D1, Sequence_data_struc *D2, Sequence_data_struc *DST, char *out_format, char *out_file); + +char * identify_seq_format ( char *file); +char * name2type_name ( char *name); +char identify_format (char **fname); +char **identify_list_format ( char **list, int n); + +int type_is_exon_boundaries(char **seq, int n); + +int format_is_oligo ( char *file); +int format_is_msf ( char *file); +int format_is_fasta( char *file); +int format_is_fasta_aln( char *file); +int format_is_fasta_seq( char *file); +int is_pir_name (char *name); +int format_is_pir ( char *file); +int format_is_pir_aln( char *file); +int format_is_pir_seq( char *file); +int pir_name (char *name); +int format_is_conc_aln (char *file); +int format_is_saga ( char *file); +int format_is_swissprot (char *name); + +int is_seq ( char *name); +int is_aln ( char *name); +int has_pdb (char *name); +int is_stockhom_aln ( char *name); +int is_blast_file (char *name); +int is_sap_file (char *name); +int is_pdb_file ( char *name); +int is_simple_pdb_file ( char *name); +char *fix_pdb_file (char *name); + +int is_pdb_name ( char *name); +char* get_pdb_id(char *name); +char* get_pdb_struc(char *name, int start, int end); +char* seq_is_pdb_struc ( Sequence *S, int i); +char* is_pdb_struc ( char *name); /*Returns NULL if not a PDB structure Or a the name of a file containing a PDB structure*/ +int is_matrix (char *name); + +int is_lib (char *name); +int is_lib_01 (char *name); +int is_lib_02 (char *name); +int is_lib_list ( char *name); +int is_single_seq_weight_file (char *fname); +int is_newick (char *name); + +int is_method ( char *file); + +char *format_name2aln_format_name (char *name); +int is_in_format_list ( char *name); +int is_out_format_list ( char *name); +int is_struc_in_format_list ( char *name); +int is_struc_out_format_list ( char *name); +/*******************************************************************************************/ +/* */ +/* */ +/* INPUT MISC */ +/* */ +/***************************************************************************************** */ + +char *** read_rename_file ( char *fname, int mode); +void get_barton_list_tc_seq ( char *in_file); +int process_barton_entry (char *buf, char *name); + +Structure *read_rna_struc_number ( Alignment *A, char *fname); +char ** read_lib_list (char *name, int *n); +/*******************************************************************************************/ +/* */ +/* */ +/* INPUT WEIGHTS */ +/* */ +/***************************************************************************************** */ +Weights* get_amps_sd_scores ( char *fname); +Weights *read_seq_weight (char **name, int nseq, char* seq_weight); +/*******************************************************************************************/ +/* */ +/* */ +/* INPUT SEQUENCES */ +/* */ +/***************************************************************************************** */ +char ***read_group ( char *file); +Sequence* get_pdb_sequence ( char *fname); +Sequence* get_struc_gor ( char *fname); +Sequence* get_dialign_sequence ( char *fname); +Sequence* get_pima_sequence ( char *fname); +Sequence* get_sequence_dali ( char *fname); +Sequence* get_pir_sequence ( char *fname, char *comment_name); +Sequence* perl_reformat2fasta ( char *perl_script, char *file); + +Sequence* get_fasta_tree ( char *fname, char *comment_name); +Sequence* get_fasta_sequence ( char *fname, char *comment_name); +Sequence* get_fasta_sequence_num ( char *fname, char *comment_name); +Sequence* get_fasta_sequence_raw ( char *fname, char *comment_name); +Sequence *get_file_list ( char *fname); +Sequence *get_tree_file_list ( char *fname); + +Sequence* get_gor_sequence ( char *fname, char *comment_name); +Sequence* get_swissprot_sequence ( char *fname, char *comment_name); +int fscanf_seq_name ( FILE *fp, char *sname); + +void read_check ( Alignment *A, char *check_file); +void read_stockholm_aln ( char *fname, Alignment *A); +void read_aln ( char *fname, Alignment *A); +void read_number_aln ( char *fname, Alignment *A); +Alignment *read_blast_aln ( char *fname, Alignment *A); +void read_msf_aln ( char *fname, Alignment *A); +void read_amps_aln ( char *in_file, Alignment *A); +int get_amps_seq_name ( char **name, char* fname); +Alignment *read_gotoh_aln ( char *fname, Alignment *A); + +void undump_msa ( Alignment *A, char *tmp); +void dump_msa ( char *file,Alignment *A, int nseq, int *lseq); +/*******************************************************************************************/ +/* */ +/* */ +/* OUTPUT MATRICES */ +/* */ +/***************************************************************************************** */ +int output_freq_mat ( char *outfile, Alignment *A); +/*******************************************************************************************/ +/* */ +/* */ +/* OUTPUT P-Values */ +/* */ +/***************************************************************************************** */ +float output_maln_pval ( char *outfile, Alignment *A); +/*******************************************************************************************/ +/* */ +/* */ +/* OUTPUT WEIGHTS */ +/* */ +/***************************************************************************************** */ +void output_similarities (char *file, Alignment *A, char *mode); +void output_similarities_pw (char *file, Alignment *A, Alignment *B, char *mode); +Alignment * similarities_file2aln ( char *file); +int** input_similarities (char *file, Alignment *A, char *mode); + +void output_statistics (char *file, Alignment *A, char *mode); +void output_pw_weights4saga ( Weights *W, float **w_list, char *wfile); +int output_seq_weights ( Weights *W, char *wfile); +FILE * display_weights (Weights *W, FILE *fp); +/*******************************************************************************************/ +/* */ +/* */ +/* OUTPUT SEQ */ +/* */ +/***************************************************************************************** */ +char** clean_seq_names (char **names, int n, int mode); +char *clean_seq_name (char *name, int mode); + + +void output_pir_seq1 (char *fname, Alignment*A ); +void output_pir_seq (char *fname, Alignment*A ); +void output_gor_seq (char *fname, Alignment*A ); +void output_mult_fasta_seq (char *fname, Alignment*A, int n ); + +void main_output_fasta_seq ( char *fname, Alignment *A, int header); +void output_fasta_tree ( char *fname, Alignment *A); +void output_fasta_seqS (char *fname, Sequence *S ); +void output_fasta_seq1 (char *fname, Alignment*A ); +char *output_fasta_seqX (char *name, char *mode, Sequence *S, Alignment *A, int i); + +void output_pir_check (char *fname,int nseq, char **A ); +void output_fasta_seq (char *fname, Alignment*A ); +void output_gotoh_seq (char *fname, Alignment*A ); +void output_est_prf (char *fname, Alignment *A); +void output_gor_seq (char *fname, Alignment*A ); +/*******************************************************************************************/ +/* */ +/* */ +/* OUTPUT ALN */ +/* */ +/***************************************************************************************** */ +void output_pir_aln ( char *fname,Alignment*A); +void output_model_aln ( char *fname,Alignment*A ); +char * output_fasta_sub_aln (char *fname, Alignment*A, int ns, int *ls ); +char * output_fasta_sub_aln2 (char *fname, Alignment*A, int *ns, int **ls ); + +void ouput_suchard_aln ( char *fname,Alignment*A); +void output_fasta_aln ( char *fname,Alignment*A); +void output_msf_aln ( char *fname,Alignment*B); +FILE * output_generic_interleaved_aln (FILE *fp, Alignment *B, int line, char gap, char *mode); +void output_stockholm_aln (char *file, Alignment *A, Alignment *ST); +void output_clustal_aln( char *name, Alignment*B); +void output_strict_clustal_aln( char *name, Alignment*B); +void output_generic_clustal_aln( char *name, Alignment*B, char *format); +void output_saga_aln ( char *name, Alignment*B); +void output_phylip_aln ( char *name, Alignment*B); +void output_mocca_aln ( char *name, Alignment*B,Alignment*S); +void output_rnalign (char *out_file, Alignment*A,Sequence *STRUC); +void output_pw_lib_saga_aln (char *lib_name, Alignment *A ); +void output_lib (char *lib_name, Alignment *A ); +void output_compact_aln( char *name, Alignment *B); + +void print_sub_aln ( Alignment *B, int *ns, int **ls); +void print_aln ( Alignment *B); +FILE * output_aln( Alignment *B, FILE *fp); + + +FILE * output_aln_score ( Alignment *B, FILE *fp); +FILE * output_aln_with_res_number ( Alignment *B, FILE *fp); + + +FILE* output_Alignment ( Alignment *B, FILE *fp); +FILE* output_Alignment_without_header ( Alignment *B, FILE *fp); +FILE * output_Alignment_score ( Alignment *B, FILE *fp); +FILE * output_Alignment_with_res_number ( Alignment *B, FILE *fp); +void output_constraints ( char *fname, char *mode, Alignment *A); + +Alignment *input_conc_aln ( char *name, Alignment *A); +void output_conc_aln ( char *name, Alignment *B); +void output_glalign ( char *name, Alignment *B, Alignment *S); +void output_lalign_header( char *name, Alignment *B); +void output_lalign ( char *name, Alignment *B); +void output_lalign_aln ( char *name, Alignment *B); + +/**************************************************************************************************/ +/* */ +/* */ +/* INPUT/OUTPUT MATRICES */ +/* */ +/**************************************************************************************************/ +int is_blast_matrix (char *fname); +int is_pavie_matrix (char *fname); +int is_clustalw_matrix (char *fname); + +int is_distance_matrix_file (char *name); +int is_similarity_matrix_file (char *name); + +void aln2mat (Sequence *S); +void aln2mat_diaa (Sequence *S); +int **seq2latmat ( Sequence *S, char *fname); +int output_mat (int **mat, char *fname, char *alp, int offset); +int ** read_blast_matrix ( char *mat_name); +int output_blast_mat (int **mat, char *fname); +double* mat2cmp (int **mat1, int **mat2); + +void output_pavie_mat (int **mat, char *fname, double gep, char *alp); +int ** read_pavie_matrix ( char *mat_name); + +/****************************************************************************************************/ +/*************************** *************************************/ +/*************************** PROCESSING *************************************/ +/*************************** *************************************/ +/*******************************************************************************************/ +/* */ +/* */ +/* THREADING */ +/***************************************************************************************** */ + + + + +Structure * declare_rna_structure_num (Sequence *SA); + +char *thread_aa_seq_on_dna_seq( char *s); +void thread_seq_struc2aln ( Alignment *A, Sequence *ST); +Alignment *thread_dnaseq_on_prot_aln (Sequence *S, Alignment *A); +void cache_id ( Alignment *A); + + + +int process_est_sequence ( Sequence *S, int *cluster_list); +char * invert_seq ( char *seq); +int get_best_match ( char *seq1, char *seq2); +int** extract_m_diag_streches ( int ** m, int l1, int l2,char *seq1, char *seq2, int *n_mdiag); +int is_strech ( char *AA, char *seq1, char *seq2, int len, int x, int y); + +int search_for_cluster ( int seq, int cluster_number, int *cluster_list, int T, int nseq, int **S); +int * SHC ( int nseq, int **NST, int **ST); +int mutate_sol (int *sol, int nseq); +int evaluate_sol ( int*sol, int nseq, int **ST, int **NST); + + + +char **make_symbols ( char *name, int *n); +Alignment *code_dna_aln (Alignment *A); +char* back_translate_dna_codon ( char aa, int deterministic); +int translate_dna_codon ( char *seq, char stop); +char* mutate_amino_acid ( char aa, char *mode); +Alignment * mutate_aln ( Alignment *A, char *r); + +int extend_seqaln (Sequence *S, Alignment *A); +int unextend_seqaln (Sequence *S, Alignment *A); +char *extend_seq (char *seq); +char *unextend_seq (char *seq); + +Sequence * transform_sequence ( Sequence *S, char *mode); +Alignment *translate_splice_dna_aln (Alignment *A,Alignment *ST ); +Alignment * mutate_cdna_aln ( Alignment *A); + +char *test_dna2gene (char *dna, int *w); +Sequence *dnaseq2geneseq (Sequence *S, int **w); + +int ** shift_res_weights ( Sequence *R, int **w, int shift); +int res_weights2min(Sequence *R, int **w); +int res_weights2max(Sequence *R, int **w); +int res_weights2avg(Sequence *R, int **w); +int output_wexons (char *name, Alignment *A); +int scan_res_weights4ac (Sequence *R, int **w, int start, int end, int step); +float *res_weights2accuracy_counts ( Sequence *R, int **w,int T, float *result); +float* genepred_seq2accuracy_counts (Sequence *R, Sequence *T,float *result); +void genepred_seq2accuracy_counts4all (Sequence *R, Sequence *Ts); //JM +float* genepred2accuracy_counts (char *ref, char *target , float *result); + +char *dna2gene (char *dna, int *w); +char * translate_dna_seq_on3frame ( char *dna_seq, char stop, char *prot); + +char * translate_dna_seq ( char *dna_seq, int frame, char stop, char *prot); +int is_stop (char r1, char r2, char r3); +int seq2tblastx_db (char *file,Sequence *S, int strand); + +char * back_translate_dna_seq ( char *in_seq,char *out_seq, int mode); +Alignment *back_translate_dna_aln (Alignment *A); +Sequence *translate_dna_seqS (Sequence *S, int frame, int stop); +Alignment *translate_dna_aln (Alignment *A, int frame); +char *dna_seq2pep_seq (char *seq, int frame); + +Alignment *clean_gdna_aln (Alignment *A); +Alignment *clean_cdna_aln (Alignment *A); +Alignment *clean_est (Alignment *A); +/**************************************************************************************************/ +/******************************** ********************************************/ +/******************************** PROCESSING ********************************************/ +/*************** **************** ********************************************/ +void modify_data (Sequence_data_struc *D1, Sequence_data_struc *D2, Sequence_data_struc *DST, char **action_list,int n_actions, Action_data_struc *RAD); + +// +// Name MAnipulation +// + +Alignment *clean_aln (Alignment *A); +Sequence *clean_sequence ( Sequence *S); +char ** translate_names (int n, char **name); +char * translate_name ( char *name); +char *decode_name (char *name, int mode); +FILE * display_sequences_names (Sequence *S, FILE *fp, int check_pdb_status, int print_templates); +Sequence *add_file2file_list (char *name, Sequence *S); +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/t_coffee_source/util_make_tree.c b/binaries/src/tcoffee/t_coffee_source/util_make_tree.c new file mode 100644 index 0000000..211d79a --- /dev/null +++ b/binaries/src/tcoffee/t_coffee_source/util_make_tree.c @@ -0,0 +1,1472 @@ +#include +#include +#include +#include + +#include "io_lib_header.h" +#include "util_lib_header.h" +#include "dp_lib_header.h" +#include "define_header.h" + +static int first_seq, last_seq; + +static int nseqs; +static char **names; /* the seq. names */ + +static double **tmat; +static double *av; +static double *left_branch, *right_branch; +static int *tkill; + + +/*! + * \file util_make_tree.c + * \brief Source code tree algorithms + */ + +NT_node ** seq2cw_tree ( Sequence *S, char *tree) +{ + Alignment *A; + char *aln,command[1000]; + int tot_node; + + + + A=seq2clustalw_aln (S); + aln=vtmpnam (NULL); if (!tree)tree=vtmpnam (NULL); + + output_fasta_aln (aln, A); + + sprintf ( command, "clustalw -infile=%s -newtree=%s -tree %s", aln, tree, TO_NULL_DEVICE); + my_system (command); + return read_tree (tree, &tot_node, S->nseq, S->name); +} + +NT_node ** make_upgma_tree ( Alignment *A,int **distances,int gop, int gep, char **out_seq, char **out_seq_name, int out_nseq, char *tree_file, char *tree_mode) + { + + if ( distances==NULL && A==NULL) + { + fprintf ( stderr, "\nError: make_nj_tree, must provide an alignment or a distance matrix [FATAL:%s]", PROGRAM); + myexit (EXIT_FAILURE); + } + else if ( distances==NULL) + { + + distances=get_dist_aln_array (A, "idmat"); + } + return int_dist2upgma_tree (distances,A, A->nseq,tree_file); + } +NT_node ** make_nj_tree ( Alignment *A,int **distances,int gop, int gep, char **out_seq, char **out_seq_name, int out_nseq, char *tree_file, char *tree_mode) + { + + if ( distances==NULL && A==NULL) + { + fprintf ( stderr, "\nError: make_nj_tree, must provide an alignment or a distance matrix [FATAL:%s]", PROGRAM); + myexit (EXIT_FAILURE); + } + else if ( distances==NULL) + { + distances=get_dist_aln_array (A, "idmat"); + } + return int_dist2nj_tree (distances,out_seq_name, out_nseq,tree_file); + } + +NT_node ** int_dist2nj_tree (int **distances, char **out_seq_name, int out_nseq, char *tree_file) + { + int a, b; + double **d; + NT_node **T; + + d=declare_double( out_nseq, out_nseq); + for ( a=0; a< out_nseq; a++) + for ( b=0; b< out_nseq; b++) + d[a][b]=distances[a][b]; + + T=dist2nj_tree ( d, out_seq_name, out_nseq, tree_file); + + free_double (d, -1); + return T; + } +NT_node ** float_dist2nj_tree (float **distances, char **out_seq_name, int out_nseq, char *tree_file) + { + int a, b; + double **d; + NT_node **T; + + d=declare_double( out_nseq, out_nseq); + for ( a=0; a< out_nseq; a++) + for ( b=0; b< out_nseq; b++) + d[a][b]=distances[a][b]; + T=dist2nj_tree ( d, out_seq_name, out_nseq, tree_file); + free_double (d, -1); + return T; + } +NT_node ** dist2nj_tree (double **distances, char **out_seq_name, int out_nseq, char *tree_file) + { + int a, b; + double **d_dist; + int tot_node=0; + NT_node **T; + + if ( !tree_file)tree_file=vtmpnam(NULL); + d_dist=declare_double( out_nseq+1, out_nseq+1); + + for ( a=0; aMY_EPS) + tmin = total; + mini = ii; + minj = jj; + } + } + + +/*.................compute branch lengths and print the results ........*/ + + + dio = djo = 0.0; + for(i=1; i<=nseqs; ++i) { + dio = dio + tmat[i][mini]; + djo = djo + tmat[i][minj]; + } + + dmin = tmat[mini][minj]; + dio = (dio - dmin) / fnseqs2; + djo = (djo - dmin) / fnseqs2; + bi = (dmin + dio - djo) * 0.5; + bj = dmin - bi; + bi = bi - av[mini]; + bj = bj - av[minj]; + + if( av[mini] > 0.0 ) + typei = 0; + else + typei = 1; + if( av[minj] > 0.0 ) + typej = 0; + else + typej = 1; + + + +/* + set negative branch lengths to zero. Also set any tiny positive + branch lengths to zero. +*/ + if( fabs(bi) < 0.0001) bi = 0.0; + if( fabs(bj) < 0.0001) bj = 0.0; + + + + + left_branch[nc] = bi; + right_branch[nc] = bj; + + for(i=1; i<=nseqs; i++) + tree_description[nc][i] = 0; + + if(typei == 0) { + for(i=nc-1; i>=1; i--) + if(tree_description[i][mini] == 1) { + for(j=1; j<=nseqs; j++) + if(tree_description[i][j] == 1) + tree_description[nc][j] = 1; + break; + } + } + else + tree_description[nc][mini] = 1; + + if(typej == 0) { + for(i=nc-1; i>=1; i--) + if(tree_description[i][minj] == 1) { + for(j=1; j<=nseqs; j++) + if(tree_description[i][j] == 1) + tree_description[nc][j] = 1; + break; + } + } + else + tree_description[nc][minj] = 1; + + +/* + Here is where the -0.00005 branch lengths come from for 3 or more + identical seqs. +*/ +/* if(dmin <= 0.0) dmin = 0.0001; */ + if(dmin <= 0.0) dmin = 0.000001; + av[mini] = dmin * 0.5; + + /*........................Re-initialisation................................*/ + + fnseqs = fnseqs - 1.0; + tkill[minj] = 1; + + for(j=1; j<=nseqs; ++j) + if( tkill[j] != 1 ) { + da = ( tmat[mini][j] + tmat[minj][j] ) * 0.5; + if( (mini - j) < 0 ) + tmat[mini][j] = da; + if( (mini - j) > 0) + tmat[j][mini] = da; + } + + for(j=1; j<=nseqs; ++j) + tmat[minj][j] = tmat[j][minj] = 0.0; + + + + } + /*end main cycle**/ + +/******************************Last Cycle (3 Seqs. left)********************/ + + nude = 1; + + + for(i=1; i<=nseqs; ++i) + if( tkill[i] != 1 ) { + l[nude] = i; + nude = nude + 1; + } + + b1 = (tmat[l[1]][l[2]] + tmat[l[1]][l[3]] - tmat[l[2]][l[3]]) * 0.5; + b2 = tmat[l[1]][l[2]] - b1; + b3 = tmat[l[1]][l[3]] - b1; + + branch[1] = b1 - av[l[1]]; + branch[2] = b2 - av[l[2]]; + branch[3] = b3 - av[l[3]]; + +/* Reset tiny negative and positive branch lengths to zero */ + if( fabs(branch[1]) < 0.0001) branch[1] = 0.0; + if( fabs(branch[2]) < 0.0001) branch[2] = 0.0; + if( fabs(branch[3]) < 0.0001) branch[3] = 0.0; + + left_branch[nseqs-2] = branch[1]; + left_branch[nseqs-1] = branch[2]; + left_branch[nseqs] = branch[3]; + + for(i=1; i<=nseqs; i++) + tree_description[nseqs-2][i] = 0; + + + + for(i=1; i<=3; ++i) { + if( av[l[i]] > 0.0) { + + for(k=nseqs-3; k>=1; k--) + if(tree_description[k][l[i]] == 1) { + for(j=1; j<=nseqs; j++) + if(tree_description[k][j] == 1) + tree_description[nseqs-2][j] = i; + break; + } + } + else { + + tree_description[nseqs-2][l[i]] = i; + } + if(i < 3) { + } + } +} + +void print_phylip_tree(char **tree_description, FILE *tree, int bootstrap) +{ + + fprintf(tree,"(\n"); + + two_way_split(tree_description, tree, nseqs-2,1,bootstrap); + fprintf(tree,":%7.5f,\n",left_branch[nseqs-2]); + two_way_split(tree_description, tree, nseqs-2,2,bootstrap); + fprintf(tree,":%7.5f,\n",left_branch[nseqs-1]); + two_way_split(tree_description, tree, nseqs-2,3,bootstrap); + + fprintf(tree,":%7.5f)",left_branch[nseqs]); + if (bootstrap) fprintf(tree,"TRICHOTOMY"); + fprintf(tree,";\n"); +} + + +void two_way_split +(char **tree_description, FILE *tree, int start_row, int flag, int bootstrap) +{ + int row, new_row, col, test_col=0; + int single_seq; + + if(start_row != nseqs-2) fprintf(tree,"(\n"); + + for(col=1; col<=nseqs; col++) { + if(tree_description[start_row][col] == flag) { + test_col = col; + break; + } + } + + single_seq = TRUE; + for(row=start_row-1; row>=1; row--) + if(tree_description[row][test_col] == 1) { + single_seq = FALSE; + new_row = row; + break; + } + + if(single_seq) { + tree_description[start_row][test_col] = 0; + fprintf(tree,"%s",names[test_col+0-1]); + } + else { + for(col=1; col<=nseqs; col++) { + if((tree_description[start_row][col]==1)&& + (tree_description[new_row][col]==1)) + tree_description[start_row][col] = 0; + } + two_way_split(tree_description, tree, new_row, (int)1, bootstrap); + } + + if(start_row == nseqs-2) { +/* if (bootstrap && (flag==1)) fprintf(tree,"[TRICHOTOMY]"); +*/ + return; + } + + fprintf(tree,":%7.5f,\n",left_branch[start_row]); + + for(col=1; col<=nseqs; col++) + if(tree_description[start_row][col] == flag) { + test_col = col; + break; + } + + single_seq = TRUE; + for(row=start_row-1; row>=1; row--) + if(tree_description[row][test_col] == 1) { + single_seq = FALSE; + new_row = row; + break; + } + + if(single_seq) { + tree_description[start_row][test_col] = 0; + fprintf(tree,"%s",names[test_col+0-1]); + } + else { + for(col=1; col<=nseqs; col++) { + if((tree_description[start_row][col]==1)&& + (tree_description[new_row][col]==1)) + tree_description[start_row][col] = 0; + } + two_way_split(tree_description, tree, new_row, (int)1, bootstrap); + } + + fprintf(tree,":%7.5f)\n",right_branch[start_row]); + + +} + + + + +/**************************************************************************** + * [ Improvement ideas in fast_nj_tree() ] by DDBJ & FUJITSU Limited. + * written by Tadashi Koike + * (takoike@genes.nig.ac.jp) + ******************* + * : Store the value of sum of the score to temporary array, + * and use again and again. + * + * In the main cycle, these are calculated again and again : + * diq = sum of tmat[n][ii] (n:1 to last_seq-first_seq+1), + * djq = sum of tmat[n][jj] (n:1 to last_seq-first_seq+1), + * dio = sum of tmat[n][mini] (n:1 to last_seq-first_seq+1), + * djq = sum of tmat[n][minj] (n:1 to last_seq-first_seq+1) + * // 'last_seq' and 'first_seq' are both constant values // + * and the result of above calculations is always same until + * a best pair of neighbour nodes is joined. + * + * So, we change the logic to calculate the sum[i] (=sum of tmat[n][i] + * (n:1 to last_seq-first_seq+1)) and store it to array, before + * beginning to find a best pair of neighbour nodes, and after that + * we use them again and again. + * + * tmat[i][j] + * 1 2 3 4 5 + * +---+---+---+---+---+ + * 1 | | | | | | + * +---+---+---+---+---+ + * 2 | | | | | | 1) calculate sum of tmat[n][i] + * +---+---+---+---+---+ (n: 1 to last_seq-first_seq+1) + * 3 | | | | | | 2) store that sum value to sum[i] + * +---+---+---+---+---+ + * 4 | | | | | | 3) use sum[i] during finding a best + * +---+---+---+---+---+ pair of neibour nodes. + * 5 | | | | | | + * +---+---+---+---+---+ + * | | | | | + * V V V V V Calculate sum , and store it to sum[i] + * +---+---+---+---+---+ + * sum[i] | | | | | | + * +---+---+---+---+---+ + * + * At this time, we thought that we use upper triangle of the matrix + * because tmat[i][j] is equal to tmat[j][i] and tmat[i][i] is equal + * to zero. Therefore, we prepared sum_rows[i] and sum_cols[i] instead + * of sum[i] for storing the sum value. + * + * tmat[i][j] + * 1 2 3 4 5 sum_cols[i] + * +---+---+---+---+---+ +---+ + * 1 | # | # | # | # | --> | | ... sum of tmat[1][2..5] + * + - +---+---+---+---+ +---+ + * 2 | # | # | # | --> | | ... sum of tmat[2][3..5] + * + - + - +---+---+---+ +---+ + * 3 | # | # | --> | | ... sum of tmat[3][4..5] + * + - + - + - +---+---+ +---+ + * 4 | # | --> | | ... sum of tmat[4][5] + * + - + - + - + - +---+ +---+ + * 5 | --> | | ... zero + * + - + - + - + - + - + +---+ + * | | | | | + * V V V V V Calculate sum , sotre to sum[i] + * +---+---+---+---+---+ + * sum_rows[i] | | | | | | + * +---+---+---+---+---+ + * | | | | | + * | | | | +----- sum of tmat[1..4][5] + * | | | +--------- sum of tmat[1..3][4] + * | | +------------- sum of tmat[1..2][3] + * | +----------------- sum of tmat[1][2] + * +--------------------- zero + * + * And we use (sum_rows[i] + sum_cols[i]) instead of sum[i]. + * + ******************* + * : We manage valid nodes with chain list, instead of + * tkill[i] flag array. + * + * In original logic, invalid(killed?) nodes after nodes-joining + * are managed with tkill[i] flag array (set to 1 when killed). + * By this method, it is conspicuous to try next node but skip it + * at the latter of finding a best pair of neighbor nodes. + * + * So, we thought that we managed valid nodes by using a chain list + * as below: + * + * 1) declare the list structure. + * struct { + * int n; // entry number of node. + * void *prev; // pointer to previous entry. + * void *next; // pointer to next entry. + * } + * 2) construct a valid node list. + * + * +-----+ +-----+ +-----+ +-----+ +-----+ + * NULL<-|prev |<---|prev |<---|prev |<---|prev |<- - - -|prev | + * | 0 | | 1 | | 2 | | 3 | | n | + * | next|--->| next|--->| next|--->| next|- - - ->| next|->NULL + * +-----+ +-----+ +-----+ +-----+ +-----+ + * + * 3) when finding a best pair of neighbor nodes, we use + * this chain list as loop counter. + * + * 4) If an entry was killed by node-joining, this chain list is + * modified to remove that entry. + * + * EX) remove the entry No 2. + * +-----+ +-----+ +-----+ +-----+ + * NULL<-|prev |<---|prev |<--------------|prev |<- - - -|prev | + * | 0 | | 1 | | 3 | | n | + * | next|--->| next|-------------->| next|- - - ->| next|->NULL + * +-----+ +-----+ +-----+ +-----+ + * +-----+ + * NULL<-|prev | + * | 2 | + * | next|->NULL + * +-----+ + * + * By this method, speed is up at the latter of finding a best pair of + * neighbor nodes. + * + ******************* + * : Cut the frequency of division. + * + * At comparison between 'total' and 'tmin' in the main cycle, total is + * divided by (2.0*fnseqs2) before comparison. If N nodes are available, + * that division happen (N*(N-1))/2 order. + * + * We thought that the comparison relation between tmin and total/(2.0*fnseqs2) + * is equal to the comparison relation between (tmin*2.0*fnseqs2) and total. + * Calculation of (tmin*2.0*fnseqs2) is only one time. so we stop dividing + * a total value and multiply tmin and (tmin*2.0*fnseqs2) instead. + * + ******************* + * : some transformation of the equation (to cut operations). + * + * We transform an equation of calculating 'total' in the main cycle. + * + */ + + +void fast_nj_tree(char **tree_description) +{ + register int i; + int l[4],nude,k; + int nc,mini,minj,j,ii,jj; + double fnseqs,fnseqs2=0,sumd; + double diq,djq,dij,dio,djo,da; + double tmin,total,dmin; + double bi,bj,b1,b2,b3,branch[4]; + int typei,typej; /* 0 = node; 1 = OTU */ + + /* IMPROVEMENT 1, STEP 0 : declare variables */ + double *sum_cols, *sum_rows, *join; + + /* IMPROVEMENT 2, STEP 0 : declare variables */ + int loop_limit; + typedef struct _ValidNodeID { + int n; + struct _ValidNodeID *prev; + struct _ValidNodeID *next; + } ValidNodeID; + ValidNodeID *tvalid, *lpi, *lpj, *lpii, *lpjj, *lp_prev, *lp_next; + + /* + * correspondence of the loop counter variables. + * i .. lpi->n, ii .. lpii->n + * j .. lpj->n, jj .. lpjj->n + */ + + fnseqs = (double)last_seq-first_seq+1; + +/*********************** First initialisation ***************************/ + + + if (fnseqs == 2) { + return; + } + + mini = minj = 0; + + left_branch = (double *) ckalloc( (nseqs+2) * sizeof (double) ); + right_branch = (double *) ckalloc( (nseqs+2) * sizeof (double) ); + tkill = (int *) ckalloc( (nseqs+1) * sizeof (int) ); + av = (double *) ckalloc( (nseqs+1) * sizeof (double) ); + + /* IMPROVEMENT 1, STEP 1 : Allocate memory */ + sum_cols = (double *) ckalloc( (nseqs+1) * sizeof (double) ); + sum_rows = (double *) ckalloc( (nseqs+1) * sizeof (double) ); + join = (double *) ckalloc( (nseqs+1) * sizeof (double) ); + + /* IMPROVEMENT 2, STEP 1 : Allocate memory */ + tvalid = (ValidNodeID *) ckalloc( (nseqs+1) * sizeof (ValidNodeID) ); + /* tvalid[0] is special entry in array. it points a header of valid entry list */ + tvalid[0].n = 0; + tvalid[0].prev = NULL; + tvalid[0].next = &tvalid[1]; + + /* IMPROVEMENT 2, STEP 2 : Construct and initialize the entry chain list */ + for(i=1, loop_limit = last_seq-first_seq+1, + lpi=&tvalid[1], lp_prev=&tvalid[0], lp_next=&tvalid[2] ; + i<=loop_limit ; + ++i, ++lpi, ++lp_prev, ++lp_next) + { + tmat[i][i] = av[i] = 0.0; + tkill[i] = 0; + lpi->n = i; + lpi->prev = lp_prev; + lpi->next = lp_next; + + /* IMPROVEMENT 1, STEP 2 : Initialize arrays */ + sum_cols[i] = sum_rows[i] = join[i] = 0.0; + } + tvalid[loop_limit].next = NULL; + + /* + * IMPROVEMENT 1, STEP 3 : Calculate the sum of score value that + * is sequence[i] to others. + */ + sumd = 0.0; + for (lpj=tvalid[0].next ; lpj!=NULL ; lpj = lpj->next) { + double tmp_sum = 0.0; + j = lpj->n; + /* calculate sum_rows[j] */ + for (lpi=tvalid[0].next ; lpi->n < j ; lpi = lpi->next) { + i = lpi->n; + tmp_sum += tmat[i][j]; + /* tmat[j][i] = tmat[i][j]; */ + } + sum_rows[j] = tmp_sum; + + tmp_sum = 0.0; + /* Set lpi to that lpi->n is greater than j */ + if ((lpi != NULL) && (lpi->n == j)) { + lpi = lpi->next; + } + /* calculate sum_cols[j] */ + for( ; lpi!=NULL ; lpi = lpi->next) { + i = lpi->n; + tmp_sum += tmat[j][i]; + /* tmat[i][j] = tmat[j][i]; */ + } + sum_cols[j] = tmp_sum; + } + +/*********************** Enter The Main Cycle ***************************/ + + for(nc=1, loop_limit = (last_seq-first_seq+1-3); nc<=loop_limit; ++nc) { + + sumd = 0.0; + /* IMPROVEMENT 1, STEP 4 : use sum value */ + for(lpj=tvalid[0].next ; lpj!=NULL ; lpj = lpj->next) { + sumd += sum_cols[lpj->n]; + } + + /* IMPROVEMENT 3, STEP 0 : multiply tmin and 2*fnseqs2 */ + fnseqs2 = fnseqs - 2.0; /* Set fnseqs2 at this point. */ + tmin = 99999.0 * 2.0 * fnseqs2; + + +/*.................compute SMATij values and find the smallest one ........*/ + + mini = minj = 0; + + /* jj must starts at least 2 */ + if ((tvalid[0].next != NULL) && (tvalid[0].next->n == 1)) { + lpjj = tvalid[0].next->next; + } else { + lpjj = tvalid[0].next; + } + + for( ; lpjj != NULL; lpjj = lpjj->next) { + jj = lpjj->n; + for(lpii=tvalid[0].next ; lpii->n < jj ; lpii = lpii->next) { + ii = lpii->n; + diq = djq = 0.0; + + /* IMPROVEMENT 1, STEP 4 : use sum value */ + diq = sum_cols[ii] + sum_rows[ii]; + djq = sum_cols[jj] + sum_rows[jj]; + /* + * always ii < jj in this point. Use upper + * triangle of score matrix. + */ + dij = tmat[ii][jj]; + + /* + * IMPROVEMENT 3, STEP 1 : fnseqs2 is + * already calculated. + */ + /* fnseqs2 = fnseqs - 2.0 */ + + /* IMPROVEMENT 4 : transform the equation */ + /*-------------------------------------------------------------------* + * OPTIMIZE of expression 'total = d2r + fnseqs2*dij + dr*2.0' * + * total = d2r + fnseq2*dij + 2.0*dr * + * = d2r + fnseq2*dij + 2(sumd - dij - d2r) * + * = d2r + fnseq2*dij + 2*sumd - 2*dij - 2*d2r * + * = fnseq2*dij + 2*sumd - 2*dij - 2*d2r + d2r * + * = fnseq2*dij + 2*sumd - 2*dij - d2r * + * = fnseq2*dij + 2*sumd - 2*dij - (diq + djq - 2*dij) * + * = fnseq2*dij + 2*sumd - 2*dij - diq - djq + 2*dij * + * = fnseq2*dij + 2*sumd - 2*dij + 2*dij - diq - djq * + * = fnseq2*dij + 2*sumd - diq - djq * + *-------------------------------------------------------------------*/ + total = fnseqs2*dij + 2.0*sumd - diq - djq; + + /* + * IMPROVEMENT 3, STEP 2 : abbrevlate + * the division on comparison between + * total and tmin. + */ + /* total = total / (2.0*fnseqs2); */ + + if(total < tmin) { + tmin = total; + mini = ii; + minj = jj; + } + } + } + + /* MEMO: always ii < jj in avobe loop, so mini < minj */ + +/*.................compute branch lengths and print the results ........*/ + + + dio = djo = 0.0; + + /* IMPROVEMENT 1, STEP 4 : use sum value */ + dio = sum_cols[mini] + sum_rows[mini]; + djo = sum_cols[minj] + sum_rows[minj]; + + dmin = tmat[mini][minj]; + dio = (dio - dmin) / fnseqs2; + djo = (djo - dmin) / fnseqs2; + bi = (dmin + dio - djo) * 0.5; + bj = dmin - bi; + bi = bi - av[mini]; + bj = bj - av[minj]; + + if( av[mini] > 0.0 ) + typei = 0; + else + typei = 1; + if( av[minj] > 0.0 ) + typej = 0; + else + typej = 1; + + +/* + set negative branch lengths to zero. Also set any tiny positive + branch lengths to zero. +*/ if( fabs(bi) < 0.0001) bi = 0.0; + if( fabs(bj) < 0.0001) bj = 0.0; + + + left_branch[nc] = bi; + right_branch[nc] = bj; + + for(i=1; i<=last_seq-first_seq+1; i++) + tree_description[nc][i] = 0; + + if(typei == 0) { + for(i=nc-1; i>=1; i--) + if(tree_description[i][mini] == 1) { + for(j=1; j<=last_seq-first_seq+1; j++) + if(tree_description[i][j] == 1) + tree_description[nc][j] = 1; + break; + } + } + else + tree_description[nc][mini] = 1; + + if(typej == 0) { + for(i=nc-1; i>=1; i--) + if(tree_description[i][minj] == 1) { + for(j=1; j<=last_seq-first_seq+1; j++) + if(tree_description[i][j] == 1) + tree_description[nc][j] = 1; + break; + } + } + else + tree_description[nc][minj] = 1; + + +/* + Here is where the -0.00005 branch lengths come from for 3 or more + identical seqs. +*/ +/* if(dmin <= 0.0) dmin = 0.0001; */ + if(dmin <= 0.0) dmin = 0.000001; + av[mini] = dmin * 0.5; + +/*........................Re-initialisation................................*/ + + fnseqs = fnseqs - 1.0; + tkill[minj] = 1; + + /* IMPROVEMENT 2, STEP 3 : Remove tvalid[minj] from chain list. */ + /* [ Before ] + * +---------+ +---------+ +---------+ + * |prev |<-------|prev |<-------|prev |<--- + * | n | | n(=minj)| | n | + * | next|------->| next|------->| next|---- + * +---------+ +---------+ +---------+ + * + * [ After ] + * +---------+ +---------+ + * |prev |<--------------------------|prev |<--- + * | n | | n | + * | next|-------------------------->| next|---- + * +---------+ +---------+ + * +---------+ + * NULL---|prev | + * | n(=minj)| + * | next|---NULL + * +---------+ + */ + (tvalid[minj].prev)->next = tvalid[minj].next; + if (tvalid[minj].next != NULL) { + (tvalid[minj].next)->prev = tvalid[minj].prev; + } + tvalid[minj].prev = tvalid[minj].next = NULL; + + /* IMPROVEMENT 1, STEP 5 : re-calculate sum values. */ + for(lpj=tvalid[0].next ; lpj != NULL ; lpj = lpj->next) { + double tmp_di = 0.0; + double tmp_dj = 0.0; + j = lpj->n; + + /* + * subtrace a score value related with 'minj' from + * sum arrays . + */ + if (j < minj) { + tmp_dj = tmat[j][minj]; + sum_cols[j] -= tmp_dj; + } else if (j > minj) { + tmp_dj = tmat[minj][j]; + sum_rows[j] -= tmp_dj; + } /* nothing to do when j is equal to minj. */ + + + /* + * subtrace a score value related with 'mini' from + * sum arrays . + */ + if (j < mini) { + tmp_di = tmat[j][mini]; + sum_cols[j] -= tmp_di; + } else if (j > mini) { + tmp_di = tmat[mini][j]; + sum_rows[j] -= tmp_di; + } /* nothing to do when j is equal to mini. */ + + /* + * calculate a score value of the new inner node. + * then, store it temporary to join[] array. + */ + join[j] = (tmp_dj + tmp_di) * 0.5; + } + + /* + * 1) + * Set the score values (stored in join[]) into the matrix, + * row/column position is 'mini'. + * 2) + * Add a score value of the new inner node to sum arrays. + */ + for(lpj=tvalid[0].next ; lpj != NULL; lpj = lpj->next) { + j = lpj->n; + if (j < mini) { + tmat[j][mini] = join[j]; + sum_cols[j] += join[j]; + } else if (j > mini) { + tmat[mini][j] = join[j]; + sum_rows[j] += join[j]; + } /* nothing to do when j is equal to mini. */ + } + + /* Re-calculate sum_rows[mini],sum_cols[mini]. */ + sum_cols[mini] = sum_rows[mini] = 0.0; + + /* calculate sum_rows[mini] */ + da = 0.0; + for(lpj=tvalid[0].next ; lpj->n < mini ; lpj = lpj->next) { + da += join[lpj->n]; + } + sum_rows[mini] = da; + + /* skip if 'lpj->n' is equal to 'mini' */ + if ((lpj != NULL) && (lpj->n == mini)) { + lpj = lpj->next; + } + + /* calculate sum_cols[mini] */ + da = 0.0; + for( ; lpj != NULL; lpj = lpj->next) { + da += join[lpj->n]; + } + sum_cols[mini] = da; + + /* + * Clean up sum_rows[minj], sum_cols[minj] and score matrix + * related with 'minj'. + */ + sum_cols[minj] = sum_rows[minj] = 0.0; + for(j=1; j<=last_seq-first_seq+1; ++j) + tmat[minj][j] = tmat[j][minj] = join[j] = 0.0; + + +/****/ } /*end main cycle**/ + +/******************************Last Cycle (3 Seqs. left)********************/ + + nude = 1; + + for(lpi=tvalid[0].next; lpi != NULL; lpi = lpi->next) { + l[nude] = lpi->n; + ++nude; + } + + b1 = (tmat[l[1]][l[2]] + tmat[l[1]][l[3]] - tmat[l[2]][l[3]]) * 0.5; + b2 = tmat[l[1]][l[2]] - b1; + b3 = tmat[l[1]][l[3]] - b1; + + branch[1] = b1 - av[l[1]]; + branch[2] = b2 - av[l[2]]; + branch[3] = b3 - av[l[3]]; + +/* Reset tiny negative and positive branch lengths to zero */ + if( fabs(branch[1]) < 0.0001) branch[1] = 0.0; + if( fabs(branch[2]) < 0.0001) branch[2] = 0.0; + if( fabs(branch[3]) < 0.0001) branch[3] = 0.0; + + left_branch[last_seq-first_seq+1-2] = branch[1]; + left_branch[last_seq-first_seq+1-1] = branch[2]; + left_branch[last_seq-first_seq+1] = branch[3]; + + for(i=1; i<=last_seq-first_seq+1; i++) + tree_description[last_seq-first_seq+1-2][i] = 0; + + + for(i=1; i<=3; ++i) { + if( av[l[i]] > 0.0) { + + for(k=last_seq-first_seq+1-3; k>=1; k--) + if(tree_description[k][l[i]] == 1) { + for(j=1; j<=last_seq-first_seq+1; j++) + if(tree_description[k][j] == 1) + tree_description[last_seq-first_seq+1-2][j] = i; + break; + } + } + else { + tree_description[last_seq-first_seq+1-2][l[i]] = i; + } + if(i < 3) {; + } + } + ckfree(sum_cols); + ckfree(sum_rows); + ckfree(join); + ckfree(tvalid); +} +////////////////////////////////////////////////////////////////////////////// +// +// UPGMA_aln +////////////////////////////////////////////////////////////////////////////// + +Alignment * upgma_merge_aln_rows (Alignment *A, int *ns, int **ls,int N, int**mat,int *used, int *n, Constraint_list *CL); +int upgma_pair_wise (Alignment *A, int *ls0, int ns0, int *ls2, int ns2, Constraint_list *CL); + + +Alignment * upgma_tree_aln ( Alignment*A, int nseq, Constraint_list *CL) +{ + int a, b,n, *used; + static int **mat; + int **ls; + int *ns; + nseq=(CL->S)->nseq; + mat=declare_int (nseq, nseq); + ls=declare_int (nseq,nseq); + ns=vcalloc (nseq,sizeof (int)); + + for (a=0; a1) + { + upgma_merge_aln_rows (A,ns, ls,nseq, mat, used, &n,CL); + } + print_aln (A); + HERE ("finished"); + free_int ( mat, -1); + free_int (ls, -1); + vfree (ns); + return A; +} + +Alignment * upgma_merge_aln_rows (Alignment *A, int *ns, int **ls,int N, int**mat,int *used, int *n, Constraint_list *CL) +{ + + int a, b, w, best_a, best_b, set; + float best_s; + + for (set=0,a=0; abest_s) + { + best_s=w; + best_a=a; + best_b=b; + set=1; + } + } + } + used[best_b]=1; + + //merge a and b + mat[best_a][best_b]=upgma_pair_wise (A, ls[best_a], ns[best_a], ls[best_b], ns[best_b], CL); + for (a=0; anseq; a++) + { + if (a!=best_a && !used[a]) + mat[best_a][a]=mat[a][best_a]=upgma_pair_wise (A, ls[best_a], ns[best_a], ls[a], ns[a], CL); + } + + HERE ("DONE"); + + n[0]--; + return A; +} +int upgma_pair_wise (Alignment *A, int *ls0, int ns0, int *ls1, int ns1, Constraint_list *CL) +{ + static int **ls; + static int *ns; + static int *fl; + int a, b, n; + + if ( !ls ) + { + ls=vcalloc (2, sizeof (int*)); + ns=vcalloc (2, sizeof (int)); + fl=vcalloc ((CL->S)->nseq, sizeof (int)); + } + ls[0]=ls0; + ls[1]=ls1; + ns[0]=ns0; ns[1]=ns1; + + fprintf ( stderr, "\n"); + for (a=0; anseq; a++) + { + NL[a]=new_declare_tree_node (); + upgma_node_heap (NL[a]); + sprintf (NL[a]->name, "%s", A->name[a]); + NL[a]->isseq=1; + NL[a]->leaf=1; + } + + used=vcalloc ( A->nseq, sizeof (int)); + n=A->nseq; + while (n>1) + { + T=upgma_merge (mat, NL,used, &n, A->nseq); + } + + vfree (used); + vfclose (print_tree (T, "newick", vfopen (fname, "w"))); + upgma_node_heap (NULL); + vfree (NL); + + return read_tree (fname,&tot_node,A->nseq, A->name); +} +NT_node upgma_merge (int **mat, NT_node *NL, int *used, int *n, int N) +{ + NT_node P, LC, RC; + int a, b, w, best_a, best_b, set; + float best_s; + P=new_declare_tree_node(); + upgma_node_heap (P); + + for (set=0,a=0; adist=RC->dist=best_s; + LC->parent=RC->parent=P; + P->left=LC; + P->right=RC; + NL[best_a]=P; + n[0]--; + return P; + +} + + +////////////////////////////////////////////////////////////////////////////// +// +// SPLIT UPGMA +/////////////////////////////////////////////////////////////////////////////// + +int upgma_node_heap (NT_node X) +{ + static int n; + static NT_node *h; + if ( X==NULL) + { + int a,r; + if (n==0) return 0; + for (a=0; anseq; a++) + { + + NL[a]=new_declare_tree_node (); + NL[a]->lseq2=vcalloc (A->nseq+1, sizeof (int)); + NL[a]->lseq2[a]=1; + sprintf (NL[a]->name, "%s", A->name[a]); + NL[a]->isseq=1; + NL[a]->leaf=1; + NL[a]->dist=1; + upgma_node_heap (NL[a]); + } + used=vcalloc ( A->nseq, sizeof (int)); + n=A->nseq; + while (n>1) + { + T=split_upgma_merge (A,S, NL,used, &n, A->nseq); + } + vfree (used); + fprintf ( stdout, "\n"); + vfclose (print_tree (T, "newick", vfopen (fname, "w"))); + upgma_node_heap (NULL); + return T; +} +NT_node split_upgma_merge (Alignment *A, Split **S, NT_node *NL, int *used, int *n, int N) +{ + NT_node P, LC, RC; + int a, b, w, best_a, best_b, set; + float best_s; + static int **mat; + + if (!mat) + { + mat=declare_int (N, N); + for (a=0; alseq2=vcalloc (N, sizeof (int)); + for (set=0,a=0; adist=1-best_s; + LC->parent=RC->parent=P; + P->left=LC; + P->right=RC; + P->bootstrap=best_s*100; + used[best_b]=1; + + n[0]--; + + for (a=0; anseq; a++) + { + P->lseq2[a]=(LC->lseq2[a] || RC->lseq2[a])?1:0; + } + + for (a=0; anseq+1, sizeof (char)); + } + + + + for ( a=0; anseq; a++) + split[a]=((L->lseq2[a] || R->lseq2[a])?1:0)+'0'; + + n=0; + while (S[n]) + { + float score; + if ( strm (S[n]->split,split)) + { + return score=100-S[n]->score; + } + n++; + } + return 100; +} +/******************************COPYRIGHT NOTICE*******************************/ +/*© Centro de Regulacio Genomica */ +/*and */ +/*Cedric Notredame */ +/*Fri Feb 18 08:27:45 CET 2011 - Revision 596. */ +/*All rights reserved.*/ +/*This file is part of T-COFFEE.*/ +/**/ +/* T-COFFEE is free software; you can redistribute it and/or modify*/ +/* it under the terms of the GNU General Public License as published by*/ +/* the Free Software Foundation; either version 2 of the License, or*/ +/* (at your option) any later version.*/ +/**/ +/* T-COFFEE is distributed in the hope that it will be useful,*/ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the*/ +/* GNU General Public License for more details.*/ +/**/ +/* You should have received a copy of the GNU General Public License*/ +/* along with Foobar; if not, write to the Free Software*/ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/*............................................... |*/ +/* If you need some more information*/ +/* cedric.notredame@europe.com*/ +/*............................................... |*/ +/**/ +/**/ +/* */ +/******************************COPYRIGHT NOTICE*******************************/ diff --git a/binaries/src/tcoffee/tclinkdb.txt b/binaries/src/tcoffee/tclinkdb.txt new file mode 100644 index 0000000..082f3f1 --- /dev/null +++ b/binaries/src/tcoffee/tclinkdb.txt @@ -0,0 +1,357 @@ +PG t_coffee 4_TCOFFEE TCOFFEE +PG t_coffee type sequence_multiple_aligner +PG t_coffee ADDRESS http://www.tcoffee.org +PG t_coffee language C +PG t_coffee language2 C +PG t_coffee source http://www.tcoffee.org/Packages/T-COFFEE_distribution.tar.gz +PG t_coffee update_action always +PG t_coffee mode tcoffee,mcoffee,rcoffee,expresso,3dcoffee + + +PG clustalw2 4_TCOFFEE CLUSTALW2 +PG clustalw2 type sequence_multiple_aligner +PG clustalw2 ADDRESS http://www.clustal.org +PG clustalw2 language C++ +PG clustalw2 language2 CXX +PG clustalw2 source http://www.clustal.org/download/2.0.10/clustalw-2.0.10-src.tar.gz +PG clustalw2 mode mcoffee,rcoffee +PG clustalw2 version 2.0.10 + +PG clustalw 4_TCOFFEE CLUSTALW +PG clustalw type sequence_multiple_aligner +PG clustalw ADDRESS http://www.clustal.org +PG clustalw language C +PG clustalw language2 C +PG clustalw source http://www.clustal.org/download/1.X/ftp-igbmc.u-strasbg.fr/pub/ClustalW/clustalw1.82.UNIX.tar.gz +PG clustalw mode mcoffee,rcoffee +PG clustalw version 1.82 + +PG dialign-t 4_TCOFFEE DIALIGNT +PG dialign-t type sequence_multiple_aligner +PG dialign-t ADDRESS http://dialign-tx.gobics.de/ +PG dialign-t DIR /usr/share/dialign-tx/ +PG dialign-t language C +PG dialign-t language2 C +PG dialign-t source http://dialign-tx.gobics.de/DIALIGN-TX_1.0.2.tar.gz +PG dialign-t mode mcoffee +PG dialign-t binary dialign-t +PG dialign-t version 1.0.2 + +PG dialign-tx 4_TCOFFEE DIALIGNTX +PG dialign-tx type sequence_multiple_aligner +PG dialign-tx ADDRESS http://dialign-tx.gobics.de/ +PG dialign-tx DIR /usr/share/dialign-tx/ +PG dialign-tx language C +PG dialign-tx language2 C +PG dialign-tx source http://dialign-tx.gobics.de/DIALIGN-TX_1.0.2.tar.gz +PG dialign-tx mode mcoffee +PG dialign-tx binary dialign-tx +PG dialign-tx version 1.0.2 + +PG poa 4_TCOFFEE POA +PG poa type sequence_multiple_aligner +PG poa ADDRESS http://www.bioinformatics.ucla.edu/poa/ +PG poa language C +PG poa language2 C +PG poa source http://downloads.sourceforge.net/poamsa/poaV2.tar.gz +PG poa DIR /usr/share/ +PG poa FILE1 blosum80.mat +PG poa mode mcoffee +PG poa binary poa +PG poa version 2.0 + +PG probcons 4_TCOFFEE PROBCONS +PG probcons type sequence_multiple_aligner +PG probcons ADDRESS http://probcons.stanford.edu/ +PG probcons language2 CXX +PG probcons language C++ +PG probcons source http://probcons.stanford.edu/probcons_v1_12.tar.gz +PG probcons mode mcoffee +PG probcons binary probcons +PG probcons version 1.12 + +PG mafft 4_TCOFFEE MAFFT +PG mafft type sequence_multiple_aligner +PG mafft ADDRESS http://align.bmr.kyushu-u.ac.jp/mafft/online/server/ +PG mafft language C +PG mafft language C +PG mafft source http://align.bmr.kyushu-u.ac.jp/mafft/software/mafft-6.603-with-extensions-src.tgz +PG mafft windows http://align.bmr.kyushu-u.ac.jp/mafft/software/mafft-6.603-mingw.tar +PG mafft mode mcoffee,rcoffee +PG mafft binary mafft.tar.gz +PG mafft version 6.603 + +PG muscle 4_TCOFFEE MUSCLE +PG muscle type sequence_multiple_aligner +PG muscle ADDRESS http://www.drive5.com/muscle/ +PG muscle language C++ +PG muscle language2 GPP +PG muscle source http://www.drive5.com/muscle/downloads3.7/muscle3.7_src.tar.gz +PG muscle windows http://www.drive5.com/muscle/downloads3.7/muscle3.7_win32.zip +PG muscle linux http://www.drive5.com/muscle/downloads3.7/muscle3.7_linux_ia32.tar.gz +PG muscle mode mcoffee,rcoffee +PG muscle version 3.7 + +PG mus4 4_TCOFFEE MUS4 +PG mus4 type sequence_multiple_aligner +PG mus4 ADDRESS http://www.drive5.com/muscle/ +PG mus4 language C++ +PG mus4 language2 GPP +PG mus4 source http://www.drive5.com/muscle/muscle4.0_src.tar.gz +PG mus4 mode mcoffee,rcoffee +PG mus4 version 4.0 + + +PG pcma 4_TCOFFEE PCMA +PG pcma type sequence_multiple_aligner +PG pcma ADDRESS ftp://iole.swmed.edu/pub/PCMA/ +PG pcma language C +PG pcma language2 C +PG pcma source ftp://iole.swmed.edu/pub/PCMA/pcma.tar.gz +PG pcma mode mcoffee +PG pcma version 1.0 + +PG kalign 4_TCOFFEE KALIGN +PG kalign type sequence_multiple_aligner +PG kalign ADDRESS http://msa.cgb.ki.se +PG kalign language C +PG kalign language2 C +PG kalign source http://msa.cgb.ki.se/downloads/kalign/current.tar.gz +PG kalign mode mcoffee +PG kalign version 1.0 + + +PG amap 4_TCOFFEE AMAP +PG amap type sequence_multiple_aligner +PG amap ADDRESS http://bio.math.berkeley.edu/amap/ +PG amap language C++ +PG amap language2 CXX +PG amap source http://amap-align.googlecode.com/files/amap.2.0.tar.gz +PG amap mode mcoffee +PG amap version 2.0 + + +PG proda 4_TCOFFEE PRODA +PG proda type sequence_multiple_aligner +PG proda ADDRESS http://proda.stanford.edu +PG proda language C++ +PG proda language2 CXX +PG proda source http://proda.stanford.edu/proda_1_0.tar.gz +PG proda mode mcoffee +PG proda version 1.0 + +PG fsa 4_TCOFFEE FSA +PG fsa type sequence_multiple_aligner +PG fsa ADDRESS http://fsa.sourceforge.net/ +PG fsa language C++ +PG fsa language2 CXX +PG fsa source http://sourceforge.net/projects/fsa/files/fsa-1.15.3.tar.gz/download/ +PG fsa mode mcoffee +PG fsa version 1.15.3 + +PG prank 4_TCOFFEE PRANK +PG prank type sequence_multiple_aligner +PG prank ADDRESS http://www.ebi.ac.uk/goldman-srv/prank/ +PG prank language C++ +PG prank language2 CXX +PG prank source http://www.ebi.ac.uk/goldman-srv/prank/src/prank/prank.src.100303.tgz +PG prank mode mcoffee +PG prank version 100303 + +PG sap 4_TCOFFEE SAP +PG sap type structure_pairwise_aligner +PG sap ADDRESS http://mathbio.nimr.mrc.ac.uk/wiki/Software +PG sap language C +PG sap language2 C +PG sap source http://mathbio.nimr.mrc.ac.uk/download/sap-1.1.1.tar.gz +PG sap mode expresso,3dcoffee +PG sap version 1.1.1 + +PG TMalign 4_TCOFFEE TMALIGN +PG TMalign type structure_pairwise_aligner +PG TMalign ADDRESS http://zhang.bioinformatics.ku.edu/TM-align/TMalign.f +PG TMalign language Fortran +PG TMalign language2 Fortran +PG TMalign source http://zhang.bioinformatics.ku.edu/TM-align/TMalign.f +PG TMalign linux http://zhang.bioinformatics.ku.edu/TM-align/TMalign_32.gz +PG TMalign mode expresso,3dcoffee +PG TMalign version 1.0 + + +PG mustang 4_TCOFFEE MUSTANG +PG mustang type structure_pairwise_aligner +PG mustang ADDRESS http://www.cs.mu.oz.au/~arun/mustang +PG mustang language C++ +PG mustang language2 CXX +PG mustang source http://ww2.cs.mu.oz.au/~arun/mustang/mustang_v3.2.1.tgz +PG mustang mode expresso,3dcoffee +PG mustang version 3.2.1 + +PG lsqman 4_TCOFFEE LSQMAN +PG lsqman type structure_pairwise_aligner +PG lsqman ADDRESS empty +PG lsqman language empty +PG lsqman language2 empty +PG lsqman source empty +PG lsqman update_action never +PG lsqman mode expresso,3dcoffee + +PG align_pdb 4_TCOFFEE ALIGN_PDB +PG align_pdb type structure_pairwise_aligner +PG align_pdb ADDRESS empty +PG align_pdb language empty +PG align_pdb language2 empty +PG align_pdb source empty +PG align_pdb update_action never +PG align_pdb mode expresso,3dcoffee + + +PG fugueali 4_TCOFFEE FUGUE +PG fugueali type structure_pairwise_aligner +PG fugueali ADDRESS http://www-cryst.bioc.cam.ac.uk/fugue/download.html +PG fugueali language empty +PG fugueali language2 empty +PG fugueali source empty +PG fugueali update_action never +PG fugueali mode expresso,3dcoffee + +PG dalilite.pl 4_TCOFFEE DALILITEc +PG dalilite.pl type structure_pairwise_aligner +PG dalilite.pl ADDRESS built_in +PG dalilite.pl ADDRESS2 http://www.ebi.ac.uk/Tools/webservices/services/dalilite +PG dalilite.pl language Perl +PG dalilite.pl language2 Perl +PG dalilite.pl source empty +PG dalilite.pl update_action never +PG dalilite.pl mode expresso,3dcoffee + +PG probconsRNA 4_TCOFFEE PROBCONSRNA +PG probconsRNA type RNA_multiple_aligner +PG probconsRNA ADDRESS http://probcons.stanford.edu/ +PG probconsRNA language C++ +PG probconsRNA language2 CXX +PG probconsRNA source http://probcons.stanford.edu/probconsRNA.tar.gz +PG probconsRNA mode mcoffee,rcoffee +PG probconsRNA version 1.0 + +PG sfold 4_TCOFFEE CONSAN +PG sfold type RNA_pairwise_aligner +PG sfold ADDRESS http://selab.janelia.org/software/consan/ +PG sfold language empty +PG sfold language2 empty +PG sfold source empty +PG sfold update_action never +PG sfold mode rcoffee + +PG RNAplfold 4_TCOFFEE RNAPLFOLD +PG RNAplfold type RNA_secondarystructure_predictor +PG RNAplfold ADDRESS http://www.tbi.univie.ac.at/~ivo/RNA/ +PG RNAplfold language C +PG RNAplfold language2 C +PG RNAplfold source http://www.tbi.univie.ac.at/~ivo/RNA/ViennaRNA-1.7.2.tar.gz +PG RNAplfold mode rcoffee, seq_reformat +PG RNAplfold version 1.7.2 + +PG retree 4_TCOFFEE PHYLIP +PG retree type RNA_secondarystructure_predictor +PG retree ADDRESS http://evolution.gs.washington.edu/phylip/ +PG retree language C +PG retree language2 C +PG retree source http://evolution.gs.washington.edu/phylip/download/phylip-3.69.tar.gz +PG retree mode trmsd, seq_reformat +PG retree version 3.69 + + +PG hmmtop 4_TCOFFEE HMMTOP +PG hmmtop type protein_secondarystructure_predictor +PG hmmtop ADDRESS www.enzim.hu/hmmtop/ +PG hmmtop language C +PG hmmtop language2 C +PG hmmtop source empty +PG hmmtop update_action never +PG hmmtop mode tcoffee + +PG gorIV 4_TCOFFEE GOR4 +PG gorIV type protein_secondarystructure_predictor +PG gorIV ADDRESS http://mig.jouy.inra.fr/logiciels/gorIV/ +PG gorIV language C +PG gorIV language2 C +PG gorIV source http://mig.jouy.inra.fr/logiciels/gorIV/GOR_IV.tar.gz +PG gorIV update_action never +PG gorIV mode tcoffee + +PG wublast.pl 4_TCOFFEE EBIWUBLASTc +PG wublast.pl type protein_homology_predictor +PG wublast.pl ADDRESS built_in +PG wublast.pl ADDRESS2 http://www.ebi.ac.uk/Tools/webservices/services/wublast +PG wublast.pl language Perl +PG wublast.pl language2 Perl +PG wublast.pl source empty +PG wublast.pl update_action never +PG wublast.pl mode psicoffee,expresso,accurate + +PG blastpgp.pl 4_TCOFFEE EBIBLASTPGPc +PG blastpgp.pl type protein_homology_predictor +PG blastpgp.pl ADDRESS built_in +PG blastpgp.pl ADDRESS2 http://www.ebi.ac.uk/Tools/webservices/services/blastpgp +PG blastpgp.pl language Perl +PG blastpgp.pl language2 Perl +PG blastpgp.pl source empty +PG blastpgp.pl update_action never +PG blastpgp.pl mode psicoffee,expresso,accurate + + +PG blastcl3 4_TCOFFEE NCBIWEBBLAST +PG blastcl3 type protein_homology_predictor +PG blastcl3 ADDRESS ftp://ftp.ncbi.nih.gov/blast/executables/LATEST +PG blastcl3 language C +PG blastcl3 language2 C +PG blastcl3 source empty +PG blastcl3 update_action never +PG blastcl3 mode psicoffee,expresso,3dcoffee + +PG blastall 4_TCOFFEE blastall +PG blastall type protein_homology_predictor +PG blastall ADDRESS ftp://ftp.ncbi.nih.gov/blast/executables/LATEST +PG blastall language C +PG blastall language2 C +PG blastall source empty +PG blastall update_action never +PG blastall mode psicoffee,expresso,3dcoffee + +PG legacy_blast.pl 4_TCOFFEE NCBIBLAST +PG legacy_blast.pl type protein_homology_predictor +PG legacy_blast.pl ADDRESS ftp://ftp.ncbi.nih.gov/blast/executables/LATEST +PG legacy_blast.pl language C +PG legacy_blast.pl language2 C +PG legacy_blast.pl source empty +PG legacy_blast.pl update_action never +PG legacy_blast.pl mode psicoffee,expresso,3dcoffee + +PG SOAP::Lite 4_TCOFFEE SOAPLITE +PG SOAP::Lite type library +PG SOAP::Lite ADDRESS http://cpansearch.perl.org/src/MKUTTER/SOAP-Lite-0.710.08/Makefile.PL +PG SOAP::Lite language Perl +PG SOAP::Lite language2 Perl +PG SOAP::Lite source empty +PG blastpgp update_action never +PG SOAP::Lite mode none + +PG XML::Simple 4_TCOFFEE XMLSIMPLE +PG XML::Simple type library +PG XML::Simple ADDRESS http://search.cpan.org/~grantm/XML-Simple-2.18/lib/XML/Simple.pm +PG XML::Simple language Perl +PG XML::Simple language2 Perl +PG XML::Simple source empty +PG XML::Simple mode psicoffee,expresso,accurate + + + +MODE tcoffee name tcoffee +MODE rcoffee name rcoffee +MODE 3dcoffee name 3dcoffee +MODE mcoffee name mcoffee +MODE expresso name expresso +MODE trmsd name trmsd +MODE accurate name accurate +MODE seq_reformat name seq_reformat -- 1.7.10.2
  • Wf3mGvIYn4lZfZ> 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ⅆ6r`4us;y6U730MnLH4m!OMQP6xHKEnbF&y6H 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