pax_global_header00006660000000000000000000000064135366437220014525gustar00rootroot0000000000000052 comment=d6667e78bbde00232ff25d3b6f16964cc7639378 wtdbg2-2.5/000077500000000000000000000000001353664372200125645ustar00rootroot00000000000000wtdbg2-2.5/.gitignore000066400000000000000000000000261353664372200145520ustar00rootroot00000000000000*.o *.a .*.swp *.dSYM wtdbg2-2.5/.travis.yml000066400000000000000000000000651353664372200146760ustar00rootroot00000000000000language: c compiler: - gcc - clang script: make wtdbg2-2.5/LICENSE.txt000066400000000000000000001045131353664372200144130ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. 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 them 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 prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. 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. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey 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; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If 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 convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU 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 that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. 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. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 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. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. 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 state 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 3 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, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program 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, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU 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 Lesser General Public License instead of this License. But first, please read . wtdbg2-2.5/Makefile000066400000000000000000000032101353664372200142200ustar00rootroot00000000000000VERSION=2.5 RELEASE=20190621 CC := gcc BIN := /usr/local/bin ifeq (0, ${MAKELEVEL}) TIMESTAMP=$(shell date) endif ifeq (1, ${DEBUG}) CFLAGS=-g3 -W -Wall -Wno-unused-but-set-variable -O0 -DDEBUG=1 -DVERSION="$(VERSION)" -DRELEASE="$(RELEASE)" -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -mpopcnt -msse4.2 else CFLAGS=-g3 -W -Wall -Wno-unused-but-set-variable -O4 -DVERSION="$(VERSION)" -DRELEASE="$(RELEASE)" -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -mpopcnt -msse4.2 endif GLIBS=-lm -lrt -lpthread -lz GENERIC_SRC=mem_share.h chararray.h sort.h list.h pgzf.h sort.h list.h dna.h thread.h filereader.h filewriter.h bitvec.h bit2vec.h bitsvec.h hashset.h PROGS=kbm2 wtdbg2 wtdbg-cns wtpoa-cns pgzf all: $(PROGS) kbm2: $(GENERIC_SRC) kbm.c kbm.h kbmpoa.h wtpoa.h tripoa.h poacns.h kswx.h ksw.h ksw.c $(CC) $(CFLAGS) -o $@ kbm.c ksw.c $(GLIBS) wtdbg2: $(GENERIC_SRC) wtdbg.c wtdbg-graph.h wtdbg.h kbm.h kswx.h ksw.h ksw.c kbmpoa.h wtpoa.h tripoa.h poacns.h $(CC) $(CFLAGS) -o $@ wtdbg.c ksw.c $(GLIBS) wtdbg-cns: $(GENERIC_SRC) wtdbg-cns.c kswx.h ksw.h ksw.c dbgcns.h dagcns.h queue.h general_graph.h $(CC) $(CFLAGS) -o wtdbg-cns wtdbg-cns.c ksw.c $(GLIBS) wtpoa-cns: $(GENERIC_SRC) wtpoa.h wtpoa-cns.c poacns.h tripoa.h ksw.h ksw.c $(CC) $(CFLAGS) -o $@ wtpoa-cns.c ksw.c $(GLIBS) pgzf: mem_share.h sort.h list.h thread.h pgzf.h pgzf.c $(CC) $(CFLAGS) -o $@ pgzf.c $(GLIBS) best_sam_hits4longreads: $(GENERIC_SRC) best_sam_hits4longreads.c $(CC) $(CFLAGS) -o $@ best_sam_hits4longreads.c $(GLIBS) clean: rm -f *.o *.gcda *.gcno *.gcov gmon.out $(PROGS) clear: rm -f *.o *.gcda *.gcno *.gcov gmon.out install: $(PROGS) mkdir -p $(BIN) && cp -fvu $(PROGS) $(BIN) wtdbg2-2.5/README-ori.md000066400000000000000000000241041353664372200146330ustar00rootroot00000000000000# NEWS * |2018-09-21| Rename wtdbg-1.2.8 to wtdbg2 * |2018-09-19| GFA supports ```sh wtdbg-dot2gfa.pl dbg.3.dot >dbg.3.gfa ``` * |2018-09-01| New consensus module: POACNS
```sh wtpoa-cns -t 0 -i dbg.ctg.lay -fo dbg.ctg.poacns.fa ``` 1, wtpoa-cns implements POA to generate MSA from reads fragments within an edge. Used SSE instructions, but seems still can be further improved in speed
2, performs realignment on MSA.
3, recalibrates homopolymers, and make consensus sequence for an edge. Most reamining small errors come from homopolymer, more efforts are needed
4, joins edges' sequences into a contig.
Welcome to test POACNS and feedback. # WTDBG A fuzzy Bruijn graph (FBG) approach to long noisy reads assembly # Introduction A challenge in assembling long noisy reads from third generation sequencing (TGS) is reducing its requirement of computing resource, especially for large genomes. To address this issue, I developed a novel sequence alignment algorithm and a new assembly graph for efficiently assembling large genomes using TGS data. * Alignment
KBM: Kmer-BIN-Mapping.
KBM groups k-mers from each non-overlapped sliding 256 bp fragments in long reads into bins. Bins of which most k-mers are high frequency, are filtered as highly repetitive ones. Then, KBM searches synteny of matched bin pairs in sequences in a dynamic programming way. A matched bin pair in two sequences is defined as two bins different by original but share a set of k-mers. The result of alignments in KBM have the same features of traditional sequence alignment, excepting the unit of KBM alignments is 256 bp bin instead of single base. * Assembly
FBG: Fuzzy Bruijn Graph.
FBG is composed of vertices in length of 1024 bp from reads, and edges connecting vertices in their order on read paths. Comparing with DBG, the size of vertices in FBG are much bigger, thus wonĄŻt be sensitive to small repeat. To tolerate high sequencing errors, FBG's vertices are found using gapped sequence alignments from KBM or other aligners, comparing with searching identical k-mers in DBG. * Why choose wtdbg in genome assembly
There are many assemblers for long noisy reads assembly, e.g. FALCON, CANU, miniasm, and SMARTdenovo (progenitor of wtdbg). If you have a genome of 10G bp or bigger in size, wtdbg is your first or even the only option. For small but complicated genomes (< 3 G), wtdbg was often reported to yield better assembly by my friends. Besides, KBM is easy to use when you are setting up a web-server for long reads mapping (see Example 2). * Limitation
Max read length is 0x0003FFFFU (256 Kb), longer reads will be split.
Max number of reads is 0x03FFFFFFU (64 M). If your data volume exceeds, please filter relative shorter reads.
In KBM, max read length is 0xFFFFFFFFU (4 Gb), max number of reads is 0x0FFFFFFFU (256 M).
Max number of threads is 4096.
Cannot parallelly run in multiple nodes. But you can implement it simplely using `kbm` and `wtdbg --load-alignments`
Developed and tested in Linux-GCC only.
Only accepts fasta/fastq format for input, '.gz' suffixed files will be piped by `gzip -dc`. # Installation ```sh git clone https://github.com/ruanjue/wtdbg2.git cd wtdbg2 make ``` # Long reads mapping Supposes you have `hg19.fa` as reference sequences, and `reads.fq.gz` as query sequences. ## Example 1 ```sh kbm -t 64 -d hg19.fa -i reads.fa.gz -o reads.kbmap ``` ### output format * COL1 `qry_name` * COL2 `qry_strand` * COL3 `qry_length` * COL4 `qry_beg` * COL5 `qry_end` * COL6 `ref_name` * COL7 `ref_strand` (always equals `+`) * COL8 `ref_length` * COL9 `ref_beg` * COL10 `ref_end` * COL11 `match_len` (length of matched k-mers) * COL12 `align_len` (length of aligned) * COL13 `#kcnt` (number of matched k-mers) * COL14 `#gap` (number of gapped BINs) * COL15 `cigar` (256 x SAM's cigar) ## Example 2 Suitable for online tools, or frequently used references ### Build KBM-INDEX ```sh kbm -t 64 -d hg19.fa -i /dev/null -W hg19.kbmidx ``` ### Set up KBM server ```sh kbm -R hg19.kbmidx start ``` Now, hg19.kbmidx is cached in memory for further call. ### Mapping with KBM-INDEX ```sh kbm -R hg19.kbmidx -t 64 -i reads.fa -o reads.kbmap ``` Please note that, hg19.kbmidx can be multilple called by any processes in the same computer.
### Shutdown KBM server ```sh kbm -R hg19.kbmidx stop ``` # Long reads assembling ## Quick Start ```sh echo "manual" run_wtdbg_assembly.sh -h echo "generating shell script" run_wtdbg_assembly.sh -t 0 -i reads.fa.gz -o dbg -T >run.sh ``` `run.sh` is ready for invoked ## Play with wtdbg ```sh wtdbg2 -h wtdbg2 --help ``` ### options ```sh -t Number of threads, 0: all cores, [0] -i Long reads sequences file, + * -I Error-free sequences file, + -o Prefix of output files, * -f Force overwrite -k Kmer fsize, 0 <= k <= 25, [0] -p Kmer psize, 0 <= p <= 25, [21] k + p <= 25, seed is + -K Filter high frequency kmers, maybe repetitive, [1000] if K >= 1, take the integer value as cutoff else, mask the top fraction part high frequency kmers -E Min kmer frequency, [2] -F Filter low frequency kmers by a 4G-bytes array (max_occ=3 2-bits). Here, -E must greater than 1 -S Subsampling kmers, 1/(<-S>) kmers are indexed, [4] -S is very useful in saving memeory and speeding up please note that subsampling kmers will have less matched length -X Max number of bin(256bp) in one gap, [4] -Y Max number of bin(256bp) in one deviation, [4] -x penalty for BIN gap, [-7] -y penalty for BIN deviation, [-21] -l Min length of alignment, [2048] -m Min matched, [200] -s Max length variation of two aligned fragments, [0.2] -q Quiet -v Verbose, + --help Show more options ``` ### For higher error rate long sequences Decrease `-p`. Try `-p 19` or `-p 17`
Decrease `-S`. Try `-S 2` or `-S 1`
Both will increase computing time. ### For very high coverage Increase `--edge-min`. Try `--edge-min 4`, or higher. ### For low coverage Decrease `--edge-min`. Try `--edge-min 2 --rescue-low-cov-edges`. ### Filter reads `--tidy-reads 5000`. Will filtered shorter sequences. If names in format of `\/\d+_\d+$`, will selected the longest subread. ### output Suppose the prefix is `dbg` * dbg.1.dot
DOT file for initialized graph * dbg.1.nodes
nodes and their positions in reads * dbg.1.reads
reads and their nodes * dbg.2.dot
DOT file after transitive reduction * dbg.3.dot
DOT file after merging bubble and remove tips * dbg.alignments
KBMAP file, all vs all alignments * dbg.binkmer
Distribution of number of k-mers in a BIN * dbg.closed\_bins
Filtered BINs * dbg.clps Reads clip information.
COL1 read\_name
COL2 read\_length
COL3 keep\_offset
COL4 keep\_length * dbg.ctg.dot
DOT file for contigs * dbg.ctg.lay
Contigs layout file. Will be read by `wtdbg-cns`. This file is the main result of `wtdbg`
**Format**:
``` >ctg(\d+) nodes=(\d+) len=(\d+) E S S S ... E ... ... ``` One contig contains many edges (starting with 'E'), each edge contains many regions inside reads.
Please note that one read often contains many REGs. * dbg.events
Log file of graph simplification * dbg.frg.dot
DOT file for unitigs * dbg.frg.nodes
unitigs and their nodes * dbg.kmerdep
Distribution of k-mer depth * STDERR stream
wtdbg print runtime information on progrom's STDERR stream. `--quiet` to disiable it ## Consensus ```sh wtdbg-cns -t 64 -i dbg.ctg.lay -o dbg.ctg.lay.fa ``` The output file `dbg.ctg.lay.fa` is ready for further polished by `PILON` or `QUIVER`. ```sh wtpoa-cns -t 64 -i dbg.ctg.lay -o dbg.ctg.lay.fa ``` wtpoa-cns is slower than wtdbg-cns, but offer more accurate consensus sequences. I will update it in following development. # Performance ## Human (3G) CHM1 PacBio P5C3 dataset, 65.5 core.hours * Data Source http://datasets.pacb.com/2014/Human54x/fasta.html * Command ```sh wtdbg2 -t 96 -i pb.fa -fo dbg --tidy-reads 5000 --edge-min 2 --rescue-low-cov-edges ``` * Contigs `TOT 2978536704, CNT 8752, AVG 340327, MAX 11662848, N50 1925120, L50 453, N90 400128, L90 1727, Min 5120` * Runtime `real 6131.803 sec, user 201836.200 sec, sys 33956.790 sec, maxrss 117281672.0 kB, maxvsize 202422172.0 kB` ## Human (3G) CHM1 PacBio P6C4 dataset, 211.3 core.hours * Data Source http://www.ebi.ac.uk/ena/data/view/PRJNA246220 * Command ```sh wtdbg2 -t 96 -i wt.fa -fo dbg --tidy-reads 5000 --edge-min 4 --rescue-low-cov-edges ``` * Contigs `TOT 2964872448, CNT 1909, AVG 1553103, MAX 105310208, N50 23586816, L50 34, N90 3326976, L90 158, Min 5120` * Runtime `real 16806.534 sec, user 681278.770 sec, sys 79371.630 sec, maxrss 264956752.0 kB, maxvsize 443356532.0 kB` ## Axolotl (32G) PacBio dataset, 32 X, 3053 core.hours * Command ```sh wtdbg2 -t 96 -i ../rawdata/pacbio.fa.gz -p 21 -S 2 --aln-noskip --rescue-low-cov-edges --tidy-reads 5000 -fo axolotl ``` * Contigs `TOT 27375160576, CNT 115355, AVG 237313, MAX 7812608, N50 606976, L50 12527, N90 144896, L90 47295, Min 5120` * Runtime `real 190237.591 sec, user 10994200.800 sec, sys 488715.030 sec, maxrss 1671005352.0 kB, maxvsize 2365400208.0 kB` ## Human (3G) NA12878 ONT dataset, 197.5 core.hours * Data Source https://github.com/nanopore-wgs-consortium/NA12878 * Command ```sh wtdbg2 -t 64 -i NA12878-ONT.fa.gz -fo dbg -S 2 --edge-min 2 --rescue-low-cov-edges ``` * Contigs `TOT 2827644928, CNT 19473, AVG 145209, MAX 31366400, N50 4540672, L50 162, N90 172800, L90 1111, Min 5120` * Runtime `real 14992.925 sec, user 649202.270 sec, sys 61638.300 sec, maxrss 256840096.0 kB, maxvsize 356668088.0 kB` # Citation To be published.
URL **https://github.com/ruanjue/wtdbg2/**
# Contact Jue Ruan
Jue Ruan wtdbg2-2.5/README.md000066400000000000000000000156451353664372200140560ustar00rootroot00000000000000## Getting Started ```sh git clone https://github.com/ruanjue/wtdbg2 cd wtdbg2 && make #quick start with wtdbg2.pl ./wtdbg2.pl -t 16 -x rs -g 4.6m -o dbg reads.fa.gz # Step by step commandlines # assemble long reads ./wtdbg2 -x rs -g 4.6m -i reads.fa.gz -t 16 -fo dbg # derive consensus ./wtpoa-cns -t 16 -i dbg.ctg.lay.gz -fo dbg.raw.fa # polish consensus, not necessary if you want to polish the assemblies using other tools minimap2 -t16 -ax map-pb -r2k dbg.raw.fa reads.fa.gz | samtools sort -@4 >dbg.bam samtools view -F0x900 dbg.bam | ./wtpoa-cns -t 16 -d dbg.raw.fa -i - -fo dbg.cns.fa # Addtional polishment using short reads bwa mem -t 16 dbg.cns.fa sr.1.fa sr.2.fa | samtools sort -O SAM | ./wtpoa-cns -t 16 -x sam-sr -d dbg.cns.fa -i - -fo dbg.srp.fa ``` ## Introduction Wtdbg2 is a *de novo* sequence assembler for long noisy reads produced by PacBio or Oxford Nanopore Technologies (ONT). It assembles raw reads without error correction and then builds the consensus from intermediate assembly output. Wtdbg2 is able to assemble the human and even the 32Gb [Axolotl][Axolotl] genome at a speed tens of times faster than [CANU][canu] and [FALCON][falcon] while producing contigs of comparable base accuracy. During assembly, wtdbg2 chops reads into 1024bp segments, merges similar segments into a vertex and connects vertices based on the segment adjacency on reads. The resulting graph is called fuzzy Bruijn graph (FBG). It is akin to De Bruijn graph but permits mismatches/gaps and keeps read paths when collapsing k-mers. The use of FBG distinguishes wtdbg2 from the majority of long-read assemblers. ## Installation Wtdbg2 only works on 64-bit Linux. To compile, please type `make` in the source code directory. You can then copy `wtdbg2` and `wtpoa-cns` to your `PATH`. Wtdbg2 also comes with an approxmimate read mapper `kbm`, a faster but less accurate consesus tool `wtdbg-cns` and many auxiliary scripts in the `scripts` directory. ## Usage Wtdbg2 has two key components: an assembler **wtdbg2** and a consenser **wtpoa-cns**. Executable **wtdbg2** assembles raw reads and generates the contig layout and edge sequences in a file "*prefix*.ctg.lay.gz". Executable **wtpoa-cns** takes this file as input and produces the final consensus in FASTA. A typical workflow looks like this: ```sh ./wtdbg2 -x rs -g 4.6m -t 16 -i reads.fa.gz -fo prefix ./wtpoa-cns -t 16 -i prefix.ctg.lay.gz -fo prefix.ctg.fa ``` where `-g` is the estimated genome size and `-x` specifies the sequencing technology, which could take value "rs" for PacBio RSII, "sq" for PacBio Sequel, "ccs" for PacBio CCS reads and "ont" for Oxford Nanopore. This option sets multiple parameters and should be **applied before other parameters**. When you are unable to get a good assembly, you may need to tune other parameters as follows. Wtdbg2 combines normal k-mers and homopolymer-compressed (HPC) k-mers to find read overlaps. Option `-k` specifies the length of normal k-mers, while `-p` specifies the length of HPC k-mers. By default, wtdbg2 samples a fourth of all k-mers by their hashcodes. For data of relatively low coverage, you may increase this sampling rate by reducing `-S`. This will greatly increase the peak memory as a cost, though. Option `-e`, which defaults to 3, specifies the minimum read coverage of an edge in the assembly graph. You may adjust this option according to the overall sequencing depth, too. Option `-A` also helps relatively low coverage data at the cost of performance. For PacBio data, `-L5000` often leads to better assemblies emperically, so is recommended. Please run `wtdbg2 --help` for a complete list of available options or consult [README-ori.md](README-ori.md) for more help. The following table shows various command lines and their resource usage for the assembly step: |Dataset |GSize |Cov |Asm options |CPU asm |CPU cns |Real tot| RAM| |:-----------------------|-----:|-------:|:------------------|-------:|-------:|-------:|-------:| |[E. coli][pbcr] |4.6Mb |PB x20 |-x rs -g4.6m -t16 | 53s| 8m54s| 42s| 1.0G| |[C. elegans][ce] |100Mb |PB x80 |-x rs -g100m -t32 | 1h07m| 5h06m| 13m42s| 11.6G| |[D. melanogaster A4][dm2]| 144m|PB x120 |-x rs -g144m -t32 | 2h06m| 5h11m| 26m17s| 19.4G| |[D. melanogaster ISO1][dm1]|144m|ONT x32|-xont -g144m -t32 | 5h12m| 4h30m| 25m59s| 17.3G| |[A. thaliana][at] |125Mb |PB x75 |-x sq -g125m -t32 | 11h26m| 4h57m| 49m35s| 25.7G| |[Human NA12878][na12878]|3Gb |ONT x36 |-x ont -g3g -t31 | 793h11m| 97h46m| 31h03m| 221.8G| |[Human NA19240][na19240]|3Gb |ONT x35 |-x ont -g3g -t31 | 935h31m| 89h17m| 35h20m| 215.0G| |[Human HG00733][hg00733]|3Gb |PB x93 |-x sq -g3g -t47 |2114h26m| 152h24m| 52h22m| 338.1G| |[Human NA24385][na24385]|3Gb |CCS x28 |-x ccs -g3g -t31 | 231h25m| 58h48m| 10h14m| 112.9G| |[Human CHM1][chm1] |3Gb |PB x60 |-x rs -g3g -t96 | 105h33m| 139h24m| 5h17m| 225.1G| |[Axolotl][axosra] |32Gb |PB x32 |-x rs -g32g -t96 |2806h40m|1456h13m| 110h16m| 1788.1G| The timing was obtained on three local servers with different hardware configurations. There are also run-to-run fluctuations. Exact timing on your machines may differ. The assembled contigs can be found at the following FTP: ```txt ftp://ftp.dfci.harvard.edu/pub/hli/wtdbg/ ``` ## Limitations * For Nanopore data, wtdbg2 may produce an assembly smaller than the true genome. * When inputing multiple files of both fasta and fastq format, please put fastq first, then fasta. Otherwise, program cannot find '>' in fastq, and append all fastq in one read. ## Citing wtdbg2 If you use wtdbg2, please cite: > Ruan, J. and Li, H. (2019) Fast and accurate long-read assembly with wtdbg2. *bioRxiv*. doi:10.1101/530972 ## Getting Help Please use the [GitHub's Issues page][issue] if you have questions. You may also directly contact Jue Ruan at ruanjue@gmail.com. [miniasm]: https://github.com/lh3/miniasm [canu]: https://github.com/marbl/canu [falcon]: https://github.com/PacificBiosciences/FALCON [Axolotl]: https://www.nature.com/articles/nature25458 [chm1]: https://trace.ncbi.nlm.nih.gov/Traces/sra/?study=SRP044331 [na12878]: https://github.com/nanopore-wgs-consortium/NA12878/blob/master/rel5.md [na19240]: https://www.ebi.ac.uk/ena/data/view/PRJEB26791 [pbcr]: http://www.cbcb.umd.edu/software/PBcR/data/selfSampleData.tar.gz [ce]: https://github.com/PacificBiosciences/DevNet/wiki/C.-elegans-data-set [axosra]: https://www.ncbi.nlm.nih.gov/bioproject/?term=PRJNA378970 [issue]: https://github.com/ruanjue/wtdbg2/issues [at]: https://downloads.pacbcloud.com/public/SequelData/ArabidopsisDemoData/ [dm1]: https://www.ebi.ac.uk/ena/data/view/SRR6702603 [dm2]: https://www.ebi.ac.uk/ena/data/view/SRR5439404 [hg00733]: https://www.ebi.ac.uk/ena/data/view/SRR7615963 [na24385]: https://ftp-trace.ncbi.nlm.nih.gov/giab/ftp/data/AshkenazimTrio/HG002_NA24385_son/PacBio_CCS_15kb/ wtdbg2-2.5/best_sam_hits4longreads.c000066400000000000000000000123221353664372200175370ustar00rootroot00000000000000 #include "mem_share.h" #include "filereader.h" #include "list.h" #include "hashset.h" typedef struct { u4i stroff, strlen; u4i taglen, flag; u4i qlen, qb, qe; u4i refidx, reflen; } lr_hit_t; define_list(lrhitv, lr_hit_t); int select_best_hit(lrhitv *hits, String *lines, u4i minlen, float mincov, FILE *out){ lr_hit_t *h1, *h2; u4i i, j, pass; int x, y, ret; sort_array(hits->buffer, hits->size, lr_hit_t, num_cmpgt(b.qe - b.qb, a.qe - a.qb)); ret = 0; for(i=0;isize;i++){ h1 = ref_lrhitv(hits, i); if(h1->qe - h1->qb < minlen) break; if(h1->qe - h1->qb < UInt(mincov * h1->qlen)) break; pass = 1; for(j=0;jqb, h2->qb); y = num_min(h1->qe, h2->qe); if(y - x >= (1 - mincov) * (h1->qe - h1->qb)){ pass = 0; break; } } if(pass){ fprintf(out, "%s\n", lines->string + h1->stroff); ret ++; } } clear_lrhitv(hits); clear_string(lines); return ret; } int usage(char *prog){ printf( "Usage: %s [-h] [-v] [-B:retain secondary aligment] [-l min_map_len:100] [-f min_map_cov:0.70]\n" , prog ); return 1; } int main(int argc, char **argv){ FileReader *fr; FILE *out; cuhash *refs; cplist *reftags; u4v *reflens; String *lines; lrhitv *hits; lr_hit_t *hit, HIT; char *str, *reftag; u4i minlen, i, reflen; float mincov; int c, primary_hit, verbose; u1i movs[256]; minlen = 100; mincov = 0.70; primary_hit = 1; verbose = 0; out = stdout; while((c = getopt(argc, argv, "hvBl:f:")) != -1){ switch(c){ case 'l': minlen = atoi(optarg); break; case 'f': mincov = atof(optarg); break; case 'B': primary_hit = 0; break; case 'v': verbose = 1; break; default: return usage(argv[0]); } } fr = open_filereader(NULL, 1); refs = init_cuhash(13); reftags = init_cplist(8); reflens = init_u4v(8); hits = init_lrhitv(4); lines = init_string(1024); memset(movs, 0, 256); movs[(int)'M'] = 0b11; movs[(int)'I'] = 0b10; movs[(int)'D'] = 0b01; movs[(int)'N'] = 0b01; movs[(int)'S'] = 0b10; movs[(int)'H'] = 0b10; movs[(int)'P'] = 0b00; movs[(int)'='] = 0b11; movs[(int)'X'] = 0b11; while((c = readline_filereader(fr))){ if(fr->line->string[0] == '@'){ fprintf(out, "%s\n", fr->line->string); if(fr->line->string[1] == 'S' && fr->line->string[2] == 'Q'){ if((c = split_line_filereader(fr, '\t')) > 2){ reftag = NULL; reflen = 0; for(i=1;i<3;i++){ if(get_col_len(fr, i) <= 3){ continue; } str = get_col_str(fr, i); if(str[0] == 'S' && str[1] == 'N' && str[2] == ':'){ reftag = strdup(str + 3); } else if(str[0] == 'L' && str[1] == 'N' && str[2] == ':'){ reflen = atol(str + 3); } } if(strlen(reftag) && reflen){ push_cplist(reftags, reftag); push_u4v(reflens, reflen); put_cuhash(refs, (cuhash_t){reftag, reftags->size - 1}); } } } } else { hit = &HIT; str = index(fr->line->string, '\t'); if(str == NULL){ fprintf(stderr, "[WARNNING:too_few_column] %s\n", fr->line->string); continue; } hit->taglen = str - fr->line->string; if(hits->size && (hits->buffer[0].taglen != hit->taglen || strncmp(lines->string + hits->buffer[0].stroff, fr->line->string, hit->taglen))){ select_best_hit(hits, lines, minlen, mincov, out); } hit->stroff = lines->size; hit->strlen = fr->line->size; append_string(lines, fr->line->string, fr->line->size); add_char_string(lines, '\0'); if((c = split_line_filereader(fr, '\t')) < 11){ fprintf(stderr, "[WARNNING:too_few_columns] %s\n", lines->string + hit->stroff); continue; } hit->taglen = get_col_len(fr, 0); hit->flag = atol(get_col_str(fr, 1)); if(primary_hit && (hit->flag & 0x900)){ continue; } if(get_col_str(fr, 2)[0] == '*'){ continue; } hit->refidx = getval_cuhash(refs, get_col_str(fr, 2)); if(hit->refidx == MAX_U4){ fprintf(stderr, "[WARNNING:unknown_refname] %s\n", lines->string + hit->stroff); continue; } hit->reflen = reflens->buffer[hit->refidx]; hit->qlen = 0; u4i tb, te, qb, qe, len, cnt, tmp; u4i ln; char op; tb = atoi(get_col_str(fr, 3)); te = tb; qb = qe = 0; len = 0; tmp = cnt = 0; str = get_col_str(fr, 5); // CIGAR ln = 0; op = 0; while(str[0]){ if(str[0] >= '0' && str[0] <= '9'){ ln = ln * 10 + str[0] - '0'; } else { op = movs[(int)str[0]]; if(op & 0b01){ te += ln; qe += tmp; tmp = 0; if(cnt == 0){ qb = qe; cnt = 1; } if(op & 0b10){ qe += ln; len += ln; } } else if(op & 0b10){ tmp += ln; len += ln; } ln = 0; } str ++; } if(hit->flag & 0x10){ tmp = len - qb; qb = len - qe; qe = tmp; } hit->qlen = len; hit->qb = qb; hit->qe = qe; if(verbose){ fprintf(out, "#%s\t%u\t+\t%u\t%u\t%s\t%c\t%u\t%u\n", get_col_str(fr, 0), len, qb, qe, get_col_str(fr, 2), "+-"[(hit->flag & 0x10) >> 4], tb, te); } push_lrhitv(hits, HIT); } } select_best_hit(hits, lines, minlen, mincov, out); free_string(lines); free_lrhitv(hits); free_cuhash(refs); for(i=0;isize;i++){ free(reftags->buffer[i]); } free_cplist(reftags); free_u4v(reflens); close_filereader(fr); return 0; } wtdbg2-2.5/bit2vec.h000066400000000000000000000051361353664372200143000ustar00rootroot00000000000000/* * * Copyright (c) 2011, Jue Ruan * * * 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 3 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, see . */ #ifndef __BIT2_VEC_RJ_H #define __BIT2_VEC_RJ_H #include #include #include #include #include "mem_share.h" typedef struct { uint8_t *bits; uint64_t size; uint64_t cap; } Bit2Vec; static inline Bit2Vec* init_bit2vec(uint64_t size){ Bit2Vec *vec; vec = malloc(sizeof(Bit2Vec)); vec->size = 0; vec->cap = size; vec->bits = calloc(1, (size * 2 + 7) / 8); return vec; } static inline size_t bit2vec_obj_desc_cnt(void *obj, int idx){ return (((Bit2Vec*)obj)->cap * 2 + 7) / 8; idx = idx; } static const obj_desc_t bit2vec_obj_desc = {"bit2vec_obj_desc", sizeof(Bit2Vec), 1, {1}, {offsetof(Bit2Vec, bits)}, {(obj_desc_t*)&OBJ_DESC_DATA}, bit2vec_obj_desc_cnt, NULL}; static inline void clear_bit2vec(Bit2Vec *vec){ memset(vec->bits, 0, (vec->cap * 2 + 7) / 8); vec->size = 0; } static inline void free_bit2vec(Bit2Vec *vec){ free(vec->bits); free(vec); } static inline int encap_bit2vec(Bit2Vec *vec, uint32_t n){ uint64_t cap; if(vec->size + n <= vec->cap) return 0; cap = vec->cap; while(vec->size + n > vec->cap){ if(vec->cap < 1024 * 1024){ vec->cap <<= 1; } else { vec->cap += 1024 * 1024; } } vec->bits = realloc(vec->bits, (vec->cap * 2 + 7) / 8); memset(vec->bits + (cap * 2 + 7) / 8, 0, (vec->cap * 2 + 7) / 8 - (cap * 2 + 7) / 8); return 1; } static inline void set_bit2vec(Bit2Vec *vec, uint64_t idx, uint8_t dat){ vec->bits[idx >> 2] = (vec->bits[idx >> 2] & (~(3U << ((idx & 0x03U) << 1)))) | ((dat & 0x03) << ((idx & 0x03U) << 1)); } static inline void push_bit2vec(Bit2Vec *vec, uint8_t dat){ encap_bit2vec(vec, 1); set_bit2vec(vec, vec->size, dat); vec->size ++; } static inline uint8_t get_bit2vec(Bit2Vec *vec, uint64_t idx){ return (vec->bits[idx >> 2] >> ((idx & 0x03U) << 1)) & 0x03; } static inline int pop_bit2vec(Bit2Vec *vec){ if(vec->size == 0) return -1; vec->size --; return get_bit2vec(vec, vec->size); } #endif wtdbg2-2.5/bitsvec.h000066400000000000000000000121501353664372200143730ustar00rootroot00000000000000/* * * Copyright (c) 2011, Jue Ruan * * * 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 3 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, see . */ #ifndef __BITS_VEC_RJ_H #define __BITS_VEC_RJ_H #include #include #include #include #include "mem_share.h" /* Useful functions when n_bit > 8 */ static inline void u8byte2bits(uint64_t val, uint8_t *dat, uint64_t offset, uint8_t size){ uint8_t i, *v; v = (uint8_t*)&val; #if __BYTE_ORDER == 1234 for(i=0;i> 3] & (1U << (i & 0x7U))) dat[offset >> 3] |= 1U << (offset & 0x7U); else dat[offset >> 3] &= ~(1U << (offset & 0x7U)); offset ++; } #else for(i=0;i> 3)] & (1U << (i & 0x7U))) dat[offset >> 3] |= 1U << (offset & 0x7U); else dat[offset >> 3] &= ~(1U << (offset & 0x7U)); offset ++; } #endif } static inline uint64_t bits2u8byte(uint8_t *dat, uint64_t offset, uint8_t size){ uint64_t ret; uint8_t i, *v; ret = 0; v = (uint8_t*)&ret; #if __BYTE_ORDER == 1234 for(i=0;i> 3] & (1U << (offset & 0x7U))) v[i >> 3] |= 1U << (i & 0x7U); offset ++; } #else for(i=0;i> 3] & (1U << (offset & 0x7U))) v[7 - (i >> 3)] |= 1U << (i & 0x7U); offset ++; } #endif return ret; } typedef struct { uint8_t *bits; uint64_t size; uint64_t cap; uint8_t n_bit; uint32_t mask; } BitsVec; static inline BitsVec* init_bitsvec(uint64_t size, uint32_t n_bit){ BitsVec *vec; if(n_bit == 0) n_bit = 1; else if(n_bit > 8) n_bit = 8; if(size < 8) size = 8; vec = calloc(1, sizeof(BitsVec)); vec->n_bit = n_bit; vec->mask = (1U << n_bit) - 1U; vec->size = 0; vec->cap = size; vec->bits = calloc((size * vec->n_bit + 15) / 8, 1); return vec; } static inline size_t bitsvec_obj_desc_cnt(void *obj, int idx){ return (((BitsVec*)obj)->cap * ((BitsVec*)obj)->n_bit + 15) / 8; idx = idx; } static const obj_desc_t bitsvec_obj_desc = {"bitsvec_obj_desc", sizeof(BitsVec), 1, {1}, {offsetof(BitsVec, bits)}, {(obj_desc_t*)&OBJ_DESC_DATA}, bitsvec_obj_desc_cnt, NULL}; static inline void clear_bitsvec(BitsVec *vec){ vec->size = 0; } static inline void free_bitsvec(BitsVec *vec){ free(vec->bits); free(vec); } static inline int encap_bitsvec(BitsVec *vec, u8i n){ if(vec->size + n <= vec->cap) return 0; if(vec->size + n < 0x3FFFFFFFLLU){ vec->cap = roundup_power2(vec->size + n); } else { vec->cap = (vec->size + n + 0x3FFFFFFFLLU) & (MAX_U8 << 30); } vec->bits = realloc(vec->bits, (vec->cap * vec->n_bit + 15) / 8); return 1; } static inline void set_bitsvec(BitsVec *vec, u8i idx, u1i dat){ register u8i off; register u2i x, d; off = (idx * vec->n_bit); d = off & 0x07; off >>= 3; x = (((u2i)vec->bits[off + 1]) << 8) | vec->bits[off + 0]; x = (x & (~(vec->mask << d))) | ((UInt(dat) & vec->mask) << d); vec->bits[off] = x; vec->bits[off + 1] = x >> 8; } static inline void push_bitsvec(BitsVec *vec, u1i dat){ encap_bitsvec(vec, 1); set_bitsvec(vec, vec->size, dat); vec->size ++; } // TODO: need to be optimized static inline void pushs_bitsvec(BitsVec *vec, u1i dat, u8i len){ u8i i; encap_bitsvec(vec, len); for(i=0;isize + i, dat); } vec->size += len; } static inline u2i gets_bitsvec(BitsVec *vec, u8i idx){ u8i off; off = (idx * vec->n_bit); return ((((u2i)vec->bits[(off >> 3) + 1]) << 8) | vec->bits[(off >> 3) + 0]) >> (off & 0x07); } static inline uint8_t get_bitsvec(BitsVec *vec, u8i idx){ return gets_bitsvec(vec, idx) & vec->mask; } static inline void append_bitsvec(BitsVec *dst, BitsVec *src, u8i off, u8i len){ u8i i, di, si, se; u2i x; u1i p, n, sd; if(0){ // Assume dst->n_bit == src->n_bit if(dst->n_bit != src->n_bit){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); abort(); } } encap_bitsvec(dst, len); p = (dst->n_bit & 0x01)? 8 : (8 / dst->n_bit); n = dst->size % p; if(n) n = p - n; if(len <= n){ for(i=0;isize + i, get_bitsvec(src, off + i)); } dst->size += len; return; } else { for(i=0;isize + i, get_bitsvec(src, off + i)); } dst->size += n; } di = (dst->size * dst->n_bit) >> 3; si = ((off + i) * src->n_bit); sd = si & 0x07; si >>= 3; se = ((off + len) * src->n_bit + 7) >> 3; while(si < se){ x = ((src->bits[si + 1] << 8) | src->bits[si]) >> sd; dst->bits[di++] = x; si ++; } dst->size += len - i; } static inline int pop_bitsvec(BitsVec *vec){ if(vec->size == 0) return -1; vec->size --; return get_bitsvec(vec, vec->size); } #endif wtdbg2-2.5/bitvec.h000066400000000000000000000354011353664372200142140ustar00rootroot00000000000000/* * * Copyright (c) 2011, Jue Ruan * * * 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 3 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, see . */ #ifndef __BIT_VEC_RJ_H #define __BIT_VEC_RJ_H #include #include #include #include #include "mem_share.h" static const u1i byte_ones_table[256] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 }; static inline unsigned int _bitvec_roundup_power2(unsigned int v){ if(v == 0) return 0; v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; return v + 1; } typedef struct { u8i *bits; u8i n_bit; u8i n_cap; u8i *sums; u8i sum_size; u8i n_ones; u8i *hash; u8i hash_size; u8i hash_mod; int64_t iter_idx; } BitVec; #if 0 static inline u4i count_ones_bit32(u4i v){ v = v - ((v >> 1) & 0x55555555U); // reuse input as temporary v = (v & 0x33333333U) + ((v >> 2) & 0x33333333U); // temp return (((v + (v >> 4)) & 0xF0F0F0FU) * 0x1010101U) >> 24; // count } #define ONES_STEP_4 0x1111111111111111ULL #define ONES_STEP_8 0x0101010101010101ULL static inline int count_ones_bit64(const u8i x){ register u8i byte_sums = x - ((x & 0xa * ONES_STEP_4) >> 1); byte_sums = (byte_sums & 3 * ONES_STEP_4) + ((byte_sums >> 2) & 3 * ONES_STEP_4); byte_sums = (byte_sums + (byte_sums >> 4)) & 0x0f * ONES_STEP_8; return byte_sums * ONES_STEP_8 >> 56; } #else #define count_ones_bit32(v) __builtin_popcount(v) #define count_ones_bit64(v) __builtin_popcountll(v) #endif #define reverse_u1i(v) (((((u1i)v) * 0x0202020202ULL) & 0x010884422010ULL) % 1023) static inline size_t bitvec_obj_desc_cnt(void *bitv, int idx){ switch(idx){ case 0: return ((BitVec*)bitv)->n_cap / 64 * 8; case 1: return ((BitVec*)bitv)->sums? (((BitVec*)bitv)->sum_size * 2 + 1) * 8 : 0; case 2: return ((BitVec*)bitv)->hash? (((BitVec*)bitv)->hash_size) * 8 : 0; default: return 0; } } static const obj_desc_t bitvec_obj_desc = {"bitvec_obj_desc", sizeof(BitVec), 3, {1, 1, 1}, {offsetof(BitVec, bits), offsetof(BitVec, sums), offsetof(BitVec, hash)}, {(obj_desc_t*)&OBJ_DESC_DATA, (obj_desc_t*)&OBJ_DESC_DATA, (obj_desc_t*)&OBJ_DESC_DATA}, bitvec_obj_desc_cnt, NULL}; static inline BitVec* init_bitvec(u8i n_bit){ BitVec *bitv; if(n_bit == 0) n_bit = 64 * 8; bitv = (BitVec*)malloc(sizeof(BitVec)); bitv->n_bit = 0; bitv->n_cap = (((n_bit + 63) / 64) + 7) / 8 * 64 * 8; bitv->bits = (u8i*)calloc((bitv->n_cap / 64) + 1, 8); bitv->bits[bitv->n_cap / 64] = 0x0000000000000001LLU; //memset(bitv->bits, 0, bitv->n_cap / 8); bitv->sums = NULL; bitv->hash = NULL; bitv->sum_size = 0; bitv->n_ones = 0; bitv->hash_size = 0; bitv->hash_mod = 0; bitv->iter_idx = 0; return bitv; } static inline size_t dump_bitvec(BitVec *bitv, FILE *out){ fwrite(&bitv->n_bit, sizeof(u8i), 1, out); fwrite(&bitv->n_cap, sizeof(u8i), 1, out); fwrite(bitv->bits, sizeof(u8i), bitv->n_cap / 64, out); return sizeof(u8i) * (2 + bitv->n_cap / 64); } static inline BitVec* load_bitvec(FILE *inp){ BitVec *bitv; size_t n; bitv = (BitVec*)malloc(sizeof(BitVec)); if((n = fread(&bitv->n_bit, sizeof(u8i), 1, inp)) != 1){ free(bitv); return NULL; } if((n = fread(&bitv->n_cap, sizeof(u8i), 1, inp)) != 1){ free(bitv); return NULL; } bitv->bits = (u8i*)malloc(bitv->n_cap / 8); if(bitv->bits == NULL){ fprintf(stderr, " Out of memeory in load_bitvec\n "); fflush(stderr); exit(1); } if((n = fread(bitv->bits, sizeof(u8i), bitv->n_cap / 64, inp)) != bitv->n_cap / 64){ free(bitv); free(bitv->bits); return NULL; } bitv->sums = NULL; bitv->hash = NULL; bitv->hash_size = 0; return bitv; } #if 0 static inline BitVec* mem_load_bitvec(void *mem, FILE *inp){ BitVec *bitv; size_t off, n; bitv = mem; off = ((sizeof(BitVec) + 7) / 8) * 8; if((n = fread(&bitv->n_bit, sizeof(u8i), 1, inp)) != 1) return NULL; if((n = fread(&bitv->n_cap, sizeof(u8i), 1, inp)) != 1) return NULL; bitv->sums = NULL; bitv->hash = NULL; bitv->hash_size = 0; bitv->bits = mem + off; off += (bitv->n_cap / 64) * 8; if((n = fread(bitv->bits, sizeof(u8i), bitv->n_cap / 64, inp)) != bitv->n_cap / 64) return NULL; return bitv; } #endif static inline void clear_bitvec(BitVec *bitv){ bitv->n_bit = 0; } static inline void zeros_bitvec(BitVec *bitv){ memset(bitv->bits, 0, bitv->n_cap / 8); } // exclusive end static inline void reg_zeros_bitvec(BitVec *bitv, u8i beg, u8i end){ u8i b, e; if(beg >= end) return; b = beg >> 6; e = end >> 6; if(b == e){ bitv->bits[b] &= (MAX_U8 << (beg & 0x3FU)) ^ (MAX_U8 >> (64 - (end & 0x3FU))); } else { bitv->bits[b] &= ~(MAX_U8 << (beg & 0x3FU)); while(++b < e){ bitv->bits[b] = 0; } bitv->bits[b] &= MAX_U8 << (end & 0x3FU); } } static inline void ones_bitvec(BitVec *bitv){ memset(bitv->bits, 0xFFU, bitv->n_cap / 8); } // exclusive end static inline void reg_ones_bitvec(BitVec *bitv, u8i beg, u8i end){ u8i b, e; if(beg >= end) return; b = beg >> 6; e = end >> 6; if(b == e){ bitv->bits[b] |= (MAX_U8 << (beg & 0x3FU)) & (MAX_U8 >> (64 - (end & 0x3FU))); } else { bitv->bits[b] |= MAX_U8 << (beg & 0x3FU); while(++b < e){ bitv->bits[b] = MAX_U8; } bitv->bits[b] |= ~(MAX_U8 << (end & 0x3FU)); } } static inline void flip_bitvec(BitVec *bitv, u8i idx){ bitv->bits[idx>>6] ^= 1LLU << (idx&0x3FU); } static inline void one_bitvec(BitVec *bitv, u8i idx){ bitv->bits[idx>>6] |= 1LLU << (idx&0x3FU); } static inline void zero_bitvec(BitVec *bitv, u8i idx){ bitv->bits[idx>>6] &= ~(1LLU << (idx&0x3FU)); } static inline void set_bitvec(BitVec *bitv, u8i idx, int v){ if(v){ one_bitvec(bitv, idx); } else { zero_bitvec(bitv, idx); } } static inline u8i get_bitvec(BitVec *bitv, u8i idx){ return (bitv->bits[idx>>6] >> (idx&0x3FU)) & 0x01LLU; } static inline u8i get64_bitvec(BitVec *bitv, u8i off){ u8i m, n; m = off >> 6; n = off & 0x3F; if(n){ return (bitv->bits[m] >> (64 - n)) | (bitv->bits[m + 1] << n); } else { return bitv->bits[m]; } } static inline void set64_bitvec(BitVec *bitv, u8i off, u8i val){ u8i m, n; m = off >> 6; n = off & 0x3F; if(n){ bitv->bits[m] = ((bitv->bits[m] << (64 - n)) >> (64 - n)) | (val << (64 - n)); m ++; bitv->bits[m] = ((bitv->bits[m] >> n) << n) | (val >> (64 - n)); } else { bitv->bits[m] = val; } } static inline void encap_bitvec(BitVec *bitv, u8i num){ u8i cap; if(bitv->n_bit + num < bitv->n_cap) return; cap = bitv->n_cap; while(bitv->n_bit + num >= bitv->n_cap){ if(bitv->n_cap < 1024 * 1024 * 8){ bitv->n_cap <<= 1; } else bitv->n_cap += 1024 * 1024 * 8; } bitv->bits = (u8i*)realloc(bitv->bits, bitv->n_cap / 8 + 8); memset(((void*)bitv->bits) + cap / 8, 0, (bitv->n_cap - cap) / 8 + 8); bitv->bits[cap / 64] = 0x0000000000000001LLU; } static inline void recap_bitvec(BitVec *bitv, u8i new_cap){ if(new_cap & 0x3FU) new_cap = (new_cap & 0xFFFFFFFFFFFFFFC0LLU) + 0x40U; if(bitv->n_cap == new_cap) return; bitv->bits = (u8i*)realloc(bitv->bits, new_cap / 8 + 8); if(new_cap > bitv->n_cap){ memset(((void*)bitv->bits) + bitv->n_cap / 8, 0, (new_cap - bitv->n_cap) / 8 + 8); } bitv->bits[new_cap / 64] = 0x0000000000000001LLU; bitv->n_cap = new_cap; } static inline void one2bitvec(BitVec *bitv){ encap_bitvec(bitv, 1); one_bitvec(bitv, bitv->n_bit); bitv->n_bit ++; } static inline void zero2bitvec(BitVec *bitv){ encap_bitvec(bitv, 1); zero_bitvec(bitv, bitv->n_bit); bitv->n_bit ++; } static inline u8i get_2bitvec(BitVec *bitv, u8i idx){ return (bitv->bits[idx>>5] >> ((idx&0x1FU) << 1)) & 0x03LLU; } static inline void set_2bitvec(BitVec *bitv, u8i idx, u8i v){ bitv->bits[idx>>5] = (bitv->bits[idx>>5] & (~(0x03LLU << ((idx&0x1FU) << 1)))) | ((v&0x03LLU) << ((idx&0x1FU) << 1)); } static inline void push_2bitvec(BitVec *bitv, u8i v){ encap_bitvec(bitv, 2); set_2bitvec(bitv, bitv->n_bit >> 1, v); bitv->n_bit = ((bitv->n_bit >> 1) + 1) << 1; } static inline void end_bitvec(BitVec *bitv){ encap_bitvec(bitv, 1); one_bitvec(bitv, bitv->n_bit); } static inline u8i next_one_bitvec(BitVec *bitv, u8i idx){ register u8i p, v; register u4i s; p = idx >> 6; s = idx & 0x3F; while(!(bitv->bits[p] >> s)){ p ++; s = 0; } v = bitv->bits[p] >> s; s += __builtin_ctzll(v); return (p << 6) + s; } static inline u8i reg_count_bitvec(BitVec *bitv, u8i beg, u8i end){ u8i cnt, b, e, t; if(beg >= end) return 0; b = beg >> 6; e = end >> 6; if(b == e){ t = (bitv->bits[b] & (MAX_U8 >> (64 - (end & 0x3F)))) >> (beg & 0x3F); cnt = count_ones_bit64(t); } else { cnt = count_ones_bit64(bitv->bits[b] >> (beg & 0x3F)); while(++b < e){ cnt += count_ones_bit64(bitv->bits[b]); } if(end & 0x3F){ cnt += count_ones_bit64(bitv->bits[b] & (MAX_U8 >> (64 - (end & 0x3F)))); } } return cnt; } static const int Mod37BitPosition[] = // map a bit value mod 37 to its position { 32, 0, 1, 26, 2, 23, 27, 0, 3, 16, 24, 30, 28, 11, 0, 13, 4, 7, 17, 0, 25, 22, 31, 15, 29, 10, 12, 6, 0, 21, 14, 9, 5, 20, 8, 19, 18 }; static inline u8i next_one_bitvec2(BitVec *bitv, u8i idx){ register u8i p; register u4i s, v; p = idx >> 6; s = idx & 0x3F; while(!(bitv->bits[p] >> s)){ p ++; s = 0; } if(!((bitv->bits[p] >> s) & 0xFFFFFFFFU)) s += 32; v = bitv->bits[p] >> s; s += Mod37BitPosition[(-v & v) % 37]; return (p << 6) + s; } static inline u8i next_one_bitvec3(BitVec *bitv, u8i idx){ register u8i p; register u4i s; p = idx >> 6; s = idx & 0x3F; while(!(bitv->bits[p] >> s)){ p ++; s = 0; } while(!((bitv->bits[p] >> s) & 0xFFU)) s += 8; while(!((bitv->bits[p] >> s) & 0x01U)) s ++; return (p << 6) + s; } //n_cap MUST be times of 64 * 8 static inline void index_bitvec_core(BitVec *bitv, size_t n_cap){ u8i i, k, s, t, m; m = ((n_cap + 63) / 64 + 7) / 8; if(bitv->sums) free(bitv->sums); bitv->sums = (u8i*)calloc((m * 2 + 1), 8); t = 0; for(i=0;i>6) >> 3) << 1; bitv->sums[k] = t; s = 0; s += count_ones_bit64(bitv->bits[(i>>6)+0]); bitv->sums[k+1] |= s << 0; s += count_ones_bit64(bitv->bits[(i>>6)+1]); bitv->sums[k+1] |= s << 9; s += count_ones_bit64(bitv->bits[(i>>6)+2]); bitv->sums[k+1] |= s << 18; s += count_ones_bit64(bitv->bits[(i>>6)+3]); bitv->sums[k+1] |= s << 27; s += count_ones_bit64(bitv->bits[(i>>6)+4]); bitv->sums[k+1] |= s << 36; s += count_ones_bit64(bitv->bits[(i>>6)+5]); bitv->sums[k+1] |= s << 45; s += count_ones_bit64(bitv->bits[(i>>6)+6]); bitv->sums[k+1] |= s << 54; s += count_ones_bit64(bitv->bits[(i>>6)+7]); t += s; } bitv->sums[((i>>6) >> 3) << 1] = t; bitv->n_ones = t; bitv->sum_size = m; bitv->hash_size = (n_cap / 64 / 8) / 2; if(bitv->hash_size == 0) bitv->hash_size = 1; bitv->hash_mod = (t + bitv->hash_size) / bitv->hash_size; if(bitv->hash_mod == 0) bitv->hash_mod = 1; if(bitv->hash) free(bitv->hash); bitv->hash = (u8i*)malloc(sizeof(u8i) * bitv->hash_size); s = 0; t = 0; for(i=0;i<=m;i++){ k = bitv->sums[i*2] / bitv->hash_mod; if(s < k){ while(s < k){ bitv->hash[s] = t; s ++; } t = i? i - 1 : 0; } } bitv->hash[bitv->sums[m*2] / bitv->hash_mod] = t; } static inline void index_bitvec(BitVec *bitv){ index_bitvec_core(bitv, bitv->n_cap); } static inline u8i rank_bitvec(BitVec *bitv, u8i idx){ u8i p, s, sum; p = (idx>>6)>>3; s = (idx >> 6) & 0x07U; sum = bitv->sums[p<<1]; if(s) sum += (bitv->sums[(p<<1)+1] >> (9 * (s - 1))) & 0x1FFU; if(idx & 0x3FU) sum += count_ones_bit64(bitv->bits[idx>>6]<<(64-(idx&0x3FU))); return sum; } static inline u1i select_8bytes(u8i word, u1i n_one){ u1i idx, n, m; n = count_ones_bit32((u4i)word); if(n >= n_one){ n = 0; idx = 0; word = word & 0xFFFFFFFFU; } else { idx = 32; word = word >> 32; } while(1){ m = byte_ones_table[(u1i)word]; if(n + m >= n_one) break; n += m; idx += 8; word >>= 8; } m = byte_ones_table[(u1i)(word & 0xF)]; if(n + m < n_one){ idx += 4; word >>= 4; n += m; } while(word){ idx ++; if(word & 0x01){ n ++; if(n == n_one) break; } word >>= 1; } return idx; } /* * To select the 1'st one, use select_bitvec(bitv, 1) - 1 * */ static inline u8i select_bitvec(BitVec *bitv, u8i idx){ u8i i, p, s, sum, t; p = bitv->hash[idx / bitv->hash_mod]; while(p + 1 < bitv->sum_size && bitv->sums[(p + 1) << 1] < idx) p ++; sum = bitv->sums[p << 1]; i = 0; t = sum; while(i < 7){ s = (bitv->sums[(p << 1) + 1] >> (9 * i)) & 0x1FFU; if(sum + s >= idx) break; t = sum + s; i ++; } p = p * 8 + i; s = idx - t; return p * 64 + select_8bytes(bitv->bits[p], s); } static inline void begin_iter_bitvec(BitVec *bitv){ bitv->iter_idx = -1; } static inline u8i iter_bitvec(BitVec *bitv){ if((u8i)(bitv->iter_idx + 1) > bitv->n_cap) return 0xFFFFFFFFFFFFFFFFLLU; bitv->iter_idx = next_one_bitvec(bitv, bitv->iter_idx + 1); return (u8i)bitv->iter_idx; } static inline void free_bitvec(BitVec *bitv){ free(bitv->bits); if(bitv->sums) free(bitv->sums); if(bitv->hash) free(bitv->hash); free(bitv); } #if 0 static inline size_t mem_size_bitvec(BitVec *bitv){ size_t m; m = (sizeof(BitVec) + 7) / 8 * 8 + ((bitv->n_cap / 64) * 8); if(bitv->sums){ m += (bitv->sum_size * 2 + 1) * 8; } if(bitv->hash){ m += bitv->hash_size * 8; } return m; } static inline size_t mem_dump_bitvec(BitVec *bitv, void *mem){ BitVec *clone; size_t off; clone = mem; memcpy(clone, bitv, sizeof(BitVec)); off = ((sizeof(BitVec) + 7) / 8) * 8; clone->bits = mem + off; memcpy(clone->bits, bitv->bits, (bitv->n_cap / 64) * 8); off += (bitv->n_cap / 64) * 8; if(bitv->sums){ clone->sums = mem + off; memcpy(clone->sums, bitv->sums, (bitv->sum_size * 2 + 1) * 8); off += (bitv->sum_size * 2 + 1) * 8; } if(bitv->hash){ clone->hash = mem + off; memcpy(clone->hash, bitv->hash, bitv->hash_size * 8); off += bitv->hash_size * 8; } return off; } #endif #endif wtdbg2-2.5/chararray.h000066400000000000000000000203761353664372200147210ustar00rootroot00000000000000/* * * Copyright (c) 2011, Jue Ruan * * * 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 3 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, see . */ #ifndef __STRING_RJ_H #define __STRING_RJ_H #include #include #include #include #include "list.h" #include "mem_share.h" /** * String */ #ifdef HUGE_STRING typedef long int string_size_t; #else typedef int string_size_t; #endif typedef struct { union { char *string; char *buffer; }; string_size_t size; string_size_t capacity; } String; typedef struct { char *string; string_size_t size; } VString; define_list(VStrv, VString); static inline String* init_string(string_size_t cap){ String *str; str = (String*)malloc(sizeof(String)); str->size = 0; str->capacity = (cap&0x1)? cap + 1 : cap + 2; str->string = (char*)malloc(sizeof(char) * (str->capacity)); str->string[0] = 0; return str; } static inline size_t string_obj_desc_cnt(void *obj, int idx){ return ((String*)obj)->size + 1; idx = idx; } static const obj_desc_t string_obj_desc = {"string_obj_desc", sizeof(String), 1, {1}, {offsetof(String, string)}, {(obj_desc_t*)&OBJ_DESC_DATA}, string_obj_desc_cnt, NULL}; static inline unsigned int _string_size_roundup_power2(unsigned int v){ v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; return v + 1; } static inline void encap_string(String *str, string_size_t inc){ if(inc + str->size + 1 > str->capacity){ if(inc + str->size + 1 < 0xFFFFFFF){ str->capacity = _string_size_roundup_power2(inc + str->size + 1); } else { str->capacity += (((inc + str->size + 1) - str->capacity + 0xFFFFFFF - 1) / 0xFFFFFFF) * 0xFFFFFFF; } str->string = (char*)realloc(str->string, str->capacity); } } static inline void recap_string(String *str, string_size_t cap){ if(cap <= str->size) return; str->string = (char*)realloc(str->string, cap); str->capacity = cap; } static inline void uc_string(String *str){ string_size_t i; for(i=0;isize;i++){ if(str->string[i] >= 'a' && str->string[i] <= 'z') str->string[i] = str->string[i] + 'A' - 'a'; } } static inline void lc_string(String *str){ string_size_t i; for(i=0;isize;i++){ if(str->string[i] >= 'A' && str->string[i] <= 'Z') str->string[i] = str->string[i] + 'a' - 'A'; } } static inline char* substr(char *string, string_size_t len, char *dst){ char *str; if(len < 0) len = strlen(string); if(dst != NULL) str = dst; else str = (char*)malloc(sizeof(char) * (len + 1)); strncpy(str, string, len); str[len] = '\0'; return str; } static inline char* catstr(string_size_t n_str, ...){ char *str, *s; string_size_t i, len, inc; va_list params; len = 0; str = NULL; va_start(params, n_str); for(i=0;isize && str->string[str->size - 1] == '\n'){ str->size --; str->string[str->size] = 0; } } static inline void chomp_vstring(VString *str){ if(str->size && str->string[str->size - 1] == '\n'){ str->size --; } } static inline void trim_string(String *str){ string_size_t i, j; i = str->size - 1; while(i >= 0 && (str->string[i] == '\n' || str->string[i] == '\t' || str->string[i] == ' ')) i--; str->size = i + 1; i = 0; while(i < str->size && (str->string[i] == '\n' || str->string[i] == '\t' || str->string[i] == ' ')) i++; if(i){ for(j=i;jsize;j++){ str->string[j-i] = str->string[j]; } str->size -= i; } str->string[str->size] = 0; } static inline void trim_vstring(VString *str){ string_size_t i; i = str->size - 1; while(i >= 0 && (str->string[i] == '\n' || str->string[i] == '\t' || str->string[i] == ' ')) i--; str->size = i + 1; i = 0; while(i < str->size && (str->string[i] == '\n' || str->string[i] == '\t' || str->string[i] == ' ')) i++; str->string += i; } static inline void append_string(String *str, char *src, string_size_t offlen){ encap_string(str, offlen); memcpy(str->string + str->size, src, offlen); str->size += offlen; str->string[str->size] = 0; } static inline void append_char_string(String *str, char c, string_size_t num){ encap_string(str, num); while(num-- > 0){ str->string[str->size ++] = c; } str->string[str->size] = 0; } static inline String* as_string(char *chs, string_size_t len){ String *str; str = init_string(len); memcpy(str->string, chs, len); str->size = len; str->string[len] = 0; return str; } static inline VString* as_vstring(char *chs){ string_size_t len; VString *str; len = strlen(chs); str = malloc(sizeof(VString)); str->string = chs; str->size = len; return str; } static inline void add_char_string(String *str, char ch){ encap_string(str, 1); str->string[str->size++] = ch; str->string[str->size] = 0; } #define push_string(str, ch) add_char_string(str, ch) static inline void add_int_string(String *str, long long val){ string_size_t n; long long v; encap_string(str, 30); if(val == 0){ str->string[str->size++] = '0'; } else { if(val < 0){ val = - val; str->string[str->size++] = '-'; } v = val; for(n=0;v;n++) v /= 10; str->size += n; v = val; while(v){ str->string[--str->size] = '0' + (v % 10); v /= 10; } str->size += n; } str->string[str->size] = 0; } static inline void clear_string(String *str){ str->size = 0; str->string[0] = 0; } static inline string_size_t split_string(String *str, char separator, VStrv *vstrs){ VString *vstr; string_size_t n_tab, i, s; for(i=s=n_tab=0;isize;i++){ if(str->string[i] == separator){ if(i > s){ str->string[i] = '\0'; vstr = next_ref_VStrv(vstrs); vstr->string = str->string + s; n_tab ++; vstr->size = i - s; } s = i + 1; } } if(i > s){ str->string[i] = '\0'; vstr = next_ref_VStrv(vstrs); vstr->string = str->string + s; n_tab ++; vstr->size = i - s; } return n_tab; } static inline string_size_t split_vstring(VString *str, char separator, VStrv *vstrs, string_size_t cut){ VString *vstr; string_size_t n_tab, i, s; for(i=s=n_tab=0;isize;i++){ if(str->string[i] == separator){ if(i > s){ if(cut) str->string[i] = '\0'; vstr = next_ref_VStrv(vstrs); vstr->string = str->string + s; n_tab ++; vstr->size = i - s; } s = i + 1; } } if(i > s){ if(cut) str->string[i] = '\0'; vstr = next_ref_VStrv(vstrs); vstr->string = str->string + s; n_tab ++; vstr->size = i - s; } return n_tab; } static inline void reverse_string(String *str){ string_size_t i, j; char c; i = 0; j = str->size - 1; while(i < j){ swap_tmp(str->string[i], str->string[j], c); i ++; j --; } } static inline void reverse_str(char *str, string_size_t len){ string_size_t i, j; char c; i = 0; j = len - 1; while(i < j){ swap_tmp(str[i], str[j], c); i ++; j --; } } static inline void tidy_string(String *src, String *dst, char ch){ string_size_t i; encap_string(dst, src->size); for(i=0;isize;i++){ if(src->string[i] != ch){ dst->string[dst->size ++] = src->string[i]; } } dst->string[dst->size] = 0; } static inline string_size_t occ_str(char *str, string_size_t len, char c){ string_size_t i, ret; for(i=ret=0;i= str->size || size < 0) return; str->size = size; str->string[size] = 0; } static inline String* clone_string(String *str){ String *clone; clone = init_string(str->size); append_string(clone, str->string, str->size); return clone; } static inline void free_string(String *str){ free(str->string); free(str); } static inline void free_vstring(VString *str){ free(str); } #endif wtdbg2-2.5/dagcns.h000066400000000000000000000615171353664372200142060ustar00rootroot00000000000000/* * * Copyright (c) 2011, Jue Ruan * * * 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 3 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, see . */ #include "dna.h" #include "chararray.h" #include "list.h" #include "queue.h" #include "hashset.h" #include "general_graph.h" #include #include #ifndef PACBIO_PROBS_DAGCNS_RJ_H #define PACBIO_PROBS_DAGCNS_RJ_H #define DAGCNS_MAX_LEN 0x3FFF // 16k static int dagcns_debug = 0; typedef struct { int x, y; u4i dnidx; f8i probs[2]; } bdp_node_t; define_list(bdpnodev, bdp_node_t); typedef struct { f8i prob; u1i cigar, base; } bdp_edge_t; define_list(bdpedgev, bdp_edge_t); define_simple_geg_callback(bdp, bdpnodev, bdp_node_t, bdpedgev, bdp_edge_t); typedef struct { u4i gnidx, dnidx; } bdp_link_t; define_list(bdplinkv, bdp_link_t); typedef struct { uint32_t nodes[2]; uint32_t links[2]; uint32_t cov:28, visit:1, closed:1, cns:1, alt:1; double score; } dagedge_t; define_list(dagedgev, dagedge_t); #define NODE_MAX_FW_EDGE 0xFFFFFFFFU typedef struct dagnode_t { uint32_t pos:28, base:2, cns:1, visit:1; uint32_t fw_edge; uint32_t edges[2]; f8i aux; } dagnode_t; define_list(dagnodev, dagnode_t); typedef struct { uint32_t pos; uint32_t bases[4]; } dagsnp_t; define_list(dagsnpv, dagsnp_t); typedef struct { u8list *cns; u32list *deps; dagnodev *nodes; dagedgev *edges; u32list *trash; String *alns[2]; int W, M, X, I, D, E; f4i pM, pX, pI, pD; // log(prob_M) double ref_penalty, alt_penalty; // 0.5 and 0.2 double cns_score; uint32_t cns_head, backbone_size; } DAGCNS; static inline DAGCNS* init_dagcns(int W, int M, int X, int I, int D, int E, f4i pM, f4i pX, f4i pI, f4i pD){ DAGCNS *g; g = malloc(sizeof(DAGCNS)); g->cns = init_u8list(1024); g->deps = init_u32list(1024); g->nodes = init_dagnodev(1024); g->edges = init_dagedgev(1024); g->trash = init_u32list(1024); g->alns[0] = init_string(1024); g->alns[1] = init_string(1024); g->cns_score = 0; g->cns_head = 0xFFFFFFFFU; g->backbone_size = 0; g->W = W; g->M = M; g->X = X; g->I = I; g->D = D; g->E = E; g->pM = pM; g->pX = pX; g->pI = pI; g->pD = pD; g->ref_penalty = 0.5; g->alt_penalty = 0.2; return g; } static inline void free_dagcns(DAGCNS *g){ free_dagnodev(g->nodes); free_dagedgev(g->edges); free_u32list(g->trash); free_u8list(g->cns); free_u32list(g->deps); free_string(g->alns[0]); free_string(g->alns[1]); free(g); } static inline void reset_dagcns(DAGCNS *g){ clear_dagnodev(g->nodes); clear_dagedgev(g->edges); clear_u32list(g->trash); clear_u8list(g->cns); clear_u32list(g->deps); g->cns_score = 0; g->cns_head = 0xFFFFFFFFU; g->backbone_size = 0; } static uint32_t prepare_node_dagcns(DAGCNS *g, uint32_t pos, uint8_t base){ dagnode_t *n; n = next_ref_dagnodev(g->nodes); n->pos = pos; n->base = base; n->cns = 0; n->aux = 0; n->visit = 0; n->edges[0] = 0xFFFFFFFFU; n->edges[1] = 0xFFFFFFFFU; n->fw_edge = NODE_MAX_FW_EDGE; return g->nodes->size - 1; } static inline dagedge_t* find_edge_by_node_dagcns(DAGCNS *g, uint32_t nid1, uint32_t nid2, int dir){ dagnode_t *n; dagedge_t *e; n = ref_dagnodev(g->nodes, nid1); if(n->edges[dir] != 0xFFFFFFFFU){ e = ref_dagedgev(g->edges, n->edges[dir]); while(1){ if(e->nodes[dir] == nid2) return e; if(e->links[dir] == 0xFFFFFFFFU) break; e = ref_dagedgev(g->edges, e->links[dir]); } } return NULL; } static inline dagedge_t* add_edge_dagcns(DAGCNS *g, uint32_t nid1, uint32_t nid2, int dir){ dagnode_t *n; dagedge_t *e; uint32_t eid; n = ref_dagnodev(g->nodes, nid1); if(pop_u32list(g->trash, &eid)){ e = ref_dagedgev(g->edges, eid); } else { eid = g->edges->size; e = next_ref_dagedgev(g->edges); } e->nodes[!dir] = nid1; e->nodes[dir] = nid2; e->cov = 1; e->score = 0; e->visit = 0; e->closed = 0; e->cns = 0; e->alt = 0; e->links[dir] = n->edges[dir]; n->edges[dir] = eid; n = ref_dagnodev(g->nodes, nid2); e->links[!dir] = n->edges[!dir]; n->edges[!dir] = eid; return e; } static inline dagedge_t* prepare_edge_dagcns(DAGCNS *g, uint32_t nid1, uint32_t nid2, int dir){ dagedge_t *e; e = find_edge_by_node_dagcns(g, nid1, nid2, dir); if(e){ e->cov ++; return e; } return add_edge_dagcns(g, nid1, nid2, dir); } static inline void gen_pregraph_dagcns(DAGCNS *g){ dagedge_t *e; uint32_t i; clear_dagnodev(g->nodes); clear_dagedgev(g->edges); clear_u32list(g->trash); clear_u32list(g->deps); g->backbone_size = g->cns->size; for(i=0;icns->size;i++){ push_u32list(g->deps, 0); prepare_node_dagcns(g, i, g->cns->buffer[i]); if(i){ // make sure the graph is conntective even the alignment is partial e = add_edge_dagcns(g, i - 1, i, 0); e->cov = 0; } } } static inline int remove_edge_dagcns(DAGCNS *g, uint32_t eid){ dagnode_t *n; dagedge_t *e; uint32_t i, lst; for(i=0;i<2;i++){ e = ref_dagedgev(g->edges, eid); lst = e->links[i]; n = ref_dagnodev(g->nodes, e->nodes[!i]); if(n->edges[i] == eid){ n->edges[i] = lst; } else if(n->edges[i] == 0xFFFFFFFFU){ //fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); abort(); return 0; } else { e = ref_dagedgev(g->edges, n->edges[i]); while(1){ if(e->links[i] == eid){ e->links[i] = lst; break; } else if(e->links[i] == 0xFFFFFFFFU){ //fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); abort(); return 0; } else { e = ref_dagedgev(g->edges, e->links[i]); } } } } push_u32list(g->trash, eid); return 1; } #define MIN_SCORE -0x0FFFFFFF static inline f8i log_sum(f8i a, f8i b){ f8i c; c = num_max(a, b); if(c - a >= 10 || c - b >= 10) return c; return logl(expl(a - c) + expl(b - c)) + c; } typedef struct { int x, y, d; } bdp_beg_t; define_list(bdpbegv, bdp_beg_t); static inline void fprint_dot_bdpgraph(GEGraph *g, bdpnodev *bnodes, bdpedgev *bedges, char *prefix, char *suffix){ static const char *colors[2][2] = {{"blue", "green"}, {"red", "gray"}}; FILE *out; ge_node_t *n; bdp_node_t *bn; ge_edge_t *e; bdp_edge_t *be; u8i i; out = open_file_for_write(prefix, suffix, 1); fprintf(out, "digraph {\nnode [shape=record]\nrankdir=LR\n"); for(i=0;inodes->size;i++){ n = ref_genodev(g->nodes, i); if(n->closed) continue; bn = ref_bdpnodev(bnodes, offset_genodev(g->nodes, n)); fprintf(out, " N%llu [label=\"{N%llu|%d|%d}|{%.4Lf|%.4Lf}\"]\n", i, i, bn->x, bn->y, bn->probs[0], bn->probs[1]); } for(i=1;iedges->size;i++){ e = ref_geedgev(g->edges, i); if(e->closed) continue; be = ref_bdpedgev(bedges, offset_geedgev(g->edges, e)); fprintf(out, " N%llu -> N%llu [label=\"%c%c:%d:%c:%.4Lf\" color=%s]\n", (u8i)e->node1, (u8i)e->node2, "+-"[e->dir1], "+-"[e->dir2], e->cov, "MIDX"[be->cigar], be->prob, colors[e->dir1][e->dir2]); fprintf(out, " N%llu -> N%llu [label=\"%c%c:%d:%c:%.4Lf\" color=%s]\n", (u8i)e->node2, (u8i)e->node1, "-+"[e->dir2], "-+"[e->dir1], e->cov, "MIDX"[be->cigar], be->prob, colors[!e->dir2][!e->dir1]); } fprintf(out, "}\n"); fclose(out); } static inline u4i dp_matrix2alignment_graph(DAGCNS *dag, u1i *query, u1i *z, int x, int y, GEGraph *g, bdpnodev *bnodes, bdpedgev *bedges){ ge_node_t *gn, *gn2; ge_edge_ref_t *gf; ge_edge_t *ge; bdp_node_t *bn, *bn2; bdp_edge_t *be; bdp_beg_t BEG; UUhash *bnhash; UUhash_t *u; bdpbegv *stack; f8i cigar_probs[4], curator; u8v *idxs; u1i *target; u4i i, k, nidx, nlst, nbegs[2], visit, ret; int d, f, n_col, ops[2], base, exists; cigar_probs[0] = dag->pM; cigar_probs[1] = dag->pI; cigar_probs[2] = dag->pD; cigar_probs[3] = dag->pX; n_col = dag->cns->size; target = dag->cns->buffer; bdp_set_callbacks_gegraph(g, bnodes, bedges); reset_gegraph(g); stack = init_bdpbegv(4); push_bdpbegv(stack, (bdp_beg_t){x, y, 0}); idxs = init_u8v(4); nbegs[0] = nbegs[1] = 0; bnhash = init_UUhash(1023); ret = 0; while(stack->size){ BEG = stack->buffer[--stack->size]; u = prepare_UUhash(bnhash, (((b8i)BEG.x) << 32) | BEG.y, &exists); if(exists){ nidx = u->val; } else { gn = add_node_gegraph(g); nidx = offset_genodev(g->nodes, gn); u->key = (((b8i)BEG.x) << 32) | BEG.y; u->val = nidx; bn = ref_bdpnodev(bnodes, nidx); bn->x = BEG.x; bn->y = BEG.y; bn->dnidx = MAX_VALUE_U4; } nlst = nidx; x = BEG.x; y = BEG.y; d = BEG.d; f = 0; clear_u8v(idxs); while(x >= 0 && y >= 0){ d = (z[x * n_col + y] >> (d << 1)) & 0x03; if(d == 0){ if(query[x] == target[y]){ if(z[x * n_col + y] & (1 << 6)){ f = 1; break; } else if(BEG.d == 0){ z[x * n_col + y] |= 1 << 6; push_bdpbegv(stack, (bdp_beg_t){x, y, 1}); push_bdpbegv(stack, (bdp_beg_t){x, y, 2}); } ops[0] = 0; ops[1] = 3; } else { ops[0] = 1; ops[1] = 2; } //x --; y --; } else if(d == 1){ ops[0] = 1; ops[1] = 3; //x --; } else { ops[0] = 2; ops[1] = 3; //y --; } for(i=0;i<2;i++){ if(ops[i] == 3) break; base = query[x]; if(ops[i] == 0){ x --; y --; } else if(ops[i] == 1){ x --; } else { y --; } u = prepare_UUhash(bnhash, (((b8i)x) << 32) | y, &exists); if(exists){ nidx = u->val; } else { gn = add_node_gegraph(g); nidx = offset_genodev(g->nodes, gn); u->key = (((b8i)x) << 32) | y; u->val = nidx; bn = ref_bdpnodev(bnodes, nidx); bn->x = x; bn->y = y; bn->dnidx = MAX_VALUE_U4; } ge = prepare_edge_gegraph(g, nlst, 1, nidx, 1, &exists); if(exists){ ge->cov ++; } else { ge->cov = 1; be = ref_bdpedgev(bedges, offset_geedgev(g->edges, ge)); be->cigar = ops[i]; be->base = base; } nlst = nidx; if(BEG.d) push_u8v(idxs, offset_geedgev(g->edges, ge)); } } if(BEG.d){ if(f == 0){ // not a bubble for(i=0;isize;i++){ ge = ref_geedgev(g->edges, idxs->buffer[i]); ge->cov --; if(ge->cov == 0) cut_edge_gegraph(g, ge); } } else ret ++; } else { ret ++; nbegs[0] = g->nodes->size > 1? g->nodes->size - 2 : 0; nbegs[1] = 0; } } free_bdpbegv(stack); free_UUhash(bnhash); u4i cnt = 0; for(i=0;inodes->size;i++){ gn = ref_genodev(g->nodes, i); if(gn->edges[0].cnt || gn->edges[1].cnt){ cnt++; continue; } gn->closed = 1; } // calculate probabilities (forward + backward) if(nbegs[0] == nbegs[1]){ free_u8v(idxs); return ret; } for(k=0;k<2;k++){ bn = ref_bdpnodev(bnodes, nbegs[k]); bn->probs[k] = 0; clear_u8v(idxs); push_u8v(idxs, nbegs[k]); visit = k + 1; while(idxs->size){ gn = ref_genodev(g->nodes, idxs->buffer[idxs->size - 1]); bn = ref_bdpnodev(bnodes, idxs->buffer[idxs->size - 1]); idxs->size --; geg_beg_iter_edges(g, gn, k, gf, ge); if(ge->closed) continue; be = ref_bdpedgev(bedges, offset_geedgev(g->edges, ge)); gn2 = ref_genodev(g->nodes, gf->flg? ge->node1 : ge->node2); bn2 = ref_bdpnodev(bnodes, gf->flg? ge->node1 : ge->node2); if(gn2->bt_visit == visit){ bn2->probs[k] = log_sum(bn2->probs[k], bn->probs[k] + cigar_probs[be->cigar]); // p1 + p2 } else { gn2->bt_visit = visit; gn2->unvisit = gn2->edges[!k].cnt; bn2->probs[k] = bn->probs[k] + cigar_probs[be->cigar]; // p1 * p2 } if(gn2->unvisit) gn2->unvisit --; if(gn2->unvisit == 0){ push_u8v(idxs, offset_genodev(g->nodes, gn2)); } geg_end_iter_edges(); } } free_u8v(idxs); // calculate edge prob curator = -FLT_MAX; for(i=1;iedges->size;i++){ ge = ref_geedgev(g->edges, i); if(ge->closed) continue; be = ref_bdpedgev(bedges, i); be->prob = cigar_probs[be->cigar] + ref_bdpnodev(bnodes, ge->node1)->probs[ge->dir1] + ref_bdpnodev(bnodes, ge->node2)->probs[!ge->dir2]; if(be->prob > curator) curator = be->prob; } for(i=1;iedges->size;i++){ ge = ref_geedgev(g->edges, i); if(ge->closed) continue; be = ref_bdpedgev(bedges, i); be->prob = expl(be->prob - curator); } //fprint_dot_bdpgraph(g, bnodes, bedges, "geg.dot", NULL); return nbegs[0]; } static inline u4i branched_dynamic_programming_alignment(DAGCNS *g, u1i *query, int ql, GEGraph *geg, bdpnodev *bnodes, bdpedgev *bedges, u1v *mem_buffer){ u4i nbeg; int *rh, *re; u1i *z, *zi, d, *target; int tl, n_col; int i, j, jc, jb, je, h1, h, m, e, f, t; int mi, mj, max; int W, M, X, I, D, E; tl = g->cns->size; target = g->cns->buffer; if(ql <= 0 || tl <= 0){ return 0; } n_col = tl; encap_u1v(mem_buffer, kswx_roundup8x((tl + 2) * sizeof(int)) + kswx_roundup8x((tl + 2) * sizeof(int)) + kswx_roundup8x(((long long)ql) * n_col)); rh = (int*)(mem_buffer->buffer + mem_buffer->size); re = (int*)(mem_buffer->buffer + mem_buffer->size + kswx_roundup8x((tl + 2) * sizeof(int))); z = (mem_buffer->buffer + mem_buffer->size + kswx_roundup8x((tl + 2) * sizeof(int)) + kswx_roundup8x((tl + 2) * sizeof(int))); W = g->W; M = g->M; X = g->X; I = g->I; D = g->D; E = g->E; // banded DP, global alignment rh[0] = 0; re[1] = 0 + D + E; for(j=2;j<=tl&&j<=W;j++) rh[j] = rh[j-1] + E; for(;j W? jc - W : 0; je = jc + W + 1 < tl? jc + W + 1 : tl; h1 = jb == 0? (I + E * (i + 1)) : MIN_SCORE; zi = &z[i * n_col]; for(j=jb;j= e? 0 : 1; h = m >= e? m : e; d = h >= f? d : 2; h = h >= f? h : f; h1 = h; t = m + I + E; e = e + E; d |= e > t? 1<<2 : 0; e = e > t? e : t; re[j] = e; t = m + D + E; f = f + E; d |= f > t? 2<<4 : 0; f = f > t? f : t; zi[j] = d; } rh[j] = h1; re[j] = MIN_SCORE; if(i + 1 == ql){ for(j=jb;j max){ max = rh[j + 1]; mi = i; mj = j; } } } else if(je == tl){ if(h1 > max){ max = h1; mi = i; mj = tl - 1; } } } if(max == MIN_SCORE) return 0; nbeg = dp_matrix2alignment_graph(g, query, z, mi, mj, geg, bnodes, bedges); return nbeg; } static inline void bdpgraph2dagcns(DAGCNS *dg, GEGraph *gg, bdpnodev *bnodes, bdpedgev *bedges, u4i nbeg, bdplinkv *stack){ dagnode_t *dn, *dn2; dagedge_t *de; ge_node_t *gn, *gn2; ge_edge_ref_t *gf; ge_edge_t *ge; bdp_node_t *bn, *bn2; bdp_edge_t *be; bdp_link_t T; u4i i, j, beg, end; int open; for(i=0;inodes->size;i++) gg->nodes->buffer[i].bt_visit = 0; clear_bdplinkv(stack); push_bdplinkv(stack, (bdp_link_t){nbeg, 0xFFFFFFFFU}); beg = bnodes->buffer[nbeg].y; end = beg; open = 0; while(stack->size){ T = stack->buffer[--stack->size]; gn = ref_genodev(gg->nodes, T.gnidx); bn = ref_bdpnodev(bnodes, T.gnidx); if(bn->y > (int)end) end = bn->y; dn = (T.dnidx == 0xFFFFFFFFU)? NULL : ref_dagnodev(dg->nodes, T.dnidx); geg_beg_iter_edges(gg, gn, 0, gf, ge); if(ge->closed) continue; be = ref_bdpedgev(bedges, offset_geedgev(gg->edges, ge)); gn2 = ref_genodev(gg->nodes, gf->flg? ge->node1 : ge->node2); bn2 = ref_bdpnodev(bnodes, gf->flg? ge->node1 : ge->node2); if(gn2->bt_visit == 0){ gn2->bt_visit = 1; open ++; gn2->unvisit = gn2->edges[1].cnt; } if(gn2->unvisit) gn2->unvisit --; if(gn2->unvisit == 0){ open --; } if(open < 0){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); } if(bn2->dnidx == MAX_VALUE_U4){ if(be->cigar == 2){ dn2 = dn; } else if(dn && (open || be->cigar == 1)){ dn2 = ref_dagnodev(dg->nodes, prepare_node_dagcns(dg, bn2->y, be->base)); dn = dn? ref_dagnodev(dg->nodes, T.dnidx) : NULL; } else if((dn || open == 0) && be->cigar == 0){ // cigar == 0 && open == 0 dn2 = ref_dagnodev(dg->nodes, bn2->y); } else dn2 = NULL; bn2->dnidx = dn2? offset_dagnodev(dg->nodes, dn2) : MAX_VALUE_U4; } else { dn2 = ref_dagnodev(dg->nodes, bn2->dnidx); } if(dn && dn2 && dn != dn2){ de = prepare_edge_dagcns(dg, offset_dagnodev(dg->nodes, dn), offset_dagnodev(dg->nodes, dn2), 0); de->score += be->prob; } if(gn2->unvisit == 0){ push_bdplinkv(stack, (bdp_link_t){offset_genodev(gg->nodes, gn2), dn2? offset_dagnodev(dg->nodes, dn2) : 0xFFFFFFFFU}); } geg_end_iter_edges(); } for(j=beg;jdeps->buffer[j] ++; return; } static inline void merge_nodes_core_dagcns(DAGCNS *g, uint32_t nid, u32list *stack, u32list *cache[4], int dir){ dagnode_t *n0, *n2, *n; dagedge_t *e, *e2, *e1; uint32_t base, eid, nid1, i, ret; clear_u32list(stack); push_u32list(stack, nid); ret = 0; while(pop_u32list(stack, &nid)){ n0 = ref_dagnodev(g->nodes, nid); if((eid = n0->edges[dir]) == 0xFFFFFFFFU) continue; clear_u32list(cache[0]); clear_u32list(cache[1]); clear_u32list(cache[2]); clear_u32list(cache[3]); while(1){ e = ref_dagedgev(g->edges, eid); n = ref_dagnodev(g->nodes, e->nodes[dir]); e2 = ref_dagedgev(g->edges, n->edges[!dir]); if(e2->links[!dir] == 0xFFFFFFFFU){ // check whether there is only one edge from n -(!dir)-> n0 push_u32list(cache[n->base], eid); } if((eid = e->links[dir]) == 0xFFFFFFFFU) break; } for(base=0;base<4;base++){ if(cache[base]->size < 2) continue; for(i=0;isize;i++) ref_dagedgev(g->edges, cache[base]->buffer[i])->visit = 1; e1 = ref_dagedgev(g->edges, cache[base]->buffer[0]); n = ref_dagnodev(g->nodes, e1->nodes[dir]); eid = n->edges[dir]; nid1 = e1->nodes[dir]; while(eid != 0xFFFFFFFFU){ e = ref_dagedgev(g->edges, eid); e->visit = 1; eid = e->links[dir]; } for(i=1;isize;i++){ e2 = ref_dagedgev(g->edges, cache[base]->buffer[i]); n2 = ref_dagnodev(g->nodes, e2->nodes[dir]); e1->cov += e2->cov; e1->score += e2->score; remove_edge_dagcns(g, cache[base]->buffer[i]); eid = n2->edges[dir]; while(eid != 0xFFFFFFFFU){ e2 = ref_dagedgev(g->edges, eid); e = prepare_edge_dagcns(g, nid1, e2->nodes[dir], dir); { e1 = ref_dagedgev(g->edges, cache[base]->buffer[0]); // memory referred by e1 may be freed in prepare_edge_dagcns } e->cov = e->cov - 1 + e2->cov; e->score = e->score + e2->score; e->visit = 1; eid = e2->links[dir]; } eid = n2->edges[dir]; while(eid != 0xFFFFFFFFU){ e2 = ref_dagedgev(g->edges, eid); remove_edge_dagcns(g, eid); // e2->links retain the same values after removing eid = e2->links[dir]; } } //n = ref_dagnodev(g->nodes, e1->nodes[dir]); //eid = n->edges[dir]; //if(eid != 0xFFFFFFFFU && g->edges->buffer[eid].links[dir] == 0xFFFFFFFFU) continue; // we had merged a bubble branch1:A->C->T, branch2:A->C->T push_u32list(stack, nid1); } } } static inline int has_non_visited_edge_dagcns(DAGCNS *g, uint32_t nid, int dir){ dagnode_t *n; dagedge_t *e; uint32_t eid; n = ref_dagnodev(g->nodes, nid); eid = n->edges[dir]; while(eid != 0xFFFFFFFFU){ e = ref_dagedgev(g->edges, eid); if(e->visit == 0) return 1; eid = e->links[dir]; } return 0; } static inline void print_local_dot_dagcns(DAGCNS *g, uint32_t nid, int distance, FILE *out){ u32list *stack; u32hash *hash; dagnode_t *n, *n1, *n2; dagedge_t *e; uint32_t id1, id2, eid, *u; int lo, hi, dir, exists; n = ref_dagnodev(g->nodes, nid); stack = init_u32list(32); hash = init_u32hash(1023); lo = n->pos - distance; hi = n->pos + distance; push_u32list(stack, nid); put_u32hash(hash, nid); fprintf(out, "digraph {\nrankdir=LR\n"); while(stack->size){ id1 = stack->buffer[--stack->size]; n1 = ref_dagnodev(g->nodes, id1); for(dir=0;dir<1;dir++){ eid = n1->edges[dir]; while(eid != 0xFFFFFFFFU){ e = ref_dagedgev(g->edges, eid); id2 = e->nodes[dir]; n2 = ref_dagnodev(g->nodes, id2); fprintf(out, "N%d_%d_%c -> N%d_%d_%c [label=\"%d:%0.6f\" color=%s]\n", id1, n1->pos, "ACGT"[n1->base], id2, n2->pos, "ACGT"[n2->base], e->cov, e->score, e->visit? "blue" : "black"); if(n2->pos >= lo && n2->pos <= hi){ u = prepare_u32hash(hash, id2, &exists); if(exists){ } else { *u = id2; push_u32list(stack, id2); } } eid = e->links[dir]; } } } fprintf(out, "}\n"); fflush(out); free_u32list(stack); free_u32hash(hash); } static inline void fprint_local_dot_dagcns(DAGCNS *g, u4i nid, int level, char *prefix, char *suffix){ FILE *out; out = open_file_for_write(prefix, suffix, 1); print_local_dot_dagcns(g, nid, level, out); fclose(out); } static inline void merge_nodes_dagcns(DAGCNS *g){ dagnode_t *n; dagedge_t *e; u32list *stack, *cache[4]; u32fifo *queue; uint32_t i, nid, eid; stack = init_u32list(1024); cache[0] = init_u32list(4); cache[1] = init_u32list(4); cache[2] = init_u32list(4); cache[3] = init_u32list(4); for(i=0;iedges->size;i++) g->edges->buffer[i].visit = 0; for(i=0;inodes->size;i++) g->nodes->buffer[i].visit = 0; queue = init_u32fifo(); for(i=0;inodes->size;i++){ n = ref_dagnodev(g->nodes, i); if(n->edges[1] != 0xFFFFFFFFU) continue; push_u32fifo(queue, i); } //dagcns_debug = 2; while(pop_u32fifo(queue, &nid)){ if(dagcns_debug > 1) fprintf(stdout, "\npop(%u) %u\n", (u4i)queue->size, nid); n = ref_dagnodev(g->nodes, nid); if(n->visit) continue; n->visit = 1; merge_nodes_core_dagcns(g, nid, stack, cache, 1); merge_nodes_core_dagcns(g, nid, stack, cache, 0); n = ref_dagnodev(g->nodes, nid); eid = n->edges[0]; while(eid != 0xFFFFFFFFU){ e = ref_dagedgev(g->edges, eid); e->visit = 1; eid = e->links[0]; } eid = n->edges[0]; while(eid != 0xFFFFFFFFU){ e = ref_dagedgev(g->edges, eid); if(!has_non_visited_edge_dagcns(g, e->nodes[0], 1)){ if(dagcns_debug > 1) fprintf(stdout, "push %u\n", e->nodes[0]); push_u32fifo(queue, e->nodes[0]); } eid = e->links[0]; } } free_u32fifo(queue); free_u32list(stack); free_u32list(cache[0]); free_u32list(cache[1]); free_u32list(cache[2]); free_u32list(cache[3]); } static inline void print_seq_dagcns(DAGCNS *g, FILE *out){ char buffer[100]; uint32_t i, j; for(i=j=0;icns->size;i++){ buffer[j++] = bit_base_table[g->cns->buffer[i]]; if(j == 99){ buffer[j] = '\0'; fprintf(out, "%s", buffer); j = 0; } } buffer[j] = '\0'; fprintf(out, "%s", buffer); } static inline void gen_consensus_dagcns(DAGCNS *g, u32list *map){ dagnode_t *n1, *n2; dagedge_t *e; u32fifo *queue; uint32_t i, lst, nid, eid, best_e; f8i best_s, score; queue = init_u32fifo(); if(queue == NULL){ // un-reachable, but is used to call fprint_local_dot_dagcns in gdb Debug fprint_local_dot_dagcns(g, 0, 10, "test.dot", NULL); } for(i=0;inodes->size;i++){ n1 = ref_dagnodev(g->nodes, i); if(n1->edges[0] == 0xFFFFFFFFU && n1->edges[1] != 0xFFFFFFFFU){ push_u32fifo(queue, i); n1->fw_edge = NODE_MAX_FW_EDGE; n1->aux = 0; } } for(i=0;iedges->size;i++) g->edges->buffer[i].visit = 0; while(pop_u32fifo(queue, &nid)){ best_s = - FLT_MAX; best_e = 0xFFFFFFFFU; n1 = ref_dagnodev(g->nodes, nid); eid = n1->edges[0]; while(eid != 0xFFFFFFFFU){ e = ref_dagedgev(g->edges, eid); n2 = ref_dagnodev(g->nodes, e->nodes[0]); if(e->nodes[0] < g->backbone_size){ //score = n2->aux + e->cov - g->ref_penalty * g->deps->buffer[n1->pos]; score = n2->aux + e->score - g->ref_penalty * g->deps->buffer[n1->pos]; } else { //score = n2->aux + e->cov - g->alt_penalty * g->deps->buffer[n1->pos]; score = n2->aux + e->score - g->alt_penalty * g->deps->buffer[n1->pos]; } if(score > best_s){ best_s = score; best_e = eid; } eid = e->links[0]; } if(best_s > - FLT_MAX) n1->aux = best_s; n1->fw_edge = best_e; eid = n1->edges[1]; while(eid != 0xFFFFFFFFU){ e = ref_dagedgev(g->edges, eid); e->visit = 1; if(!has_non_visited_edge_dagcns(g, e->nodes[1], 0)){ push_u32fifo(queue, e->nodes[1]); } eid = e->links[1]; } } free_u32fifo(queue); clear_u8list(g->cns); clear_u32list(g->deps); if(map) clear_u32list(map); g->cns_head = 0; if(g->nodes->size == 0) return; n1 = ref_dagnodev(g->nodes, g->cns_head); g->cns_score = n1->aux; n1->cns = 1; lst = 0; if(map && g->cns_head < g->backbone_size){ while(lst < g->cns_head){ push_u32list(map, g->cns->size); lst ++; } } push_u8list(g->cns, n1->base); push_u32list(g->deps, 0); while(n1->fw_edge != NODE_MAX_FW_EDGE){ e = ref_dagedgev(g->edges, n1->fw_edge); e->cns = 1; if(map && e->nodes[0] < g->backbone_size){ while(lst < e->nodes[0]){ push_u32list(map, g->cns->size); lst ++; } } n1 = ref_dagnodev(g->nodes, e->nodes[0]); n1->cns = 1; push_u8list(g->cns, n1->base); push_u32list(g->deps, 0); } if(map) while(lst <= g->backbone_size){ push_u32list(map, g->cns->size); lst ++; } } #endif wtdbg2-2.5/dbgcns.h000066400000000000000000001164651353664372200142120ustar00rootroot00000000000000/* * * Copyright (c) 2011, Jue Ruan * * * 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 3 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, see . */ #ifndef __DBGCNS_CNS_RJ_H #define __DBGCNS_CNS_RJ_H #include "dna.h" #include "list.h" #include "hashset.h" #include "thread.h" #include "ksw.h" #include "chararray.h" /* #ifndef DBGCNS_DEBUG #define DBGCNS_DEBUG 0 #endif */ static int DBGCNS_DEBUG = 0; #define DBGCNS_KMER_MAX_SIZE 21 #define DBGCNS_KMER_MAX_NODE_COV 0x3FF #define DBGCNS_KMER_MAX_EDGE_COV 0xFF #define DBGCNS_MAX_UID 0xFFF typedef struct { uint64_t mer:42, cov:10, visit:12; uint8_t edges[2][4]; } dbgcns_kmer_t; define_list(dbgcnskmerv, dbgcns_kmer_t); #define UD(E) ((dbgcnskmerv*)set->userdata)->buffer[E].mer #define kmer_hashcode(E) u64hashcode(UD(E)) #define kmer_hashequals(E1, E2) UD(E1) == UD(E2) define_hashset(dbgcnskmerhash, uint32_t, kmer_hashcode, kmer_hashequals); #undef UD typedef struct { u4i ksize; u8i kmask; int hz; dbgcnskmerv *kmers; dbgcnskmerhash *khash; u1v *zseq; } DBG; #define BT_SCORE_MIN -0x0FFFFFFF typedef struct { u8i mer:42, off:21, closed:1; u2i n_in, n_visit; u4i edges, bt_node, bt_edge; int bt_score; u8i ptr; // refer to dbg->kmers } fbg_kmer_t; #define fbgkmer_hashcode(E) u64hashcode((E).mer) #define fbgkmer_equals(E1, E2) ((E1).mer == (E2).mer) define_hashset(fbgkmerh, fbg_kmer_t, fbgkmer_hashcode, fbgkmer_equals); typedef struct { u4i node, cov:28, most:1, key:2, select:1; u4i dist; u4i link; u4i next; } fbg_edge_t; define_list(fbgedgev, fbg_edge_t); typedef struct { u4i ridx, roff:15, rlen:15, key:1, select:1; u4i next; } fbg_link_t; define_list(fbglinkv, fbg_link_t); typedef struct { u8i ridx:16, kidx:30, koff:17, closed:1; } rd_kmer_t; define_list(rdkmerv, rd_kmer_t); typedef struct { u4i lidx, len, gidx; } link_grp_t; define_list(linkgrpv, link_grp_t); typedef struct { fbgkmerh *kmers; fbgedgev *edges; fbglinkv *links; linkgrpv *grps; rdkmerv *mats; u1v *starseq; } FBG; #define DBGCNS_DP_SCORE_MIN -0x7FFFFFFF #define DBGCNS_PATH_M 0 #define DBGCNS_PATH_X 1 #define DBGCNS_PATH_I 2 #define DBGCNS_PATH_D 3 #define DBGCNS_CNS_NON 0 #define DBGCNS_CNS_TIP 1 #define DBGCNS_CNS_CUT 2 #define DBGCNS_CNS_EXT 3 #define DBGCNS_CNS_HIT 4 typedef struct { union { struct { uint32_t kidx:30, path:2; uint32_t qpos; }; uint64_t identifier; }; int score; uint32_t bt_idx; } dbgcns_dp_t; define_list(dbgcnsdpv, dbgcns_dp_t); #define DD(E) ((dbgcnsdpv*)set->userdata)->buffer[E] #define dp_hashcode(E) u64hashcode(DD(E).identifier) #define dp_hashequals(E1, E2) DD(E1).identifier == DD(E2).identifier define_hashset(dbgcnsdphash, uint32_t, dp_hashcode, dp_hashequals); #undef DD typedef struct {uint64_t off:40, len:23, solid:1;} blk_t; define_list(blkv, blk_t); typedef struct { DBG *g; FBG *fbg; int C, M, X, I, D, E, H, L; int Z, W; u1v *qseqs; blkv *qblks; uint8_t *qry; uint32_t qlen; u4i qidx; int avg_cov; dbgcnsdpv *dps; u4v *heap; dbgcnsdphash *hash; b4v *qmaxs; uint32_t qtop; int max_score; uint32_t best_idx; String *seq; u1v *cns; u1v *cigars; int alns[4]; } CNS; static inline DBG* init_dbg(uint32_t ksize){ DBG *g; if(ksize > DBGCNS_KMER_MAX_SIZE){ fprintf(stderr, " -- ksize MUST be no greater than %d, but is %d in %s -- %s:%d --\n", DBGCNS_KMER_MAX_SIZE, ksize, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); exit(1); } g = malloc(sizeof(DBG)); g->hz = 0; g->ksize = ksize; g->kmask = 0xFFFFFFFFFFFFFFFFLLU >> ((32 - ksize) << 1); g->kmers = init_dbgcnskmerv(32); next_ref_dbgcnskmerv(g->kmers); memset(g->kmers->buffer, 0, sizeof(dbgcns_kmer_t)); g->khash = init_dbgcnskmerhash(1023); set_userdata_dbgcnskmerhash(g->khash, g->kmers); g->zseq = init_u1v(64); return g; } static inline void free_dbg(DBG *g){ free_dbgcnskmerv(g->kmers); free_dbgcnskmerhash(g->khash); free_u1v(g->zseq); free(g); } static inline void clear_dbg(DBG *g){ clear_dbgcnskmerv(g->kmers); next_ref_dbgcnskmerv(g->kmers); memset(g->kmers->buffer, 0, sizeof(dbgcns_kmer_t)); clear_dbgcnskmerhash(g->khash); } static inline int add_kmer_dbg(DBG *g, u8i kmer, u4i ridx, uint8_t fbase, uint8_t rbase, int inc){ dbgcns_kmer_t *k; u8i krev; uint32_t *u; int dir, exists; if(0){ krev = dna_rev_seq(kmer, g->ksize); if(kmer < krev){ dir = 0; } else { kmer = krev; dir = 1; } } else { dir = 0; } g->kmers->buffer[0].mer = kmer; u = prepare_dbgcnskmerhash(g->khash, 0, &exists); if(exists){ k = ref_dbgcnskmerv(g->kmers, *u); } else { *u = g->kmers->size; k = next_ref_dbgcnskmerv(g->kmers); memset(k, 0, sizeof(dbgcns_kmer_t)); k->mer = kmer; k->cov = 0; k->visit = 0; } if(k->visit != ridx + 1 && k->cov < DBGCNS_KMER_MAX_NODE_COV && (inc || k->cov == 0)){ k->cov ++; } k->visit = ridx + 1; if(dir){ if(fbase < 4){ fbase = (~fbase) & 0x03; if(k->edges[1][fbase] < DBGCNS_KMER_MAX_EDGE_COV && (inc || k->edges[1][fbase] == 0)) k->edges[1][fbase] ++; } if(rbase < 4){ if(k->edges[0][rbase] < DBGCNS_KMER_MAX_EDGE_COV && (inc || k->edges[0][rbase] == 0)) k->edges[0][rbase] ++; } } else { if(fbase < 4){ if(k->edges[0][fbase] < DBGCNS_KMER_MAX_EDGE_COV && (inc || k->edges[0][fbase] == 0)) k->edges[0][fbase] ++; } if(rbase < 4){ rbase = (~rbase) & 0x03; if(k->edges[1][rbase] < DBGCNS_KMER_MAX_EDGE_COV && (inc || k->edges[1][rbase] == 0)) k->edges[1][rbase] ++; } } return exists; } static inline void homopolymer_compress_dbg(DBG *g, u1i *seq, u4i len){ u4i i; u1i b; clear_u1v(g->zseq); b = 4; for(i=0;izseq, b); } } static inline void add_seq_dbg(DBG *g, u4i ridx, uint8_t *seq, uint32_t len, int cov_inc){ u8i kmer; uint32_t i; uint8_t b, f, r; if(g->hz){ homopolymer_compress_dbg(g, seq, len); seq = g->zseq->buffer; len = g->zseq->size; } kmer = 0; for(i=0;ikmask; i ++; if(i < g->ksize) continue; f = (i < len)? seq[i] : 4; r = (i > g->ksize)? seq[i - g->ksize] : 4; add_kmer_dbg(g, kmer, ridx, f, r, cov_inc); } } static inline int kmer_cov_seq_dbg(DBG *g, u1i *seq, u4i len, u4i uid){ dbgcns_kmer_t *k; u8i kmer; uint32_t i, *u; uint8_t b; int cov; uid = uid % DBGCNS_MAX_UID; if(g->hz){ homopolymer_compress_dbg(g, seq, len); seq = g->zseq->buffer; len = g->zseq->size; } cov = 0; kmer = 0; for(i=0;ikmask; i ++; if(i < g->ksize) continue; g->kmers->buffer[0].mer = kmer; u = get_dbgcnskmerhash(g->khash, 0); if(u){ k = ref_dbgcnskmerv(g->kmers, *u); if(k->visit == uid){ cov --; continue; } k->visit = uid; cov += k->cov > 1? k->cov + 1 : - 1; } } return cov; } static inline void print_kmers_dbg(DBG *g, FILE *out){ dbgcns_kmer_t *k; uint64_t i; char seq[DBGCNS_KMER_MAX_SIZE + 1]; for(i=1;ikmers->size;i++){ k = ref_dbgcnskmerv(g->kmers, i); kmer2seq(seq, k->mer, g->ksize); fprintf(out, "%s\t%d\t%d,%d,%d,%d\t%d,%d,%d,%d\n", seq, k->cov, k->edges[0][0], k->edges[0][1], k->edges[0][2], k->edges[0][3], k->edges[1][0], k->edges[1][1], k->edges[1][2], k->edges[1][3]); } } static inline CNS* init_cns(uint32_t ksize, int Z, int W, int M, int X, int I, int D, int E, int H, int L){ CNS *cns; cns = malloc(sizeof(CNS)); cns->g = init_dbg(ksize); cns->fbg = malloc(sizeof(FBG)); cns->fbg->kmers = init_fbgkmerh(1023); cns->fbg->edges = init_fbgedgev(32); memset(next_ref_fbgedgev(cns->fbg->edges), 0, sizeof(fbg_edge_t)); cns->fbg->links = init_fbglinkv(32); memset(next_ref_fbglinkv(cns->fbg->links), 0, sizeof(fbg_link_t)); cns->fbg->grps = init_linkgrpv(32); cns->fbg->mats = init_rdkmerv(32); cns->fbg->starseq = init_u1v(32); cns->qseqs = init_u1v(32); cns->qblks = init_blkv(32); cns->Z = Z; cns->W = W; cns->C = 1; cns->M = M; cns->X = X; cns->I = I; cns->D = D; cns->E = E; cns->H = H; cns->L = L; cns->qlen = 0; cns->qidx = 0; cns->avg_cov = 0; cns->dps = init_dbgcnsdpv(32); next_ref_dbgcnsdpv(cns->dps); memset(cns->dps->buffer, 0, sizeof(dbgcns_dp_t)); // no need, it is always zero-filled cns->heap = init_u4v(32); cns->hash = init_dbgcnsdphash(1023); set_userdata_dbgcnsdphash(cns->hash, cns->dps); cns->qmaxs = init_b4v(32); cns->qtop = 0; cns->max_score = DBGCNS_DP_SCORE_MIN; cns->best_idx = 0; cns->seq = init_string(32); cns->cns = init_u1v(32); cns->cigars = init_u1v(32); return cns; } static inline void free_cns(CNS *cns){ free_dbg(cns->g); free_fbgkmerh(cns->fbg->kmers); free_fbgedgev(cns->fbg->edges); free_fbglinkv(cns->fbg->links); free_linkgrpv(cns->fbg->grps); free_rdkmerv(cns->fbg->mats); free_u1v(cns->fbg->starseq); free(cns->fbg); free_u1v(cns->qseqs); free_blkv(cns->qblks); free_dbgcnsdpv(cns->dps); free_u4v(cns->heap); free_dbgcnsdphash(cns->hash); free_b4v(cns->qmaxs); free_string(cns->seq); free_u1v(cns->cns); free_u1v(cns->cigars); free(cns); } static inline void reset_cns(CNS *cns){ clear_dbg(cns->g); clear_u1v(cns->qseqs); clear_blkv(cns->qblks); clear_fbgkmerh(cns->fbg->kmers); clear_fbgedgev(cns->fbg->edges); memset(next_ref_fbgedgev(cns->fbg->edges), 0, sizeof(fbg_edge_t)); clear_fbglinkv(cns->fbg->links); memset(next_ref_fbglinkv(cns->fbg->links), 0, sizeof(fbg_link_t)); cns->qry = NULL; cns->qlen = 0; } static inline void add_seq_cns(CNS *cns, char *seq, int len, int solid){ blk_t *b; int i; b = next_ref_blkv(cns->qblks); b->off = cns->qseqs->size; b->len = len; b->solid = solid; for(i=0;iqseqs, base_bit_table[(int)seq[i]]); } static inline void ready_cns(CNS *cns){ UNUSED(cns); //blk_t *b; //u4i i; //for(i=0;iqblks->size;i++){ //b = ref_blkv(cns->qblks, i); //add_seq_dbg(cns->g, cns->qseqs->buffer + b->off, b->len); //} } static inline int dbg_cns_core(CNS *cns){ dbgcns_dp_t *dp, *dp2; dbgcns_kmer_t *k; u8i kmer, knew; uint32_t i, dp_idx, kidx, *u; int sum, cov, cut; uint8_t b, q; int exists, score, nadd, mat_only; if(cns->heap->size == 0) return DBGCNS_CNS_NON; dp_idx = cns->heap->buffer[0]; //array_heap_pop(cns->heap->buffer, cns->heap->size, cns->heap->cap, uint32_t, num_cmp(cns->dps->buffer[b].score, cns->dps->buffer[a].score)); encap_dbgcnsdpv(cns->dps, 9); dp = ref_dbgcnsdpv(cns->dps, dp_idx); mat_only = 0; if(dp->qpos >= cns->qlen) return DBGCNS_CNS_HIT; if(dp->qpos + cns->W < cns->qtop){ mat_only = 1; //array_heap_remove(cns->heap->buffer, cns->heap->size, cns->heap->cap, uint32_t, 0, num_cmp(cns->dps->buffer[b].score, cns->dps->buffer[a].score)); //return DBGCNS_CNS_CUT; } else if(dp->qpos > cns->qtop){ cns->qtop = dp->qpos; for(i=cns->heap->size;i>0;i--){ if(cns->dps->buffer[cns->heap->buffer[i-1]].qpos + cns->W < cns->qtop){ array_heap_remove(cns->heap->buffer, cns->heap->size, cns->heap->cap, uint32_t, i - 1, num_cmp(cns->dps->buffer[b].score, cns->dps->buffer[a].score)); } } } if(dp->score < cns->qmaxs->buffer[dp->qpos]){ mat_only = 1; //array_heap_remove(cns->heap->buffer, cns->heap->size, cns->heap->cap, uint32_t, 0, num_cmp(cns->dps->buffer[b].score, cns->dps->buffer[a].score)); //return DBGCNS_CNS_CUT; } else if(dp->score + cns->Z * cns->X > cns->qmaxs->buffer[dp->qpos]){ cns->qmaxs->buffer[dp->qpos] = dp->score + cns->Z * cns->X; } u = prepare_dbgcnsdphash(cns->hash, dp_idx, &exists); if(exists){ dp2 = ref_dbgcnsdpv(cns->dps, *u); if(dp->score > dp2->score){ *u = dp_idx; } else { array_heap_remove(cns->heap->buffer, cns->heap->size, cns->heap->cap, uint32_t, 0, num_cmp(cns->dps->buffer[b].score, cns->dps->buffer[a].score)); return DBGCNS_CNS_CUT; } } else { *u = dp_idx; } array_heap_remove(cns->heap->buffer, cns->heap->size, cns->heap->cap, uint32_t, 0, num_cmp(cns->dps->buffer[b].score, cns->dps->buffer[a].score)); k = ref_dbgcnskmerv(cns->g->kmers, dp->kidx); kmer = k->mer; q = cns->qry[dp->qpos]; sum = k->edges[0][0] + k->edges[0][1] + k->edges[0][2] + k->edges[0][3]; if(sum == 0) return DBGCNS_CNS_TIP; cut = num_max((cns->avg_cov + cns->L - 1) / cns->L, 1); //cut = num_max((cns->avg_cov + 2) / 3, 1); nadd = 0; for(b=0;b<4;b++){ if((cov = k->edges[0][b]) == 0) continue; if(b == q){ score = dp->score + cns->M; } else if(mat_only){ continue; } else { score = dp->score + cns->X; } //score += (cov > 1)? (cov >= cut? 1 : 0) : -1; score += (cov > cut)? (cns->H + (b == q? 1 : 0)) : cov - cut; //score += (cov > cut)? cns->H : cov - cut; knew = ((kmer << 2) | b) & cns->g->kmask; cns->g->kmers->buffer[0].mer = knew; u = get_dbgcnskmerhash(cns->g->khash, 0); kidx = *u; dp2 = next_ref_dbgcnsdpv(cns->dps); dp2->kidx = kidx; dp2->path = (b == q)? DBGCNS_PATH_M : DBGCNS_PATH_X; dp2->qpos = dp->qpos + 1; dp2->score = score; dp2->bt_idx = dp_idx; array_heap_push(cns->heap->buffer, cns->heap->size, cns->heap->cap, uint32_t, cns->dps->size - 1, num_cmp(cns->dps->buffer[b].score, cns->dps->buffer[a].score)); nadd ++; // deletion if(dp->path != DBGCNS_PATH_I){ dp2 = next_ref_dbgcnsdpv(cns->dps); score = dp->score + (cns->E + (dp->path == DBGCNS_PATH_D? 0 : cns->D)); if(dp->path != DBGCNS_PATH_D) score += (cov > cut)? 0 : cov - cut; else score += (cov > cut)? cns->H : cov - cut; dp2->kidx = kidx; dp2->path = DBGCNS_PATH_D; dp2->qpos = dp->qpos; dp2->score = score; dp2->bt_idx = dp_idx; array_heap_push(cns->heap->buffer, cns->heap->size, cns->heap->cap, uint32_t, cns->dps->size - 1, num_cmp(cns->dps->buffer[b].score, cns->dps->buffer[a].score)); nadd ++; } } // insertion if(mat_only == 0 && dp->path != DBGCNS_PATH_D){ dp2 = next_ref_dbgcnsdpv(cns->dps); score = dp->score + (cns->E + (dp->path == DBGCNS_PATH_I? 0 : cns->I)); //if(dp->qpos && cns->qry[dp->qpos] == cns->qry[dp->qpos - 1]) score += 1; // homopolymer merge score += 1 - cut; dp2->kidx = dp->kidx; dp2->path = DBGCNS_PATH_I; dp2->qpos = dp->qpos + 1; dp2->score = score; dp2->bt_idx = dp_idx; array_heap_push(cns->heap->buffer, cns->heap->size, cns->heap->cap, uint32_t, cns->dps->size - 1, num_cmp(cns->dps->buffer[b].score, cns->dps->buffer[a].score)); nadd ++; } return nadd? DBGCNS_CNS_EXT : DBGCNS_CNS_CUT; } static inline void ready_core_cns(CNS *cns, int candidate_mode, int reflen){ blk_t *b; u4i i; int tot; if(candidate_mode == 3) i = 1; else i = 0; tot = 0; for(;iqblks->size;i++){ b = ref_blkv(cns->qblks, i); add_seq_dbg(cns->g, i, cns->qseqs->buffer + b->off, b->len, 1); tot += b->len; } if(candidate_mode == 3){ b = ref_blkv(cns->qblks, 0); add_seq_dbg(cns->g, i, cns->qseqs->buffer + b->off, b->len, 0); tot += b->len; } cns->avg_cov = (tot + reflen - 1) / reflen; } static inline int run_core_cns(CNS *cns, uint8_t *qry, uint32_t qlen){ dbgcns_dp_t *dp; dbgcns_kmer_t *k; uint32_t i, kmer, kidx, dp_idx, *u; int status; { cns->qry = qry; cns->qlen = qlen; // reset auxiliaries clear_dbgcnsdpv(cns->dps); next_ref_dbgcnsdpv(cns->dps); memset(cns->dps->buffer, 0, sizeof(dbgcns_dp_t)); clear_u4v(cns->heap); clear_dbgcnsdphash(cns->hash); clear_b4v(cns->qmaxs); for(i=0;iqmaxs, DBGCNS_DP_SCORE_MIN); cns->qtop = 0; cns->max_score= DBGCNS_DP_SCORE_MIN; cns->best_idx = 0; clear_u1v(cns->cns); clear_string(cns->seq); clear_u1v(cns->cigars); cns->alns[0] = cns->alns[1] = cns->alns[2] = cns->alns[3] = 0; } // set first kmer kmer = 0; for(cns->qtop=0;cns->qtopg->ksize;cns->qtop++){ kmer = (kmer << 2) | qry[cns->qtop]; } cns->g->kmers->buffer[0].mer = kmer; u = get_dbgcnskmerhash(cns->g->khash, 0); if(u == NULL) return 0; kidx = *u; dp = next_ref_dbgcnsdpv(cns->dps); dp->kidx = kidx; dp->path = DBGCNS_PATH_M; dp->qpos = cns->qtop; dp->score = 0; dp->bt_idx = 0; array_heap_push(cns->heap->buffer, cns->heap->size, cns->heap->cap, uint32_t, cns->dps->size - 1, num_cmp(cns->dps->buffer[b].score, cns->dps->buffer[a].score)); // dbg traversing while(cns->heap->size){ status = dbg_cns_core(cns); if(status == DBGCNS_CNS_HIT){ dp_idx = cns->heap->buffer[0]; array_heap_remove(cns->heap->buffer, cns->heap->size, cns->heap->cap, uint32_t, 0, num_cmp(cns->dps->buffer[b].score, cns->dps->buffer[a].score)); dp = ref_dbgcnsdpv(cns->dps, dp_idx); if(dp->score > cns->max_score){ cns->max_score = dp->score; cns->best_idx = dp_idx; } } } if(cns->best_idx == 0) return 0; // traceback to get cns seq dp_idx = cns->best_idx; while(dp_idx){ dp = ref_dbgcnsdpv(cns->dps, dp_idx); push_u1v(cns->cigars, dp->path); cns->alns[dp->path] ++; if(dp->path != DBGCNS_PATH_I){ k = ref_dbgcnskmerv(cns->g->kmers, dp->kidx); push_u1v(cns->cns, k->mer & 0x03); if(k->cov == 1){ add_char_string(cns->seq, "acgt"[k->mer & 0x03]); } else { add_char_string(cns->seq, "ACGT"[k->mer & 0x03]); } } dp_idx = dp->bt_idx; } // first ksize - 1 bases may be not corrected, truncated reverse_string(cns->seq); reverse_u1v(cns->cns); reverse_u1v(cns->cigars); return cns->seq->size; } static inline int hierarchical_clustering_edge_links(FBG *fbg, fbg_edge_t *e, linkgrpv *grps, double max_var){ fbg_link_t *lnk; u4i lidx, gidx; u4i i, b; double sum, avg; clear_linkgrpv(grps); lidx = e->link; while(lidx){ lnk = ref_fbglinkv(fbg->links, lidx); push_linkgrpv(grps, (link_grp_t){lidx, lnk->rlen, 0}); lidx = lnk->next; } if(grps->size == 0) return 0; sort_array(grps->buffer, grps->size, link_grp_t, num_cmpgt(a.len, b.len)); gidx = 0; b = 0; sum = avg = grps->buffer[0].len; for(i=1;isize;i++){ if(grps->buffer[i].len - avg > avg * max_var){ gidx ++; sum = avg = grps->buffer[i].len; b = i; } else { sum += grps->buffer[i].len; avg = sum / (i - b + 1); if(avg - grps->buffer[b].len > avg * max_var || grps->buffer[i].len - avg > avg * max_var){ gidx ++; sum = avg = grps->buffer[i].len; b = i; } } grps->buffer[i].gidx = gidx; } return gidx + 1; } static inline int revise_edge_fbg(FBG *fbg, u4i kidx, u4i eidx, linkgrpv *grps, double max_var){ fbg_kmer_t *k; fbg_edge_t *e, *p; fbg_link_t *lnk; u4i eidx2, eidx3; u4i i, b, j, ng, avg, gidx; u4i max_cov, max_eidx, key; double sum; e = ref_fbgedgev(fbg->edges, eidx); ng = hierarchical_clustering_edge_links(fbg, e, grps, max_var); encap_fbgedgev(fbg->edges, ng - 1); k = ref_fbgkmerh(fbg->kmers, kidx); e = ref_fbgedgev(fbg->edges, eidx); e->key = key = e->key? 2 : 0; e->most = 0; if(DBGCNS_DEBUG){ if(ng > 1){ fprintf(stderr, "REVISE K%d -> K%d cov = %d into %d edges --\n", k->off, ref_fbgkmerh(fbg->kmers, e->node)->off, e->cov, ng); fflush(stderr); } } ref_fbgkmerh(fbg->kmers, e->node)->n_in += ng - 1; p = e; p->link = 0; eidx3 = e->next; gidx = 0; sum = 0; max_cov = 0; max_eidx = 0; for(i=b=0;i<=grps->size;i++){ if(i == grps->size || grps->buffer[i].gidx != gidx){ avg = sum / (i - b) + 0.5; if(p == NULL){ eidx2 = fbg->edges->size; p = next_ref_fbgedgev(fbg->edges); p->node = e->node; e->next = eidx2; p->next = eidx3; } p->link = 0; p->cov = i - b; p->dist = avg; p->key = key; p->select = 0; p->most = 0; if(p->cov > max_cov){ max_cov = p->cov; max_eidx = offset_fbgedgev(fbg->edges, p); } else if(p->cov == max_cov){ max_eidx = 0; } if(DBGCNS_DEBUG){ if(ng > 1){ fprintf(stderr, "+ %d %d --\n", p->cov, p->dist); fflush(stderr); } } for(j=b;jlinks, grps->buffer[j].lidx); lnk->next = p->link; p->link = grps->buffer[j].lidx; if(lnk->key) p->key = 1; } e = p; p = NULL; b = i; gidx ++; sum = 0; } if(i < grps->size) sum += grps->buffer[i].len; } if(max_eidx){ ref_fbgedgev(fbg->edges, max_eidx)->most = 1; } return gidx; } static inline void revise_edge_cov_fbg(FBG *fbg, fbg_edge_t *e){ fbg_link_t *lnk; u4i lidx, cnt; double sum, var, max, avg, std; sum = 0; var = 0; max = 0; cnt = 0; lidx = e->link; while(lidx){ lnk = ref_fbglinkv(fbg->links, lidx); if((double)lnk->rlen > max) max = lnk->rlen; sum += lnk->rlen; var += lnk->rlen * lnk->rlen; cnt ++; lidx = lnk->next; } if(cnt == 0) return; avg = sum / cnt; std = sqrt(var / cnt - avg * avg); if(std > 10 && std > 0.2 * avg) std = 0.2 * max; if(std < 1) std = 1; cnt = 0; sum = 0; lidx = e->link; while(lidx){ lnk = ref_fbglinkv(fbg->links, lidx); if(num_diff((double)lnk->rlen, avg) <= std){ sum += lnk->rlen; cnt ++; } lidx = lnk->next; } if(cnt == 0) cnt = 1; avg = sum / cnt; e->cov = cnt; e->dist = avg + 0.5; } static inline void build_DirectFuzzyBruijnGraph(CNS *cns, u4i ridx, u4i cov_cutoff, double max_dist_var){ DBG *g; dbgcns_kmer_t *k; fbg_kmer_t A, *a; fbg_edge_t *e; fbg_link_t *l; rd_kmer_t *rk; u8i kmer; u4i r, rr, i, j, beg, end, c, len, idx1, off1, idx2, off2, *u; u4i eidx; u1i b, *seq; int exists; g = cns->g; // select high cov kmers if(cov_cutoff){ seq = cns->qseqs->buffer + cns->qblks->buffer[ridx].off; len = cns->qblks->buffer[ridx].len; memset(&A, 0, sizeof(fbg_kmer_t)); kmer = 0; j = 0x0000FFFFU; for(i=0;ikmask; i ++; if(i < g->ksize) continue; g->kmers->buffer[0].mer = kmer; u = get_dbgcnskmerhash(g->khash, 0); if(u == NULL) continue; k = ref_dbgcnskmerv(g->kmers, *u); if(k->cov < cov_cutoff) continue; //if(j + 1 == i){ j = i; continue; } A.mer = kmer; a = prepare_fbgkmerh(cns->fbg->kmers, A, &exists); if(exists){ a->closed = 1; } else { a->mer = kmer; a->off = i - g->ksize; a->closed = 0; a->n_in = 0; a->n_visit = 0; a->edges = 0; a->ptr = *u; j = i; } } } else { // select best cov per 10 bp, but cov >= 4 clear_rdkmerv(cns->fbg->mats); seq = cns->qseqs->buffer + cns->qblks->buffer[ridx].off; len = cns->qblks->buffer[ridx].len; memset(&A, 0, sizeof(fbg_kmer_t)); kmer = 0; for(i=0;ikmask; i ++; if(i < g->ksize) continue; g->kmers->buffer[0].mer = kmer; u = get_dbgcnskmerhash(g->khash, 0); if(u == NULL) continue; if(g->kmers->buffer[*u].cov < 4) continue; push_rdkmerv(cns->fbg->mats, (rd_kmer_t){ridx, *u, i - g->ksize, 0}); } sort_array(cns->fbg->mats->buffer, cns->fbg->mats->size, rd_kmer_t, num_cmpgtx(g->kmers->buffer[b.kidx].cov, g->kmers->buffer[a.kidx].cov, a.kidx, b.kidx)); for(i=1;ifbg->mats->size;i++){ rk = ref_rdkmerv(cns->fbg->mats, i); if(rk->kidx == ref_rdkmerv(cns->fbg->mats, i - 1)->kidx){ rk->closed = 1; ref_rdkmerv(cns->fbg->mats, i - 1)->closed = 1; } } sort_array(cns->fbg->mats->buffer, cns->fbg->mats->size, rd_kmer_t, num_cmpgt(a.koff, b.koff)); beg = 0; j = 0xFFFFFFFFU; for(i=0;ifbg->mats->size;i++){ rk = ref_rdkmerv(cns->fbg->mats, i); if(rk->closed) continue; if(j == 0xFFFFFFFFU) j = i; if(rk->koff - beg < 10){ if(g->kmers->buffer[rk->kidx].cov > g->kmers->buffer[cns->fbg->mats->buffer[j].kidx].cov){ j = i; } continue; } rk = ref_rdkmerv(cns->fbg->mats, j); beg = rk->koff; j = i; i --; k = ref_dbgcnskmerv(g->kmers, rk->kidx); kmer = k->mer; A.mer = kmer; a = prepare_fbgkmerh(cns->fbg->kmers, A, &exists); if(exists){ a->closed = 1; } else { a->mer = kmer; a->off = rk->koff; a->closed = 0; a->n_in = 0; a->n_visit = 0; a->edges = 0; a->ptr = rk->kidx; } } } clear_rdkmerv(cns->fbg->mats); for(r=0;rqblks->size;r++){ seq = cns->qseqs->buffer + cns->qblks->buffer[r].off; len = cns->qblks->buffer[r].len; memset(&A, 0, sizeof(fbg_kmer_t)); kmer = 0; for(i=0;ikmask; i ++; if(i < g->ksize) continue; A.mer = kmer; a = get_fbgkmerh(cns->fbg->kmers, A); if(a == NULL) continue; if(a->closed) continue; push_rdkmerv(cns->fbg->mats, (rd_kmer_t){r, offset_fbgkmerh(cns->fbg->kmers, a), i - g->ksize, 0}); } } sort_array(cns->fbg->mats->buffer, cns->fbg->mats->size, rd_kmer_t, num_cmpgtx(a.ridx, b.ridx, a.kidx, b.kidx)); for(i=1;ifbg->mats->size;i++){ if(cns->fbg->mats->buffer[i-1].ridx == cns->fbg->mats->buffer[i].ridx && cns->fbg->mats->buffer[i-1].kidx == cns->fbg->mats->buffer[i].kidx){ ref_fbgkmerh(cns->fbg->kmers, cns->fbg->mats->buffer[i].kidx)->closed = 1; } } for(i=0;ifbg->mats->size;i++){ if(ref_fbgkmerh(cns->fbg->kmers, cns->fbg->mats->buffer[i].kidx)->closed){ cns->fbg->mats->buffer[i].closed = 1; } } sort_array(cns->fbg->mats->buffer, cns->fbg->mats->size, rd_kmer_t, num_cmpgtx(a.ridx, b.ridx, a.koff, b.koff)); // add edges for(i=0;i+1fbg->mats->size;i++){ if(cns->fbg->mats->buffer[i].closed) continue; idx1 = cns->fbg->mats->buffer[i].kidx; off1 = cns->fbg->mats->buffer[i].koff; a = ref_fbgkmerh(cns->fbg->kmers, idx1); for(j=i+1,c=0;jfbg->mats->size&&c<1;j++){ if(cns->fbg->mats->buffer[j].ridx != cns->fbg->mats->buffer[i].ridx) break; if(cns->fbg->mats->buffer[j].closed) continue; idx2 = cns->fbg->mats->buffer[j].kidx; off2 = cns->fbg->mats->buffer[j].koff; if(a->off >= ref_fbgkmerh(cns->fbg->kmers, idx2)->off) continue; c ++; eidx = a->edges; while(eidx){ e = ref_fbgedgev(cns->fbg->edges, eidx); if(e->node == idx2) break; eidx = e->next; } if(eidx == 0){ eidx = cns->fbg->edges->size; e = next_ref_fbgedgev(cns->fbg->edges); e->node = idx2; e->link = 0; e->next = a->edges; e->cov = 0; e->dist = 0; e->key = 0; e->select = 0; a->edges = eidx; ref_fbgkmerh(cns->fbg->kmers, idx2)->n_in ++; } e = ref_fbgedgev(cns->fbg->edges, eidx); if(cns->fbg->mats->buffer[i].ridx == ridx) e->key = 1; e->cov ++; l = next_ref_fbglinkv(cns->fbg->links); l->ridx = cns->fbg->mats->buffer[i].ridx; l->roff = off1; l->rlen = off2 - off1; l->key = (cns->fbg->mats->buffer[i].ridx == ridx); l->select = 0; l->next = e->link; e->link = cns->fbg->links->size - 1; } } rr = 0xFFFFFFFFU; for(beg=end=0;begfbg->mats->size;beg=end){ r = rr; for(;endfbg->mats->size;end++){ if(cns->fbg->mats->buffer[end].closed) continue; if(r == 0xFFFFFFFFU){ r = cns->fbg->mats->buffer[end].ridx; } else if(cns->fbg->mats->buffer[end].ridx == r) continue; else { rr = cns->fbg->mats->buffer[end].ridx; break; } } if(r == ridx) continue; // reference seq for(i=beg;i+2fbg->mats->buffer[i].closed) continue; idx1 = cns->fbg->mats->buffer[i].kidx; off1 = cns->fbg->mats->buffer[i].koff; a = ref_fbgkmerh(cns->fbg->kmers, idx1); c = 0; for(j=i+1;jfbg->mats->buffer[j].closed) continue; idx2 = cns->fbg->mats->buffer[j].kidx; off2 = cns->fbg->mats->buffer[j].koff; if(a->off >= ref_fbgkmerh(cns->fbg->kmers, idx2)->off) continue; c ++; if(c < 2) continue; if(c > 5) break; eidx = a->edges; while(eidx){ e = ref_fbgedgev(cns->fbg->edges, eidx); if(e->node == idx2) break; eidx = e->next; } if(eidx == 0) continue; e = ref_fbgedgev(cns->fbg->edges, eidx); e->cov ++; l = next_ref_fbglinkv(cns->fbg->links); l->ridx = r; l->roff = off1; l->rlen = off2 - off1; l->key = 0; l->select = 0; l->next = e->link; e->link = cns->fbg->links->size - 1; } } } if(0){ for(i=1;ifbg->edges->size;i++){ revise_edge_cov_fbg(cns->fbg, ref_fbgedgev(cns->fbg->edges, i)); } } else { reset_iter_fbgkmerh(cns->fbg->kmers); while((a = ref_iter_fbgkmerh(cns->fbg->kmers))){ eidx = a->edges; while(eidx){ e = ref_fbgedgev(cns->fbg->edges, eidx); eidx = e->next; revise_edge_fbg(cns->fbg, offset_fbgkmerh(cns->fbg->kmers, a), offset_fbgedgev(cns->fbg->edges, e), cns->fbg->grps, max_dist_var); } } } } static inline void print_dot_DirectFuzzyBruijnGraph(CNS *cns, FILE *out){ fbg_kmer_t *k, *n; fbg_edge_t *e; fbg_link_t *l; u4i eidx, lidx; if(out == NULL) return; fprintf(out, "digraph {\n\trankdir=LR\n"); reset_iter_fbgkmerh(cns->fbg->kmers); while((k = ref_iter_fbgkmerh(cns->fbg->kmers))){ if(k->closed) continue; eidx = k->edges; while(eidx){ e = ref_fbgedgev(cns->fbg->edges, eidx); if(e->cov >= 3 || e->key || e->select){ n = ref_fbgkmerh(cns->fbg->kmers, e->node); lidx = e->link; while(lidx){ l = ref_fbglinkv(cns->fbg->links, lidx); fprintf(out, "\tK%d -> K%d [label=\"R%04d_%d_%d(%d:%d)\" color=%s%s]\n", k->off, n->off, l->ridx, l->roff, l->rlen, e->cov, e->dist, l->key? "blue" : (e->most? "green" : "black"), l->select? " style=dashed" : ""); lidx = l->next; } } eidx = e->next; } } fprintf(out, "}\n"); } static inline void DP_best_path_DirectFuzzyBruijnGraph(CNS *cns){ FBG *fbg; fbg_kmer_t *k, *n; fbg_edge_t *e; u4v *heap; u4i kidx, nb, ne, nboff, neoff; u4i eidx, etmp; int ref_score, ref_one, alt_one, most_score, max_dist_var, var, score; float dist_var; ref_score = 1; ref_one = -50; alt_one = -1000; most_score = 2; max_dist_var = 100; dist_var = -0.5; fbg = cns->fbg; reset_iter_fbgkmerh(fbg->kmers); nb = ne = 0xFFFFFFFFU; nboff = 0xFFFFFFFFU; neoff = 0; while((k = ref_iter_fbgkmerh(fbg->kmers))){ k->n_visit = 0; k->bt_node = 0xFFFFFFFFU; k->bt_edge = 0; k->bt_score = BT_SCORE_MIN; if(k->closed) continue; if(k->off < nboff){ nb = offset_fbgkmerh(fbg->kmers, k); nboff = k->off; } if(k->off >= neoff){ ne = offset_fbgkmerh(fbg->kmers, k); neoff = k->off; } } if(nb == 0xFFFFFFFFU) return; heap = init_u4v(32); k = ref_fbgkmerh(fbg->kmers, nb); k->bt_score = 0; push_u4v(heap, nb); while(heap->size){ kidx = heap->buffer[--heap->size]; k = ref_fbgkmerh(fbg->kmers, kidx); eidx = k->edges; while(eidx){ e = ref_fbgedgev(fbg->edges, eidx); n = ref_fbgkmerh(fbg->kmers, e->node); score = k->bt_score + e->most * most_score; var = n->off - k->off; var = num_diff(var, (int)e->dist); if(e->key == 1){ score += ref_score + (e->cov <= 1? ref_one : 0); } else if(e->key == 2){ score += (e->cov <= 1? alt_one : 0); } else { if(var > max_dist_var) score = -1000000; else score += var * dist_var + (e->cov <= 1? alt_one : 0); } if(score > n->bt_score){ n->bt_score = score; n->bt_node = kidx; n->bt_edge = eidx; } n->n_visit ++; if(n->n_visit >= n->n_in){ push_u4v(heap, e->node); } eidx = e->next; } } free_u4v(heap); k = ref_fbgkmerh(fbg->kmers, ne); if(ne != nb && k->bt_edge == 0){ FILE *out = open_file_for_write("debug.dot", NULL, 1); print_dot_DirectFuzzyBruijnGraph(cns, out); fclose(out); fprintf(stderr, " -- something wrong, nb = %d(K%04d), ne = %d(K%04d) in %s -- %s:%d --\n", nb, fbg->kmers->array[nb].off, ne, fbg->kmers->array[ne].off, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); exit(1); } kidx = 0xFFFFFFFFU; eidx = 0; while(kidx != nb){ k = ref_fbgkmerh(fbg->kmers, ne); ne = k->bt_node; swap_tmp(eidx, k->bt_edge, etmp); k->bt_node = kidx; kidx = offset_fbgkmerh(fbg->kmers, k); } } static inline int correct_struct_DirectFuzzyBruijnGraph(CNS *cns, u4i ridx){ FBG *fbg; fbg_kmer_t *k, *n; fbg_edge_t *e; fbg_link_t *lnk; int chg; u4i off, kidx, koff, eidx, lidx, key, upd; fbg = cns->fbg; reset_iter_fbgkmerh(fbg->kmers); kidx = 0xFFFFFFFFU; koff = 0xFFFFFFFFU; while((k = ref_iter_fbgkmerh(fbg->kmers))){ if(k->closed) continue; if(k->off < koff){ kidx = offset_fbgkmerh(fbg->kmers, k); koff = k->off; } } clear_u1v(fbg->starseq); if(DBGCNS_DEBUG){ fprintf(stderr, " -- select seq[%d] len=%d in %s -- %s:%d --\n", ridx, cns->qblks->buffer[ridx].len, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); } if(kidx == 0xFFFFFFFFU){ append_array_u1v(fbg->starseq, cns->qseqs->buffer + cns->qblks->buffer[ridx].off, cns->qblks->buffer[ridx].len); return 0; } chg = 0; off = 0; while(1){ k = ref_fbgkmerh(fbg->kmers, kidx); if(off < k->off){ if(DBGCNS_DEBUG){ fprintf(stderr, "-- %d + %d bases from seq[%d], offset %d -> %d\n", (int)fbg->starseq->size, k->off - off, ridx, off, k->off); } append_array_u1v(fbg->starseq, cns->qseqs->buffer + cns->qblks->buffer[ridx].off + off, k->off - off); off = k->off; } if(k->bt_edge == 0) break; eidx = k->bt_edge; e = ref_fbgedgev(fbg->edges, eidx); e->select = 1; key = 0; double sum, var, cnt, avg, std, min; sum = 0; var = 0; cnt = 0; lidx = e->link; while(lidx){ lnk = ref_fbglinkv(fbg->links, lidx); sum += lnk->rlen; var += lnk->rlen * lnk->rlen; cnt ++; if(lnk->key) key = lidx; lidx = lnk->next; } if(key){ upd = key; } else { avg = sum / cnt; std = sqrt(var / cnt - avg * avg); if(std < 1) std = 1; lidx = e->link; min = 100000; upd = key; while(lidx){ lnk = ref_fbglinkv(fbg->links, lidx); if(num_diff((double)lnk->rlen, avg) < min){ upd = lidx; min = num_diff((double)lnk->rlen, avg); } lidx = lnk->next; } } lnk = ref_fbglinkv(fbg->links, upd); lnk->select = 1; kidx = k->bt_node; n = ref_fbgkmerh(fbg->kmers, kidx); if(DBGCNS_DEBUG){ fprintf(stderr, "-- %d + %d bases from seq[%d], offset %d + %d -> %d\n", (int)fbg->starseq->size, lnk->rlen, lnk->ridx, off, n->off - off, n->off); } append_array_u1v(fbg->starseq, cns->qseqs->buffer + cns->qblks->buffer[lnk->ridx].off + lnk->roff, lnk->rlen); off = n->off; } k = NULL; if(off < cns->qblks->buffer[ridx].len){ if(DBGCNS_DEBUG){ fprintf(stderr, "-- %d + %d bases from seq[%d], offset %d -> %d\n", (int)fbg->starseq->size, cns->qblks->buffer[ridx].len - off, ridx, off, cns->qblks->buffer[ridx].len); } append_array_u1v(fbg->starseq, cns->qseqs->buffer + cns->qblks->buffer[ridx].off + off, cns->qblks->buffer[ridx].len - off); } return chg; } static inline int homopolymer_analysis_cns(CNS *cns){ u8i kmer, xmask[2]; u4i chg, i, j, l, r, c, brun, *u, kcnts[3]; u1i b; char kstr[64]; UNUSED(kstr); // only for compile warning xmask[1] = 0xFFFFFFFFFFFFFFFFLLU >> (64 - (cns->g->ksize / 2 * 2)); xmask[0] = (~xmask[1]) & cns->g->kmask; b = 4; brun = 0; clear_u1v(cns->g->zseq); chg = 0; for(i=0;ig->ksize;i++) push_u1v(cns->g->zseq, cns->cns->buffer[i]); for(;i+cns->g->ksizecns->size;i++){ if(cns->cns->buffer[i] == b){ brun ++; } else { if(brun >= 3 && brun + 2 <= cns->g->ksize){ if(DBGCNS_DEBUG){ fprintf(stderr, "POLY %c(%d) at pos %d\n", "ACGT"[b], brun, i); } r = i - brun; c = (cns->g->ksize - brun) / 2; l = r - c; kmer = 0; for(j=l;jcns->buffer[j]; for(j=1;jg->ksize - brun - c) + 1; for(j=l;jcns->buffer[j]; cns->g->kmers->buffer[0].mer = kmer; u = get_dbgcnskmerhash(cns->g->khash, 0); kcnts[0] = u? ref_dbgcnskmerv(cns->g->kmers, *u)->cov : 0; if(DBGCNS_DEBUG){ kmer2seq(kstr, kmer, cns->g->ksize); fprintf(stderr, "%s\t%d\n", kstr, kcnts[0]); } kmer = (kmer & xmask[0]) | (((u8i)b) << (cns->g->ksize / 2 * 2 - 2)) | ((kmer & xmask[1]) >> 2); cns->g->kmers->buffer[0].mer = kmer; u = get_dbgcnskmerhash(cns->g->khash, 0); kcnts[1] = u? ref_dbgcnskmerv(cns->g->kmers, *u)->cov : 0; if(DBGCNS_DEBUG){ kmer2seq(kstr, kmer, cns->g->ksize); fprintf(stderr, "%s\t%d\n", kstr, kcnts[1]); } kmer = (kmer & xmask[0]) | (((u8i)b) << (cns->g->ksize / 2 * 2 - 2)) | ((kmer & xmask[1]) >> 2); cns->g->kmers->buffer[0].mer = kmer; u = get_dbgcnskmerhash(cns->g->khash, 0); kcnts[2] = u? ref_dbgcnskmerv(cns->g->kmers, *u)->cov : 0; if(DBGCNS_DEBUG){ kmer2seq(kstr, kmer, cns->g->ksize); fprintf(stderr, "%s\t%d\n", kstr, kcnts[2]); } if(kcnts[0] > kcnts[1] && kcnts[1] >= kcnts[2]){ // there is a insertion base brun --; chg ++; if(DBGCNS_DEBUG){ fprintf(stderr, "#HOMO ins\n"); } } else if(kcnts[2] > kcnts[1] && kcnts[1] >= kcnts[0]){ // deletion brun ++; chg ++; if(DBGCNS_DEBUG){ fprintf(stderr, "#HOMO del\n"); } } } for(j=0;jg->zseq, b); b = cns->cns->buffer[i]; brun = 1; } } for(j=0;jg->zseq, b); for(;icns->size;i++) push_u1v(cns->g->zseq, cns->cns->buffer[i]); if(chg){ clear_u1v(cns->cns); append_u1v(cns->cns, cns->g->zseq); clear_string(cns->seq); encap_string(cns->seq, cns->g->zseq->size); for(i=0;ig->zseq->size;i++){ cns->seq->string[i] = bit_base_table[cns->g->zseq->buffer[i]]; } cns->seq->size = i; cns->seq->string[i] = '\0'; } return chg; } static inline int run_cns(CNS *cns, int candidate_mode, int corr_struct){ u4i i; if(cns->qblks->size == 0) return 0; cns->qidx = 0; if(candidate_mode == 4){ // longest for(i=0;iqblks->size;i++){ if(cns->qblks->buffer[i].solid == 0) continue; if(cns->qblks->buffer[i].len > cns->qblks->buffer[cns->qidx].len) cns->qidx = i; } } else if(candidate_mode == 5){ // shortest for(i=0;iqblks->size;i++){ if(cns->qblks->buffer[i].solid == 0) continue; if(cns->qblks->buffer[i].len < cns->qblks->buffer[cns->qidx].len) cns->qidx = i; } } else if(candidate_mode == 3){ // first and but not increase coverage cns->qidx = 0; } else if(candidate_mode == 0){ // kmer coverage cns->qidx = 0; } else if(candidate_mode == 2){ // first and include cns->qidx = 0; } else if(candidate_mode < 0){ cns->qidx = num_min(-1 - candidate_mode, (int)(cns->qblks->size - 1)); } else if(candidate_mode == 1){ // median u2v *idxs; idxs = init_u2v(cns->qblks->size); for(i=0;iqblks->size;i++){ if(cns->qblks->buffer[i].solid == 0) continue; push_u2v(idxs, i); } cns->qidx = quick_median_array(idxs->buffer, idxs->size, u2i, num_cmpgt(cns->qblks->buffer[a].len, cns->qblks->buffer[b].len)); } else { fprintf(stderr, " -- Unknown candidate mode %d in %s -- %s:%d --\n", candidate_mode, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); } ready_core_cns(cns, candidate_mode, cns->qblks->buffer[cns->qidx].len); if(candidate_mode == 0){ double max, cov; max = - 1000000; for(i=0;ig->kmers->size;i++) cns->g->kmers->buffer[i].visit = 0; for(i=cns->qblks->size;i>0;i--){ if(cns->qblks->buffer[i - 1].solid == 0) continue; cov = kmer_cov_seq_dbg(cns->g, cns->qseqs->buffer + cns->qblks->buffer[i - 1].off, cns->qblks->buffer[i - 1].len, (i - 1 + 1) % 255) * 1.0 / cns->qblks->buffer[i - 1].len; if(cov > max){ max = cov; cns->qidx = i - 1; } } // revise cns->avg_cov cns->avg_cov = cns->avg_cov * cns->qblks->buffer[0].len / cns->qblks->buffer[cns->qidx].len; } if(corr_struct){ build_DirectFuzzyBruijnGraph(cns, cns->qidx, 5, 0.2); //build_DirectFuzzyBruijnGraph(cns, cns->qidx, 0, 0.2); DP_best_path_DirectFuzzyBruijnGraph(cns); correct_struct_DirectFuzzyBruijnGraph(cns, cns->qidx); if(DBGCNS_DEBUG){ FILE *dotf = open_file_for_write("debug.dot", NULL, 1); print_dot_DirectFuzzyBruijnGraph(cns, dotf); fclose(dotf); } run_core_cns(cns, cns->fbg->starseq->buffer, cns->fbg->starseq->size); } else { run_core_cns(cns, cns->qseqs->buffer + cns->qblks->buffer[cns->qidx].off, cns->qblks->buffer[cns->qidx].len); } homopolymer_analysis_cns(cns); return cns->seq->size; } #endif wtdbg2-2.5/dna.h000066400000000000000000001151521353664372200135040ustar00rootroot00000000000000/* * * Copyright (c) 2011, Jue Ruan * * * 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 3 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, see . */ #ifndef __DNA_RJ_H #define __DNA_RJ_H #include #include #include #include #include "list.h" #include "bitvec.h" #include "hashset.h" #include "thread.h" static const u1i base_bit_table[256] = { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 1, 4, 4, 4, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 1, 4, 4, 4, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }; static const u1i base_bit4_table[256] = { 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 1, 14, 2, 13, 15, 15, 4, 11, 15, 15, 12, 15, 3, 15, 15, 15, 15, 5, 6, 8, 15, 7, 9, 15, 10, 15, 15, 15, 15, 15, 15, 15, 1, 14, 2, 13, 15, 15, 4, 11, 15, 15, 12, 15, 3, 15, 15, 15, 15, 5, 6, 8, 15, 7, 9, 15, 10, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 }; static const u1i bit4_bit_table[16] = { 4, 0, 1, 4, 2, 4, 4, 4, 3, 4, 4, 4, 4, 4, 4, 4 }; static const char bit_base_table[12] = "ACGTN-acgtn*"; static const char bit4_base_table[16] = "-ACMGRSVTWYHKDBN"; // u8i = 0|1|2|3|4|5|6|... #define bits2bit(bits, off) (((bits)[(off) >> 5] >> (((~(off)) & 0x1FU) << 1)) & 0x03U) #define bits2revbit(bits, off) ((~((bits)[(off) >> 5] >> (((~(off)) & 0x1FU) << 1))) & 0x03U) static inline u8i dna_xor2ones(u8i seq){ return ((seq & 0xAAAAAAAAAAAAAAAALLU) >> 1) | (seq & 0x5555555555555555LLU); } static inline u8i dna_rev_seq32(u8i seq){ seq = ~seq; seq = ((seq & 0x3333333333333333LLU)<< 2) | ((seq & 0xCCCCCCCCCCCCCCCCLLU)>> 2); seq = ((seq & 0x0F0F0F0F0F0F0F0FLLU)<< 4) | ((seq & 0xF0F0F0F0F0F0F0F0LLU)>> 4); #if 0 seq = ((seq & 0x00FF00FF00FF00FFLLU)<< 8) | ((seq & 0xFF00FF00FF00FF00LLU)>> 8); seq = ((seq & 0x0000FFFF0000FFFFLLU)<<16) | ((seq & 0xFFFF0000FFFF0000LLU)>>16); seq = ((seq & 0x00000000FFFFFFFFLLU)<<32) | ((seq & 0xFFFFFFFF00000000LLU)>>32); #else seq = __builtin_bswap64(seq); #endif return seq; } static inline u8i dna_rev_seq(u8i seq, u1i seq_size){ return dna_rev_seq32(seq) >> (64 - (seq_size<<1)); } // order of 2-bit in this->seqs is different with that in dna_rev_seq->seq static inline void dna_rev_seqs(u8i *seqs, u8i seq_size){ register u8i t; int i, j; register u1i d, e; j = (seq_size + 31) >> 5; // Swap within 64bit for(i=0;i> 2); seqs[i] = ((seqs[i] & 0x0F0F0F0F0F0F0F0FLLU)<< 4) | ((seqs[i] & 0xF0F0F0F0F0F0F0F0LLU)>> 4); seqs[i] = __builtin_bswap64(seqs[i]); } // Swap 64bit blocks for(i=0;i>1;i++){ t = seqs[i]; seqs[i] = seqs[j - i - 1]; seqs[j - i - 1] = t; } // left-align seqs if((d = ((j << 5) - seq_size) << 1)){ e = 64 - d; for(i=0;i> e); } seqs[i] = (seqs[i] << d) | 0; } } //shift one base, and append one base, useful to build big-kmer static inline void dna_shl_seqs(u8i *seqs, u8i seq_size, u1i base_val){ const u1i d = 2; const u1i e = 62; int i, j; j = (seq_size + 31) >> 5; for(i=0;i> e); } seqs[i] = (seqs[i] << d) | (((u8i)(base_val & 0x03U)) << ((32 - (seq_size & 0x1FU)) << 1)); } static inline int dna_cmp_seqs(u8i *seqs1, u8i *seqs2, u8i seq_size){ int i, j; j = (seq_size + 31) >> 5; for(i=0;i seqs2[i]) return 1; } return 0; } static inline int dna_cmpx_seqs(u8i *seqs, u8i seq_size){ register int i, j; register u1i a, b; j = (seq_size + 1) >> 1; for(i=0;i b) return 1; } return 0; } static inline u8i seq2kmer(char *seq, u4i ksize){ u8i kmer; u4i i; kmer = 0; for(i=0;i> ((ksize - 1 - i) << 1)) & 0x03]; } seq[i] = 0; } static inline void kmer2revseq(char *seq, u8i kmer, u4i ksize){ u4i i; kmer = ~kmer; for(i=0;i> (i << 1)) & 0x03]; } seq[i] = 0; } static inline void print_kmer_seq(u8i kmer, u4i ksize, FILE *out){ char seq[33]; kmer2seq(seq, kmer, ksize); fputs(seq, out); } static inline void print_kmer_revseq(u8i kmer, u4i ksize, FILE *out){ char seq[33]; kmer2revseq(seq, kmer, ksize); fputs(seq, out); } #define kmer_mask(ksize) (0xFFFFFFFFFFFFFFFFLLU >> ((32 - (ksize)) * 2)) #define beg_seq2kmers(seq, seqlen, ksize, kmask, kmer, idx) { \ u1i beg_seq2kmers_v; \ kmer = 0; \ for(idx=0;(int)idx+1<(int)ksize;idx++){ \ beg_seq2kmers_v = base_bit_table[(int)(seq)[idx]]; \ if(beg_seq2kmers_v == 4) beg_seq2kmers_v = lrand48() & 0x03; \ kmer = (((kmer) << 2) | beg_seq2kmers_v); \ } \ for(idx=0;(int)idx<=(int)(seqlen-ksize);idx++){ \ beg_seq2kmers_v = base_bit_table[(int)(seq)[idx + (ksize) - 1]]; \ if(beg_seq2kmers_v == 4) beg_seq2kmers_v = lrand48() & 0x03; \ kmer = ((kmer << 2) | beg_seq2kmers_v) & kmask; #define end_seq2kmers } } #define beg_seq2revkmers(seq, seqlen, ksize, kmask, kmer, idx) { \ u1i beg_seq2revkmers_v; \ kmer = 0; \ for(idx=0;(int)idx+1<(int)ksize;idx++){ \ beg_seq2revkmers_v = base_bit_table[(int)(seq)[seqlen - 1 - idx]]; \ if(beg_seq2revkmers_v == 4) beg_seq2revkmers_v = lrand48() & 0x03; \ kmer = (((kmer) << 2) | beg_seq2revkmers_v); \ } \ for(idx=0;(int)idx<=(int)seqlen-ksize;idx++){ \ beg_seq2revkmers_v = base_bit_table[(int)(seq)[seqlen - idx - (ksize)]]; \ if(beg_seq2revkmers_v == 4) beg_seq2revkmers_v = lrand48() & 0x03; \ kmer = ((kmer << 2) | beg_seq2revkmers_v) & kmask; #define end_seq2revkmers } } static inline char reverse_dna_base(char b){ switch(b){ case 'a': return 't'; case 'A': return 'T'; case 'c': return 'g'; case 'C': return 'G'; case 'g': return 'c'; case 'G': return 'C'; case 't': return 'a'; case 'T': return 'A'; default: return 'N'; } } static inline void reverse_dna(char *seq, int len){ int i, j; char c; i = 0; j = len - 1; while(i < j){ c = seq[i]; seq[i] = seq[j]; seq[j] = c; i ++; j --; } for(i=0;i> 5] = 0; (bits)[(off) >> 5] |= ((u8i)(bit)) << (((~(off)) & 0x1FU) << 1); } #define bit2bits(bits, off, bit) { \ u8i __off1; \ u4i __off2; \ __off1 = (off) >> 5; \ __off2 = (((~(off)) & 0x1FU) << 1); \ (bits)[__off1] = ((bits)[__off1] & (~(0x3LLU << __off2))) | (((u8i)(bit)) << __off2); \ } static inline void seq2bits(u8i *bits, u8i bitoff, char *seq, u4i seqlen){ u8i i, c; for(i=0;i>5] >> (((~(off + i)) & 0x1FU) << 1)) & 0x03; seq[len - i - 1] = bit_base_table[(~c)&0x03]; } seq[i] = 0; } static inline u8i sub32seqbits(u8i *src, u8i off){ u8i m; u4i n; m = off >> 5; n = (off & 0x1F) << 1; return (src[m] << n) | (((src[m + 1] >> (62 - n)) >> 2)); //n = off & 0x1F; //if(n){ //return (src[m] << (n << 1)) | (src[m + 1] >> ((32 - n) << 1)); //} else { //return src[m]; //} } static inline u8i sub8seqbits(u8i *src, u8i off){ u8i off1; u4i off2; off1 = off >> 5; off2 = (off & 0x1FU) << 1; return ((src[off1] << off2) | (((src[off1 + 1] >> (62 - off2)) >> 2))) >> 48; } static inline u8i sub4seqbits(u8i *src, u8i off){ u8i off1; u4i off2; off1 = off >> 5; off2 = (off & 0x1FU) << 1; return ((src[off1] << off2) | (((src[off1 + 1] >> (62 - off2)) >> 2))) >> 56; } static inline u8i sub2seqbits(u8i *src, u8i off){ u8i off1; u4i off2; off1 = off >> 5; off2 = (off & 0x1FU) << 1; return ((src[off1] << off2) | (((src[off1 + 1] >> (62 - off2)) >> 2))) >> 60; } static inline u8i sub_seqbits(u8i *src, u8i off, u1i len){ u8i off1; u4i off2; off1 = off >> 5; off2 = (off & 0x1FU) << 1; return ((src[off1] << off2) | (((src[off1 + 1] >> (62 - off2)) >> 2))) >> ((32 - len) << 1); } #define subseqbits(src, off, len) sub_seqbits(src, off, len) static inline int cmpgt_seqbits(u8i *bits, u8i off1, u8i off2, u4i _len){ u8i idxs[2], v[2]; u4i offs[2], i, len; idxs[0] = off1 >> 5; idxs[1] = off2 >> 5; offs[0] = (off1 & 0x1FU) << 1; offs[1] = (off2 & 0x1FU) << 1; len = roundup_times(_len, 32); for(i=0;i> (62 - offs[0])) >> 2)); v[1] = (bits[idxs[1]] << offs[1]) | (((bits[idxs[1] + 1] >> (62 - offs[1])) >> 2)); if(v[0] > v[1]){ return 1; } else if(v[0] < v[1]){ return 0; } idxs[0] ++; idxs[1] ++; } return 0; } #if __BYTE_ORDER == 1234 static const u4i spare_2bits_table[256] = { 0, 16777216, 33554432, 50331648, 65536, 16842752, 33619968, 50397184, 131072, 16908288, 33685504, 50462720, 196608, 16973824, 33751040, 50528256, 256, 16777472, 33554688, 50331904, 65792, 16843008, 33620224, 50397440, 131328, 16908544, 33685760, 50462976, 196864, 16974080, 33751296, 50528512, 512, 16777728, 33554944, 50332160, 66048, 16843264, 33620480, 50397696, 131584, 16908800, 33686016, 50463232, 197120, 16974336, 33751552, 50528768, 768, 16777984, 33555200, 50332416, 66304, 16843520, 33620736, 50397952, 131840, 16909056, 33686272, 50463488, 197376, 16974592, 33751808, 50529024, 1, 16777217, 33554433, 50331649, 65537, 16842753, 33619969, 50397185, 131073, 16908289, 33685505, 50462721, 196609, 16973825, 33751041, 50528257, 257, 16777473, 33554689, 50331905, 65793, 16843009, 33620225, 50397441, 131329, 16908545, 33685761, 50462977, 196865, 16974081, 33751297, 50528513, 513, 16777729, 33554945, 50332161, 66049, 16843265, 33620481, 50397697, 131585, 16908801, 33686017, 50463233, 197121, 16974337, 33751553, 50528769, 769, 16777985, 33555201, 50332417, 66305, 16843521, 33620737, 50397953, 131841, 16909057, 33686273, 50463489, 197377, 16974593, 33751809, 50529025, 2, 16777218, 33554434, 50331650, 65538, 16842754, 33619970, 50397186, 131074, 16908290, 33685506, 50462722, 196610, 16973826, 33751042, 50528258, 258, 16777474, 33554690, 50331906, 65794, 16843010, 33620226, 50397442, 131330, 16908546, 33685762, 50462978, 196866, 16974082, 33751298, 50528514, 514, 16777730, 33554946, 50332162, 66050, 16843266, 33620482, 50397698, 131586, 16908802, 33686018, 50463234, 197122, 16974338, 33751554, 50528770, 770, 16777986, 33555202, 50332418, 66306, 16843522, 33620738, 50397954, 131842, 16909058, 33686274, 50463490, 197378, 16974594, 33751810, 50529026, 3, 16777219, 33554435, 50331651, 65539, 16842755, 33619971, 50397187, 131075, 16908291, 33685507, 50462723, 196611, 16973827, 33751043, 50528259, 259, 16777475, 33554691, 50331907, 65795, 16843011, 33620227, 50397443, 131331, 16908547, 33685763, 50462979, 196867, 16974083, 33751299, 50528515, 515, 16777731, 33554947, 50332163, 66051, 16843267, 33620483, 50397699, 131587, 16908803, 33686019, 50463235, 197123, 16974339, 33751555, 50528771, 771, 16777987, 33555203, 50332419, 66307, 16843523, 33620739, 50397955, 131843, 16909059, 33686275, 50463491, 197379, 16974595, 33751811, 50529027 }; #else static const u4i spare_2bits_table[256] = { 0, 1, 2, 3, 256, 257, 258, 259, 512, 513, 514, 515, 768, 769, 770, 771, 65536, 65537, 65538, 65539, 65792, 65793, 65794, 65795, 66048, 66049, 66050, 66051, 66304, 66305, 66306, 66307, 131072, 131073, 131074, 131075, 131328, 131329, 131330, 131331, 131584, 131585, 131586, 131587, 131840, 131841, 131842, 131843, 196608, 196609, 196610, 196611, 196864, 196865, 196866, 196867, 197120, 197121, 197122, 197123, 197376, 197377, 197378, 197379, 16777216, 16777217, 16777218, 16777219, 16777472, 16777473, 16777474, 16777475, 16777728, 16777729, 16777730, 16777731, 16777984, 16777985, 16777986, 16777987, 16842752, 16842753, 16842754, 16842755, 16843008, 16843009, 16843010, 16843011, 16843264, 16843265, 16843266, 16843267, 16843520, 16843521, 16843522, 16843523, 16908288, 16908289, 16908290, 16908291, 16908544, 16908545, 16908546, 16908547, 16908800, 16908801, 16908802, 16908803, 16909056, 16909057, 16909058, 16909059, 16973824, 16973825, 16973826, 16973827, 16974080, 16974081, 16974082, 16974083, 16974336, 16974337, 16974338, 16974339, 16974592, 16974593, 16974594, 16974595, 33554432, 33554433, 33554434, 33554435, 33554688, 33554689, 33554690, 33554691, 33554944, 33554945, 33554946, 33554947, 33555200, 33555201, 33555202, 33555203, 33619968, 33619969, 33619970, 33619971, 33620224, 33620225, 33620226, 33620227, 33620480, 33620481, 33620482, 33620483, 33620736, 33620737, 33620738, 33620739, 33685504, 33685505, 33685506, 33685507, 33685760, 33685761, 33685762, 33685763, 33686016, 33686017, 33686018, 33686019, 33686272, 33686273, 33686274, 33686275, 33751040, 33751041, 33751042, 33751043, 33751296, 33751297, 33751298, 33751299, 33751552, 33751553, 33751554, 33751555, 33751808, 33751809, 33751810, 33751811, 50331648, 50331649, 50331650, 50331651, 50331904, 50331905, 50331906, 50331907, 50332160, 50332161, 50332162, 50332163, 50332416, 50332417, 50332418, 50332419, 50397184, 50397185, 50397186, 50397187, 50397440, 50397441, 50397442, 50397443, 50397696, 50397697, 50397698, 50397699, 50397952, 50397953, 50397954, 50397955, 50462720, 50462721, 50462722, 50462723, 50462976, 50462977, 50462978, 50462979, 50463232, 50463233, 50463234, 50463235, 50463488, 50463489, 50463490, 50463491, 50528256, 50528257, 50528258, 50528259, 50528512, 50528513, 50528514, 50528515, 50528768, 50528769, 50528770, 50528771, 50529024, 50529025, 50529026, 50529027 }; #endif static inline void spare_2bits(u1i bs[32], u8i v){ ((u4i*)bs)[0] = spare_2bits_table[((v >> 56) & 0xFF)]; ((u4i*)bs)[1] = spare_2bits_table[((v >> 48) & 0xFF)]; ((u4i*)bs)[2] = spare_2bits_table[((v >> 40) & 0xFF)]; ((u4i*)bs)[3] = spare_2bits_table[((v >> 32) & 0xFF)]; ((u4i*)bs)[4] = spare_2bits_table[((v >> 24) & 0xFF)]; ((u4i*)bs)[5] = spare_2bits_table[((v >> 16) & 0xFF)]; ((u4i*)bs)[6] = spare_2bits_table[((v >> 8) & 0xFF)]; ((u4i*)bs)[7] = spare_2bits_table[((v >> 0) & 0xFF)]; } typedef struct { u8i *bits; u8i size; u8i cap; } BaseBank; static inline size_t basebank_obj_desc_cnt(void *obj, int idx){ return ((((BaseBank*)obj)->size + 31) / 32 + 1) * 8; idx = idx; } static inline void basebank_obj_desc_post_load(void *obj, size_t aux_data){ BaseBank *bnk; UNUSED(aux_data); bnk = (BaseBank*)obj; bnk->cap = ((bnk->size + 31) / 32) * 32; } static const obj_desc_t basebank_obj_desc = {"BaseBank", sizeof(BaseBank), 1, {1}, {offsetof(BaseBank, bits)}, {(obj_desc_t*)&OBJ_DESC_DATA}, basebank_obj_desc_cnt, basebank_obj_desc_post_load}; static inline BaseBank* init_basebank(){ BaseBank *bnk; bnk = malloc(sizeof(BaseBank)); bnk->size = 0; bnk->cap = 256; bnk->bits = calloc(bnk->cap / 32 + 1, 8); return bnk; } static inline void free_basebank(BaseBank *bnk){ free(bnk->bits); free(bnk); } static inline void encap_basebank(BaseBank *bnk, u8i inc){ u8i old; u8i *bits; if(bnk->cap - bnk->size >= inc) return; old = bnk->cap; if(MAX_U8 - inc <= bnk->size){ fprintf(stderr, " -- Overflow(64bits) %llu + %llu, in %s -- %s:%d --\n", (u8i)bnk->size, (u8i)inc, __FUNCTION__, __FILE__, __LINE__); print_backtrace(stderr, 20); abort(); } if(MAX_U8 - inc < 0x3FFFFFFFLLU){ fprintf(stderr, " -- Overflow(64bits) %llu + %llu, in %s -- %s:%d --\n", (u8i)bnk->size, (u8i)inc, __FUNCTION__, __FILE__, __LINE__); print_backtrace(stderr, 20); abort(); } if(bnk->size + inc <= 0x3FFFFFFFLLU){ bnk->cap = roundup_times(2 * (bnk->size + inc), 32); } else { //bnk->cap = ((bnk->size + inc + 0xFFFFFFFLLU - 1LLU) / 0xFFFFFFFLLU) * 0xFFFFFFFLLU; bnk->cap = (bnk->size + inc + 0x3FFFFFFFLLU) & (MAX_U8 << 30); } if(bnk->cap < 32) bnk->cap = 32; bits = realloc(bnk->bits, ((bnk->cap >> 5) + 1) << 3); if(bits == NULL){ fprintf(stderr, " -- Out of memory, try to allocate %llu bytes, old size %llu, in %s -- %s:%d --\n", (u8i)bnk->cap >> 2, old >> 2, __FUNCTION__, __FILE__, __LINE__); print_backtrace(stderr, 20); abort(); } bnk->bits = bits; memset(bnk->bits + (old / 32), 0, (bnk->cap + 32 - old) / 4); } static inline void clear_basebank(BaseBank *bnk){ //memset(bnk->bits, 0, ((bnk->size + 31) / 32) * 8); bnk->size = 0; } static inline void normalize_basebank(BaseBank *bnk){ if(bnk->size < bnk->cap){ if(bnk->size & 0x1FU){ bnk->bits[bnk->size>>5] = bnk->bits[bnk->size>>5] & (MAX_U8 << (64 - ((bnk->size & 0x1FU) << 1))); } } } static inline void pack_basebank(BaseBank *bnk){ u8i size; size = (bnk->size + 31) & (~0x1FLLU); if(size == 0) size = 32; if(size >= bnk->cap) return; bnk->cap = ((size + 31) / 32) * 32; bnk->bits = realloc(bnk->bits, ((bnk->cap >> 5) + 1) << 3); memset(bnk->bits + (bnk->cap >> 5), 0, 8); } static inline void bit2basebank(BaseBank *bnk, u1i v){ encap_basebank(bnk, 1); bit2bits(bnk->bits, bnk->size, (v & 0x03)); bnk->size ++; } static inline void bits2basebank(BaseBank *bnk, u8i *bits, u8i off, u8i len){ u8i offset; encap_basebank(bnk, len); for(offset=off;offsetbits, bnk->size, bits2bit(bits, offset)); bnk->size ++; } } #define fwdbits2basebank(bnk, bits, off, len) bits2basebank(bnk, bits, off, len) static inline void fast_bits2basebank(BaseBank *bnk, u8i *bits, u8i off, u8i len){ u8i end, dat; u4i gap; encap_basebank(bnk, len); if(len == 0) return; if(bnk->size & 0x1FU){ gap = 32 - (bnk->size & 0x1FU); if(len <= gap){ dat = subseqbits(bits, off, len); bnk->bits[bnk->size >> 5] |= dat << ((gap - len) << 1); bnk->size += len; return; } else { dat = subseqbits(bits, off, gap); bnk->bits[bnk->size >> 5] |= dat; bnk->size += gap; off += gap; len -= gap; } } end = off + len; for(;off+32<=end;off+=32){ dat = sub32seqbits(bits, off); bnk->bits[bnk->size >> 5] = dat; bnk->size += 32; } if(off < end){ dat = sub32seqbits(bits, off); bnk->bits[bnk->size >> 5] = dat & (MAX_U8 << ((32 - (end - off)) << 1)); bnk->size += end - off; } else { bnk->bits[bnk->size >> 5] = 0; } } #define fast_fwdbits2basebank(bnk, bits, off, len) fast_bits2basebank(bnk, bits, off, len) static inline void revbits2basebank(BaseBank *bnk, u8i *bits, u8i off, u8i len){ u8i i; encap_basebank(bnk, len); for(i=1;i<=len;i++){ bit2bits(bnk->bits, bnk->size, bits2revbit(bits, (off + len - i))); bnk->size ++; } } static inline void fast_revbits2basebank(BaseBank *bnk, u8i *bits, u8i off, u8i len){ u8i end, dat; u4i gap; if(len == 0) return; encap_basebank(bnk, len); if(bnk->size & 0x1FU){ gap = 32 - (bnk->size & 0x1FU); if(len <= gap){ dat = subseqbits(bits, off, len); dat = dna_rev_seq(dat, len); bnk->bits[bnk->size >> 5] |= dat << ((gap - len) << 1); bnk->size += len; return; } else { dat = subseqbits(bits, off + len - gap, gap); dat = dna_rev_seq(dat, gap); bnk->bits[bnk->size >> 5] |= dat; bnk->size += gap; //off += gap; len -= gap; } } end = off + len; for(;off+32<=end;){ end -= 32; dat = sub32seqbits(bits, end); dat = dna_rev_seq32(dat); bnk->bits[bnk->size >> 5] = dat; bnk->size += 32; } if(off < end){ dat = sub32seqbits(bits, off); dat = dna_rev_seq32(dat); //bnk->bits[bnk->size >> 5] = dat & (MAX_U8 << ((32 - (end - off)) << 1)); bnk->bits[bnk->size >> 5] = dat << ((32 - (end - off)) << 1); bnk->size += end - off; } else { bnk->bits[bnk->size >> 5] = 0; } } static inline void seq2basebank(BaseBank *bnk, char *seq, u8i len){ u8i idx1, i, c; u1i idx2; encap_basebank(bnk, len); idx1 = bnk->size >> 5; idx2 = ((bnk->size) & 0x1FU) << 1; bnk->size += len; if(idx2 == 0) bnk->bits[idx1] = 0; for(i=0;ibits[idx1] |= c << (62 - idx2); idx2 = (idx2 + 2) & 0x3F; if(idx2 == 0){ bnk->bits[++idx1] = 0; } } } #define fwdseq2basebank(bnk, seq, len) seq2basebank(bnk, seq, len) static inline void revseq2basebank(BaseBank *bnk, char *seq, u8i len){ char *p; u1i c; p = seq + len; encap_basebank(bnk, len); while(p > seq){ p --; c = base_bit_table[(int)*p]; c = (~c) & 0x03; bit2bits(bnk->bits, bnk->size, c); bnk->size ++; } } static inline void seq2basebank2(BaseBank *bnk, char *seq, u8i len){ char *p; u1i c; p = seq; seq = seq + len; encap_basebank(bnk, len); while(p < seq){ c = base_bit_table[(int)*p]; if(c == 4) c = lrand48() & 0x03; bit2bits(bnk->bits, bnk->size, c); bnk->size ++; p ++; } } static inline void revseq2basebank2(BaseBank *bnk, char *seq, u8i len){ char *p; u1i c; p = seq + len; encap_basebank(bnk, len); while(p > seq){ p --; c = base_bit_table[(int)*p]; if(c == 4) c = lrand48() & 0x03; c = (~c) & 0x03; bit2bits(bnk->bits, bnk->size, c); bnk->size ++; } } static inline u1i get_basebank(BaseBank *bnk, u8i off){ return bits2bit(bnk->bits, off); } static inline void seq_basebank(BaseBank *bnk, u8i off, u8i len, char *seq){ u8i i; for(i=0;ibits, off + i)]; } seq[i] = 0; } #define fwdseq_basebank(bnk, off, len, seq) seq_basebank(bnk, off, len, seq) static inline void bitseq_basebank(BaseBank *bnk, u8i off, u8i len, u1i *seq){ u8i i; for(i=0;ibits, off + i); } } static inline void revseq_basebank(BaseBank *bnk, u8i off, u8i len, char *seq){ u8i i; for(i=0;ibits, off + len - 1 - i)) & 0x03]; } seq[i] = 0; } static inline void revbitseq_basebank(BaseBank *bnk, u8i off, u8i len, u1i *seq){ u8i i; for(i=0;ibits, off + len - 1 - i)) & 0x03; } } static inline void reverse_basebank(BaseBank *bnk){ u8i size, rsize; size = bnk->size; rsize = (bnk->size + 31) & (~0x1FLLU); encap_basebank(bnk, rsize + 32); memcpy(bnk->bits + (rsize >> 5), bnk->bits + 0, (rsize >> 5) << 3); bnk->size = 0; fast_revbits2basebank(bnk, bnk->bits, rsize, size); } static inline void print_seq_basebank(BaseBank *bnk, u8i off, u8i len, FILE *out){ u8i i, b, e; char buf[101]; for(b=off;bbits, i)]; } buf[e - b] = '\0'; fputs(buf, out); //fputc('\n', out); b = e; } } static inline void print_lines_basebank(BaseBank *bnk, u8i off, u8i len, FILE *out, int linewidth){ u8i i, b, e; char *buf; if(linewidth < 1) linewidth = 100; buf = malloc(linewidth + 1); for(b=off;bbits, i)]; } buf[e - b] = '\0'; fputs(buf, out); fputc('\n', out); b = e; } free(buf); } #define print_fwdseq_basebank(bnk, off, len, out) print_seq_basebank(bnk, off, len, out) static inline void println_seq_basebank(BaseBank *bnk, u8i off, u8i len, FILE *out){ print_seq_basebank(bnk, off, len, out); fputc('\n', out); } #define println_fwdseq_basebank(bnk, off, len, out) println_seq_basebank(bnk, off, len, out) static inline void print_revseq_basebank(BaseBank *bnk, u8i off, u8i len, FILE *out){ u8i i; char buf[65]; buf[64] = '\0'; for(i=0;ibits, off + len - 1 - i)]; i ++; if((i & 0x3F) == 0){ fprintf(out, "%s", buf); } } if(i & 0x3F){ buf[i & 0x3F] = '\0'; fprintf(out, "%s", buf); } } static inline u8i sub32_basebank(BaseBank *bnk, u8i off){ return sub32seqbits(bnk->bits, off); } static inline u8i sub4_basebank(BaseBank *bnk, u8i off){ return sub4seqbits(bnk->bits, off); } // assert(len > 0 && len <= 32) static inline u8i subbits_basebank(BaseBank *bnk, u8i off, u1i len){ return sub_seqbits(bnk->bits, off, len); } static inline void println_revseq_basebank(BaseBank *bnk, u8i off, u8i len, FILE *out){ print_revseq_basebank(bnk, off, len, out); fputc('\n', out); } static inline u8i hzsubbits_basebank(BaseBank *bnk, u8i off, u1i len){ u8i k; u1i i, b, c; k = 0; b = 4; for(i=0;ibits, off); if(c == b) continue; i ++; b = c; k = (k << 2) | b; } return k; } static inline int bitsearch_basebank(BaseBank *bnk, u8i *_off, u8i len, u8i bits, u1i size, int max_occ){ u8i off, end, k, mask; u1i b; int ret; off = *_off; end = off + len; mask = MAX_U8 >> ((32 - size) << 1); k = subbits_basebank(bnk, off, size - 1); off += size - 1; ret = 0; for(;offbits, off); k = ((k << 2) | b) & mask; if(k == bits){ _off[ret++] = off - (size - 1); if(ret >= max_occ) break; } } return ret; } static inline int hzbitsearch_basebank(BaseBank *bnk, u8i *_off, u8i len, u8i bits, u1i size, int max_occ){ u8i off, h, end, k, mask; u1i b, c; int ret; off = *_off; end = off + len; mask = MAX_U8 >> ((32 - size) << 1); k = 0; h = 0; b = 4; ret = 0; for(;offbits, off); if(c == b) continue; b = c; h ++; k = ((k << 2) | b) & mask; if(h >= size && k == bits){ _off[ret++] = off - (size - 1); if(ret >= max_occ) break; } } return ret; } static inline u4i mismatch_basebank(BaseBank *bnk, u8i off1, u8i off2, u4i len){ u8i seq1, seq2; u4i mm, i; mm = 0; for(i=0;i+32<=len;i+=32){ seq1 = sub32seqbits(bnk->bits, off1 + i); seq2 = sub32seqbits(bnk->bits, off2 + i); mm += count_ones_bit64(dna_xor2ones(seq1 ^ seq2)); } if(i < len){ seq1 = sub32seqbits(bnk->bits, off1 + i); seq2 = sub32seqbits(bnk->bits, off2 + i); mm += count_ones_bit64((dna_xor2ones(seq1 ^ seq2)) >> ((32 - (len - i)) << 1)); } return mm; } thread_beg_def(_mradix); BaseBank *bb; u4i *counts[2]; u4i *offs; u1v *lcps; u4i size, klen; int task; FILE *log; thread_end_def(_mradix); thread_beg_func(_mradix); BaseBank *bb; u4i *offs, *counts[2]; u4i i, j, size, klen, m, n, v, t; u4i ncpu, tidx; bb = _mradix->bb; counts[0] = calloc((MAX_U2 + 1), sizeof(u4i)); // used in twice counts[1] = calloc((MAX_U2 + 1), sizeof(u4i)); ncpu = _mradix->n_cpu; tidx = _mradix->t_idx; thread_beg_loop(_mradix); if(_mradix->task == 1){ size = _mradix->size; for(i=_mradix->t_idx;in_cpu){ v = sub8seqbits(bb->bits, i); counts[1][v] ++; } _mradix->counts[0] = counts[0]; _mradix->counts[1] = counts[1]; } else if(_mradix->task == 11){ offs = _mradix->offs; size = _mradix->size; for(i=0;ibits, i); if((v % _mradix->n_cpu) == (u4i)_mradix->t_idx){ offs[_mradix->counts[0][v]++] = i; } if(_mradix->t_idx == 0 && _mradix->log && (i % 1000000) == 0){ fprintf(_mradix->log, "\r%u", i); fflush(_mradix->log); } } if(_mradix->t_idx == 0 && _mradix->log){ fprintf(_mradix->log, "\r%u\n", size); } } else if(_mradix->task == 2) { offs = _mradix->offs; size = _mradix->size; klen = _mradix->klen - 8; if(size <= MAX_U1){ sort_array(offs, size, u4i, cmpgt_seqbits(bb->bits, a + 8, b + 8, klen)); // 8 bp already sorted } else { memset(counts[1], 0, (MAX_U1 + 1) * sizeof(u4i)); for(i=0;ibits, offs[i] + 8); counts[1][v] ++; } m = 0; for(i=0;i<=MAX_U1;i++){ counts[0][i] = m; m += counts[1][i]; counts[1][i] = m; } for(m=0;m<=MAX_U1;m++){ while(counts[0][m] < counts[1][m]){ v = offs[counts[0][m]]; n = sub4seqbits(bb->bits, v + 8); while(n > m){ t = offs[counts[0][n]]; offs[counts[0][n]] = v; counts[0][n] ++; v = t; n = sub4seqbits(bb->bits, v + 8); } offs[counts[0][m]++] = v; } } n = 0; klen -= 4; for(m=0;m<=MAX_U1;m++){ if(counts[0][m] - n < 2){ // nothing to do } else { sort_array(offs + n, counts[0][m] - n, u4i, cmpgt_seqbits(bb->bits, a + 8 + 4, b + 8 + 4, klen)); } n = counts[0][m]; } } } else if(_mradix->task == 3){ u1v *lcps; u8i mask; u4i beg, end; u1i lcp; offs = _mradix->offs; lcps = _mradix->lcps; beg = ((_mradix->size + ncpu - 1) / ncpu) * tidx; end = ((_mradix->size + ncpu - 1) / ncpu) * (tidx + 1); if(end > _mradix->size) end = _mradix->size; klen = _mradix->klen; if(beg == 0){ lcps->buffer[0] = 0; beg = 1; } for(i=beg;ibits, offs[i - 1] + j) ^ sub32seqbits(bb->bits, offs[i] + j); if(mask == 0){ lcp += 32; } else { lcp += __builtin_clzll(mask) >> 1; break; } } lcps->buffer[i] = lcp; } } thread_end_loop(_mradix); free(counts[0]); free(counts[1]); thread_end_func(_mradix); // bullet size = 4^8 = (MAX_U2 + 1) static inline void msd_radix_sort_u4_basebank(BaseBank *bb, u4v *offs, u1v *lcps, u1i _klen, u4i ncpu, FILE *log){ u4i *counts[3]; // off, end, off u4i klen, i, j, size, m, n; thread_preprocess(_mradix); klen = roundup_times(_klen, 32); size = num_max(bb->size, klen) - klen; clear_u4v(offs); encap_u4v(offs, size); offs->size = size; counts[0] = calloc(MAX_U2 + 1, sizeof(u4i)); counts[1] = calloc(MAX_U2 + 1, sizeof(u4i)); if(log) fprintf(log, "[%s] msd_radix_sort length=%u depth=%u\n", date(), (u4i)bb->size, klen); thread_beg_init(_mradix, ncpu); _mradix->bb = bb; _mradix->counts[0] = NULL; _mradix->counts[1] = NULL; _mradix->size = size; _mradix->offs = NULL; _mradix->klen = klen; _mradix->task = 0; _mradix->log = log; thread_end_init(_mradix); thread_apply_all(_mradix, _mradix->task = 1); thread_beg_iter(_mradix); for(j=0;j<=MAX_U2;j++){ counts[1][j] += _mradix->counts[1][j]; } thread_end_iter(_mradix); m = 0; for(i=0;i<=MAX_U2;i++){ counts[0][i] = m; m += counts[1][i]; counts[1][i] = m; } thread_beg_iter(_mradix); _mradix->offs = offs->buffer; _mradix->counts[0] = counts[0]; _mradix->counts[1] = counts[1]; _mradix->task = 11; thread_wake(_mradix); thread_end_iter(_mradix); thread_wait_all(_mradix); if(log) fprintf(log, "[%s] msd_radix_sort sorted by first 8 bp\n", date()); n = 0; for(m=0;m<=MAX_U2;m++){ if(log && (m % 100) == 0){ fprintf(log, "\r%u", counts[0][m]); fflush(log); } if(counts[0][m] - n < 2){ // nothing to do } else { thread_wait_one(_mradix); _mradix->offs = offs->buffer + n; _mradix->size = counts[0][m] - n; _mradix->task = 2; thread_wake(_mradix); } n = counts[0][m]; } thread_wait_all(_mradix); if(log) fprintf(log, "\r%u\n", n); if(log) fprintf(log, "[%s] msd_radix_sort sorted %u bases\n", date(), klen - 8); free(counts[0]); free(counts[1]); if(lcps){ clear_u1v(lcps); encap_u1v(lcps, size); lcps->size = size; thread_beg_iter(_mradix); _mradix->offs = offs->buffer; _mradix->size = size; _mradix->lcps = lcps; _mradix->task = 3; thread_wake(_mradix); thread_end_iter(_mradix); thread_wait_all(_mradix); if(log) fprintf(log, "[%s] msd_radix_sort calculated LCP\n", date()); } thread_beg_close(_mradix); thread_end_close(_mradix); } /* * Sequence DB */ typedef struct { u4i nseq; BaseBank *rdseqs; cplist *rdtags; u8v *rdoffs; u4v *rdlens; cuhash *rdhash; } SeqBank; static inline void rebuild_rdhash_seqbank(void *sb, size_t aux); static const obj_desc_t seqbank_obj_desc = {"SeqBank", sizeof(SeqBank), 5, {1, 1, 1, 1, 1}, {offsetof(SeqBank, rdseqs), offsetof(SeqBank, rdtags), offsetof(SeqBank, rdoffs), offsetof(SeqBank, rdlens), offsetof(SeqBank, rdhash)}, {&basebank_obj_desc, &cplist_deep_obj_desc, &u8v_obj_desc, &u4v_obj_desc, &cuhash_obj_desc}, NULL, rebuild_rdhash_seqbank}; static inline SeqBank* init_seqbank(){ SeqBank *sb; sb = malloc(sizeof(SeqBank)); sb->nseq = 0; sb->rdseqs = init_basebank(); sb->rdtags = init_cplist(16); sb->rdoffs = init_u8v(16); sb->rdlens = init_u4v(16); sb->rdhash = init_cuhash(1023); return sb; } static inline void free_seqbank(SeqBank *sb){ u4i i; for(i=0;irdtags->size;i++) if(sb->rdtags->buffer[i]) free(sb->rdtags->buffer[i]); free_basebank(sb->rdseqs); free_cplist(sb->rdtags); free_u8v(sb->rdoffs); free_u4v(sb->rdlens); free_cuhash(sb->rdhash); free(sb); } static inline void clear_seqbank(SeqBank *sb){ u4i i; for(i=0;irdtags->size;i++) if(sb->rdtags->buffer[i]) free(sb->rdtags->buffer[i]); clear_basebank(sb->rdseqs); clear_cplist(sb->rdtags); clear_u8v(sb->rdoffs); clear_u4v(sb->rdlens); clear_cuhash(sb->rdhash); sb->nseq = 0; } // SeqBank's rdhash is wrongly loaded, need to be corrected static inline void rebuild_rdhash_seqbank(void *_sb, size_t aux){ SeqBank *sb; u4i i; UNUSED(aux); sb = (SeqBank*)_sb; clear_cuhash(sb->rdhash); // hash size is not changed, thus there won't have hash re-size for(i=0;irdtags->size;i++){ put_cuhash(sb->rdhash, (cuhash_t){get_cplist(sb->rdtags, i), i}); } } static inline void push_seqbank(SeqBank *sb, char *tag, int tag_len, char *seq, int seq_len){ char *ptr; if(tag && tag_len){ ptr = malloc(tag_len + 1); memcpy(ptr, tag, tag_len); ptr[tag_len] = 0; } else { ptr = NULL; } push_cplist(sb->rdtags, ptr); push_u8v(sb->rdoffs, sb->rdseqs->size); seq2basebank(sb->rdseqs, seq, seq_len); push_u4v(sb->rdlens, seq_len); if(ptr) put_cuhash(sb->rdhash, (cuhash_t){ptr, sb->nseq}); sb->nseq ++; } static inline void fwdbitpush_seqbank(SeqBank *sb, char *tag, int tag_len, u8i *bits, u8i off, u4i len){ char *ptr; if(tag && tag_len){ ptr = malloc(tag_len + 1); memcpy(ptr, tag, tag_len); ptr[tag_len] = 0; } else { ptr = NULL; } push_cplist(sb->rdtags, ptr); push_u8v(sb->rdoffs, sb->rdseqs->size); fast_fwdbits2basebank(sb->rdseqs, bits, off, len); push_u4v(sb->rdlens, len); if(ptr) put_cuhash(sb->rdhash, (cuhash_t){ptr, sb->nseq}); sb->nseq ++; } static inline void revbitpush_seqbank(SeqBank *sb, char *tag, int tag_len, u8i *bits, u8i off, u4i len){ char *ptr; if(tag && tag_len){ ptr = malloc(tag_len + 1); memcpy(ptr, tag, tag_len); ptr[tag_len] = 0; } else { ptr = NULL; } push_cplist(sb->rdtags, ptr); push_u8v(sb->rdoffs, sb->rdseqs->size); fast_revbits2basebank(sb->rdseqs, bits, off, len); push_u4v(sb->rdlens, len); if(ptr) put_cuhash(sb->rdhash, (cuhash_t){ptr, sb->nseq}); sb->nseq ++; } static inline u4i find_seqbank(SeqBank *sb, char *tag){ cuhash_t *e; if((e = get_cuhash(sb->rdhash, tag))) return e->val; else return MAX_U4; } static inline u4i off2idx_seqbank(SeqBank *sb, u8i off){ u4i ret; bsearch_array(sb->rdoffs->buffer, sb->rdoffs->size, u8i, ret, a < off); return ret? ret - 1 : 0; } static inline u4i num_n50(u4v *lens, FILE *out){ u8i tot, cum; u4i i, max, min, n50, l50, n90, l90, avg; if(lens->size == 0) return 0; sort_array(lens->buffer, lens->size, u4i, num_cmpgt(b, a)); tot = 0; max = lens->buffer[0]; min = lens->buffer[lens->size - 1]; for(i=0;isize;i++){ tot += lens->buffer[i]; } avg = (tot + lens->size - 1) / lens->size; cum = 0; i = 0; while(i < lens->size){ cum += lens->buffer[i]; if((b8i)cum >= tot * 0.5) break; i ++; } n50 = i < lens->size? lens->buffer[i] : min; l50 = i < lens->size? i + 1 : i; i ++; while(i < lens->size){ cum += lens->buffer[i]; if((b8i)cum >= tot * 0.9) break; i ++; } n90 = i < lens->size? lens->buffer[i] : min; l90 = i < lens->size? i + 1 : i; if(out){ fprintf(out, "TOT %llu, CNT %u, AVG %u, MAX %u, N50 %u, L50 %u, N90 %u, L90 %u, Min %u", tot, (u4i)lens->size, avg, max, n50, l50, n90, l90, min); fflush(out); } return n50; } #endif wtdbg2-2.5/filereader.h000066400000000000000000000413321353664372200150420ustar00rootroot00000000000000/* * * Copyright (c) 2011, Jue Ruan * * * 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 3 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, see . */ #ifndef __FILEREADER_RJ_H #define __FILEREADER_RJ_H #include #include #include #include #include #include #include #include "chararray.h" #include "mem_share.h" #include "list.h" #include "thread.h" #include "pgzf.h" #define BIOSEQ_ATTR_NULL 0 #define BIOSEQ_ATTR_TAG 1 #define BIOSEQ_ATTR_SEQ 2 #define BIOSEQ_ATTR_QLT 4 #define BIOSEQ_ATTR_FULL 7 typedef struct { String *tag, *seq, *dsc, *qlt; u4i attr; } BioSequence; #define FILEREADER_TYPE_NULL 0 #define FILEREADER_TYPE_FASTA 1 #define FILEREADER_TYPE_FASTQ 2 #define FILEREADER_TYPE_TEXT 3 #define FILEREADER_ATTR_NULL 0 #define FILEREADER_ATTR_NORMAL 1 #define FILEREADER_ATTR_STDIN 2 #define FILEREADER_ATTR_PROC 3 #define FILEREADER_ATTR_TEXT 4 #define FILEREADER_ATTR_USER 5 // defined by user typedef size_t (*read_data_func)(void *obj, void *dat, size_t len); typedef void (*close_input_func)(void *obj); static inline size_t _read_data_file(void *obj, void *dat, size_t len){ return fread(dat, 1, len, (FILE*)obj); } static inline void _close_input_file(void *obj){ if(obj) fclose((FILE*)obj); } static inline void _close_input_proc(void *obj){ if(obj) pclose((FILE*)obj); } typedef struct { int file_attr; char *filename; void *_file; read_data_func _read; close_input_func _close; } file_src_t; define_list_core(filesrcv, file_src_t, int, 0xFF); typedef struct { filesrcv *files; int fidx; char *buffer[2]; int ridx, widx, flag; u8i bufmax, bufoff, bufcnt[2]; #ifdef FR_USE_SPINLOCK pthread_spinlock_t lock; #else pthread_mutex_t lock; #endif char line_breaker; char delimiter; u8i n_char, n_line; String *line, *line2; VStrv *tabs; int rollback; // line will be re-used in next readline // thread pthread_t pid; int running; int eof; } FileReader; static inline BioSequence* init_biosequence(){ BioSequence *seq; seq = malloc(sizeof(BioSequence)); seq->tag = init_string(32); seq->seq = init_string(32); seq->dsc = init_string(32); seq->qlt = init_string(32); seq->attr = BIOSEQ_ATTR_FULL; return seq; } static inline void reset_biosequence(BioSequence *seq){ clear_string(seq->tag); clear_string(seq->seq); clear_string(seq->dsc); clear_string(seq->qlt); } static inline void free_biosequence(BioSequence *seq){ free_string(seq->tag); free_string(seq->seq); free_string(seq->dsc); free_string(seq->qlt); free(seq); } static inline void* file_src_thread_func(void *obj){ FileReader *fr; file_src_t *fc; void *_file; read_data_func _read; close_input_func _close; size_t off, cnt, len; fr = (FileReader*)obj; while(fr->running){ if(fr->fidx >= fr->files->size){ fr->eof = 1; microsleep(1); } else { fr->eof = 0; fc = ref_filesrcv(fr->files, fr->fidx); _file = NULL; _read = NULL; _close = NULL; switch(fc->file_attr){ case FILEREADER_ATTR_TEXT: len = strlen(fc->filename); off = 0; while(fr->running && len){ while(fr->flag == 1 && fr->running){ nano_sleep(1); } cnt = num_min(len, fr->bufmax); memcpy(fr->buffer[fr->widx], fc->filename + off, cnt); fr->flag = 1; off += cnt; len -= cnt; fr->widx = !fr->widx; } break; case FILEREADER_ATTR_STDIN: if(_file == NULL){ _file = fc->_file = stdin; _read = fc->_read = _read_data_file; _close = fc->_close = NULL; } case FILEREADER_ATTR_PROC: if(_file == NULL){ _file = fc->_file = popen(fc->filename, "r"); _read = fc->_read = _read_data_file; _close = fc->_close = _close_input_proc; } case FILEREADER_ATTR_USER: if(_file == NULL){ _file = fc->_file; _read = fc->_read; _close = fc->_close; } default: if(_file == NULL){ _file = fc->_file = open_file_for_read(fc->filename, NULL); _read = fc->_read = _read_data_file; _close = fc->_close = _close_input_file; } while(fr->running){ while(fr->flag == 1){ nano_sleep(1); if(fr->running == 0){ break; } } if(fr->flag == 1) break; fr->bufcnt[fr->widx] = _read(_file, fr->buffer[fr->widx], fr->bufmax); fr->widx = !fr->widx; fr->flag = 1; if(fr->bufcnt[!fr->widx] == 0) break; } } if(_file && _close){ _close(_file); } fr->fidx ++; } } return NULL; } static inline FileReader* init_filereader(){ FileReader *fr; fr = malloc(sizeof(FileReader)); fr->files = init_filesrcv(4); fr->fidx = 0; fr->bufmax = 128 * 1024; fr->bufoff = 0; fr->bufcnt[0] = 0; fr->bufcnt[1] = 0; fr->ridx = 0; fr->widx = 1; fr->flag = 0; #ifdef FR_USE_SPINLOCK pthread_spin_init(&fr->lock, 0); #else pthread_mutex_init(&fr->lock, NULL); #endif fr->buffer[0] = malloc(fr->bufmax); fr->buffer[1] = malloc(fr->bufmax); fr->line_breaker = '\n'; fr->delimiter = '\t'; fr->n_char = 0; fr->n_line = 0; fr->line = init_string(32); fr->line2 = init_string(32); fr->tabs = init_VStrv(16); fr->rollback = 0; fr->pid = 0; fr->running = 1; fr->eof = 0; return fr; } static inline void beg_asyn_filereader(FileReader *fr){ if(pthread_create(&fr->pid, NULL, file_src_thread_func, fr) != 0){ fprintf(stderr, " -- Failed to create thread [%s] in %s -- %s:%d --\n", "file_src_thread_func", __FUNCTION__, __FILE__, __LINE__); fr->pid = 0; // switch to directed read } } static inline void reset_filereader(FileReader *fr){ if(fr->pid){ fr->running = 0; pthread_join(fr->pid, NULL); } fr->fidx = 0; fr->bufoff = 0; fr->bufcnt[0] = 0; fr->bufcnt[1] = 0; fr->ridx = 0; fr->widx = 0; fr->flag = 0; #ifdef FR_USE_SPINLOCK pthread_spin_destroy(&fr->lock); pthread_spin_init(&fr->lock, 0); #else pthread_mutex_destroy(&fr->lock); pthread_mutex_init(&fr->lock, NULL); #endif clear_string(fr->line); clear_VStrv(fr->tabs); fr->rollback = 0; fr->n_line = 0; fr->n_char = 0; fr->running = 1; fr->eof = 0; if(fr->pid){ fr->pid = 0; beg_asyn_filereader(fr); } } static inline void free_filereader(FileReader *fr){ file_src_t *f; int i; if(fr->pid){ fr->running = 0; pthread_join(fr->pid, NULL); } for(i=0;ifiles->size;i++){ f = ref_filesrcv(fr->files, i); if(f->filename) free(f->filename); } #ifdef FR_USE_SPINLOCK pthread_spin_destroy(&fr->lock); #else pthread_mutex_destroy(&fr->lock); #endif free(fr->buffer[0]); free(fr->buffer[1]); free_filesrcv(fr->files); free_string(fr->line); free_string(fr->line2); free_VStrv(fr->tabs); free(fr); } static inline int push_filereader(FileReader *fr, char *filename){ file_src_t *f; int len; f = next_ref_filesrcv(fr->files); f->_file = NULL; f->_read = NULL; f->_close = NULL; len = filename? strlen(filename) : 0; while(len && filename[len-1] == ' ') len --; if(len == 0 || strcmp(filename, "-") == 0){ f->filename = NULL; f->file_attr = FILEREADER_ATTR_STDIN; } else if(filename[len-1] == '|'){ f->filename = malloc(len); strncpy(f->filename, filename, len - 1); f->file_attr = FILEREADER_ATTR_PROC; } else if(len > 3 && strcmp(filename + len - 3, ".gz") == 0){ //f->filename = malloc(len + 20); //sprintf(f->filename, "gzip -dc %s", filename); //f->file_attr = FILEREADER_ATTR_PROC; f->filename = strdup(filename); f->file_attr = FILEREADER_ATTR_USER; f->_file = open_pgzf_reader(open_file_for_read(f->filename, NULL), 0, 4); f->_read = read_pgzf4filereader; f->_close = close_pgzf4filereader; } else if(len > 5 && strcmp(filename + len - 5, ".pgzf") == 0){ f->filename = strdup(filename); f->file_attr = FILEREADER_ATTR_USER; f->_file = open_pgzf_reader(open_file_for_read(f->filename, NULL), 0, 4); f->_read = read_pgzf4filereader; f->_close = close_pgzf4filereader; } else { f->filename = strdup(filename); f->file_attr = FILEREADER_ATTR_NORMAL; } return f->file_attr; } static inline int push_text_filereader(FileReader *fr, char *str, size_t len){ file_src_t *f; UNUSED(len); f = next_ref_filesrcv(fr->files); f->_file = NULL; f->_read = NULL; f->_close = NULL; f->filename = str; f->file_attr = FILEREADER_ATTR_TEXT; return f->file_attr; } static inline int push_user_filereader(FileReader *fr, void *_file, read_data_func _read, close_input_func _close){ file_src_t *f; f = next_ref_filesrcv(fr->files); f->_file = _file; f->_read = _read; f->_close = _close; f->filename = NULL; f->file_attr = FILEREADER_ATTR_USER; return f->file_attr; } static inline void push_all_filereader(FileReader *fr, int nfile, char **filenames){ int i; for(i=0;irollback){ fr->rollback = 0; return line->size + 1; // in case of end of file and not terminated by line_breaker, the return value is bigger by 1 } else if(fr->eof && fr->bufoff == fr->bufcnt[fr->ridx]){ return 0; } else { clear_string(line); nc = fr->n_char; while(1){ buffer = fr->buffer[fr->ridx]; ret = 0; for(i=fr->bufoff;ibufcnt[fr->ridx];){ if(buffer[i++] == fr->line_breaker){ ret = 1; break; } } fr->n_char += i - fr->bufoff; encap_string(line, i - fr->bufoff); append_string(line, buffer + fr->bufoff, i - fr->bufoff - ret); fr->bufoff = i; if(ret){ return fr->n_char - nc; } else if(fr->eof){ return fr->n_char - nc; } fr->bufoff = 0; fr->bufcnt[fr->ridx] = 0; while(fr->flag == 0){ nano_sleep(1); if(fr->eof){ if(fr->flag) break; else { return fr->n_char - nc; } } } fr->flag = 0; fr->ridx = !fr->ridx; } return 0; } } static inline int directed_readline_filereader(FileReader *fr, String *line){ file_src_t *fc; void *_file; read_data_func _read; close_input_func _close; u8i i, nc; int ch; int ret; if(fr->eof) return 0; else if(fr->rollback){ fr->rollback = 0; return line->size + 1; // in case of end of file and not terminated by line_breaker, the return value is bigger by 1 } clear_string(line); nc = fr->n_char; while(fr->fidx < fr->files->size){ fc = ref_filesrcv(fr->files, fr->fidx); _file = NULL; _read = NULL; _close = NULL; if(fr->flag == 0){ switch(fc->file_attr){ case FILEREADER_ATTR_TEXT: break; case FILEREADER_ATTR_STDIN: _file = fc->_file = stdin; _read = fc->_read = _read_data_file; _close = fc->_close = NULL; break; case FILEREADER_ATTR_PROC: _file = fc->_file = popen(fc->filename, "r"); _read = fc->_read = _read_data_file; _close = fc->_close = _close_input_proc; break; case FILEREADER_ATTR_USER: _file = fc->_file; _read = fc->_read; _close = fc->_close; break; default: _file = fc->_file = open_file_for_read(fc->filename, NULL); _read = fc->_read = _read_data_file; _close = fc->_close = _close_input_file; break; } fr->flag = 1; fr->bufoff = 0; fr->bufcnt[0] = fr->bufcnt[1] = 0; } else { _file = fc->_file; _read = fc->_read; _close = fc->_close; } switch(fc->file_attr){ case FILEREADER_ATTR_TEXT: ret = 0; for(i=fr->bufoff;fc->filename[i];){ if(fc->filename[i++] == fr->line_breaker){ ret = 1; break; } } fr->n_char += i - fr->bufoff; encap_string(line, i - fr->bufoff); append_string(line, fc->filename + fr->bufoff, i - fr->bufoff - ret); fr->bufoff = i; if(ret){ break; } break; case FILEREADER_ATTR_STDIN: while((ch = fgetc(stdin)) != EOF){ fr->n_char ++; if(ch == fr->line_breaker){ break; } add_char_string(line, ch); } break; default: while(1){ if(fr->bufoff >= fr->bufcnt[0]){ fr->bufoff = 0; fr->bufcnt[0] = _read(_file, fr->buffer[0], fr->bufmax); if(fr->bufcnt[0] == 0) break; } ret = 0; for(i=fr->bufoff;ibufcnt[0];){ if(fr->buffer[0][i++] == fr->line_breaker){ ret = 1; break; } } fr->n_char += i - fr->bufoff; encap_string(line, i - fr->bufoff); append_string(line, fr->buffer[0] + fr->bufoff, i - fr->bufoff - ret); fr->bufoff = i; if(ret){ break; } } break; } if(fr->n_char > nc){ return fr->n_char - nc; } else { if(_file && _close){ _close(_file); } fr->flag = 0; fr->fidx ++; } } fr->eof = 1; return 0; } int readline_filereader(FileReader *fr){ int ret; ret = ((fr)->pid? asyn_readline_filereader(fr, (fr)->line) : directed_readline_filereader(fr, (fr)->line)); if(ret > 0){ fr->n_line ++; } return ret; } static inline void rollback_filereader(FileReader *fr){ fr->rollback = 1; fr->n_line --; } static inline int split_line_filereader(FileReader *fr, char delimiter){ VString *vs; int i; clear_VStrv(fr->tabs); vs = next_ref_VStrv(fr->tabs); vs->string = fr->line->string; vs->size = 0; for(i=0;iline->size;i++){ if(fr->line->string[i] == delimiter){ vs->size = fr->line->string + i - vs->string; vs = next_ref_VStrv(fr->tabs); vs->string = fr->line->string + i + 1; vs->size = 0; } } vs->size = fr->line->string + fr->line->size - vs->string; return (int)fr->tabs->size; } static inline int readtable_filereader(FileReader *fr){ if(readline_filereader(fr) == 0) return -1; return split_line_filereader(fr, fr->delimiter); } static inline int get_col_len(FileReader *fr, int col){ return fr->tabs->buffer[col].size; } static inline char* get_col_str(FileReader *fr, int col){ VString *vs; vs = ref_VStrv(fr->tabs, col); vs->string[vs->size] = '\0'; return vs->string; } static inline char* get_line_str(FileReader *fr){ int i; for(i=0;iline->size;i++){ if(fr->line->string[i] == 0){ fr->line->string[i] = fr->delimiter; } } return fr->line->string; } // @return FILEREADER_TYPE_NULL (end of files), _FASTA, _FASTQ, or _TEXT (cannot parse sequence type) static inline int readseq_filereader(FileReader *fr, BioSequence *seq){ int n, i; do { if((n = readline_filereader(fr)) == 0) return FILEREADER_TYPE_NULL; } while(n == 0); reset_biosequence(seq); if(fr->line->string[0] == '>'){ if(seq->attr & BIOSEQ_ATTR_TAG){ for(i=1;iline->size;i++){ if(fr->line->string[i] == ' ' || fr->line->string[i] == '\t') break; } append_string(seq->tag, fr->line->string + 1, i - 1); append_string(seq->dsc, fr->line->string + i, fr->line->size - i); } while((n = readline_filereader(fr))){ if(fr->line->string[0] == '>'){ rollback_filereader(fr); break; } else if(seq->attr & BIOSEQ_ATTR_SEQ){ append_string(seq->seq, fr->line->string, fr->line->size); } } return FILEREADER_TYPE_FASTA; } else if(fr->line->string[0] == '@'){ if(seq->attr & BIOSEQ_ATTR_TAG){ for(i=1;iline->size;i++){ if(fr->line->string[i] == ' ' || fr->line->string[i] == '\t') break; } append_string(seq->tag, fr->line->string + 1, i - 1); append_string(seq->dsc, fr->line->string + i, fr->line->size - i); } if((n = readline_filereader(fr))){ if(seq->attr & BIOSEQ_ATTR_SEQ) append_string(seq->seq, fr->line->string, fr->line->size); } else { return FILEREADER_TYPE_FASTQ; } if((n = readline_filereader(fr))){ // expected '+' } else { return FILEREADER_TYPE_FASTQ; } if((n = readline_filereader(fr))){ if(seq->attr & BIOSEQ_ATTR_QLT) append_string(seq->qlt, fr->line->string, fr->line->size); } else { return FILEREADER_TYPE_FASTQ; } return FILEREADER_TYPE_FASTQ; } else { append_string(seq->dsc, fr->line->string, fr->line->size); return FILEREADER_TYPE_TEXT; } } #endif wtdbg2-2.5/filewriter.h000066400000000000000000000122071353664372200151130ustar00rootroot00000000000000/* * * Copyright (c) 2011, Jue Ruan * * * 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 3 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, see . */ #ifndef __FILEWRITER_RJ_H #define __FILEWRITER_RJ_H #include "mem_share.h" #include "thread.h" #include "pgzf.h" typedef size_t (*write_data_func)(void *obj, void *dat, size_t len); typedef void (*close_output_func)(void *obj); static inline size_t _write_data_file(void *obj, void *dat, size_t len){ return fwrite(dat, 1, len, (FILE*)obj); } static inline void _close_output_file(void *obj){ if(obj) fclose((FILE*)obj); } /** * BufferedWriter */ typedef struct { FILE *bios[2]; FILE *out; void *_file; write_data_func _write; close_output_func _close; int bidx; size_t buf_size; char *buffs[2]; size_t blens[2]; size_t nbytes; pthread_mutex_t lock; pthread_t pid; int running, flush; } BufferedWriter; static inline void* _buffered_writer_thread_func(void *obj){ BufferedWriter *bw; size_t bsize[2]; int bidx, lock; bw = (BufferedWriter*)obj; bw->running = 1; bw->flush = 0; bw->nbytes = 0; while(bw->running){ bidx = bw->bidx; bsize[0] = ftell(bw->bios[0]); bsize[1] = ftell(bw->bios[1]); if(bsize[bidx] >= bw->buf_size || (bsize[bidx] && bw->flush == 1)){ lock = 1; pthread_mutex_lock(&bw->lock); } else { lock = 0; } if(bsize[!bidx]){ fflush(bw->bios[!bidx]); bw->_write(bw->_file, bw->buffs[!bidx], bsize[!bidx]); bw->nbytes += bsize[!bidx]; fseek(bw->bios[!bidx], 0, SEEK_SET); } if(lock){ bw->bidx = !bidx; pthread_mutex_unlock(&bw->lock); } else if(bsize[bidx]){ pthread_mutex_lock(&bw->lock); bw->bidx = !bidx; pthread_mutex_unlock(&bw->lock); } if(bw->flush && bsize[0] == 0 && bsize[1] == 0){ bw->flush = 2; while(bw->flush == 2){ nano_sleep(1); } bw->flush = 0; } nano_sleep(10); } { bsize[0] = ftell(bw->bios[0]); bsize[1] = ftell(bw->bios[1]); fflush(bw->bios[0]); fflush(bw->bios[1]); bidx = bw->bidx; if(bsize[!bidx]){ bw->_write(bw->_file, bw->buffs[!bidx], bsize[!bidx]); bw->nbytes += bsize[!bidx]; } if(bsize[bidx]){ bw->_write(bw->_file, bw->buffs[bidx], bsize[bidx]); bw->nbytes += bsize[bidx]; } } return NULL; } static inline BufferedWriter* open2_bufferedwriter(void *obj, write_data_func _write, close_output_func _close, size_t buf_size){ BufferedWriter *bw; bw = malloc(sizeof(BufferedWriter)); bw->_file = obj; bw->_write = _write; bw->_close = _close; bw->buffs[0] = NULL; bw->buffs[1] = NULL; bw->blens[0] = 0; bw->blens[1] = 0; bw->bios[0] = open_memstream(bw->buffs + 0, bw->blens + 0); bw->bios[1] = open_memstream(bw->buffs + 1, bw->blens + 1); bw->out = NULL; bw->bidx = 0; bw->buf_size = buf_size? buf_size : 4 * 1024; bw->nbytes = 0; bw->lock = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER; bw->running = 0; bw->flush = 0; if(pthread_create(&bw->pid, NULL, _buffered_writer_thread_func, bw) != 0){ fprintf(stderr, " -- Failed to create thread [%s] in %s -- %s:%d --\n", "_buffered_writer_thread_func", __FUNCTION__, __FILE__, __LINE__); bw->pid = 0; } while(bw->running != 1){ nano_sleep(1); } return bw; } static inline BufferedWriter* open_bufferedwriter(FILE *out, size_t buf_size){ return open2_bufferedwriter(out, _write_data_file, NULL, buf_size); } static inline BufferedWriter* zopen_bufferedwriter(FILE *out, size_t buf_size, int ncpu, int level){ PGZF *pz; pz = open_pgzf_writer(out, buf_size, ncpu, level); return open2_bufferedwriter(pz, write_pgzf4filewriter, close_pgzf4filewriter, pz->bufsize); } static inline int beg_bufferedwriter(BufferedWriter *bw){ if(bw->pid){ while(bw->flush){ nano_sleep(1); } pthread_mutex_lock(&bw->lock); bw->out = bw->bios[bw->bidx]; return 0; } else { bw->out = NULL; return 1; // error } } static inline int end_bufferedwriter(BufferedWriter *bw){ if(bw->pid){ pthread_mutex_unlock(&bw->lock); } bw->out = NULL; return 0; } static inline size_t flush_bufferedwriter(BufferedWriter *bw){ size_t ret; if(bw->pid){ pthread_mutex_unlock(&bw->lock); while(bw->flush == 1){ nano_sleep(1); } bw->flush = 1; while(bw->flush == 1){ nano_sleep(1); } pthread_mutex_lock(&bw->lock); bw->flush = 0; bw->out = bw->bios[bw->bidx]; ret = bw->nbytes; } else { ret = 0; } return ret; } static inline size_t close_bufferedwriter(BufferedWriter *bw){ size_t ret; if(bw->pid){ bw->running = 0; pthread_join(bw->pid, NULL); } fclose(bw->bios[0]); fclose(bw->bios[1]); if(bw->buffs[0]) free(bw->buffs[0]); if(bw->buffs[1]) free(bw->buffs[1]); if(bw->_close){ bw->_close(bw->_file); } ret = bw->nbytes; free(bw); return ret; } #endif wtdbg2-2.5/general_graph.h000066400000000000000000000261431353664372200155410ustar00rootroot00000000000000/* * * Copyright (c) 2011, Jue Ruan * * * 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 3 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, see . */ #ifndef __GENERAL_GRAPH_RJ_H #define __GENERAL_GRAPH_RJ_H #include "list.h" #include "hashset.h" #define GEG_MAX_NODE 0xFFFFFFFFFFLLU #define GEG_MAX_EDGE_CNT 0x3FFFF #define GEG_MAX_EDGE_COV 0x7FFFF #define GEG_MAX_EDGE_OFF 0x7FFFFF #define GEG_MIN_EDGE_OFF -0x7FFFFF typedef struct { u8i node1:40, dir1:1, dir2:1, closed:2, cov:19, visit:1; u8i node2:40; b8i off:24; } ge_edge_t; define_list(geedgev, ge_edge_t); static inline uint64_t _ge_edge_hashcode(ge_edge_t e){ const uint64_t m = 0xc6a4a7935bd1e995LLU; const int r = 47; uint64_t h = 1023 ^ (16 * m); uint64_t k = (e.node1 << 1) | e.dir1; k *= m; k ^= k >> r; k *= m; h ^= k; h *= m; k = (e.node2 << 1) | e.dir2; k *= m; k ^= k >> r; k *= m; h ^= k; h *= m; h ^= h >> r; h *= m; h ^= h >> r; return h; } #define GEEDGEHASH(idx) ((geedgev *)set->userdata)->buffer[idx] #define ge_edge_hashcode(E) _ge_edge_hashcode(GEEDGEHASH(E)) #define ge_edge_hashequals(E1, E2) (GEEDGEHASH(E1).node1 == GEEDGEHASH(E2).node1 && GEEDGEHASH(E1).node2 == GEEDGEHASH(E2).node2 \ && GEEDGEHASH(E1).dir1 == GEEDGEHASH(E2).dir1 && GEEDGEHASH(E1).dir2 == GEEDGEHASH(E2).dir2) define_hashset(geedgehash, u8i, ge_edge_hashcode, ge_edge_hashequals); typedef struct { u8i idx:63, flg:1; u8i next; } ge_edge_ref_t; define_list(geedgerefv, ge_edge_ref_t); typedef struct { uint64_t idx:46, cnt:18; } ge_ptr_ref_t; static const ge_ptr_ref_t GE_PTR_REF_NULL = (ge_ptr_ref_t){0, 0}; define_list(geptrrefv, ge_ptr_ref_t); typedef struct { uint64_t idx:46, cnt:18; } ge_vec_ref_t; static const ge_vec_ref_t GE_VEC_REF_NULL = (ge_vec_ref_t){0, 0}; define_list(gevecrefv, ge_vec_ref_t); typedef struct { u8i closed:1, bt_visit:40, bt_dir:1, bt_idx:18, status:4; u8i unvisit:18, aux:46; ge_ptr_ref_t edges[2]; } ge_node_t; define_list(genodev, ge_node_t); #define GEG_TRACE_MSG_ZERO 0 #define GEG_TRACE_MSG_ONE 1 #define GEG_TRACE_MSG_MORE 2 #define GEG_TRACE_MSG_VISITED 3 #define GEG_TRACE_MSG_UNDEF 4 typedef void (*geg_clr_node_callback)(void *userdata); typedef void (*geg_add_node_callback)(void *userdata, u8i nidx); typedef void (*geg_del_node_callback)(void *userdata, u8i nidx); typedef void (*geg_clr_edge_callback)(void *userdata); typedef void (*geg_add_edge_callback)(void *userdata, u8i eidx); typedef void (*geg_del_edge_callback)(void *userdata, u8i eidx); #define define_simple_geg_callback(tag, node_tag, node_tag_t, edge_tag, edge_tag_t) \ void tag##nodeclr(void *aux){ clear_##node_tag((node_tag*)aux); } \ void tag##nodeadd(void *aux, u8i idx){ \ node_tag *nodes = (node_tag*)aux; \ if(idx < nodes->size){ \ memset(ref_##node_tag(nodes, idx), 0, sizeof(node_tag_t)); \ } else { \ memset(next_ref_##node_tag(nodes), 0, sizeof(node_tag_t)); \ } \ } \ void tag##nodedel(void *aux, u8i idx){ UNUSED(aux); UNUSED(idx); } \ void tag##edgeclr(void *aux){ clear_##edge_tag((edge_tag*)aux); } \ void tag##edgeadd(void *aux, u8i idx){ \ edge_tag *edges = (edge_tag*)aux; \ if(idx < edges->size){ \ memset(ref_##edge_tag(edges, idx), 0, sizeof(edge_tag_t)); \ } else { \ memset(next_ref_##edge_tag(edges), 0, sizeof(edge_tag_t)); \ } \ } \ void tag##edgedel(void *aux, u8i idx){ UNUSED(aux); UNUSED(idx); } \ static inline void tag##_set_callbacks_gegraph(GEGraph *g, node_tag *nodeaux, edge_tag *edgeaux){ \ set_callbacks_gegraph(g, (void*)nodeaux, (void*)edgeaux, tag##nodeclr, tag##nodeadd, tag##nodedel, tag##edgeclr, tag##edgeadd, tag##edgedel); \ } typedef struct { genodev *nodes; geedgev *edges; geedgehash *ehash; geedgerefv *erefs; void *nodeaux; void *edgeaux; geg_clr_node_callback nodeclr; geg_add_node_callback nodeadd; geg_del_node_callback nodedel; geg_clr_edge_callback edgeclr; geg_add_edge_callback edgeadd; geg_del_edge_callback edgedel; } GEGraph; static inline GEGraph* init_gegraph(){ GEGraph *g; g = malloc(sizeof(GEGraph)); g->nodes = init_genodev(32); g->edges = init_geedgev(32); g->ehash = init_geedgehash(1023); set_userdata_geedgehash(g->ehash, g->edges); g->erefs = init_geedgerefv(32); g->nodeaux = NULL; g->edgeaux = NULL; g->nodeclr = NULL; g->nodeadd = NULL; g->nodedel = NULL; g->edgeclr = NULL; g->edgeadd = NULL; g->edgedel = NULL; return g; } static inline void set_callbacks_gegraph(GEGraph *g, void *nodeaux, void *edgeaux, geg_clr_node_callback nodeclr, geg_add_node_callback nodeadd, geg_del_node_callback nodedel, geg_clr_edge_callback edgeclr, geg_add_edge_callback edgeadd, geg_del_edge_callback edgedel){ g->nodeaux = nodeaux; g->edgeaux = edgeaux; g->nodeclr = nodeclr; g->nodeadd = nodeadd; g->nodedel = nodedel; g->edgeclr = edgeclr; g->edgeadd = edgeadd; g->edgedel = edgedel; } static inline void free_gegraph(GEGraph *g){ free_genodev(g->nodes); free_geedgev(g->edges); free_geedgehash(g->ehash); free_geedgerefv(g->erefs); free(g); } static inline void reset_gegraph(GEGraph *g){ clear_genodev(g->nodes); if(g->nodeclr) g->nodeclr(g->nodeaux); clear_geedgev(g->edges); memset(next_ref_geedgev(g->edges), 0, sizeof(ge_edge_t)); if(g->edgeclr){ g->edgeclr(g->edgeaux); g->edgeadd(g->edgeaux, 0); } clear_geedgehash(g->ehash); clear_geedgerefv(g->erefs); memset(next_ref_geedgerefv(g->erefs), 0, sizeof(ge_edge_ref_t)); } static inline ge_node_t* add_node_gegraph(GEGraph *g){ ge_node_t *n; n = next_ref_genodev(g->nodes); memset(n, 0, sizeof(ge_node_t)); if(g->nodeadd) g->nodeadd(g->nodeaux, offset_genodev(g->nodes, n)); return n; } static inline ge_edge_t* prepare_edge_gegraph(GEGraph *g, u8i node1, int dir1, u8i node2, int dir2, int *exists){ ge_node_t *n; ge_edge_t *e; ge_edge_ref_t *f; u8i *u; e = ref_geedgev(g->edges, 0); if(node1 <= node2){ e->node1 = node1; e->dir1 = dir1; e->node2 = node2; e->dir2 = dir2; } else { e->node1 = node2; e->dir1 = !dir2; e->node2 = node1; e->dir2 = !dir1; } e->cov = 0; e->off = 0; e->visit = 0; e->closed = 0; u = prepare_geedgehash(g->ehash, 0, exists); if(*exists){ return g->edges->buffer + *u; } else { *u = g->edges->size; e = next_ref_geedgev(g->edges); *e = g->edges->buffer[0]; n = g->nodes->buffer + e->node1; f = next_ref_geedgerefv(g->erefs); f->idx = *u; f->flg = 0; f->next = n->edges[e->dir1].idx; n->edges[e->dir1].idx = g->erefs->size - 1; n->edges[e->dir1].cnt ++; n = g->nodes->buffer + e->node2; f = next_ref_geedgerefv(g->erefs); f->idx = *u; f->flg = 1; f->next = n->edges[!e->dir2].idx; n->edges[!e->dir2].idx = g->erefs->size - 1; n->edges[!e->dir2].cnt ++; if(g->edgeadd) g->edgeadd(g->edgeaux, offset_geedgev(g->edges, e)); return e; } } static inline void cut_edge_core_gegraph(GEGraph *g, ge_edge_t *e, int closed_val){ if(e->closed) return; e->closed = closed_val; ref_genodev(g->nodes, e->node1)->edges[e->dir1].cnt --; ref_genodev(g->nodes, e->node2)->edges[!e->dir2].cnt --; if(g->edgedel) g->edgedel(g->edgeaux, offset_geedgev(g->edges, e)); } #define cut_edge_gegraph(g, e) cut_edge_core_gegraph(g, e, 1) static inline void revive_edge_gegraph(GEGraph *g, ge_edge_t *e){ if(e->closed == 0) return; e->closed = 0; ref_genodev(g->nodes, e->node1)->edges[e->dir1].cnt ++; ref_genodev(g->nodes, e->node2)->edges[!e->dir2].cnt ++; if(g->edgedel) g->edgeadd(g->edgeaux, offset_geedgev(g->edges, e)); } static inline ge_edge_ref_t* single_edge_gegraph(GEGraph *g, ge_node_t *n, int dir, int *info){ ge_edge_ref_t *f, *ret; uint64_t idx; ret = NULL; if(info){ *info = GEG_TRACE_MSG_ZERO; if(n->edges[dir].cnt == 0) return NULL; idx = n->edges[dir].idx; while(idx){ f = ref_geedgerefv(g->erefs, idx); idx = f->next; if(g->edges->buffer[f->idx].closed) continue; if(ret){ *info = GEG_TRACE_MSG_MORE; return NULL; } else { *info = GEG_TRACE_MSG_ONE; ret = f; } } } else { if(n->edges[dir].cnt == 0) return NULL; idx = n->edges[dir].idx; while(idx){ f = ref_geedgerefv(g->erefs, idx); idx = f->next; if(g->edges->buffer[f->idx].closed) continue; if(ret){ return NULL; } else { ret = f; } } } return ret; } #define count_edges_gegraph(g, n, dir) (n)->edges[dir].cnt // dir = 2 means either strand static inline ge_edge_ref_t* edge_node2node_gegraph(GEGraph *g, u8i node1, int dir1, u8i node2, int dir2){ ge_node_t *n; ge_edge_ref_t *f; ge_edge_t *e; uint64_t idx; int dire; n = ref_genodev(g->nodes, node1); if(dir1 > 1){ dir1 = 0; dire = 2; } else { dire = dir1 + 1; } while(dir1 < dire){ idx = n->edges[dir1].idx; while(idx){ f = ref_geedgerefv(g->erefs, idx); idx = f->next; e = ref_geedgev(g->edges, f->idx); if(f->flg){ if(e->node1 == node2 && (dir2 > 1? 1 : (dir2 == (!e->dir1)))) return f; } else { if(e->node2 == node2 && (dir2 > 1? 1 : (dir2 == e->dir2))) return f; } } dir1 ++; } return NULL; } static inline void del_node_edges_gegraph(GEGraph *g, ge_node_t *n, int closed_val){ ge_edge_ref_t *f; ge_edge_t *e; uint64_t idx; uint32_t k; for(k=0;k<2;k++){ idx = n->edges[k].idx; while(idx){ f = ref_geedgerefv(g->erefs, idx); idx = f->next; e = g->edges->buffer + f->idx; cut_edge_core_gegraph(g, e, closed_val); } } } static inline void del_node_gegraph(GEGraph *g, ge_node_t *n){ del_node_edges_gegraph(g, n, 1); n->closed = 1; if(g->nodedel) g->nodeadd(g->nodeaux, offset_genodev(g->nodes, n)); } #define geg_beg_iter_edges(g, n, dir, f, e) \ { \ u8i _geg_iter_idx; \ _geg_iter_idx = (n)->edges[dir].idx; \ while(_geg_iter_idx){ \ (f) = ref_geedgerefv((g)->erefs, _geg_iter_idx); \ _geg_iter_idx = (f)->next; \ (e) = (g)->edges->buffer + (f)->idx #define geg_end_iter_edges() \ } \ } static inline void print_dot_gegraph(GEGraph *g, FILE *out){ static const char *colors[2][2] = {{"blue", "green"}, {"red", "gray"}}; ge_node_t *n; ge_edge_t *e; u8i i; fprintf(out, "digraph {\n"); for(i=0;inodes->size;i++){ n = ref_genodev(g->nodes, i); if(n->closed) continue; fprintf(out, " N%llu\n", i); } for(i=1;iedges->size;i++){ e = ref_geedgev(g->edges, i); if(e->closed) continue; fprintf(out, " N%llu -> N%llu [label=\"%c%c:%d:%d\" color=%s]\n", (u8i)e->node1, (u8i)e->node2, "+-"[e->dir1], "+-"[e->dir2], e->cov, e->off, colors[e->dir1][e->dir2]); fprintf(out, " N%llu -> N%llu [label=\"%c%c:%d:%d\" color=%s]\n", (u8i)e->node2, (u8i)e->node1, "-+"[e->dir2], "-+"[e->dir1], e->cov, e->off, colors[!e->dir2][!e->dir1]); } fprintf(out, "}\n"); fflush(out); } static inline void fprint_dot_gegraph(GEGraph *g, char *prefix, char *suffix){ FILE *out; out = open_file_for_write(prefix, suffix, 1); print_dot_gegraph(g, out); fclose(out); } #endif wtdbg2-2.5/hashset.h000066400000000000000000000620571353664372200144060ustar00rootroot00000000000000/* * * Copyright (c) 2011, Jue Ruan * * * 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 3 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, see . */ #ifndef __HASH_SET_RJ #define __HASH_SET_RJ #include #include #include #include #include #include "mem_share.h" #include "bitvec.h" static const uint64_t sys_prime_list[61] = { 0x7LLU, 0xfLLU, 0x1fLLU, 0x43LLU, 0x89LLU, 0x115LLU, 0x22dLLU, 0x45dLLU, 0x8bdLLU, 0x1181LLU, 0x2303LLU, 0x4609LLU, 0x8c17LLU, 0x1183dLLU, 0x2307bLLU, 0x460fdLLU, 0x8c201LLU, 0x118411LLU, 0x230833LLU, 0x461069LLU, 0x8c20e1LLU, 0x11841cbLLU, 0x2308397LLU, 0x461075bLLU, 0x8c20ecbLLU, 0x11841da5LLU, 0x23083b61LLU, 0x461076c7LLU, 0x8c20ed91LLU, 0x11841db31LLU, 0x23083b673LLU, 0x461076d1bLLU, 0x8c20eda41LLU, 0x11841db48dLLU, 0x23083b6937LLU, 0x461076d27fLLU, 0x8c20eda50dLLU, 0x11841db4a59LLU, 0x23083b694ebLLU, 0x461076d29f1LLU, 0x8c20eda5441LLU, 0x11841db4a887LLU, 0x23083b69511fLLU, 0x461076d2a2c1LLU, 0x8c20eda54591LLU, 0x11841db4a8b55LLU, 0x23083b69516c1LLU, 0x461076d2a2da5LLU, 0x8c20eda545b55LLU, 0x11841db4a8b6b5LLU, 0x23083b69516d91LLU, 0x461076d2a2db3bLLU, 0x8c20eda545b69dLLU, 0x11841db4a8b6d5dLLU, 0x23083b69516daf5LLU, 0x461076d2a2db5edLLU, 0x8c20eda545b6c5fLLU, 0x11841db4a8b6d8ebLLU, 0x23083b69516db1ffLLU, 0x461076d2a2db643fLLU, 0x8c20eda545b6c8f3LLU }; static inline uint64_t _rj_hashset_find_prime(uint64_t n){ uint32_t i; i = 0; while(i < 60 && n > sys_prime_list[i]) i ++; return sys_prime_list[i]; } #define init_hashset_macro(hash_type, hash_ele_type) \ typedef struct { hash_ele_type *array; BitVec *ones, *dels; size_t e_size; size_t ocp; size_t size; size_t count; size_t max; float load_factor; size_t iter_ptr; void *userdata; } hash_type; \ static inline size_t hash_type##_obj_desc_cnt(void *obj, int idx){ \ hash_type *set; \ set = (hash_type*)obj; \ if(set->dels){ \ switch(idx){ \ case 0: return ((hash_type*)obj)->size * sizeof(hash_ele_type); \ default: return 1; \ } \ } else { \ switch(idx){ \ case 0: return ((hash_type*)obj)->count * sizeof(hash_ele_type); \ case 1: return 1; \ default: return 0; \ } \ } \ } \ static const obj_desc_t hash_type##_obj_desc = {TOSTR(_hashset_##hash_type), sizeof(hash_type), 3, {1, 1, 1}, {offsetof(hash_type, array), offsetof(hash_type, ones), offsetof(hash_type, dels)}, {(obj_desc_t*)&OBJ_DESC_DATA, (obj_desc_t*)&bitvec_obj_desc, (obj_desc_t*)&bitvec_obj_desc}, hash_type##_obj_desc_cnt, NULL}; \ static inline int hash_type##_is_prime(uint64_t num){ \ uint64_t i, max; \ if(num < 4) return 1; \ if(num % 2 == 0) return 0; \ max = (uint64_t)sqrt((double)num); \ for(i=3;ie_size = sizeof(hash_ele_type); \ set->size = _rj_hashset_find_prime(size); \ set->count = 0; \ set->ocp = 0; \ set->load_factor = factor; \ set->max = set->size * set->load_factor; \ set->iter_ptr = 0; \ set->array = calloc(set->size, set->e_size); \ set->ones = init_bitvec(set->size); \ set->dels = init_bitvec(set->size); \ set->userdata = NULL; \ return set; \ } \ static inline void set_userdata_##hash_type(hash_type *set, void *userdata){ set->userdata = userdata; } \ static inline hash_type* init_##hash_type(uint32_t size){ return init2_##hash_type(size, 0.67f); } #define get_hashset_macro(hash_type, hash_ele_type, hash_key_type, hash_key_code, hash_key_equal, hash_val_type, hash_ele2val) \ static inline hash_ele_type* get_##hash_type(hash_type *set, hash_key_type key){\ hash_ele_type *e; \ size_t hc, hi; \ hc = hash_key_code(key) % set->size; \ if(set->dels){ \ while(1){ \ if(get_bitvec(set->ones, hc) == 0){ \ return NULL; \ } else if(get_bitvec(set->dels, hc)){ \ } else { \ e = ((hash_ele_type*)set->array) + hc; \ if(hash_key_equal((key), (*e))) return e; \ } \ hc = (hc + 1) % set->size; \ } \ } else { \ hi = MAX_U8; \ while(1){ \ if(get_bitvec(set->ones, hc)){ \ if(hi == MAX_U8){ \ hi = rank_bitvec(set->ones, hc); \ } \ e = ((hash_ele_type*)set->array) + hi; \ if(hash_key_equal((key), (*e))) return e; \ } else { \ return NULL; \ } \ hc ++; \ hi ++; \ } \ } \ return NULL; \ } \ static inline size_t offset_##hash_type(hash_type *set, hash_ele_type *ptr){ \ return ptr - set->array; \ } \ static inline hash_ele_type* ref_##hash_type(hash_type *set, size_t off){ return set->array + off; } \ static inline hash_val_type getval_##hash_type(hash_type *set, hash_key_type key){ \ hash_ele_type *e; \ e = get_##hash_type(set, key); \ return hash_ele2val(e); \ } #define prepare_hashset_macro(hash_type, hash_ele_type, hash_key_type, hash_key_code, hash_key_equal) \ static inline void encap_##hash_type(hash_type *set, size_t num); \ static inline hash_ele_type* prepare_##hash_type(hash_type *set, hash_key_type key, int *exists){\ hash_ele_type *e; \ size_t hc, d; \ if(set->dels == NULL){ *exists = 0; return NULL; } \ encap_##hash_type(set, 1); \ hc = hash_key_code((key)) % set->size; \ d = set->size; \ while(1){ \ if(get_bitvec(set->ones, hc) == 0){ \ if(d == set->size){ \ one_bitvec(set->ones, hc); \ set->ocp ++; \ } else { \ hc = d; \ zero_bitvec(set->dels, hc); \ } \ if(exists) *exists = 0; \ set->count ++; \ e = ((hash_ele_type*)set->array) + hc; \ return e; \ } else if(get_bitvec(set->dels, hc)){ \ if(d == set->size) d = hc; \ } else { \ e = ((hash_ele_type*)set->array) + hc; \ if(hash_key_equal((key), (*e))){ \ if(exists) *exists = 1; \ return e; \ } \ } \ hc = (hc + 1) % set->size; \ } \ return NULL; \ } #define exists_hashset_macro(hash_type, hash_ele_type, hash_key_type, hash_key_code, hash_key_equal) \ static inline int exists_##hash_type(hash_type *set, hash_key_type key){ \ return get_##hash_type(set, key) != NULL; \ } #define add_hashset_macro(hash_type, hash_ele_type, hash_code_macro, hash_equal_macro) \ static inline hash_ele_type* add_##hash_type(hash_type *set, hash_ele_type ele){ \ hash_ele_type *e; \ size_t d, hc; \ if(set->dels == NULL) return NULL; \ hc = hash_code_macro(ele) % set->size; \ d = set->size; \ do { \ if(get_bitvec(set->ones, hc) == 0){ \ if(d == set->size){ \ one_bitvec(set->ones, hc); \ set->ocp ++; \ } else { \ hc = d; \ zero_bitvec(set->dels, hc); \ } \ set->count ++; \ e = ((hash_ele_type*)set->array) + hc; \ *e = ele; \ return e; \ } else if(get_bitvec(set->dels, hc)){ \ if(d == set->size) d = hc; \ } else { \ e = ((hash_ele_type*)set->array) + hc; \ if(hash_equal_macro((ele), (*e))){ \ *e = ele; \ return e; \ } \ } \ hc = (hc + 1) % set->size; \ } while(1); \ return NULL; \ } #define put_hashset_macro(hash_type, hash_ele_type) \ static inline hash_ele_type* put_##hash_type(hash_type *set, hash_ele_type ele){ \ encap_##hash_type(set, 1); \ return add_##hash_type(set, ele); \ } #define remove_hashset_macro(hash_type, hash_ele_type, hash_key_type, hash_key_code, hash_key_equal) \ static inline int delete_##hash_type(hash_type *set, hash_ele_type *ele){ \ size_t hc; \ if(set->dels == NULL) return 0; \ hc = offset_##hash_type(set, ele); \ if(get_bitvec(set->ones, (hc + 1) % set->size) == 0){ \ zero_bitvec(set->ones, hc); \ set->ocp --; \ } else { \ one_bitvec(set->dels, hc); \ } \ set->count --; \ return 1; \ } \ \ static inline int remove_##hash_type(hash_type *set, hash_key_type key){ \ hash_ele_type *e; \ size_t hc; \ if(set->dels == NULL) return 0; \ hc = hash_key_code(key) % set->size; \ while(1){ \ if(get_bitvec(set->ones, hc) == 0){ \ return 0; \ } else if(get_bitvec(set->dels, hc)){ \ } else { \ e = ((hash_ele_type*)set->array) + hc; \ if(hash_key_equal((key), (*e))){ \ if(get_bitvec(set->ones, (hc + 1) % set->size) == 0){ \ zero_bitvec(set->ones, hc); \ set->ocp --; \ } else { \ one_bitvec(set->dels, hc); \ } \ set->count --; \ return 1; \ } \ } \ hc = (hc + 1) % set->size; \ } \ return 0; \ } #define reset_iter_hashset_macro(hash_type) static inline void reset_iter_##hash_type(hash_type *set){ set->iter_ptr = 0; } #define ref_iter_hashset_macro(hash_type, hash_ele_type) \ static inline hash_ele_type* ref_iter2_##hash_type(hash_type *set, size_t *iter_ptr){ \ if(set->dels){ \ while(((*iter_ptr) = next_one_bitvec(set->ones, (*iter_ptr))) < set->size){ \ if(get_bitvec(set->dels, (*iter_ptr))){ \ (*iter_ptr) ++; \ } else { \ return (((hash_ele_type*)set->array) + (*iter_ptr)++); \ } \ } \ } else { \ while((*iter_ptr) < set->count){ \ return (((hash_ele_type*)set->array) + (*iter_ptr)++); \ } \ } \ return NULL; \ } \ static inline hash_ele_type* ref_iter_##hash_type(hash_type *set){ \ return ref_iter2_##hash_type(set, &(set->iter_ptr)); \ } #define count_hashset_macro(hash_type) static inline int64_t count_##hash_type(hash_type *set){ return set->count; } #define freeze_hashset_macro(hash_type, hash_ele_type, hash_code_macro) \ static inline int freeze_##hash_type(hash_type *set, float load_factor){ \ size_t *hvs, i, j, sz; \ if(set->dels == NULL) return 0; \ if(load_factor == 0) load_factor = set->load_factor; \ sz = set->count / load_factor; \ sz = _rj_hashset_find_prime(sz); \ for(i=j=0;(i=next_one_bitvec(set->ones, i))size;i++){ \ if(get_bitvec(set->dels, i)) continue; \ if(j < i){ \ set->array[j] = set->array[i]; \ } \ j ++; \ } \ free_bitvec(set->ones); \ set->ones = NULL; \ free_bitvec(set->dels); \ set->dels = NULL; \ set->size = sz; \ set->load_factor = load_factor; \ set->ocp = set->count; \ set->array = realloc(set->array, (set->count + 1) * sizeof(hash_ele_type)); \ memset(set->array + set->count, 0, sizeof(hash_ele_type)); \ hvs = malloc(set->count * sizeof(size_t)); \ for(i=0;icount;i++){ \ hvs[i] = hash_code_macro(set->array[i]) % sz; \ } \ sort_array_adv(set->count, hvs[a] > hvs[b], swap_var(hvs[a], hvs[b]); swap_var(set->array[a], set->array[b])); \ for(i=j=0;icount;i++){ \ if(j < hvs[i]) j = hvs[i]; \ j ++; \ } \ if(j < sz) j = sz; \ set->ones = init_bitvec(j + 1); \ for(i=j=0;icount;i++){ \ if(j < hvs[i]) j = hvs[i]; \ one_bitvec(set->ones, j); \ j ++; \ } \ free(hvs); \ index_bitvec(set->ones); \ return 1; \ } #define clear_hashset_macro(hash_type) \ static inline void clear_##hash_type(hash_type *set){ \ if(set->dels == NULL){ \ return; \ } \ zeros_bitvec(set->ones); \ zeros_bitvec(set->dels); \ set->count = 0; \ set->ocp = 0; \ set->iter_ptr = 0; \ } #define free_hashset_macro(hash_type) \ static inline void free_##hash_type(hash_type *set){ \ free(set->array); \ if(set->ones) free_bitvec(set->ones); \ if(set->dels) free_bitvec(set->dels); \ free(set); \ } #define encap_hashset_macro(hash_type, hash_ele_type, hash_code_macro) \ static inline void encap_##hash_type(hash_type *set, size_t num){ \ BitVec *ones, *dels; \ size_t i, n, hc; \ hash_ele_type key; \ if(set->dels == NULL) return; \ if(set->ocp + num <= set->max) return; \ n = set->size; \ do{ n = _rj_hashset_find_prime(n * 2); } while(n * set->load_factor < set->count + num); \ set->array = realloc(set->array, n * set->e_size); \ if(set->array == NULL){ \ fprintf(stderr, "-- Out of memory --\n"); \ print_backtrace(stderr, 20); \ exit(1); \ } \ ones = init_bitvec(n); \ dels = init_bitvec(n); \ set->ocp = set->count; \ set->max = n * set->load_factor; \ for(i=0;(i=next_one_bitvec(set->ones, i))size;i++){ \ if(get_bitvec(set->dels, i)) continue; \ key = ((hash_ele_type*)set->array)[i]; \ one_bitvec(set->dels, i); \ while(1){ \ hc = hash_code_macro(key) % n; \ while(get_bitvec(ones, hc)){ \ hc = (hc + 1) % n; \ } \ one_bitvec(ones, hc); \ if(hc < set->size && get_bitvec(set->ones, hc) && get_bitvec(set->dels, hc) == 0){ \ swap_var(key, ((hash_ele_type*)set->array)[hc]); \ one_bitvec(set->dels, hc); \ } else { \ ((hash_ele_type*)set->array)[hc] = key; \ break; \ } \ } \ } \ swap_var(ones, set->ones); \ swap_var(dels, set->dels); \ set->size = n; \ free_bitvec(ones); \ free_bitvec(dels); \ } \ static inline size_t offsetof_##hash_type(hash_type *set, hash_ele_type *ptr){ return ptr - set->array; } \ #define ITSELF(E) (E) #define NUM_EQUALS(E1, E2) ((E1) == (E2)) #define define_hashtable(hash_type, hash_ele_type, hash_code_macro, hash_equal_macro, hash_key_type, hash_key_code, hash_key_equal, hash_val_type, hash_ele2val) \ init_hashset_macro(hash_type, hash_ele_type); \ get_hashset_macro(hash_type, hash_ele_type, hash_key_type, hash_key_code, hash_key_equal, hash_val_type, hash_ele2val); \ prepare_hashset_macro(hash_type, hash_ele_type, hash_key_type, hash_key_code, hash_key_equal); \ exists_hashset_macro(hash_type, hash_ele_type, hash_key_type, hash_key_code, hash_key_equal); \ add_hashset_macro(hash_type, hash_ele_type, hash_code_macro, hash_equal_macro); \ put_hashset_macro(hash_type, hash_ele_type); \ remove_hashset_macro(hash_type, hash_ele_type, hash_key_type, hash_key_code, hash_key_equal); \ ref_iter_hashset_macro(hash_type, hash_ele_type); \ reset_iter_hashset_macro(hash_type); \ count_hashset_macro(hash_type); \ clear_hashset_macro(hash_type); \ freeze_hashset_macro(hash_type, hash_ele_type, hash_code_macro); \ free_hashset_macro(hash_type); \ encap_hashset_macro(hash_type, hash_ele_type, hash_code_macro); #define define_hashset(hash_type, hash_ele_type, hash_code_macro, hash_equal_macro) define_hashtable(hash_type, hash_ele_type, hash_code_macro, hash_equal_macro, hash_ele_type, hash_code_macro, hash_equal_macro, hash_ele_type*, ITSELF) /* ------------------ Useful functions ------------------------------------- */ static inline uint32_t __lh3_Jenkins_hash_int(uint32_t key){ key += (key << 12); key ^= (key >> 22); key += (key << 4); key ^= (key >> 9); key += (key << 10); key ^= (key >> 2); key += (key << 7); key ^= (key >> 12); return key; } static inline uint64_t __lh3_Jenkins_hash_64(uint64_t key){ key += ~(key << 32); key ^= (key >> 22); key += ~(key << 13); key ^= (key >> 8); key += (key << 3); key ^= (key >> 15); key += ~(key << 27); key ^= (key >> 31); return key; } static inline uint32_t jenkins_one_at_a_time_hash(char *key, size_t len){ uint32_t hash, i; for(hash = i = 0; i < len; ++i){ hash += key[i]; hash += (hash << 10); hash ^= (hash >> 6); } hash += (hash << 3); hash ^= (hash >> 11); hash += (hash << 15); return hash; } static inline u8i invertible_hashcode(u8i x, int p){ u8i m; m = 0xFFFFFFFFFFFFFFFFLLU >> (64 - p); x = ((~x) + (x << 21)) & m; x = x ^ (x >> 24); x = (x + (x << 3) + (x << 8)) & m; x = x ^ (x >> 14); x = (x + (x << 2) + (x << 4)) & m; x = x ^ (x >> 28); x = (x + (x << 31)) & m; return x; } static inline uint64_t hash64shift(uint64_t key){ key = (~key) + (key << 21); // key = (key << 21) - key - 1; key = key ^ (key >> 24); key = (key + (key << 3)) + (key << 8); // key * 265 key = key ^ (key >> 14); key = (key + (key << 2)) + (key << 4); // key * 21 key = key ^ (key >> 28); key = key + (key << 31); return key; } static inline uint64_t MurmurHash64A(const void * key, int len, uint32_t seed){ const uint64_t m = 0xc6a4a7935bd1e995LLU; const int r = 47; uint64_t h = seed ^ (len * m); const uint64_t * data = (const uint64_t *)key; const uint64_t * end = data + (len/8); while(data != end){ uint64_t k = *data++; k *= m; k ^= k >> r; k *= m; h ^= k; h *= m; } const unsigned char * data2 = (const unsigned char*)data; switch(len & 7){ case 7: h ^= ((uint64_t)data2[6]) << 48; case 6: h ^= ((uint64_t)data2[5]) << 40; case 5: h ^= ((uint64_t)data2[4]) << 32; case 4: h ^= ((uint64_t)data2[3]) << 24; case 3: h ^= ((uint64_t)data2[2]) << 16; case 2: h ^= ((uint64_t)data2[1]) << 8; case 1: h ^= ((uint64_t)data2[0]); h *= m; }; h ^= h >> r; h *= m; h ^= h >> r; return h; } #define u32hashcode(key) __lh3_Jenkins_hash_int(key) #define u64hashcode(key) __lh3_Jenkins_hash_64(key) static inline uint32_t __string_hashcode(const char *s){ uint32_t h = *s; if (h) for (++s ; *s; ++s) h = (h << 5) - h + *s; return h; } #define u32hash_code(e) u32hashcode(e) #define u64hash_code(e) u64hashcode(e) #define uxxhash_equals(e1, e2) ((e1) == (e2)) define_hashset(u32hash, uint32_t, u32hash_code, uxxhash_equals); define_hashset(u64hash, uint64_t, u64hash_code, uxxhash_equals); #define i32hash_code(e) u32hashcode((uint32_t)(e)) #define i32hash_equals(e1, e2) ((e1) == (e2)) define_hashset(i32hash, int, i32hash_code, i32hash_equals); #define chash_code(e) __string_hashcode(e) #define chash_equals(e1, e2) (strcmp(e1, e2) == 0) define_hashset(chash, char*, chash_code, chash_equals); #define KV_HASH_GET_VAL(e) (e)? (e)->val : ((typeof(e->val))MAX_U8) typedef struct { u4i key, val; } uuhash_t; #define uuhash_code(e) u32hashcode((e).key) #define uuhash_equals(e1, e2) ((e1).key == (e2).key) #define uuhash_key_equals(e1, e2) ((e1) == (e2).key) define_hashtable(uuhash, uuhash_t, uuhash_code, uuhash_equals, u4i, u32hashcode, uuhash_key_equals, u4i, KV_HASH_GET_VAL); typedef struct { u4i key; int val; } uihash_t; #define uihashcode(E) u32hashcode((E).key) #define uihashequals(E1, E2) (E1).key == (E2).key #define uihashkeyequals(E1, E2) (E1) == (E2).key define_hashtable(uihash, uihash_t, uihashcode, uihashequals, u4i, u32hashcode, uihashkeyequals, b4i, KV_HASH_GET_VAL); typedef struct { u8i key, val; } UUhash_t; #define UUhashcode(E) u64hashcode((E).key) #define UUhashequals(E1, E2) (E1).key == (E2).key #define UUhashkeyequals(E1, E2) (E1) == (E2).key define_hashtable(UUhash, UUhash_t, UUhashcode, UUhashequals, u8i, u64hashcode, UUhashkeyequals, u8i, KV_HASH_GET_VAL); typedef struct { char *key; u4i val; } cuhash_t; #define cuhash_code(e) __string_hashcode((e).key) #define cuhash_equals(e1, e2) (strcmp((e1).key, (e2).key) == 0) #define cuhash_key_equals(e1, e2) (strcmp((char*)(e1), (e2).key) == 0) define_hashtable(cuhash, cuhash_t, cuhash_code, cuhash_equals, char*, __string_hashcode, cuhash_key_equals, u4i, KV_HASH_GET_VAL); static const obj_desc_t cuhash_struct_deep_obj_desc = {"cuhash_struct_deep_obj_desc", sizeof(cuhash_t), 1, {1}, {offsetof(cuhash_t, key)}, {(obj_desc_t*)&OBJ_DESC_CHAR_ARRAY}, NULL, NULL}; static const obj_desc_t cuhash_deep_obj_desc = {"cuhash_deep_obj_desc", sizeof(cuhash), 3, {1, 1, 1}, {offsetof(cuhash, array), offsetof(cuhash, ones), offsetof(cuhash, dels)}, {(obj_desc_t*)&cuhash_struct_deep_obj_desc, (obj_desc_t*)&bitvec_obj_desc, &bitvec_obj_desc}, cuhash_obj_desc_cnt, NULL}; typedef struct { char *key; int val; } cihash_t; #define cihash_code(e) __string_hashcode((e).key) #define cihash_equals(e1, e2) (strcmp((e1).key, (e2).key) == 0) #define cihash_key_equals(e1, e2) (strcmp((char*)(e1), (e2).key) == 0) define_hashtable(cihash, cihash_t, cihash_code, cihash_equals, char*, __string_hashcode, cihash_key_equals, b4i, KV_HASH_GET_VAL); typedef struct { char *key; unsigned long long val; } clhash_t; #define clhash_code(e) __string_hashcode((e).key) #define clhash_equals(e1, e2) (strcmp((e1).key, (e2).key) == 0) #define clhash_key_equals(e1, e2) (strcmp((char*)(e1), (e2).key) == 0) define_hashtable(clhash, clhash_t, clhash_code, clhash_equals, char*, __string_hashcode, clhash_key_equals, u8i, KV_HASH_GET_VAL); typedef struct { char *key; char *val; } cchash_t; #define cchash_code(e) __string_hashcode((e).key) #define cchash_equals(e1, e2) (strcmp((e1).key, (e2).key) == 0) #define cchash_key_equals(e1, e2) (strcmp((char*)(e1), (e2).key) == 0) #define KV_CCHASH_GET_VAL(e) ((e)? (e)->val : NULL) define_hashtable(cchash, cchash_t, cchash_code, cchash_equals, char*, __string_hashcode, cchash_key_equals, char*, KV_CCHASH_GET_VAL); /** * Example of using userdata in thread-safe mode * char **strs; * ... codes init strs * #define test_hc(E) __string_hashcode(((char**)set->userdata)[E]) * #define test_he(E1, E2) (strcmp(((char**)set->userdata)[E1], ((char**)set->userdata)[E2]) == 0) * define_hashset(testhash, uint32_t, test_hc, test_he); * testhash *hash = init_testhash(13); * set_userdata_testhash(hash, strs); * ... now, the key of testhash is uint32_t, but refer to strs */ #endif wtdbg2-2.5/kbm.c000066400000000000000000000630201353664372200135020ustar00rootroot00000000000000/* * * Copyright (c) 2011, Jue Ruan * * * 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 3 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, see . */ #include "kbm.h" #include "kbmpoa.h" #include #ifndef VERSION #define VERSION 0.0 #endif #ifndef RELEASE #define RELEASE 19830203 #endif int kbm_usage(){ fprintf(stdout, "Program: kbm is a simple instance which implemented kmer-binmap\n"); fprintf(stdout, " it maps query sequence against reference by kmer matching\n"); fprintf(stdout, " matched kmer-pairs are bined (256bp) and counted in a matrix\n"); fprintf(stdout, " dynamic programming is used to search the best path\n"); fprintf(stdout, "Version: %s (%s)\n", TOSTR(VERSION), TOSTR(RELEASE)); fprintf(stdout, "Author: Jue Ruan \n"); fprintf(stdout, "Usage: kbm [start|list|stop]\n"); fprintf(stdout, "Options:\n"); fprintf(stdout, " -i File(s) of query sequences, +, [STDIN]\n"); fprintf(stdout, " -d File(s) of reference sequences, +, [<-i>]\n"); fprintf(stdout, " -L Choose the longest subread and drop reads shorter than (5000 recommended for PacBio) [0]\n"); fprintf(stdout, " Negative integer indicate keeping read names, e.g. -5000.\n"); fprintf(stdout, " -o Output file, [STDOUT]\n"); fprintf(stdout, " -I Interactive mode\n"); fprintf(stdout, " e.g. `mkfifo pipe` then `while true; do cat pipe && sleep 1; done | kbm -t 8 -I -d ref.fa -i - -Hk 21 -S 4`\n"); fprintf(stdout, " then `cat 1.fq >pipe; cat 2.fq >pipe`, fastq format is better in interaction\n"); fprintf(stdout, " -f Force overwrite\n"); fprintf(stdout, " -t Number of threads, 0: all cores, [1]\n"); fprintf(stdout, " -k Kmer-f size, <= %d, [0]\n", KBM_MAX_KSIZE); fprintf(stdout, " -p Kmer-p size, <= %d, [21]\n", KBM_MAX_KSIZE); fprintf(stdout, " -K Filter high frequency kmers, maybe repetitive, [1000]\n"); fprintf(stdout, " if K >= 1, take the integer value as cutoff, MUST <= 65535\n"); fprintf(stdout, " else, mask the top fraction part high frequency kmers\n"); fprintf(stdout, " -E Min kmer frequency, [1]\n"); fprintf(stdout, " -O Filter low complexity bins (#indexed_kmer less than <-O>), [2]\n"); fprintf(stdout, " -S Subsampling kmers, 1/(<-S>) kmers are indexed, [4.00]\n"); fprintf(stdout, " -S is very useful in saving memeory and speeding up\n"); fprintf(stdout, " please note that subsampling kmers will have less matched length\n"); fprintf(stdout, " -B Select no more than n seeds in a query bin, [256]\n"); // Obsolete //fprintf(stdout, " -G Recognize error kmers in a bin when be aligned >= <-G> times, [0]\n"); fprintf(stdout, " If you are using shared kbmidx by other process using -D too, it will bring wrong behavior\n"); fprintf(stdout, " -D Strand of alignment, 1: forward, 2: reverse, 3: both, [3]\n"); fprintf(stdout, " -X Max number of bin(256bp) in one gap, [4]\n"); fprintf(stdout, " -Y Max number of bin(256bp) in one deviation, [4]\n"); fprintf(stdout, " -Z Max fraction of gapped BINs / aligned BINs, [0.6]\n"); fprintf(stdout, " -x penalty for BIN gap, [-7]\n"); fprintf(stdout, " -y penalty for BIN deviation, [-21]\n"); fprintf(stdout, " -z Enable refine alignment with -p <-z> [0]\n"); fprintf(stdout, " -l Min alignment length, [2048]\n"); fprintf(stdout, " -m Min matched length, [200]\n"); fprintf(stdout, " -s Min similarity, calculated by kmer matched length / aligned length, [0.05]\n"); fprintf(stdout, " -r Max length variation of two aligned fragments, [0.25]\n"); fprintf(stdout, " -c Insist to query contained reads against all\n"); fprintf(stdout, " -C Chainning alignments\n"); fprintf(stdout, " -n Max hits per query, [1000]\n"); #ifdef TEST_MODE fprintf(stdout, " -T For debug, [0]\n"); #endif fprintf(stdout, " -W Dump kbm index to file, [NULL]\n"); fprintf(stdout, " -R Load kbm index from file, [NULL]\n"); fprintf(stdout, " -q Quiet\n"); fprintf(stdout, " -V Print version information and then exit\n"); #if __DEBUG__ fprintf(stdout, " -v Verbose, +\n"); #endif fprintf(stdout, "Server start: {kbm -R start}, will mmap wt.fa.kbmidx into mmeory\n"); fprintf(stdout, "Server list: {kbm -R list [10]}, will list the object tree in file\n"); fprintf(stdout, "Server stop: {kbm -R stop}, will remove the mmap object\n"); return 1; } thread_beg_def(maln); CTGCNS *cc; KBMAux *aux; String *rdtag; BaseBank *rdseqs; u4i qidx; u8i rdoff; u4i rdlen; int corr_mode; float corr_cov; u4i corr_min, corr_max; FILE *out, *lay; int chainning; int interactive; int refine; thread_end_def(maln); thread_beg_func(maln); KBMPar *rpar; KBM *rkbm; KBMAux *raux; kbm_map_t HIT; u4v *tidxs; { rpar = init_kbmpar(); rpar->ksize = 0; rpar->psize = maln->refine; rpar->min_bin_degree = 0; rpar->kmin = 1; rpar->kmax = 1000; rpar->kmer_mod = KBM_N_HASH; rkbm = init_kbm(rpar); raux = init_kbmaux(rkbm); } tidxs = init_u4v(16); thread_beg_loop(maln); if(maln->rdlen == 0) break; if(maln->corr_mode){ if(map_kbmpoa(maln->cc, maln->aux, maln->rdtag->size? maln->rdtag->string : NULL, maln->qidx, maln->rdseqs, maln->rdoff, maln->rdlen, maln->corr_min, maln->corr_max, maln->corr_cov, maln->lay) == 0){ clear_kbmmapv(maln->aux->hits); break; } } else { query_index_kbm(maln->aux, maln->rdtag->size? maln->rdtag->string : NULL, maln->qidx, maln->rdseqs, maln->rdoff, maln->rdlen); map_kbm(maln->aux); if(maln->refine && maln->aux->hits->size){ kbm_read_t *rd; kbm_map_t *hit; u4i i, j, tidx; clear_kbm(rkbm); bitpush_kbm(rkbm, maln->rdtag->size? maln->rdtag->string : NULL, maln->rdtag->size, maln->rdseqs->bits, 0, maln->rdlen); ready_kbm(rkbm); simple_index_kbm(rkbm, 0, rkbm->bins->size); clear_u4v(tidxs); for(i=0;iaux->hits->size;i++){ hit = ref_kbmmapv(maln->aux->hits, i); if(tidxs->size == 0 || hit->tidx != tidxs->buffer[tidxs->size - 1]){ push_u4v(tidxs, hit->tidx); } if(KBM_LOG){ fprintf(maln->out, "#"); fprint_hit_kbm(maln->aux, i, maln->out); } } clear_kbmmapv(maln->aux->hits); clear_bitsvec(maln->aux->cigars); for(i=0;isize;i++){ tidx = get_u4v(tidxs, i); rd = ref_kbmreadv(maln->aux->kbm->reads, tidx); query_index_kbm(raux, rd->tag, tidx, maln->aux->kbm->rdseqs, rd->seqoff * KBM_BIN_SIZE, rd->bincnt * KBM_BIN_SIZE); map_kbm(raux); for(j=0;jhits->size;j++){ flip_hit_kbmaux(maln->aux, raux, j); } } } } if(maln->chainning){ u4i idx, lst; for(idx=lst=0;idx<=maln->aux->hits->size;idx++){ if(idx == maln->aux->hits->size || maln->aux->hits->buffer[lst].tidx != maln->aux->hits->buffer[idx].tidx || maln->aux->hits->buffer[idx].qdir != maln->aux->hits->buffer[lst].qdir){ if(idx > lst + 1){ if(simple_chain_all_maps_kbm(maln->aux->hits->buffer + lst, idx - lst, maln->aux->cigars, &HIT, maln->aux->cigars, maln->aux->par->aln_var)){ maln->aux->hits->buffer[lst++] = HIT; while(lst < idx){ maln->aux->hits->buffer[lst++].mat = 0; } } } lst = idx; } } } if(maln->aux->par->max_hit){ sort_array(maln->aux->hits->buffer, maln->aux->hits->size, kbm_map_t, num_cmpgt(b.mat, a.mat)); if(maln->aux->hits->size > maln->aux->par->max_hit) maln->aux->hits->size = maln->aux->par->max_hit; } if(maln->interactive){ u4i i; thread_beg_syn(maln); for(i=0;iaux->hits->size;i++){ fprint_hit_kbm(maln->aux, i, maln->out); } fflush(maln->out); thread_end_syn(maln); } thread_end_loop(maln); { free_kbmaux(raux); free_kbm(rkbm); free_kbmpar(rpar); } free_u4v(tidxs); thread_end_func(maln); int kbm_main(int argc, char **argv){ cplist *qrys, *refs; char *outf, *loadf, *dumpf; FILE *out, *dump; KBM *kbm; KBMPar *par; KBMAux *aux; BitVec *solids, *rdflags; FileReader *fr; BioSequence *seqs[2], *seq; char regtag[14]; u8i tot_bp, max_bp, opt_flags, nhit; u4i qidx, i; int c, ncpu, buffered_read, overwrite, quiet, tidy_reads, tidy_rdtag, skip_ctn, chainning, interactive, server, tree_maxcnt; int solid_kmer, refine; float fval; thread_preprocess(maln); par = init_kbmpar(); par->rd_len_order = 1; chainning = 0; KBM_LOG = 0; buffered_read = 1; skip_ctn = 1; interactive = 0; solid_kmer = 0; refine = 0; solids = NULL; rdflags = NULL; ncpu = 1; quiet = 0; tidy_reads = 0; tidy_rdtag = -1; max_bp = MAX_U8; qrys = init_cplist(4); refs = init_cplist(4); outf = NULL; loadf = NULL; dumpf = NULL; overwrite = 0; server = 0; tree_maxcnt = 10; opt_flags = 0; while((c = getopt(argc, argv, "hi:d:o:fIt:k:p:K:E:O:S:B:G:D:X:Y:Z:x:y:z:l:m:n:s:cr:CT:W:R:qvV")) != -1){ switch(c){ case 'h': return kbm_usage(); case 'i': push_cplist(qrys, optarg); break; case 'd': push_cplist(refs, optarg); break; case 'L': tidy_reads = atoi(optarg); break; case 'o': outf = optarg; break; case 'f': overwrite = 1; break; case 'I': interactive = 1; break; case 't': ncpu = atoi(optarg); break; case 'k': par->ksize = atoi(optarg); opt_flags |= (1 << 1); break; case 'p': par->psize = atoi(optarg); opt_flags |= (1 << 0); break; case 'K': fval = atof(optarg); par->kmax = fval; par->ktop = fval - par->kmax; break; case 'E': par->kmin = atoi(optarg); break; case 'O': par->min_bin_degree = atoi(optarg); break; case 'S': par->kmer_mod = UInt(atof(optarg) * KBM_N_HASH); opt_flags |= (1 << 2); break; case 'B': par->ksampling = atoi(optarg); break; case 'G': solid_kmer = atoi(optarg); break; case 'D': par->strand_mask = atoi(optarg); break; case 'X': par->max_bgap = atoi(optarg); break; case 'Y': par->max_bvar = atoi(optarg); break; case 'Z': par->max_gap = atof(optarg); break; case 'x': par->pgap = atoi(optarg); break; case 'y': par->pvar = atoi(optarg); break; case 'z': refine = atoi(optarg); break; case 'l': par->min_aln = atoi(optarg) / KBM_BIN_SIZE; break; case 'm': par->min_mat = atoi(optarg); break; case 'n': par->max_hit = atoi(optarg); break; case 's': par->min_sim = atof(optarg); break; case 'r': par->aln_var = atof(optarg); break; case 'c': skip_ctn = 0; break; case 'C': chainning = 1; break; #ifdef TEST_MODE case 'T': par->test_mode = atoi(optarg); break; #endif case 'W': dumpf = optarg; break; case 'R': loadf = optarg; break; case 'q': quiet = 1; break; case 'v': KBM_LOG ++; break; case 'V': fprintf(stdout, "kbm2 %s\n", TOSTR(VERSION)); return 0; default: return kbm_usage(); } } if(quiet){ int devnull; devnull = open("/dev/null", O_WRONLY); dup2(devnull, KBM_LOGFNO); } if(tidy_rdtag == -1){ tidy_rdtag = (tidy_reads >= 0); } if(tidy_reads < 0) tidy_reads = - tidy_reads; BEG_STAT_PROC_INFO(KBM_LOGF, argc, argv); if(par->ksize + par->psize > KBM_MAX_KSIZE){ fprintf(stderr, " -- Invalid kmer size %d+%d=%d > %d in %s -- %s:%d --\n", par->ksize, par->psize, par->ksize + par->psize, KBM_MAX_KSIZE, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); return 1; } out = open_file_for_write(outf, NULL, overwrite); if(refs->size == 0){ if(loadf){ } else if(qrys->size){ append_cplist(refs, qrys); clear_cplist(qrys); } else { fprintf(KBM_LOGF, " ** -h to show document\n"); fflush(KBM_LOGF); push_cplist(refs, "-"); } } if(qrys->size == 0){ par->self_aln = 1; interactive = 0; if(par->kmin < 2) par->kmin = 2; } if(interactive) buffered_read = 0; if(ncpu <= 0){ ncpu = _proc_deamon->ncpu; if(ncpu == 0) ncpu = 1; // failed to get number of cores } if(KBM_LOG > 0){ fprintf(KBM_LOGF, "KBM_LOG_LEVEL = %d\n", KBM_LOG); } if(optind < argc){ server = 0; if(strcasecmp("start", argv[optind]) == 0) server = 1; else if(strcasecmp("stop", argv[optind]) == 0) server = 2; else if(strcasecmp("list", argv[optind]) == 0){ server = 3; if(optind + 1 < argc) tree_maxcnt = atoi(argv[optind + 1]); } if(loadf == NULL) server = 0; } if(loadf){ if(server == 1){ fprintf(KBM_LOGF, "[%s] loading kbm index from %s\n", date(), loadf); kbm = mem_load_obj_file(&kbm_obj_desc, loadf, NULL, NULL, NULL, NULL); fprintf(KBM_LOGF, "[%s] Done. %u sequences, %llu bp, parameter('-k %d -p %d -S %d')\n", date(), (u4i)kbm->reads->size, (u8i)kbm->rdseqs->size, kbm->par->ksize, kbm->par->psize, kbm->par->kmer_mod / KBM_N_HASH); fprintf(KBM_LOGF, "[%s] kbm-index server start\n", date()); return 0; } else if(server == 2){ if(mem_stop_obj_file(loadf)){ fprintf(KBM_LOGF, "[%s] kbm-index server for '%s' stop\n", date(), loadf); } else { fprintf(KBM_LOGF, "[%s] unable to find kbm-index server for '%s'\n", date(), loadf); } return 0; } else if(server == 3){ print_tree_obj_file(stdout, &kbm_obj_desc, loadf, tree_maxcnt, 0); return 0; } else { fprintf(KBM_LOGF, "[%s] loading kbm index from %s\n", date(), loadf); if((kbm = mem_find_obj_file(&kbm_obj_desc, loadf, NULL, NULL, NULL, NULL, 1)) == NULL){ fprintf(KBM_LOGF, " -- cannot find mmap object %s --\n", loadf); fprintf(KBM_LOGF, " -- try read from file --\n"); kbm = mem_read_obj_file(&kbm_obj_desc, loadf, NULL, NULL, NULL, NULL); } } fprintf(KBM_LOGF, "[%s] Done. %u sequences, %llu bp, parameter('-k %d -p %d -S %d')\n", date(), (u4i)kbm->reads->size, (u8i)kbm->rdseqs->size, kbm->par->ksize, kbm->par->psize, kbm->par->kmer_mod / KBM_N_HASH); // Please note that, kbm->tag2idx is not functional after mem_load // check KBMPar if((opt_flags >> 0) & 0x01){ if(kbm->par->psize != par->psize){ fprintf(KBM_LOGF, " ** -p is different, %d != %d\n", kbm->par->psize, par->psize); exit(1); } } else { par->psize = kbm->par->psize; } if((opt_flags >> 1) & 0x01){ if(kbm->par->ksize != par->ksize){ fprintf(KBM_LOGF, " ** -k is different, %d != %d\n", kbm->par->ksize, par->ksize); exit(1); } } else { par->ksize = kbm->par->ksize; } if((opt_flags >> 2) & 0x01){ if(kbm->par->kmer_mod != par->kmer_mod){ fprintf(KBM_LOGF, " ** -S is different, %d != %d\n", kbm->par->kmer_mod / KBM_N_HASH, par->kmer_mod / KBM_N_HASH); exit(1); } } else { par->kmer_mod = kbm->par->kmer_mod; } if((opt_flags >> 3) & 0x01){ if(kbm->par->rd_len_order != par->rd_len_order){ fprintf(KBM_LOGF, " ** par->rd_len_order is different, %d != %d\n", kbm->par->rd_len_order, par->rd_len_order); exit(1); } } else { par->rd_len_order = kbm->par->rd_len_order; } } else { kbm = init_kbm(par); fprintf(KBM_LOGF, "[%s] loading sequences\n", date()); fflush(KBM_LOGF); fr = open_all_filereader(refs->size, refs->buffer, buffered_read); tot_bp = 0; seqs[0] = init_biosequence(); seqs[1] = init_biosequence(); regex_t reg; regmatch_t mats[3]; int z, tag_size, len; z = regcomp(®, "^(.+?)/[0-9]+_[0-9]+$", REG_EXTENDED); if(z){ regerror(z, ®, regtag, 13); fprintf(stderr, " -- REGCOMP: %s --\n", regtag); fflush(stderr); return 1; } { int k = 0; reset_biosequence(seqs[0]); reset_biosequence(seqs[1]); while(1){ int has = readseq_filereader(fr, seqs[k]); if(tidy_reads){ if(has){ if((z = regexec(®, seqs[k]->tag->string, 3, mats, 0)) == 0){ trunc_string(seqs[k]->tag, mats[1].rm_eo); } else if(z != REG_NOMATCH){ regerror(z, ®, regtag, 13); fprintf(stderr, " -- REGEXEC: %s --\n", regtag); fflush(stderr); } //fprintf(stderr, "1: %s len=%d\n", seqs[k]->tag->string, seqs[k]->seq->size); fflush(stderr); //fprintf(stderr, "2: %s len=%d\n", seqs[!k]->tag->string, seqs[!k]->seq->size); fflush(stderr); if(seqs[k]->tag->size == seqs[!k]->tag->size && strcmp(seqs[k]->tag->string, seqs[!k]->tag->string) == 0){ if(seqs[k]->seq->size > seqs[!k]->seq->size){ k = !k; } continue; } else { seq = seqs[!k]; k = !k; } } else { seq = seqs[!k]; } if(seq->seq->size < tidy_reads){ if(has) continue; else break; } if(tidy_rdtag){ sprintf(regtag, "S%010llu", (u8i)kbm->reads->size); clear_string(seq->tag); append_string(seq->tag, regtag, 11); } } else { if(has == 0) break; seq = seqs[k]; } tag_size = seq->tag->size; for(i=0;iseq->size);i+=KBM_MAX_RDLEN){ len = num_min(seq->seq->size - i, KBM_MAX_RDLEN); if(i){ append_string(seq->tag, "_V", 2); add_int_string(seq->tag, i / KBM_MAX_RDLEN); } if(!KBM_LOG && (kbm->reads->size % 10000) == 0){ fprintf(KBM_LOGF, "\r%u", (u4i)kbm->reads->size); fflush(KBM_LOGF); } //fprintf(stderr, " -- %s len=%d in %s -- %s:%d --\n", seq->tag->string, seq->seq->size, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); if(kbm->reads->size >= KBM_MAX_RDCNT){ fprintf(stderr, " -- Read Number Out of Range: %u --\n", (u4i)kbm->reads->size); fflush(stderr); break; } push_kbm(kbm, seq->tag->string, seq->tag->size, seq->seq->string + i, len); if(i){ seq->tag->size = tag_size; seq->tag->string[tag_size] = '\0'; } } tot_bp += seq->seq->size; if(max_bp && tot_bp >= max_bp){ break; } if(has == 0) break; if(kbm->reads->size >= KBM_MAX_RDCNT){ fprintf(stderr, " -- Read Number Out of Range: %u --\n", (u4i)kbm->reads->size); fflush(stderr); break; } } } close_filereader(fr); regfree(®); free_biosequence(seqs[0]); free_biosequence(seqs[1]); if(!KBM_LOG){ fprintf(KBM_LOGF, "\r%u reads", (unsigned)kbm->reads->size); fflush(KBM_LOGF); } ready_kbm(kbm); fprintf(KBM_LOGF, "\n[%s] Done, %u reads, %llu bp, %u bins\n", date(), (u4i)kbm->reads->size, tot_bp, (u4i)kbm->bins->size); fflush(KBM_LOGF); fprintf(KBM_LOGF, "[%s] indexing, %d threads\n", date(), ncpu); index_kbm(kbm, 0, kbm->bins->size, ncpu, NULL); if(dumpf){ u8i size; dump = open_file_for_write(dumpf, NULL, 1); size = mem_dump_obj_file(kbm, 1, &kbm_obj_desc, 1, 0, dump); fclose(dump); fprintf(KBM_LOGF, "[%s] kbm index dumped to %s\n", date(), dumpf); } } fprintf(KBM_LOGF, "[%s] mapping\n", date()); if(solid_kmer && par->self_aln){ solids = init_bitvec((kbm->rdseqs->size >> 1) + 1); } thread_beg_init(maln, ncpu); maln->aux = init_kbmaux(kbm); maln->aux->par = par; // par might be different from kbm->par maln->aux->solids = solids; //maln->aux->bmin = 611077674; //maln->aux->bmax = 611077674 + 172; maln->rdtag = init_string(64); maln->rdseqs = qrys->size? init_basebank() : kbm->rdseqs; maln->rdoff = 0; maln->rdlen = 0; maln->cc = NULL; maln->corr_mode = 0; maln->corr_cov = 0.75; maln->corr_min = 5; maln->corr_max = 10; maln->out = out; maln->lay = NULL; maln->chainning = chainning; maln->interactive = interactive; maln->refine = refine; thread_end_init(maln); if(qrys->size){ int run_mode; fr = open_all_filereader(qrys->size, qrys->buffer, buffered_read); run_mode = 0; if(readline_filereader(fr) > 0){ if(strcasecmp(fr->line->string, "#pairwise_test") == 0){ run_mode = 1; } else if(strcasecmp(fr->line->string, "#print_exists") == 0){ run_mode = 2; } else if(strcasecmp(fr->line->string, "#correct_align") == 0){ run_mode = 3; cns_debug = KBM_LOG; thread_beg_iter(maln); maln->corr_mode = 1; KBMBlock *kb; POGPar par; kb = init_kbmblock(2048, 2048 - 512); par = DEFAULT_POG_PAR; //maln->cc = init_ctgcns(kb, iter_kbmblock, info_kbmblock, 1, 1, 1, maln->corr_max, 200, 100, 1, 96, 2, -5, -2, -4, -1, 16, 3, 0.5, 512); par.refmode = 1; maln->cc = init_ctgcns(kb, iter_kbmblock, info_kbmblock, 1, 1, maln->corr_max, 200, 100, 1, 512, &par); maln->lay = maln->out; thread_end_iter(maln); } else if(strcasecmp(fr->line->string, "#print_read") == 0){ run_mode = 4; } else { rollback_filereader(fr); } } seq = init_biosequence(); qidx = 0; nhit = 0; if(run_mode == 0 || run_mode == 3){ while(readseq_filereader(fr, seq)){ if((qidx % 100) == 0){ fprintf(KBM_LOGF, "\r%u\t%llu", qidx, nhit); fflush(KBM_LOGF); } thread_wait_one(maln); if(maln->rdlen && !maln->interactive){ { aux = maln->aux; for(i=0;ihits->size;i++){ fprint_hit_kbm(aux, i, out); } if(run_mode == 3) fflush(out); nhit += aux->hits->size; } } trunc_string(seq->seq, kbm_cvt_length(seq->seq->size)); clear_basebank(maln->rdseqs); seq2basebank(maln->rdseqs, seq->seq->string, seq->seq->size); clear_string(maln->rdtag); append_string(maln->rdtag, seq->tag->string, seq->tag->size); maln->qidx = qidx ++; maln->rdoff = 0; maln->rdlen = seq->seq->size; thread_wake(maln); } } else if(run_mode == 1){ int nc; u4i tidx; thread_beg_operate(maln, 0); aux = maln->aux; free_basebank(maln->rdseqs); maln->rdseqs = kbm->rdseqs; while((nc = readtable_filereader(fr)) >= 0){ if(nc < 2) continue; qidx = getval_cuhash(kbm->tag2idx, get_col_str(fr, 0)); tidx = getval_cuhash(kbm->tag2idx, get_col_str(fr, 1)); if(qidx == MAX_U4 || tidx == MAX_U4) continue; if(qidx > tidx){ swap_var(qidx, tidx); } maln->qidx = qidx; maln->rdoff = kbm->reads->buffer[qidx].seqoff * KBM_BIN_SIZE; maln->rdlen = kbm->reads->buffer[qidx].bincnt * KBM_BIN_SIZE; aux->bmin = kbm->reads->buffer[tidx].binoff; aux->bmax = kbm->reads->buffer[tidx].binoff + kbm->reads->buffer[tidx].bincnt; fprintf(out, "%s <-> %s\n", kbm->reads->buffer[qidx].tag, kbm->reads->buffer[tidx].tag); thread_wake(maln); thread_wait(maln); if(maln->rdlen && !maln->interactive){ for(i=0;ihits->size;i++){ fprint_hit_kbm(aux, i, out); } nhit += aux->hits->size; } fprintf(out, "//\n"); maln->rdlen = 0; } } else if(run_mode == 2){ kmeroffv *kmers[2]; int nc; kmers[0] = adv_init_kmeroffv(32, 0, 1); kmers[1] = adv_init_kmeroffv(32, 0, 1); while((nc = readtable_filereader(fr)) >= 0){ //fprintf(stdout, "%s\n", fr->line->string); if(nc < 1) continue; qidx = getval_cuhash(kbm->tag2idx, get_col_str(fr, 0)); if(qidx == MAX_U4) continue; print_exists_index_kbm(kbm, kbm->reads->buffer[qidx].tag, kbm->rdseqs, kbm->reads->buffer[qidx].seqoff * KBM_BIN_SIZE, kbm->reads->buffer[qidx].bincnt * KBM_BIN_SIZE, kmers, stdout); } free_kmeroffv(kmers[0]); free_kmeroffv(kmers[1]); } else if(run_mode == 4){ int nc; while((nc = readtable_filereader(fr)) >= 0){ if(nc < 1) continue; if(fr->line->string[0] == '#') continue; qidx = getval_cuhash(kbm->tag2idx, get_col_str(fr, 0)); if(qidx == MAX_U4){ fprintf(out, "#%s NOT FOUND\n", get_col_str(fr, 0)); continue; } fprintf(out, ">%s\n", kbm->reads->buffer[qidx].tag); println_fwdseq_basebank(kbm->rdseqs, kbm->reads->buffer[qidx].seqoff * KBM_BIN_SIZE, kbm->reads->buffer[qidx].bincnt * KBM_BIN_SIZE, out); fflush(out); } } free_filereader(fr); free_biosequence(seq); thread_beg_iter(maln); thread_wait(maln); if(maln->rdlen && !maln->interactive){ aux = maln->aux; for(i=0;ihits->size;i++){ fprint_hit_kbm(aux, i, out); } if(run_mode == 3) fflush(out); nhit += aux->hits->size; maln->rdlen = 0; } thread_end_iter(maln); fprintf(KBM_LOGF, "\r%u\t%llu\n", qidx, (u8i)nhit); fflush(KBM_LOGF); } else { nhit = 0; rdflags = init_bitvec(kbm->reads->size); for(qidx=0;qidxreads->size+ncpu;qidx++){ if(qidx < kbm->reads->size){ thread_wait_one(maln); } else { thread_wait_next(maln); } if(maln->rdlen){ aux = maln->aux; for(i=0;ihits->size;i++){ if(par->test_mode == 0 && skip_ctn){ // whether reads[tidx] is contained by reads[qidx] kbm_map_t *hit; int margin = KBM_BIN_SIZE; hit = ref_kbmmapv(aux->hits, i); if((hit->tb <= margin && hit->te + margin >= (int)kbm->reads->buffer[hit->tidx].bincnt * KBM_BIN_SIZE) && (hit->qb > margin || hit->qe + margin < (int)kbm->reads->buffer[hit->qidx].bincnt * KBM_BIN_SIZE)){ one_bitvec(rdflags, hit->tidx); } } fprint_hit_kbm(aux, i, out); } nhit += aux->hits->size; } if(qidx >= kbm->reads->size || get_bitvec(rdflags, qidx)){ maln->rdlen = 0; continue; } else if((qidx % 100) == 0){ fprintf(KBM_LOGF, "\r%u\t%llu", qidx, nhit); fflush(KBM_LOGF); } maln->qidx = qidx; maln->rdoff = kbm->reads->buffer[qidx].seqoff * KBM_BIN_SIZE; maln->rdlen = kbm->reads->buffer[qidx].bincnt * KBM_BIN_SIZE; thread_wake(maln); } fprintf(KBM_LOGF, "\r%u\t%llu\n", qidx, nhit); fflush(KBM_LOGF); free_bitvec(rdflags); } thread_beg_close(maln); free_kbmaux(maln->aux); free_string(maln->rdtag); if(maln->rdseqs && maln->rdseqs != kbm->rdseqs) free_basebank(maln->rdseqs); if(maln->cc){ free_kbmblock((KBMBlock*)maln->cc->obj); free_ctgcns(maln->cc); } thread_end_close(maln); if(solids) free_bitvec(solids); fprintf(KBM_LOGF, "[%s] Done\n", date()); if(outf) fclose(out); free_cplist(qrys); free_cplist(refs); free_kbmpar(par); if(loadf){ // DON't free kbm, for it is mem_load object } else { free_kbm(kbm); } END_STAT_PROC_INFO(KBM_LOGF); return 0; } int main(int argc, char **argv){ return kbm_main(argc, argv); } wtdbg2-2.5/kbm.h000066400000000000000000002032031353664372200135060ustar00rootroot00000000000000/* * * Copyright (c) 2011, Jue Ruan * * * 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 3 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, see . */ #ifndef __KMER_BINMAP_RJ_H #define __KMER_BINMAP_RJ_H #include "list.h" #include "hashset.h" #include "dna.h" #include "filereader.h" #include "bitvec.h" #include "bitsvec.h" #include "bit2vec.h" #include "thread.h" #include "txtplot.h" //#define __DEBUG__ 1 #define TEST_MODE #define KBM_BIN_BITS 8 #define KBM_BSIZE 256 #define KBM_BIN_SIZE KBM_BSIZE #define KBM_MAX_BINCNT 0xFFFFFFFFFFLLU // 40 bits, 1024 G #define KBM_MAX_RDCNT 0x3FFFFFFF // 30 bits, 1 G #define KBM_MAX_RDBINCNT 0x7FFFFF // 23 bits // able to index reference sequences #define KBM_MAX_RDLEN 0x7FFFFFFFU // 31 bits, 2 G bp #define KBM_MAX_KSIZE 23 #define KBM_MAX_KCNT 0xFFFF // 16 bits, 65535 #define KBM_N_HASH 4096 #define KBM_LOGF stderr #define KBM_LOGFNO STDERR_FILENO static int KBM_LOG = 0; #define KBM_LOG_LOW 1 #define KBM_LOG_MID 2 #define KBM_LOG_HIG 3 #define KBM_LOG_ALL 4 #define KBM_MAX_RDGRP1 0x7FFFFF #define KBM_MAX_RDGRP2 0xFF typedef struct { u8i seqoff:40, flag:24; // seqoff is counted in BIN(256bp) u8i binoff:40, bincnt:23, closed:1; char *tag; } kbm_read_t; define_list(kbmreadv, kbm_read_t); const obj_desc_t kbm_read_t_obj_desc = {"kbm_read_t_obj_desc", sizeof(kbm_read_t), 1, {1}, {offsetof(kbm_read_t, tag)}, {&OBJ_DESC_CHAR_ARRAY}, NULL, NULL}; static inline size_t kbmreadv_deep_obj_desc_cnt(void *list, int idx){ if(idx == 0) return ((kbmreadv*)list)->size; else return 0; } static const obj_desc_t kbmreadv_deep_obj_desc = {.tag = "kbmreadv_deep_obj_desc", .size = sizeof(kbmreadv), .n_child = 1, .mem_type = {1}, .addr = {offsetof(kbmreadv, buffer)}, .desc = {&kbm_read_t_obj_desc}, .cnt = kbmreadv_deep_obj_desc_cnt, .post = NULL}; #define kbm_read_seqoff(rd) ((rd)->seqoff << KBM_BIN_BITS) #define kbm_read_seqlen(rd) ((rd)->bincnt << KBM_BIN_BITS) #define KBM_MAX_BIN_DEGREE 0x1FFU // each BIN takes KBM_BIN_SIZE bp in uncompressed reads typedef struct { u4i ridx:30, off:24, closed:1, degree:9; // off * KBM_BIN_SIZE is the real position } kbm_bin_t; define_list(kbmbinv, kbm_bin_t); typedef struct { u4i bidx; } kbm_bmer_t; define_list(kbmbmerv, kbm_bmer_t); typedef struct { u1i bidx; // bidx = (kbm_baux_t->bidx << 32 | kbm_bmer_t->bidx) u1i dir:1, koff:7; // koff is the real (offset? >> 1), here offset is +0 or +1 } kbm_baux_t; define_list(kbmbauxv, kbm_baux_t); #define getval_bidx(kbm, offset) ((((u8i)((kbm)->sauxs->buffer[offset].bidx)) << 32) | (kbm)->seeds->buffer[offset].bidx) //#define kbm_kmer_smear(K) ((K) ^ ((K) >> 4) ^ ((K) >> 7) ^ ((K) >> 12)) #define kbm_kmer_smear(K) ((K) ^ ((K) >> 4) ^ ((K) >> 7)) typedef struct { u8i mer:46, tot:17, flt:1; } kbm_kmer_t; define_list(kbmkmerv, kbm_kmer_t); #define KBM_KMERCODE(E) ((E).mer) #define KBM_KMEREQUALS(E1, E2) ((E1).mer == (E2).mer) #define KBM_KEYEQUALS(K, E) ((K) == (E).mer) define_hashtable(kbmhash, kbm_kmer_t, KBM_KMERCODE, KBM_KMEREQUALS, u8i, ITSELF, KBM_KEYEQUALS, kbm_kmer_t*, ITSELF); typedef struct { u8i off:40, cnt:24; } kbm_kaux_t; define_list(kbmkauxv, kbm_kaux_t); typedef struct { kbm_kmer_t *mer; kbm_kaux_t *aux; u4i kidx; u4i off:24, dir:1, pdir:1, fine:1, closed:1, extra_bits1:4; u4i qbidx; u4i poffs[2]; u8i bidx, boff, bend; //kbm_bmer_t *b, *end; } kbm_ref_t; define_list(kbmrefv, kbm_ref_t); #if 0 #define heap_cmp_kbm_bmer(refs, a, b) num_cmpx(refs[a].b->bidx, refs[b].b->bidx, refs[a].poffs[refs[a].pdir], refs[b].poffs[refs[b].pdir]) #endif #define heap_cmp_kbm_bmer(refs, a, b) num_cmpx(refs[a]->bidx, refs[b]->bidx, refs[a].poffs[refs[a].pdir], refs[b].poffs[refs[b].pdir]) typedef struct { u4i koff; u4i kcnt:8, kmat:9, boff:15; // offset from the start bin_idx } kbm_cmer_t; define_list(kbmcmerv, kbm_cmer_t); static const kbm_cmer_t KBM_CMER_NULL = {0, 0, 0, 0}; typedef struct { u8i beg:46, mat:16, bt:2; b2i var; u2i gap; b4i score; } kbm_cell_t; static const kbm_cell_t KBM_CELL_NULL = {0, 0, 0, 0, 0, 0}; define_list(kbmcellv, kbm_cell_t); typedef struct { u8i beg, end; u4i mat; int score; } kbm_path_t; define_list(kbmpathv, kbm_path_t); #define kbmpath_hashcode(E) E.beg #define kbmpath_hashequals(E1, E2) (E1).beg == (E2).beg define_hashset(kbmphash, kbm_path_t, kbmpath_hashcode, kbmpath_hashequals); typedef struct { u4i qidx:31, qdir:1; u4i tidx:31, tdir:1; u8i cgoff:40, cglen:24; int qb, qe, tb, te; int mat, cnt, aln, gap; // gap is counted in BINs } kbm_map_t; define_list(kbmmapv, kbm_map_t); typedef struct { int rd_len_order; // 0 int min_bin_degree; // 2 u4i ksize, psize; // 0, 21 u4i kmax, kmin, kmer_mod, ksampling; // 1000, 1, 4.0 * KBM_N_HASH, KBM_BSIZE float ktop; // 0.05 // runtime u4i strand_mask; // 3. 1: forward; 2: reverse; 3: both int self_aln; // 0. 0: map to all; 1: only map to greater read_id; 2: itself but reverse complementary int skip_contained; // 1 u2i max_bgap; // 4 u2i max_bvar; // 4 float max_gap; // 0.6 u8i max_bcnt; // 0xFFFF int pgap, pvar; // -7, -21 u4i max_hit; // 1000 int min_aln, min_mat; // 2048/256, 200 float aln_var; // 0.25 float min_sim; // kmer similarity: 0.05 int test_mode; // see codes } KBMPar; static const obj_desc_t kbmpar_obj_desc = {"kbmpar_obj_desc", sizeof(KBMPar), 0, {}, {}, {}, NULL, NULL}; typedef struct { u8i flags; // 64 bits, 0: mem_load all, 1: mem_load rdseqs+reads; 2: Single Hash Mode;3-63: unused KBMPar *par; BaseBank *rdseqs; u8i avail_bases; u4i avail_reads; kbmreadv *reads; cuhash *tag2idx; kbmbinv *bins; BitVec *binmarks; kbmbmerv *seeds; kbmbauxv *sauxs; kbmhash *hashs[KBM_N_HASH]; kbmkauxv *kauxs[KBM_N_HASH]; } KBM; static inline size_t kbm_obj_desc_cnt(void *kbm, int idx){ UNUSED(kbm); if(idx == 8 || idx == 9) return KBM_N_HASH; else return 1; } static inline void rebuild_tag2idx_kbm(void *kbm, size_t aux); static const obj_desc_t kbm_obj_desc = {.tag = "kbm_obj_desc", .size = sizeof(KBM), .n_child = 10, .mem_type = {1, 1, 1, 1, 1, 1, 1, 1, 2, 2}, .addr = {offsetof(KBM, par), offsetof(KBM, rdseqs), offsetof(KBM, reads), offsetof(KBM, tag2idx), offsetof(KBM, bins), offsetof(KBM, binmarks), offsetof(KBM, seeds), offsetof(KBM, sauxs), offsetof(KBM, hashs), offsetof(KBM, kauxs)}, .desc = {&kbmpar_obj_desc, &basebank_obj_desc, &kbmreadv_deep_obj_desc, &cuhash_obj_desc, &kbmbinv_obj_desc, &bitvec_obj_desc, &kbmbmerv_obj_desc, &kbmbauxv_obj_desc, &kbmhash_obj_desc, &kbmkauxv_obj_desc}, kbm_obj_desc_cnt, rebuild_tag2idx_kbm }; // Please note that, kbm->tag2idx is not functional after mem_load, because we use cuhash_obj_desc instread of cuhash_deep_obj_desc typedef struct { #if 0 u4i poff, bidx; u4i refidx:26, koff:6; #endif u4i poff; u4i refidx; u8i bidx:40, koff:24; } kbm_dpe_t; define_list(kbmdpev, kbm_dpe_t); typedef struct { kbmdpev *kms; // kmer offset in query and bidx u4i km_len; BitVec *cmask; // bit for kbm_cmer_t kbmcmerv *cms; u4v *coffs; // kbm_cmer_t offset for each bin BitVec *rmask[2]; kbmcellv *cells[2]; Bit2Vec *bts; // back trace flag: 0: diagonal, 1: horizontal, 2: vertical kbmphash *paths; // storing best unique paths by now u8i boff; u8i last_bidx; } KBMDP; typedef struct { u8i kmer; u4i off; u4i kidx:30, dir:1, closed:1; } kmer_off_t; define_list(kmeroffv, kmer_off_t); typedef struct { KBM *kbm; KBMPar *par; // can diff from kbm->par char *qtag; BaseBank *qseqs; u8i qsoff; u4i qlen, slen, qnbin, qnbit; u4i qidx; u8i bmin, bmax; kmeroffv *koffs[2]; kbmrefv *refs; u4v *rank, **heaps; u4i nheap; u4i hptr; u2i *binmap; u4i bmlen, bmoff, bmcnt; kbmdpev *caches[2]; KBMDP *dps[2]; kbmmapv *hits; BitsVec *cigars; BitVec *solids; String *str; } KBMAux; static inline KBMPar* init_kbmpar(){ KBMPar *par; par = malloc(sizeof(KBMPar)); par->rd_len_order = 0; par->min_bin_degree = 2; par->ksize = 0; par->psize = 21; par->kmax = 1000; par->kmin = 1; par->kmer_mod = 4 * KBM_N_HASH; par->ksampling = KBM_BSIZE; par->ktop = 0.05; par->strand_mask = 3; par->self_aln = 0; par->skip_contained = 1; par->max_bgap = 4; // 4 * KBM_BIN_SIZE par->max_bvar = 4; par->max_bcnt = 0xFFFF; par->max_gap = 0.6; par->pgap = -7; par->pvar = -21; par->max_hit = 1000; par->min_aln = 2048 / KBM_BIN_SIZE; par->min_mat = 200; par->min_sim = 0.05; par->aln_var = 0.25; par->test_mode = 0; return par; } static inline void free_kbmpar(KBMPar *par){ free(par); } static inline KBM* init_kbm(KBMPar *par){ KBM *kbm; u4i i; kbm = malloc(sizeof(KBM)); kbm->flags = 0; kbm->par = par; kbm->rdseqs = init_basebank(); kbm->avail_bases = 0; kbm->avail_reads = 0; kbm->reads = init_kbmreadv(64); kbm->tag2idx = init_cuhash(1023); kbm->bins = init_kbmbinv(64); kbm->binmarks = init_bitvec(1024); //kbm->kfs = NULL; kbm->seeds = init_kbmbmerv(64); kbm->sauxs = init_kbmbauxv(64); for(i=0;ihashs[i] = init_kbmhash(1023); for(i=0;ikauxs[i] = init_kbmkauxv(64); return kbm; } static inline void free_kbm(KBM *kbm){ u4i i; if(kbm->flags & 0x1) return; if(kbm->flags & 0x2){ } else { free_basebank(kbm->rdseqs); for(i=0;ireads->size;i++){ if(kbm->reads->buffer[i].tag) free(kbm->reads->buffer[i].tag); } free_kbmreadv(kbm->reads); } free_cuhash(kbm->tag2idx); free_kbmbinv(kbm->bins); free_bitvec(kbm->binmarks); //if(kbm->kfs) free(kbm->kfs); free_kbmbmerv(kbm->seeds); free_kbmbauxv(kbm->sauxs); for(i=0;ihashs[i]); for(i=0;ikauxs[i]); free(kbm); } static inline void reset_index_kbm(KBM *kbm){ u4i i; if(kbm->flags & 0x04){ free_kbmhash(kbm->hashs[0]); kbm->hashs[0] = init_kbmhash(1023); free_kbmkauxv(kbm->kauxs[0]); kbm->kauxs[0] = init_kbmkauxv(64); } else { for(i=0;ihashs[i]); kbm->hashs[i] = init_kbmhash(1023); free_kbmkauxv(kbm->kauxs[i]); kbm->kauxs[i] = init_kbmkauxv(64); } } free_kbmbmerv(kbm->seeds); kbm->seeds = init_kbmbmerv(64); free_kbmbauxv(kbm->sauxs); kbm->sauxs = init_kbmbauxv(64); //zeros_bitvec(kbm->binmarks); } static inline void clear_kbm(KBM *kbm){ u4i i; if(kbm->flags & 0x1) return; if(kbm->flags & 0x2){ } else { clear_basebank(kbm->rdseqs); for(i=0;ireads->size;i++){ if(kbm->reads->buffer[i].tag) free(kbm->reads->buffer[i].tag); } clear_kbmreadv(kbm->reads); clear_cuhash(kbm->tag2idx); } clear_kbmbinv(kbm->bins); clear_bitvec(kbm->binmarks); for(i=0;ihashs[i]); kbm->hashs[i] = init_kbmhash(1023); free_kbmkauxv(kbm->kauxs[i]); kbm->kauxs[i] = init_kbmkauxv(64); if(kbm->flags & 0x04) break; } clear_kbmbmerv(kbm->seeds); clear_kbmbauxv(kbm->sauxs); } #define kbm_cvt_length(seqlen) ((seqlen) & (MAX_U8 << KBM_BIN_BITS)) static inline void push_kbm(KBM *kbm, char *tag, int taglen, char *seq, u4i seqlen){ kbm_read_t *rd; char *ptr; if(taglen){ ptr = malloc(taglen + 1); memcpy(ptr, tag, taglen); ptr[taglen] = 0; } else { ptr = NULL; } if(seqlen > KBM_MAX_RDLEN) seqlen = KBM_MAX_RDLEN; seqlen = kbm_cvt_length(seqlen); rd = next_ref_kbmreadv(kbm->reads); rd->seqoff = (kbm->rdseqs->size >> KBM_BIN_BITS); rd->flag = 0; rd->binoff = 0; rd->bincnt = seqlen / KBM_BIN_SIZE; rd->closed = 0; rd->tag = ptr; seq2basebank(kbm->rdseqs, seq, seqlen); } static inline void bitpush_kbm(KBM *kbm, char *tag, int taglen, u8i *seqs, u8i seqoff, u4i seqlen){ kbm_read_t *rd; char *ptr; if(taglen){ ptr = malloc(taglen + 1); memcpy(ptr, tag, taglen); ptr[taglen] = 0; } else { ptr = NULL; } if(seqlen > KBM_MAX_RDLEN) seqlen = KBM_MAX_RDLEN; seqlen = kbm_cvt_length(seqlen); rd = next_ref_kbmreadv(kbm->reads); rd->seqoff = (kbm->rdseqs->size >> KBM_BIN_BITS); rd->flag = 0; rd->binoff = 0; rd->bincnt = seqlen / KBM_BIN_SIZE; rd->closed = 0; rd->tag = ptr; fast_fwdbits2basebank(kbm->rdseqs, seqs, seqoff, seqlen); } // Please call no more than once static inline u8i filter_reads_kbm(KBM *kbm, u8i retain_size, int strategy){ u8i m, b, e, len; if(kbm->reads->size == 0) return 0; if(retain_size == 0 || retain_size >= kbm->rdseqs->size) return kbm->rdseqs->size; if((kbm->flags & 0x2) == 0){ if(kbm->par->rd_len_order){ sort_array(kbm->reads->buffer, kbm->reads->size, kbm_read_t, num_cmpgt(b.bincnt, a.bincnt)); if(strategy == 0){ // longest len = 0; for(e=0;ereads->size;e++){ len += kbm->reads->buffer[e].bincnt * KBM_BIN_SIZE; if(len >= retain_size) break; } kbm->reads->size = e; } else if(strategy == 1){ // median m = kbm->reads->size / 2; len = kbm->reads->buffer[m].bincnt * KBM_BIN_SIZE; e = m; for(b=0;b<=m&&lenreads->buffer[m - b].bincnt * KBM_BIN_SIZE; len += kbm->reads->buffer[m + b].bincnt * KBM_BIN_SIZE; } e = b * 2; b = m - b; if(b){ remove_array_kbmreadv(kbm->reads, 0, b); } kbm->reads->size = e; } else { return kbm->rdseqs->size; } return len; } else { return kbm->rdseqs->size; } } else { return kbm->rdseqs->size; } } static inline void ready_kbm(KBM *kbm){ kbm_read_t *rd; u4i i, j; if((kbm->flags & 0x2) == 0){ if(kbm->par->rd_len_order){ sort_array(kbm->reads->buffer, kbm->reads->size, kbm_read_t, num_cmpgt(b.bincnt, a.bincnt)); } encap_basebank(kbm->rdseqs, KBM_BSIZE); } clear_kbmbinv(kbm->bins); for(i=0;ireads->size;i++){ rd = ref_kbmreadv(kbm->reads, i); if(rd->tag) put_cuhash(kbm->tag2idx, (cuhash_t){rd->tag, i}); if((kbm->flags & 0x2) == 0) rd->binoff = kbm->bins->size; for(j=0;jbincnt;j++){ push_kbmbinv(kbm->bins, (kbm_bin_t){i, j, 0, 0}); } if((kbm->flags & 0x2) == 0) rd->bincnt = j; } clear_bitvec(kbm->binmarks); encap_bitvec(kbm->binmarks, kbm->bins->size); kbm->binmarks->n_bit = kbm->bins->size; zeros_bitvec(kbm->binmarks); } // Share seqs, reads static inline KBM* clone_seqs_kbm(KBM *src, KBMPar *par){ KBM *dst; dst = init_kbm(par); free_basebank(dst->rdseqs); free_kbmreadv(dst->reads); dst->rdseqs = src->rdseqs; dst->reads = src->reads; dst->flags = 1LLU << 1; ready_kbm(dst); // Notice encap_basebank in ready_kbm return dst; } // rs[0]->n_head MUST >= 1 static inline void split_FIXP_kmers_kbm(BaseBank *rdseqs, u8i offset, u4i length, u1i ksize, u1i psize, u4i kmod, kmeroffv *rs[2]){ kmer_off_t *kp; u8i kmer, krev, hv, npz, kmask, p, pmask; u4i ki, npl; int i, j; u1i c, b, kshift, pshift, kpshf; clear_kmeroffv(rs[0]); clear_kmeroffv(rs[1]); kshift = (ksize - 1) << 1; kmask = (1LLU << (ksize << 1)) - 1LLU; pshift = (psize - 1) << 1; pmask = (1LLU << (psize << 1)) - 1LLU; kpshf = psize << 1; if(ksize){ // scan F-part of kmers kmer = krev = 0; for(i=0;i+1bits, offset + i); kmer = (kmer << 2) | c; krev = (krev >> 2) | (((u8i)((~c) & 0x3)) << kshift); } for(;i<(int)length;i++){ c = bits2bit(rdseqs->bits, offset + i); kmer = ((kmer << 2) | c) & kmask; krev = (krev >> 2) | (((u8i)((~c) & 0x3)) << kshift); if(kmer < krev){ push_kmeroffv(rs[0], (kmer_off_t){kmer, i - (ksize - 1), 0, 0, 1}); } else if(krev < kmer){ push_kmeroffv(rs[1], (kmer_off_t){krev, i - (ksize - 1), 0, 1, 1}); } } if(psize){ // scan P-part of forward kmers assert(rs[0]->n_head > 0); memset(rs[0]->buffer - 1, 0, sizeof(kmer_off_t)); // rs[0]->n_head > 0 rs[0]->buffer[-1].off = length; npz = 0; npl = 0; kp = rs[0]->buffer + rs[0]->size - 1; b = 4; for(i=length-1;i>=0;i--){ if(kp->off + (ksize - 1) == (u4i)i){ if(npl >= psize){ p = npz & pmask; kp->closed = 0; kp->kmer = (kp->kmer << kpshf) | p; } kp --; } c = bits2revbit(rdseqs->bits, offset + i); if(c == b){ } else { npz = (npz << 2) | c; npl ++; b = c; } } // scan P-part of reverse kmers encap_kmeroffv(rs[1], 1); memset(rs[1]->buffer + rs[1]->size, 0xFF, sizeof(kmer_off_t)); npz = 0; npl = 0; kp = rs[1]->buffer; b = 4; for(i=0;i<(int)length;i++){ if(kp->off == (u4i)(i)){ if(npl >= psize){ p = npz & pmask; kp->closed = 0; kp->kmer = (kp->kmer << kpshf) | p; kp->off = kp->off - psize; } kp ++; } c = bits2bit(rdseqs->bits, offset + i); if(c == b){ } else { npz = (npz << 2) | c; npl ++; b = c; } } } else { for(i=0;(u4i)isize;i++) rs[0]->buffer[i].closed = 0; for(i=0;(u4i)isize;i++) rs[1]->buffer[i].closed = 0; } } else if(psize){ kmer = krev = 0; b = 4; for(i=j=0;i<(int)length;i++){ c = bits2bit(rdseqs->bits, offset + i); if(b == c) continue; b = c; kmer = ((kmer << 2) | c) & pmask; krev = (krev >> 2) | (((u8i)((~c) & 0x3)) << pshift); j ++; if(j < psize) continue; if(kmer < krev){ push_kmeroffv(rs[0], (kmer_off_t){kmer, i - (psize - 1), 0, 0, 0}); } else if(krev < kmer){ push_kmeroffv(rs[1], (kmer_off_t){krev, i - (psize - 1), 0, 1, 0}); } } } for(b=0;b<2;b++){ for(i=0;(u4i)isize;i++){ if(rs[b]->buffer[i].closed) continue; hv = kbm_kmer_smear(rs[b]->buffer[i].kmer); ki = hv % kmod; if(ki >= KBM_N_HASH) rs[b]->buffer[i].closed = 1; rs[b]->buffer[i].kidx = ki; } } } static inline u8i seed2solid_idx_kbm(KBM *kbm, kbm_dpe_t *p){ kbm_bin_t *b; kbm_read_t *rd; u8i seqoff; b = kbm->bins->buffer + p->bidx; rd = kbm->reads->buffer + b->ridx; seqoff = (((rd->seqoff + b->off) * KBM_BSIZE) >> 1) + p->koff; return seqoff; } static inline u8i rdoff2solid_idx_kbm(KBM *kbm, u4i ridx, u4i roff){ kbm_read_t *rd; u8i seqoff; rd = kbm->reads->buffer + ridx; seqoff = (rd->seqoff * KBM_BIN_SIZE + roff) >> 1; return seqoff; } #define binoff2solid_koff_kbm(kbm, bidx, boff) ((boff) >> 1) typedef struct { u8i mer:50, kidx:14; u8i bidx; u4i cnt:22, koff:8, dir:1, used:1; } kbm_midx_t; define_list(kbmmidxv, kbm_midx_t); typedef struct { u8i bidx; kbm_baux_t aux; } kbm_tmp_bmer_t; define_list(tmpbmerv, kbm_tmp_bmer_t); thread_beg_def(midx); KBM *kbm; u8i beg, end; // (end - beg) * KBM_BSIZE MUST <= KBM_KMEROFF_MAX u8i ktot, nrem, Nrem, none, nflt, offset; u8i srem, Srem; u8i *cnts, n_cnt; int task; int cal_degree; pthread_mutex_t *locks; thread_end_def(midx); thread_beg_func(midx); KBM *kbm; kbm_bin_t *bin; kbmmidxv **kidxs; kbm_midx_t *mx; kmer_off_t *f; kbm_kmer_t *u; kbm_kaux_t *x; kmeroffv *kmers[2]; tmpbmerv *bms; u8i bidx, off; u4i i, j, k, len, ncpu, tidx, kidx; int exists; kbm = midx->kbm; ncpu = midx->n_cpu; tidx = midx->t_idx; kmers[0] = adv_init_kmeroffv(64, 0, 1); kmers[1] = adv_init_kmeroffv(64, 0, 1); kidxs = malloc(KBM_N_HASH * sizeof(kbmmidxv*)); for(i=0;itask == 1){ // counting kmers for(i=0;ibeg+tidx;bidxend;bidx+=ncpu){ if(KBM_LOG == 0 && tidx == 0 && ((bidx - midx->beg) % 100000) == 0){ fprintf(KBM_LOGF, "\r%llu", bidx - midx->beg); fflush(KBM_LOGF); } bin = ref_kbmbinv(kbm->bins, bidx); if(bin->closed) continue; off = (kbm->reads->buffer[bin->ridx].seqoff + bin->off) * KBM_BIN_SIZE; len = KBM_BIN_SIZE; split_FIXP_kmers_kbm(kbm->rdseqs, off, len, kbm->par->ksize, kbm->par->psize, kbm->par->kmer_mod, kmers); for(i=0;i<2;i++){ for(j=0;jsize;j++){ f = ref_kmeroffv(kmers[i], j); if(f->closed) continue; mx = next_ref_kbmmidxv(kidxs[f->kidx]); mx->mer = f->kmer; mx->kidx = f->kidx; mx->bidx = bidx; mx->dir = i; mx->koff = f->off; if(kidxs[f->kidx]->size >= 64){ kidx = f->kidx; // lock hashs[kidx] pthread_mutex_lock(midx->locks + kidx); // hash adding for(k=0;ksize;k++){ mx = ref_kbmmidxv(kidxs[kidx], k); u = prepare_kbmhash(kbm->hashs[kidx], mx->mer, &exists); if(exists){ if(u->tot < KBM_MAX_KCNT) u->tot ++; } else { u->mer = mx->mer; u->tot = 1; u->flt = 0; } } // free hashs[f->kidx] pthread_mutex_unlock(midx->locks + kidx); clear_kbmmidxv(kidxs[kidx]); } } } } for(kidx=0;kidxsize){ // lock hashs[kidx] pthread_mutex_lock(midx->locks + kidx); // hash adding for(k=0;ksize;k++){ mx = ref_kbmmidxv(kidxs[kidx], k); u = prepare_kbmhash(kbm->hashs[kidx], mx->mer, &exists); if(exists){ if(u->tot < KBM_MAX_KCNT) u->tot ++; } else { u->mer = mx->mer; u->tot = 1; u->flt = 0; } } // free hashs[f->kidx] pthread_mutex_unlock(midx->locks + kidx); clear_kbmmidxv(kidxs[kidx]); } } } else if(midx->task == 2){ // delete low freq kmers for(i=tidx;ihashs[i]); while((u = ref_iter_kbmhash(kbm->hashs[i]))){ if(u->tot < kbm->par->kmin){ delete_kbmhash(kbm->hashs[i], u); } } } } else if(midx->task == 3){ // stat kmer counts memset(midx->cnts, 0, midx->n_cnt * sizeof(u8i)); for(i=tidx;ihashs[i]); while((u = ref_iter_kbmhash(kbm->hashs[i]))){ midx->cnts[num_min(midx->n_cnt, u->tot) - 1] ++; } } } else if(midx->task == 4){ // stat counts midx->offset = 0; for(i=tidx;ihashs[i]); while((u = ref_iter_kbmhash(kbm->hashs[i]))){ x = ref_kbmkauxv(kbm->kauxs[i], offset_kbmhash(kbm->hashs[i], u)); x->off = midx->offset; x->cnt = 0; midx->ktot += u->tot; if(u->tot < kbm->par->kmin){ u->flt = 1; } else if(u->tot > kbm->par->kmax){ u->flt = 1; } else { midx->offset += u->tot; } } } } else if(midx->task == 5){ // revise offset for(i=tidx;ikauxs[i]->size;off++) kbm->kauxs[i]->buffer[off].off += midx->offset; } } else if(midx->task == 6){ // fill seeds for(i=0;ibeg+tidx;bidxend;bidx+=ncpu){ if(KBM_LOG == 0 && tidx == 0 && ((bidx - midx->beg) % 100000) == 0){ fprintf(KBM_LOGF, "\r%llu", bidx - midx->beg); fflush(KBM_LOGF); } bin = ref_kbmbinv(kbm->bins, bidx); if(bin->closed) continue; bin->degree = 0; off = (kbm->reads->buffer[bin->ridx].seqoff + bin->off) * KBM_BIN_SIZE; len = KBM_BIN_SIZE; split_FIXP_kmers_kbm(kbm->rdseqs, off, len, kbm->par->ksize, kbm->par->psize, kbm->par->kmer_mod, kmers); clear_u4v(chgs); for(i=0;i<2;i++){ for(j=0;jsize;j++){ f = ref_kmeroffv(kmers[i], j); if(f->closed) continue; mx = next_ref_kbmmidxv(kidxs[f->kidx]); mx->mer = f->kmer; mx->kidx = f->kidx; mx->bidx = bidx; mx->dir = i; mx->koff = f->off; if(kidxs[f->kidx]->size == 64){ push_u4v(chgs, f->kidx); } } } for(i=0;isize;i++){ kidx = chgs->buffer[i]; if(kidxs[kidx]->size == 0) continue; pthread_mutex_lock(midx->locks + kidx); for(k=0;ksize;k++){ mx = ref_kbmmidxv(kidxs[kidx], k); u = get_kbmhash(kbm->hashs[kidx], mx->mer); if(u && u->flt == 0){ x = ref_kbmkauxv(kbm->kauxs[kidx], offset_kbmhash(kbm->hashs[kidx], u)); kbm->bins->buffer[mx->bidx].degree ++; if(x->cnt < u->tot){ if(x->cnt && getval_bidx(kbm, x->off + x->cnt - 1) == mx->bidx && kbm->sauxs->buffer[x->off + x->cnt - 1].dir == mx->dir){ // repeated kmer within one bin } else { kbm->seeds->buffer[x->off + x->cnt].bidx = mx->bidx & MAX_U4; kbm->sauxs->buffer[x->off + x->cnt].bidx = mx->bidx >> 32; kbm->sauxs->buffer[x->off + x->cnt].dir = mx->dir; kbm->sauxs->buffer[x->off + x->cnt].koff = mx->koff >> 1; x->cnt ++; } } } } pthread_mutex_unlock(midx->locks + kidx); clear_kbmmidxv(kidxs[kidx]); } } for(kidx=0;kidxsize){ // lock hashs[kidx] pthread_mutex_lock(midx->locks + kidx); // hash adding for(k=0;ksize;k++){ mx = ref_kbmmidxv(kidxs[kidx], k); u = get_kbmhash(kbm->hashs[kidx], mx->mer); if(u && u->flt == 0){ x = ref_kbmkauxv(kbm->kauxs[kidx], offset_kbmhash(kbm->hashs[kidx], u)); kbm->bins->buffer[mx->bidx].degree ++; if(x->cnt < u->tot){ if(x->cnt && getval_bidx(kbm, x->off + x->cnt - 1) == mx->bidx && kbm->sauxs->buffer[x->off + x->cnt - 1].dir == mx->dir){ // repeated kmer within one bin } else { kbm->seeds->buffer[x->off + x->cnt].bidx = mx->bidx & MAX_U4; kbm->sauxs->buffer[x->off + x->cnt].bidx = mx->bidx >> 32; kbm->sauxs->buffer[x->off + x->cnt].dir = mx->dir; kbm->sauxs->buffer[x->off + x->cnt].koff = mx->koff >> 1; x->cnt ++; } } } } // free hashs[f->kidx] pthread_mutex_unlock(midx->locks + kidx); clear_kbmmidxv(kidxs[kidx]); } } free_u4v(chgs); } else if(midx->task == 7){ // count added kmers midx->srem = midx->Srem = 0; for(i=tidx;ihashs[i]); while((u = ref_iter_kbmhash(kbm->hashs[i]))){ x = ref_kbmkauxv(kbm->kauxs[i], offset_kbmhash(kbm->hashs[i], u)); if(x->cnt){ midx->srem ++; midx->Srem += x->cnt; } } } } else if(midx->task == 8){ // sort seeds within a kmer for(i=tidx;ihashs[i]); while((u = ref_iter_kbmhash(kbm->hashs[i]))){ x = ref_kbmkauxv(kbm->kauxs[i], offset_kbmhash(kbm->hashs[i], u)); if(x->cnt < 2) continue; clear_tmpbmerv(bms); for(j=0;jcnt;j++){ push_tmpbmerv(bms, (kbm_tmp_bmer_t){getval_bidx(kbm, x->off + j), kbm->sauxs->buffer[x->off + j]}); } sort_array(bms->buffer, bms->size, kbm_tmp_bmer_t, num_cmpgt(a.bidx, b.bidx)); kbm->seeds->buffer[x->off + 0].bidx = bms->buffer[0].bidx & MAX_U4; kbm->sauxs->buffer[x->off + 0].bidx = bms->buffer[0].bidx >> 32; kbm->sauxs->buffer[x->off + 0] = bms->buffer[0].aux; len = 1; for(j=1;jcnt;j++){ if(bms->buffer[j].bidx < bms->buffer[j - 1].bidx){ continue; } kbm->seeds->buffer[x->off + len].bidx = bms->buffer[j].bidx & MAX_U4; kbm->sauxs->buffer[x->off + len].bidx = bms->buffer[0].bidx >> 32; kbm->sauxs->buffer[x->off + len] = bms->buffer[j].aux; len ++; } x->cnt = len; } } } thread_end_loop(midx); free_kmeroffv(kmers[0]); free_kmeroffv(kmers[1]); for(i=0;iseeds); for(i=0;ihashs[i]); kcnts = NULL; MAX = KBM_MAX_KCNT; hash_locks = calloc(KBM_N_HASH, sizeof(pthread_mutex_t)); thread_beg_init(midx, ncpu); midx->kbm = kbm; midx->beg = beg; midx->end = end; midx->cnts = NULL; midx->n_cnt = MAX; midx->task = 0; midx->cal_degree = 0; midx->locks = hash_locks; thread_end_init(midx); fprintf(KBM_LOGF, "[%s] - scanning kmers (K%dP%dS%0.2f) from %llu bins\n", date(), kbm->par->ksize, kbm->par->psize, 1.0 * kbm->par->kmer_mod / KBM_N_HASH, end - beg); b = e = beg; thread_apply_all(midx, midx->task = 1); if(KBM_LOG == 0){ fprintf(KBM_LOGF, "\r%llu bins\n", end - beg); fflush(KBM_LOGF); } kcnts = calloc(MAX, sizeof(u8i)); thread_beg_iter(midx); midx->cnts = calloc(MAX, sizeof(u8i)); midx->task = 3; // counting raw kmers thread_wake(midx); thread_end_iter(midx); thread_beg_iter(midx); thread_wait(midx); for(i=0;icnts[i]; thread_end_iter(midx); if(kmstat){ fprintf(kmstat, "#Reads: %llu\n", (u8i)kbm->reads->size); fprintf(kmstat, "#Bases: %llu bp\n", (u8i)kbm->rdseqs->size); fprintf(kmstat, "#K%dP%dS%0.2f\n", kbm->par->ksize, kbm->par->psize, 1.0 * kbm->par->kmer_mod / KBM_N_HASH); for(i=0;i+1task = 2); // freeze hash to save memory and speed up the query for(i=0;ihashs[i]->count); fflush(KBM_LOGF); if((i % 8) == 7){ fprintf(KBM_LOGF, "\n"); fflush(KBM_LOGF); } } freeze_kbmhash(kbm->hashs[i], 1.0 / 16); free_kbmkauxv(kbm->kauxs[i]); kbm->kauxs[i] = init_kbmkauxv(kbm->hashs[i]->count); kbm->kauxs[i]->size = kbm->hashs[i]->count; } print_proc_stat_info(0); ktot = nrem = Nrem = none = nflt = ktyp = 0; for(i=0;i+1par->kmin){ none += kcnts[i]; } else { ktyp += kcnts[i] * (i + 1); } } if(kbm->par->ktop){ off = 0; for(i=MAX;i>kbm->par->kmin;i--){ off += kcnts[i-1] * i; if(off >= (ktyp * kbm->par->ktop)) break; } if(i > kbm->par->kmax){ kbm->par->kmax = i; } fprintf(KBM_LOGF, "[%s] - high frequency kmer depth is set to %d\n", date(), kbm->par->kmax); } for(i=kbm->par->kmin? kbm->par->kmin - 1 : 0;ipar->kmax;i++){ nrem += kcnts[i]; Nrem += kcnts[i] * (i + 1); } for(i=kbm->par->kmax;i+1task = 4); thread_beg_iter(midx); cnt = midx->offset; midx->offset = off; off += cnt; midx->task = 5; thread_wake(midx); thread_end_iter(midx); thread_wait_all(midx); clear_and_encap_kbmbmerv(kbm->seeds, off + 1); kbm->seeds->size = off; free_kbmbauxv(kbm->sauxs); kbm->sauxs = init_kbmbauxv(off + 1); kbm->sauxs->size = off; kavg = Nrem / (nrem + 1); fprintf(KBM_LOGF, "[%s] - Total kmers = %llu\n", date(), ktot); fprintf(KBM_LOGF, "[%s] - average kmer depth = %d\n", date(), kavg); fprintf(KBM_LOGF, "[%s] - %llu low frequency kmers (<%d)\n", date(), none, kbm->par->kmin); fprintf(KBM_LOGF, "[%s] - %llu high frequency kmers (>%d)\n", date(), nflt, kbm->par->kmax); fprintf(KBM_LOGF, "[%s] - indexing %llu kmers, %llu instances (at most)\n", date(), nrem, Nrem); thread_apply_all(midx, midx->task = 6); if(KBM_LOG == 0){ fprintf(KBM_LOGF, "\r%llu bins\n", end - beg); fflush(KBM_LOGF); } thread_apply_all(midx, midx->task = 7); srem = Srem = 0; thread_beg_iter(midx); srem += midx->srem; Srem += midx->Srem; thread_end_iter(midx); fprintf(KBM_LOGF, "[%s] - indexed %llu kmers, %llu instances\n", date(), srem, Srem); { n = 0; for(i=beg;ibins->buffer[i].degree < kbm->par->min_bin_degree){ kbm->bins->buffer[i].closed = 1; one_bitvec(kbm->binmarks, i); n ++; } } index_bitvec(kbm->binmarks); fprintf(KBM_LOGF, "[%s] - masked %llu bins as closed\n", date(), n); } fprintf(KBM_LOGF, "[%s] - sorting\n", date()); thread_apply_all(midx, midx->task = 8); if(kcnts) free(kcnts); thread_beg_close(midx); if(midx->cnts) free(midx->cnts); thread_end_close(midx); free(hash_locks); print_proc_stat_info(0); } static inline void simple_index_kbm(KBM *kbm, u8i beg, u8i end){ kbm_bin_t *bin; kbm_kmer_t *u; kbm_kaux_t *x; kmeroffv *kmers[2]; tmpbmerv *bms; kmer_off_t *f; u8i bidx, off; u4i i, j, len; int exists; kbm->flags |= 1LLU << 2; kmers[0] = adv_init_kmeroffv(64, 0, 1); kmers[1] = adv_init_kmeroffv(64, 0, 1); bms = init_tmpbmerv(KBM_MAX_KCNT); // count kmers { for(bidx=beg;bidxbins, bidx); if(bin->closed) continue; off = (kbm->reads->buffer[bin->ridx].seqoff + bin->off) * KBM_BIN_SIZE; split_FIXP_kmers_kbm(kbm->rdseqs, off, KBM_BIN_SIZE, kbm->par->ksize, kbm->par->psize, kbm->par->kmer_mod, kmers); for(i=0;i<2;i++){ for(j=0;jsize;j++){ f = ref_kmeroffv(kmers[i], j); if(f->closed) continue; u = prepare_kbmhash(kbm->hashs[0], f->kmer, &exists); if(exists){ if(u->tot < KBM_MAX_KCNT) u->tot ++; } else { u->mer = f->kmer; u->tot = 1; u->flt = 0; } } } } } // delete low freq kmers if(kbm->par->kmin){ reset_iter_kbmhash(kbm->hashs[0]); while((u = ref_iter_kbmhash(kbm->hashs[0]))){ if(u->tot < kbm->par->kmin){ delete_kbmhash(kbm->hashs[0], u); } } } // freeze hash { freeze_kbmhash(kbm->hashs[0], 1.0 / 16); free_kbmkauxv(kbm->kauxs[0]); kbm->kauxs[0] = init_kbmkauxv(kbm->hashs[0]->count); kbm->kauxs[0]->size = kbm->hashs[0]->count; } // encap seeds { off = 0; reset_iter_kbmhash(kbm->hashs[0]); while((u = ref_iter_kbmhash(kbm->hashs[0]))){ x = ref_kbmkauxv(kbm->kauxs[0], offset_kbmhash(kbm->hashs[0], u)); x->off = off; x->cnt = 0; if(u->tot < kbm->par->kmin){ // Never happens u->flt = 1; } else if(kbm->par->kmax && u->tot > kbm->par->kmax){ u->flt = 1; } else { off += u->tot; } } clear_and_encap_kbmbmerv(kbm->seeds, off + 1); kbm->seeds->size = off; clear_and_encap_kbmbauxv(kbm->sauxs, off + 1); kbm->sauxs->size = off; } // fill seeds { for(bidx=beg;bidxbins, bidx); if(bin->closed) continue; off = (kbm->reads->buffer[bin->ridx].seqoff + bin->off) * KBM_BIN_SIZE; split_FIXP_kmers_kbm(kbm->rdseqs, off, KBM_BIN_SIZE, kbm->par->ksize, kbm->par->psize, kbm->par->kmer_mod, kmers); for(i=0;i<2;i++){ for(j=0;jsize;j++){ f = ref_kmeroffv(kmers[i], j); if(f->closed) continue; u = get_kbmhash(kbm->hashs[0], f->kmer); if(u == NULL || u->flt) continue; x = ref_kbmkauxv(kbm->kauxs[0], offset_kbmhash(kbm->hashs[0], u)); kbm->bins->buffer[bidx].degree ++; if(x->cnt < u->tot){ if(x->cnt && getval_bidx(kbm, x->off + x->cnt - 1) == bidx && kbm->sauxs->buffer[x->off + x->cnt - 1].dir == i){ // repeated kmer within one bin } else { kbm->seeds->buffer[x->off + x->cnt].bidx = bidx & MAX_U4; kbm->sauxs->buffer[x->off + x->cnt].bidx = bidx >> 32; kbm->sauxs->buffer[x->off + x->cnt].dir = i; kbm->sauxs->buffer[x->off + x->cnt].koff = f->off >> 1; x->cnt ++; } } } } } } // sort seeds within a kmer { reset_iter_kbmhash(kbm->hashs[0]); while((u = ref_iter_kbmhash(kbm->hashs[0]))){ x = ref_kbmkauxv(kbm->kauxs[0], offset_kbmhash(kbm->hashs[0], u)); clear_tmpbmerv(bms); for(j=0;jcnt;j++){ push_tmpbmerv(bms, (kbm_tmp_bmer_t){getval_bidx(kbm, x->off + j), kbm->sauxs->buffer[x->off + j]}); } sort_array(bms->buffer, bms->size, kbm_tmp_bmer_t, num_cmpgt(a.bidx, b.bidx)); kbm->seeds->buffer[x->off + 0].bidx = bms->buffer[0].bidx & MAX_U4; kbm->sauxs->buffer[x->off + 0].bidx = bms->buffer[0].bidx >> 32; kbm->sauxs->buffer[x->off + 0] = bms->buffer[0].aux; len = 1; for(j=1;jcnt;j++){ if(bms->buffer[j].bidx < bms->buffer[j - 1].bidx){ continue; } kbm->seeds->buffer[x->off + len].bidx = bms->buffer[j].bidx & MAX_U4; kbm->sauxs->buffer[x->off + len].bidx = bms->buffer[0].bidx >> 32; kbm->sauxs->buffer[x->off + len] = bms->buffer[j].aux; len ++; } x->cnt = len; } } free_kmeroffv(kmers[0]); free_kmeroffv(kmers[1]); free_tmpbmerv(bms); } static inline KBMDP* init_kbmdp(){ KBMDP *dp; dp = malloc(sizeof(KBMDP)); dp->kms = init_kbmdpev(1024); dp->km_len = 0; dp->cmask = init_bitvec(1024); dp->cms = init_kbmcmerv(64); dp->coffs = init_u4v(32); dp->rmask[0] = init_bitvec(256); dp->rmask[1] = init_bitvec(256); dp->cells[0] = init_kbmcellv(16); dp->cells[1] = init_kbmcellv(16); dp->bts = init_bit2vec(1024); dp->paths = init_kbmphash(13); dp->boff = 0; dp->last_bidx = 0; return dp; } static inline void reset_kbmdp(KBMDP *dp, KBMAux *aux, u8i bidx){ //clear_kbmdpev(dp->kms); //dp->km_len = 0; clear_bitvec(dp->cmask); clear_kbmcmerv(dp->cms); clear_u4v(dp->coffs); recap_bitvec(dp->rmask[0], aux->qnbit); zeros_bitvec(dp->rmask[0]); recap_bitvec(dp->rmask[1], aux->qnbit); zeros_bitvec(dp->rmask[1]); recap_kbmcellv(dp->cells[0], aux->qnbin); recap_kbmcellv(dp->cells[1], aux->qnbin); clear_bit2vec(dp->bts); if(dp->paths->size > 1024 * 10){ free_kbmphash(dp->paths); dp->paths = init_kbmphash(1023); } else { clear_kbmphash(dp->paths); } dp->boff = bidx; dp->last_bidx = bidx; } static inline void clear_kbmdp(KBMDP *dp, KBMAux *aux, u8i bidx){ reset_kbmdp(dp, aux , bidx); clear_kbmdpev(dp->kms); dp->km_len = 0; } static inline void free_kbmdp(KBMDP *dp){ free_kbmdpev(dp->kms); free_bitvec(dp->cmask); free_kbmcmerv(dp->cms); free_u4v(dp->coffs); free_bitvec(dp->rmask[0]); free_bitvec(dp->rmask[1]); free_kbmcellv(dp->cells[0]); free_kbmcellv(dp->cells[1]); free_bit2vec(dp->bts); free_kbmphash(dp->paths); free(dp); } static inline KBMAux* init_kbmaux(KBM *kbm){ KBMAux *aux; aux = malloc(sizeof(KBMAux)); aux->kbm = kbm; aux->par = kbm->par; aux->qtag = NULL; aux->qseqs = NULL; aux->qsoff = 0; aux->qlen = 0; aux->slen = 0; aux->qidx = 0; aux->qnbin = 0; aux->qnbit = (aux->qnbin + 63) & 0xFFFFFFC0U; aux->bmin = 0; aux->bmax = MAX_U8; aux->koffs[0] = adv_init_kmeroffv(32, 0, 1); aux->koffs[1] = adv_init_kmeroffv(32, 0, 1); aux->refs = init_kbmrefv(64); aux->rank = init_u4v(64); aux->nheap = 1024; aux->heaps = malloc((aux->nheap + 1) * sizeof(u4v*)); { u4i i; for(i=0;i<=aux->nheap;i++){ aux->heaps[i] = init_u4v(8); } } aux->bmlen = 1; aux->bmoff = 0; aux->bmcnt = aux->kbm->bins->size; aux->binmap = NULL; aux->caches[0] = init_kbmdpev(64); aux->caches[1] = init_kbmdpev(64); aux->dps[0] = init_kbmdp(); aux->dps[1] = init_kbmdp(); aux->hits = init_kbmmapv(16); aux->cigars = init_bitsvec(1024, 3); aux->solids = NULL; aux->str = init_string(1024); return aux; } static inline void free_kbmaux(KBMAux *aux){ free_kmeroffv(aux->koffs[0]); free_kmeroffv(aux->koffs[1]); free_kbmrefv(aux->refs); free_u4v(aux->rank); if(aux->heaps){ u4i i; for(i=0;i<=aux->nheap;i++){ if(aux->heaps[i]) free_u4v(aux->heaps[i]); } free(aux->heaps); } if(aux->binmap) free(aux->binmap); free_kbmdpev(aux->caches[0]); free_kbmdpev(aux->caches[1]); free_kbmdp(aux->dps[0]); free_kbmdp(aux->dps[1]); free_kbmmapv(aux->hits); free_bitsvec(aux->cigars); free_string(aux->str); free(aux); } static inline void query_index_kbm(KBMAux *aux, char *qtag, u4i qidx, BaseBank *rdseqs, u8i seqoff, u4i seqlen){ KBM *kbm; KBMPar *par; kbm_kmer_t *u; kbm_kaux_t *x; kmer_off_t *f; kbm_ref_t *ref; u8i sidx, bmin, bmax; u4i hidx, next; u4i i, j, l, tot, mr, pdir; kbm = aux->kbm; par = aux->par; aux->qtag = qtag? qtag : kbm->reads->buffer[qidx].tag; aux->qseqs = rdseqs; aux->qsoff = seqoff; aux->qlen = seqlen; aux->slen = (seqlen / KBM_BIN_SIZE) * KBM_BIN_SIZE; aux->qidx = qidx; aux->qnbin = aux->slen / KBM_BIN_SIZE; aux->qnbit = (aux->qnbin + 63) & 0xFFFFFFC0U; clear_kbmdp(aux->dps[0], aux, 0); clear_kbmdp(aux->dps[1], aux, 0); clear_kbmrefv(aux->refs); clear_u4v(aux->rank); clear_kbmdpev(aux->caches[0]); clear_kbmdpev(aux->caches[1]); clear_kbmmapv(aux->hits); clear_bitsvec(aux->cigars); #ifdef TEST_MODE if(par->test_mode >= 7) return; #endif bmin = par->self_aln? kbm->reads->buffer[qidx].binoff + kbm->reads->buffer[qidx].bincnt : 0; if(bmin < aux->bmin) bmin = aux->bmin; bmax = aux->bmax; if(par->self_aln == 2){ par->strand_mask = 2; // 1: forward; 2: reverse; 3: both } split_FIXP_kmers_kbm(rdseqs, seqoff, aux->slen, par->ksize, par->psize, par->kmer_mod, aux->koffs); #ifdef TEST_MODE if(par->test_mode >= 6) return; #endif tot = 0; for(i=0;i<2;i++){ next = 0; for(j=0;jkoffs[i]->size;j++){ f = ref_kmeroffv(aux->koffs[i], j); if(f->closed) continue; if(kbm->flags & (1LLU << 2)) f->kidx = 0; u = get_kbmhash(kbm->hashs[f->kidx], f->kmer); if(u == NULL || u->flt || u->tot < par->kmin){ continue; } x = ref_kbmkauxv(kbm->kauxs[f->kidx], offset_kbmhash(kbm->hashs[f->kidx], u)); ref = next_ref_kbmrefv(aux->refs); ref->mer = u; ref->aux = x; ref->kidx = f->kidx; ref->off = f->off; ref->dir = i; if(par->self_aln && aux->solids){ sidx = (kbm->reads->buffer[qidx].seqoff * KBM_BIN_SIZE + ref->off) >> 1; ref->fine = get_bitvec(aux->solids, sidx); } else { ref->fine = 0; } ref->qbidx = ref->off / KBM_BIN_SIZE; ref->poffs[0] = ref->off; ref->poffs[1] = aux->slen - (ref->off + (aux->par->ksize + aux->par->psize)); ref->boff = x->off; ref->bend = x->off + x->cnt; ref->bidx = getval_bidx(kbm, x->off); ref->closed = 0; { // Refine boundray if(par->self_aln == 2){ // reverse complementary only while(ref->boff < ref->bend && getval_bidx(kbm, ref->bend - 1) > bmin){ ref->bend --; } } while(ref->boff < ref->bend){ if(ref->bidx < bmin){ ref->boff ++; ref->bidx = getval_bidx(kbm, ref->boff); continue; //} else if(ref->b->bidx >= bmax){ //break; } break; } while(ref->bend > ref->boff){ if(getval_bidx(kbm, ref->bend - 1) > bmax){ ref->bend --; } else { break; } } if(ref->boff >= ref->bend){ ref->closed = 1; } } if(ref->closed){ aux->refs->size --; continue; } tot += x->cnt; } } if(0){ //sort_array(aux->refs->buffer, aux->refs->size, kbm_ref_t, num_cmpgt(a.off, b.off)); for(i=0;irefs->size;i++){ ref = ref_kbmrefv(aux->refs, i); fprintf(KBM_LOGF, "%s\t%d\t%c\t%d\n", aux->qtag, ref->off, "+-"[ref->dir], (int)ref->aux->cnt); } } if(par->self_aln && aux->solids){ // Obsolete sort_array(aux->refs->buffer, aux->refs->size, kbm_ref_t, num_cmpgt(a.off, b.off)); tot = 0; next = 0; for(i=0;irefs->size;i++){ ref = ref_kbmrefv(aux->refs, i); if(ref->closed){ continue; } else if(ref->fine){ tot += ref->bend - ref->boff; next = ref->off + (aux->par->ksize + aux->par->psize) / 2 + 1; } else if(ref->off >= next){ tot += ref->bend - ref->boff; } else { ref->boff = ref->bend; ref->closed = 1; } } } else if(aux->par->ksampling < KBM_BIN_SIZE && aux->refs->size){ sort_array(aux->refs->buffer, aux->refs->size, kbm_ref_t, num_cmpgtx(a.qbidx, b.qbidx, b.bend - b.boff, a.bend - a.boff)); tot = 0; for(i=j=0;irefs->size;i++){ if(aux->refs->buffer[i].qbidx != aux->refs->buffer[j].qbidx){ if(aux->refs->buffer[j].qbidx){ // skip the first and last bin if((i - j) > aux->par->ksampling){ l = j + aux->par->ksampling; for(;jrefs->buffer[j].bend - aux->refs->buffer[j].boff; } for(;jrefs->buffer[j].boff = aux->refs->buffer[j].bend; aux->refs->buffer[j].bidx = getval_bidx(kbm, aux->refs->buffer[j].boff); aux->refs->buffer[j].closed = 1; } } } j = i; } } //sort_array(aux->refs->buffer, aux->refs->size, kbm_ref_t, num_cmpgt(a.off, b.off)); } sort_array(aux->refs->buffer, aux->refs->size, kbm_ref_t, num_cmpgt(a.off, b.off)); // estimate binmap aux->bmoff = 0; if(aux->refs->size){ mr = aux->par->min_mat / (aux->par->ksize + aux->par->psize); if(mr < 512) mr = 512; aux->bmlen = tot / mr; if(aux->bmlen == 0) aux->bmlen = 1; aux->bmcnt = (aux->kbm->bins->size + aux->bmlen - 1) / aux->bmlen; if(aux->bmcnt < aux->qnbin * 50){ aux->bmcnt = aux->qnbin * 50; aux->bmlen = (aux->kbm->bins->size + aux->bmcnt - 1) / aux->bmcnt; } } else { aux->bmlen = 1; aux->bmcnt = aux->kbm->bins->size; } if(0 && aux->bmlen > aux->nheap){ aux->bmlen = aux->nheap; aux->bmcnt = (aux->kbm->bins->size + aux->bmlen - 1) / aux->bmlen; } //fprintf(stderr, " -- %s tot=%d bmlen=%d bmcnt=%d mr=%d in %s -- %s:%d --\n", aux->qtag, tot, aux->bmlen, aux->bmcnt, tot / aux->bmlen, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); for(i=0;inheap&&ibmlen;i++){ clear_u4v(aux->heaps[i]); } //fprintf(stderr, " -- %s tot=%d avg=%d bmlen=%d bmcnt=%d mr=%d qnbin=%d in %s -- %s:%d --\n", aux->qtag, tot, tot / aux->bmlen, aux->bmlen, aux->bmcnt, mr, aux->qnbin, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); #ifdef TEST_MODE if(par->test_mode >= 5) return; #endif // init heaps for(i=0;irefs->size;i++){ ref = ref_kbmrefv(aux->refs, i); while(ref->boff < ref->bend){ if(0){ pdir = (ref->dir ^ kbm->sauxs->buffer[ref->boff].dir); if(((aux->par->strand_mask >> pdir) & 0x01) == 0){ ref->boff ++; ref->bidx = getval_bidx(aux->kbm, ref->boff); continue; } } hidx = ref->bidx / aux->bmcnt; if(hidx - aux->bmoff < aux->nheap){ push_u4v(aux->heaps[hidx - aux->bmoff], i); } break; } } aux->hptr = 0; } static inline void print_exists_index_kbm(KBM *kbm, char *qtag, BaseBank *rdseqs, u8i seqoff, u4i seqlen, kmeroffv *kmers[2], FILE *out){ KBMPar *par; kbm_kmer_t *u; kbm_kaux_t *x; kmer_off_t *f; u4i i, j; par = kbm->par; split_FIXP_kmers_kbm(rdseqs, seqoff, seqlen, par->ksize, par->psize, par->kmer_mod, kmers); for(i=0;i<2;i++){ for(j=0;jsize;j++){ f = ref_kmeroffv(kmers[i], j); if(f->closed) continue; if(kbm->flags & 0x04) f->kidx = 0; u = get_kbmhash(kbm->hashs[f->kidx], f->kmer); if(u == NULL){ continue; } x = ref_kbmkauxv(kbm->kauxs[f->kidx], offset_kbmhash(kbm->hashs[f->kidx], u)); fprintf(out, "%s\t%d\t%c\t0x%llx\t%u\t%u\t%c\n", qtag, f->off, "+-"[f->dir], f->kmer, x->cnt, u->tot, "YN"[u->flt]); } } } static inline int _update_dp_path_kbm(KBMDP *dp, u8i end, kbm_cell_t *c){ int exists; kbm_path_t *p, P; P.beg = c->beg; p = prepare_kbmphash(dp->paths, P, &exists); if(exists){ if(p->score < c->score){ p->end = end; p->mat = c->mat; p->score = c->score; } else { return 0; } } else { p->beg = c->beg; p->end = end; p->mat = c->mat; p->score = c->score; } return 1; } static inline void _dp_cal_spare_row_kbm(KBMAux *aux, int dir){ KBMDP *dp; kbmcellv *cells[2]; BitVec *masks[2]; kbm_cmer_t *m; kbm_cell_t D, H, V; u4i i, n, ni, rowoff; u8i bitoff, celoff; int flg, is_gap, score; dp = aux->dps[dir]; flg = (dp->last_bidx - dp->boff) & 0x01; cells[0] = dp->cells[flg]; cells[1] = dp->cells[!flg]; masks[0] = dp->rmask[flg]; masks[1] = dp->rmask[!flg]; rowoff = dp->coffs->buffer[dp->last_bidx - dp->boff]; bitoff = (dp->last_bidx - dp->boff) * aux->qnbit; celoff = (dp->last_bidx - dp->boff) * aux->qnbin; // update cells' mask to be calculated by new coming kbm_cmer_t for(i=0;iqnbit;i+=64){ masks[1]->bits[i >> 6] = masks[0]->bits[i >> 6] | dp->cmask->bits[(i + bitoff) >> 6]; } // dp core H = KBM_CELL_NULL; i = next_one_bitvec(masks[1], 0); D = (i && get_bitvec(masks[0], i - 1))? cells[0]->buffer[i - 1] : KBM_CELL_NULL; reg_zeros_bitvec(masks[0], 0, i); encap_bit2vec(dp->bts, aux->qnbin); n = 0; while(i < aux->qnbin){ if(get_bitvec(dp->cmask, i + bitoff)){ is_gap = 0; m = ref_kbmcmerv(dp->cms, rowoff + n); score = m->kmat + m->kcnt; n ++; } else { is_gap = 1; m = (kbm_cmer_t*)&KBM_CMER_NULL; score = aux->par->pgap; } // horizontal { H.score += score; H.mat += m->kmat; //H.gap = 0; } if(H.var < 0){ H.score += - aux->par->pvar; // score increases for abs(var) decreased } else { H.score += aux->par->pvar; } H.var ++; H.bt = 1; // horizontal backtrace, insertion for query sequence // diagonal { D.score += score; D.mat += m->kmat; //D.gap = 0; } D.var = 0; // whether to reset var D.bt = 0; // diagonal backtrace if(D.score >= H.score){ H = D; } // vertical V = D = get_bitvec(masks[0], i)? cells[0]->buffer[i] : KBM_CELL_NULL; { V.score += score; V.mat += m->kmat; //V.gap = 0; } if(V.var > 0){ V.score += - aux->par->pvar; // score increases for abs(var) decreased } else { V.score += aux->par->pvar; } V.var --; V.bt = 2; // vertical backtrace if(V.score > H.score){ H = V; } if(is_gap){ H.gap ++; } else { H.gap = 0; } set_bit2vec(dp->bts, dp->bts->size + i, H.bt); // init new path ID when there is no progenitor if(H.beg == 0){ H.beg = 1 + i + celoff; } #if __DEBUG__ if(KBM_LOG >= KBM_LOG_ALL){ fprintf(KBM_LOGF, "KBMLOG%d [x=%d, y=%llu, beg=%llu, score=%d, gap=%d, var=%d, bt=%d]\n", __LINE__, i, dp->last_bidx, (u8i)H.beg, H.score, H.gap, H.var, H.bt); } #endif if(H.score > 0 && H.gap <= aux->par->max_bgap && num_abs(H.var) <= aux->par->max_bvar){ // set cell, move next one_bitvec(masks[1], i); cells[1]->buffer[i] = H; if(is_gap == 0 && H.mat >= aux->par->min_mat) _update_dp_path_kbm(dp, 1 + i + celoff, &H); i ++; } else if(D.score > 0){ // move next, may have diagonal hit zero_bitvec(masks[1], i); H = KBM_CELL_NULL; i ++; } else { zero_bitvec(masks[1], i); ni = next_one_bitvec(masks[1], i + 1); if(i + 1 < ni){ reg_zeros_bitvec(masks[1], i + 1, ni); D = H = KBM_CELL_NULL; } i = ni; } } // prepare next row //NEXT_ROW: push_u4v(dp->coffs, dp->cms->size); zero_bitvec(dp->cmask, dp->cmask->n_bit); dp->cmask->n_bit += aux->qnbit; one_bitvec(dp->cmask, dp->cmask->n_bit); dp->bts->size += aux->qnbin; dp->last_bidx ++; } static inline int _backtrace_map_kbm(KBMAux *aux, int dir, kbm_path_t *p){ KBMDP *dp; kbm_map_t *hit; kbm_cmer_t *c; u8i cgoff, sidx; u4i i, mat, cnt, gap, cglen; int tmp, x, y, bt, lst; dp = aux->dps[dir]; hit = next_ref_kbmmapv(aux->hits); hit->qidx = aux->qidx; hit->qdir = dir; hit->tidx = aux->kbm->bins->buffer[dp->boff + p->beg / aux->qnbin].ridx; hit->tdir = 0; hit->qb = p->beg % aux->qnbin; hit->qe = p->end % aux->qnbin; hit->tb = p->beg / aux->qnbin; hit->te = p->end / aux->qnbin; hit->aln = num_min(hit->qe - hit->qb, hit->te - hit->tb); hit->aln ++; if(hit->aln < aux->par->min_aln){ aux->hits->size --; return 0; } cgoff = aux->cigars->size; cglen = 0; cnt = 0; mat = 0; gap = 0; x = hit->qe; y = hit->te; lst = 0; while(x >= hit->qb && y >= hit->tb){ bt = get_bit2vec(dp->bts, x + y * aux->qnbin); if(get_bitvec(dp->cmask, x + y * aux->qnbit)){ c = ref_kbmcmerv(dp->cms, rank_bitvec(dp->cmask, x + y * aux->qnbit)); cnt += c->kcnt; mat += c->kmat; // try merge 'ID' or 'DI' into 'M' if(lst == 0){ if(bt == 0){ push_bitsvec(aux->cigars, 0); } lst = bt; } else if(bt == 0){ push_bitsvec(aux->cigars, lst); push_bitsvec(aux->cigars, 0); lst = 0; } else if(bt == lst){ push_bitsvec(aux->cigars, lst); } else { push_bitsvec(aux->cigars, 0); lst = 0; } } else { gap ++; if(lst){ push_bitsvec(aux->cigars, lst); } lst = 0; push_bitsvec(aux->cigars, 0x4 | bt); } switch(bt){ case 0: x --; y --; break; case 1: x --; break; default: y --; break; } } if(lst){ push_bitsvec(aux->cigars, lst); } cglen = aux->cigars->size - cgoff; if(mat < (u4i)aux->par->min_mat || mat < UInt(hit->aln * KBM_BSIZE * aux->par->min_sim) || gap > (u4i)(hit->aln * aux->par->max_gap) || hit->aln < (int)aux->par->min_aln || num_diff(hit->qe - hit->qb, hit->te - hit->tb) > (int)num_max(aux->par->aln_var * hit->aln, 1.0)){ aux->hits->size --; aux->cigars->size = cgoff; return 0; } if(aux->par->self_aln && aux->solids){ // Obsolete x = hit->qe; y = hit->te; while(x >= hit->qb && y >= hit->tb){ bt = get_bit2vec(dp->bts, x + y * aux->qnbin); if(get_bitvec(dp->cmask, x + y * aux->qnbit)){ c = ref_kbmcmerv(dp->cms, rank_bitvec(dp->cmask, x + y * aux->qnbit)); for(i=0;ikcnt;i++){ sidx = seed2solid_idx_kbm(aux->kbm, dp->kms->buffer + c->koff + i); one_bitvec(aux->solids, sidx); // Thread-unsafe, but no hurt } } else { } switch(bt){ case 0: x --; y --; break; case 1: x --; break; default: y --; break; } } } hit->qe = (hit->qe + 1); hit->tb = (dp->boff + hit->tb - aux->kbm->reads->buffer[hit->tidx].binoff); hit->te = (dp->boff + hit->te - aux->kbm->reads->buffer[hit->tidx].binoff + 1); hit->mat = mat; hit->cnt = cnt; hit->gap = gap; hit->cgoff = cgoff; hit->cglen = cglen; if(dir){ tmp = aux->qnbin - hit->qb; hit->qb = aux->qnbin - hit->qe; hit->qe = tmp; } #if __DEBUG__ if(KBM_LOG){ fprintf(KBM_LOGF, "HIT\tQ[%d]\t%c\t%d\t%d", hit->qidx, "+-"[hit->qdir], hit->qb, hit->qe); fprintf(KBM_LOGF, "\tT[%d]\t%c\t%d\t%d", hit->tidx, "+-"[hit->tdir], hit->tb, hit->te); fprintf(KBM_LOGF, "\t%d\t%d\t%d\t%d\n", hit->mat, hit->aln, hit->cnt, hit->gap); } #endif return 1; } static inline int check_hit_cigar_kbm(kbm_map_t *hit, BitsVec *cigars){ u4i i, bt; int x, y; x = y = -1; i = hit->cglen; while(i){ bt = get_bitsvec(cigars, hit->cgoff + i - 1); bt = bt & 0x03; x += (0b0011 >> bt) & 0x01; y += (0b0101 >> bt) & 0x01; i --; } return !(x + 1 + hit->qb == hit->qe && y + 1 + hit->tb == hit->te); } static inline void print_hit_kbm(KBM *kbm, char *qtag, u4i qlen, kbm_map_t *hit, BitsVec *cigars, String *_str, FILE *out){ String *str; u8i coff; u4i clen, len, bt, _bt; if(hit->mat == 0) return; fprintf(out, "%s\t%c\t%d\t%d\t%d", qtag, "+-"[hit->qdir], qlen, hit->qb * KBM_BIN_SIZE, hit->qe * KBM_BIN_SIZE); fprintf(out, "\t%s\t%c\t%d\t%d\t%d", kbm->reads->buffer[hit->tidx].tag, "+-"[hit->tdir], kbm->reads->buffer[hit->tidx].bincnt * KBM_BIN_SIZE, hit->tb * KBM_BIN_SIZE, hit->te * KBM_BIN_SIZE); fprintf(out, "\t%d\t%d\t%d\t%d\t", hit->mat, hit->aln * KBM_BIN_SIZE, hit->cnt, hit->gap); if(cigars){ str = _str? _str : init_string(64); bt = len = 0; coff = hit->cgoff; clen = hit->cglen; clear_string(str); while(clen){ _bt = get_bitsvec(cigars, coff + clen - 1); if(_bt == bt){ len ++; } else { if(len > 1){ add_int_string(str, len); add_char_string(str, "MID?mid?"[bt]); } else if(len == 1){ add_char_string(str, "MID?mid?"[bt]); } bt = _bt; len = 1; } clen --; } if(len > 1){ add_int_string(str, len); add_char_string(str, "MID?mid?"[bt]); } else if(len == 1){ add_char_string(str, "MID?mid?"[bt]); } fputs(str->string, out); if(_str == NULL) free_string(str); } else { fputc('*', out); } fprintf(out, "\n"); } static inline void fprint_hit_kbm(KBMAux *aux, u4i hidx, FILE *out){ kbm_map_t *hit; hit = ref_kbmmapv(aux->hits, hidx); print_hit_kbm(aux->kbm, aux->qtag, aux->slen, hit, aux->cigars, aux->str, out); } static inline void flip_hit_kbmaux(KBMAux *dst, KBMAux *src, u4i hidx){ kbm_map_t *h1, *h2; u4i t, i; h2 = next_ref_kbmmapv(dst->hits); h1 = ref_kbmmapv(src->hits, hidx); //h2->qidx = h1->tidx; h2->qidx = dst->qidx; h2->qdir = h1->qdir; h2->tidx = h1->qidx; h2->tdir = h1->tdir; h2->cgoff = dst->cigars->size; h2->cglen = h1->cglen; h2->qb = h1->tb; h2->qe = h1->te; h2->tb = h1->qb; h2->te = h1->qe; h2->mat = h1->mat; h2->cnt = h1->cnt; h2->aln = h1->aln; h2->gap = h1->gap; if(h1->qdir){ for(i=0;icglen;i++){ t = get_bitsvec(src->cigars, h1->cgoff + h1->cglen - i - 1); if((t & 0x03)){ t = ((~(t & 0x03)) & 0x03) | (t & 0x4); } push_bitsvec(dst->cigars, t); } } else { for(i=0;icglen;i++){ t = get_bitsvec(src->cigars, h1->cgoff + i); if((t & 0x03)){ t = ((~(t & 0x03)) & 0x03) | (t & 0x4); } push_bitsvec(dst->cigars, t); } } } static inline int _dp_path2map_kbm(KBMAux *aux, int dir){ KBMDP *dp; kbm_path_t *p; u4i ret; dp = aux->dps[dir]; ret = 0; index_bitvec_core(dp->cmask, roundup_times(dp->cmask->n_bit, 64 * 8)); reset_iter_kbmphash(dp->paths); while((p = ref_iter_kbmphash(dp->paths))){ p->beg --; // 1-based to 0-based p->end --; #if __DEBUG__ if(KBM_LOG >= KBM_LOG_HIG){ fprintf(KBM_LOGF, "KBMLOG%d\t%d\t%c\tkbm_path_t[%llu(%d:%d),%llu(%d:%d),%d]\n", __LINE__, aux->qidx, "+-"[dir], (u8i)p->beg, (u4i)(p->beg % aux->qnbin), (u4i)((p->beg / aux->qnbin) + dp->boff), (u8i)p->end, (u4i)(p->end % aux->qnbin), (u4i)((p->end / aux->qnbin) + dp->boff), p->score); } #endif if(_backtrace_map_kbm(aux, dir, p)){ ret ++; } } //clear_kbmphash(dp->paths); return ret; } static inline void push_kmer_match_kbm(KBMAux *aux, int dir, kbm_dpe_t *p){ KBM *kbm; KBMDP *dp; kbm_cmer_t *c; kbm_dpe_t *e, E; u8i bb; u4i i, qb, kmat, kcnt, blen; kbm = aux->kbm; dp = aux->dps[dir]; if(p == NULL){ if(dp->kms->size == 0){ dp->km_len = 0; return; } e = ref_kbmdpev(dp->kms, dp->kms->size - 1); if((int)dp->km_len < aux->par->min_mat || e->bidx + 1 < dp->kms->buffer[0].bidx + aux->par->min_aln){ clear_kbmdpev(dp->kms); dp->km_len = aux->par->ksize + aux->par->psize; return; } } else { if(dp->kms->size == 0){ dp->km_len = (aux->par->ksize + aux->par->psize); push_kbmdpev(dp->kms, *p); return; } e = ref_kbmdpev(dp->kms, dp->kms->size - 1); if(e->bidx == p->bidx){ if(p->poff <= e->poff + aux->par->ksize + aux->par->psize){ dp->km_len += p->poff - e->poff; } else { dp->km_len += aux->par->ksize + aux->par->psize; } push_kbmdpev(dp->kms, *p); return; #if __DEBUG__ } else if(p->bidx < e->bidx){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); abort(); #endif } if(e->bidx + aux->par->max_bgap + 1 < p->bidx || dp->kms->buffer[0].bidx + aux->par->max_bcnt < p->bidx || aux->kbm->bins->buffer[e->bidx].ridx != aux->kbm->bins->buffer[p->bidx].ridx){ if(Int(dp->km_len) < aux->par->min_mat || e->bidx + 1 < dp->kms->buffer[0].bidx + aux->par->min_aln){ clear_kbmdpev(dp->kms); push_kbmdpev(dp->kms, *p); dp->km_len = aux->par->ksize + aux->par->psize; return; } } else { dp->km_len += aux->par->ksize + aux->par->psize; push_kbmdpev(dp->kms, *p); return; } } reset_kbmdp(dp, aux, dp->kms->buffer[0].bidx); #ifdef TEST_MODE if(aux->par->test_mode >= 1){ clear_kbmdpev(dp->kms); if(p){ dp->km_len = aux->par->ksize + aux->par->psize; push_kbmdpev(dp->kms, *p); } return; } #endif blen = dp->kms->buffer[dp->kms->size - 1].bidx + 1 - dp->kms->buffer[0].bidx + 2; { push_u4v(dp->coffs, 0); clear_bitvec(dp->cmask); encap_bitvec(dp->cmask, aux->qnbit * blen); reg_zeros_bitvec(dp->cmask, 0, aux->qnbit * blen); dp->cmask->n_bit = aux->qnbit; one_bitvec(dp->cmask, dp->cmask->n_bit); } qb = dp->kms->buffer[0].poff; bb = dp->kms->buffer[0].bidx; kcnt = 0; kmat = aux->par->ksize + aux->par->psize; E.bidx = dp->kms->buffer[dp->kms->size - 1].bidx + 1; E.poff = 0; for(i=0;i<=dp->kms->size;i++){ e = (i < dp->kms->size)? ref_kbmdpev(dp->kms, i) : &E; if(e->bidx == bb && e->poff / KBM_BIN_SIZE == qb / KBM_BIN_SIZE){ kcnt ++; if(qb + aux->par->ksize + aux->par->psize >= e->poff){ kmat += e->poff - qb; } else { kmat += aux->par->ksize + aux->par->psize; } } else { one_bitvec(dp->cmask, (bb - dp->boff) * aux->qnbit + qb / KBM_BIN_SIZE); c = next_ref_kbmcmerv(dp->cms); c->koff = i - kcnt; c->kcnt = kcnt; c->kmat = kmat; c->boff = bb - dp->boff; #if __DEBUG__ if(KBM_LOG >= KBM_LOG_ALL){ fprintf(KBM_LOGF, "KBMLOG%d [x=%d, y=%d(%s:%d), off=%d cnt=%d, mat=%d]\n", __LINE__, qb / KBM_BIN_SIZE, bb, aux->kbm->reads->buffer[aux->kbm->bins->buffer[bb].ridx].tag, bb - aux->kbm->reads->buffer[aux->kbm->bins->buffer[bb].ridx].binoff, c->koff, c->kcnt, c->kmat); } #endif while(bb < e->bidx){ _dp_cal_spare_row_kbm(aux, dir); bb ++; } kcnt = 1; kmat = aux->par->ksize + aux->par->psize; } qb = e->poff; } // flush last row _dp_cal_spare_row_kbm(aux, dir); //collecting maps _dp_path2map_kbm(aux, dir); clear_kbmdpev(dp->kms); if(p) push_kbmdpev(dp->kms, *p); dp->km_len = aux->par->ksize + aux->par->psize; } static inline void map_kbm(KBMAux *aux){ KBM *kbm; kbm_ref_t *ref; kbm_baux_t *saux; u4v *heap; u4i idx, hidx, i, j, pdir; kbm = aux->kbm; #ifdef TEST_MODE if(aux->par->test_mode >= 4) return; #endif while(aux->hptr < aux->bmlen){ if(aux->hptr - aux->bmoff >= aux->nheap){ aux->bmoff += aux->nheap; for(i=0;inheap;i++){ clear_u4v(aux->heaps[i]); } for(i=0;irefs->size;i++){ ref = ref_kbmrefv(aux->refs, i); while(ref->boff < ref->bend){ hidx = ref->bidx / aux->bmcnt; if(hidx - aux->bmoff < aux->nheap){ push_u4v(aux->heaps[hidx - aux->bmoff], i); } break; } } } heap = aux->heaps[aux->hptr - aux->bmoff]; if(heap->size){ clear_kbmdpev(aux->caches[0]); clear_kbmdpev(aux->caches[1]); for(i=0;isize;i++){ idx = heap->buffer[i]; ref = ref_kbmrefv(aux->refs, idx); while(1){ saux = ref_kbmbauxv(kbm->sauxs, ref->boff); pdir = (ref->dir ^ saux->dir); if(((aux->par->strand_mask >> pdir) & 0x01)){ push_kbmdpev(aux->caches[pdir], (kbm_dpe_t){ref->poffs[pdir], idx, ref->bidx, saux->koff}); } ref->boff ++; ref->bidx = getval_bidx(aux->kbm, ref->boff); if(ref->boff >= ref->bend) break; #if __DEBUG__ if(ref->bidx < getval_bidx(aux->kbm, ref->boff - 1)){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); abort(); } #endif hidx = ref->bidx / aux->bmcnt; if(hidx > aux->hptr){ if(hidx - aux->bmoff < aux->nheap){ push_u4v(aux->heaps[hidx - aux->bmoff], idx); } break; } } } { #ifdef TEST_MODE if(aux->par->test_mode <= 2){ #endif if(aux->caches[0]->size * (aux->par->ksize + aux->par->psize) < UInt(aux->par->min_mat)){ aux->caches[0]->size = 0; } else { sort_array(aux->caches[0]->buffer, aux->caches[0]->size, kbm_dpe_t, num_cmpgtx(a.bidx, b.bidx, a.poff, b.poff)); } if(aux->caches[1]->size * (aux->par->ksize + aux->par->psize) < UInt(aux->par->min_mat)){ aux->caches[1]->size = 0; } else { sort_array(aux->caches[1]->buffer, aux->caches[1]->size, kbm_dpe_t, num_cmpgtx(a.bidx, b.bidx, a.poff, b.poff)); } //sort_array(aux->caches[0]->buffer, aux->caches[0]->size, kbm_dpe_t, num_cmpgtx(a.bidx, b.bidx, a.poff, b.poff)); //sort_array(aux->caches[1]->buffer, aux->caches[1]->size, kbm_dpe_t, num_cmpgtx(a.bidx, b.bidx, a.poff, b.poff)); // TODO: sort by bidx+koff is more reasonable, need to modify push_kmer_match_kbm too #ifdef TEST_MODE } #endif #ifdef TEST_MODE if(aux->par->test_mode <= 1){ #endif for(i=0;i<2;i++){ for(j=0;jcaches[i]->size;j++){ #if __DEBUG__ if(KBM_LOG >= KBM_LOG_ALL){ //fprintf(KBM_LOGF, "KBMLOG%d\t%d\t%d\t%c\t%d\t%llu[%d,%d]\t%llu[%d,%d]\n", __LINE__, aux->qidx, ref->poffs[ref->pdir], "+-"[ref->pdir], aux->hptr, ref->bidx, aux->kbm->bins->buffer[ref->bidx].ridx, aux->kbm->bins->buffer[ref->bidx].off * KBM_BIN_SIZE, (u8i)e->bidx, aux->kbm->bins->buffer[e->bidx].ridx, e->poff); } #endif push_kmer_match_kbm(aux, i, aux->caches[i]->buffer + j); } } if(aux->hits->size >= aux->par->max_hit) return; #ifdef TEST_MODE } #endif } } aux->hptr ++; } if(aux->par->strand_mask & 0x01) push_kmer_match_kbm(aux, 0, NULL); if(aux->par->strand_mask & 0x02) push_kmer_match_kbm(aux, 1, NULL); } // KBM's tag2idx is wrongly loaded, need to be corrected static inline void rebuild_tag2idx_kbm(void *_kbm, size_t aux){ KBM *kbm; kbm_read_t *rd; u4i i; UNUSED(aux); kbm = (KBM*)_kbm; clear_cuhash(kbm->tag2idx); // hash size is not changed, thus there won't have hash re-size for(i=0;ireads->size;i++){ rd = ref_kbmreadv(kbm->reads, i); if(rd->tag) put_cuhash(kbm->tag2idx, (cuhash_t){rd->tag, i}); } kbm->flags |= 1LLU << 0; } static inline int simple_chain_all_maps_kbm(kbm_map_t *srcs, u4i size, BitsVec *src_cigars, kbm_map_t *dst, BitsVec *dst_cigars, float max_aln_var){ kbm_map_t *hit; u4i i, x, y, z, f; if(size < 2) return 0; sort_array(srcs, size, kbm_map_t, num_cmpgt(a.tb, b.tb)); *dst = srcs[size - 1]; dst->cgoff = dst_cigars->size; append_bitsvec(dst_cigars, src_cigars, srcs[size - 1].cgoff, srcs[size - 1].cglen); for(i=size-1;i>0;i--){ hit = srcs + i - 1; if(dst->tb < hit->te){ goto FAILED; } else { y = dst->tb - hit->te; dst->tb = hit->tb; } if(dst->qdir){ if(hit->qe > dst->qb){ goto FAILED; } else { x = dst->qb - hit->qe; dst->qb = hit->qb; } } else { if(dst->qb < hit->qe){ goto FAILED; } else { x = dst->qb - hit->qe; dst->qb = hit->qb; } } dst->mat += hit->mat; dst->cnt += hit->cnt; dst->gap += hit->gap; dst->gap += num_max(x, y); z = num_min(x, y); f = 0x4 | 0; // diagonal GAP pushs_bitsvec(dst_cigars, f, z); x -= z; y -= z; if(x > y){ z = x; f = 0x4 | 1; } else { z = y; f = 0x4 | 2; } pushs_bitsvec(dst_cigars, f, z); append_bitsvec(dst_cigars, src_cigars, hit->cgoff, hit->cglen); } dst->aln = num_min(dst->qe - dst->qb, dst->te - dst->tb); if(dst->aln * max_aln_var < num_diff(dst->qe - dst->qb, dst->te - dst->tb)){ goto FAILED; } dst->cglen = dst_cigars->size - dst->cgoff; return 1; FAILED: dst_cigars->size = dst->cgoff; return 0; } #endif wtdbg2-2.5/kbmpoa.h000066400000000000000000000302271353664372200142120ustar00rootroot00000000000000/* * * Copyright (c) 2018, Jue Ruan * * * 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 3 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, see . */ #ifndef KMER_BIN_MAP_PO_MSA_CNS_RJ_H #define KMER_BIN_MAP_PO_MSA_CNS_RJ_H #include "kbm.h" #include "wtpoa.h" typedef struct { u4i chridx, cidx, bidx; String *rdtag; BaseBank *rdseq; u8i rdoff; u4i rdlen; KBMAux *aux; layseqr *seqs; u4v *heap; u2i bsize, bstep; // block size, and slide steps u4i sidx, lidx, hidx; } KBMBlock; static inline KBMBlock* init_kbmblock(u2i bsize, u2i bstep){ KBMBlock *kb; kb = malloc(sizeof(KBMBlock)); kb->rdtag = init_string(1024); kb->rdseq = NULL; kb->rdoff = 0; kb->rdlen = 0; kb->aux = NULL; kb->seqs = init_layseqr(32); kb->heap = init_u4v(32); bsize = ((bsize + KBM_BIN_SIZE - 1) / KBM_BIN_SIZE) * KBM_BIN_SIZE; if(bsize == 0) bsize = KBM_BIN_SIZE; bstep = ((bstep + KBM_BIN_SIZE - 1) / KBM_BIN_SIZE) * KBM_BIN_SIZE; if(bstep == 0) bstep = KBM_BIN_SIZE; kb->bsize = bsize; kb->bstep = bstep; kb->chridx = 0; kb->cidx = 0; kb->bidx = 0; kb->sidx = MAX_U4; kb->lidx = MAX_U4; kb->hidx = 0; return kb; } static inline void free_kbmblock(KBMBlock *kb){ free_string(kb->rdtag); free_layseqr(kb->seqs); free(kb); } static inline void reset_kbmblock(KBMBlock *kb, char *rdtag, u4i chridx, BaseBank *rdseq, u8i rdoff, u4i rdlen, KBMAux *aux){ lay_seq_t *stop; kb->chridx = chridx; kb->cidx = chridx; kb->bidx = 0; clear_string(kb->rdtag); if(rdtag){ append_string(kb->rdtag, rdtag, strlen(rdtag)); } else { append_string(kb->rdtag, "anonymous", strlen("anonymous")); } kb->rdseq = rdseq; kb->rdoff = rdoff; kb->rdlen = rdlen; kb->aux = aux; recyc_all_layseqr(kb->seqs); clear_u4v(kb->heap); kb->sidx = MAX_U4; kb->lidx = MAX_U4; sort_array(aux->hits->buffer, aux->hits->size, kbm_map_t, num_cmpgt(a.qb, b.qb)); kb->hidx = 0; stop = pop_layseqr(kb->seqs); stop->chridx = chridx + 1; stop->bidx = 0; } static inline lay_seq_t* _push_padding_ref_kbmblock(KBMBlock *kb, lay_seq_t *sq){ lay_seq_t *st; u8i off; u4i sqidx, len; sqidx = offset_layseqr(kb->seqs, sq); while(kb->chridx == sq->chridx && kb->bidx <= sq->bidx){ st = pop_layseqr(kb->seqs); st->chridx = kb->cidx; st->bidx = kb->bidx; st->rdidx = 0; st->rddir = 0; st->rdoff = st->bidx * kb->bstep; st->rbeg = st->rdoff; off = kb->rdoff; len = kb->rdlen; st->rend = num_min(st->rbeg + kb->bsize, len); st->rdtag = kb->rdtag->string; clear_basebank(st->seq); fast_fwdbits2basebank(st->seq, kb->rdseq->bits, off + st->rdoff, st->rend - st->rbeg); array_heap_push(kb->heap->buffer, kb->heap->size, kb->heap->cap, u4i, offset_layseqr(kb->seqs, st), num_cmpx(ref_layseqr(kb->seqs, a)->bidx, ref_layseqr(kb->seqs, b)->bidx, ref_layseqr(kb->seqs, a)->rdidx, ref_layseqr(kb->seqs, b)->rdidx)); if(st->rend >= len){ kb->chridx = MAX_U4; kb->bidx = 0; break; } else { kb->bidx ++; } sq = ref_layseqr(kb->seqs, sqidx); } sq = ref_layseqr(kb->seqs, sqidx); return sq; } static inline lay_seq_t* iter_kbmblock(void *obj){ KBMBlock *kb; kbm_map_t *hit; lay_seq_t *sc, *sl; u8i coff, tsoff; u4i off, rdoff, rdlen, nxt, val, len, clen, bt; kb = (KBMBlock*)obj; if(kb->sidx != MAX_U4){ recyc_layseqr(kb->seqs, kb->sidx); kb->sidx = MAX_U4; } sc = NULL; sl = NULL; do { if(kb->heap->size == 0){ kb->lidx = MAX_U4; } while(kb->lidx == MAX_U4){ while(kb->hidx < kb->aux->hits->size){ if(kb->aux->hits->buffer[kb->hidx].mat == 0) kb->hidx ++; else break; } if(kb->hidx >= kb->aux->hits->size){ sc = ref_layseqr(kb->seqs, 0); sc = _push_padding_ref_kbmblock(kb, sc); break; } hit = ref_kbmmapv(kb->aux->hits, kb->hidx ++); tsoff = kb->aux->kbm->reads->buffer[hit->tidx].seqoff * KBM_BIN_SIZE; rdlen = kb->aux->kbm->reads->buffer[hit->tidx].bincnt * KBM_BIN_SIZE; off = hit->qb; rdoff = hit->qdir? Int(rdlen - hit->te) : hit->tb; { encap_layseqr(kb->seqs, 2); sc = pop_layseqr(kb->seqs); sc->chridx = kb->cidx; sc->bidx = (off / kb->bstep); sc->rdidx = hit->tidx; sc->rddir = hit->qdir; sc->rdoff = rdoff; sc->rbeg = off; sc->rend = 0; sc->rdtag = kb->aux->kbm->reads->buffer[hit->tidx].tag; clear_basebank(sc->seq); } sl = NULL; { nxt = (off / kb->bstep) * kb->bstep; if(nxt && off - nxt < UInt(kb->bsize - kb->bstep)){ if(sc->bidx){ sl = pop_layseqr(kb->seqs); sl->chridx = kb->cidx; sl->bidx = sc->bidx - 1; sl->rdidx = hit->tidx; sl->rddir = hit->qdir; sl->rdoff = rdoff; sl->rbeg = off; sl->rend = 0; sl->rdtag = kb->aux->kbm->reads->buffer[hit->tidx].tag; clear_basebank(sl->seq); } nxt += kb->bsize - kb->bstep; } else { nxt += kb->bstep; } } coff = hit->cgoff; clen = hit->cglen; while(clen){ bt = get_bitsvec(kb->aux->cigars, coff + clen - 1); clen --; val = KBM_BIN_SIZE; bt = (bt & 0x03)? (bt & 0x03) : 3; while(val){ if(bt & 0b001){ len = num_min(val, nxt - off); off += len; } else { len = val; } val -= len; if(bt & 0b010){ { if(sc){ if(sc->seq->size == 0){ sc->rbeg = (bt & 0b001)? off - len : off; } if(hit->qdir){ revbits2basebank(sc->seq, kb->aux->kbm->rdseqs->bits, tsoff + rdlen - (rdoff + len), len); } else { fwdbits2basebank(sc->seq, kb->aux->kbm->rdseqs->bits, tsoff + rdoff, len); } sc->rend = off; } if(sl){ if(sl->seq->size == 0){ sl->rbeg = (bt & 0b001)? off - len : off; } if(hit->qdir){ revbits2basebank(sl->seq, kb->aux->kbm->rdseqs->bits, tsoff + rdlen - (rdoff + len), len); } else { fwdbits2basebank(sl->seq, kb->aux->kbm->rdseqs->bits, tsoff + rdoff, len); } sl->rend = off; } } rdoff += len; } if(off == nxt){ if(sl){ if(sl->rend > sl->rbeg){ u4i scidx; scidx = offset_layseqr(kb->seqs, sc); sl = _push_padding_ref_kbmblock(kb, sl); sc = ref_layseqr(kb->seqs, scidx); if(kb->lidx == MAX_U4){ kb->lidx = offset_layseqr(kb->seqs, sl); } array_heap_push(kb->heap->buffer, kb->heap->size, kb->heap->cap, u4i, offset_layseqr(kb->seqs, sl), num_cmpx(ref_layseqr(kb->seqs, a)->bidx, ref_layseqr(kb->seqs, b)->bidx, ref_layseqr(kb->seqs, a)->rdidx, ref_layseqr(kb->seqs, b)->rdidx)); } sl = NULL; nxt += 2 * kb->bstep - kb->bsize; } else { u4i scidx; scidx = offset_layseqr(kb->seqs, sc); encap_layseqr(kb->seqs, 1); sl = ref_layseqr(kb->seqs, scidx); sc = pop_layseqr(kb->seqs); sc->chridx = kb->cidx; sc->bidx = sl->bidx + 1; sc->rdidx = hit->tidx; sc->rddir = hit->qdir; sc->rdoff = rdoff; sc->rbeg = off; sc->rend = 0; sc->rdtag = kb->aux->kbm->reads->buffer[hit->tidx].tag; clear_basebank(sc->seq); nxt += kb->bsize - kb->bstep; } } } } if(sl && sl->rend > sl->rbeg){ u4i scidx; scidx = offset_layseqr(kb->seqs, sc); sl = _push_padding_ref_kbmblock(kb, sl); sc = ref_layseqr(kb->seqs, scidx); if(kb->lidx == MAX_U4){ kb->lidx = offset_layseqr(kb->seqs, sl); } array_heap_push(kb->heap->buffer, kb->heap->size, kb->heap->cap, u4i, offset_layseqr(kb->seqs, sl), num_cmpx(ref_layseqr(kb->seqs, a)->bidx, ref_layseqr(kb->seqs, b)->bidx, ref_layseqr(kb->seqs, a)->rdidx, ref_layseqr(kb->seqs, b)->rdidx)); } if(sc && sc->rend > sc->rbeg){ u4i scidx; scidx = offset_layseqr(kb->seqs, sl); sc = _push_padding_ref_kbmblock(kb, sc); sl = ref_layseqr(kb->seqs, scidx); if(kb->lidx == MAX_U4){ kb->lidx = offset_layseqr(kb->seqs, sc); } array_heap_push(kb->heap->buffer, kb->heap->size, kb->heap->cap, u4i, offset_layseqr(kb->seqs, sc), num_cmpx(ref_layseqr(kb->seqs, a)->bidx, ref_layseqr(kb->seqs, b)->bidx, ref_layseqr(kb->seqs, a)->rdidx, ref_layseqr(kb->seqs, b)->rdidx)); } } if(kb->heap->size == 0) break; if(kb->lidx != MAX_U4){ sl = ref_layseqr(kb->seqs, kb->lidx); kb->sidx = kb->heap->buffer[0]; sc = ref_layseqr(kb->seqs, kb->sidx); if(sc->chridx == sl->chridx && sc->bidx + 1 >= sl->bidx){ kb->lidx = MAX_U4; continue; } array_heap_remove(kb->heap->buffer, kb->heap->size, kb->heap->cap, u4i, 0, num_cmpx(ref_layseqr(kb->seqs, a)->bidx, ref_layseqr(kb->seqs, b)->bidx, ref_layseqr(kb->seqs, a)->rdidx, ref_layseqr(kb->seqs, b)->rdidx)); sc->rbeg -= sc->bidx * kb->bstep; sc->rend -= sc->bidx * kb->bstep; } else { kb->sidx = kb->heap->buffer[0]; array_heap_remove(kb->heap->buffer, kb->heap->size, kb->heap->cap, u4i, 0, num_cmpx(ref_layseqr(kb->seqs, a)->bidx, ref_layseqr(kb->seqs, b)->bidx, ref_layseqr(kb->seqs, a)->rdidx, ref_layseqr(kb->seqs, b)->rdidx)); sc = ref_layseqr(kb->seqs, kb->sidx); sc->rbeg -= sc->bidx * kb->bstep; sc->rend -= sc->bidx * kb->bstep; } return sc; } while(1); kb->sidx = MAX_U4; return NULL; } static inline void info_kbmblock(void *obj, lay_seq_t *sq, lay_blk_t *bk){ KBMBlock *kb; kb = (KBMBlock*)obj; if(sq == NULL) return; bk->node1 = sq->bidx; bk->node2 = sq->bidx + 1; bk->reftag = kb->rdtag->string; bk->reflen = kb->rdlen; bk->refoff = sq->bidx * kb->bstep; } static inline int map_kbmpoa(CTGCNS *cc, KBMAux *aux, char *rdtag, u4i qidx, BaseBank *rdseq, u8i seqoff, u4i seqlen, u4i corr_min, u4i corr_max, float corr_cov, FILE *layf){ ctg_cns_t *ctg; KBMBlock *kb; u4i i; int self_aln, max_hit, min_aln, min_mat; kb = (KBMBlock*)cc->obj; reset_ctgcns(cc, kb, iter_kbmblock, info_kbmblock); seqlen = kbm_cvt_length(seqlen); if(seqlen < 4 * KBM_BIN_SIZE + UInt(aux->par->min_aln)) return 0; if(rdseq && rdseq != aux->kbm->rdseqs){ self_aln = 0; } else { self_aln = 1; rdseq = aux->kbm->rdseqs; } max_hit = aux->par->max_hit; min_aln = aux->par->min_aln; min_mat = aux->par->min_mat; aux->par->self_aln = 0; aux->par->max_hit = corr_max; aux->par->min_aln = num_max(seqlen * corr_cov, min_aln); aux->par->min_mat = num_max(aux->par->min_aln * aux->par->min_sim, min_mat); query_index_kbm(aux, rdtag, qidx, rdseq, seqoff, seqlen); map_kbm(aux); aux->par->self_aln = 0; aux->par->max_hit = max_hit; aux->par->min_aln = min_aln; aux->par->min_mat = min_mat; if(KBM_LOG){ fprintf(KBM_LOGF, ">>> Contained alignments\n"); fflush(KBM_LOGF); for(i=0;ihits->size;i++){ fprint_hit_kbm(aux, i, KBM_LOGF); } } if(aux->hits->size < corr_min){ return 0; } if(self_aln){ for(i=0;ihits->size;i++){ if(aux->hits->buffer[i].tidx == qidx){ aux->hits->buffer[i].mat = 0; } } } reset_kbmblock(kb, rdtag, qidx, rdseq, seqoff, seqlen, aux); if(layf){ print_lays_ctgcns(cc, layf); fflush(layf); reset_kbmblock(kb, rdtag, qidx, rdseq, seqoff, seqlen, aux); reset_ctgcns(cc, kb, iter_kbmblock, info_kbmblock); } if((ctg = iter_ctgcns(cc))){ if(KBM_LOG){ fprintf(KBM_LOGF, ">%s corrected\n", ctg->tag->string); print_lines_basebank(ctg->cns, 0, ctg->cns->size, KBM_LOGF, 100); fflush(KBM_LOGF); } } else { return 0; } clear_kbmmapv(aux->hits); if(ctg->cns->size > seqlen){ ctg->cns->size = seqlen; normalize_basebank(ctg->cns); } else if(ctg->cns->size < seqlen){ ctg->cns->size = kbm_cvt_length(ctg->cns->size); normalize_basebank(ctg->cns); } if(ctg->cns->size == 0){ repay_ctgcns(cc, ctg); return 0; } query_index_kbm(aux, rdtag, qidx, ctg->cns, 0, ctg->cns->size); map_kbm(aux); repay_ctgcns(cc, ctg); // Please make sure ctg is not used unless this function return return 1; } #endif wtdbg2-2.5/ksw.c000066400000000000000000000617431353664372200135470ustar00rootroot00000000000000/* The MIT License Copyright (c) 2011 by Attractive Chaos Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include "ksw.h" #ifdef USE_MALLOC_WRAPPERS # include "malloc_wrap.h" #endif #ifdef __GNUC__ #define LIKELY(x) __builtin_expect((x),1) #define UNLIKELY(x) __builtin_expect((x),0) #else #define LIKELY(x) (x) #define UNLIKELY(x) (x) #endif const kswr_t g_defr = { 0, -1, -1, -1, -1, -1, -1 }; struct _kswq_t { int qlen, slen; uint8_t shift, mdiff, max, size; __m128i *qp, *H0, *H1, *E, *Hmax; }; /** * Initialize the query data structure * * @param size Number of bytes used to store a score; valid valures are 1 or 2 * @param qlen Length of the query sequence * @param query Query sequence * @param m Size of the alphabet * @param mat Scoring matrix in a one-dimension array * * @return Query data structure */ kswq_t *ksw_qinit(int size, int qlen, const uint8_t *query, int m, const int8_t *mat) { kswq_t *q; int slen, a, tmp, p; size = size > 1? 2 : 1; p = 8 * (3 - size); // # values per __m128i slen = (qlen + p - 1) / p; // segmented length q = (kswq_t*)malloc(sizeof(kswq_t) + 256 + 16 * slen * (m + 4)); // a single block of memory q->qp = (__m128i*)(((size_t)q + sizeof(kswq_t) + 15) >> 4 << 4); // align memory q->H0 = q->qp + slen * m; q->H1 = q->H0 + slen; q->E = q->H1 + slen; q->Hmax = q->E + slen; q->slen = slen; q->qlen = qlen; q->size = size; // compute shift tmp = m * m; for (a = 0, q->shift = 127, q->mdiff = 0; a < tmp; ++a) { // find the minimum and maximum score if (mat[a] < (int8_t)q->shift) q->shift = mat[a]; if (mat[a] > (int8_t)q->mdiff) q->mdiff = mat[a]; } q->max = q->mdiff; q->shift = 256 - q->shift; // NB: q->shift is uint8_t q->mdiff += q->shift; // this is the difference between the min and max scores // An example: p=8, qlen=19, slen=3 and segmentation: // {{0,3,6,9,12,15,18,-1},{1,4,7,10,13,16,-1,-1},{2,5,8,11,14,17,-1,-1}} if (size == 1) { int8_t *t = (int8_t*)q->qp; for (a = 0; a < m; ++a) { int i, k, nlen = slen * p; const int8_t *ma = mat + a * m; for (i = 0; i < slen; ++i) for (k = i; k < nlen; k += slen) // p iterations *t++ = (k >= qlen? 0 : ma[query[k]]) + q->shift; } } else { int16_t *t = (int16_t*)q->qp; for (a = 0; a < m; ++a) { int i, k, nlen = slen * p; const int8_t *ma = mat + a * m; for (i = 0; i < slen; ++i) for (k = i; k < nlen; k += slen) // p iterations *t++ = (k >= qlen? 0 : ma[query[k]]); } } return q; } kswr_t ksw_u8(kswq_t *q, int tlen, const uint8_t *target, int _o_del, int _e_del, int _o_ins, int _e_ins, int xtra) // the first gap costs -(_o+_e) { int slen, i, m_b, n_b, te = -1, gmax = 0, minsc, endsc; uint64_t *b; __m128i zero, oe_del, e_del, oe_ins, e_ins, shift, *H0, *H1, *E, *Hmax; kswr_t r; #define __max_16(ret, xx) do { \ (xx) = _mm_max_epu8((xx), _mm_srli_si128((xx), 8)); \ (xx) = _mm_max_epu8((xx), _mm_srli_si128((xx), 4)); \ (xx) = _mm_max_epu8((xx), _mm_srli_si128((xx), 2)); \ (xx) = _mm_max_epu8((xx), _mm_srli_si128((xx), 1)); \ (ret) = _mm_extract_epi16((xx), 0) & 0x00ff; \ } while (0) // initialization r = g_defr; minsc = (xtra&KSW_XSUBO)? xtra&0xffff : 0x10000; endsc = (xtra&KSW_XSTOP)? xtra&0xffff : 0x10000; m_b = n_b = 0; b = 0; zero = _mm_set1_epi32(0); oe_del = _mm_set1_epi8(_o_del + _e_del); e_del = _mm_set1_epi8(_e_del); oe_ins = _mm_set1_epi8(_o_ins + _e_ins); e_ins = _mm_set1_epi8(_e_ins); shift = _mm_set1_epi8(q->shift); H0 = q->H0; H1 = q->H1; E = q->E; Hmax = q->Hmax; slen = q->slen; for (i = 0; i < slen; ++i) { _mm_store_si128(E + i, zero); _mm_store_si128(H0 + i, zero); _mm_store_si128(Hmax + i, zero); } // the core loop for (i = 0; i < tlen; ++i) { int j, k, cmp, imax; __m128i e, h, t, f = zero, max = zero, *S = q->qp + target[i] * slen; // s is the 1st score vector h = _mm_load_si128(H0 + slen - 1); // h={2,5,8,11,14,17,-1,-1} in the above example h = _mm_slli_si128(h, 1); // h=H(i-1,-1); << instead of >> because x64 is little-endian for (j = 0; LIKELY(j < slen); ++j) { /* SW cells are computed in the following order: * H(i,j) = max{H(i-1,j-1)+S(i,j), E(i,j), F(i,j)} * E(i+1,j) = max{H(i,j)-q, E(i,j)-r} * F(i,j+1) = max{H(i,j)-q, F(i,j)-r} */ // compute H'(i,j); note that at the beginning, h=H'(i-1,j-1) h = _mm_adds_epu8(h, _mm_load_si128(S + j)); h = _mm_subs_epu8(h, shift); // h=H'(i-1,j-1)+S(i,j) e = _mm_load_si128(E + j); // e=E'(i,j) h = _mm_max_epu8(h, e); h = _mm_max_epu8(h, f); // h=H'(i,j) max = _mm_max_epu8(max, h); // set max _mm_store_si128(H1 + j, h); // save to H'(i,j) // now compute E'(i+1,j) e = _mm_subs_epu8(e, e_del); // e=E'(i,j) - e_del t = _mm_subs_epu8(h, oe_del); // h=H'(i,j) - o_del - e_del e = _mm_max_epu8(e, t); // e=E'(i+1,j) _mm_store_si128(E + j, e); // save to E'(i+1,j) // now compute F'(i,j+1) f = _mm_subs_epu8(f, e_ins); t = _mm_subs_epu8(h, oe_ins); // h=H'(i,j) - o_ins - e_ins f = _mm_max_epu8(f, t); // get H'(i-1,j) and prepare for the next j h = _mm_load_si128(H0 + j); // h=H'(i-1,j) } // NB: we do not need to set E(i,j) as we disallow adjecent insertion and then deletion for (k = 0; LIKELY(k < 16); ++k) { // this block mimics SWPS3; NB: H(i,j) updated in the lazy-F loop cannot exceed max f = _mm_slli_si128(f, 1); for (j = 0; LIKELY(j < slen); ++j) { h = _mm_load_si128(H1 + j); h = _mm_max_epu8(h, f); // h=H'(i,j) _mm_store_si128(H1 + j, h); h = _mm_subs_epu8(h, oe_ins); f = _mm_subs_epu8(f, e_ins); cmp = _mm_movemask_epi8(_mm_cmpeq_epi8(_mm_subs_epu8(f, h), zero)); if (UNLIKELY(cmp == 0xffff)) goto end_loop16; } } end_loop16: //int k;for (k=0;k<16;++k)printf("%d ", ((uint8_t*)&max)[k]);printf("\n"); __max_16(imax, max); // imax is the maximum number in max if (imax >= minsc) { // write the b array; this condition adds branching unfornately if (n_b == 0 || (int32_t)b[n_b-1] + 1 != i) { // then append if (n_b == m_b) { m_b = m_b? m_b<<1 : 8; b = (uint64_t*)realloc(b, 8 * m_b); } b[n_b++] = (uint64_t)imax<<32 | i; } else if ((int)(b[n_b-1]>>32) < imax) b[n_b-1] = (uint64_t)imax<<32 | i; // modify the last } if (imax > gmax) { gmax = imax; te = i; // te is the end position on the target for (j = 0; LIKELY(j < slen); ++j) // keep the H1 vector _mm_store_si128(Hmax + j, _mm_load_si128(H1 + j)); if (gmax + q->shift >= 255 || gmax >= endsc) break; } S = H1; H1 = H0; H0 = S; // swap H0 and H1 } r.score = gmax + q->shift < 255? gmax : 255; r.te = te; // modified by Jue Ruan //if (r.score != 255) { // get a->qe, the end of query match; find the 2nd best score { // get a->qe, the end of query match; find the 2nd best score int max = -1, tmp, low, high, qlen = slen * 16; uint8_t *t = (uint8_t*)Hmax; for (i = 0; i < qlen; ++i, ++t) if ((int)*t > max) max = *t, r.qe = i / 16 + i % 16 * slen; else if ((int)*t == max && (tmp = i / 16 + i % 16 * slen) < r.qe) r.qe = tmp; //printf("%d,%d\n", max, gmax); if (b) { i = (r.score + q->max - 1) / q->max; low = te - i; high = te + i; for (i = 0; i < n_b; ++i) { int e = (int32_t)b[i]; if ((e < low || e > high) && (int)(b[i]>>32) > r.score2) r.score2 = b[i]>>32, r.te2 = e; } } } free(b); return r; } kswr_t ksw_i16(kswq_t *q, int tlen, const uint8_t *target, int _o_del, int _e_del, int _o_ins, int _e_ins, int xtra) // the first gap costs -(_o+_e) { int slen, i, m_b, n_b, te = -1, gmax = 0, minsc, endsc; uint64_t *b; __m128i zero, oe_del, e_del, oe_ins, e_ins, *H0, *H1, *E, *Hmax; kswr_t r; #define __max_8(ret, xx) do { \ (xx) = _mm_max_epi16((xx), _mm_srli_si128((xx), 8)); \ (xx) = _mm_max_epi16((xx), _mm_srli_si128((xx), 4)); \ (xx) = _mm_max_epi16((xx), _mm_srli_si128((xx), 2)); \ (ret) = _mm_extract_epi16((xx), 0); \ } while (0) // initialization r = g_defr; minsc = (xtra&KSW_XSUBO)? xtra&0xffff : 0x10000; endsc = (xtra&KSW_XSTOP)? xtra&0xffff : 0x10000; m_b = n_b = 0; b = 0; zero = _mm_set1_epi32(0); oe_del = _mm_set1_epi16(_o_del + _e_del); e_del = _mm_set1_epi16(_e_del); oe_ins = _mm_set1_epi16(_o_ins + _e_ins); e_ins = _mm_set1_epi16(_e_ins); H0 = q->H0; H1 = q->H1; E = q->E; Hmax = q->Hmax; slen = q->slen; for (i = 0; i < slen; ++i) { _mm_store_si128(E + i, zero); _mm_store_si128(H0 + i, zero); _mm_store_si128(Hmax + i, zero); } // the core loop for (i = 0; i < tlen; ++i) { int j, k, imax; __m128i e, t, h, f = zero, max = zero, *S = q->qp + target[i] * slen; // s is the 1st score vector h = _mm_load_si128(H0 + slen - 1); // h={2,5,8,11,14,17,-1,-1} in the above example h = _mm_slli_si128(h, 2); for (j = 0; LIKELY(j < slen); ++j) { h = _mm_adds_epi16(h, *S++); e = _mm_load_si128(E + j); h = _mm_max_epi16(h, e); h = _mm_max_epi16(h, f); max = _mm_max_epi16(max, h); _mm_store_si128(H1 + j, h); e = _mm_subs_epu16(e, e_del); t = _mm_subs_epu16(h, oe_del); e = _mm_max_epi16(e, t); _mm_store_si128(E + j, e); f = _mm_subs_epu16(f, e_ins); t = _mm_subs_epu16(h, oe_ins); f = _mm_max_epi16(f, t); h = _mm_load_si128(H0 + j); } for (k = 0; LIKELY(k < 16); ++k) { f = _mm_slli_si128(f, 2); for (j = 0; LIKELY(j < slen); ++j) { h = _mm_load_si128(H1 + j); h = _mm_max_epi16(h, f); _mm_store_si128(H1 + j, h); h = _mm_subs_epu16(h, oe_ins); f = _mm_subs_epu16(f, e_ins); if(UNLIKELY(!_mm_movemask_epi8(_mm_cmpgt_epi16(f, h)))) goto end_loop8; } } end_loop8: __max_8(imax, max); if (imax >= minsc) { if (n_b == 0 || (int32_t)b[n_b-1] + 1 != i) { if (n_b == m_b) { m_b = m_b? m_b<<1 : 8; b = (uint64_t*)realloc(b, 8 * m_b); } b[n_b++] = (uint64_t)imax<<32 | i; } else if ((int)(b[n_b-1]>>32) < imax) b[n_b-1] = (uint64_t)imax<<32 | i; // modify the last } if (imax > gmax) { gmax = imax; te = i; for (j = 0; LIKELY(j < slen); ++j) _mm_store_si128(Hmax + j, _mm_load_si128(H1 + j)); if (gmax >= endsc) break; } S = H1; H1 = H0; H0 = S; } r.score = gmax; r.te = te; { int max = -1, tmp, low, high, qlen = slen * 8; uint16_t *t = (uint16_t*)Hmax; for (i = 0, r.qe = -1; i < qlen; ++i, ++t) if ((int)*t > max) max = *t, r.qe = i / 8 + i % 8 * slen; else if ((int)*t == max && (tmp = i / 8 + i % 8 * slen) < r.qe) r.qe = tmp; if (b) { i = (r.score + q->max - 1) / q->max; low = te - i; high = te + i; for (i = 0; i < n_b; ++i) { int e = (int32_t)b[i]; if ((e < low || e > high) && (int)(b[i]>>32) > r.score2) r.score2 = b[i]>>32, r.te2 = e; } } } free(b); return r; } static inline void revseq(int l, uint8_t *s) { int i, t; for (i = 0; i < l>>1; ++i) t = s[i], s[i] = s[l - 1 - i], s[l - 1 - i] = t; } kswr_t ksw_align2(int qlen, uint8_t *query, int tlen, uint8_t *target, int m, const int8_t *mat, int o_del, int e_del, int o_ins, int e_ins, int xtra, kswq_t **qry) { int size; kswq_t *q; kswr_t r, rr; kswr_t (*func)(kswq_t*, int, const uint8_t*, int, int, int, int, int); q = (qry && *qry)? *qry : ksw_qinit((xtra&KSW_XBYTE)? 1 : 2, qlen, query, m, mat); if (qry && *qry == 0) *qry = q; func = q->size == 2? ksw_i16 : ksw_u8; size = q->size; r = func(q, tlen, target, o_del, e_del, o_ins, e_ins, xtra); if (qry == 0) free(q); if ((xtra&KSW_XSTART) == 0 || ((xtra&KSW_XSUBO) && r.score < (xtra&0xffff))) return r; revseq(r.qe + 1, query); revseq(r.te + 1, target); // +1 because qe/te points to the exact end, not the position after the end q = ksw_qinit(size, r.qe + 1, query, m, mat); rr = func(q, tlen, target, o_del, e_del, o_ins, e_ins, KSW_XSTOP | r.score); revseq(r.qe + 1, query); revseq(r.te + 1, target); free(q); if (r.score == rr.score) r.tb = r.te - rr.te, r.qb = r.qe - rr.qe; return r; } kswr_t ksw_align(int qlen, uint8_t *query, int tlen, uint8_t *target, int m, const int8_t *mat, int gapo, int gape, int xtra, kswq_t **qry) { return ksw_align2(qlen, query, tlen, target, m, mat, gapo, gape, gapo, gape, xtra, qry); } /******************** *** SW extension *** ********************/ typedef struct { int32_t h, e; } eh_t; int ksw_extend2(int qlen, const uint8_t *query, int tlen, const uint8_t *target, int m, const int8_t *mat, int o_del, int e_del, int o_ins, int e_ins, int w, int end_bonus, int zdrop, int h0, int *_qle, int *_tle, int *_gtle, int *_gscore, int *_max_off) { eh_t *eh; // score array int8_t *qp; // query profile int i, j, k, oe_del = o_del + e_del, oe_ins = o_ins + e_ins, beg, end, max, max_i, max_j, max_ins, max_del, max_ie, gscore, max_off; if (h0 < 0) h0 = 0; // allocate memory qp = malloc(qlen * m); eh = calloc(qlen + 1, 8); // generate the query profile for (k = i = 0; k < m; ++k) { const int8_t *p = &mat[k * m]; for (j = 0; j < qlen; ++j) qp[i++] = p[query[j]]; } // fill the first row eh[0].h = h0; eh[1].h = h0 > oe_ins? h0 - oe_ins : 0; for (j = 2; j <= qlen && eh[j-1].h > e_ins; ++j) eh[j].h = eh[j-1].h - e_ins; // adjust $w if it is too large k = m * m; for (i = 0, max = 0; i < k; ++i) // get the max score max = max > mat[i]? max : mat[i]; max_ins = (int)((double)(qlen * max + end_bonus - o_ins) / e_ins + 1.); max_ins = max_ins > 1? max_ins : 1; w = w < max_ins? w : max_ins; max_del = (int)((double)(qlen * max + end_bonus - o_del) / e_del + 1.); max_del = max_del > 1? max_del : 1; w = w < max_del? w : max_del; // TODO: is this necessary? // DP loop max = h0, max_i = max_j = -1; max_ie = -1, gscore = -1; max_off = 0; beg = 0, end = qlen; for (i = 0; LIKELY(i < tlen); ++i) { int t, f = 0, h1, m = 0, mj = -1; int8_t *q = &qp[target[i] * qlen]; // compute the first column h1 = h0 - (o_del + e_del * (i + 1)); if (h1 < 0) h1 = 0; // apply the band and the constraint (if provided) if (beg < i - w) beg = i - w; if (end > i + w + 1) end = i + w + 1; if (end > qlen) end = qlen; for (j = beg; LIKELY(j < end); ++j) { // At the beginning of the loop: eh[j] = { H(i-1,j-1), E(i,j) }, f = F(i,j) and h1 = H(i,j-1) // Similar to SSE2-SW, cells are computed in the following order: // H(i,j) = max{H(i-1,j-1)+S(i,j), E(i,j), F(i,j)} // E(i+1,j) = max{H(i,j)-gapo, E(i,j)} - gape // F(i,j+1) = max{H(i,j)-gapo, F(i,j)} - gape eh_t *p = &eh[j]; int h, M = p->h, e = p->e; // get H(i-1,j-1) and E(i-1,j) p->h = h1; // set H(i,j-1) for the next row M += q[j]; // separating H and M to disallow a cigar like "100M3I3D20M" h = M > e? M : e; h = h > f? h : f; h1 = h; // save H(i,j) to h1 for the next column mj = m > h? mj : j; // record the position where max score is achieved m = m > h? m : h; // m is stored at eh[mj+1] t = M - oe_del; t = t > 0? t : 0; e -= e_del; e = e > t? e : t; // computed E(i+1,j) p->e = e; // save E(i+1,j) for the next row t = M - oe_ins; t = t > 0? t : 0; f -= e_ins; f = f > t? f : t; // computed F(i,j+1) } eh[end].h = h1; eh[end].e = 0; if (j == qlen) { max_ie = gscore > h1? max_ie : i; gscore = gscore > h1? gscore : h1; } if (m == 0) break; if (m > max) { max = m, max_i = i, max_j = mj; max_off = max_off > abs(mj - i)? max_off : abs(mj - i); } else if (zdrop > 0) { if (i - max_i > mj - max_j) { if (max - m - ((i - max_i) - (mj - max_j)) * e_del > zdrop) break; } else { if (max - m - ((mj - max_j) - (i - max_i)) * e_ins > zdrop) break; } } // update beg and end for the next round for (j = mj; j >= beg && eh[j].h; --j); beg = j + 1; for (j = mj + 2; j <= end && eh[j].h; ++j); end = j; //beg = 0; end = qlen; // uncomment this line for debugging } free(eh); free(qp); if (_qle) *_qle = max_j + 1; if (_tle) *_tle = max_i + 1; if (_gtle) *_gtle = max_ie + 1; if (_gscore) *_gscore = gscore; if (_max_off) *_max_off = max_off; return max; } int ksw_extend(int qlen, const uint8_t *query, int tlen, const uint8_t *target, int m, const int8_t *mat, int gapo, int gape, int w, int end_bonus, int zdrop, int h0, int *qle, int *tle, int *gtle, int *gscore, int *max_off) { return ksw_extend2(qlen, query, tlen, target, m, mat, gapo, gape, gapo, gape, w, end_bonus, zdrop, h0, qle, tle, gtle, gscore, max_off); } /******************** * Global alignment * ********************/ #define MINUS_INF -0x40000000 static inline uint32_t *push_cigar(int *n_cigar, int *m_cigar, uint32_t *cigar, int op, int len) { if (*n_cigar == 0 || op != (int)(cigar[(*n_cigar) - 1]&0xf)) { if (*n_cigar == *m_cigar) { *m_cigar = *m_cigar? (*m_cigar)<<1 : 4; cigar = realloc(cigar, (*m_cigar) << 2); } cigar[(*n_cigar)++] = len<<4 | op; } else cigar[(*n_cigar)-1] += len<<4; return cigar; } int ksw_global2(int qlen, const uint8_t *query, int tlen, const uint8_t *target, int m, const int8_t *mat, int o_del, int e_del, int o_ins, int e_ins, int w, int *n_cigar_, uint32_t **cigar_) { eh_t *eh; int8_t *qp; // query profile int i, j, k, oe_del = o_del + e_del, oe_ins = o_ins + e_ins, score, n_col; uint8_t *z; // backtrack matrix; in each cell: f<<4|e<<2|h; in principle, we can halve the memory, but backtrack will be a little more complex if (n_cigar_) *n_cigar_ = 0; // allocate memory n_col = qlen < 2*w+1? qlen : 2*w+1; // maximum #columns of the backtrack matrix z = malloc(n_col * tlen); qp = malloc(qlen * m); eh = calloc(qlen + 1, 8); // generate the query profile for (k = i = 0; k < m; ++k) { const int8_t *p = &mat[k * m]; for (j = 0; j < qlen; ++j) qp[i++] = p[query[j]]; } // fill the first row eh[0].h = 0; eh[0].e = MINUS_INF; for (j = 1; j <= qlen && j <= w; ++j) eh[j].h = -(o_ins + e_ins * j), eh[j].e = MINUS_INF; for (; j <= qlen; ++j) eh[j].h = eh[j].e = MINUS_INF; // everything is -inf outside the band // DP loop for (i = 0; LIKELY(i < tlen); ++i) { // target sequence is in the outer loop int32_t f = MINUS_INF, h1, beg, end, t; int8_t *q = &qp[target[i] * qlen]; uint8_t *zi = &z[i * n_col]; beg = i > w? i - w : 0; end = i + w + 1 < qlen? i + w + 1 : qlen; // only loop through [beg,end) of the query sequence h1 = beg == 0? -(o_del + e_del * (i + 1)) : MINUS_INF; for (j = beg; LIKELY(j < end); ++j) { // At the beginning of the loop: eh[j] = { H(i-1,j-1), E(i,j) }, f = F(i,j) and h1 = H(i,j-1) // Cells are computed in the following order: // M(i,j) = H(i-1,j-1) + S(i,j) // H(i,j) = max{M(i,j), E(i,j), F(i,j)} // E(i+1,j) = max{M(i,j)-gapo, E(i,j)} - gape // F(i,j+1) = max{M(i,j)-gapo, F(i,j)} - gape // We have to separate M(i,j); otherwise the direction may not be recorded correctly. // However, a CIGAR like "10M3I3D10M" allowed by local() is disallowed by global(). // Such a CIGAR may occur, in theory, if mismatch_penalty > 2*gap_ext_penalty + 2*gap_open_penalty/k. // In practice, this should happen very rarely given a reasonable scoring system. eh_t *p = &eh[j]; int32_t h, m = p->h, e = p->e; uint8_t d; // direction p->h = h1; m += q[j]; d = m >= e? 0 : 1; h = m >= e? m : e; d = h >= f? d : 2; h = h >= f? h : f; h1 = h; t = m - oe_del; e -= e_del; d |= e > t? 1<<2 : 0; e = e > t? e : t; p->e = e; t = m - oe_ins; f -= e_ins; d |= f > t? 2<<4 : 0; // if we want to halve the memory, use one bit only, instead of two f = f > t? f : t; zi[j - beg] = d; // z[i,j] keeps h for the current cell and e/f for the next cell } eh[end].h = h1; eh[end].e = MINUS_INF; } score = eh[qlen].h; if (n_cigar_ && cigar_) { // backtrack int n_cigar = 0, m_cigar = 0, which = 0; uint32_t *cigar = 0, tmp; i = tlen - 1; k = (i + w + 1 < qlen? i + w + 1 : qlen) - 1; // (i,k) points to the last cell while (i >= 0 && k >= 0) { which = z[i * n_col + (k - (i > w? i - w : 0))] >> (which<<1) & 3; if (which == 0) cigar = push_cigar(&n_cigar, &m_cigar, cigar, 0, 1), --i, --k; else if (which == 1) cigar = push_cigar(&n_cigar, &m_cigar, cigar, 2, 1), --i; else cigar = push_cigar(&n_cigar, &m_cigar, cigar, 1, 1), --k; } if (i >= 0) cigar = push_cigar(&n_cigar, &m_cigar, cigar, 2, i + 1); if (k >= 0) cigar = push_cigar(&n_cigar, &m_cigar, cigar, 1, k + 1); for (i = 0; i < n_cigar>>1; ++i) // reverse CIGAR tmp = cigar[i], cigar[i] = cigar[n_cigar-1-i], cigar[n_cigar-1-i] = tmp; *n_cigar_ = n_cigar, *cigar_ = cigar; } free(eh); free(qp); free(z); return score; } int ksw_global(int qlen, const uint8_t *query, int tlen, const uint8_t *target, int m, const int8_t *mat, int gapo, int gape, int w, int *n_cigar_, uint32_t **cigar_) { return ksw_global2(qlen, query, tlen, target, m, mat, gapo, gape, gapo, gape, w, n_cigar_, cigar_); } /******************************************* * Main function (not compiled by default) * *******************************************/ #ifdef _KSW_MAIN #include #include #include #include "kseq.h" KSEQ_INIT(gzFile, err_gzread) unsigned char seq_nt4_table[256] = { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 1, 4, 4, 4, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 1, 4, 4, 4, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }; int main(int argc, char *argv[]) { int c, sa = 1, sb = 3, i, j, k, forward_only = 0, max_rseq = 0; int8_t mat[25]; int gapo = 5, gape = 2, minsc = 0, xtra = KSW_XSTART; uint8_t *rseq = 0; gzFile fpt, fpq; kseq_t *kst, *ksq; // parse command line while ((c = getopt(argc, argv, "a:b:q:r:ft:1")) >= 0) { switch (c) { case 'a': sa = atoi(optarg); break; case 'b': sb = atoi(optarg); break; case 'q': gapo = atoi(optarg); break; case 'r': gape = atoi(optarg); break; case 't': minsc = atoi(optarg); break; case 'f': forward_only = 1; break; case '1': xtra |= KSW_XBYTE; break; } } if (optind + 2 > argc) { fprintf(stderr, "Usage: ksw [-1] [-f] [-a%d] [-b%d] [-q%d] [-r%d] [-t%d] \n", sa, sb, gapo, gape, minsc); return 1; } if (minsc > 0xffff) minsc = 0xffff; xtra |= KSW_XSUBO | minsc; // initialize scoring matrix for (i = k = 0; i < 4; ++i) { for (j = 0; j < 4; ++j) mat[k++] = i == j? sa : -sb; mat[k++] = 0; // ambiguous base } for (j = 0; j < 5; ++j) mat[k++] = 0; // open file fpt = xzopen(argv[optind], "r"); kst = kseq_init(fpt); fpq = xzopen(argv[optind+1], "r"); ksq = kseq_init(fpq); // all-pair alignment while (kseq_read(ksq) > 0) { kswq_t *q[2] = {0, 0}; kswr_t r; for (i = 0; i < (int)ksq->seq.l; ++i) ksq->seq.s[i] = seq_nt4_table[(int)ksq->seq.s[i]]; if (!forward_only) { // reverse if ((int)ksq->seq.m > max_rseq) { max_rseq = ksq->seq.m; rseq = (uint8_t*)realloc(rseq, max_rseq); } for (i = 0, j = ksq->seq.l - 1; i < (int)ksq->seq.l; ++i, --j) rseq[j] = ksq->seq.s[i] == 4? 4 : 3 - ksq->seq.s[i]; } gzrewind(fpt); kseq_rewind(kst); while (kseq_read(kst) > 0) { for (i = 0; i < (int)kst->seq.l; ++i) kst->seq.s[i] = seq_nt4_table[(int)kst->seq.s[i]]; r = ksw_align(ksq->seq.l, (uint8_t*)ksq->seq.s, kst->seq.l, (uint8_t*)kst->seq.s, 5, mat, gapo, gape, xtra, &q[0]); if (r.score >= minsc) err_printf("%s\t%d\t%d\t%s\t%d\t%d\t%d\t%d\t%d\n", kst->name.s, r.tb, r.te+1, ksq->name.s, r.qb, r.qe+1, r.score, r.score2, r.te2); if (rseq) { r = ksw_align(ksq->seq.l, rseq, kst->seq.l, (uint8_t*)kst->seq.s, 5, mat, gapo, gape, xtra, &q[1]); if (r.score >= minsc) err_printf("%s\t%d\t%d\t%s\t%d\t%d\t%d\t%d\t%d\n", kst->name.s, r.tb, r.te+1, ksq->name.s, (int)ksq->seq.l - r.qb, (int)ksq->seq.l - 1 - r.qe, r.score, r.score2, r.te2); } } free(q[0]); free(q[1]); } free(rseq); kseq_destroy(kst); err_gzclose(fpt); kseq_destroy(ksq); err_gzclose(fpq); return 0; } #endif wtdbg2-2.5/ksw.h000066400000000000000000000117431353664372200135470ustar00rootroot00000000000000#ifndef __AC_KSW_H #define __AC_KSW_H #include #define KSW_XBYTE 0x10000 #define KSW_XSTOP 0x20000 #define KSW_XSUBO 0x40000 #define KSW_XSTART 0x80000 struct _kswq_t; typedef struct _kswq_t kswq_t; typedef struct { int score; // best score int te, qe; // target end and query end int score2, te2; // second best score and ending position on the target int tb, qb; // target start and query start } kswr_t; #ifdef __cplusplus extern "C" { #endif /** * Aligning two sequences * * @param qlen length of the query sequence (typically =0, *gscore keeps the best score such that * the entire query sequence is aligned; *gtle keeps the position on the * target where *gscore is achieved. Returning *gscore and *gtle helps the * caller to decide whether an end-to-end hit or a partial hit is preferred. * * The first 9 parameters are identical to those in ksw_global() * * @param h0 alignment score of upstream sequences * @param _qle (out) length of the query in the alignment * @param _tle (out) length of the target in the alignment * @param _gtle (out) length of the target if query is fully aligned * @param _gscore (out) score of the best end-to-end alignment; negative if not found * * @return best semi-local alignment score */ int ksw_extend(int qlen, const uint8_t *query, int tlen, const uint8_t *target, int m, const int8_t *mat, int gapo, int gape, int w, int end_bonus, int zdrop, int h0, int *qle, int *tle, int *gtle, int *gscore, int *max_off); int ksw_extend2(int qlen, const uint8_t *query, int tlen, const uint8_t *target, int m, const int8_t *mat, int o_del, int e_del, int o_ins, int e_ins, int w, int end_bonus, int zdrop, int h0, int *qle, int *tle, int *gtle, int *gscore, int *max_off); #ifdef __cplusplus } #endif #endif wtdbg2-2.5/kswx.h000066400000000000000000001416511353664372200137410ustar00rootroot00000000000000/* * * Copyright (c) 2011, Jue Ruan * * * 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 3 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, see . */ #ifndef __KSW_EXT_RJ_H #define __KSW_EXT_RJ_H #include "ksw.h" #include "dna.h" #include "chararray.h" #include "list.h" #include #include typedef struct { int score; int tb, te, qb, qe; int aln, mat, mis, ins, del; } kswx_t; static const kswr_t KSWR_NULL = (kswr_t){0, 0, 0, 0, 0, 0, 0}; static const kswx_t KSWX_NULL = (kswx_t){0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static inline kswr_t kswx2kswr(kswx_t x){ kswr_t r; r.score = x.score; r.tb = x.tb; r.te = x.te; r.qb = x.qb; r.qe = x.qe; r.score2 = 0; r.te2 = 0; return r; } static inline void kswx_push_cigar(u32list *cigars, uint32_t op, uint32_t len){ if(len == 0) return; if(cigars->size && (cigars->buffer[cigars->size-1] & 0xF) == op){ cigars->buffer[cigars->size-1] += len << 4; } else push_u32list(cigars, (len << 4) | op); } static inline void kswx_push_cigars(u32list *cigars, uint32_t *cigar, size_t size){ if(size == 0) return; if(cigars->size && (cigars->buffer[cigars->size-1] & 0x0F) == (cigar[0] & 0x0FU)){ cigars->buffer[cigars->size-1] += cigar[0] & 0xFFFFFFF0U; append_array_u32list(cigars, cigar + 1, size - 1); } else append_array_u32list(cigars, cigar, size); } static inline void kswx_print_cigars(uint32_t *cigar, size_t size, FILE *out){ size_t i; uint32_t op, len; for(i=0;i> 4; fprintf(out, "%d%c", len, "MIDX"[op]); } fflush(out); } static inline kswx_t kswx_stat_cigars(uint32_t *cigar, size_t size){ kswx_t x; size_t i; uint32_t op, len; x = KSWX_NULL; for(i=0;i> 4; x.aln += len; switch(op){ case 0: x.mat += len; x.te += len; x.qe += len; break; case 1: x.ins += len; x.qe += len; break; case 2: x.del += len; x.te += len; break; } } return x; } static inline void revseq_bytes(uint8_t *ary, int size){ int i, v; for(i=0;i>1;i++){ v = ary[i]; ary[i] = ary[size - 1 - i]; ary[size - 1 - i] = v; } } static inline void revseq_4bytes(uint32_t *ary, int size){ int i; uint32_t v; for(i=0;i>1;i++){ v = ary[i]; ary[i] = ary[size - 1 - i]; ary[size - 1 - i] = v; } } #define kswx_roundup8x(n) (((n) + 0x7LLU) & 0xFFFFFFFFFFFFFFF8LLU) static inline void kswx_overlap_align_core(kswx_t *xs[2], u32list *cigars[2], int qlen, uint8_t *query, int tlen, uint8_t *target, int strand, int M, int X, int I, int D, int E, u8list *mem_cache){ kswx_t x; int *rh, *re; uint8_t *z, *zi, d; int ql, tl, n_col; int i, j, k, h1, h, m, e, f, t; int imax, mj2, gmax, gi; if(xs[0]) *xs[0] = KSWX_NULL; if(xs[1]) *xs[1] = KSWX_NULL; if(qlen <= 0 || tlen <= 0){ if(xs[0]) clear_u32list(cigars[0]); if(xs[1]) clear_u32list(cigars[1]); return; } ql = qlen; tl = tlen; n_col = tl; encap_u8list(mem_cache, kswx_roundup8x((tl + 2) * sizeof(int)) + kswx_roundup8x((tl + 2) * sizeof(int)) + kswx_roundup8x(((long long)ql) * n_col)); rh = (int*)(mem_cache->buffer + mem_cache->size); re = (int*)(mem_cache->buffer + mem_cache->size + kswx_roundup8x((tl + 2) * sizeof(int))); z = (mem_cache->buffer + mem_cache->size + kswx_roundup8x((tl + 2) * sizeof(int)) + kswx_roundup8x((tl + 2) * sizeof(int))); for(j=0;j<=tl;j++) rh[j] = 0; for(j=0;j<=tl;j++) re[j] = -10000; gmax = 0; gi = -1; imax = 0; mj2 = -1; for(i=0;i= e? 0 : 1; h = m >= e? m : e; d = h >= f? d : 2; h = h >= f? h : f; h1 = h; if(i + 1 == ql){ imax = imax > h? imax : h; mj2 = imax > h? mj2 : j; } t = m + I + E; e = e + E; d |= e > t? 1<<2 : 0; e = e > t? e : t; re[j] = e; t = m + D + E; f = f + E; d |= f > t? 2<<4 : 0; f = f > t? f : t; zi[j] = d; } rh[j] = h1; re[j] = -10000; if(gmax < h1){ gmax = h1; gi = i; } } for(k=0;k<2;k++){ if(xs[k] == NULL) continue; x = KSWX_NULL; if(k){ x.score = gmax; x.qe = gi; x.te = tl - 1; } else { x.score = imax; x.qe = ql - 1; x.te = mj2; } i = x.qe; j = x.te; d = 0; if(cigars[k]) clear_u32list(cigars[k]); while(i >= 0 && j >= 0){ d = (z[i * n_col + j] >> (d << 1)) & 0x03; if(d == 0){ if(query[i * strand] == target[j * strand]){ x.mat ++; } else { x.mis ++; } i --; j --; } else if(d == 1){ i --; x.ins ++; } else { j --; x.del ++; } if(cigars[k]) kswx_push_cigar(cigars[k], d, 1); } switch(d){ case 1: x.qb = i + 1; x.tb = j; break; case 2: x.tb = i; x.tb = j + 1; break; default: x.qb = i + 1; x.tb = j + 1; break; } if(cigars[k]) reverse_u32list(cigars[k]); x.aln = x.mat + x.mis + x.ins + x.del; x.qe ++; x.te ++; *xs[k] = x; } } // diagonal will shift 1 bp to max score of each row static inline kswx_t kswx_extend_align_shift_core(int qlen, uint8_t *query, int tlen, uint8_t *target, int strand, int init_score, int W, int M, int X, int I, int D, int E, int T, u8list *mem_cache, u32list *cigars){ kswx_t x; int *rh, *re, *zb; uint8_t *z, *zi; int8_t *qp, *qpp; register uint8_t d; int ql, tl, n_col; int i, j, jb, je, h1, c; register int h, m, e, f, t; int max_gap, max, mi, mj, imax, mj2, gmax, gi, gj; clear_u32list(cigars); x = KSWX_NULL; if(init_score < 0) init_score = 0; if(qlen <= 0 || tlen <= 0){ x.score = init_score; return x; } if(W > 0){ max = ((qlen < tlen)? qlen : tlen) * M + init_score + (- T); max_gap = (max + (((I > D)? I : D))) / (- E) + 1; if(max_gap < 1) max_gap = 1; if(W > max_gap) W = max_gap; } else W = -W; W = num_min(W, num_max(qlen, tlen)); if(qlen < tlen){ if(qlen + W < tlen){ ql = qlen; tl = qlen + W; } else { ql = qlen; tl = tlen; } } else { if(tlen + W < qlen){ tl = tlen; ql = tlen + W; } else { tl = tlen; ql = qlen; } } n_col = tl < 2 * W + 1? tl : 2 * W + 1; encap_u8list(mem_cache, kswx_roundup8x(mem_cache->size) - mem_cache->size + kswx_roundup8x((tl + 2) * sizeof(int)) * 2 + kswx_roundup8x((ql + 2) * sizeof(int)) + kswx_roundup8x(((long long)ql) * n_col) + kswx_roundup8x(tl + 2) * sizeof(int8_t) * 4); // assume only A,C,G,T rh = (int*)(mem_cache->buffer + kswx_roundup8x(mem_cache->size)); re = (int*)(mem_cache->buffer + kswx_roundup8x(mem_cache->size) + kswx_roundup8x((tl + 2) * sizeof(int))); zb = (int*)(mem_cache->buffer + kswx_roundup8x(mem_cache->size) + kswx_roundup8x((tl + 2) * sizeof(int)) * 2); z = (mem_cache->buffer + kswx_roundup8x(mem_cache->size) + kswx_roundup8x((tl + 2) * sizeof(int)) * 2 + kswx_roundup8x((ql + 2) * sizeof(int))); qp = (int8_t*)(mem_cache->buffer + kswx_roundup8x(mem_cache->size) + kswx_roundup8x((tl + 2) * sizeof(int)) * 2 + kswx_roundup8x((ql + 2) * sizeof(int)) + kswx_roundup8x(((long long)ql) * n_col)); for(c=i=0;c<4;c++){ for(j=0;j c + W + 1) je = c + W + 1; if(je > tl) je = tl; if(jb == 0) h1 = init_score + I + E * (i + 1); else h1 = -10000; zi = z + (i * n_col); zb[i] = jb; imax = 0; mj2 = -1; f = -10000; qpp = qp + query[i * strand] * tl; for(j=jb;j= e){ d = 0; h = m; } else { d = 1; h = e; } if(h < f){ d = 2; h = f; } h1 = h; if(h > imax){ imax = h; mj2 = j; } t = m + I + E; e = e + E; if(e > t){ d |= 1 << 2; } else { e = t; } re[j] = e; t = m + D + E; f = f + E; if(f > t){ d |= 2 << 4; } else { f = t; } zi[j-jb] = d; } rh[j] = h1; re[j] = -10000; if(j == tlen && gmax < h1){ gmax = h1; gi = i; gj = j - 1; } if(i + 1 == qlen && gmax < imax){ gmax = imax; gi = i; gj = mj2; } if(imax > max){ max = imax; mi = i; mj = mj2; } else if(imax <= 0) break; c ++; if(c < mj2){ c ++; if(je < tl){ rh[je + 1] = -10000; re[je + 1] = -10000; } } else if(c > mj2) { c --; if(jb){ rh[jb-1] = -10000; re[jb-1] = -10000; } } jb = 0; je = tl; } if(gmax > 0 && gmax >= max + T){ x.score = gmax; x.qe = gi; x.te = gj; } else { x.score = max; x.qe = mi; x.te = mj; } i = x.qe; j = x.te; d = 0; while(i >= 0 && j >= 0){ d = (z[i * n_col + (j - zb[i])] >> (d << 1)) & 0x03; if(d == 0){ if(query[i * strand] == target[j * strand]){ x.mat ++; } else { x.mis ++; } i --; j --; } else if(d == 1){ i --; x.ins ++; } else { j --; x.del ++; } if(cigars) kswx_push_cigar(cigars, d, 1); } if(i >= 0){ x.ins += i + 1; if(cigars) kswx_push_cigar(cigars, 1, i + 1); } if(j >= 0){ x.del += j + 1; if(cigars) kswx_push_cigar(cigars, 2, j + 1); } if(cigars) reverse_u32list(cigars); x.aln = x.mat + x.mis + x.ins + x.del; x.qe ++; x.te ++; return x; } static inline kswx_t kswx_extend_align_core(int qlen, uint8_t *query, int tlen, uint8_t *target, int strand, int init_score, int W, int M, int X, int I, int D, int E, int T, u8list *mem_cache, u32list *cigars){ kswx_t x; int *rh, *re; uint8_t *z, *zi, d; int ql, tl, n_col; int i, j, jb, je, h1, h, m, e, f, t; int max_gap, max, mi, mj, imax, mj2, gmax, gi, gj; x = KSWX_NULL; if(init_score < 0) init_score = 0; if(qlen <= 0 || tlen <= 0){ x.score = init_score; return x; } if(W > 0){ max = ((qlen < tlen)? qlen : tlen) * M + init_score + (- T); max_gap = (max + (((I > D)? I : D))) / (- E) + 1; if(max_gap < 1) max_gap = 1; if(W > max_gap) W = max_gap; } else W = -W; W = num_min(W, num_max(qlen, tlen)); if(qlen < tlen){ if(qlen + W < tlen){ ql = qlen; tl = qlen + W; } else { ql = qlen; tl = tlen; } } else { if(tlen + W < qlen){ tl = tlen; ql = tlen + W; } else { tl = tlen; ql = qlen; } } n_col = tl < 2 * W + 1? tl : 2 * W + 1; encap_u8list(mem_cache, kswx_roundup8x((tl + 2) * sizeof(int)) + kswx_roundup8x((tl + 2) * sizeof(int)) + kswx_roundup8x(((long long)ql) * n_col)); rh = (int*)(mem_cache->buffer + mem_cache->size); re = (int*)(mem_cache->buffer + mem_cache->size + kswx_roundup8x((tl + 2) * sizeof(int))); z = (mem_cache->buffer + mem_cache->size + kswx_roundup8x((tl + 2) * sizeof(int)) + kswx_roundup8x((tl + 2) * sizeof(int))); rh[0] = init_score; rh[1] = init_score + D + E; for(j=2;j<=tl;j++) rh[j] = rh[j - 1] + E; for(j=0;j<=tl;j++) re[j] = -10000; max = init_score; mi = -1; mj = -1; gmax = 0; gi = -1; gj = -1; jb = 0; je = tl; for(i=0;i tl) je = tl; if(jb == 0) h1 = init_score + I + E * (i + 1); else h1 = -10000; zi = &z[i * n_col]; imax = 0; mj2 = -1; f = -10000; for(j=jb;j= e? 0 : 1; h = m >= e? m : e; d = h >= f? d : 2; h = h >= f? h : f; h1 = h; imax = imax > h? imax : h; mj2 = imax > h? mj2 : j; t = m + I + E; e = e + E; d |= e > t? 1<<2 : 0; e = e > t? e : t; re[j] = e; t = m + D + E; f = f + E; d |= f > t? 2<<4 : 0; f = f > t? f : t; zi[j-jb] = d; } rh[j] = h1; re[j] = -10000; if(j == tlen && gmax < h1){ gmax = h1; gi = i; gj = j - 1; } if(i + 1 == qlen && gmax < imax){ gmax = imax; gi = i; gj = mj2; } if(imax > max){ max = imax; mi = i; mj = mj2; } else if(imax <= 0) break; } if(gmax > 0 && gmax >= max + T){ x.score = gmax; x.qe = gi; x.te = gj; } else { x.score = max; x.qe = mi; x.te = mj; } i = x.qe; j = x.te; d = 0; clear_u32list(cigars); while(i >= 0 && j >= 0){ d = (z[i * n_col + j - (i > W? i - W : 0)] >> (d << 1)) & 0x03; if(d == 0){ if(query[i * strand] == target[j * strand]){ x.mat ++; } else { x.mis ++; } i --; j --; } else if(d == 1){ i --; x.ins ++; } else { j --; x.del ++; } if(cigars) kswx_push_cigar(cigars, d, 1); } if(i >= 0){ x.ins += i + 1; if(cigars) kswx_push_cigar(cigars, 1, i + 1); } if(j >= 0){ x.del += j + 1; if(cigars) kswx_push_cigar(cigars, 2, j + 1); } if(cigars) reverse_u32list(cigars); x.aln = x.mat + x.mis + x.ins + x.del; x.qe ++; x.te ++; return x; } static inline kswx_t kswx_mismatch_free_extend_align_core(int qlen, uint8_t *query, int tlen, uint8_t *target, int strand, int init_score, int W, int M, int I, int D, int E, int T, u8list *mem_cache, u32list *cigars){ kswx_t x; int *rh, *re; uint8_t *z, *zi, d; int ql, tl, n_col; int i, j, jb, je, h1, h, m, e, f; int max_gap, max, mi, mj, imax, mj2, gmax, gi, gj; x = KSWX_NULL; if(init_score < 0) init_score = 0; if(qlen <= 0 || tlen <= 0){ x.score = init_score; return x; } if(W > 0){ max = ((qlen < tlen)? qlen : tlen) * M + init_score + (- T); max_gap = (max + (((I > D)? I : D))) / (- E) + 1; if(max_gap < 1) max_gap = 1; if(W > max_gap) W = max_gap; } else W = -W; W = num_min(W, num_max(qlen, tlen)); if(qlen < tlen){ if(qlen + W < tlen){ ql = qlen; tl = qlen + W; } else { ql = qlen; tl = tlen; } } else { if(tlen + W < qlen){ tl = tlen; ql = tlen + W; } else { tl = tlen; ql = qlen; } } n_col = tl < 2 * W + 1? tl : 2 * W + 1; encap_u8list(mem_cache, kswx_roundup8x((tl + 2) * sizeof(int)) + kswx_roundup8x((tl + 2) * sizeof(int)) + kswx_roundup8x(((long long)ql) * n_col)); rh = (int*)(mem_cache->buffer + mem_cache->size); re = (int*)(mem_cache->buffer + mem_cache->size + kswx_roundup8x((tl + 2) * sizeof(int))); z = (mem_cache->buffer + mem_cache->size + kswx_roundup8x((tl + 2) * sizeof(int)) + kswx_roundup8x((tl + 2) * sizeof(int))); rh[0] = init_score; rh[1] = init_score + D + E; for(j=2;j<=tl;j++) rh[j] = rh[j - 1] + E; for(j=0;j<=tl;j++) re[j] = -10000; max = init_score; mi = -1; mj = -1; gmax = 0; gi = -1; gj = -1; jb = 0; je = tl; for(i=0;i tl) je = tl; if(jb == 0) h1 = init_score + I + E * (i + 1); else h1 = -10000; zi = &z[i * n_col]; imax = 0; mj2 = -1; f = h1 + D + E; for(j=jb;j= e){ if(m >= f){ d = 0; h = m; f = m + D + E; e = m + I + E; } else { d = 2; h = f; f = f + E; e = f + I + E; } } else { if(e >= f){ d = 1; h = e; f = e + D + E; e = e + E; } else { d = 2; h = f; f = f + E; e = f + I + E; } } } else { rh[j] = h1; { if(e >= f){ d = 1; h = e; f = e + D + E; e = e + E; } else { d = 2; h = f; f = f + E; e = f + I + E; } } } h1 = h; if(imax < h){ imax = h; mj2 = j; } re[j] = e; zi[j-jb] = d; } rh[j] = h1; re[j] = -10000; if(j == tlen && gmax < h1){ gmax = h1; gi = i; gj = j - 1; } if(i + 1 == qlen && gmax < imax){ gmax = imax; gi = i; gj = mj2; } if(imax > max){ max = imax; mi = i; mj = mj2; } else if(imax <= 0) break; } if(gmax > 0 && gmax >= max + T){ x.score = gmax; x.qe = gi; x.te = gj; } else { x.score = max; x.qe = mi; x.te = mj; } i = x.qe; j = x.te; d = 0; clear_u32list(cigars); while(i >= 0 && j >= 0){ d = (z[i * n_col + j - (i > W? i - W : 0)]) & 0x03; if(d == 0){ x.mat ++; i --; j --; } else if(d == 1){ i --; x.ins ++; } else { j --; x.del ++; } if(cigars) kswx_push_cigar(cigars, d, 1); } if(i >= 0){ x.ins += i + 1; if(cigars) kswx_push_cigar(cigars, 1, i + 1); } if(j >= 0){ x.del += j + 1; if(cigars) kswx_push_cigar(cigars, 2, j + 1); } if(cigars) reverse_u32list(cigars); x.aln = x.mat + x.mis + x.ins + x.del; x.qe ++; x.te ++; return x; } static inline kswx_t kswx_extend_align(int qlen, uint8_t *query, int tlen, uint8_t *target, int strand, int init_score, int W, int M, int X, int I, int D, int E, int T, int *n_cigar, uint32_t **cigar){ u8list *caches; u32list *cigars; kswx_t x; caches = init_u8list(256); cigars = init_u32list(64); x = kswx_extend_align_shift_core(qlen, query, tlen, target, strand, init_score, W, M, X, I, D, E, T, caches, cigars); free_u8list(caches); *n_cigar = cigars->size; *cigar = cigars->buffer; free(cigars); return x; } static inline kswx_t kswx_flexible_banded_affine_alignment(uint8_t *query, int ql, uint8_t *target, int tl, int M, int X, int I, int D, int E, int T, int is_local, int *bands[2], u8list *mem, u32list *cigars){ kswx_t x; int *rh, *re; uint8_t *z, *zi; long long tot_z; int8_t *qp, *qpp; register uint8_t d; register int h, h1, m, e, f, t, imax, mj2; int i, j, c, max, mi, mj, gmax, gi, gj; long long ii; clear_u32list(cigars); tot_z = 0; for(i=0;ibuffer); re = (int*)(((void*)rh) + kswx_roundup8x((tl + 2) * sizeof(int))); z = (uint8_t*)(((void*)re) + kswx_roundup8x((tl + 2) * sizeof(int))); qp = (int8_t*)(((void*)z) + kswx_roundup8x(tot_z)); for(c=ii=0;c<4;c++){ for(j=0;j= e){ d = 0; h = m; } else { d = 1; h = e; } if(h < f){ d = 2; h = f; } if(is_local && h < 0){ d = 3; h = 0; } h1 = h; if(imax < h){ imax = h; mj2 = j; } t = m + I + E; e = e + E; if(e > t){ d |= 1 << 2; } else { e = t; } re[j] = e; t = m + D + E; f = f + E; if(f > t){ d |= 2 << 4; } else { f = t; } *zi = d; zi ++; } rh[j] = h1; re[j] = -10000; if(j == tl && gmax < h1){ gmax = h1; gi = i; gj = j - 1; } if(i + 1 == ql && gmax < imax){ gmax = imax; gi = i; gj = mj2; } if(imax > max){ max = imax; mi = i; mj = mj2; } } if(gmax >= max + T){ x.score = gmax; x.qe = gi; x.te = gj; } else { x.score = max; x.qe = mi; x.te = mj; } i = x.qe; j = x.te; d = 0; for(i=ql-1;i>=x.qe;i--){ zi -= bands[1][i] - bands[0][i]; } clear_u32list(cigars); while(i >= 0 && j >= 0){ d = (zi[j - bands[0][i]] >> (d << 1)) & 0x03; if(d == 3) break; if(d == 0){ x.mat ++; i --; zi -= bands[1][i] - bands[0][i]; j --; } else if(d == 1){ i --; zi -= bands[1][i] - bands[0][i]; x.ins ++; } else { j --; x.del ++; } if(cigars) kswx_push_cigar(cigars, d, 1); } if(d != 3){ if(i >= 0){ x.ins += i + 1; if(cigars) kswx_push_cigar(cigars, 1, i + 1); } if(j >= 0){ x.del += j + 1; if(cigars) kswx_push_cigar(cigars, 2, j + 1); } } x.qb = i; x.tb = j; if(cigars) reverse_u32list(cigars); x.aln = x.mat + x.mis + x.ins + x.del; x.qe ++; x.te ++; return x; } static inline kswx_t kswx_refine_alignment(uint8_t *query, int qb, uint8_t *target, int tb, int W, int M, int X, int I, int D, int E, u32list *cigars, u8list *mem_cache, u32list *cigars2){ kswx_t y; int *rh, *re; int *zb, *ze, *zw; int ql, tl, _zb, _ze, tx, qx; int qe, te; uint8_t *z, *zi; int8_t *qp, *qpp; register uint8_t d; register int h, m, e, f, t; long long i, j; int op, len, h1, c; clear_u32list(cigars2); qe = qb; te = tb; for(i=0;i<(int)cigars->size;i++){ op = cigars->buffer[i] & 0xFU; len = cigars->buffer[i] >> 4; switch(op){ case 0: qe += len; te += len; break; case 1: qe += len; break; default: te += len; } } ql = qe - qb; tl = te - tb; if(ql == 0 || tl == 0) return KSWX_NULL; clear_and_encap_u8list(mem_cache, kswx_roundup8x((tl + 2) * sizeof(int)) * 2 // rh, re + kswx_roundup8x((ql + 2) * sizeof(int)) * 3 // zb, ze, zw + kswx_roundup8x(((long long)ql) * tl) // z + kswx_roundup8x(tl + 2) * sizeof(int8_t) * 4); // qp rh = (int*)(mem_cache->buffer); re = (int*)(((void*)rh) + kswx_roundup8x((tl + 2) * sizeof(int))); zb = (int*)(((void*)re) + kswx_roundup8x((tl + 2) * sizeof(int))); ze = (int*)(((void*)zb) + kswx_roundup8x((ql + 2) * sizeof(int))); zw = (int*)(((void*)ze) + kswx_roundup8x((ql + 2) * sizeof(int))); z = (uint8_t*)(((void*)zw) + kswx_roundup8x((ql + 2) * sizeof(int))); qp = (int8_t*)(((void*)z) + kswx_roundup8x(((long long)ql) * tl)); for(c=i=0;c<4;c++){ for(j=0;jsize;i++){ op = cigars->buffer[i] & 0xFU; len = cigars->buffer[i] >> 4; switch(op){ case 0: for(j=0;jsize;i++){ op = cigars->buffer[i] & 0xFU; len = cigars->buffer[i] >> 4; switch(op){ case 0: qx += len; break; case 1: for(j=1;jsize;i++){ op = cigars->buffer[i] & 0xFU; len = cigars->buffer[i] >> 4; switch(op){ case 0: for(j=0;j tl) _ze = tl; zb[qx] = _zb; ze[qx] = _ze; tx ++; qx ++; } break; case 1: for(j=0;j tl) _ze = tl; zb[qx] = _zb; ze[qx] = _ze; qx ++; } break; default: tx += len; } } // trim band beg _zb = 0; for(i=0;i _zb) _zb = zb[i]; } // trim band end _ze = tl; for(i=ql-1;i>=0;i--){ if(ze[i] > _ze) ze[i] = _ze; else if(ze[i] < _ze) _ze = ze[i]; } // perform alignment rh[0] = 0; for(i=1;i<=tl;i++) rh[i] = -10000; for(i=0;i<=tl;i++) re[i] = -10000; for(i=0;i= e){ d = 0; h = m; } else { d = 1; h = e; } if(h < f){ d = 2; h = f; } h1 = h; t = m + I + E; e = e + E; if(e > t){ d |= 1 << 2; } else { e = t; } re[j] = e; t = m + D + E; f = f + E; if(f > t){ d |= 2 << 4; } else { f = t; } zi[j-zb[i]] = d; } rh[j] = h1; re[j] = -10000; } y.qb = qb; y.qe = qe; y.tb = tb; y.te = te; y.score = rh[tl]; y.mat = y.mis = y.ins = y.del = y.aln = 0; d = 0; i = ql - 1; j = tl - 1; while(i >= 0 && j >= 0){ d = (z[i * tl + (j - zb[i])] >> (d << 1)) & 0x03; if(d == 0){ if(query[i + y.qb] == target[j + y.tb]){ y.mat ++; } else { y.mis ++; } i --; j --; } else if(d == 1){ i --; y.ins ++; } else { j --; y.del ++; } kswx_push_cigar(cigars2, d, 1); } if(i >= 0){ y.ins += i + 1; kswx_push_cigar(cigars2, 1, i + 1); } if(j >= 0){ y.del += j + 1; kswx_push_cigar(cigars2, 2, j + 1); } reverse_u32list(cigars2); y.aln = y.mat + y.mis + y.ins + y.del; return y; } // qvs: 0:errQV, 1:misQV, 2:insQV, 3:delQV, 4:mrgQV, 5, misTag, 6, delTag static inline kswx_t kswx_refine_alignment_5q(uint8_t *query, int qb, uint8_t *target, int tb, int W, uint8_t QCLP, uint8_t QMIS, uint8_t QDEL, uint8_t *qvs[7], u32list *cigars, u8list *mem_cache, u32list *cigars2){ kswx_t y; uint32_t *rh, SCORE_INF; int *zb, *ze, *zw; int ql, tl, rl, _zb, _ze, tx, qx; int qe, te; uint8_t *z, *zi; uint8_t d, qmat[4], qins, qdel[4]; register uint32_t h1, h, m, e, f; long long i, j; int op, len; SCORE_INF = 0xFFFFFFFFU >> 1; clear_u32list(cigars2); qe = qb; te = tb; for(i=0;i<(int)cigars->size;i++){ op = cigars->buffer[i] & 0xFU; len = cigars->buffer[i] >> 4; switch(op){ case 0: qe += len; te += len; break; case 1: qe += len; break; default: te += len; } } ql = qe - qb; tl = te - tb; if(ql == 0 || tl == 0) return KSWX_NULL; rl = tl; clear_and_encap_u8list(mem_cache, kswx_roundup8x((tl + 2) * sizeof(uint32_t)) // rh + kswx_roundup8x((ql + 2) * sizeof(int)) * 3 // zb, ze, zw + kswx_roundup8x(((long long)ql) * rl)); // z rh = (uint32_t*)(mem_cache->buffer); zb = (int*)(((void*)rh) + kswx_roundup8x((tl + 2) * sizeof(uint32_t))); ze = (int*)(((void*)zb) + kswx_roundup8x((ql + 2) * sizeof(int))); zw = (int*)(((void*)ze) + kswx_roundup8x((ql + 2) * sizeof(int))); z = (uint8_t*)(((void*)zw) + kswx_roundup8x((ql + 2) * sizeof(int))); // calculate alignment band // basic band tx = qx = 0; for(i=0;i<(int)cigars->size;i++){ op = cigars->buffer[i] & 0xFU; len = cigars->buffer[i] >> 4; switch(op){ case 0: for(j=0;jsize;i++){ op = cigars->buffer[i] & 0xFU; len = cigars->buffer[i] >> 4; switch(op){ case 0: qx += len; break; case 1: for(j=1;jsize;i++){ op = cigars->buffer[i] & 0xFU; len = cigars->buffer[i] >> 4; switch(op){ case 0: for(j=0;j tl) _ze = tl; zb[qx] = _zb; ze[qx] = _ze; tx ++; qx ++; } break; case 1: for(j=0;j tl) _ze = tl; zb[qx] = _zb; ze[qx] = _ze; qx ++; } break; default: tx += len; } } // trim band beg _zb = 0; for(i=0;i _zb) _zb = zb[i]; } // trim band end _ze = tl; for(i=ql-1;i>=0;i--){ if(ze[i] > _ze) ze[i] = _ze; else if(ze[i] < _ze) _ze = ze[i]; } // perform alignment for(i=0;i<=tl;i++) rh[i] = SCORE_INF; for(i=0;i= 0 && j >= 0){ d = z[i * rl + (j - zb[i])] & 0x03; if(d == 0){ //add_char_string(qs, bit_base_table[query[i + y.qb]]); //add_char_string(ts, bit_base_table[target[j + y.tb]]); if(query[i + y.qb] == target[j + y.tb]){ //add_char_string(ms, '|'); y.mat ++; } else { //add_char_string(ms, '*'); y.mis ++; } i --; j --; } else if(d == 1){ //add_char_string(qs, bit_base_table[query[i + y.qb]]); //add_char_string(ts, '-'); //add_char_string(ms, '-'); i --; y.ins ++; } else { //add_char_string(qs, '-'); //add_char_string(ts, bit_base_table[target[j + y.tb]]); //add_char_string(ms, '-'); j --; y.del ++; } kswx_push_cigar(cigars2, d, 1); } //reverse_string(qs); //reverse_string(ts); //reverse_string(ms); //printf("%s\n%s\n%s\n", qs->string, ms->string, ts->string); //free_string(qs); //free_string(ts); //free_string(ms); if(1){ if(i >= 0){ y.ins += i + 1; kswx_push_cigar(cigars2, 1, i + 1); } if(j >= 0){ y.del += j + 1; kswx_push_cigar(cigars2, 2, j + 1); } } else { y.qb += i + 1; y.tb += j + 1; } reverse_u32list(cigars2); y.aln = y.mat + y.mis + y.ins + y.del; return y; } static inline kswx_t kswx_refine_affine_alignment_5q(uint8_t *query, int qb, uint8_t *target, int tb, int W, uint8_t QCLP, uint8_t QMIS, uint8_t QDEL, uint8_t QEXT, uint8_t *qvs[7], u32list *cigars, u8list *mem_cache, u32list *cigars2){ kswx_t y; uint32_t *rh, *re, SCORE_INF; int *zb, *ze, *zw; int ql, tl, rl, _zb, _ze, tx, qx; int qe, te; uint8_t *z, *zi; uint8_t d, qmat[4], qins, qdel[4]; register uint32_t h1, h, m, e, f, t; long long i, j; int op, len; SCORE_INF = 0xFFFFFFFFU >> 1; clear_u32list(cigars2); qe = qb; te = tb; for(i=0;i<(int)cigars->size;i++){ op = cigars->buffer[i] & 0xFU; len = cigars->buffer[i] >> 4; switch(op){ case 0: qe += len; te += len; break; case 1: qe += len; break; default: te += len; } } ql = qe - qb; tl = te - tb; if(ql == 0 || tl == 0) return KSWX_NULL; rl = tl; clear_and_encap_u8list(mem_cache, kswx_roundup8x((tl + 2) * sizeof(uint32_t)) * 2 // rh, re + kswx_roundup8x((ql + 2) * sizeof(int)) * 3 // zb, ze, zw + kswx_roundup8x(((long long)ql) * rl)); // z rh = (uint32_t*)(mem_cache->buffer); re = (uint32_t*)(((void*)rh) + kswx_roundup8x((tl + 2) * sizeof(uint32_t))); zb = (int*)(((void*)re) + kswx_roundup8x((tl + 2) * sizeof(uint32_t))); ze = (int*)(((void*)zb) + kswx_roundup8x((ql + 2) * sizeof(int))); zw = (int*)(((void*)ze) + kswx_roundup8x((ql + 2) * sizeof(int))); z = (uint8_t*)(((void*)zw) + kswx_roundup8x((ql + 2) * sizeof(int))); // calculate alignment band // basic band tx = qx = 0; for(i=0;i<(int)cigars->size;i++){ op = cigars->buffer[i] & 0xFU; len = cigars->buffer[i] >> 4; switch(op){ case 0: for(j=0;jsize;i++){ op = cigars->buffer[i] & 0xFU; len = cigars->buffer[i] >> 4; switch(op){ case 0: qx += len; break; case 1: for(j=1;jsize;i++){ op = cigars->buffer[i] & 0xFU; len = cigars->buffer[i] >> 4; switch(op){ case 0: for(j=0;j tl) _ze = tl; zb[qx] = _zb; ze[qx] = _ze; tx ++; qx ++; } break; case 1: for(j=0;j tl) _ze = tl; zb[qx] = _zb; ze[qx] = _ze; qx ++; } break; default: tx += len; } } // trim band beg _zb = 0; for(i=0;i _zb) _zb = zb[i]; } // trim band end _ze = tl; for(i=ql-1;i>=0;i--){ if(ze[i] > _ze) ze[i] = _ze; else if(ze[i] < _ze) _ze = ze[i]; } // perform alignment rh[0] = 0; for(i=1;i<=tl;i++) rh[i] = rh[i - 1] + QCLP; for(i=0;i<=tl;i++) re[i] = SCORE_INF; for(i=0;i f){ d = 2; h = f; } h1 = h; t = m + qins; //e = e + QEXT; e = e + qins; if(e < t){ d |= 1 << 2; } else { e = t; } re[j] = e; t = m + qdel[target[j + tb]]; f = f + QEXT; if(f < t){ d |= 2 << 4; } else { f = t; } zi[j-zb[i]] = d; } rh[j] = h1; re[j] = SCORE_INF; } y.qb = qb; y.qe = qe; y.tb = tb; y.te = te; y.score = - (int)rh[tl]; y.mat = y.mis = y.ins = y.del = y.aln = 0; d = 0; i = ql - 1; j = tl - 1; //String *qs = init_string(1024); //String *ts = init_string(1024); //String *ms = init_string(1024); while(i >= 0 && j >= 0){ d = (z[i * rl + (j - zb[i])] >> (d << 1)) & 0x03; if(d == 0){ //add_char_string(qs, bit_base_table[query[i + y.qb]]); //add_char_string(ts, bit_base_table[target[j + y.tb]]); if(query[i + y.qb] == target[j + y.tb]){ //add_char_string(ms, '|'); y.mat ++; } else { //add_char_string(ms, '*'); y.mis ++; } i --; j --; } else if(d == 1){ //add_char_string(qs, bit_base_table[query[i + y.qb]]); //add_char_string(ts, '-'); //add_char_string(ms, '-'); i --; y.ins ++; } else { //add_char_string(qs, '-'); //add_char_string(ts, bit_base_table[target[j + y.tb]]); //add_char_string(ms, '-'); j --; y.del ++; } kswx_push_cigar(cigars2, d, 1); } //reverse_string(qs); //reverse_string(ts); //reverse_string(ms); //printf("%s\n%s\n%s\n", qs->string, ms->string, ts->string); //free_string(qs); //free_string(ts); //free_string(ms); if(1){ if(i >= 0){ y.ins += i + 1; kswx_push_cigar(cigars2, 1, i + 1); } if(j >= 0){ y.del += j + 1; kswx_push_cigar(cigars2, 2, j + 1); } } else { y.qb += i + 1; y.tb += j + 1; } reverse_u32list(cigars2); y.aln = y.mat + y.mis + y.ins + y.del; return y; } static inline void kswx_cigar2string(String *str, int n, uint32_t *cigar){ int i, j, c, op, len; char ch; for(i=0;i> 4; if(len == 0) continue; if(op > 2){ fprintf(stderr, " -- CIGAR only support M(0),I(1),D(2) cigar, but met ?(%d) in %s -- %s:%d --\n", op, __FUNCTION__, __FILE__, __LINE__); exit(1); } c = 0; encap_string(str, 20); while(len){ str->string[str->size + c] = '0' + (len % 10); len = len / 10; c ++; } for(j=0;j>1;j++){ ch = str->string[str->size + j]; str->string[str->size + j] = str->string[str->size + c - 1 - j]; str->string[str->size + c - 1 - j] = ch; } str->size += c; str->string[str->size++] = "MIDX"[op]; } str->string[str->size] = '\0'; } static inline uint32_t kswx_string2cigar(u32list *cigar, char *str){ uint32_t c, len, op, n; char *p; p = str; len = 0; n = 0; while(*p){ if(*p >= '0' && *p <= '9'){ len = len * 10 + (*p) - '0'; } else { switch(*p){ case 'M': op = 0; break; case 'I': op = 1; break; case 'D': op = 2; break; default: op = 3; } c = (len << 4) | op; if(cigar->size && (cigar->buffer[cigar->size - 1] & 0xFU) == op){ cigar->buffer[cigar->size - 1] += len << 4; } else push_u32list(cigar, c); n ++; len = 0; } p ++; } return n; } static inline void kswx_cigar2pairwise(String *alns[2], uint8_t *seqs[2], int n, uint32_t *cigar){ char *p1, *p2; int i, j, op, len, off[2]; off[0] = off[1] = 0; for(i=0;i> 4; if(len == 0) continue; encap_string(alns[0], len); encap_string(alns[1], len); p1 = alns[0]->string + alns[0]->size; p2 = alns[1]->string + alns[1]->size; switch(op){ case 0: for(j=0;jsize += len; alns[1]->size += len; } alns[0]->string[alns[0]->size] = 0; alns[1]->string[alns[1]->size] = 0; } static inline void kswx_polish_pairwise(char *alns[2], int len){ int i, j, m, c, gaps[2]; while(1){ c = 0; gaps[0] = gaps[1] = 0; for(i=0;i 2){ fprintf(stderr, " -- ZIGAR only support M(0),I(1),D(2) cigar, but met ?(%d) in %s -- %s:%d --\n", op, __FUNCTION__, __FILE__, __LINE__); exit(1); } len = cigar[i] >> 4; if(len == 0) continue; } else { op = 0x1FU; len = 0; } if(op == t) s += len; else { while(s){ ss = (s <= KSWX_ZIGAR_MAX_LEN)? s : KSWX_ZIGAR_MAX_LEN; s -= ss; ss = ss + t * KSWX_ZIGAR_MAX_LEN + KSWX_ZIGAR_ZERO; add_char_string(str, ss); } t = op; s = len; } } } static inline uint32_t kswx_zigar2cigar(u32list *cigar, char *str){ uint32_t c, len, op, s, t; char *p; p = str; op = 0x1FU; len = 0; c = 0; while(1){ if(*p){ s = (*p) - KSWX_ZIGAR_ZERO; t = s / KSWX_ZIGAR_MAX_LEN; s = s % KSWX_ZIGAR_MAX_LEN; } else { t = 0x1FU; s = 0; } if(op == t) len += s; else { if(len){ push_u32list(cigar, (len << 4) | op); c ++; } op = t; len = s; } if(*p == 0) break; p ++; } return c; } static inline void kswx_zigar2string(String *str, char *zigar){ int j, c, op, len, s, t; char ch, *p; p = zigar; op = 0x1FU; len = 0; while(1){ if(*p){ s = (*p) - KSWX_ZIGAR_ZERO; t = s / KSWX_ZIGAR_MAX_LEN; s = s % KSWX_ZIGAR_MAX_LEN; } else { t = 0x1FU; s = 0; } if(op == t) len += s; else { if(len){ c = 0; encap_string(str, 20); while(len){ str->string[str->size + c] = '0' + (len % 10); len = len / 10; c ++; } for(j=0;j>1;j++){ ch = str->string[str->size + j]; str->string[str->size + j] = str->string[str->size + c - 1 - j]; str->string[str->size + c - 1 - j] = ch; } str->size += c; str->string[str->size++] = "MIDX"[op]; } op = t; len = s; } if(*p == '\0') break; p ++; } str->string[str->size] = '\0'; } static inline int kswx_string2zigar(String *zigar, char *str){ uint32_t len, op, n, t, s, ss; char *p; p = str; op = 0; len = 0; n = 0; t = s = 0; while(1){ if(*p >= '0' && *p <= '9'){ len = len * 10 + (*p) - '0'; p ++; continue; } if(*p){ switch(*p){ case 'M': op = 0; break; case 'I': op = 1; break; case 'D': op = 2; break; default: op = 3; fprintf(stderr, " -- ZIGAR only support M(0),I(1),D(2) cigar, but met %c(?) in %s -- %s:%d --\n", *p, __FUNCTION__, __FILE__, __LINE__); fprintf(stderr, "%s\n", str); fflush(stderr); exit(1); } } else { op = 0x1FU; len = 0; } if(op == t){ s += len; len = 0; } else { while(s){ ss = (s <= KSWX_ZIGAR_MAX_LEN)? s : KSWX_ZIGAR_MAX_LEN; s -= ss; ss = ss + t * KSWX_ZIGAR_MAX_LEN + KSWX_ZIGAR_ZERO; add_char_string(zigar, ss); n ++; } t = op; s = len; len = 0; } if(*p == '\0') break; p ++; }; return n; } static inline kswr_t kswx_extend_core(int qlen, uint8_t *query, int tlen, uint8_t *target, kswr_t r, int m, const int8_t *matrix, int w, int I, int D, int E, int T){ int y1, y2, x1, x2, x3, score, gscore, max_off; if(T < 0){ // try extend left do { if(r.qb == 0 || r.tb == 0) break; if(r.tb >= r.qb){ y1 = (r.qb + w > r.tb)? r.tb : r.qb + w; y2 = r.qb; revseq_bytes(target + r.tb - y1, y1); revseq_bytes(query + r.qb - y2, y2); score = ksw_extend2(y2, query + r.qb - y2, y1, target + r.tb - y1, m, matrix, - D, - E, - I, - E, w, - T, -1, r.score, &x2, &x1, &x3, &gscore, &max_off); revseq_bytes(target + r.tb - y1, y1); revseq_bytes(query + r.qb - y2, y2); if(gscore <= 0 || gscore <= score + T){ r.tb = r.tb - x1; r.qb = r.qb - x2; r.score = score; } else { r.tb = r.tb - x3; r.qb = 0; r.score = gscore; } } else { y1 = r.tb; y2 = (r.tb + w > r.qb)? r.qb : r.tb + w; revseq_bytes(target + r.tb - y1, y1); revseq_bytes(query + r.qb - y2, y2); score = ksw_extend2(y1, target + r.tb - y1, y2, query + r.qb - y2, m, matrix, - I, - E, - D, - E, w, - T, -1, r.score, &x1, &x2, &x3, &gscore, &max_off); revseq_bytes(target + r.tb - y1, y1); revseq_bytes(query + r.qb - y2, y2); if(gscore <= 0 || gscore <= score + T){ r.tb = r.tb - x1; r.qb = r.qb - x2; r.score = score; } else { r.qb = r.qb - x3; r.tb = 0; r.score = gscore; } } } while(0); // try extend right do { if(r.qe == qlen || r.te == tlen) break; if(tlen - r.te >= qlen - r.qe){ y1 = (qlen - r.qe + w > tlen - r.te)? tlen - r.te : qlen - r.qe + w; y2 = qlen - r.qe; score = ksw_extend2(y2, query + r.qe, y1, target + r.te, m, matrix, - D, - E, - I, - E, w, - T, -1, r.score, &x2, &x1, &x3, &gscore, &max_off); if(gscore <= 0 || gscore <= score + T){ r.te += x1; r.qe += x2; r.score = score; } else { r.te += x3; r.qe = qlen; r.score = gscore; } } else { y1 = tlen - r.te; y2 = (tlen - r.te + w > qlen - r.qe)? qlen - r.qe : tlen - r.te + w; score = ksw_extend2(y1, target + r.te, y2, query + r.qe, m, matrix, - I, - E, - D, - E, w, - T, -1, r.score, &x1, &x2, &x3, &gscore, &max_off); if(gscore <= 0 || gscore <= score + T){ r.te += x1; r.qe += x2; r.score = score; } else { r.te = tlen; r.qe += x3; r.score = gscore; } } } while(0); } return r; } static inline kswx_t kswx_gen_cigar_core2(int qlen, uint8_t *query, int tlen, uint8_t *target, kswr_t r, int m, const int8_t *matrix, int w, int I, int D, int E, int *_n_cigar, uint32_t **_cigar){ kswx_t x; uint32_t *cigar; int i, j, n_cigar, w2, x1, x2, op, len; UNUSED(qlen); UNUSED(tlen); n_cigar = *_n_cigar; cigar = *_cigar; if(w >= 0){ x1 = r.te - r.tb; x2 = r.qe - r.qb; x1 -= x2; if(x1 < 0) x1 = -x1; if(w < x1 * 1.5) w = x1 * 1.5; w2 = (((r.te - r.tb < r.qe - r.qb)? r.te - r.tb : r.qe - r.qb) * matrix[0] - r.score) / (-E) + 1; if(w2 < (w / 4) + 1) w2 = (w / 4) + 1; if(w > w2) w = w2; } else w = - w; x.score = ksw_global2(r.qe - r.qb, query + r.qb, r.te - r.tb, target + r.tb, m, matrix, - D, - E, - I, - E, w, &n_cigar, &cigar); x.tb = r.tb; x.te = r.te; x.qb = r.qb; x.qe = r.qe; x.aln = x.mat = x.mis = x.ins = x.del = 0; for(i=x1=x2=0;i> 4; x.aln += len; switch(op){ case 0: for(j=0;j * * * 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 3 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, see . */ #ifndef __LIST_RJ_H #define __LIST_RJ_H #include #include #include #include #include "sort.h" #include "mem_share.h" /** * Heap macros */ //ary, size and cap must be explict variable, not expression #define array_heap_push(ary, size, cap, e_type, id, cmp_expr)\ do { \ e_type _pp_, _p_; \ _p_ = (e_type)(id); \ size_t i, j; \ i = (size); \ e_type a, b; \ if((size_t)((size) + 1) > (size_t)(cap)){ \ if((size_t)((size) + 1) < 0xFFFFFFFFU){ \ (cap) = roundup_power2((size) + 1); \ } else { \ (cap) = (((size) + 1 + 0xFFFFFFFLLU - 1LLU) / 0xFFFFFFFLLU) * 0xFFFFFFFLLU; \ } \ (ary) = realloc((ary), sizeof(e_type) * (cap)); \ if((ary) == NULL){ \ fprintf(stderr, " -- Out of memory, try to allocate %llu bytes in %s, -- %s:%d --\n", (unsigned long long)(sizeof(e_type) * (cap)), __FUNCTION__, __FILE__, __LINE__); \ print_backtrace(stderr, 20); \ exit(1); \ } \ } \ (ary)[(size)++] = _p_; \ while(i){ \ j = (i - 1) >> 1; \ a = (ary)[i]; b = (ary)[j]; \ if((cmp_expr) >= 0) break; \ _pp_ = (ary)[i]; (ary)[i] = (ary)[j]; (ary)[j] = _pp_; \ i = j; \ } \ } while(0) #define array_heap_remove(ary, len, cap, e_type, _idx, cmp_expr)\ do { \ e_type _pp_; \ size_t swap, idx; \ idx = (size_t)(_idx); \ (ary)[idx] = (ary)[--(len)]; \ e_type a, b; \ while((size_t)((idx << 1) + 1) < (size_t)(len)){ \ swap = idx; \ a = (ary)[swap]; b = (ary)[(idx << 1) + 1]; \ if((cmp_expr) > 0) swap = (idx << 1) + 1; \ if(((idx << 1) + 2) < (size_t)(len)){ \ a = (ary)[swap]; b = (ary)[(idx << 1) + 2]; \ if((cmp_expr) > 0) swap = (idx << 1) + 2; \ } \ if(swap == idx) break; \ _pp_ = (ary)[idx]; (ary)[idx] = (ary)[swap]; (ary)[swap] = _pp_; \ idx = swap; \ } \ } while(0) #define array_heap_replace(ary, len, cap, e_type, _idx, _val, cmp_expr)\ do { \ e_type _pp_; \ size_t swap, idx; \ idx = (size_t)(_idx); \ (ary)[idx] = _val; \ e_type a, b; \ while((size_t)((idx << 1) + 1) < (size_t)(len)){ \ swap = idx; \ a = (ary)[swap]; b = (ary)[(idx << 1) + 1]; \ if((cmp_expr) > 0) swap = (idx << 1) + 1; \ if(((idx << 1) + 2) < (size_t)(len)){ \ a = (ary)[swap]; b = (ary)[(idx << 1) + 2]; \ if((cmp_expr) > 0) swap = (idx << 1) + 2; \ } \ if(swap == idx) break; \ _pp_ = (ary)[idx]; (ary)[idx] = (ary)[swap]; (ary)[swap] = _pp_; \ idx = swap; \ } \ } while(0) #define array_heap_pop(ary, len, cap, e_type, cmp_expr) \ ({ \ e_type _ret_; \ if(len){ _ret_ = ary[0]; array_heap_remove(ary, len, cap, e_type, 0, cmp_expr); } \ else memset(&_ret_, 0xFFU, sizeof(e_type)); \ _ret_; \ }) /** * List */ #define define_list_core(list_type, e_type, size_type, inc_size) \ \ typedef struct { e_type* buffer; union { size_type size; size_type length; }; size_type cap; size_type off; u4i mem_zero:1, n_head:31; } list_type; \ \ static inline size_t list_type##_obj_desc_cnt(void *list, int idx){ \ if(idx == 0) return ((list_type*)list)->size * sizeof(e_type); \ else return 0; \ } \ \ static inline void list_type##_obj_desc_post_load(void *obj, size_t aux_data){ \ list_type *list; \ UNUSED(aux_data); \ list = (list_type*)obj; \ list->cap = list->size; \ } \ \ static const obj_desc_t list_type##_obj_desc = {.tag = TOSTR(_list_##list_type), .size = sizeof(list_type), .n_child = 1, .mem_type = {1}, .addr = {offsetof(list_type, buffer)}, .desc = {(struct obj_desc_t*)&OBJ_DESC_DATA}, .cnt = list_type##_obj_desc_cnt, .post = list_type##_obj_desc_post_load}; \ \ static inline void adv_##list_type##_init(list_type *list, size_type init_size, int mem_zero, u4i n_head){ \ if(init_size == 0) init_size = 2; \ list->size = 0; \ list->off = 0; \ list->cap = init_size; \ list->mem_zero = mem_zero; \ list->n_head = n_head; \ if(n_head){ \ list->buffer = (e_type*)calloc(list->cap + n_head, sizeof(e_type)); \ list->buffer += n_head; \ } else { \ list->buffer = (e_type*)calloc(list->cap, sizeof(e_type)); \ } \ } \ \ static inline list_type* adv_init_##list_type(size_type init_size, int mem_zero, u4i n_head){ \ list_type *list = (list_type*)malloc(sizeof(list_type)); \ adv_##list_type##_init(list, init_size, mem_zero, n_head); \ return list; \ } \ \ static inline list_type* init_##list_type(size_type init_size){ \ return adv_init_##list_type(init_size, 0, 0); \ } \ \ static inline void list_type##_init(list_type *list, size_type init_size){ \ adv_##list_type##_init(list, init_size, 0, 0); \ } \ \ static inline int head_sl_##list_type(list_type *list, size_type len){ \ if(list->n_head < len) return 0; \ list->buffer -= len; \ list->n_head -= len; \ list->cap += len; \ if(list->size) list->size += len; \ return 1; \ } \ \ static inline int head_sr_##list_type(list_type *list, size_type len){ \ if(list->cap < len) return 0; \ list->buffer += len; \ list->n_head += len; \ list->cap -= len; \ if(list->size > len) list->size -= len; \ else list->size = 0; \ return 1; \ } \ \ static inline void renew_##list_type(list_type *list, size_type init_size){ \ if(list->buffer) free(list->buffer - list->n_head); \ adv_##list_type##_init(list, init_size, list->mem_zero, list->n_head); \ } \ \ static inline size_type count_##list_type(list_type *list){ return list->size; } \ \ static inline void clear_##list_type(list_type *list){ list->size = 0; list->off = 0; } \ \ static inline void zeros_##list_type(list_type *list){ memset(list->buffer, 0, list->cap * sizeof(e_type)); } \ \ static inline void encap_##list_type(list_type *list, size_type n){ \ list->cap = encap_list((void**)&list->buffer, sizeof(e_type), list->size, list->cap, n, list->mem_zero, list->n_head); \ } \ \ static inline void recap_##list_type(list_type *list, size_type n){ \ if((size_t)n == (size_t)list->cap) return; \ list->cap = n; \ if(list->size > n) list->size = n; \ list->buffer = realloc(list->buffer - list->n_head, (list->cap + list->n_head) * sizeof(e_type)) + list->n_head; \ } \ \ static inline void pack_##list_type(list_type *list){ \ return recap_##list_type(list, list->size); \ } \ \ static inline void encap_and_zeros_##list_type(list_type *list, size_type n){ \ if(((size_t)list->size) + ((size_t)n) <= (size_t)list->cap){ \ } else { \ if((size_t)(list->size + n) != ((size_t)list->size) + ((size_t)n)){ \ fprintf(stderr, " -- elements size exceed %s's data type %s in %s -- %s:%d --\n", #list_type, #size_type, __FUNCTION__, __FILE__, __LINE__); \ print_backtrace(stderr, 20); \ fflush(stderr); \ exit(1); \ } \ while(list->size + n > list->cap){ \ if(list->cap < inc_size){ \ list->cap <<= 1; \ } else { \ list->cap += inc_size; \ } \ } \ list->buffer = realloc(list->buffer, list->cap * sizeof(e_type)); \ } \ memset(list->buffer + list->size, 0, n * sizeof(e_type)); \ } \ \ static inline void clear_and_encap_##list_type(list_type *list, size_type n){ \ list->size = 0; \ list->off = 0; \ encap_##list_type(list, n); \ } \ \ static inline void clear_and_inc_##list_type(list_type *list, size_type n){ \ list->size = 0; \ list->off = 0; \ encap_##list_type(list, n); \ list->size = n; \ } \ \ static inline void trunc_##list_type(list_type *list, size_type size){ \ if(size > count_##list_type(list)) size = count_##list_type(list); \ list->size -= size; \ } \ \ static inline void set_##list_type##_size(list_type *list, size_type size){ list->size = size; } \ \ static inline void inc_##list_type(list_type *list, size_type size){ \ encap_##list_type(list, size); \ list->size += size; \ } \ \ static inline void lazy_push_##list_type(list_type *list, e_type e){ list->buffer[list->size ++] = e; } \ \ static inline void push_##list_type(list_type *list, e_type e){ \ encap_##list_type(list, 1); \ list->buffer[list->size++] = e; \ } \ \ static inline e_type* ring_ref_##list_type(list_type *list, size_type idx){ \ idx = (list->off + idx) % list->cap; \ return list->buffer + idx; \ } \ \ static inline void ring_push_##list_type(list_type *list, e_type e){ \ size_type idx; \ idx = (list->off + list->size) % list->cap; \ list->buffer[idx] = e; \ if(list->size < list->cap){ \ list->size ++; \ } \ } \ \ static inline e_type* ring_peer_##list_type(list_type *list){ \ if(list->size){ \ return list->buffer + list->size - 1; \ } else return NULL; \ } \ \ static inline e_type* ring_pop_##list_type(list_type *list){ \ size_type idx; \ if(list->size){ \ list->size --; \ idx = (list->off + list->size) % list->cap; \ return list->buffer + idx; \ } else return NULL; \ } \ \ static inline void ring_shift_##list_type(list_type *list, e_type e){ \ list->off = (list->off + list->cap - 1) % list->cap; \ list->buffer[list->off] = e; \ if(list->size < list->cap){ \ list->size ++; \ } \ } \ \ static inline e_type* ring_unshift_##list_type(list_type *list){ \ size_type idx; \ if(list->size){ \ list->size --; \ list->off = (list->off + 1) % list->cap; \ idx = (list->off + list->size) % list->cap; \ return list->buffer + idx; \ } else return NULL; \ } \ \ static inline int fpush_##list_type(list_type *list, FILE *inp){ \ int ret; \ encap_##list_type(list, 1); \ ret = fread(list->buffer + list->size, sizeof(e_type), 1, inp); \ if(ret == 1) list->size ++; \ return ret; \ } \ \ static inline e_type* peer_##list_type(list_type *list){ \ if(count_##list_type(list)){ \ return list->buffer + list->size - 1; \ } else return NULL; \ } \ \ static inline e_type* head_##list_type(list_type *list){ \ if(list->size) return list->buffer; \ else return NULL; \ } \ \ static inline e_type* tail_##list_type(list_type *list){ \ if(list->size) return list->buffer + list->size - 1; \ else return NULL; \ } \ static inline int pop_##list_type(list_type *list, e_type*e){ \ if(count_##list_type(list)){ \ list->size --; \ *e = list->buffer[list->size]; \ return 1; \ } else return 0; \ } \ \ static inline int fpop_##list_type(list_type *list, FILE *oup){ \ if(list->size){ \ fwrite(list->buffer + list->size - 1, sizeof(e_type), 1, oup); \ list->size --; \ return 1; \ } else { \ return 0; \ } \ } \ \ static inline void insert_##list_type(list_type *list, size_type idx, e_type e){ \ if(idx > list->size) return; \ encap_##list_type(list, 1); \ if(idx == list->size){ \ list->buffer[list->size] = e; \ } else { \ memmove(list->buffer + idx + 1, list->buffer + idx, (list->size - idx) * sizeof(e_type)); \ list->buffer[idx] = e; \ } \ list->size ++; \ } \ \ static inline void insert_array_##list_type(list_type *list, size_type idx, e_type *es, size_type size){ \ if(idx > list->size) return; \ encap_##list_type(list, size); \ if(idx == list->size){ \ } else { \ memmove(list->buffer + idx + size, list->buffer + idx, (list->size - idx) * sizeof(e_type)); \ } \ memcpy(list->buffer + idx, es, size * sizeof(e_type)); \ list->size += size; \ } \ \ static inline void remove_##list_type(list_type *list, size_type idx){ \ if(idx >= list->size) return; \ if(idx + 1 < list->size){ \ memmove(list->buffer + idx, list->buffer + idx + 1, (list->size - idx - 1) * sizeof(e_type)); \ } \ list->size --; \ } \ \ static inline void remove_array_##list_type(list_type *list, size_type off, size_type len){ \ if(off >= list->size) return; \ if(off + len < list->size){ \ memmove(list->buffer + off, list->buffer + off + len, (list->size - off - len) * sizeof(e_type)); \ list->size -= len; \ } else { \ list->size = off; \ } \ } \ \ static inline void set_##list_type(list_type *list, size_type idx, e_type e){ list->buffer[idx] = e; } \ \ static inline e_type get_##list_type(list_type *list, size_type idx){ return list->buffer[idx]; } \ \ static inline e_type* ref_##list_type(list_type *list, size_type idx){ return list->buffer + idx; } \ \ static inline size_type offset_##list_type(list_type *list, e_type *e){ return e - list->buffer; } \ \ static inline e_type* next_ref_##list_type(list_type *list){ encap_##list_type(list, 1); list->size ++; return list->buffer + list->size - 1; } \ \ static inline e_type* ref_next_##list_type(list_type *list){ list->size ++; return list->buffer + list->size - 1; } \ \ static inline e_type* as_array_##list_type(list_type *list){ return list->buffer; } \ \ static inline void reverse_##list_type(list_type *list){ \ size_type i, j; \ e_type t; \ if(count_##list_type(list) == 0) return; \ i = 0; \ j = count_##list_type(list) - 1; \ while(i < j){ \ t = get_##list_type(list, i); \ set_##list_type(list, i, get_##list_type(list, j)); \ set_##list_type(list, j, t); \ i ++; \ j --; \ } \ } \ \ static inline void sub_reverse_##list_type(list_type *list, size_type beg, size_type end){ \ size_type i, j; \ e_type t; \ if(end <= beg) return; \ i = beg; \ j = end - 1; \ while(i < j){ \ t = get_##list_type(list, i); \ set_##list_type(list, i, get_##list_type(list, j)); \ set_##list_type(list, j, t); \ i ++; \ j --; \ } \ } \ \ static inline void append_##list_type(list_type *list1, list_type *list2){ \ encap_##list_type(list1, count_##list_type(list2)); \ memcpy(list1->buffer + list1->size, list2->buffer, sizeof(e_type) * list2->size); \ list1->size += list2->size; \ } \ \ static inline void append_array_##list_type(list_type *list1, e_type *ary, size_type size){ \ if(size == 0) return; \ encap_##list_type(list1, size); \ memcpy(list1->buffer + list1->size, ary, sizeof(e_type) * size); \ list1->size += size; \ } \ \ static inline size_type write_##list_type(list_type *list, FILE *out){ \ return fwrite(list->buffer, sizeof(e_type), count_##list_type(list), out); \ } \ \ static inline size_type dump_##list_type(list_type *list, FILE *out){ \ fwrite(&list->size, sizeof(size_type), 1, out); \ fwrite(list->buffer, sizeof(e_type), list->size, out); \ return sizeof(size_type) + sizeof(e_type) * list->size; \ } \ \ static inline size_t mem_size_##list_type(list_type *list){ \ return ((sizeof(list_type) + 7) / 8) * 8 + (list->size * sizeof(e_type) + 7) / 8 * 8; \ } \ \ static inline size_t mem_dump_##list_type(list_type *list, FILE *out, void *addr){ \ list_type clone; \ size_t size; \ b1i i, v; \ size = mem_size_##list_type(list); \ clone.size = list->size; \ clone.cap = list->size; \ clone.buffer = addr + (sizeof(list_type) + 7) / 8 * 8; \ fwrite(&clone, sizeof(list_type), 1, out); \ v = 0; \ for(i=(sizeof(list_type) + 7) / 8 * 8 - sizeof(list_type);i>0;i--) fwrite(&v, 1, 1, out); \ fwrite(list->buffer, sizeof(e_type), list->size, out); \ for(i=(sizeof(e_type) * list->size + 7) / 8 * 8 - sizeof(e_type) * list->size;i>0;i--) fwrite(&v, 1, 1, out); \ return size; \ } \ \ static inline list_type* load_##list_type(FILE *inp){ \ list_type *list; \ size_type n; \ list = (list_type*)malloc(sizeof(list_type)); \ if((n = fread(&list->size, sizeof(size_type), 1, inp)) != 1){ \ free(list); return NULL; \ } \ list->cap = list->size; \ list->buffer = (e_type*)malloc(sizeof(e_type) * list->cap); \ if(list->buffer == NULL){ \ fprintf(stderr, " Out of memory in load_%s \n", #list_type); fflush(stderr); exit(1); \ print_backtrace(stderr, 20); \ } \ if((n = fread(list->buffer, sizeof(e_type), list->size, inp)) != list->size){ \ print_backtrace(stderr, 20); \ free(list->buffer); free(list); return NULL; \ } \ return list; \ } \ \ static inline void free_##list_type(list_type *list){ if(list){ free(list->buffer - list->n_head); free(list); } } \ \ static inline void list_type##_free(list_type *list){ free(list->buffer); list->buffer = NULL; } \ #define define_list_ext(list_type, e_type, size_type, cmp_func) \ static inline size_type delete_##list_type(list_type *list, e_type e){ \ size_type i, ret; \ ret = 0; \ for(i=list->size;i>0;i--){ \ if(cmp_func(list->buffer[i-1], e, NULL) == 0){ \ if(i < list->size){ \ memmove(list->buffer + i - 1, list->buffer + i, (list->size - i) * sizeof(e_type)); \ } \ list->size --; \ ret ++; \ } \ } \ return ret; \ } \ \ static inline size_type occ_##list_type(list_type *list, e_type e){ \ size_type i, n; \ for(i=0,n=0;isize;i++){ \ if(cmp_func(list->buffer[i], e, NULL) == 0) n++; \ } \ return n; \ } \ \ static inline size_type replace_##list_type(list_type *list, e_type from, e_type to){ \ size_type i, ret; \ ret = 0; \ for(i=0;isize;i++){ \ if(cmp_func(list->buffer[i], from, NULL) == 0){ \ list->buffer[i] = to; \ ret ++; \ } \ } \ return ret; \ } \ \ static inline size_type locate_##list_type(list_type *list, e_type e, size_type start){ \ size_type i; \ for(i=start;isize;i++){ \ if(cmp_func(list->buffer[i], e, NULL) == 0) return i; \ } \ return i; \ } \ \ define_quick_sort(sort_##list_type##_core, e_type, cmp_func); \ \ static inline void sort_##list_type(list_type *list){ sort_##list_type##_core(ref_##list_type(list, 0), count_##list_type(list), NULL); } #define define_list(name, e_type) define_list_core(name, e_type, size_t, 0xFFFFFU) #define native_number_cmp(e1, e2, obj) (((e1) == (e2))? 0 : (((e1) < (e2))? -1 : 1)) #define define_native_list(name, e_type) \ define_list_core(name, e_type, size_t, 0xFFFFFU); \ define_list_ext(name, e_type, size_t, native_number_cmp); define_native_list(u8list, u1i); define_native_list(u1v, u1i); define_native_list(u16list, u2i); define_native_list(u2v, u2i); define_native_list(u32list, u4i); define_native_list(u4v, u4i); define_native_list(u64list, u8i); define_native_list(u8v, u8i); define_native_list(b8list, b1i); define_native_list(b1v, b1i); define_native_list(b16list, b2i); define_native_list(b2v, b2i); define_native_list(b32list, b4i); define_native_list(b4v, b4i); define_native_list(b64list, b8i); define_native_list(b8v, b8i); define_native_list(f4v, f4i); define_native_list(f8v, f8i); define_list(vplist, void*); define_list(cplist, char*); // mem_share for deep dump of cplist static inline size_t cplist_deep_obj_desc_cnt(void *list, int idx){ if(idx == 0) return ((cplist*)list)->size; else return 1; } static const obj_desc_t cplist_deep_obj_desc = {.tag = "cplist_deep_dump", .size = sizeof(cplist), .n_child = 1, .mem_type = {3}, .addr = {offsetof(cplist, buffer)}, .desc = {(struct obj_desc_t*)&OBJ_DESC_CHAR_ARRAY}, .cnt = cplist_deep_obj_desc_cnt, .post=NULL}; #define define_recycle_list_array(name, list_type) \ typedef struct { \ vplist *array; \ vplist *dustbin; \ } name; \ \ static inline name* init_##name(){ \ name *g; \ g = (name*)malloc(sizeof(name)); \ g->buffer = init_vplist(4); \ g->dustbin = init_vplist(4); \ return g; \ } \ \ static inline void free_##name(name *g){ \ list_type *v; \ size_t i; \ for(i=0;iarray->size;i++){ \ v = (list_type*)get_vplist(g->array, i); \ if(v) free_##list_type(v); \ } \ for(i=0;idustbin->size;i++){ \ v = (list_type*)get_vplist(g->dustbin, i); \ if(v) free_##list_type(v); \ } \ free_vplist(g->array); \ free_vplist(g->dustbin); \ free(g); \ } \ \ static inline list_type* fetch_##name(name *g){ \ list_type *v; \ if(g->dustbin->size) v = (list_type*)g->dustbin->buffer[--g->dustbin->size]; \ else v = init_##list_type(4); \ return v; \ } \ \ static inline void recyc_##name(name *g, list_type *v){ \ push_vplist(g->dustbin, v); \ } \ \ static inline void recyc_all_##name(name *g, vplist *vs){ \ append_vplist(g->dustbin, vs); \ vs->size = 0; \ } // e.g. define_recycle_list(u8r, u8i, u8i, *a = 0, NULL) // u8r, when increase an element, set the to 0 (*a = 0), when free it, do nothing (NULL) #define define_recycle_list(list_type, e_type, size_type, e_init, e_free) \ typedef struct { \ e_type *buffer; \ size_type size, cap; \ size_type *recyc; \ size_type rsize, rcap; \ u8i userdata; \ } list_type; \ \ static inline list_type* init_##list_type(size_type size){ \ list_type *list; \ if(size < 2) size = 2; \ list = malloc(sizeof(list_type)); \ list->size = 0; \ list->cap = size; \ list->buffer = calloc(size, sizeof(e_type)); \ list->recyc = calloc(2, sizeof(size_type)); \ list->rsize = 0; \ list->rcap = 2; \ list->userdata = 0; \ return list; \ } \ \ static inline void free_##list_type(list_type *list){ \ e_type* a; \ size_type i; \ for(i=0;isize;i++){ \ a = list->buffer + i; \ UNUSED(e_free); \ } \ UNUSED(a); \ free(list->buffer); \ free(list->recyc); \ free(list); \ } \ \ static inline void encap_##list_type(list_type *list, size_type inc){ \ if(list->rsize >= inc) return; \ inc -= list->rsize; \ list->cap = encap_list((void**)&list->buffer, sizeof(e_type), list->size, list->cap, inc, 0, 0); \ } \ \ static inline size_type fetch_##list_type(list_type *list){ \ e_type* a; \ if(list->rsize){ \ return list->recyc[--list->rsize]; \ } \ list->cap = encap_list((void**)&list->buffer, sizeof(e_type), list->size, list->cap, 1, 0, 0); \ a = list->buffer + list->size; \ UNUSED(e_init); \ UNUSED(a); \ return list->size ++; \ } \ \ static inline e_type* ref_##list_type(list_type *list, size_type idx){ \ return list->buffer + idx; \ } \ \ static inline size_type offset_##list_type(list_type *list, e_type *e){ \ return e - list->buffer; \ } \ \ static inline void recyc_##list_type(list_type *list, size_type idx){ \ list->rcap = encap_list((void**)&list->recyc, sizeof(size_type), list->rsize, list->rcap, 1, 0, 0); \ list->recyc[list->rsize++] = idx; \ } \ \ static inline e_type* pop_##list_type(list_type *list){ \ size_type idx; \ idx = fetch_##list_type(list); \ return ref_##list_type(list, idx); \ } \ \ static inline void push_##list_type(list_type *list, e_type* e){ \ recyc_##list_type(list, offset_##list_type(list, e)); \ } \ \ static inline void recyc_all_##list_type(list_type *list){ \ size_type i; \ list->rsize = 0; \ list->rcap = encap_list((void**)&list->recyc, sizeof(size_type), list->rsize, list->rcap, list->size, 0, 0); \ for(i=0;isize;i++){ \ list->recyc[i] = i; \ } \ list->rsize = list->size; \ } # endif wtdbg2-2.5/mem_share.h000066400000000000000000001412761353664372200147100ustar00rootroot00000000000000/* * * Copyright (c) 2011, Jue Ruan * * * 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 3 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, see . */ #ifndef __MEM_SHARE_RJ_H #define __MEM_SHARE_RJ_H #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #if defined(__APPLE__) && defined(__MACH__) #include #else #include #endif #include #include //#include #include #include //#include //#include #include #include #include #include #include #include #include #include #include #include #ifndef __HEADER_NO_EXECINFO #include #endif #include #include "thread.h" /** * Data types */ #define MAX_VALUE_U1 0xFFU #define MAX_U1 MAX_VALUE_U1 typedef uint8_t u1i; #define MAX_VALUE_U2 0xFFFFU #define MAX_U2 MAX_VALUE_U2 typedef uint16_t u2i; #define MAX_VALUE_U4 0xFFFFFFFFU #define MAX_U4 MAX_VALUE_U4 typedef uint32_t u4i; #define MAX_VALUE_U8 0xFFFFFFFFFFFFFFFFLLU #define MAX_U8 MAX_VALUE_U8 typedef unsigned long long u8i; #define MAX_VALUE_B1 0x7F #define MAX_B1 MAX_VALUE_B1 typedef int8_t b1i; #define MAX_VALUE_B2 0x7FFF #define MAX_B2 MAX_VALUE_B2 typedef int16_t b2i; #define MAX_VALUE_B4 0x7FFFFFFF #define MAX_B4 MAX_VALUE_B4 typedef int32_t b4i; #define MAX_VALUE_B8 0x7FFFFFFFFFFFFFFFLL #define MAX_B8 MAX_VALUE_B8 typedef long long b8i; typedef float f4i; typedef long double f8i; #define Int(x) ((int)(x)) #define UInt(x) ((unsigned)(x)) #define Int32(x) ((b4i)(x)) #define Int64(x) ((b8i)(x)) #define UInt64(x) ((u8i)(x)) /** * Useful functions */ #define num_min(n1, n2) (((n1) < (n2))? (n1) : (n2)) #define num_max(n1, n2) (((n1) > (n2))? (n1) : (n2)) #define num_diff(n1, n2) (((n1) < (n2))? ((n2) - (n1)) : ((n1) - (n2))) #define num_cmp(a, b) (((a) > (b))? 1 : (((a) < (b))? -1 : -0)) #define num_cmpgt(a, b) ((a) > (b)) #define num_cmpx(a, b, c, d) (((a) > (b))? 1 : (((a) < (b))? -1 : (((c) > (d))? 1 : (((c) < (d))? -1 : 0)))) #define num_cmpgtx(a, b, c, d) (((a) > (b))? 1 : (((a) < (b))? 0 : (((c) > (d))))) #define num_cmpxx(a, b, c, d, e, f) (((a) > (b))? 1 : (((a) < (b))? -1 : (((c) > (d))? 1 : (((c) < (d))? -1 : (((e) > (f))? 1 : (((e) < (f))? -1 : 0)))))) #define num_cmpgtxx(a, b, c, d, e, f) (((a) > (b))? 1 : (((a) < (b))? 0 : (((c) > (d))? 1 : (((c) < (d))? 0 : ((e) > (f)))))) #define num_abs(n) ((n) < 0? -(n) : (n)) #ifndef SWAP_TMP #define SWAP_TMP #define swap_tmp(a, b, t) { t = a; a = b; b = t; } #endif #define swap_var(a, b) { typeof(a) __swap_tmp__ = (a); (a) = (b); (b) = __swap_tmp__; } #define UNUSED(x) (void)(x) #define EXPR(...) __VA_ARGS__ #define _QUOTE_STR(x) #x #define TOSTR(x) _QUOTE_STR(x) #define uc(ch) (((ch) >= 'a' && (ch) <= 'z')? (ch) + 'A' - 'a' : (ch)) #define lc(ch) (((ch) >= 'A' && (ch) <= 'Z')? (ch) + 'a' - 'A' : (ch)) #define get_bit8(bits, idx) ((((bits)[(idx) >> 3]) >> ((idx) & 0x07)) & 0x01) #define get_bit16(bits, idx) ((((bits)[(idx) >> 4]) >> ((idx) & 0x0F)) & 0x01) #define get_bit32(bits, idx) ((((bits)[(idx) >> 5]) >> ((idx) & 0x1F)) & 0x01) #define get_bit64(bits, idx) ((((bits)[(idx) >> 6]) >> ((idx) & 0x3F)) & 0x01) #define get_2bit8(bits, idx) ((((bits)[(idx) >> 2]) >> (((idx) & 0x03) << 1)) & 0x03) #define get_2bit16(bits, idx) ((((bits)[(idx) >> 3]) >> (((idx) & 0x07) << 1)) & 0x03) #define get_2bit32(bits, idx) ((((bits)[(idx) >> 4]) >> (((idx) & 0x0F) << 1)) & 0x03) #define get_2bit64(bits, idx) ((((bits)[(idx) >> 5]) >> (((idx) & 0x1F) << 1)) & 0x03) #define inc_2bit64(bits, idx) (((bits)[(idx) >> 5]) += (1LLU << (((idx) & 0x1F) << 1))) #define get_4bit8(bits, idx) ((((bits)[(idx) >> 1]) >> (((idx) & 0x01) << 2)) & 0x0F) #define get_4bit16(bits, idx) ((((bits)[(idx) >> 2]) >> (((idx) & 0x03) << 2)) & 0x0F) #define get_4bit32(bits, idx) ((((bits)[(idx) >> 3]) >> (((idx) & 0x07) << 2)) & 0x0F) #define get_4bit64(bits, idx) ((((bits)[(idx) >> 4]) >> (((idx) & 0x0F) << 2)) & 0x0F) #define get_8bit16(bits, idx) ((((bits)[(idx) >> 1]) >> (((idx) & 0x01) << 3)) & 0xFF) #define get_8bit32(bits, idx) ((((bits)[(idx) >> 2]) >> (((idx) & 0x03) << 3)) & 0xFF) #define get_8bit64(bits, idx) ((((bits)[(idx) >> 3]) >> (((idx) & 0x07) << 3)) & 0xFF) #ifndef __HEADER_NO_EXECINFO static inline void print_backtrace(FILE *out, int max_frame){ void **buffer; int frames; if(max_frame < 1) max_frame = 1; buffer = malloc(sizeof(void*) * max_frame); frames = backtrace(buffer, max_frame); backtrace_symbols_fd(buffer, frames, fileno(out)); free(buffer); } #else static inline void print_backtrace(FILE *out, int max_frame){ UNUSED(max_frame); fprintf(out, "-- ** Cannot back trace frames ** --\n"); } #endif static inline void num2bits(u8i num, char bits[64]){ int i; for(i=0;i<64;i++){ bits[i] = '0' + ((num >> (63 - i)) & 0x01); } } static inline size_t roundup_power2(size_t v){ if(v == 0) return 0; v --; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; return v + 1; } static inline size_t roundup_times(size_t v, size_t base){ return (v + base - 1) / base * base; } static inline void* malloc16(size_t size){ u1i *p, *q; p = malloc(size + 16); if(p == NULL) return NULL; q = (u1i*)(((u8i)(p + 16)) & (~0xFLLU)); *(q - 1) = q - p; return q; } static inline void free16(void *ptr){ u1i *p, *q; q = (u1i*)ptr; p = q - *(q - 1); free(p); } static inline size_t encap_list(void **buffer, size_t e_size, size_t size, size_t cur_cap, size_t inc, int mem_zeros, size_t n_head){ void *ptr; size_t cap; if(cur_cap - size >= inc) return cur_cap; if(MAX_U8 - inc <= size){ fprintf(stderr, " -- Overflow(64bits) %llu + %llu, in %s -- %s:%d --\n", (u8i)size, (u8i)inc, __FUNCTION__, __FILE__, __LINE__); print_backtrace(stderr, 20); abort(); } if(MAX_U8 - inc < 0x3FFFFFFFLLU){ fprintf(stderr, " -- Overflow(64bits) %llu + %llu, in %s -- %s:%d --\n", (u8i)size, (u8i)inc, __FUNCTION__, __FILE__, __LINE__); print_backtrace(stderr, 20); abort(); } if(size + inc < 0x3FFFFFFFLLU){ cap = roundup_power2(size + inc); } else { cap = (size + inc + 0x3FFFFFFFLLU) & (MAX_U8 << 30); } ptr = realloc((*buffer) - n_head * e_size, e_size * (cap + n_head)); if(ptr == NULL){ fprintf(stderr, " -- Out of memory, try to allocate %llu bytes, old size %llu, old addr %p in %s -- %s:%d --\n", (unsigned long long)(e_size * (cap + n_head)), (unsigned long long)(e_size * (cur_cap + n_head)), *buffer, __FUNCTION__, __FILE__, __LINE__); print_backtrace(stderr, 20); abort(); } *buffer = ptr + n_head * e_size; if(mem_zeros) memset((*buffer) + (cur_cap * e_size), 0, e_size * (cap - cur_cap)); return cap; } #define ZEROS(e) memset((void*)(e), 0, sizeof(*(e))) #ifndef __USE_GNU # define TEMP_FAILURE_RETRY(expression) \ ({ \ long int __result; \ do __result = (long int) (expression); \ while (__result == -1L && errno == EINTR); \ __result; \ }) #endif static inline void nano_sleep(u8i nsec){ struct timespec timeout; timeout.tv_sec = nsec/1000000000; timeout.tv_nsec = nsec%1000000000; nanosleep(&timeout, NULL); } #define micro_sleep(usec) nano_sleep(((u8i)(usec)) * 1000LLU) #define microsleep(usec) micro_sleep(usec) static inline long long microtime(){ struct timeval tv; gettimeofday(&tv, NULL); return ((long long)tv.tv_sec) * 1000000 + tv.tv_usec; } static inline char* date(){ time_t tm; char *dstr, *p; tm = time(NULL); p = dstr = asctime(localtime(&tm)); while(*p){ if(*p == '\n'){ *p = 0; break; } p ++; } return dstr; } static inline int replace_char(char *str, char src, char dst, int max){ int ret; ret = 0; while(*str){ if((*str) == src){ (*str) = dst; ret ++; if(ret == max) break; } str ++; } return ret; } static inline int file_exists(const char *filename){ char *realpath; struct stat s; realpath = canonicalize_file_name(filename); if(realpath == NULL) return 0; if(stat(realpath, &s) == -1){ free(realpath); return 0; } free(realpath); switch(s.st_mode & S_IFMT){ //case S_IFBLK: //case S_IFCHR: //case S_IFDIR: //case S_IFIFO: //case S_IFSOCK: //case S_IFLNK: case S_IFREG: return 1; default: return 0; } } static inline int dir_exists(const char *filename){ char *realpath; struct stat s; realpath = canonicalize_file_name(filename); if(realpath == NULL) return 0; if(stat(realpath, &s) == -1){ free(realpath); return 0; } free(realpath); switch(s.st_mode & S_IFMT){ //case S_IFBLK: //case S_IFCHR: //case S_IFREG: //case S_IFIFO: //case S_IFSOCK: //case S_IFLNK: case S_IFDIR: return 1; default: return 0; } } static inline char* relative_filename(char *filename){ char *ptr; if(filename == NULL) return NULL; ptr = filename + strlen(filename); while(ptr >= filename){ if(*ptr == '/') break; ptr --; } return strdup(ptr + 1); } static inline char* absolute_filename(char *filename){ char *path, *cwd, *ptr; int x, y, z, i; if(filename == NULL) return NULL; if(filename[0] == '/') return strdup(filename); cwd = getcwd(NULL, 0); path = malloc(strlen(cwd) + strlen(filename) + 2); x = 0; y = 0; z = 0; ptr = filename; while(*ptr){ if((*ptr) == '.'){ z ++; if(z > 2) break; } else if((*ptr) == '/'){ y = ptr - filename + 1; if(z == 2) x ++; z = 0; } else { break; } ptr ++; } z = 0; i = strlen(cwd); while(x && i){ while(i){ i --; if(cwd[i] == '/') break; } x --; } if(x || i == 0){ fprintf(stderr, " -- BAD File name: '%s'. PWD = '%s' --\n", filename, cwd); fflush(stderr); free(cwd); return NULL; } strncpy(path, cwd, i); free(cwd); path[i] = '/'; strncpy(path + i + 1, filename + y, strlen(filename) - y); path[i + 1 + strlen(filename) - y] = 0; return path; } static inline int exists_file(char *dir, char *filename){ char *realpath, *fullname; int ret; realpath = absolute_filename(dir? dir : "."); if(!dir_exists(realpath)){ free(realpath); return 0; } fullname = malloc(strlen(realpath) + strlen(filename) + 3); sprintf(fullname, "%s/%s", realpath, filename); free(realpath); ret = file_exists(fullname); free(fullname); return ret; } static inline FILE* open_file_for_read(char *name, char *suffix){ char *full_name; FILE *file; if(name == NULL && suffix == NULL){ full_name = "-"; } else if(suffix == NULL){ full_name = name; } else { full_name = (char*)alloca(strlen(name) + strlen(suffix) + 1); memcpy(full_name, name, strlen(name)); memcpy(full_name + strlen(name), suffix, strlen(suffix) + 1); } if(strcmp(full_name, "-") == 0){ file = stdin; } else { file = fopen(full_name, "r"); } if(file == NULL){ fprintf(stderr, "Cannot open file for read: %s\n", full_name); perror(NULL); exit(1); } return file; } static inline FILE* open_file_for_write(char *name, char *suffix, int overwrite){ char *full_name; FILE *file; if(name == NULL && suffix == NULL){ full_name = "-"; } else if(suffix == NULL){ full_name = name; } else { full_name = (char*)alloca(strlen(name) + strlen(suffix) + 1); memcpy(full_name, name, strlen(name)); memcpy(full_name + strlen(name), suffix, strlen(suffix) + 1); } if(strcmp(full_name, "-") == 0){ file = stdout; } else if(!overwrite && file_exists(full_name)){ fprintf(stderr, "File exists: %s\n", full_name); exit(1); } else { file = fopen(full_name, "w+"); } if(file == NULL){ fprintf(stderr, "Cannot open file for write: %s\n", full_name); perror(NULL); exit(1); } return file; } static inline FILE* open_file_for_append(char *name, char *suffix){ char *full_name; FILE *file; if(name == NULL && suffix == NULL){ full_name = "-"; } else if(suffix == NULL){ full_name = name; } else { full_name = (char*)alloca(strlen(name) + strlen(suffix) + 1); memcpy(full_name, name, strlen(name)); memcpy(full_name + strlen(name), suffix, strlen(suffix) + 1); } if(strcmp(full_name, "-") == 0){ file = stdout; } else { file = fopen(full_name, "a+"); } if(file == NULL){ fprintf(stderr, "Cannot open file for append: %s\n", full_name); perror(NULL); exit(1); } return file; } static inline void close_file(FILE *file){ if(file == NULL) return; if(file == stdin || file == stdout || file == stderr) return; if(fclose(file)) perror("Error on close file"); } #define STEP_WISE_BUFF_SIZE 4096 static inline size_t fread_stepwise(void *_ptr, size_t size, size_t ne, FILE *stream){ void *ptr; size_t ret, len, n, sz; ret = 0; ptr = _ptr; sz = STEP_WISE_BUFF_SIZE / size; if(sz < 1) sz = 1; while(ne){ len = num_min(ne, sz); if((n = fread(ptr, size, len, stream)) == 0){ break; } ret += n; ptr += n; ne -= n; } return ret; } //static inline u8i total_sys_memory(){ return getpagesize() * get_phys_pages(); } //static inline u8i avail_sys_memory(){ return getpagesize() * get_avphys_pages(); } //static inline u8i proc_maxrss_memory(){ struct rusage ru; if(getrusage(RUSAGE_SELF, &ru) != -1){ return ru.ru_maxrss * 1024; } else { return 0; } } /* * runtime memory usage, adopt from Heng's runlib */ static inline int get_linux_sys_info(u8i *memtotal, u8i *memavail, int *ncpu){ FILE *fp; char buffer[64]; u8i freed, buffered, cached; int core; if(memtotal || memavail){ freed = buffered = cached = 0; fp = open_file_for_read("/proc/meminfo", NULL); while((fscanf(fp, "%s", buffer)) > 0){ if (strstr(buffer, "MemTotal") == buffer) { fscanf(fp, "%llu", memtotal); (*memtotal) *= 1024; } else if (strstr(buffer, "MemFree") == buffer) { fscanf(fp, "%llu", &freed); } else if (strstr(buffer, "Buffers") == buffer) { fscanf(fp, "%llu", &buffered); } else if (strstr(buffer, "Cached") == buffer) { fscanf(fp, "%llu", &cached); } } fclose(fp); if(memavail){ *memavail = (freed + buffered + cached) * 1024; } } if(ncpu){ fp = open_file_for_read("/proc/cpuinfo", NULL); core = 0; while((fscanf(fp, "%s", buffer)) > 0){ if (strstr(buffer, "processor") == buffer) { core ++; } } fclose(fp); *ncpu = core; } return 0; } static inline int get_linux_proc_info(u8i *rss, u8i *vsize, double *utime, double *stime){ int c, n_spc; char str[64]; FILE *fp; unsigned long tmp, tmp2; size_t page_size; *rss = *vsize = 0; *utime = *stime = 0; //page_size = getpagesize(); page_size = sysconf(_SC_PAGESIZE); sprintf(str, "/proc/%u/stat", getpid()); fp = open_file_for_read(str, NULL); n_spc = 0; while ((c = fgetc(fp)) != EOF) { if (c == ' ') ++n_spc; if (n_spc == 13) break; } fscanf(fp, "%lu%lu", &tmp, &tmp2); *utime = tmp / 100.0; *stime = tmp2 / 100.0; ++n_spc; while ((c = fgetc(fp)) != EOF) { if (c == ' ') ++n_spc; if (n_spc == 22) break; } fscanf(fp, "%lu%lu", &tmp, &tmp2); fclose(fp); *vsize = tmp; *rss = tmp2 * page_size; return 0; } thread_beg_def(_proc_deamon); u8i memtotal, memavail; int ncpu; u8i max_rss, max_vsz; u8i rss_limit; double utime, stime, rtime; double rtime_limit; int interval; thread_end_def(_proc_deamon); static struct _proc_deamon_struct* _sig_proc_deamon = NULL; static inline void print_proc_stat_info(int signum){ FILE *log; if(_sig_proc_deamon == NULL) return; log = stderr; thread_beg_syn_read(_sig_proc_deamon); fprintf(log, "** PROC_STAT(%d) **: real %.3f sec, user %.3f sec, sys %.3f sec, maxrss %.1f kB, maxvsize %.1f kB\n", signum, _sig_proc_deamon->rtime, _sig_proc_deamon->utime, _sig_proc_deamon->stime, _sig_proc_deamon->max_rss / 1024.0, _sig_proc_deamon->max_vsz / 1024.0); thread_end_syn_read(_sig_proc_deamon); //if(signum > 0) fprintf(log, "-- noticed by signal %d\n", signum); //else fprintf(log, "-- noticed by program\n"); //fprintf(log, "-- real %16.3f sec\n", _sig_proc_deamon->rtime); //fprintf(log, "-- user %16.3f sec\n", _sig_proc_deamon->utime); //fprintf(log, "-- sys %16.3f sec\n", _sig_proc_deamon->stime); //fprintf(log, "-- maxrss %16.3f kB\n", _sig_proc_deamon->max_rss / 1024.0); //fprintf(log, "-- maxvsize %16.3f kB\n", _sig_proc_deamon->max_vsz / 1024.0); //fprintf(log, "--\n"); fflush(log); } static inline void _deamon_config_proc_limit(int signum){ char *val; u8i rss_limit, rtime_limit; UNUSED(signum); if(_sig_proc_deamon == NULL) return; thread_beg_syn_write(_sig_proc_deamon); val = getenv("LIMIT_RSS"); if(val){ rss_limit = atol(val) * 1024 * 1024; } else { rss_limit = 0; } val = getenv("LIMIT_RTIME"); if(val){ rtime_limit = atol(val); } else { rtime_limit = 0; } _sig_proc_deamon->rss_limit = rss_limit; _sig_proc_deamon->rtime_limit = rtime_limit; fprintf(stderr, "** PROC_LIMIT: max rss = %llu MB rtime = %llu secs. **\n", rss_limit / 1024 * 1024, rtime_limit); thread_end_syn_write(_sig_proc_deamon); } thread_beg_func(_proc_deamon); u8i rss, vsz; u8i cb, ce; cb = microtime(); get_linux_sys_info((u8i*)&_proc_deamon->memtotal, (u8i*)&_proc_deamon->memavail, (int*)&_proc_deamon->ncpu); _proc_deamon->max_rss = 0; _proc_deamon->max_vsz = 0; _proc_deamon->rtime = 0; _proc_deamon->rss_limit = 0; _proc_deamon->rtime_limit = 0; _proc_deamon->interval = 100000; // 0.1 sec get_linux_proc_info(&rss, &vsz, (double*)&_proc_deamon->utime, (double*)&_proc_deamon->stime); _sig_proc_deamon = (struct _proc_deamon_struct*)_proc_deamon; signal(SIGUSR1, _deamon_config_proc_limit); signal(SIGUSR2, print_proc_stat_info); _proc_deamon->once = 0; // Don't set ->state to 0 at thread_end_loop thread_beg_loop(_proc_deamon); thread_beg_syn_write(_proc_deamon); get_linux_proc_info(&rss, &vsz, (double*)&_proc_deamon->utime, (double*)&_proc_deamon->stime); if(rss > _proc_deamon->max_rss) _proc_deamon->max_rss = rss; if(vsz > _proc_deamon->max_vsz) _proc_deamon->max_vsz = vsz; ce = microtime(); _proc_deamon->rtime = (ce - cb) / 1000000.0; thread_end_syn_write(_proc_deamon); if(_proc_deamon->rss_limit && rss > _proc_deamon->rss_limit){ fprintf(stderr, "-- Exceed memory limit: %llu > %llu\n", rss, _proc_deamon->rss_limit); abort(); } if(_proc_deamon->rtime_limit){ if(_proc_deamon->rtime > _proc_deamon->rtime_limit){ fprintf(stderr, "-- Timeout: %16.3f > %16.3f\n", _proc_deamon->rtime, _proc_deamon->rtime_limit); abort(); } } microsleep(_proc_deamon->interval); // 0.1 sec thread_end_loop(_proc_deamon); get_linux_proc_info(&rss, &vsz, (double*)&_proc_deamon->utime, (double*)&_proc_deamon->stime); if(rss > _proc_deamon->max_rss) _proc_deamon->max_rss = rss; if(vsz > _proc_deamon->max_vsz) _proc_deamon->max_vsz = vsz; ce = microtime(); _proc_deamon->rtime = (ce - cb) / 1000000.0; thread_end_func(_proc_deamon); #if defined(__linux__) || defined(__unix__) || defined(__CYGWIN__) #define BEG_STAT_PROC_INFO(log, argc, argv) \ thread_preprocess(_proc_deamon); \ thread_beg_init(_proc_deamon, 1); \ thread_end_init(_proc_deamon); \ thread_wake_all(_proc_deamon); \ if(log){ \ fprintf(log, "--\n"); \ fprintf(log, "-- total memory %16.1f kB\n", _proc_deamon->memtotal / 1024.0); \ fprintf(log, "-- available %16.1f kB\n", _proc_deamon->memavail / 1024.0); \ fprintf(log, "-- %d cores\n", _proc_deamon->ncpu); \ int i; \ char **opts; \ opts = (char**)argv; \ fprintf(log, "-- Starting program:"); \ for(i=0;irss_limit = memory; \ _proc_deamon->rtime_limit = time; \ thread_end_iter(_proc_deamon) #else #define SET_PROC_LIMIT(memory, time) #endif #if defined(__linux__) || defined(__unix__) || defined(__CYGWIN__) #define END_STAT_PROC_INFO(log) \ _proc_deamon->once = 1; \ thread_beg_close(_proc_deamon); \ if(log){ \ fprintf(log, "** PROC_STAT(TOTAL) **: real %.3f sec, user %.3f sec, sys %.3f sec, maxrss %.1f kB, maxvsize %.1f kB\n---\n", _sig_proc_deamon->rtime, _sig_proc_deamon->utime, _sig_proc_deamon->stime, _sig_proc_deamon->max_rss / 1024.0, _sig_proc_deamon->max_vsz / 1024.0); \ } \ thread_end_close(_proc_deamon) #else #define END_STAT_PROC_INFO(log) \ if(log){ \ fprintf(log, "-- proc stat failed: only support 'linux, unix, cygwin' OS --\n"); \ } #endif // Object I/O /** * Careful: when two pointers refer to the same addr of a object, we cannot make sure of it after mem_load */ #ifndef OBJ_DESC_MAX_CHILD #define OBJ_DESC_MAX_CHILD 64 #endif static inline size_t mem_size_round(size_t size){ return (size + 7) & 0xFFFFFFFFFFFFFFF8LLU; } static inline uint8_t mem_size_gap(size_t size){ return (size & 0x07U)? 8 - (size & 0x07U) : 0; } static inline size_t mem_dump(void *mem, size_t len, FILE *out){ size_t size; uint8_t i, v; if(mem == NULL) return 0; size = mem_size_round(len); if(out){ fwrite(mem, 1, len, out); v = 0; for(i=0;isize or sizeof(void*) bytes typedef struct obj_desc_t { const char *tag; size_t size; // If size = 0, it is virtual, mem_type will be OR with MEM_PTR_TYPE_DUMP. See OBJ_DESC_CHAR_ARRAY int n_child; // <= OBJ_DESC_MAX_CHILD. uint8_t mem_type[OBJ_DESC_MAX_CHILD]; off_t addr[OBJ_DESC_MAX_CHILD]; // offsetof(type, field) const struct obj_desc_t *desc[OBJ_DESC_MAX_CHILD]; mem_array_count cnt; mem_load_post post; } obj_desc_t; // Basic obj_desc_t, size = 1 byte static const struct obj_desc_t OBJ_DESC_DATA = {"OBJ_DESC_DATA", 1, 0, {}, {}, {}, NULL, NULL}; // Special obj_desc_t for string, set mem_type=0 and addr=0 to call the _char_array_obj_desc_cnt on itself // so that we know the length of string, then set size=0 to indicate that it is an virtual reference, program should add MEM_PTR_TYPE_DUMP to its mem_type static inline size_t _char_array_obj_desc_cnt(void *obj, int idx){ if(idx == 0 && obj) return strlen((char*)obj) + 1; else return 0; } static const struct obj_desc_t OBJ_DESC_CHAR_ARRAY = {"OBJ_DESC_CHAR_ARRAY", 0, 1, {0}, {0}, {&OBJ_DESC_DATA}, _char_array_obj_desc_cnt, NULL}; static inline size_t mem_size_obj(void *obj, uint8_t mem_type, const obj_desc_t *desc, size_t size, size_t cnt){ size_t m; void *ref; int i; if(desc == NULL) return size; if(obj == NULL) return size; switch(mem_type){ case 3: size += mem_size_round(sizeof(void*) * cnt); case 2: for(m=0;msize); break; case 1: size += mem_size_round(cnt * desc->size); // TODO: if desc == &OBJ_DESC_DATA, mem_size_round may waste many memory case 0: break; } if(desc->n_child == 0) return size; for(m=0;msize; } for(i=0;in_child;i++){ if(desc->mem_type[i] & 0x01){ size += mem_size_obj(*((void**)(ref + desc->addr[i])), desc->mem_type[i] | (desc->size? 0 : MEM_PTR_TYPE_DUMP), desc->desc[i], 0, desc->cnt? desc->cnt(ref, i) : 1); } else { size += mem_size_obj(ref + desc->addr[i], desc->mem_type[i] | (desc->size? 0 : MEM_PTR_TYPE_DUMP), desc->desc[i], 0, desc->cnt? desc->cnt(ref, i) : 1); } } } return size; } static inline void mem_dup_obj(void **ret, void *obj, size_t aux_data, uint8_t mem_type, const obj_desc_t *desc, size_t cnt){ size_t m; void *ref, *chd; int i; if(desc == NULL || obj == NULL){ *ret = NULL; return; } if(mem_type & 0x01){ if(mem_type & 0x02){ *ret = calloc(cnt, sizeof(void*) * cnt); } else if(desc->size){ *ret = calloc(cnt, desc->size); memcpy(*ret, obj, desc->size * cnt); } else { // OBJ_DESC_CHAR_ARRAY } } if(desc->n_child == 0 && desc->post == NULL){ //if((mem_type & 0x02) == 0 && desc->n_child == 0){ } else { for(m=0;msize); memcpy(chd, ref, desc->size); ret[m] = chd; } else if(desc->size){ ref = obj + m * desc->size; chd = (*ret) + m * desc->size; } else { ref = obj; chd = ret; } for(i=0;in_child;i++){ if(desc->mem_type[i] & 0x01){ mem_dup_obj((void**)(chd + desc->addr[i]), *((void**)(ref + desc->addr[i])), aux_data, desc->mem_type[i] | (desc->size? 0 : MEM_PTR_TYPE_DUMP), desc->desc[i], desc->cnt? desc->cnt(ref, i) : 1); } else { mem_dup_obj((void**)(chd + desc->addr[i]), ref + desc->addr[i], aux_data, desc->mem_type[i] | (desc->size? 0 : MEM_PTR_TYPE_DUMP), desc->desc[i], desc->cnt? desc->cnt(ref, i) : 1); } } if(desc->post) desc->post(chd, aux_data); } } } static inline size_t mem_dump_obj(void *obj, uint8_t mem_type, const obj_desc_t *desc, size_t offset, size_t cnt, FILE *out, int mem_free){ void *ref; size_t size, m; int i; if(obj == NULL) return offset; size = offset; if(mem_type & 0x01){ if(mem_type & 0x02){ size += mem_dump(obj, cnt * sizeof(void*), out); } else { size += mem_dump(obj, cnt * desc->size, out); } } if((mem_type & 0x02) == 0 && desc->n_child == 0){ } else { for(m=0;msize, out); } else { ref = obj + m * desc->size; } for(i=0;in_child;i++){ if(desc->mem_type[i] & 0x01){ size = mem_dump_obj(*((void**)(ref + desc->addr[i])), desc->mem_type[i] | (desc->size? 0 : MEM_PTR_TYPE_DUMP), desc->desc[i], size, desc->cnt? desc->cnt(ref, i) : 1, out, mem_free); } else { size = mem_dump_obj(ref + desc->addr[i], desc->mem_type[i] | (desc->size? 0 : MEM_PTR_TYPE_DUMP), desc->desc[i], size, desc->cnt? desc->cnt(ref, i) : 1, out, mem_free); } } } } if(mem_free){ if((mem_type & 0x02) && desc->size) for(m=0;msize)) free(obj); } return size; } static inline size_t mem_load_obj(void *obj, size_t aux_data, uint8_t mem_type, const obj_desc_t *desc, size_t addr_beg, size_t cnt){ size_t addr, m; int i; void *ref, **ptr; if(obj == NULL) return 0; addr = addr_beg? : (size_t)obj; if(mem_type & 0x01){ if(mem_type & 0x02){ addr += mem_size_round(cnt * sizeof(void*)); } else { addr += mem_size_round(cnt * desc->size); } } if(desc->n_child == 0 && desc->post == NULL){ switch(mem_type){ case 2: case 3: for(m=0;msize); } default: return addr; } } for(m=0;msize); } else { ref = obj + m * desc->size; } for(i=0;in_child;i++){ ptr = ref + desc->addr[i]; if(desc->mem_type[i] & 0x01){ if(*ptr == NULL) continue; *ptr = (void*)addr; addr = mem_load_obj(*ptr, aux_data, desc->mem_type[i] | (desc->size? 0 : MEM_PTR_TYPE_DUMP), desc->desc[i], addr, desc->cnt? desc->cnt(ref, i) : 1); } else { addr = mem_load_obj((void*)ptr, aux_data, desc->mem_type[i] | (desc->size? 0 : MEM_PTR_TYPE_DUMP), desc->desc[i], addr, desc->cnt? desc->cnt(ref, i) : 1); } } if(desc->post) desc->post(ref, aux_data); } return addr; } static inline size_t mem_tree_obj(FILE *out, void *obj, size_t mem_type, const obj_desc_t *desc, size_t addr, size_t cnt, size_t max_cnt, int level, int max_level){ size_t m; int i, j; void *ref, **ptr; if(obj == NULL) return 0; if(addr == 0) addr = (size_t)obj; if(max_level <= 0 || level <= max_level){ for(j=0;jtag, obj, (u8i)mem_type, (u8i)cnt); } if(mem_type & 0x01){ if(mem_type & 0x02){ addr += mem_size_round(cnt * sizeof(void*)); } else { addr += mem_size_round(cnt * desc->size); } } if(desc->n_child == 0){ if(mem_type == 3){ for(m=0;msize); } } if(max_level <= 0 || level <= max_level) fprintf(out, "%llu\n", (u8i)(addr - (size_t)obj)); return addr; } if(max_level <= 0 || level <= max_level) fprintf(out, "%llu\n", (u8i)(addr - (size_t)obj)); for(m=0;m 1 && (max_level <= 0 || level <= max_level) && (max_cnt == 0 || m < max_cnt)){ for(j=0;jsize); } else { ref = obj + m * desc->size; } for(i=0;in_child;i++){ ptr = ref + desc->addr[i]; if(desc->mem_type[i] & 0x01){ if(*ptr == NULL) continue; if(max_cnt && m >= max_cnt){ addr = mem_tree_obj(out, (void*)addr, desc->mem_type[i] | (desc->size? 0 : MEM_PTR_TYPE_DUMP), desc->desc[i], addr, desc->cnt? desc->cnt(ref, i) : 1, max_cnt, 2, 1); } else { addr = mem_tree_obj(out, (void*)addr, desc->mem_type[i] | (desc->size? 0 : MEM_PTR_TYPE_DUMP), desc->desc[i], addr, desc->cnt? desc->cnt(ref, i) : 1, max_cnt, level + 1, max_level); } } else { if(max_cnt && m >= max_cnt){ addr = mem_tree_obj(out, (void*)ptr, desc->mem_type[i] | (desc->size? 0 : MEM_PTR_TYPE_DUMP), desc->desc[i], addr, desc->cnt? desc->cnt(ref, i) : 1, max_cnt, 2, 1); } else { addr = mem_tree_obj(out, (void*)ptr, desc->mem_type[i] | (desc->size? 0 : MEM_PTR_TYPE_DUMP), desc->desc[i], addr, desc->cnt? desc->cnt(ref, i) : 1, max_cnt, level + 1, max_level); } } } } return addr; } static inline const obj_desc_t* mem_locate_obj(void *obj, size_t *_mem_type, const obj_desc_t *desc, u4i *trace_childs, size_t *trace_cnts, u4i ntrace, size_t *addr, size_t *cnt, int selected){ const obj_desc_t *ret; size_t m, mem_type; u4i ns; int i, nc; void *ref, **ptr; if(obj == NULL) return desc; if(*addr == 0) *addr = (size_t)obj; if(selected && ntrace == 0) return desc; mem_type = *_mem_type; if(mem_type & 0x01){ if(mem_type & 0x02){ *addr += mem_size_round((*cnt) * sizeof(void*)); } else { *addr += mem_size_round((*cnt) * desc->size); } } if(selected){ if(trace_childs[0] >= (u4i)desc->n_child){ fprintf(stderr, " -- Illegal trace child (%d >= %d) in OBJ_DESC[%s] in %s -- %s:%d --\n", trace_childs[0], desc->n_child, desc->tag, __FUNCTION__, __FILE__, __LINE__); return desc; } if(trace_cnts[0] >= *cnt){ fprintf(stderr, " -- Illegal trace cont (%llu >= %llu) in OBJ_DESC[%s] in %s -- %s:%d --\n", (u8i)trace_cnts[0], (u8i)*cnt, desc->tag, __FUNCTION__, __FILE__, __LINE__); return desc; } } if(desc->n_child == 0){ switch(mem_type){ case 2: case 3: *addr += (*cnt) * mem_size_round(desc->size); default: return desc; } } ret = desc; ns = selected? trace_cnts[0] + 1 : *cnt; for(m=0;mmem_type[trace_childs[0]] | (desc->size? 0 : MEM_PTR_TYPE_DUMP); *cnt = 0; } continue; } ref = (void*)*addr; *addr += mem_size_round(desc->size); } else { ref = obj + m * desc->size; } nc = (selected && m + 1 == ns)? trace_childs[0] + 1 : (u4i)desc->n_child; for(i=0;iaddr[i]; if(desc->mem_type[i] & 0x01){ *_mem_type = desc->mem_type[i] | (desc->size? 0 : MEM_PTR_TYPE_DUMP); if(*ptr == NULL){ *cnt = 0; continue; } *cnt = desc->cnt? desc->cnt(ref, i) : 1; ret = mem_locate_obj((void*)*addr, _mem_type, desc->desc[i], trace_childs + 1, trace_cnts + 1, ntrace - 1, addr, cnt, (selected && m + 1 == ns && i == nc)); } else { *_mem_type = desc->mem_type[i] | (desc->size? 0 : MEM_PTR_TYPE_DUMP); *cnt = desc->cnt? desc->cnt(ref, i) : 1; ret = mem_locate_obj((void*)ptr, _mem_type, desc->desc[i], trace_childs + 1, trace_cnts + 1, ntrace - 1, addr, cnt, (selected && m + 1 == ns && i == nc)); } } } return ret; } static inline size_t mem_dump_obj_file(void *obj, size_t mem_type, const obj_desc_t *desc, size_t cnt, size_t aux_data, FILE *out){ size_t size; if(desc == NULL) return 0; if((mem_type & 0x01) == 0){ fprintf(stderr, " -- Illegal mem_type (%u) to call mem_dump, object should have standalone memory in %s -- %s:%d --\n", (int)mem_type, __FUNCTION__, __FILE__, __LINE__); exit(1); } size = mem_size_obj(obj, mem_type, desc, 0, cnt); if(out){ fwrite(&size, sizeof(size_t), 1, out); fwrite(&mem_type, sizeof(size_t), 1, out); fwrite(&cnt, sizeof(size_t), 1, out); fwrite(&aux_data, sizeof(size_t), 1, out); } size = 4 * sizeof(size_t); size = mem_dump_obj(obj, mem_type, desc, size, cnt, out, 0); if(out) fflush(out); return size; } static inline size_t mem_dump_free_obj_file(void *obj, size_t mem_type, const obj_desc_t *desc, size_t cnt, size_t aux_data, FILE *out){ size_t size; if(desc == NULL) return 0; if((mem_type & 0x01) == 0){ fprintf(stderr, " -- Illegal mem_type (%u) to call mem_dump, object should have standalone memory in %s -- %s:%d --\n", (int)mem_type, __FUNCTION__, __FILE__, __LINE__); exit(1); } size = mem_size_obj(obj, mem_type, desc, 0, cnt); if(out){ fwrite(&size, sizeof(size_t), 1, out); fwrite(&mem_type, sizeof(size_t), 1, out); fwrite(&cnt, sizeof(size_t), 1, out); fwrite(&aux_data, sizeof(size_t), 1, out); } size = 4 * sizeof(size_t); size = mem_dump_obj(obj, mem_type, desc, size, cnt, out, 1); if(out) fflush(out); return size; } static char *mem_share_locks = NULL; static int mem_share_lock_size = 0; static inline void cleanup_mem_share_file_locks(){ int off; off = 0; while(off < mem_share_lock_size){ shm_unlink(mem_share_locks + off); off += strlen(mem_share_locks + off) + 1; } if(mem_share_locks) free(mem_share_locks); mem_share_lock_size = 0; mem_share_locks = NULL; } #ifndef sighandler_t typedef void (*sighandler_t)(int sig); #endif static sighandler_t sig_term = SIG_IGN; static sighandler_t sig_int = SIG_IGN; static sighandler_t sig_hup = SIG_IGN; static sighandler_t sig_kill = SIG_IGN; static volatile sig_atomic_t cleanup_mem_share_in_progress = 0; static inline void sig_cleanup_mem_share_file_locks(int sig){ if(cleanup_mem_share_in_progress) raise(sig); cleanup_mem_share_in_progress = 1; cleanup_mem_share_file_locks(); signal(SIGTERM, sig_term); signal(SIGINT , sig_int); signal(SIGHUP, sig_hup); signal(SIGKILL, sig_kill); raise(sig); } static inline void register_mem_share_file_lock(char *file){ int len; if(mem_share_lock_size == 0){ if((sig_term = signal(SIGTERM, sig_cleanup_mem_share_file_locks)) == SIG_IGN) signal(SIGTERM, SIG_IGN); if((sig_int = signal(SIGINT , sig_cleanup_mem_share_file_locks)) == SIG_IGN) signal(SIGINT , SIG_IGN); if((sig_hup = signal(SIGHUP , sig_cleanup_mem_share_file_locks)) == SIG_IGN) signal(SIGHUP , SIG_IGN); if((sig_kill = signal(SIGKILL, sig_cleanup_mem_share_file_locks)) == SIG_IGN) signal(SIGKILL, SIG_IGN); atexit(cleanup_mem_share_file_locks); } len = strlen(file); mem_share_locks = realloc(mem_share_locks, mem_share_lock_size + len + 1); strcpy(mem_share_locks + mem_share_lock_size, file); mem_share_lock_size += len + 1; } static inline void print_tree_obj_file(FILE *out, const obj_desc_t *desc, char *path, size_t max_cnt, int max_level){ FILE *file; void *mem; size_t psize, *size, *mem_type, *cnt, *aux_data; if(desc == NULL) return; if((file = fopen(path, "r")) == NULL){ fprintf(stderr, " -- Cannot open %s in %s -- %s:%d --\n", path, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); return; } size = alloca(sizeof(size_t)); mem_type = alloca(sizeof(size_t)); cnt = alloca(sizeof(size_t)); aux_data = alloca(sizeof(size_t)); fread(size, sizeof(size_t), 1, file); fread(mem_type, sizeof(size_t), 1, file); fread(cnt, sizeof(size_t), 1, file); fread(aux_data, sizeof(size_t), 1, file); psize = getpagesize(); mem = mmap(0, (((*size) + 4 * sizeof(size_t)) + psize - 1) / psize * psize, PROT_READ, MAP_PRIVATE, fileno(file), 0); if(mem == NULL){ perror("Cannot mmap"); return; } fprintf(out, "OBJ_TREE[%s]{\n", path); mem_tree_obj(out, mem + 4 * sizeof(size_t), *mem_type, desc, 0, *cnt, max_cnt, 1, max_level); fprintf(out, "}\n"); munmap(mem, (((*size) + 4 * sizeof(size_t)) + psize - 1) / psize * psize); fclose(file); } // Directly read from file, don't share this object static inline void* mem_read_obj_file(const obj_desc_t *desc, char *path, size_t *size, size_t *mem_type, size_t *cnt, size_t *aux_data){ void *mem; size_t nin; FILE *file; if(desc == NULL) return NULL; if((file = fopen(path, "r")) == NULL){ fprintf(stderr, " -- Cannot open %s in %s -- %s:%d --\n", path, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); return NULL; } if(size == NULL) size = alloca(sizeof(size_t)); if(mem_type == NULL) mem_type = alloca(sizeof(size_t)); if(cnt == NULL) cnt = alloca(sizeof(size_t)); if(aux_data == NULL) aux_data = alloca(sizeof(size_t)); fread(size, sizeof(size_t), 1, file); fread(mem_type, sizeof(size_t), 1, file); fread(cnt, sizeof(size_t), 1, file); fread(aux_data, sizeof(size_t), 1, file); mem = malloc(*size); if(mem == NULL){ fprintf(stderr, " -- Cannot alloc %llu bytes memory for %s in %s -- %s:%d --\n", (unsigned long long)*size, path, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); return NULL; } if((nin = fread_stepwise(mem, 1, *size, file)) != *size){ fprintf(stderr, " -- Read %llu bytes, not %llu bytes in %s -- %s:%d --\n", (unsigned long long)nin, (unsigned long long)*size, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); return NULL; } fclose(file); mem_load_obj(mem, *aux_data, *mem_type, desc, 0, *cnt); //if(desc->post) desc->post(mem, *aux_data); return mem; } // only read a child object specified by indexs and nidx static inline void* mem_read_sub_obj_file(const obj_desc_t *desc, u4i *trace_childs, size_t *trace_cnts, u4i ntrace, char *path, size_t *size){ const obj_desc_t *sub; void *mem; size_t *mem_type, *cnt, *aux_data, psize, addr, sz, nin; FILE *file; if(desc == NULL) return NULL; if((file = fopen(path, "r")) == NULL){ fprintf(stderr, " -- Cannot open %s in %s -- %s:%d --\n", path, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); exit(1); } if(size == NULL) size = alloca(sizeof(size_t)); mem_type = alloca(sizeof(size_t)); cnt = alloca(sizeof(size_t)); aux_data = alloca(sizeof(size_t)); fread(size, sizeof(size_t), 1, file); fread(mem_type, sizeof(size_t), 1, file); fread(cnt, sizeof(size_t), 1, file); fread(aux_data, sizeof(size_t), 1, file); psize = getpagesize(); mem = mmap(0, (((*size) + 4 * sizeof(size_t)) + psize - 1) / psize * psize, PROT_READ, MAP_PRIVATE, fileno(file), 0); if(mem == NULL){ perror("Cannot mmap"); return NULL; } addr = 0; sub = mem_locate_obj(mem + 4 * sizeof(size_t), mem_type, desc, trace_childs, trace_cnts, ntrace, &addr, cnt, 1); sz = mem_size_obj((void*)addr, *mem_type, sub, 0, *cnt); munmap(mem, (((*size) + 4 * sizeof(size_t)) + psize - 1) / psize * psize); mem = malloc(sz); fseek(file, addr - ((size_t)mem) + 4 * sizeof(size_t), SEEK_SET); if((nin = fread_stepwise(mem, 1, sz, file)) != sz){ fprintf(stderr, " -- Read %llu bytes, not %llu bytes in %s -- %s:%d --\n", (unsigned long long)nin, (unsigned long long)sz, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); return NULL; } fclose(file); mem_load_obj(mem, *aux_data, *mem_type, sub, 0, *cnt); //if(sub->post) sub->post(mem, *aux_data); *size = sz; return mem; } // WARNNING ** the content of shared memory object can be modified by any mmaped process, thus is not multiple-process-safety static inline void* mem_load_obj_file(const obj_desc_t *desc, char *_path, size_t *size, size_t *mem_type, size_t *cnt, size_t *aux_data){ void *mem; size_t sz, nin, psize, *msg; char *lock, *shadow, *path, *shmp; char hostname[65]; FILE *file; int fd, ret; if(desc == NULL) return NULL; path = absolute_filename(_path); shmp = strdup(path); replace_char(shmp, '/', '_', 0); if((file = fopen(path, "r+")) == NULL){ fprintf(stderr, " -- Cannot open %s in %s -- %s:%d --\n", path, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); exit(1); } if(size == NULL) size = alloca(sizeof(size_t)); if(mem_type == NULL) mem_type = alloca(sizeof(size_t)); if(cnt == NULL) cnt = alloca(sizeof(size_t)); if(aux_data == NULL) aux_data = alloca(sizeof(size_t)); fread(size, sizeof(size_t), 1, file); fread(mem_type, sizeof(size_t), 1, file); fread(cnt, sizeof(size_t), 1, file); fread(aux_data, sizeof(size_t), 1, file); psize = getpagesize(); sz = (*size) + 4 * sizeof(size_t); //fd = fileno(file); //mem = mmap(0, (size + 4 * sizeof(size_t) + psize - 1) / psize * psize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); gethostname(hostname, 64); shadow = alloca(strlen(shmp) + strlen(hostname) + 40); sprintf(shadow, "%s.mem_share.%s.%ld.shm", shmp, hostname, gethostid()); fd = shm_open(shadow, O_CREAT | O_RDWR, 0777); if(fd == -1){ fprintf(stderr, " -- shm_open failed: %s in %s -- %s:%d --\n", shadow, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); exit(1); } ret = ftruncate(fd, (sz + psize - 1) / psize * psize); if(ret == -1){ fprintf(stderr, " -- ftruncate failed: %s in %s -- %s:%d --\n", shadow, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); exit(1); } //register_mem_share_file_lock(shadow); mem = mmap(0, (sz + psize - 1) / psize * psize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if(mem == MAP_FAILED){ perror("Cannot mmap"); return NULL; } fseek(file, 0, SEEK_SET); if((nin = fread_stepwise(mem, 1, sz, file)) != sz){ fprintf(stderr, " -- Read %llu bytes, not %llu bytes in %s -- %s:%d --\n", (unsigned long long)nin, (unsigned long long)sz, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); exit(1); } fclose(file); fprintf(stderr, " -- Read %llu bytes from %s --\n", (unsigned long long)nin, path); fflush(stderr); mem_load_obj(mem + 4 * sizeof(size_t), *aux_data, *mem_type, desc, 0, *cnt); //if(desc->post) desc->post(mem + 4 * sizeof(size_t), *aux_data); lock = alloca(strlen(shmp) + strlen(hostname) + 20); sprintf(lock, "%s.mem_share.%s.%ld", shmp, hostname, gethostid()); if((fd = shm_open(lock, O_CREAT | O_RDWR, 0777)) == -1){ fprintf(stderr, " -- shm_open failed: %s in %s -- %s:%d --\n", lock, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); exit(1); } if((ret = ftruncate(fd, psize)) == -1){ fprintf(stderr, " -- ftruncate failed: %s in %s -- %s:%d --\n", lock, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); exit(1); } msg = mmap(0, psize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if(msg == MAP_FAILED){ perror("Cannot mmap"); exit(1); } msg[0] = (size_t)mem; msg[1] = *size; fprintf(stderr, "-- mem_share '%s' at %p:%llu --\n", path, mem, (u8i)*size); fflush(stderr); free(path); free(shmp); //register_mem_share_file_lock(lock); return mem + 4 * sizeof(size_t); } static inline int mem_stop_obj_file(char *_path){ char *lock, *shadow, *path, *shmp; char hostname[65]; path = absolute_filename(_path); shmp = strdup(path); replace_char(shmp, '/', '_', 0); gethostname(hostname, 64); shadow = alloca(strlen(shmp) + strlen(hostname) + 40); sprintf(shadow, "%s.mem_share.%s.%ld.shm", shmp, hostname, gethostid()); if(shm_unlink(shadow) == -1){ fprintf(stderr, " -- Failed to remove mmap object %s --\n", shadow); fflush(stderr); return 0; } lock = alloca(strlen(shmp) + strlen(hostname) + 20); sprintf(lock, "%s.mem_share.%s.%ld", shmp, hostname, gethostid()); if(shm_unlink(lock) == -1){ fprintf(stderr, " -- Failed to remove mmap object %s --\n", lock); fflush(stderr); return 0; } free(path); free(shmp); return 1; } // wr: whether to obtain write permission the mmap object static inline void* mem_find_obj_file(const obj_desc_t *desc, char *_path, size_t *size, size_t *mem_type, size_t *cnt, size_t *aux_data, int wr){ char *lock, *shadow, *path, *shmp; char hostname[65]; void *addr, *mem; size_t psize, *msg; int fd, prot; UNUSED(desc); gethostname(hostname, 64); psize = getpagesize(); path = absolute_filename(_path); shmp = strdup(path); replace_char(shmp, '/', '_', 0); lock = alloca(strlen(shmp) + strlen(hostname) + 32); sprintf(lock, "%s.mem_share.%s.%ld", shmp, hostname, gethostid()); if(size == NULL) size = alloca(sizeof(size_t)); if(mem_type == NULL) mem_type = alloca(sizeof(size_t)); if(cnt == NULL) cnt = alloca(sizeof(size_t)); if(aux_data == NULL) aux_data = alloca(sizeof(size_t)); if((fd = shm_open(lock, O_RDWR, 0777)) == -1){ return NULL; } msg = mmap(0, psize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if(msg == MAP_FAILED){ perror("Cannot mmap"); return NULL; } addr = (void*)msg[0]; *size = msg[1]; munmap(msg, psize); shadow = alloca(strlen(shmp) + strlen(hostname) + 40); sprintf(shadow, "%s.mem_share.%s.%ld.shm", shmp, hostname, gethostid()); fd = shm_open(shadow, O_RDWR, 0777); prot = PROT_READ; if(wr) prot |= PROT_WRITE; mem = mmap(addr, ((*size) + 4 * sizeof(size_t) + psize - 1) / psize * psize, prot, MAP_SHARED | MAP_FIXED, fd, 0); if(mem == MAP_FAILED){ perror("Cannot map shared object"); return NULL; } *mem_type = ((size_t*)addr)[1]; *cnt = ((size_t*)addr)[2]; *aux_data = ((size_t*)addr)[3]; //fclose(file); //mem_load_obj(mem + 4 * sizeof(size_t), *mem_type, desc, 0, *cnt); fprintf(stderr, "-- mem_map '%s' at %p:%llu --\n", path, addr, (u8i)*size); fflush(stderr); free(path); free(shmp); return mem + 4 * sizeof(size_t); } #endif /* * An example to use mem_dump */ /* #include "mem_share.h" typedef struct { char *str; int val; } Type1; size_t type1_count(void *obj, int idx){ if(idx == 0){ return strlen(((Type1*)obj)->str) + 1; } else return 0; } //const obj_desc_t type1_obj_desc = {"TYPE1", sizeof(Type1), 1, {1}, {offsetof(Type1, str)}, {&OBJ_DESC_DATA}, type1_count, NULL}; const obj_desc_t type1_obj_desc = {"TYPE1", sizeof(Type1), 1, {1}, {offsetof(Type1, str)}, {&OBJ_DESC_CHAR_ARRAY}, NULL, NULL}; typedef struct { int a, b, c; Type1 d1, d2[10], *d3, *d4[10], **d5; char **strs; int d3len, d5len; } Type2; size_t type2_count(void *obj, int idx){ switch(idx){ case 0: return 1; case 1: return 10; case 2: return ((Type2*)obj)->d3len; case 3: return 10; case 4: return ((Type2*)obj)->d5len; default: return 10; } } const obj_desc_t type2_obj_desc = {"TYPE2", sizeof(Type2), 6, {0, 0, 1, 2, 3, 3}, {offsetof(Type2, d1), offsetof(Type2, d2), offsetof(Type2, d3), offsetof(Type2, d4), offsetof(Type2, d5), offsetof(Type2, strs)}, {&type1_obj_desc, &type1_obj_desc, &type1_obj_desc, &type1_obj_desc, &type1_obj_desc, &OBJ_DESC_CHAR_ARRAY}, type2_count, NULL}; int main(){ Type2 *t2, *t3; t2 = calloc(1, sizeof(Type2)); int idx = 0; t2->d1.val = idx ++; t2->d1.str = strdup("d1"); int i; for(i=0;i<10;i++){ t2->d2[i].val = idx ++; t2->d2[i].str = strdup("d2"); } t2->d3len = 10; t2->d3 = malloc(sizeof(Type1) * t2->d3len); for(i=0;id3len;i++){ t2->d3[i].val = idx ++; t2->d3[i].str = strdup("d3"); } for(i=0;i<10;i++){ t2->d4[i] = malloc(sizeof(Type1)); t2->d4[i]->val = idx ++; t2->d4[i]->str = strdup("d4"); } t2->d5len = 10; t2->d5 = malloc(sizeof(Type1*) * t2->d5len); for(i=0;id5len;i++){ t2->d5[i] = malloc(sizeof(Type1)); t2->d5[i]->val = idx ++; t2->d5[i]->str = strdup("d5"); } t2->strs = malloc(sizeof(char*) * 10); for(i=0;i<10;i++){ t2->strs[i] = malloc(32); sprintf(t2->strs[i], "strs[%d,%d]", i, idx ++); } size_t aux_data, size, cnt, mem_type; FILE *file; size = mem_size_obj(t2, 1, &type2_obj_desc, 0, 1); fprintf(stdout, " -- size = %d in %s -- %s:%d --\n", (int)size, __FUNCTION__, __FILE__, __LINE__); aux_data = 1000999900; file = fopen("test.mem_share", "w"); size = mem_dump_free_obj_file(t2, 1, &type2_obj_desc, 1, aux_data, file); fclose(file); fprintf(stdout, " -- size = %d in %s -- %s:%d --\n", (int)(size - 4 * sizeof(size_t)), __FUNCTION__, __FILE__, __LINE__); t3 = mem_read_obj_file(&type2_obj_desc, "test.mem_share", &mem_type, &cnt, &aux_data); fprintf(stdout, " -- aux_data = %d in %s -- %s:%d --\n", (int)aux_data, __FUNCTION__, __FILE__, __LINE__); printf("%d %s\n", t3->d1.val, t3->d1.str); for(i=0;i<10;i++) printf("%d %s\n", t3->d2[i].val, t3->d2[i].str); for(i=0;id3len;i++) printf("%d %s\n", t3->d3[i].val, t3->d3[i].str); for(i=0;i<10;i++) printf("%d %s\n", t3->d4[i]->val, t3->d4[i]->str); for(i=0;id5len;i++) printf("%d %s\n", t3->d5[i]->val, t3->d5[i]->str); for(i=0;i<10;i++) printf("%s\n", t3->strs[i]); free(t3); return 0; } */ wtdbg2-2.5/pgzf.c000066400000000000000000000161171353664372200137040ustar00rootroot00000000000000/* * * Copyright (c) 2018, Jue Ruan * * * 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 3 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, see . */ #include "pgzf.h" int usage(int ret){ fprintf(stdout, "PGZF: Parallel gzip file IO\n" "Author: Jue Ruan \n" "Version: 1.1\n" "Usage: pgzf [options] file1 [file2 ...]\n" "Options:\n" " -d Decompress mode\n" " -t Number of threads, [8]\n" " -f Force to overwrite\n" " -o Output file name, support directory\n" " -x Delete input files after done\n" " -b Block size in MB, 1 ~ 256 [16]\n" " -l Compress level, 1-9, see gzip, [6]\n" " -h Show this document\n" " -V Print version information and exit\n" "\n" "File format:\n" " PGZF fellows standard GZIP format (rfc1952), and is blocked compressed.\n" " It defines two TAGs in each GZIP header, ZS: block size, ZX: random access index.\n" " Program pgzf can decompress .pgzf and .gz files. When decompressing .gz files,\n" " pgzf is in fact a buffered gzip reader. Also, .pgzf files can be decompressed\n" " by program gzip.\n" "\n" "In plan to support random access\n" ); return ret; } int main(int argc, char **argv){ PGZF *pz; char *outf, *ftag; FILE *in, *out; void *buff; u4i bufsize, nbyte; int c, rw, ncpu, level, overwrite, del, is_dir; rw = PGZF_MODE_W; ncpu = 8; bufsize = PGZF_DEFAULT_BUFF_SIZE; level = 6; overwrite = 0; del = 0; outf = NULL; while((c = getopt(argc, argv, "hdxft:b:l:o:V")) != -1){ switch(c){ case 'h': return usage(0); case 'd': rw = PGZF_MODE_R; break; case 't': ncpu = atoi(optarg); break; case 'b': bufsize = (atol(optarg) << 20); break; case 'l': level = atoi(optarg); break; case 'f': overwrite = 1; break; case 'o': outf = optarg; break; case 'x': del = 1; break; case 'V': fprintf(stdout, "pgzf 1.1\n"); return 0; default: return usage(1); } } if(optind == argc){ return usage(1); } if(0 && del){ if(outf == NULL && overwrite == 0){ if(optind < argc){ fprintf(stderr, " ** WARNNING: won't delete input files. To force delete input files, please specify -o or/and -f\n"); } del = 0; } } is_dir = 0; out = NULL; if(outf){ if(file_exists(outf)){ if(overwrite == 0){ fprintf(stderr, " ** ERROR: '%s' exists\n", outf); return 1; } else { for(c=optind;cerror){ fprintf(stderr, " ** ERROR: error code (%d)'\n", pz->error); return 1; } close_pgzf(pz); if(in != stdin){ fclose(in); if(del){ unlink(argv[optind]); } } optind ++; if(outf == NULL || is_dir){ fclose(out); } } while(optind < argc); } else { if(outf && !is_dir){ pz = open_pgzf_writer(out, bufsize, ncpu, level); } else { pz = NULL; for(c=optind;c= 4 && strcasecmp(argv[c] + strlen(argv[c]) - 3, ".gz") == 0){ fprintf(stderr, " ** ERROR: file seems already compressed '%s'\n", argv[c]); return 1; } else if(strcmp(argv[c], "-") == 0){ fprintf(stderr, " ** ERROR: Please specify output file when read from STDIN '%s'\n", argv[c]); return 1; } else if(is_dir){ char *rtag; rtag = relative_filename(argv[c]); ftag = malloc(strlen(outf) + 1 + strlen(rtag) + 3 + 1); sprintf(ftag, "%s/%s.gz", outf, rtag); free(rtag); if(overwrite == 0 && file_exists(ftag)){ fprintf(stderr, " ** ERROR: '%s' exists\n", ftag); return 1; } free(ftag); } else { ftag = malloc(strlen(argv[c]) + 4); sprintf(ftag, "%s.gz", argv[c]); if(overwrite == 0 && file_exists(ftag)){ fprintf(stderr, " ** ERROR: '%s' exists\n", ftag); return 1; } free(ftag); } } } do { if(outf == NULL){ ftag = malloc(strlen(argv[optind]) + 4); sprintf(ftag, "%s.gz", argv[optind]); out = open_file_for_write(ftag, NULL, overwrite); pz = open_pgzf_writer(out, bufsize, ncpu, level); free(ftag); } else if(is_dir){ char *rtag; rtag = relative_filename(argv[optind]); ftag = malloc(strlen(outf) + 1 + strlen(rtag) + 3 + 1); sprintf(ftag, "%s/%s.gz", outf, rtag); free(rtag); out = open_file_for_write(ftag, NULL, overwrite); pz = open_pgzf_writer(out, bufsize, ncpu, level); free(ftag); } in = open_file_for_read(argv[optind], NULL); while((nbyte = fread(buff, 1, bufsize, in))){ write_pgzf(pz, buff, nbyte); } if(in != stdin){ fclose(in); if(del){ unlink(argv[optind]); } } if(outf == NULL || is_dir){ close_pgzf(pz); fclose(out); } optind ++; } while(optind < argc); if(outf && !is_dir){ close_pgzf(pz); } } if(outf && !is_dir) fclose(out); free(buff); return 0; } wtdbg2-2.5/pgzf.h000066400000000000000000000537071353664372200137170ustar00rootroot00000000000000/* * * Copyright (c) 2018, Jue Ruan * * * 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 3 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, see . */ #ifndef __PGZF_RJ_H #define __PGZF_RJ_H #include #include "mem_share.h" #include "list.h" #include "thread.h" #define PGZF_DEFAULT_BUFF_SIZE (1U << 24) // 16MB #define PGZF_MAX_BUFF_SIZE (1U << 28) #define PGZF_HEAD_SIZE 30 #define PGZF_HEAD_ZS_OFFSET 16 #define PGZF_HEAD_ZX_OFFSET 24 #define PGZF_TAIL_SIZE 8 #define PGZF_INDEX_BIN 64 #define PGZF_MODE_W 1 // pgzf writer #define PGZF_MODE_R 2 // pgzf reader #define PGZF_MODE_R_GZ 3 // gz reader #define PGZF_MODE_R_UNKNOWN 4 // unknown file type #define PGZF_FILETYPE_UNKNOWN 0 #define PGZF_FILETYPE_GZ 1 #define PGZF_FILETYPE_PGZF 2 struct PGZF; #define PGZF_TASK_NULL 0 #define PGZF_TASK_DEFLATE 1 #define PGZF_TASK_INFLATE 2 thread_beg_def(pgz); struct PGZF *pz; u4i zsval, soff; u8i zxval, doff; u1v *dst, *src; u4i token; int level; int task; thread_end_def(pgz); typedef struct PGZF { u4i ncpu, ridx, widx; int rw_mode, seekable; u4i bufsize; // MUST be multiple of 1MB u8i xsize; // total uncompressed size u8v *boffs; u8v *xoffs; u8i tot_in, tot_out; u1v **dsts, **srcs, *tmp; z_stream *z; u8i offset; FILE *file; thread_def_shared_vars(pgz); int step; // used in decompress gzip file int eof, error; } PGZF; static inline void _num2bytes_pgzf(u1i *bs, u1i bl, u8i val){ u1i i; for(i=0;i>= 8; } } static inline u8i _bytes2num_pgzf(u1i *bs, u1i bl){ u8i val; u1i i; val = 0; for(i=0;i> 0; // compressed block size bs[17] = z_size >> 8; // bs[18] = z_size >> 16; // bs[19] = z_size >> 24; // = z_size bs[20] = 'Z'; //TAG ZX bs[21] = 'X'; // every 64 block size bs[22] = 6; // TAG LEN bs[23] = 0; // 6 bs[24] = 0; // reserve to store the random access index bs[25] = 0; // bs[26] = 0; // bs[27] = 0; // bs[28] = 0; // bs[29] = 0; // } static inline void _gen_pgzf_tailer(u1i bs[8], u4i crc, u4i u_size){ _num2bytes_pgzf(bs + 0, 4, crc); _num2bytes_pgzf(bs + 4, 4, u_size); } static inline u4i _zlib_raw_deflate_all(u1i *dst, u4i dlen, u1i *src, u4i slen, int level){ z_stream Z, *z; u4i ret; z = &Z; ZEROS(z); deflateInit2(z, level, Z_DEFLATED, -15, 9, Z_DEFAULT_STRATEGY); z->avail_in = slen; z->next_in = src; z->avail_out = dlen; z->next_out = dst; deflate(z, Z_FINISH); ret = dlen - z->avail_out; deflateEnd(z); return ret; } static inline u4i _pgzf_deflate(u1v *dst, u1v *src, int level){ u4i z_size; uLong crc; clear_u1v(dst); if(src->size == 0 || src->size >= MAX_U4) return 0; z_size = compressBound(src->size); encap_u1v(dst, z_size + PGZF_HEAD_SIZE + PGZF_TAIL_SIZE); z_size = _zlib_raw_deflate_all(dst->buffer + PGZF_HEAD_SIZE, z_size, src->buffer, src->size, level); _gen_pgzf_header(dst->buffer, z_size + PGZF_HEAD_SIZE + PGZF_TAIL_SIZE); crc = crc32(0L, Z_NULL, 0); crc = crc32(crc, src->buffer, src->size); _gen_pgzf_tailer(dst->buffer + PGZF_HEAD_SIZE + z_size, crc, src->size); dst->size = PGZF_HEAD_SIZE + z_size + PGZF_TAIL_SIZE; return dst->size; } static inline int _read_pgzf_header(FILE *in, u1v *src, u4i *hoff, u4i *zsval, u8i *zxval){ u4i off, val, sl, end; int ch, is_pgzf, xflag; char si1, si2; is_pgzf = 0; off = *hoff; *zsval = 0; *zxval = 0; if(src->size < off + 10){ encap_u1v(src, 10); src->size += fread(src->buffer + src->size, 1, off + 10 - src->size, in); } // At least give 10 bytes if(src->size < off + 10) return PGZF_FILETYPE_UNKNOWN; if(src->buffer[off + 0] != 0x1f) return PGZF_FILETYPE_UNKNOWN; if(src->buffer[off + 1] != 0x8b) return PGZF_FILETYPE_UNKNOWN; if((src->buffer[off + 2] != 0x08) || (src->buffer[off + 2] & 0xE0)) return PGZF_FILETYPE_UNKNOWN; xflag = src->buffer[off + 3]; off += 10; if(xflag & 0x04){ if(src->size < off + 2){ encap_u1v(src, 2); sl = fread(src->buffer + src->size, 1, off + 2 - src->size, in); src->size += sl; } if(src->size < off + 2) return PGZF_FILETYPE_UNKNOWN; val = _bytes2num_pgzf(src->buffer + off, 2); off += 2; end = off + val; if(val > 0 && val < 4) return PGZF_FILETYPE_UNKNOWN; if(src->size < off + val){ encap_u1v(src, val); sl = fread(src->buffer + src->size, 1, off + val - src->size, in); src->size += sl; if(src->size < off + val) return PGZF_FILETYPE_UNKNOWN; } //parse TAGs while(off < end){ si1 = src->buffer[off + 0]; si2 = src->buffer[off + 1]; sl = _bytes2num_pgzf(src->buffer + off + 2, 2); off += 4; if(si1 == 'Z' && si2 == 'S' && sl == 4){ is_pgzf = 1; *zsval = _bytes2num_pgzf(src->buffer + off, 4); } else if(is_pgzf && si1 == 'Z' && si2 == 'X' && sl == 6){ *zxval = _bytes2num_pgzf(src->buffer + off, 6); } off += sl; } } if(xflag & 0x08){ do { if(off < src->size){ ch = src->buffer[off]; } else { ch = getc(in); if(ch == -1){ return PGZF_FILETYPE_UNKNOWN; } push_u1v(src, ch); } off ++; } while(ch); } if(xflag & 0x10){ do { if(off < src->size){ ch = src->buffer[off]; } else { ch = getc(in); if(ch == -1){ return PGZF_FILETYPE_UNKNOWN; } push_u1v(src, ch); } off ++; } while(ch); } if(xflag & 0x02){ if(src->size < off + 2){ encap_u1v(src, 2); sl = fread(src->buffer + src->size, 1, off + 2 - src->size, in); src->size += sl; } off += 2; if(src->size < off) return PGZF_FILETYPE_UNKNOWN; } *hoff = off; return is_pgzf? PGZF_FILETYPE_PGZF : PGZF_FILETYPE_GZ; } int pgzf_inflate_raw_core(z_stream *z, u1i *dst, u4i *dlen, u1i *src, u4i *slen, int flush){ u4i dl, sl; int ret; ret = Z_OK; dl = *dlen; sl = *slen; z->avail_in = sl; z->next_in = src; z->avail_out = dl; z->next_out = dst; ret = inflate(z, flush); *dlen = dl - z->avail_out; *slen = sl - z->avail_in; return ret; } // src start just after gz_header, and include fz_tailer int pgzf_inflate_core(u1i *dst, u4i *dlen, u1i *src, u4i slen, int check){ z_stream Z, *z; u4i soff, dsz; uLong crc, rcr; int ret; z = &Z; ZEROS(z); inflateInit2(z, -15); z->avail_in = slen - PGZF_TAIL_SIZE; z->next_in = src; z->avail_out = *dlen; z->next_out = dst; ret = inflate(z, Z_FINISH); *dlen -= z->avail_out; soff = slen - PGZF_TAIL_SIZE - z->avail_in; inflateEnd(z); if(check){ if(soff + 8 > slen){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); return 0; } rcr = _bytes2num_pgzf(src + soff, 4); dsz = _bytes2num_pgzf(src + soff + 4, 4); if(dsz != *dlen){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); return 0; } crc = crc32(0L, Z_NULL, 0); crc = crc32(crc, dst, *dlen); if(crc != rcr){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); return 0; } } return 1; } thread_beg_func(pgz); PGZF *pz; u1v *dst, *src; u4i bufsize, hsize, rsize, dsz, ssz, next; int ret; pz = pgz->pz; dst = pgz->dst; src = pgz->src; thread_beg_loop(pgz); if(pgz->task == PGZF_TASK_DEFLATE){ if(src->size == 0) continue; clear_u1v(dst); _pgzf_deflate(dst, src, pgz->level); while(pz->ridx != pgz->token){ nano_sleep(1); } { pz->tot_out += pgz->dst->size; push_u8v(pz->boffs, pz->tot_out); fwrite(pgz->dst->buffer, 1, pgz->dst->size, pz->file); clear_u1v(pgz->dst); clear_u1v(pgz->src); } pz->ridx ++; } else if(pgz->task == PGZF_TASK_INFLATE){ pgz->doff = 0; clear_u1v(pgz->dst); while((pz->ridx % pz->ncpu) != UInt(pgz->t_idx)){ nano_sleep(10); if(pz->error) break; //if(pz->eof){ //if(pz->rw_mode != PGZF_MODE_R_GZ){ //break; //} //} if(pgz->running == 0){ break; } } if(pz->error) break; if(pz->rw_mode == PGZF_MODE_R){ if(pgz->src->size){ // loaded header, had set zsval and zxval } else { pgz->zsval = pgz->zxval = 0; pgz->soff = pgz->src->size = 0; ret = _read_pgzf_header(pz->file, pgz->src, &pgz->soff, &pgz->zsval, &pgz->zxval); if(pgz->src->size == 0){ pz->eof = 1; pz->ridx ++; break; } if(ret != PGZF_FILETYPE_PGZF){ fprintf(stderr, " -- Error: not a PGZF format at %u block, in %s -- %s:%d --\n", pz->ridx, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); pz->error = 1; pz->ridx ++; break; } } hsize = pgz->soff; encap_u1v(pgz->src, pgz->zsval - pgz->src->size); rsize = fread(pgz->src->buffer + hsize, 1, pgz->zsval - pgz->src->size, pz->file); if(rsize < pgz->zsval - pgz->src->size){ fprintf(stderr, " -- Error: read %u < %u at %u block, in %s -- %s:%d --\n", UInt(pgz->src->size + rsize), pgz->zsval, pz->ridx, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); pz->error = 1; pz->ridx ++; break; } pgz->src->size += rsize; pz->tot_in += pgz->zsval; pz->ridx ++; dsz = _bytes2num_pgzf(pgz->src->buffer + pgz->zsval - 4, 4); encap_u1v(pgz->dst, dsz); pgz->soff = 0; if(pgzf_inflate_core(pgz->dst->buffer, &dsz, pgz->src->buffer + hsize, pgz->zsval - hsize, 1) == 0){ clear_u1v(pgz->src); pz->error = 1; break; } pgz->dst->size = dsz; clear_u1v(pgz->src); } else if(pz->rw_mode == PGZF_MODE_R_GZ){ u4i bsz; bsz = 1024 * 1024; bufsize = pz->bufsize? pz->bufsize : PGZF_DEFAULT_BUFF_SIZE; encap_u1v(pgz->dst, bufsize); while(!pz->error){ if(pgz->src->size == pgz->soff){ pgz->soff = pgz->src->size = 0; } if(pgz->src->size < bsz){ encap_u1v(pgz->src, bsz - pgz->src->size); rsize = fread(pgz->src->buffer + pgz->src->size, 1, bsz - pgz->src->size, pz->file); if(rsize < bsz - pgz->src->size){ pz->eof = 1; } pz->tot_in += rsize; pgz->src->size += rsize; } if(pgz->src->size == pgz->soff){ break; } if(pz->step == 0){ u4i tsz; tsz = pgz->src->size; ret = _read_pgzf_header(pz->file, pgz->src, &pgz->soff, &pgz->zsval, &pgz->zxval); if(ret != PGZF_FILETYPE_GZ && ret != PGZF_FILETYPE_PGZF){ if(pgz->src->size == pgz->soff){ pz->eof = 1; } else { fprintf(stderr, " -- failed in read gzip header, ret = %d in %s -- %s:%d --\n", ret, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); pz->error = 1; } break; } else { pz->tot_in += pgz->src->size - tsz; } pz->step = 1; continue; } else if(pz->step == 2){ if(pgz->src->size >= pgz->soff + PGZF_TAIL_SIZE){ pgz->soff += PGZF_TAIL_SIZE; pz->step = 0; inflateReset(pz->z); continue; } else if(pz->eof){ pz->error = 2; break; } else { memmove(pgz->src->buffer, pgz->src->buffer + pgz->soff, pgz->src->size - pgz->soff); pgz->src->size -= pgz->soff; pgz->soff = 0; } } while(pgz->dst->size < bufsize && pgz->soff < pgz->src->size){ dsz = bufsize - pgz->dst->size; ssz = pgz->src->size - pgz->soff; ret = pgzf_inflate_raw_core(pz->z, pgz->dst->buffer + pgz->dst->size, &dsz, pgz->src->buffer + pgz->soff, &ssz, Z_NO_FLUSH); pgz->dst->size += dsz; pgz->soff += ssz; if(ret == Z_STREAM_END){ pz->step = 2; break; } else if(ret != Z_OK){ fprintf(stderr, " -- ZERROR: %d in %s -- %s:%d --\n", ret, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); pz->error = 1; break; } } if(pgz->dst->size == bufsize){ if(pgz->soff < pgz->src->size){ if(pz->ncpu > 1){ next = (pz->ridx + 1) % pz->ncpu; if(pz->srcs[next]->size != 0){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); abort(); } append_array_u1v(pz->srcs[next], pgz->src->buffer + pgz->soff, pgz->src->size - pgz->soff); } } pgz->soff = pgz->src->size = 0; break; } } pz->ridx ++; } else if(pz->rw_mode == PGZF_MODE_R_UNKNOWN){ bufsize = pz->bufsize? pz->bufsize : PGZF_DEFAULT_BUFF_SIZE; encap_u1v(pgz->dst, bufsize); if(pgz->src->size > bufsize){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); pz->error = 1; pz->ridx ++; break; } else if(pgz->src->size){ append_u1v(pgz->dst, pgz->src); clear_u1v(pgz->src); } rsize = fread(pgz->dst->buffer + pgz->dst->size, 1, bufsize - pgz->dst->size, pz->file); if(rsize < bufsize - pgz->dst->size){ pz->eof = 1; } pgz->dst->size += rsize; pz->tot_in += pgz->dst->size; pz->ridx ++; } } thread_end_loop(pgz); thread_end_func(pgz); static inline PGZF* open_pgzf_writer(FILE *out, u4i buffer_size, int ncpu, int level){ PGZF *pz; u4i i; b8i offset; thread_prepare(pgz); pz = malloc(sizeof(PGZF)); if(ncpu < 1){ get_linux_sys_info(NULL, NULL, &ncpu); if(ncpu < 1) ncpu = 8; } pz->ncpu = ncpu; pz->ridx = 0; pz->widx = 0; offset = ftell(out); if(offset == -1){ pz->offset = 0; pz->seekable = 0; } else { pz->offset = offset; pz->seekable = 1; } pz->file = out; pz->error = 0; pz->eof = 0; pz->step = 0; pz->rw_mode = 1; // write if(buffer_size == 0) buffer_size = PGZF_DEFAULT_BUFF_SIZE; pz->bufsize = (buffer_size + 0xFFFFFU) & 0xFFF00000U; pz->xsize = 0; pz->boffs = init_u8v(32); pz->xoffs = init_u8v(32); pz->z = NULL; pz->dsts = calloc(pz->ncpu, sizeof(u1v*)); for(i=0;incpu;i++){ pz->dsts[i] = init_u1v(pz->bufsize); } pz->srcs = calloc(pz->ncpu, sizeof(u1v*)); for(i=0;incpu;i++){ pz->srcs[i] = init_u1v(pz->bufsize); } pz->tmp = init_u1v(32); pz->tot_in = 0; pz->tot_out = 0; if(level == 0) level = Z_DEFAULT_COMPRESSION; // disable level 0, set to default level 6 thread_beg_init(pgz, pz->ncpu); pgz->pz = pz; pgz->zsval = 0; pgz->zxval = 0; pgz->soff = 0; pgz->doff = 0; pgz->dst = pz->dsts[pgz->t_idx]; pgz->src = pz->srcs[pgz->t_idx]; pgz->token = 0; pgz->level = level; pgz->task = PGZF_TASK_NULL; thread_end_init(pgz); thread_export(pgz, pz); return pz; } static inline size_t write_pgzf(PGZF *pz, void *dat, size_t len){ size_t off, cnt; thread_prepare(pgz); thread_import(pgz, pz); off = 0; while(off < len){ thread_beg_operate(pgz, pz->widx % pz->ncpu); thread_wait(pgz); /* if(pgz->dst->size){ pz->tot_out += pgz->dst->size; push_u8v(pz->boffs, pz->tot_out); fwrite(pgz->dst->buffer, 1, pgz->dst->size, pz->file); clear_u1v(pgz->dst); clear_u1v(pgz->src); } */ cnt = num_min(len - off, pz->bufsize - pgz->src->size); append_array_u1v(pgz->src, dat + off, cnt); off += cnt; if(pgz->src->size == pz->bufsize){ pz->tot_in += pgz->src->size; pgz->task = PGZF_TASK_DEFLATE; pgz->token = pz->widx; thread_wake(pgz); pz->widx ++; } } thread_export(pgz, pz); return len; } static inline void _end_pgzf_writer(PGZF *pz){ u4i i, widx; thread_prepare(pgz); thread_import(pgz, pz); widx = pz->widx; for(i=0;i<=pz->ncpu;i++){ // (pz->tidx + ncpu + 1) % ncpu thread_beg_operate(pgz, widx % pz->ncpu); thread_wait(pgz); /* if(pgz->dst->size){ pz->tot_out += pgz->dst->size; push_u8v(pz->boffs, pz->tot_out); fwrite(pgz->dst->buffer, 1, pgz->dst->size, pz->file); clear_u1v(pgz->dst); clear_u1v(pgz->src); } */ if(pgz->src->size){ // will force to write un-full block pz->tot_in += pgz->src->size; pgz->task = PGZF_TASK_DEFLATE; pgz->token = pz->widx; thread_wake(pgz); pz->widx ++; } widx ++; } thread_export(pgz, pz); } static inline int write_index_pgzf(PGZF *pz){ u8i i, x; u1i bs[6]; pz->xsize = pz->tot_in; if(!pz->seekable) return 0; if(fseek(pz->file, pz->offset + PGZF_HEAD_ZX_OFFSET, SEEK_SET) == -1){ perror("fseek error in write_index_pgzf"); return 0; } _num2bytes_pgzf(bs, 6, pz->xsize); fwrite(bs, 1, 6, pz->file); for(i=64,x=1;i+PGZF_INDEX_BIN<=pz->boffs->size;i+=PGZF_INDEX_BIN,x++){ push_u8v(pz->xoffs, pz->boffs->buffer[i+PGZF_INDEX_BIN]); _num2bytes_pgzf(bs, 6, pz->boffs->buffer[i+PGZF_INDEX_BIN]); if(fseek(pz->file, pz->offset + pz->boffs->buffer[x] + PGZF_HEAD_ZX_OFFSET, SEEK_SET) == -1){ perror("fseek error in write_index_pgzf"); return 0; } fwrite(bs, 1, 6, pz->file); } fseek(pz->file, 0, SEEK_END); return 1; } static inline PGZF* open_pgzf_reader(FILE *in, u4i bufsize, int ncpu){ PGZF *pz; u8i zxval; b8i offset; u4i i, zsval, hoff; int ftype; thread_prepare(pgz); pz = malloc(sizeof(PGZF)); pz->ncpu = ncpu; pz->ridx = 0; pz->widx = 0; offset = ftell(in); if(offset == -1){ pz->offset = 0; pz->seekable = 0; } else { pz->offset = offset; pz->seekable = 1; } pz->file = in; pz->eof = 0; pz->error = 0; pz->step = 0; pz->dsts = calloc(pz->ncpu, sizeof(u1v*)); pz->srcs = calloc(pz->ncpu, sizeof(u1v*)); pz->tmp = init_u1v(32); pz->tot_in = 0; pz->tot_out = 0; pz->boffs = init_u8v(32); pz->xoffs = init_u8v(32); // recognize PGZF zsval = zxval = 0; hoff = 0; pz->srcs[0] = init_u1v(1024); ftype = _read_pgzf_header(pz->file, pz->srcs[0], &hoff, &zsval, &zxval); pz->tot_in = pz->srcs[0]->size; switch(ftype){ case PGZF_FILETYPE_GZ: pz->step = 1; pz->rw_mode = PGZF_MODE_R_GZ; break; case PGZF_FILETYPE_PGZF: pz->rw_mode = PGZF_MODE_R; break; default: fprintf(stderr, " ** WARNNING: input file is not in gzip format **\n"); pz->rw_mode = PGZF_MODE_R_UNKNOWN; break; } if(pz->rw_mode == PGZF_MODE_R){ pz->z = NULL; pz->xsize = zxval; push_u8v(pz->boffs, zsval); if(pz->seekable){ u8i foff; foff = ftell(pz->file); if(fseek(pz->file, pz->offset + zsval - 4, SEEK_SET) == -1){ fprintf(stderr, " ** ERROR: failed to read uncompress block size in the first block ERR(1) **\n"); return NULL; } if(fread(&pz->bufsize, 4, 1, pz->file) == 0){ fprintf(stderr, " ** ERROR: failed to read uncompress block size in the first block ERR(2) **\n"); return NULL; } if(fseek(pz->file, foff, SEEK_SET) == -1){ fprintf(stderr, " ** ERROR: failed to read uncompress block size in the first block ERR(3) **\n"); return NULL; } } else { pz->bufsize = bufsize; } } else if(pz->rw_mode == PGZF_MODE_R_GZ){ pz->z = calloc(1, sizeof(z_stream)); inflateInit2(pz->z, -15); pz->bufsize = bufsize; } else { pz->z = NULL; pz->bufsize = bufsize; } if(pz->bufsize == 0) pz->bufsize = PGZF_DEFAULT_BUFF_SIZE; pz->bufsize = (pz->bufsize + 0xFFFFFU) & 0xFFF00000U; for(i=0;incpu;i++){ pz->dsts[i] = init_u1v(pz->bufsize); } if(pz->bufsize > pz->srcs[0]->size){ encap_u1v(pz->srcs[0], pz->bufsize - pz->srcs[0]->size); } for(i=1;incpu;i++){ pz->srcs[i] = init_u1v(pz->bufsize); } thread_beg_init(pgz, pz->ncpu); pgz->pz = pz; pgz->zsval = pgz->t_idx? 0 : zsval; pgz->zxval = pgz->t_idx? 0 : zxval; pgz->soff = pgz->t_idx? 0 : hoff; pgz->doff = 0; pgz->src = pz->srcs[pgz->t_idx]; pgz->dst = pz->dsts[pgz->t_idx]; pgz->level = Z_DEFAULT_COMPRESSION; // useless in inflating pgz->task = PGZF_TASK_INFLATE; thread_end_init(pgz); thread_wake_all(pgz); thread_export(pgz, pz); return pz; } /* static inline _clear_pgzf_reader(PGZF *pz){ UNUSED(pz); } static inline off_t seek_pgzf(PGZF *pz, u8i offset){ u4i bidx, boff, xidx, xoff; if(offset > pz->xsize) return -1; else if(offset == pz->xsize){ pz->eof = 1; return offset; } if(!pz->seekable) return -1; bidx = offset / pz->bufsize; boff = offset % pz->>bufsize; xidx = bidx / PGZF_INDEX_BIN; xoff = bidx % PGZF_INDEX_BIN; if(xidx > pz->xoffs->size){ } return 0; } */ static inline size_t read_pgzf(PGZF *pz, void *dat, size_t len){ size_t off; u4i nrun; thread_prepare(pgz); thread_import(pgz, pz); nrun = 0; for(off=0;offwidx % pz->ncpu); thread_wait(pgz); if(pz->error) break; if(len - off < pgz->dst->size - pgz->doff){ memcpy(dat + off, pgz->dst->buffer + pgz->doff, len - off); pz->tot_out += len - off; pgz->doff += len - off; off = len; break; } else if(pgz->dst->size){ memcpy(dat + off, pgz->dst->buffer + pgz->doff, pgz->dst->size - pgz->doff); pz->tot_out += pgz->dst->size - pgz->doff; off += pgz->dst->size - pgz->doff; pgz->doff = pgz->dst->size; pgz->task = PGZF_TASK_INFLATE; thread_wake(pgz); pz->widx ++; } else if(pz->eof){ nrun ++; if(nrun >= pz->ncpu){ break; } } } return off; } static inline void close_pgzf(PGZF *pz){ thread_prepare(pgz); if(pz->rw_mode == PGZF_MODE_W){ _end_pgzf_writer(pz); } thread_import(pgz, pz); thread_beg_close(pgz); free_u1v(pgz->dst); free_u1v(pgz->src); thread_end_close(pgz); free(pz->dsts); free(pz->srcs); free_u1v(pz->tmp); switch(pz->rw_mode){ case PGZF_MODE_W: write_index_pgzf(pz); fflush(pz->file); break; case PGZF_MODE_R: break; case PGZF_MODE_R_GZ: if(pz->z){ inflateEnd(pz->z); free(pz->z); } break; } free_u8v(pz->boffs); free_u8v(pz->xoffs); free(pz); } static inline size_t read_pgzf4filereader(void *obj, void *dat, size_t len){ return read_pgzf((PGZF*)obj, dat, len); } static inline void close_pgzf4filereader(void *obj){ PGZF *pz; pz = (PGZF*)obj; if(pz->file != stdin){ fclose(pz->file); } return close_pgzf(pz); } static inline size_t write_pgzf4filewriter(void *obj, void *dat, size_t len){ return write_pgzf((PGZF*)obj, dat, len); } static inline void close_pgzf4filewriter(void *obj){ PGZF *pz; pz = (PGZF*)obj; return close_pgzf(pz); } #endif wtdbg2-2.5/poacns.h000066400000000000000000001662211353664372200142300ustar00rootroot00000000000000/* * * Copyright (c) 2018, Jue Ruan * * * 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 3 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, see . */ #ifndef PO_MSA_CNS_RJ_H #define PO_MSA_CNS_RJ_H #include "bit2vec.h" #include "dna.h" #include "chararray.h" #include "list.h" #include "hashset.h" #include #include #if __BYTE_ORDER == 1234 //#pragma message(" ** " __FILE__ " has been tested in LITTLE_ENDIAN **\n") #else #pragma message(" ** " __FILE__ " hasn't been tested in BIG_ENDIAN **\n") #endif static int cns_debug = 0; #define POG_RDLEN_MAX 0x7FF8 #define POG_RDCNT_MAX 0x3FFF #define POG_BASEWIDTH 3 #define POG_BASEMAX 0x3F #define POG_HEAD_NODE 0 #define POG_TAIL_NODE 1 #define POG_DP_BT_M 0 #define POG_DP_BT_I 1 #define POG_DP_BT_D 2 #define POG_ALNMODE_OVERLAP 0 #define POG_ALNMODE_GLOBAL 1 #define POG_VST_MAX MAX_U2 #define POG_SCORE_MIN (-(MAX_B2 >> 1)) typedef struct { u2i rid, pos, base; u2i rbeg, rend, rmax; u2i nin, vst; u4i edge, erev; u4i aligned; union { u4i aux; u4i bpos; // backbone pos }; u4i coff; union { u8i flag; struct { u4i roff, voff; }; }; } pog_node_t; define_list(pognodev, pog_node_t); typedef struct { u4i node; u4i cov:31, is_aux:1; u4i next; } pog_edge_t; define_list(pogedgev, pog_edge_t); typedef struct { int cnsmode; // 0: gen_cns_pog, 1: dp_call_cns_pog int refmode; int alnmode; int tribase; int sse; int near_dialog; int W_score; int W, rW, cW; // 64, 16, 8 int Wmax; // 1024 float W_mat_rate; // 0.92 int M, X, I, D, E; float H; // homopolymer merge int T; // bonus for end u4i msa_min_cnt; float msa_min_freq; } POGPar; static const POGPar DEFAULT_POG_PAR = (POGPar){0, 0, POG_ALNMODE_OVERLAP, 0, 1, 0, 0, 64, 16, 8, 1024, 0.92, 2, -5, -2, -4, -1, -3, 20, 3, 0.5}; typedef struct { u4i coff:29, bt:3; float max; } pog_cns_t; typedef struct { SeqBank *seqs; u2v *sbegs, *sends; // suggested [beg, end) on ref(1st seq) in reference-based mode pognodev *nodes; pogedgev *edges; POGPar *par; b2v *qprof; b2v *rows; u4v *rowr; b2v *btds; u2v *btvs; u4v *btxs; u4v *stack; u2i backbone; u4i msa_len; u1v *msa; u2v *bcnts[7]; u2v *hcovs; u1v *cbts; BaseBank *cns; u8i ncall; } POG; static inline POG* init_pog(POGPar par){ POG *g; g = malloc(sizeof(POG)); g->seqs = init_seqbank(); g->sbegs = init_u2v(32); g->sends = init_u2v(32); g->nodes = init_pognodev(16 * 1024); g->edges = init_pogedgev(16 * 1024); g->par = malloc(sizeof(POGPar)); memcpy(g->par, &par, sizeof(POGPar)); g->qprof = init_b2v(4 * 1024); g->rows = init_b2v(16 * 1024); g->rowr = init_u4v(64); g->btds = init_b2v(16 * 1024); g->btvs = init_u2v(8 * 1024 * 1024); g->btxs = init_u4v(1024); g->stack = init_u4v(32); g->backbone = 0; g->msa_len = 0; g->msa = init_u1v(16 * 1024); g->bcnts[0] = init_u2v(4 * 1024); g->bcnts[1] = init_u2v(4 * 1024); g->bcnts[2] = init_u2v(4 * 1024); g->bcnts[3] = init_u2v(4 * 1024); g->bcnts[4] = init_u2v(4 * 1024); g->bcnts[5] = init_u2v(4 * 1024); g->bcnts[6] = init_u2v(4 * 1024); g->hcovs = init_u2v(4 * 1024); g->cbts = init_u1v(5 * 2 * 1024); g->cns = init_basebank(); g->ncall = 0; return g; } static inline void renew_pog(POG *g){ free_seqbank(g->seqs); g->seqs = init_seqbank(); renew_u2v(g->sbegs, 32); renew_u2v(g->sends, 32); renew_pognodev(g->nodes, 16 * 1024); renew_pogedgev(g->edges, 16 * 1024); renew_b2v(g->qprof, 4 * 1024); renew_b2v(g->rows, 16 * 1024); renew_u4v(g->rowr, 64); renew_b2v(g->btds, 16 * 1024); renew_u2v(g->btvs, 8 * 1024 * 1024); renew_u4v(g->btxs, 16 * 1024); renew_u4v(g->stack, 32); renew_u1v(g->msa, 16 * 1024); renew_u2v(g->bcnts[0], 4 * 1024); renew_u2v(g->bcnts[1], 4 * 1024); renew_u2v(g->bcnts[2], 4 * 1024); renew_u2v(g->bcnts[3], 4 * 1024); renew_u2v(g->bcnts[4], 4 * 1024); renew_u2v(g->bcnts[5], 4 * 1024); renew_u2v(g->bcnts[6], 4 * 1024); renew_u2v(g->hcovs, 4 * 1024); renew_u1v(g->cbts, 5 * 2 * 1024); free_basebank(g->cns); g->cns = init_basebank(); } static inline void free_pog(POG *g){ free_seqbank(g->seqs); free_u2v(g->sbegs); free_u2v(g->sends); free_pognodev(g->nodes); free_pogedgev(g->edges); free_b2v(g->qprof); free_b2v(g->rows); free_u4v(g->rowr); free_b2v(g->btds); free_u2v(g->btvs); free_u4v(g->btxs); free_u4v(g->stack); free_u1v(g->msa); free_u2v(g->bcnts[0]); free_u2v(g->bcnts[1]); free_u2v(g->bcnts[2]); free_u2v(g->bcnts[3]); free_u2v(g->bcnts[4]); free_u2v(g->bcnts[5]); free_u2v(g->bcnts[6]); free_u2v(g->hcovs); free_u1v(g->cbts); free_basebank(g->cns); free(g->par); free(g); } static inline void push_pog_core(POG *g, char *seq, u4i len, u2i refbeg, u2i refend){ if(g->seqs->nseq < POG_RDCNT_MAX){ len = num_min(len, POG_RDLEN_MAX); push_seqbank(g->seqs, NULL, 0, seq, len); push_u2v(g->sbegs, refbeg); push_u2v(g->sends, refend); } } static inline void push_pog(POG *g, char *seq, u1i len){ push_pog_core(g, seq, len, 0, 0); } static inline void fwdbitpush_pog_core(POG *g, u8i *bits, u8i off, u4i len, u2i refbeg, u2i refend){ if(g->seqs->nseq < POG_RDCNT_MAX){ len = num_min(len, POG_RDLEN_MAX); fwdbitpush_seqbank(g->seqs, NULL, 0, bits, off, len); push_u2v(g->sbegs, refbeg); push_u2v(g->sends, refend); } } static inline void fwdbitpush_pog(POG *g, u8i *bits, u8i off, u4i len){ fwdbitpush_pog_core(g, bits, off, len, 0, 0); } static inline void revbitpush_pog_core(POG *g, u8i *bits, u8i off, u4i len, u2i refbeg, u2i refend){ if(g->seqs->nseq < POG_RDCNT_MAX){ len = num_min(len, POG_RDLEN_MAX); revbitpush_seqbank(g->seqs, NULL, 0, bits, off, len); push_u2v(g->sbegs, refbeg); push_u2v(g->sends, refend); } } static inline void revbitpush_pog(POG *g, u8i *bits, u8i off, u4i len){ revbitpush_pog_core(g, bits, off, len, 0, 0); } static inline void print_dot_pog(POG *g, FILE *out){ pog_node_t *n; pog_edge_t *e; u4i nidx, eidx; fprintf(out, "digraph {\n"); fprintf(out, "rankdir=LR\n"); fprintf(out, "N0 [label=\"BEG\"]\n"); fprintf(out, "N1 [label=\"END\"]\n"); for(nidx=POG_TAIL_NODE+1;nidxnodes->size;nidx++){ n = ref_pognodev(g->nodes, nidx); fprintf(out, "N%u [label=R%u_%u_%c]\n", nidx, n->rid, n->pos, bit_base_table[(n->base) & 0x03]); } for(nidx=0;nidxnodes->size;nidx++){ n = ref_pognodev(g->nodes, nidx); if(n->aligned != nidx){ fprintf(out, "N%u -> N%u [color=magenta style=dashed]\n", nidx, n->aligned); } eidx = n->edge; while(eidx){ e = ref_pogedgev(g->edges, eidx); #if DEBUG if(e->next == eidx){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); abort(); } #endif eidx = e->next; if(e->is_aux) continue; fprintf(out, "N%u -> N%u [label=%u]\n", nidx, e->node, e->cov); } } fprintf(out, "}\n"); } static inline void fprint_dot_pog(POG *g, char *prefix, char *suffix){ FILE *out; out = open_file_for_write(prefix, suffix, 1); print_dot_pog(g, out); fclose(out); } static inline void print_vstdot_pog(POG *g, char *fname){ FILE *out; pog_node_t *n; pog_edge_t *e; u4i nidx, eidx; out = open_file_for_write(fname, NULL, 1); fprintf(out, "digraph {\n"); for(nidx=0;nidxnodes->size;nidx++){ n = ref_pognodev(g->nodes, nidx); if(nidx && n->vst == 0) continue; fprintf(out, "N%u [label=\"N%u:%u:%u:%d\"]\n", nidx, nidx, n->aux, n->nin, n->vst); eidx = n->edge; while(eidx){ e = ref_pogedgev(g->edges, eidx); eidx = e->next; if(e->is_aux) continue; fprintf(out, "N%u -> N%u [label=%u]\n", nidx, e->node, e->cov); } } fprintf(out, "}\n"); fclose(out); } static inline void print_seqs_pog(POG *g, char *prefix, char *suffix){ FILE *out; u4i i; out = open_file_for_write(prefix, suffix, 1); for(i=0;iseqs->nseq;i++){ fprintf(out, ">S%u len=%u\n", i, g->seqs->rdlens->buffer[i]); println_fwdseq_basebank(g->seqs->rdseqs, g->seqs->rdoffs->buffer[i], g->seqs->rdlens->buffer[i], out); } fclose(out); } static inline void print_msa_pog(POG *g, FILE *out){ char *str; u1i *cns; u4i i, j, b, e, c, n; str = malloc(g->msa_len + 1); fprintf(out, "[POS] "); for(i=j=0;imsa_len;i++){ if((i % 10) == 0){ fprintf(out, "|%04u", i + 1); j += 5; } else if(i >= j){ putc(' ', out); j ++; } } fputc('\n', out); for(i=0;iseqs->nseq+1;i++){ if(i == g->seqs->nseq){ fprintf(out, "[CNS] "); } else { fprintf(out, "[%03u] ", i); } b = i * g->msa_len; e = b + g->msa_len; n = 0; for(j=b;jmsa->buffer[j]; if(c < 4) n ++; str[j-b] = "ACGT-acgt*"[c]; //fputc("ACGT-"[c], out); } str[e-b] = 0; fputs(str, out); if(i == g->seqs->nseq){ fprintf(out, "\t%u\t%u\n", (u4i)g->cns->size, n); } else { fprintf(out, "\t%u\t%u\n", g->seqs->rdlens->buffer[i], n); } } fprintf(out, "[POS] "); cns = ref_u1v(g->msa, g->msa_len * g->seqs->nseq); for(i=j=b=0;imsa_len;i++){ if(cns[i] < 4){ j ++; if((j % 10) == 1){ while(b < i){ fputc(' ', out); b ++; } fprintf(out, "|%04u", j); b += 5; } } } fprintf(out, "\n"); if(1){ u4i divs[5]; u2i *hcovs; hcovs = g->hcovs->buffer; divs[0] = 10000; divs[1] = 1000; divs[2] = 100; divs[3] = 10; divs[4] = 1; for(i=0;i<4;i++){ for(j=0;jmsa_len;j++){ if(hcovs[j] < divs[i + 1]){ str[j] = ' '; } else { str[j] = '0' + ((hcovs[j] % divs[i]) / divs[i + 1]); } } str[j] = 0; fprintf(out, "[%c ] %s\n", "HCOV"[i], str); } } free(str); } static inline pog_node_t* add_node_pog(POG *g, u2i rid, u2i pos, u2i base){ pog_node_t *u; u = next_ref_pognodev(g->nodes); ZEROS(u); u->rid = rid; u->pos = pos; u->base = base; u->aligned = offset_pognodev(g->nodes, u); return u; } static inline pog_edge_t* add_edge_pog(POG *g, pog_node_t *u, pog_node_t *v, int cov, int is_aux){ pog_edge_t *e, *f, *p; u4i eidx; #if DEBUG if(u == v){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); abort(); } #endif if(u->edge == 0){ e = next_ref_pogedgev(g->edges); u->edge = offset_pogedgev(g->edges, e); e->node = offset_pognodev(g->nodes, v); e->cov = cov; e->is_aux = is_aux; e->next = 0; v->nin ++; return e; } else { e = f = p = NULL; encap_pogedgev(g->edges, 1); eidx = u->edge; while(eidx){ f = ref_pogedgev(g->edges, eidx); eidx = f->next; if(f->node == offset_pognodev(g->nodes, v)){ e = f; break; } p = f; } if(e == NULL){ e = next_ref_pogedgev(g->edges); e->node = offset_pognodev(g->nodes, v); e->cov = cov; e->is_aux = is_aux; e->next = 0; v->nin ++; } else { e->is_aux &= is_aux; e->cov += cov; if(cov == 0){ return e; } else if(p == NULL){ return e; } // detach e from u->edge p->next = e->next; e->next = 0; } f = ref_pogedgev(g->edges, u->edge); if(e->cov > f->cov){ e->next = u->edge; u->edge = offset_pogedgev(g->edges, e); } else { while(f->next){ if(ref_pogedgev(g->edges, f->next)->cov < e->cov){ break; } f = ref_pogedgev(g->edges, f->next); } e->next = f->next; f->next = offset_pogedgev(g->edges, e); } return e; } } static inline pog_node_t* merge_node_pog(POG *g, pog_node_t *x, pog_node_t *u){ pog_node_t *v, *w; pog_edge_t *e; u4i xidx, eidx; xidx = offset_pognodev(g->nodes, x); do { v = ref_pognodev(g->nodes, xidx); if(v->nin && v->base == u->base){ eidx = u->edge; while(eidx){ e = ref_pogedgev(g->edges, eidx); eidx = e->next; w = ref_pognodev(g->nodes, e->node); add_edge_pog(g, v, w, e->cov, e->is_aux); w->nin --; // will delete e } u->edge = 0; break; } v = NULL; } while(xidx != offset_pognodev(g->nodes, x)); u->aligned = x->aligned; x->aligned = offset_pognodev(g->nodes, u); return v? v : u; } static inline void beg_pog_core(POG *g, BaseBank *cns, u8i off, u2i len, int clear_all){ pog_node_t *head, *tail, *u, *v; pog_edge_t *e; u4i i, bb, bk; g->ncall ++; if((g->ncall % 16) == 0){ renew_pog(g); } clear_and_encap_pognodev(g->nodes, 2 + len); clear_pogedgev(g->edges); ZEROS(next_ref_pogedgev(g->edges)); head = next_ref_pognodev(g->nodes); ZEROS(head); if(g->par->tribase){ head->base = POG_BASEMAX + 1; } else { head->base = 4; } head->aligned = POG_HEAD_NODE; tail = next_ref_pognodev(g->nodes); ZEROS(tail); if(g->par->tribase){ tail->base = POG_BASEMAX + 1; } else { tail->base = 4; } tail->aligned = POG_TAIL_NODE; u = head; bk = 0; // add backbone nodes g->backbone = len; for(i=0;ipar->tribase){ bk = ((bk << 2) | bb) & POG_BASEMAX; } else { bk = bb; } v = add_node_pog(g, g->seqs->nseq, i, bk); v->bpos = i; e = add_edge_pog(g, u, v, 0, 1); u = v; } e = add_edge_pog(g, u, tail, 0, 1); if(clear_all){ clear_seqbank(g->seqs); clear_u2v(g->sbegs); clear_u2v(g->sends); clear_basebank(g->cns); } } static inline void beg_pog(POG *g){ beg_pog_core(g, NULL, 0, 0, 1); } static inline void prepare_rd_align_pog(POG *g, u2i rid){ pog_node_t *u, *v; pog_edge_t *e; b2i *row, *btds; u8i rmax; u4i seqoff, seqlen, seqlex, slen, seqinc; u4i nidx, eidx, i, j, bb; seqoff = g->seqs->rdoffs->buffer[rid]; seqlen = g->seqs->rdlens->buffer[rid]; seqlex = roundup_times(seqlen, 8); // 128 = 8 * sizeof(b2i) slen = seqlex >> 3; seqinc = seqlex + 8; // seqlex, max_idx, beg, end, and paddings // init graph encap_pognodev(g->nodes, seqlen + 2); encap_pogedgev(g->edges, seqlen + 2); // estimate cap of g->rows for(i=0;inodes->size;i++){ v = ref_pognodev(g->nodes, i); v->roff = 0; v->voff = 0; v->coff = 0; v->vst = 0; v->aux = 0; } clear_u4v(g->stack); push_u4v(g->stack, POG_HEAD_NODE); rmax = 0; bb = 1; while(pop_u4v(g->stack, &nidx)){ u = ref_pognodev(g->nodes, nidx); eidx = u->edge; while(eidx){ e = ref_pogedgev(g->edges, eidx); #if DEBUG if(eidx == e->next){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); abort(); } #endif eidx = e->next; v = ref_pognodev(g->nodes, e->node); if(v->vst == 0){ bb ++; if(bb > rmax){ rmax = bb; } } v->vst ++; if(v->vst == v->nin){ push_u4v(g->stack, e->node); } } bb --; } #if DEBUG if(bb){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); abort(); } #endif rmax += 2; head_sl_b2v(g->rows, g->rows->n_head); clear_and_encap_b2v(g->rows, rmax * seqinc + 8); head_sr_b2v(g->rows, (16 - (((u8i)g->rows->buffer) & 0xF)) >> 1); head_sl_b2v(g->btds, g->btds->n_head); clear_and_encap_b2v(g->btds, rmax * seqinc + 8); head_sr_b2v(g->btds, (16 - (((u8i)g->btds->buffer) & 0xF)) >> 1); inc_b2v(g->rows, seqinc); inc_b2v(g->btds, seqinc); clear_u4v(g->rowr); bb = 0; for(i=0;inodes->size;i++){ v = ref_pognodev(g->nodes, i); v->vst = 0; v->erev = bb; bb += v->nin; if(i < 2) bb ++; // in case of add mnode } clear_u2v(g->btvs); inc_u2v(g->btvs, 8); clear_and_inc_u4v(g->btxs, bb + 1); //g->btxs->buffer[0] = 0; memset(g->btxs->buffer, 0, (bb + 1) * sizeof(u4i)); u = ref_pognodev(g->nodes, POG_HEAD_NODE); if(g->rowr->size){ u->coff = u->roff = g->rowr->buffer[--g->rowr->size]; } else { u->roff = g->rows->size; inc_b2v(g->rows, seqinc); u->coff = g->btds->size; inc_b2v(g->btds, seqinc); } row = ref_b2v(g->rows, u->roff); btds = ref_b2v(g->btds, u->coff); if(g->par->alnmode == POG_ALNMODE_OVERLAP){ // overlap alignment memset(row, 0, seqinc * sizeof(b2i)); //row[0] = g->par->T; } else { // global __m128i MIN; MIN = _mm_set1_epi16(POG_SCORE_MIN); for(j=0;jpar->T; } memset(btds, 0, seqinc * sizeof(b2i)); if(g->par->near_dialog && g->par->W_score <= 0){ row[seqlex] = g->par->W; row[seqlex + 1] = 0; row[seqlex + 2] = num_min(Int(seqlex), 2 * g->par->W + 1); } else { row[seqlex] = 0; row[seqlex + 1] = 0; row[seqlex + 2] = seqlex; } } // SSE // BANDED, Auto fit the previous-row's max score in center // OVERLAP static inline void sse_band_row_rdaln_pog(POG *g, u4i nidx1, u4i nidx2, u4i seqlen, u2i vst, u4i coff1, u4i coff2, u4i roff1, u4i roff2, b2i *qp, int W, int center){ __m128i I, D, H, E, F, S, MAX, MIN, CMP; __m128i BT, BT1, BT2, BT1_MASK, BT2_MASK, BTX_MASK; b2i *row1, *row2, *btds; u4i i, slen, seqlex, beg, end; int lsth, lstf, msk, mi; UNUSED(coff1); slen = (seqlen + 7) / 8; seqlex = slen * 8; I = _mm_set1_epi16(g->par->I); D = _mm_set1_epi16(g->par->D); MIN = _mm_set1_epi16(POG_SCORE_MIN); BT1_MASK = _mm_set1_epi16(0b10); BT2_MASK = _mm_set1_epi16(0b01); BTX_MASK = _mm_set1_epi16(vst << 2); row1 = ref_b2v(g->rows, roff1); row2 = ref_b2v(g->rows, roff2); btds = ref_b2v(g->btds, coff2); if(W){ if(center < 0){ if(row1[row1[seqlex]] >= g->par->W_score){ if(g->par->near_dialog){ if(row1[seqlex + 1] > 0 || row1[seqlex + 2] < Int(seqlex)){ if(row1[seqlex] == (row1[seqlex + 1] + row1[seqlex + 2]) / 2){ center = (row1[seqlex + 1] + row1[seqlex + 2]) / 2 + 1; } else if(row1[seqlex] > (row1[seqlex + 1] + row1[seqlex + 2]) / 2){ center = (row1[seqlex + 1] + row1[seqlex + 2]) / 2 + 2; } else { center = (row1[seqlex + 1] + row1[seqlex + 2]) / 2; } } else { // first set center center = row1[seqlex]; } } else { center = row1[seqlex]; } beg = num_max(center - W, row1[seqlex + 1]); end = num_min(center + 1 + W, row1[seqlex + 2] + 1); if(end > seqlex) end = seqlex; } else { beg = row1[seqlex + 1]; end = num_min(row1[seqlex + 2] + 1, Int(seqlex)); } } else { beg = num_max(center - W, row1[seqlex + 1]); end = num_min(center + 1 + W, row1[seqlex + 2] + 1); if(end > seqlex) end = seqlex; } } else { beg = 0; end = seqlex; } if(beg & 0x7U) beg = beg & (~0x7U); if(end & 0x7U) end = (end + 8) & (~0x7U); beg = beg / 8; end = (end + 7) / 8; if(row1[seqlex + 1] >= row1[seqlex + 2]){ // happening in realign mode for(i=beg*8;i row1[seqlex + 2]){ for(i=row1[seqlex+2];i= row1[seqlex + 2]){ lstf = POG_SCORE_MIN; lsth = 0; // auto global alignment } else { lstf = (g->par->alnmode == POG_ALNMODE_OVERLAP)? 0 : POG_SCORE_MIN; if(nidx1){ lsth = (g->par->alnmode == POG_ALNMODE_OVERLAP)? 0 : POG_SCORE_MIN;; } else { lsth = g->par->T; } } } for(i=beg;i ary[k]){ k = j; } } mi = beg * 8 + k; for(i=beg+1;i row2[mi]){ mi = i * 8 + k; } } } else { mi = beg * 8; for(i=mi+1;i row2[mi]){ mi = i; } } } row2[seqlex] = mi; row2[seqlex + 1] = beg * 8; row2[seqlex + 2] = end * 8; } static inline void merge_row_rdaln_pog(POG *g, u4i seqlen, u4i coff1, u4i coff2, u4i roff1, u4i roff2){ b2i *row1, *row2, *btd1, *btd2; u4i i, seqlex, beg[3], end[3], sz, b; row1 = ref_b2v(g->rows, roff1); row2 = ref_b2v(g->rows, roff2); btd1 = ref_b2v(g->btds, coff1); btd2 = ref_b2v(g->btds, coff2); seqlex = roundup_times(seqlen, 8); beg[0] = (row1[seqlex + 1]); beg[1] = (row2[seqlex + 1]); end[0] = (row1[seqlex + 2]); end[1] = (row2[seqlex + 2]); beg[2] = num_max(beg[0], beg[1]); end[2] = num_min(end[0], end[1]); if(1){ __m128i R1, R2, D1, D2, MK; for(i=beg[2];i&0x7;i++){ if(row2[i] < row1[i]){ row2[i] = row1[i]; btd2[i] = btd1[i]; } } for(;i+8<=end[2];i+=8){ R1 = _mm_load_si128((__m128i*)(row1 + i)); R2 = _mm_load_si128((__m128i*)(row2 + i)); D1 = _mm_load_si128((__m128i*)(btd1 + i)); D2 = _mm_load_si128((__m128i*)(btd2 + i)); MK = _mm_cmpgt_epi16(R1, R2); R2 = _mm_max_epi16(R1, R2); _mm_store_si128((__m128i*)(row2 + i), R2); D2 = _mm_or_si128(_mm_and_si128(MK, D1), _mm_andnot_si128(MK, D2)); _mm_store_si128((__m128i*)(btd2 + i), D2); } for(;i end[2]){ sz = num_min(end[0], seqlex) - end[2]; memcpy(row2 + end[2], row1 + end[2], sz * sizeof(b2i)); memcpy(btd2 + end[2], btd1 + end[2], sz * sizeof(b2i)); } } else { if(beg[0] < beg[1]){ b = beg[0]; if(end[0] >= beg[1]){ sz = beg[1] - beg[0]; memcpy(row2 + b, row1 + b, sz * sizeof(b2i)); memcpy(btd2 + b, btd1 + b, sz * sizeof(b2i)); } else { __m128i F; F = _mm_set1_epi16(POG_SCORE_MIN); sz = end[0] - beg[0]; memcpy(row2 + b, row1 + b, sz * sizeof(b2i)); memcpy(btd2 + b, btd1 + b, sz * sizeof(b2i)); for(i=end[0];i end[1]){ if(beg[0] <= end[1]){ b = end[1]; sz = end[0] - b; memcpy(row2 + b, row1 + b, sz * sizeof(b2i)); memcpy(btd2 + b, btd1 + b, sz * sizeof(b2i)); } else { __m128i F; F = _mm_set1_epi16(POG_SCORE_MIN); b = beg[0]; sz = end[0] - b; memcpy(row2 + b, row1 + b, sz * sizeof(b2i)); memcpy(btd2 + b, btd1 + b, sz * sizeof(b2i)); for(i=end[1];i row2[(row2[seqlex])]){ row2[seqlex] = row1[seqlex]; } } static inline void set_rd_query_prof(POG *g, u4i rid){ b2i *qp; u4i seqoff, seqlen, seqlex, slen, seqinc; u4i i, j, bb, bk; seqoff = g->seqs->rdoffs->buffer[rid]; seqlen = g->seqs->rdlens->buffer[rid]; seqlex = roundup_times(seqlen, 8); slen = seqlex >> 3; seqinc = seqlex + 8; head_sl_b2v(g->qprof, g->qprof->n_head); if(g->par->tribase){ clear_and_encap_b2v(g->qprof, seqlex * (POG_BASEMAX + 2) + 8); head_sr_b2v(g->qprof, (16 - (((u8i)g->qprof->buffer) & 0xF)) >> 1); for(i=0;i<=POG_BASEMAX;i++){ qp = g->qprof->buffer + i * seqlex; bk = 0; for(j=0;jseqs->rdseqs, seqoff + j); bk = ((bk << 2) | bb) & POG_BASEMAX; if(bb == (i & 0x03)){ if(bk == i){ qp[j] = g->par->M + g->par->tribase; } else { qp[j] = g->par->M; } } else { qp[j] = g->par->X; } } for(;jqprof, seqlex * (4 + 1) + 8); head_sr_b2v(g->qprof, (16 - (((u8i)g->qprof->buffer) & 0xF)) >> 1); for(i=0;i<4;i++){ qp = g->qprof->buffer + i * seqlex; for(j=0;jseqs->rdseqs, seqoff + j); if(bb == (i & 0x03)){ qp[j] = g->par->M; } else { qp[j] = g->par->X; } } for(;jqprof->buffer + i * seqlex; X = _mm_set1_epi16(g->par->X); for(j=0;jseqs->rdoffs->buffer[rid]; if(g->par->tribase == 0){ return get_basebank(g->seqs->rdseqs, seqoff + pos); } if(pos >= POG_BASEWIDTH){ return sub32seqbits(g->seqs->rdseqs->bits, seqoff + pos + 1 - POG_BASEWIDTH) >> (64 - (POG_BASEWIDTH << 1)); } else { return (sub32seqbits(g->seqs->rdseqs->bits, seqoff)) >> (64 - ((pos + 1) << 1)); } } static inline int _cal_matches_alignment_pog(POG *g, u4i rid, int *xb, int xe, int *badtail){ pog_node_t *u, *v; u4i nidx, seqoff, btx, bt, vst; int x, seqlen, mat, score, x0, x1, flag; seqlen = g->seqs->rdlens->buffer[rid]; seqoff = g->seqs->rdoffs->buffer[rid]; x = xe; score = 0; x0 = x1 = x; flag = 0; nidx = POG_TAIL_NODE; v = ref_pognodev(g->nodes, nidx); btx = 1; mat = 0; while(x >= 0){ u = ref_pognodev(g->nodes, nidx); bt = g->btvs->buffer[u->voff + x - u->rbeg]; vst = bt >> 2; bt = bt & 0x03; if(bt == POG_DP_BT_M){ if(flag) score += ((u->base & 0x03) == get_basebank(g->seqs->rdseqs, seqoff + x))? g->par->M : g->par->X; else { flag = 1; x1 = x; } mat ++; x --; } else if(bt & POG_DP_BT_I){ if(flag) score += g->par->I; x --; } else { if(flag) score += g->par->D; else { flag = 1; x1 = x; } } if(score == 10 * g->par->M){ x0 = x + 1; } if(bt & POG_DP_BT_I){ } else { nidx = g->btxs->buffer[g->nodes->buffer[nidx].erev + vst]; } if(x < 0){ break; } u = ref_pognodev(g->nodes, nidx); if(x < u->rbeg || x >= u->rend){ break; } } *xb = x; *badtail = x1 > x0? x1 - x0 : 0; return mat; } static inline int _alignment2graph_pog(POG *g, u4i rid, int xb, int xe){ pog_node_t *u, *v; pog_edge_t *e; u4i nidx, i, seqoff, btx, bt, vst; int x, seqlen; seqlen = g->seqs->rdlens->buffer[rid]; seqoff = g->seqs->rdoffs->buffer[rid]; x = xe; nidx = POG_TAIL_NODE; v = ref_pognodev(g->nodes, nidx); int my_print = (cns_debug > 3); if(x + 1 < (int)seqlen){ for(i=seqlen-1;(int)i>x;i--){ if(my_print){ fprintf(stderr, "BT[%u] y=N%u_R%u_%u_%c x=%d:%c z=%d\n", rid, nidx, v->rid, v->pos, bit_base_table[(v->base) & 0x03], i, bit_base_table[get_basebank(g->seqs->rdseqs, seqoff + i)], -1); fflush(stderr); } u = add_node_pog(g, rid, i, get_rdbase_pog(g, rid, i)); add_edge_pog(g, u, v, 1, 0); v = u; } v->coff = ref_pognodev(g->nodes, POG_TAIL_NODE)->coff; } btx = 1; while(1){ if(x >= 0){ u = ref_pognodev(g->nodes, nidx); bt = g->btvs->buffer[u->voff + x - u->rbeg]; } else { bt = 0; } vst = bt >> 2; bt = bt & 0x03; if(my_print){ pog_node_t *w; w = ref_pognodev(g->nodes, nidx); fprintf(stderr, "BT[%u] y=N%u_R%u_%u_%c x=%d:%c z=%d\n", rid, nidx, w->rid, w->pos, bit_base_table[(w->base) & 0x03], x, x>=0? bit_base_table[get_basebank(g->seqs->rdseqs, seqoff + x)] : '*', bt); fflush(stderr); } if(bt == POG_DP_BT_M){ if(btx){ u = add_node_pog(g, rid, x, get_rdbase_pog(g, rid, x)); e = add_edge_pog(g, u, v, 1, 0); x --; if(nidx > POG_TAIL_NODE){ u = merge_node_pog(g, ref_pognodev(g->nodes, nidx), u); } v = u; } else { xb = x; if(nidx == POG_HEAD_NODE || nidx + 1 >= g->nodes->size || g->nodes->buffer[nidx].rid != g->nodes->buffer[nidx + 1].rid){ nidx = POG_HEAD_NODE; } else { nidx ++; } u = ref_pognodev(g->nodes, nidx); e = add_edge_pog(g, u, v, 1, 0); if(nidx != POG_HEAD_NODE){ v = u; u = ref_pognodev(g->nodes, POG_HEAD_NODE); //e = add_edge_pog(g, u, v, 1, 0); e = add_edge_pog(g, u, v, 0, 1); } break; } } else if(bt & POG_DP_BT_I){ u = add_node_pog(g, rid, x, get_rdbase_pog(g, rid, x)); e = add_edge_pog(g, u, v, 1, 0); x --; v = u; } else { } if(x < 0){ // && nidx if(bt == POG_DP_BT_I){ } else { nidx = 0; } btx = 0; continue; } if(bt & POG_DP_BT_I){ } else { nidx = g->btxs->buffer[g->nodes->buffer[nidx].erev + vst]; } #if DEBUG if(nidx >= g->nodes->size){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); abort(); } #endif u = ref_pognodev(g->nodes, nidx); if(x < u->rbeg || x >= u->rend){ xb = x; while(x >= 0){ u = add_node_pog(g, rid, x, get_rdbase_pog(g, rid, x)); e = add_edge_pog(g, u, v, 1, 0); x --; v = u; } { u = ref_pognodev(g->nodes, POG_HEAD_NODE); e = add_edge_pog(g, u, v, 1, 0); v = u; } break; } } return xb; } static inline int align_rd_pog_core(POG *g, u2i rid, int W, int *xe){ pog_node_t *u, *v; pog_edge_t *e; u4i seqoff, seqlen, seqlex, slen, seqinc; b4i score, x; b2i *qp, *row; __m128i SMASK; u4i nidx, eidx, coff, roff, mnode; u4i i, j; seqoff = g->seqs->rdoffs->buffer[rid]; seqlen = g->seqs->rdlens->buffer[rid]; seqlex = roundup_times(seqlen, 8); // 128 = 8 * sizeof(b2i) slen = seqlex >> 3; seqinc = seqlex + 8; // seqlex, max_idx, beg, end, and paddings #if __BYTE_ORDER == 1234 SMASK = _mm_setr_epi8(0, 2, 4, 6, 8, 10, 12, 14, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80); #else // TODO: need to test in BIG_ENDIAN SMASK = _mm_setr_epi8(1, 3, 5, 7, 9, 11, 13, 15, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80); #endif // set query prof // fit buffer to 16 bytes aligned set_rd_query_prof(g, rid); prepare_rd_align_pog(g, rid); clear_u4v(g->stack); push_u4v(g->stack, POG_HEAD_NODE); score = POG_SCORE_MIN; mnode = POG_TAIL_NODE; // point to POG_TAIL x = seqlen - 1; int my_print = (cns_debug > 3); while(pop_u4v(g->stack, &nidx)){ u = ref_pognodev(g->nodes, nidx); u->rmax = g->rows->buffer[u->roff + seqlex]; u->rbeg = g->rows->buffer[u->roff + seqlex + 1]; u->rend = g->rows->buffer[u->roff + seqlex + 2]; if(my_print){ fprintf(stderr, "NODEALN[%u:R%u:%u] %d-%d:%d:%d %d %d\n", nidx, u->rid, u->pos, u->rbeg, u->rend, u->rmax, g->rows->buffer[u->roff + u->rmax], g->btds->buffer[u->coff + u->rmax] >> 2, g->btds->buffer[u->coff + u->rmax] & 0x03); } if(g->par->alnmode == POG_ALNMODE_OVERLAP){ if(u->rend >= seqlen && g->rows->buffer[u->roff + x] > score){ // overlap alignment score = g->rows->buffer[u->roff + x]; mnode = nidx; } } eidx = u->edge; while(eidx){ e = ref_pogedgev(g->edges, eidx); eidx = e->next; v = ref_pognodev(g->nodes, e->node); qp = g->qprof->buffer + v->base * seqlex; if(g->rowr->size){ coff = roff = g->rowr->buffer[-- g->rowr->size]; } else { #if 0 if(g->rows->size + seqinc + g->rows->n_head > g->rows->cap){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); abort(); } #endif roff = g->rows->size; inc_b2v(g->rows, seqinc); coff = g->btds->size; inc_b2v(g->btds, seqinc); } g->btxs->buffer[v->erev + v->vst] = nidx; // save backtrace nidx sse_band_row_rdaln_pog(g, nidx, e->node, seqlen, v->vst, u->coff, coff, u->roff, roff, qp, W, -1); if(v->vst){ merge_row_rdaln_pog(g, seqlen, coff, v->coff, roff, v->roff); push_u4v(g->rowr, roff); } else { v->coff = coff; v->roff = roff; } v->vst ++; if(v->vst == v->nin){ push_u4v(g->stack, e->node); #if DEBUG } else if(v->vst > v->nin){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); abort(); #endif } } push_u4v(g->rowr, u->roff); { // compress-copy btds into btvs u->voff = g->btvs->size; inc_u2v(g->btvs, u->rend - u->rbeg); if(0){ for(i=u->rbeg;irend;i++){ g->btvs->buffer[u->voff + i - u->rbeg] = (u1i)g->btds->buffer[u->coff + i]; } } else { memcpy(g->btvs->buffer + u->voff, g->btds->buffer + u->coff + u->rbeg, (u->rend - u->rbeg) * sizeof(u2i)); } } } v = ref_pognodev(g->nodes, POG_TAIL_NODE); #if DEBUG if(v->roff == 0){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); abort(); } if(v->voff == 0){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); abort(); } #endif if(W == 0){ row = ref_b2v(g->rows, v->roff); j = 0; for(i=1;i row[j]){ j = i; } } v->rmax = row[seqlex] = j; v->rbeg = row[seqlex + 1] = 0; v->rend = row[seqlex + 2] = seqlex; } if(g->par->alnmode == POG_ALNMODE_OVERLAP){ if(g->rows->buffer[v->roff + v->rmax] + g->par->T > score){ score = g->rows->buffer[v->roff + (g->rows->buffer[v->roff + seqlex])]; mnode = POG_TAIL_NODE; x = (g->rows->buffer[v->roff + seqlex]); } } else { score = g->rows->buffer[v->roff + seqlen - 1]; mnode = POG_TAIL_NODE; x = seqlen - 1; } if(x == Int(seqlen - 1) && mnode != POG_TAIL_NODE){ v = ref_pognodev(g->nodes, POG_TAIL_NODE); g->btvs->buffer[v->voff + x - v->rbeg] = (2 | (v->vst << 2)); g->btxs->buffer[v->erev + v->vst] = mnode; v->vst ++; } *xe = x; return score; } static inline int align_rd_pog(POG *g, u2i rid){ int xb, xe, rlen, bad, xlen, score, W, mat; rlen = g->seqs->rdlens->buffer[rid]; xlen = rlen / 8 * 8; W = g->par->W? g->par->W : xlen; xlen = num_min(xlen, g->par->Wmax); mat = 0; // try increase W when align score is low while(1){ score = align_rd_pog_core(g, rid, W, &xe); mat = _cal_matches_alignment_pog(g, rid, &xb, xe, &bad); if(cns_debug > 1){ fprintf(stderr, "ALIGN[%03d] len=%u ref=%d,%d band=%d aligned=%d,%d tail=%d mat=%d,%0.3f score=%d\n", rid, g->seqs->rdlens->buffer[rid], g->sbegs->buffer[rid], g->sends->buffer[rid], W, xb + 1, xe + 1, bad, mat, 1.0 * mat / rlen, score); } if(rid == 0){ break; } if(mat >= rlen * g->par->W_mat_rate && bad < 50){ break; } if(W >= xlen) break; W = num_min(W * 2, xlen); } xb = 0; xb = _alignment2graph_pog(g, rid, xb, xe); return score; } static inline u4i realign_msa_pog_core(POG *g, u4i ridx, int W){ u2i *bcnts[7], *hcovs, *bts, *bs, *bs1; u1i *r, *s; int wins[20], winl, winy, winx; u4i i, *dps, f, h, e, *row1, *row2, max, bt; int j, beg, end, off, x, y; hcovs = g->hcovs->buffer; for(i=0;i<7;i++){ clear_and_encap_u2v(g->bcnts[i], g->msa_len); bcnts[i] = g->bcnts[i]->buffer; memset(bcnts[i], 0, g->msa_len * sizeof(u2i)); } for(i=0;iseqs->nseq;i++){ if(i == ridx) continue; r = ref_u1v(g->msa, g->msa_len * i); for(j=0;j<(int)g->msa_len;j++){ bcnts[r[j]][j] ++; } } for(i=0;imsa_len;i++){ max = 0; for(j=1;j<4;j++){ if(bcnts[j][i] > bcnts[max][i]){ max = j; } } bcnts[5][i] = max; bcnts[6][i] = bcnts[0][i] + bcnts[1][i] + bcnts[2][i] + bcnts[3][i]; } s = ref_u1v(g->msa, g->msa_len * ridx); winl = 20; winx = 0; winy = 0; beg = -1; memset(wins, 0, winl * sizeof(int)); if(0){ for(i=0;imsa_len;i++){ max = bcnts[5][i]; winy -= wins[winx]; if(s[i] < 4 && ((hcovs[i] >= 4 && bcnts[s[i]][i] == 0))){ wins[winx] = 1; } else { wins[winx] = 0; } winy += wins[winx]; //fprintf(stderr, " -- hcovs = %d s[i] = %c:%d i = %u winy = %d in %s -- %s:%d --\n", hcovs[i], "ACGT-"[s[i]], bcnts[s[i]][i], i, winy, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); if(Int(i) > winl){ if(winy >= Int(0.9 * winl)){ if(beg < 0){ beg = i - winl; } } else { if(beg >= 0){ end = i; if(cns_debug > 1){ fprintf(stderr, " -- remove low quality fragment %d - %d: ", beg, end); for(j=beg;jbtds, (g->msa_len + 1) * W * 2); bts = (u2i*)g->btds->buffer; clear_and_encap_u4v(g->btxs, (g->msa_len + 1) * W * 2); dps = g->btxs->buffer; memset(bts, 0, 2 * W * sizeof(u2i)); memset(dps, 0, 2 * W * sizeof(u4i)); bts += W * 2; dps += W * 2; for(i=0;imsa_len;i++){ bs1 = bts + 2 * W * (Int(i) - 1); bs = bts + 2 * W * i; row1 = dps + 2 * W * (Int(i) - 1); row2 = dps + 2 * W * i; f = 0; off = Int(i) - W; if(Int(i) <= W){ beg = W - i; } else { beg = 0; } if(i + W - 1 >= g->msa_len){ end = W + g->msa_len - i; } else { end = W * 2 - 1; } if(s[i] == 4){ for(j=beg;j= e){ bs[j] = 0; } else { h = e; bs[j] = 1; } if(h >= f){ f = h; } else { h = f; bs[j] = 2; } row2[j] = h; } } else { for(j=beg;j= Int(bcnts[6][off + j] - bcnts[s[i]][off + j])){ h = row1[j] + 2 * bcnts[s[i]][off + j] - bcnts[6][off + j] + 1; } else { h = row1[j] + 1; } // bonus for putting homo together if(i && bs1[j] == 0 && s[i] == s[i - 1]){ h += 1; } if(h >= e){ bs[j] = 0; } else { h = e; bs[j] = 1; } if(h >= f){ f = h; } else { h = f; bs[j] = 2; } row2[j] = h; } } if(beg){ row2[beg - 1] = 0; bs[beg - 1] = 0; } row2[end] = 0; bs[end] = 0; if(cns_debug > 3){ fprintf(stderr, "ROW[%u] '%c' %03d-%03d:", i, "ACGT-"[s[i]], beg, end); for(j=beg;jmsa_len - 1); max = row2[W]; r = ref_u1v(g->msa, g->msa_len * g->seqs->nseq); x = y = g->msa_len - 1; while(y >= 0 && x >= 0){ off = x - W; bs = bts + 2 * W * x; bt = bs[y - off]; switch(bt){ case 0: r[y] = s[x]; x --; y --; break; case 1: x --; break; case 2: r[y] = 4; y --; break; } if(cns_debug > 3 && bt){ fprintf(stderr, " -- x = %d y = %d bt = %d in %s -- %s:%d --\n", x, y, bt, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); } } if(cns_debug > 1){ fprintf(stderr, " -- max = %d x = %d y = %d in %s -- %s:%d --\n", max, x, y, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); } while(y >= 0){ r[y] = 4; y --; } return max; } static inline void realign_msa_pog(POG *g){ u4i ridx; if(g->par->rW <= 0 || g->seqs->nseq < 3) return; if(cns_debug > 1){ fprintf(stderr, "RAW MSA\n"); print_msa_pog(g, stderr); } for(ridx=0;ridxseqs->nseq;ridx++){ if(cns_debug > 1){ fprintf(stderr, "REALIGN[%u]\n", ridx); } realign_msa_pog_core(g, ridx, g->par->rW); if(cns_debug > 1){ print_msa_pog(g, stderr); } // update ridx alignment memcpy(g->msa->buffer + g->msa_len * ridx, g->msa->buffer + g->msa_len * g->seqs->nseq, g->msa_len); } } static const float homo_merging_cmp_norm[20] = { 0.95, 0.90, 0.80, 0.75, 0.70, 0.70, 0.65, 0.60, 0.60, 0.55, 0.50, 0.45, 0.40, 0.30, 0.20, 0.20, 0.20, 0.20, 0.20, 0.20 }; /* static inline void dp_gen_cns_pog(POG *g){ pog_cns_t dps[2 * 5], *dp1, *dp2; b2i *row1, *row2, *row3; u1i *s, *r; u4i mcnt; int bcnts[5]; u2i *hcovs, *rexs; u4i rid, beg, end, x, val, fidx, col, dep; u4i mx, mi, i, j; float DP_MIN, score0, score1; DP_MIN = - (MAX_B4 >> 1); mcnt = num_min(g->par->msa_min_cnt, g->seqs->nseq); clear_and_encap_u1v(g->cbts, g->msa_len * 5); // scan read end clear_u4v(g->btxs); clear_u2v(g->btvs); // whether read cov current column hcovs = g->hcovs->buffer; memset(hcovs, 0, g->msa_len * sizeof(u2i)); for(rid=0;ridseqs->nseq;rid++){ push_u2v(g->btvs, MAX_U2); r = ref_u1v(g->msa, g->msa_len * rid); beg = 0; while(beg < g->msa_len && r[beg] == 4) beg ++; push_u4v(g->btxs, (0U << 31) | (rid << 16) | beg); end = g->msa_len; while(end > beg && r[end - 1] == 4) end --; push_u4v(g->btxs, (1U << 31) | (rid << 16) | end); for(i=beg;ibtxs->buffer, g->btxs->size, u4i, num_cmpgt(a & 0xFFFF, b & 0xFFFF)); mx = 0; rexs = g->btvs->buffer; memset(dps, 0, 2 * 5 * sizeof(pog_cns_t)); fidx = 0; clear_b2v(g->rows); clear_u4v(g->rowr); dp1 = dps; inc_b2v(g->rows, g->par->cW * g->seqs->nseq); for(i=0;i<5;i++){ dp1[i].coff = g->rows->size; inc_b2v(g->rows, g->par->cW * g->seqs->nseq); row1 = g->rows->buffer + dp1[i].coff; memset(row1, 0, g->par->cW * g->seqs->nseq * sizeof(b2i)); } dep = 0; for(col=0;colmsa_len;col++){ fidx = !fidx; dp1 = dps + fidx * 5; dp2 = dps + (!fidx) * 5; // collect read coverage while(mx < g->btxs->size){ val = g->btxs->buffer[mx]; if((val & 0xFFFF) <= col){ rid = (val << 1) >> 17; if(val & (1U << 31)){ #if DEBUG if(rexs[rid] == MAX_U2){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); abort(); } #endif rexs[rid] = MAX_U2; dep --; } else { #if DEBUG if(rexs[rid] < MAX_U2){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); abort(); } #endif rexs[rid] = 0; dep ++; } mx ++; } else { break; } } for(i=0;i<5;i++){ dp2[i].max = DP_MIN; dp2[i].bt = 4; if(g->rowr->size){ dp2[i].coff = pop_u4v(g->rowr); } else { dp2.coff = g->rows->size; inc_b2v(g->rows, g->par->cW * g->seqs->nseq); } } row2 = g->rows->buffer; // temprary if(dep < mcnt && !(g->par->refmode && rexs[0] != MAX_U2)){ //TODO: coding from here mi = 4; for(i=0;i<4;i++){ if(dp1[i] > dp1[mi]){ mi = i; } } dp2[4] = dp1[mi]; bts[4] = mi; } else { for(i=0;i<=4;i++){ score0 = dp1[i]; for(j=0;j<=4;j++){ score1 = score0; for(x=0;x<=4;x++){ if(j == 4){ if(x != 4){ score1 += bcnts[x] * g->par->I; } } else { if(x == 4){ if(i == j){ score1 += bcnts[x] * g->par->H; } else { score1 += bcnts[x] * g->par->D; } } else if(x == j){ score1 += bcnts[x] * g->par->M; } else { score1 += bcnts[x] * g->par->X; } } } if(score1 > dp2[j]){ dp2[j] = score1; bts[j] = i; } } } // Prior to the first read for(rid=0;ridseqs->nseq;rid++){ if(rexs[i] == 0){ continue; } r = ref_u1v(g->msa, g->msa_len * rid); dp2[r[col]] += 0.1; break; } } for(i=0;i<=4;i++){ push_u1v(g->cbts, bts[i]); } if(cns_debug > 2){ fprintf(stderr, "[DPCNS%03u]\t[%2d, %2d, %2d, %2d, %2d]", col, bcnts[0], bcnts[1], bcnts[2], bcnts[3], bcnts[4]); //fprintf(stderr, "\t[%0.1f, %0.1f, %0.1f, %0.1f, %0.1f]", dp1[0], dp1[1], dp1[2], dp1[3], dp1[4]); fprintf(stderr, "\t[%0.1f:%d, %0.1f:%d, %0.1f:%d, %0.1f:%d, %0.1f:%d]\n", dp2[0], bts[0], dp2[1], bts[1], dp2[2], bts[2], dp2[3], bts[3], dp2[4], bts[4]); } } // Backtrace consensus sequence dp2 = dps + (!fidx) * 5; mx = 4; for(i=0;i<4;i++){ if(dp2[i] > dp2[mx]){ mx = i; } } x = g->msa_len; s = ref_u1v(g->msa, g->msa_len * g->seqs->nseq); while(x){ x --; s[x] = mx; mx = g->cbts->buffer[x * 5 + mx]; } for(i=0;imsa_len;i++){ if(s[i] < 4){ bit2basebank(g->cns, s[i]); } } } */ static inline void dp_call_cns_pog(POG *g){ u1i *s, *r, bts[5]; u4i mcnt; int bcnts[5]; u2i *hcovs, *rexs; u4i rid, beg, end, x, val, fidx, col, dep; u4i mx, mi, i, j; float dps[2 * 5], *dp1, *dp2, DP_MIN, score0, score1; DP_MIN = - (MAX_B4 >> 1); mcnt = num_min(g->par->msa_min_cnt, g->seqs->nseq); clear_and_encap_u1v(g->cbts, g->msa_len * 5); // scan read end clear_u4v(g->btxs); clear_u2v(g->btvs); // whether read cov current column hcovs = g->hcovs->buffer; memset(hcovs, 0, g->msa_len * sizeof(u2i)); for(rid=0;ridseqs->nseq;rid++){ push_u2v(g->btvs, 0); r = ref_u1v(g->msa, g->msa_len * rid); beg = 0; while(beg < g->msa_len && r[beg] == 4) beg ++; push_u4v(g->btxs, (0U << 31) | (rid << 16) | beg); end = g->msa_len; while(end > beg && r[end - 1] == 4) end --; push_u4v(g->btxs, (1U << 31) | (rid << 16) | end); for(i=beg;ibtxs->buffer, g->btxs->size, u4i, num_cmpgt(a & 0xFFFF, b & 0xFFFF)); memset(dps, 0, 2 * 5 * sizeof(float)); fidx = 0; dep = 0; mx = 0; rexs = g->btvs->buffer; for(col=0;colmsa_len;col++){ fidx = !fidx; dp1 = dps + fidx * 5; dp2 = dps + (!fidx) * 5; // collect read coverage while(mx < g->btxs->size){ val = g->btxs->buffer[mx]; if((val & 0xFFFF) <= col){ rid = (val << 1) >> 17; if(val & (1U << 31)){ #if DEBUG if(rexs[rid] == 0){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); abort(); } #endif rexs[rid] = 0; dep --; } else { #if DEBUG if(rexs[rid] == 1){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); abort(); } #endif rexs[rid] = 1; dep ++; } mx ++; } else { break; } } bts[0] = bts[1] = bts[2] = bts[3] = bts[4] = 4; dp2[0] = DP_MIN; dp2[1] = DP_MIN; dp2[2] = DP_MIN; dp2[3] = DP_MIN; dp2[4] = DP_MIN; memset(bcnts, 0, sizeof(int) * 5); for(rid=0;ridseqs->nseq;rid++){ if(rexs[rid] == 0){ continue; } r = ref_u1v(g->msa, g->msa_len * rid); bcnts[r[col]] ++; } if(dep < mcnt && !(g->par->refmode && rexs[0])){ mi = 4; for(i=0;i<4;i++){ if(dp1[i] > dp1[mi]){ mi = i; } } dp2[4] = dp1[mi]; bts[4] = mi; } else { for(i=0;i<=4;i++){ score0 = dp1[i]; for(j=0;j<=4;j++){ score1 = score0; for(x=0;x<=4;x++){ if(j == 4){ if(x != 4){ score1 += bcnts[x] * g->par->I; } } else { if(x == 4){ if(i == j){ score1 += bcnts[x] * g->par->H; } else { score1 += bcnts[x] * g->par->D; } } else if(x == j){ score1 += bcnts[x] * g->par->M; } else { score1 += bcnts[x] * g->par->X; } } } if(score1 > dp2[j]){ dp2[j] = score1; bts[j] = i; } } } // Prior to the first read for(rid=0;ridseqs->nseq;rid++){ if(rexs[i] == 0){ continue; } r = ref_u1v(g->msa, g->msa_len * rid); dp2[r[col]] += 0.1; break; } } for(i=0;i<=4;i++){ push_u1v(g->cbts, bts[i]); } if(cns_debug > 2){ fprintf(stderr, "[DPCNS%03u]\t[%2d, %2d, %2d, %2d, %2d]", col, bcnts[0], bcnts[1], bcnts[2], bcnts[3], bcnts[4]); //fprintf(stderr, "\t[%0.1f, %0.1f, %0.1f, %0.1f, %0.1f]", dp1[0], dp1[1], dp1[2], dp1[3], dp1[4]); fprintf(stderr, "\t[%0.1f:%d, %0.1f:%d, %0.1f:%d, %0.1f:%d, %0.1f:%d]\n", dp2[0], bts[0], dp2[1], bts[1], dp2[2], bts[2], dp2[3], bts[3], dp2[4], bts[4]); } } // Backtrace consensus sequence dp2 = dps + (!fidx) * 5; mx = 4; for(i=0;i<4;i++){ if(dp2[i] > dp2[mx]){ mx = i; } } x = g->msa_len; s = ref_u1v(g->msa, g->msa_len * g->seqs->nseq); while(x){ x --; s[x] = mx; mx = g->cbts->buffer[x * 5 + mx]; } for(i=0;imsa_len;i++){ if(s[i] < 4){ bit2basebank(g->cns, s[i]); } } } static inline void gen_cns_pog(POG *g){ u1i *s, *r; u4i idx, lst, lsv, lsx, rid, max, i, mcnt, min_cnt, max_cnt, runlen, cnl, beg, end, cbeg, cend; u4i freqs[5][11], fmax1, fmax2, tot, cut, *hcnts; u2i cnts[5], *bls, cl, bx, bl, bm, dl, dm, *hcovs, corr; //u2i *vsts; float fl, fx1, fx2, norm, flush; mcnt = num_min(g->par->msa_min_cnt, g->seqs->nseq); min_cnt = num_max(mcnt, UInt(g->par->msa_min_freq * g->seqs->nseq)); max_cnt = g->seqs->nseq - min_cnt; s = ref_u1v(g->msa, g->msa_len * g->seqs->nseq); memset(s, 4, g->msa_len); clear_basebank(g->cns); hcovs = g->hcovs->buffer; bls = hcovs + 8 + g->msa_len; // bls is all zeros, see end_pog if(g->par->rW){ memset(hcovs, 0, g->msa_len * sizeof(u2i)); for(rid=0;ridseqs->nseq;rid++){ r = ref_u1v(g->msa, g->msa_len * rid); beg = 0; while(beg < g->msa_len && r[beg] == 4) beg ++; end = g->msa_len; while(end > beg && r[end - 1] == 4) end --; for(i=beg;ipar->refmode){ } else if(0){ tot = 0; clear_and_encap_u4v(g->btxs, mcnt + 1); hcnts = g->btxs->buffer; //hcnts = alloca((mcnt + 1) * sizeof(u4i)); memset(hcnts, 0, (mcnt + 1) * sizeof(u4i)); for(i=0;imsa_len;i++){ tot += (hcovs[i] + 1) * (hcovs[i]) / 2; hcnts[num_min(hcovs[i], mcnt)] += (hcovs[i] + 1) * (hcovs[i]) / 2; } cut = tot * 0.8; tot = 0; for(i=mcnt;i>1;i--){ tot += hcnts[i]; if(tot >= cut){ break; } } if(i < mcnt){ if(cns_debug > 1){ fprintf(stderr, " Revise mcnt %u -> %u\n", mcnt, i); fflush(stderr); } mcnt = i; min_cnt = i; max_cnt = g->seqs->nseq - min_cnt; } } // gen cns cbeg = 0; cend = g->msa_len; if(g->par->refmode){ rid = 0; { r = ref_u1v(g->msa, g->msa_len * rid); cbeg = 0; while(cbeg < g->msa_len && r[cbeg] == 4){ hcovs[cbeg] = 0; cbeg ++; } end = g->msa_len; while(cend > cbeg && r[cend - 1] == 4){ cend --; hcovs[cend] = 0; } } } else { cbeg = 0; while(cbeg < g->msa_len && hcovs[cbeg] < min_cnt) cbeg ++; cend = g->msa_len; while(cend > cbeg && hcovs[cend - 1] < min_cnt) cend --; } fmax1 = 5; fmax2 = 10; if(cns_debug > 1){ for(i=0;ipar->refmode){ if((max = g->msa->buffer[g->msa_len * 0 + idx]) == 4){ max = 0; } else { if(hcovs[idx] < min_cnt){ flush = 1; } } } else { max = 0; } for(rid=0;ridseqs->nseq;rid++){ cnts[g->msa->buffer[g->msa_len * rid + idx]] ++; } for(i=0;i<4;i++){ if(cnts[i] > cnts[max]){ max = i; } } if(flush){ s[idx] = max; end = idx; } else if(hcovs[idx] >= min_cnt && cnts[max] >= mcnt && cnts[4] - (g->seqs->nseq - hcovs[idx]) < (g->seqs->nseq - cnts[4])){ s[idx] = max; end = idx; flush = 1; } } else { if(end + 1 == idx){ end = idx; } max = 4; flush = 1; } if(flush){ if(lst == MAX_U4){ lst = idx; lsv = idx; } if(idx == cend || s[lst] != max){ runlen = 0; for(rid=0;ridseqs->nseq;rid++){ r = ref_u1v(g->msa, g->msa_len * rid); bl = 0; for(i=lsv;iseqs->nseq, u2i, num_cmpgt(b, a)); bx = 1; bl = bls[0]; bm = 1; dl = 0; dm = 0; for(rid=1;rid<=hcovs[lst];rid++){ if(rid < hcovs[lst] && bls[rid] == bls[rid - 1]){ bx ++; } else { if(cns_debug > 1 && cl <= fmax1 && bls[rid - 1] <= fmax2){ freqs[cl - 1][bls[rid - 1]] += bx; } if(bx > bm){ if(dm < bm){ dm = bm; dl = bl; } bm = bx; bl = bls[rid - 1]; } else if(bx > dm){ dm = bx; dl = bls[rid - 1]; } bx = 1; } } fl = runlen * 1.0 / hcovs[lst]; if(cns_debug > 1){ fprintf(stderr, "HOMO[%3u] %4u\t%c\t%u\t%u:%u\t%u:%u\t%u\t%u\t%0.2f", lst, cnl, bit_base_table[s[lst]], cl, bl, bm, dl, dm, runlen, hcovs[lst], fl); if(cl != bl){ fprintf(stderr, " *\n"); } else { fprintf(stderr, "\n"); } } if(cl != bl){ if(bl > cl + 1 && bl > Int(fl) + 1) bl = Int(fl) + 1; // Don't correct too much if(bl + 1 < cl && (float)bl < fl) bl = cl - 1; if(bl < cl && cl == dl && dm >= Int(0.8 * bm)){ // prefer increase runlen norm = 1.0 / homo_merging_cmp_norm[num_min(cl, 19)]; } else { norm = homo_merging_cmp_norm[num_min(bl, 19)]; } fx1 = num_abs(cl - fl); fx2 = num_abs(bl - fl); if(norm * fx2 <= fx1){ corr = bl; if(cns_debug > 1){ fprintf(stderr, "CORR[%03u] %4u\t%c\t%u->%u\n", lst, cnl, bit_base_table[s[lst]], cl, bl); } } else { corr = cl; } } else { corr = cl; } cnl += cl; for(i=0;icns, s[lst]); if(i){ s[lst + i] = s[lst]; } } for(i+=lst;i 1){ for(cl=0;clnodes->size;nidx++){ u = ref_pognodev(g->nodes, nidx); clear_u32hash(hash); eidx = u->edge; while(eidx){ e = ref_pogedgev(g->edges, eidx); eidx = e->next; t = prepare_u32hash(hash, e->node, &exists); if(exists){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); abort(); } else { *t = e->node; } } } free_u32hash(hash); } static inline void end_pog(POG *g){ pog_node_t *u, *v, *x; pog_edge_t *e; u1i *r; u4i i, ridx, nidx, eidx, xidx, moff, ready, beg, end, reflen, margin; int score; clear_basebank(g->cns); if(g->seqs->nseq == 0) return; score = align_rd_pog(g, 0); if(g->par->refmode){ // add edges to refbeg and refend, to make sure reads can be aligned quickly and correctly within small bandwidth u = ref_pognodev(g->nodes, POG_HEAD_NODE); reflen = g->seqs->rdlens->buffer[0]; margin = 5; for(i=0;isbegs->size;i++){ if(g->sbegs->buffer[i] < margin || g->sbegs->buffer[i] + margin >= reflen) continue; nidx = POG_TAIL_NODE + 1 + (reflen - 1 - g->sbegs->buffer[i]); v = ref_pognodev(g->nodes, nidx); e = add_edge_pog(g, u, v, 0, 1); } v = ref_pognodev(g->nodes, POG_TAIL_NODE); for(i=0;isends->size;i++){ if(g->sends->buffer[i] < margin || g->sends->buffer[i] + margin >= reflen) continue; nidx = POG_TAIL_NODE + 1 + (reflen - g->sends->buffer[i]); u = ref_pognodev(g->nodes, nidx); e = add_edge_pog(g, u, v, 0, 1); } } for(ridx=1;ridxseqs->nseq;ridx++){ score = align_rd_pog(g, ridx); } for(nidx=0;nidxnodes->size;nidx++){ u = ref_pognodev(g->nodes, nidx); u->vst = 0; u->aux = 0; u->coff = 0; u->erev = 0; } // calcuate msa_len clear_u4v(g->stack); push_u4v(g->stack, POG_HEAD_NODE); nidx = POG_HEAD_NODE; while(pop_u4v(g->stack, &nidx)){ u = ref_pognodev(g->nodes, nidx); eidx = u->edge; while(eidx){ e = ref_pogedgev(g->edges, eidx); eidx = e->next; v = ref_pognodev(g->nodes, e->node); if(u->coff + 1 > v->coff){ v->coff = u->coff + 1; } v->vst ++; if(v->vst > v->nin){ print_vstdot_pog(g, "1.dot"); fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); check_dup_edges_pog(g); abort(); } } eidx = u->edge; while(eidx){ e = ref_pogedgev(g->edges, eidx); eidx = e->next; v = ref_pognodev(g->nodes, e->node); if(v->aux) continue; // already pushed if(v->vst > v->nin){ print_vstdot_pog(g, "1.dot"); fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); check_dup_edges_pog(g); abort(); } if(v->vst == v->nin){ ready = 1; { xidx = v->aligned; moff = v->coff; while(xidx != e->node){ x = ref_pognodev(g->nodes, xidx); if(x->nin > x->vst){ ready = 0; break; } if(x->coff > moff){ moff = x->coff; } xidx = x->aligned; } } if(ready){ v->coff = moff; v->aux = 1; push_u4v(g->stack, e->node); xidx = v->aligned; while(xidx != e->node){ x = ref_pognodev(g->nodes, xidx); x->coff = moff; if(x->edge){ push_u4v(g->stack, xidx); x->aux = 1; } xidx = x->aligned; } } } } } if(nidx != POG_TAIL_NODE){ fprint_dot_pog(g, "1.dot", NULL); print_seqs_pog(g, "1.seqs.fa", NULL); fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); abort(); } // generate MSA u = ref_pognodev(g->nodes, POG_TAIL_NODE); g->msa_len = u->coff; for(nidx=0;nidxnodes->size;nidx++){ u = ref_pognodev(g->nodes, nidx); u->vst = 0; } clear_and_encap_u1v(g->msa, g->msa_len * (g->seqs->nseq + 2)); g->msa->size = g->msa_len * (g->seqs->nseq + 1); memset(g->msa->buffer, 4, g->msa->size); clear_u4v(g->stack); push_u4v(g->stack, POG_HEAD_NODE); while(pop_u4v(g->stack, &nidx)){ u = ref_pognodev(g->nodes, nidx); eidx = u->edge; while(eidx){ e = ref_pogedgev(g->edges, eidx); eidx = e->next; v = ref_pognodev(g->nodes, e->node); v->vst ++; if(v->vst >= v->nin){ ready = 1; xidx = v->aligned; while(xidx != e->node){ x = ref_pognodev(g->nodes, xidx); if(x->nin > x->vst){ ready = 0; break; } xidx = x->aligned; } if(ready){ xidx = e->node; do { x = ref_pognodev(g->nodes, xidx); if(xidx != POG_TAIL_NODE){ set_u1v(g->msa, x->rid * g->msa_len + x->coff, (x->base) & 0x03); } if(x->edge){ push_u4v(g->stack, xidx); } xidx = x->aligned; } while(xidx != e->node); } } } } clear_and_encap_u2v(g->hcovs, g->msa_len + 8 + g->seqs->nseq); memset(g->hcovs->buffer, 0, (g->msa_len + 8 + g->seqs->nseq) * sizeof(u2i)); for(ridx=0;ridxseqs->nseq;ridx++){ r = ref_u1v(g->msa, g->msa_len * ridx); beg = 0; while(beg < g->msa_len && r[beg] == 4) beg ++; end = g->msa_len; while(end && r[end - 1] == 4) end --; for(i=beg;ihcovs->buffer[i] ++; } // realignment realign_msa_pog(g); //// realignment again //realign_msa_pog(g); // gen consensus line if(g->par->cnsmode == 1){ dp_call_cns_pog(g); } else { gen_cns_pog(g); } if(cns_debug > 1){ print_msa_pog(g, stderr); } if(0){ fprintf(stderr, " -- seqs\t%llu --\n", (u8i)g->seqs->rdseqs->cap); fflush(stderr); fprintf(stderr, " -- nodes\t%llu --\n", (u8i)g->nodes->cap); fflush(stderr); fprintf(stderr, " -- edges\t%llu --\n", (u8i)g->edges->cap); fflush(stderr); fprintf(stderr, " -- rows\t%llu/%llu --\n", (u8i)g->rows->size, (u8i)g->rows->cap); fflush(stderr); fprintf(stderr, " -- btds\t%llu/%llu --\n", (u8i)g->rows->size, (u8i)g->btds->cap); fflush(stderr); fprintf(stderr, " -- btxs\t%llu/%llu --\n", (u8i)g->btxs->size, (u8i)g->btxs->cap); fflush(stderr); fprintf(stderr, " -- cns\t%llu --\n", (u8i)g->cns->cap); fflush(stderr); } } #endif wtdbg2-2.5/queue.h000066400000000000000000000073601353664372200140670ustar00rootroot00000000000000/* * * Copyright (c) 2011, Jue Ruan * * * 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 3 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, see . */ #ifndef __FIFO_QUEUE_RJ_H #define __FIFO_QUEUE_RJ_H #include #include #include #include #include "sort.h" #include "mem_share.h" #include "list.h" #define define_queue_core(list_type, e_type, size_type, inc_size) \ \ typedef struct { e_type* buffer; size_type* links; size_type head, tail, size; size_type* trash; size_type trash_size, trash_cap; size_type off; size_type cap; } list_type; \ \ static inline size_t list_type##_obj_desc_cnt(void *list, int idx){ \ if(idx == 0) return ((list_type*)list)->size * sizeof(e_type); \ else if(idx == 1) return ((list_type*)list)->size * sizeof(size_type); \ else if(idx == 2) return ((list_type*)list)->trash_size * sizeof(size_type); \ else return 1; \ } \ \ static const obj_desc_t list_type##_obj_desc = {.tag = TOSTR(list_type##_obj_desc), .size = sizeof(list_type), .n_child = 3, .addr = {offsetof(list_type, buffer), offsetof(list_type, links), offsetof(list_type, trash)}, .desc = {(struct obj_desc_t*)&OBJ_DESC_DATA, (struct obj_desc_t*)&OBJ_DESC_DATA, (struct obj_desc_t*)&OBJ_DESC_DATA}, .cnt = list_type##_obj_desc_cnt, .post = NULL}; \ \ static inline list_type* init_##list_type(){ \ list_type *list = (list_type*)malloc(sizeof(list_type)); \ list->off = 0; \ list->cap = 0; \ list->buffer = NULL; \ list->links = NULL; \ list->trash = NULL; \ list->trash_size = 0; \ list->trash_cap = 0; \ list->head = 0; \ list->tail = 0; \ list->size = 0; \ return list; \ } \ \ static inline size_type count_##list_type(list_type *list){ return list->size; } \ \ static inline void clear_##list_type(list_type *list){ list->trash_size = 0; list->off = 0; list->head = 0; list->tail = 0; list->size = 0; } \ \ static inline void push_##list_type(list_type *list, e_type e){ \ size_type idx; \ if(list->trash_size){ \ idx = list->trash[--list->trash_size]; \ } else { \ encap_list((void**)&(list->buffer), sizeof(e_type), list->off, list->cap, 1, 0, 0); \ list->cap = encap_list((void**)&(list->links), sizeof(size_type), list->off, list->cap, 1, 0, 0); \ idx = list->off ++; \ } \ list->buffer[idx] = e; \ if(list->size == 0){ \ list->head = list->tail = idx; \ } else { \ list->links[list->tail] = idx; \ } \ list->links[idx] = 0; \ list->tail = idx; \ list->size ++; \ } \ \ static inline int pop_##list_type(list_type *list, e_type*e){ \ if(list->size == 0) return 0; \ *e = list->buffer[list->head]; \ list->trash_cap = encap_list((void**)&list->trash, sizeof(size_type), list->trash_size, list->trash_cap, 1, 0, 0); \ list->trash[list->trash_size ++] = list->head; \ list->head = list->links[list->head]; \ list->size --; \ return 1; \ } \ \ static inline void free_##list_type(list_type *list){ \ if(list->buffer) free(list->buffer); \ if(list->links) free(list->links); \ if(list->trash) free(list->trash); \ free(list); \ } #define define_queue(name, e_type) define_queue_core(name, e_type, size_t, 0xFFFFFU) define_queue(u32fifo, uint32_t); define_queue(s32fifo, int32_t); define_queue(u64fifo, uint64_t); define_queue(s64fifo, int64_t); #endif wtdbg2-2.5/scripts/000077500000000000000000000000001353664372200142535ustar00rootroot00000000000000wtdbg2-2.5/scripts/best_kbm_hit.pl000077500000000000000000000004411353664372200172440ustar00rootroot00000000000000#!/usr/bin/perl -w # # Author: Jue Ruan # use strict; my $rs = [""]; while(<>){ my @ts = split; if($ts[0] eq $rs->[0]){ $rs = \@ts if($ts[10] > $rs->[10]); } else { print join("\t", @{$rs}), "\n" if($rs->[10]); $rs = \@ts; } } print join("\t", @{$rs}), "\n" if($rs->[10]); 1; wtdbg2-2.5/scripts/best_minimap_hit.pl000077500000000000000000000004761353664372200201350ustar00rootroot00000000000000#!/usr/bin/perl -w # #Author: Jue Ruan # use strict; my $rs = [""]; while(<>){ my @ts = split; if($ts[0] ne $rs->[0]){ if(length $rs->[0]){ print join("\t", @{$rs}), "\n"; } $rs = \@ts; } else { if($ts[9] > $rs->[9]){ $rs = \@ts; } } } if(length $rs->[0]){ print join("\t", @{$rs}), "\n"; } 1; wtdbg2-2.5/scripts/best_sam_hits4longreads.pl000077500000000000000000000041761353664372200214320ustar00rootroot00000000000000#!/usr/bin/perl -w # # Author: Jue Ruan # use Getopt::Std; use strict; our ($opt_h, $opt_l, $opt_f); getopts("hl:f:"); &usage if($opt_h); my $map_len = $opt_l || 100; my $map_cov = $opt_f || 0.75; my %refs = (); my %cigar_hash = (M=>[1,1], I=>[1,0], D=>[0,1], N=>[0,1], S=>[1,0], H=>[1,0], P=>[0,0], '='=>[1,1], X=>[1,1]); my @hits = (); while(<>){ if(/^@/){ print; if(/^\@SQ\sSN:(\S+)\sLN:(\d+)/){ $refs{$1} = $2; } next; } my $str = $_; my @ts = split; my $tag = $ts[0]; my $flg = $ts[1]; my $ref = $ts[2]; next if($ref eq '*'); my $rlen = $refs{$ref}; if(not defined $rlen){ print; die("Cannot find '$ref' in SAM Header"); } my $tb = $ts[3]; my $te = $tb; my $qb = 0; my $qe = 0; my $len = 0; my $tmp = 0; my $cnt = 0; my $cgr = $ts[5]; while($cgr=~/(\d+)(\D)/g){ my $mov = $cigar_hash{$2}; if($mov->[1]){ $te += $1; $qe += $tmp; $tmp = 0; if($cnt == 0){ $qb = $qe; $cnt = 1; } if($mov->[0]){ $qe += $1; $len += $1; } } elsif($mov->[0]){ $tmp += $1; $len += $1; } } if($flg & 0x10){ $tmp = $len - $qb; $qb = $len - $qe; $qe = $tmp; } next unless($qe - $qb >= $map_len and $te - $tb >= $map_len); next unless($qe - $qb >= $map_cov * $len or $te - $tb >= $map_cov * $rlen); my $hit = [$tag, $len, $qb, $qe, $ref, $rlen, $tb, $te, $str]; &select_best_hit($hit); } &select_best_hit(undef); 1; sub usage { print STDERR qq{Usage: $0 [-l 100:map_len] [-f 0.75:map_cov] \n}; exit 1; } sub select_best_hit { my $hit = shift; if(@hits == 0){ push(@hits, $hit) if($hit); } elsif(not defined $hit or $hit->[0] ne $hits[-1][0]){ @hits = sort {$b->[3] - $b->[2] <=> $a->[3] - $a->[2]} @hits; for(my $i=0;$i<@hits;$i++){ my $pass = 1; for(my $j=0;$j<$i;$j++){ my $x = $hits[$i][2] < $hits[$j][2]? $hits[$j][2] : $hits[$i][2]; my $y = $hits[$i][3] > $hits[$j][3]? $hits[$j][3] : $hits[$i][3]; if($y - $x >= (1 - $map_cov) * ($hits[$i][3] - $hits[$i][2])){ $pass = 0; last; } } print $hits[$i][8] if($pass); } @hits = (); push(@hits, $hit) if($hit); } else { push(@hits, $hit); } } wtdbg2-2.5/scripts/dbm_index_dot.pl000077500000000000000000000026051353664372200174150ustar00rootroot00000000000000#!/usr/bin/perl -w # #Author: Ruan Jue # use strict; use DB_File; my $dot_file = shift or die("Usage: $0 \n"); die("$dot_file.dbm already exists!!!") if(-e "$dot_file.dbm"); open(IN, "<", $dot_file) or die; my %hash; tie %hash, 'DB_File', "$dot_file.dbm", O_RDWR | O_CREAT, 0644, $DB_HASH or die "Cannot open $dot_file.dbm: $!"; my %nodes = (); my %link = (); while(){ s/^\s+//; s/\s+$//; if(/^rankdir\s*=\s*(\S+)/){ $hash{"rankdir"} = $1; next; } my $desc = ''; while(1){ if(/\s*(\[[^]]+\]);?$/){ $_ = substr($_, 0, length($_) - length($1)); $desc .= $1; s/\s+$//; } else { last; } } my @ts = split; if(@ts == 1 and length $desc){ $nodes{$ts[0]} = $desc; } elsif(@ts >= 3 and ($ts[1] eq '->' or $ts[1] eq '-')){ my ($lnk1, $lnk2) = ("", ""); if($ts[0]=~/^(\S+?):(\S+)$/){ $ts[0] = $1; $lnk1 = $2; } if($ts[2]=~/^(\S+?):(\S+)$/){ $ts[2] = $1; $lnk2 = $2; } push(@{$link{$ts[0]}{$ts[2]}}, [$desc, $lnk1, $lnk2]); $link{$ts[2]}{$ts[0]} = [] unless(defined $link{$ts[2]}{$ts[0]}); } } close IN; foreach my $n1 (keys %nodes){ $hash{$n1} = $nodes{$n1}; } foreach my $n1 (keys %link){ my $hx = $link{$n1}; my $str = (defined $hash{$n1})? $hash{$n1} : ""; foreach my $n2 (keys %{$hx}){ my $ls = $hx->{$n2}; $str .= "\nN\t$n2"; foreach my $lk (@{$ls}){ $str .= "\n" . join("\t", "L", @{$lk}); } } $hash{$n1} = $str; } untie %hash; 1; wtdbg2-2.5/scripts/dbm_index_fa.pl000077500000000000000000000012501353664372200172100ustar00rootroot00000000000000#!/usr/bin/perl -w # #Author: Ruan Jue # use strict; use DB_File; my $fasta_file = shift or die("Usage: $0 \n"); die("$fasta_file.dbm already exists!!!") if(-e "$fasta_file.dbm"); open(IN, "<", $fasta_file) or die; my %seqs; tie %seqs, 'DB_File', "$fasta_file.dbm", O_RDWR | O_CREAT, 0644, $DB_HASH or die "Cannot open $fasta_file.dbm: $!"; my $name = ''; #my $seq = ''; my $off = 0; my $len = 0; while(){ if(/^>(\S+)/){ #$seqs{$name} = $seq if($name); $seqs{$name} = $off; $name = $1; $off += $len; $len = 0; #$seq = ''; #} else { #chomp; #$seq .= $_; } $len += length($_); } $seqs{$name} = $off if($name); untie %seqs; close IN; 1; wtdbg2-2.5/scripts/dbm_read_dot.pl000077500000000000000000000023161353664372200172200ustar00rootroot00000000000000#!/usr/bin/perl -w # #Author: Ruan Jue # use strict; use Getopt::Std; use DB_File; our ($opt_l, $opt_h); getopts("l:h"); my $level = $opt_l || 0; &usage if($opt_h); my $dbf = shift or &usage; if($dbf!~/\.dbm$/){ $dbf .= ".dbm" if(-e "$dbf.dbm"); } my @nodes = @ARGV; if(@nodes == 0){ while(<>){ chomp; push(@nodes, $_); } } my %hash; tie %hash, 'DB_File', $dbf, O_RDONLY or die "Cannot open $dbf: $!"; my %levels = map {$_=>0} @nodes; print "digraph {\n"; print "rank=$hash{rank}\n" if(exists $hash{"rank"}); print "node $hash{node}\n" if(exists $hash{"node"}); print "edge $hash{edge}\n" if(exists $hash{"edge"}); while(@nodes){ my $nd = shift @nodes; my $str = $hash{$nd}; my @rs = split /\n/, $str; print "$nd $rs[0]"; if($levels{$nd} == 0){ print " [style=filled fillcolor=yellow]\n" } else { print "\n"; } my $n2 = ''; for(my $i=1;$i<@rs;$i++){ if($rs[$i]=~/^N\s(\S+)/){ $n2 = $1; if($levels{$nd} < $level and not exists $levels{$n2}){ $levels{$n2} = $levels{$nd} + 1; push(@nodes, $n2); } } elsif($rs[$i]=~/^L\s(.+)$/){ print " $nd -> $n2 $1\n" } } } print "}\n"; untie %hash; 1; sub usage { die("Usage: $0 [-l TRACE_LEVEL:0] ...\n"); } wtdbg2-2.5/scripts/dbm_read_fa.pl000077500000000000000000000046241353664372200170240ustar00rootroot00000000000000#!/usr/bin/perl -w # #Author: Ruan Jue # use strict; use DB_File; my $dbf = shift or die("Usage: $0 [read_name1 ...]\n"); my $faf = undef; if($dbf!~/\.dbm$/){ $dbf .= ".dbm" if(-e "$dbf.dbm"); } my @names = @ARGV; my $list_all = 0; if(@names == 1 and $names[0] eq '#LIST'){ $list_all = 1; @names = (); } elsif(@names == 0){ while(<>){ chomp; push(@names, $_); } } my @tags = (); foreach my $tag (@names){ if($tag=~/^(.+?)(\[([+-])(:(-?\d+),(-?\d+))?\])$/){ push(@tags, [$1, $3 eq '+'? 1:2, (defined $5)? $5:1, (defined $6)? $6:-1, 1]); } elsif($tag=~/^(.+?)_([FR])(_(\d+)(_(\d+))?)?$/){ push(@tags, [$1, $2 eq 'F'? 1:2, (defined $4)? $4:1, (defined $6)? $4 + $6 - 1 : 0, 1]); } else { push(@tags, [$tag, 1, 1, -1, 0]); } } foreach my $tag (@tags){ $tag->[2] = 1 if($tag->[2] < 1); } my %seqs; tie %seqs, 'DB_File', $dbf, O_RDONLY or die "Cannot open $dbf: $!"; if($dbf=~/^(.+?)\.dbm$/){ $faf = $1; } my $fa_file = undef; foreach my $tag (@tags){ if(exists $seqs{$tag->[0]}){ #my $seq = $seqs{$tag->[0]}; my $seq = &read_fasta($tag->[0], $tag->[4]); if($tag->[4]){ $tag->[3] = length($seq) if($tag->[3] <= $tag->[2]); if($tag->[4]){ print ">", join("_", $tag->[0], $tag->[1] == 1? "F":"R", $tag->[2], $tag->[3] + 1 - $tag->[2]), "\n"; } else { print ">$tag->[0]\n"; } if($tag->[2] < $tag->[3]){ my $ss = substr($seq, $tag->[2] - 1, $tag->[3] - $tag->[2] + 1); if($tag->[1] == 2){ $ss =~tr/ACGTacgt/TGCAtgca/; $ss = reverse $ss; } while($ss=~/(.{1,100})/g){ print "$1\n"; } } } else { print $seq; } } else { warn("'$tag->[0]' was not found\n"); } } if($list_all){ &list_all_seqs; } untie %seqs; if($fa_file){ close $fa_file; } 1; sub read_fasta { my $tag = shift; my $tidy = shift || 0; my $obj = $seqs{$tag}; if($obj!~/^[0-9]/){ return $obj; } my $off = $obj; if(not defined $fa_file){ if(not defined $faf){ die("Cannot find fasta file"); } else { open($fa_file, "<", $faf) or die $!; } } seek($fa_file, $off, 0); my $nam = ''; my $seq = ''; while(<$fa_file>){ if(/^>(\S+)/){ last if(length $nam); $nam = $1; if(!$tidy){ $seq .= $_; } } else { if($tidy){ chomp; } $seq .= $_; } } if($nam ne $tag){ die("Broken dbm index, \"$nam\" ne \"$tag\", offset = $off"); } return $seq; } sub list_all_seqs { while(my ($tag, $seq) = each %seqs){ print "$tag\t$seq\n"; } } wtdbg2-2.5/scripts/fa2fq.pl000077500000000000000000000006271353664372200156170ustar00rootroot00000000000000#!/usr/bin/perl -w # # # use strict; my $Q = '!'; my $tag = ''; my $seq = ''; while(<>){ if(/^>(.+?)$/){ if(length $seq){ print "\@$tag\n"; print "$seq\n"; print "+\n"; print $Q x length($seq); print "\n"; } $tag = $1; $seq = ''; } else { chomp; $seq .= $_; } } if(length $seq){ print "\@$tag\n"; print "$seq\n"; print "+\n"; print $Q x length($seq); print "\n"; } 1; wtdbg2-2.5/scripts/fa2tab.pl000077500000000000000000000003561353664372200157560ustar00rootroot00000000000000#!/usr/bin/perl -w # use strict; my $name; my $seq = ''; while(<>){ if(/>(\S+)/){ print "$name\t$seq\n" if(defined $name); $name = $1; $seq = ''; } else { chomp; $seq .= $_; } } print "$name\t$seq\n" if(defined $name); 1; wtdbg2-2.5/scripts/first_n_bases.pl000077500000000000000000000003161353664372200174340ustar00rootroot00000000000000#!/usr/bin/perl -w # use strict; my $n = shift or die("Usage: $0 [fasta_file]\n"); my $m = 0; while(<>){ if(/^>/){ last if($m >= $n); } else { $m += length($_) - 1; } print; } 1; wtdbg2-2.5/scripts/first_n_seqs.pl000077500000000000000000000002641353664372200173140ustar00rootroot00000000000000#!/usr/bin/perl -w # use strict; my $n = shift or die("Usage: $0 [fasta_file]\n"); my $m = 0; while(<>){ if(/^>/){ last if($m == $n); $m ++; } print; } 1; wtdbg2-2.5/scripts/fq2fa.pl000077500000000000000000000002201353664372200156040ustar00rootroot00000000000000#!/usr/bin/perl -w my $count=0; while(<>){ if($count%4==0){ print ">", substr($_, 1); } elsif($count%4==1){ print $_; } $count++; } 1; wtdbg2-2.5/scripts/hlcolor000077500000000000000000000021201353664372200156360ustar00rootroot00000000000000#!/usr/bin/env perl # # Author: Jue Ruan # use strict; my $color = 35; my %fg_color_map = (black=>30, red=>31, green=>32, yellow=>33, blue=>34, magenta=>35, cyan=>36); my @pats = (); foreach my $pat (@ARGV){ if($pat=~/^(\S+)=(\S+?)$/){ if(exists $fg_color_map{$2}){ $color = $fg_color_map{$2}; push(@pats, [$1, $color]); } else { print STDERR "[hlcolor] unknown color \"$2\"\n"; push(@pats, [$1, $color]); } } else { push(@pats, [$pat, $color]); } } $| = 1; while(){ foreach my $pat (@pats){ s/($pat->[0])/\e[1;$pat->[1]m\1\e[0m/g; } print; } 1; =pod function highlight() { declare -A fg_color_map fg_color_map[black]=30 fg_color_map[red]=31 fg_color_map[green]=32 fg_color_map[yellow]=33 fg_color_map[blue]=34 fg_color_map[magenta]=35 fg_color_map[cyan]=36 fg_c=$(echo -e "\e[1;${fg_color_map[$2]}m") c_rs=$'\e[0m' sed -u "s/$1/$fg_c\0$c_rs/g" } if [ -z $1 ]; then echo "Usage: $0 " exit fi PAT=$1 COLOR=$2 if [ -z $COLOR ]; then COLOR=magenta fi highlight $PAT $COLOR =cut wtdbg2-2.5/scripts/longest_pacbio_subreads.pl000077500000000000000000000013471353664372200215000ustar00rootroot00000000000000#!/usr/bin/perl -w # # Author: Jue Ruan # use strict; my $tag = ''; my @seqs = (['', '']); while(<>){ chomp; if(/^>(\S+)/){ my $name = $1; my $comm = substr($_, length($name) + 1); my $subr = ''; if($name=~/^(.+?)(\/\d+_\d+)$/){ $name = $1; $subr = $2; } if($name eq $tag){ push(@seqs, [$subr, '', $comm]); } else { &print_longest_seq; $tag = $name; @seqs = ([$subr, '', $comm]); } } else { $seqs[-1][1] .= $_; } } &print_longest_seq; 1; sub print_longest_seq { my $idx = 0; my $max = 0; for(my $i=0;$i<@seqs;$i++){ if(length($seqs[$i][1]) > $max){ $idx = $i; $max = length($seqs[$i][1]); } } return unless($max); print ">$tag$seqs[$idx][0]$seqs[$idx][2] len=$max\n$seqs[$idx][1]\n"; } wtdbg2-2.5/scripts/mmpoa.pl000077500000000000000000000017731353664372200157340ustar00rootroot00000000000000#!/usr/bin/env perl # # Author: Jue Ruan # use Getopt::Std; use strict; our ($opt_h, $opt_t, $opt_s, $opt_m, $opt_x, $opt_p); getopts("ht:s:m:x:p:"); &usage if($opt_h); &usage(1) if(@ARGV < 2); my $ref = shift || &usage(1); my $rst = $ref; $rst=~s/\.fa$//; $rst=~s/\.fasta$//; my $ncpu = 4; $ncpu = $opt_t if(defined $opt_t); my $MM = $opt_m || "minimap2"; my $MX = $opt_x || "pb"; my $ST = $opt_s || "samtools"; my $WP = $opt_p || "wtpoa-cns"; my $cmd = ''; $cmd = "$MM -t $ncpu -x map-$MX -a $ref @ARGV | $ST view -Sb - > $rst.bam"; &run($cmd); $cmd = "$ST sort $rst.bam $rst.srt"; &run($cmd); $cmd = "$ST view $rst.srt.bam | $WP -t $ncpu -d $ref -i - -fo $rst.mmpoa.fa"; &run($cmd); 1; sub usage { my $ret = shift || 0; print qq{Usage: $0 [-t n_cpu:4] [-s samtools] [-m minimap2] [-p wtpoa-cns] [-x pb|ont] [reads2.fa ...]\n}; exit $ret; } sub run { my $cmd = shift; system("date"); print "# $cmd\n"; if(system($cmd)){ die("$cmd"); } system("date"); } wtdbg2-2.5/scripts/mum_assess.sh000077500000000000000000000006701353664372200167740ustar00rootroot00000000000000#!/bin/bash # # Author: Jue Ruan # REF=$1 CTG=$2 # change this path to your mummer MUM=/public/software/mummer-323-intel if [ -z $REF ] || [ -z $CTG ]; then echo "Usage: $0 " exit fi echo "REF:$REF" echo "CTG:$REF" $MUM/nucmer --mumreference -l 100 -c 1000 -d 10 --banded -D 5 $REF $CTG $MUM/delta-filter -i 95 -o 95 out.delta > out.best.delta $MUM/dnadiff -d out.best.delta $MUM/mummerplot out.best.delta --fat -f -png wtdbg2-2.5/scripts/num_n50.pl000077500000000000000000000007711353664372200161010ustar00rootroot00000000000000#!/usr/bin/perl -w # # Author: Ruan Jue # use strict; my $total = 0; my @nums = (); my $len = 0; while(<>){ next unless(/(\d+)/); push(@nums, $1),$total+=$1 if($1); } print "Total: $total\n"; my @nxxs = (); for(my $i=0;$i<=10;$i++){ push(@nxxs, int($total*$i*0.1)); } push(@nxxs, $total + 1); my $i = 0; my $j = 0; @nums = sort {$b <=> $a} @nums; $len = 0; for(;$i<@nums;$i++){ $len += $nums[$i]; while($nxxs[$j] <= $len){ print "N".$j."0: $nums[$i]\t" . ($i + 1) . "\n"; $j ++; } } 1; wtdbg2-2.5/scripts/rename_fa.pl000077500000000000000000000020001353664372200165200ustar00rootroot00000000000000#!/usr/bin/perl -w # # Author: Ruan Jue # use strict; use Getopt::Std; my $prefix = $ENV{'PARAM_RENAME_FA_PREFIX'} || 'S'; my $suffix = $ENV{'PARAM_RENAME_FA_SUFFIX'} || ''; our ($opt_p, $opt_s, $opt_h, $opt_f, $opt_b, $opt_I); getopts("hp:s:f:b:I"); die("Usage: $0 [-p name_prefix] [-s name_suffix] [-f trans_file] [-b begin_idx] [-I:include orignial_name] \n") if($opt_h); $prefix = $opt_p if(defined $opt_p); $suffix = $opt_s if(defined $opt_s); my %hash; if(defined $opt_f){ open(IN, "<", $opt_f) or die; %hash = (); while(){ my @ts = split; $hash{$ts[0]} = $ts[1]; #print STDERR "$ts[0]\t$ts[1]\n"; } close IN; } my $idx = $opt_b || 0; while(<>){ if(/^>(\S+)/){ my $desc = substr($_, length($1) + 1); my $ori = $opt_I? " $1" : ""; if(%hash){ if(exists $hash{$1}){ my $tag = $hash{$1}; print ">$tag$ori$desc", substr($_, length($1) + 1); } else { print; } } else { printf(">$prefix%010d$suffix$ori$desc", $idx); } $idx ++; } else { print; } } 1; wtdbg2-2.5/scripts/rename_fq.pl000077500000000000000000000016451353664372200165560ustar00rootroot00000000000000#!/usr/bin/perl -w # # Author: Ruan Jue # use strict; use Getopt::Std; my $prefix = $ENV{'PARAM_RENAME_FA_PREFIX'} || 'S'; my $suffix = $ENV{'PARAM_RENAME_FA_SUFFIX'} || ''; our ($opt_p, $opt_s, $opt_h, $opt_f); getopts("hp:s:f:"); die("Usage: $0 [-p name_prefix] [-s name_suffix] [-f trans_file] \n") if($opt_h); $prefix = $opt_p if(defined $opt_p); $suffix = $opt_s if(defined $opt_s); my %hash; if(defined $opt_f){ open(IN, "<", $opt_f) or die; %hash = (); while(){ my @ts = split; $hash{$ts[0]} = $ts[1]; print STDERR "$ts[0]\t$ts[1]\n"; } close IN; } my $idx = 0; my $line = 0; while(<>){ if(($line % 4) == 0 and /^@(\S+)/){ my $comm = substr($_, length($1) + 1); $idx ++; if(%hash){ if(exists $hash{$1}){ my $tag = $hash{$1}; print "\@$tag", $comm; } else { print; } } else { printf("\@$prefix%012d$suffix$comm", $idx); } } else { print; } $line ++; } 1; wtdbg2-2.5/scripts/rev_seq.pl000077500000000000000000000005631353664372200162630ustar00rootroot00000000000000#!/usr/bin/perl -w # #AUthor: Ruan Jue # use strict; my $seq = shift; if($seq){ rev_seq($seq); } else { $seq = ''; while(<>){ if(/^>/){ &rev_seq($seq); print; next; $seq = ''; } chomp; $seq .= $_; } &rev_seq($seq); } 1; sub rev_seq { my $s = shift; $s =~tr/ACGTacgt/TGCAtgca/; $s = reverse $s; while($s=~/(.{1,100})/g){ print "$1\n"; } } wtdbg2-2.5/scripts/runit.pl000077500000000000000000000111711353664372200157550ustar00rootroot00000000000000#!/usr/bin/perl -w # # Author: Jue Ruan # use strict; use warnings; use POSIX; use POSIX ":sys_wait_h"; use Time::HiRes; my $USER = $ENV{USER}; if(not defined $USER){ $USER = `whoami`; chomp $USER; } my $RUNITALL = $ENV{RUNIT_ALL} || 0; my $cmd = join(" ", @ARGV); $cmd=~s/^\s+//; $cmd=~s/\s+$//; &usage unless($cmd); my $pagesize = POSIX::sysconf(POSIX::_SC_PAGESIZE); my $sleep_inv = 1000000; # in mircoseconds my $maxram = 0; # kb my $maxcpu = 0; my $retval = 0; my $utime = 0; my $stime = 0; my $rtime = 0; my $maxrss = 0; my $maxvsz = 0; my %exclusive = (); if($RUNITALL){ for my $proc (&get_all_process()){ $exclusive{$proc->[0]} = 1; } } my %procs = (); &get_linux_sys_info(); print STDERR " --------------------------------------------------------------------------------\n"; print STDERR " -- runit.pl is a program launcher and minitor written by Jue Ruan \n"; print STDERR " -- RAM : $maxram kB\n"; print STDERR " -- CPU : $maxcpu cores\n"; print STDERR " -- SYS : ", `uname -a`; print STDERR " -- USER: $USER\n"; print STDERR " -- DATE: ", `date`; print STDERR " -- PWD : ", `pwd`; print STDERR " -- CMD : $cmd\n"; print STDERR " --------------------------------------------------------------------------------\n"; my $PID = open(READ, "$cmd |") or die("Cannot invoke commands: $!"); my $begtime = Time::HiRes::time; if(fork() == 0){ while(){ print; } exit; } while(1){ my $mrss = 0; my $mvsz = 0; foreach my $proc (&get_all_process()){ my ($pid, $cm, $ppid) = @{$proc}; next if($exclusive{$pid}); my ($fail, $ut, $st, $rss, $vsz) = &get_linux_proc_info($pid); next if($fail); if(exists $procs{$pid}){ $procs{$pid}[0] = $ut; $procs{$pid}[1] = $st; } else { print STDERR " -- RUNIT PID($pid): $ppid\t$cm\n"; $procs{$pid} = [$ut, $st, $cm, $ppid]; } $mrss += $rss; $mvsz += $vsz; } #print STDERR "$mrss\t$mvsz\n"; $maxrss = $mrss if($mrss > $maxrss); $maxvsz = $mvsz if($mvsz > $maxvsz); my $res = waitpid($PID, WNOHANG); if($res == -1){ print STDERR " ** Error ", ($? >> 8), "\n"; last; } elsif($res){ $retval = $? >> 8; last; } else { Time::HiRes::usleep($sleep_inv); } } my $endtime = Time::HiRes::time; $rtime = $endtime - $begtime; foreach my $pid (sort {$a <=> $b} keys %procs){ next if($exclusive{$pid}); print STDERR " -- STAT PID($pid): $procs{$pid}[3]\t$procs{$pid}[0]\t$procs{$pid}[1]\t$procs{$pid}[2]\n"; $utime += $procs{$pid}[0]; $stime += $procs{$pid}[1]; } print STDERR " --------------------------------------------------------------------------------\n"; printf STDERR " -- retval %16d\n", $retval; printf STDERR " -- real %16.3f\n", $rtime; printf STDERR " -- user %16.3f\n", $utime; printf STDERR " -- sys %16.3f\n", $stime; printf STDERR " -- maxrss %16.3f kB\n", $maxrss; printf STDERR " -- maxvsz %16.3f kB\n", $maxvsz; print STDERR " --------------------------------------------------------------------------------\n"; 1; sub usage { print qq{Launch program and minitor the cputime and ram usage of it and its childs\n}; print qq{Usage: $0 \$'commands'\n}; exit 1; } sub get_linux_sys_info { open(IN, "/proc/meminfo") or die; while(){ my @ts = split; if($ts[0]=~/^MemTotal/){ $maxram = $ts[1]; last; } } close IN; open(IN, "/proc/cpuinfo") or die; $maxcpu = 0; while(){ if(/^processor/){ $maxcpu ++; } } close IN; } sub get_all_process { my %ps = (); my @pids = (); if(my $psid = open(IN, "ps -o ppid,pid,cmd --no-headers --user $USER 2>/dev/null |")){ while(){ chomp; my @ts = split /\s+/, $_, 3; next if($ts[1] == $psid); if($RUNITALL){ push(@pids, [$ts[1], $ts[2], $ts[0]]); } else { $ps{$ts[1]}[0] = $ts[2]; $ps{$ts[1]}[1] = $ts[0]; $ps{$ts[1]}[2] = [] if(not defined $ps{$ts[1]}[2]); push(@{$ps{$ts[0]}[2]}, $ts[1]); } } close IN; } if($RUNITALL){ } else { my @stack = ($PID); while(@stack){ my $pid = pop @stack; next unless(exists $ps{$pid}); my $p = $ps{$pid}; push(@pids, [$pid, $p->[0], $p->[1]]); push(@stack, @{$p->[2]}); } } return @pids; } sub get_linux_proc_info { my $pid = shift; my ($fail, $ut, $st, $rss, $vsz); if(open(IN, "/proc/$pid/stat")){ if($_ = ){ my @ts = split /\s/, $_; #print STDERR join("|", @ts), "\n"; #for(my $i=0;$i<@ts;$i++){ # print STDERR ($i+1), "\t", $ts[$i], "\n"; #} $ut = $ts[13] / 100; $st = $ts[14] / 100; $vsz = $ts[22] / 1024; $rss = $ts[23] * $pagesize / 1024; $fail = 0; } else { $fail = 1; } close IN; } else { $fail = 1; } if($fail){ print STDERR " ** FAIL STAT($pid)\n"; } return ($fail, $ut, $st, $rss, $vsz); } wtdbg2-2.5/scripts/sam2dbgcns.pl000077500000000000000000000054671353664372200166520ustar00rootroot00000000000000#!/usr/bin/perl -w # # Author: Jue Ruan # use strict; use Getopt::Std; our ($opt_h, $opt_w, $opt_s, $opt_d, $opt_q, $opt_t); getopts("hw:s:dq:t"); &usage if($opt_h); $opt_w = 2000 unless($opt_w); $opt_s = 1000 unless($opt_s); $opt_d = 0 unless($opt_d); $opt_q = 0 unless($opt_q); $opt_t = 0 unless($opt_t); &usage if($opt_w <= $opt_s); my $ctgf = shift or &usage; my %refs = (); my $ctag = ""; my $cdes = ""; my $cseq = ""; open(IN, "<", $ctgf) or die; while(){ chomp; if(/^>(\S+)/){ $refs{$ctag} = [$cseq, $cdes] if(length $cseq); $ctag = $1; $cdes = substr($_, 1 + length($1)); $cseq = ''; } else { $cseq .= $_; } } $refs{$ctag} = [$cseq, $cdes] if(length $cseq); close IN; $ctag = ""; my $coff = 0; my $wlen = $opt_w; my $slen = $opt_s; my @rseqs = (); my $ref = undef; my $rsize = 0; my $nid = 0; my $line = 0; while(<>){ $line ++; next if(/^@/); my @ts= split; next if($ts[2] eq '*'); next if($opt_q and $ts[4] < $opt_q); my $rtag = $ts[0]; my $rdir = (($ts[1] >> 4) & 0x01)? "-" : "+"; my $gtag = $ts[2]; my $gpos = $ts[3]; my $rseq = $ts[9]; if($opt_t){ my $l = 0; my $r = 0; if($ts[5]=~/^((\d+)S)/){ $l = $2; } if($ts[5]=~/((\d+)S)$/){ $r = $2; } $rseq = substr($rseq, $l, length($rseq) - $r - $l) if($l or $r); } if($gtag ne $ctag){ while(length $ctag and $coff < $rsize){ &print_frag; } $ctag = $gtag; #print STDERR "$ctag begin at SAM line $line\n"; $ref = $refs{$ctag}; $rsize = length $ref->[0]; $coff = 0; @rseqs = (); &print_header; } else { while($coff + $wlen < $gpos){ &print_frag; } } my $dup = 0; if($opt_d){ for(my $i=@rseqs-1;$i>=0;$i--){ last if($rseqs[$i][0] != $gpos); if($rseqs[$i][3] eq $rseq){ $dup = 1; last; } } } push(@rseqs, [$gpos, $rtag, $rdir, $rseq]) unless($dup); } while(length $ctag and $coff < $rsize){ &print_frag; } 1; sub print_header { return unless(length $ctag and exists $refs{$ctag}); print ">$ctag$refs{$ctag}->[1]\n"; } sub print_frag { my $cend = $coff + $wlen; my $cnxt = $coff + $slen; $cend = $rsize if($cend > $rsize); $cnxt = $rsize if($cnxt > $rsize); print "E\t$coff\tN$nid\t+\t"; $nid ++; print "N$nid\t+\n"; $nid ++; print "S\t$ctag\_F_$coff\_", ($cend - $coff), "\t+\t$coff\t", ($cend - $coff),"\t", substr($ref->[0], $coff, $cend - $coff), "\n"; my @nseqs = (); foreach my $r (@rseqs){ next if($r->[0] + length($r->[3]) < $coff); if($r->[0] < $cend){ print "S\t$r->[1]\t$r->[2]\t0\t", length($r->[3]), "\t$r->[3]\n"; if($r->[0] >= $cnxt){ push(@nseqs, $r); } } } @rseqs = @nseqs; $coff = $cnxt; } sub usage { die(qq{Usage: $0 [options] [srt_sam_file] Option: -w window size, [2000] -s silding size, [1000] -d remove duplication -q filter by mapQ, [0] -t trim tailing clip }); } wtdbg2-2.5/scripts/seq_n50.pl000077500000000000000000000016441353664372200160720ustar00rootroot00000000000000#!/usr/bin/perl -w # # Author: Ruan Jue # use strict; use Getopt::Std; our ($opt_h, $opt_s); getopts("hs"); my $total = 0; my @nums = (); my $len = 0; while(<>){ if(/^>(\S+)/){ if($opt_s){ print "\t$len\n" if($len); print $1; } push(@nums, $len),$total+=$len if($len); $len = 0; } else { $len += length($_) - 1; } } print "\t$len\n" if($opt_s and $len); push(@nums, $len),$total+=$len if($len); my $n_seq = @nums; my $avg = sprintf("%0.2f", $total / $n_seq); print "Total: $total\n"; print "Count: $n_seq\n"; print "Average: $avg\n"; my @nxxs = (); for(my $i=0;$i<=10;$i++){ push(@nxxs, int($total*$i*0.1)); } push(@nxxs, $total + 1); my $i = 0; my $j = 0; @nums = sort {$b <=> $a} @nums; my $median = $nums[int($n_seq / 2)]; print "Median: $median\n"; $len = 0; for(;$i<@nums;$i++){ $len += $nums[$i]; while($nxxs[$j] <= $len){ print "N".$j."0: $nums[$i]\t". ($i + 1) . "\n"; $j ++; } } 1; wtdbg2-2.5/scripts/split_seqs_2.pl000077500000000000000000000012121353664372200172160ustar00rootroot00000000000000#!/usr/bin/perl -w # # use strict; my $cnt = shift or die("Usage: $0 [gzip:0]\n"); my $inf = shift or die("Usage: $0 [gzip:0]\n"); my $zip = shift || 0; $zip = 0 unless($zip eq '1' or $zip eq 'y'); my $ouf = $inf; if($ouf eq '-'){ $ouf = 'unnamed'; } else { unshift @ARGV, $inf; } my @fhs = (); for(my $i=1;$i<=$cnt;$i++){ my $fh; if($zip){ open($fh, "| gzip -c >$ouf.shuffle$i.gz") or die; } else { open($fh, ">", "$ouf.shuffle$i") or die; } push(@fhs, $fh); } my $n = -1; while(<>){ $n ++ if(/^>/); my $fh = $fhs[$n % $cnt]; print $fh $_; } foreach my $fh (@fhs) { close $fh; } 1; wtdbg2-2.5/scripts/split_seqs_3.pl000077500000000000000000000005261353664372200172260ustar00rootroot00000000000000#!/usr/bin/perl -w # # use strict; my $cnt = shift or die("Usage: $0 \n"); my $idx = shift or die("Usage: $0 \n"); $idx --; my $ns = 0; my $print = 0; while(<>){ if(/^>/){ if($ns % $cnt == $idx){ $print = 1; } else { $print = 0; } $ns ++; } print if($print); } 1; wtdbg2-2.5/scripts/wtdbg-dot2gfa.pl000077500000000000000000000017651353664372200172570ustar00rootroot00000000000000#!/usr/bin/perl -w # # Author: Jue Ruan # use strict; =pod Transform .[1/2/3/frg/ctg].dot into GFA format. .[1/2/3/frg/ctg].dot is the assembly graph from wtdbg TAG: gl: gap length rc: read count to support the link sq: sequence can be substr from ___, F fwd, R rev, off is based on the fwd strand =cut while(<>){ chomp; next unless(/^([NF]\d+)\s(->\s([NF]\d+)\s)?\[([^\]]+)\]$/); my $n1 = $1; my $n2 = $3; my $label = $4; if(defined $n2){ if($label=~/label=\"(\S)(\S):(\d+):(\-?\d+)\"/){ if($4 >= 0){ print "L\t$n1\t$1\t$n2\t$2\t0S\tgl:i:$4\trc:i:$3\n"; } else { print "L\t$n1\t$1\t$n2\t$2\t". (0 - $4) . "M\trc:i:$3\n"; } } else { die("Bad format: $_"); } } else { if($label=~/\{N\d+\s(\d+)\s\|\s(\S+)\s\|\s([FR])_(\d+)_(\d+)\}/){ print "S\t$n1\t*\tLN:i:$5\tsq:Z:$2_$3_$4_$5\n" } elsif($label=~/\{F\d+\s(\d+)\s(\d+)\/(\d+)\s\|/){ print "S\t$n1\t*\tLN:i:$2\n"; } else { die("Bad format: $_"); } } } 1; wtdbg2-2.5/sort.h000066400000000000000000000351071353664372200137320ustar00rootroot00000000000000/* * * Copyright (c) 2011, Jue Ruan * * * 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 3 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, see . */ #ifndef __SORT_RJ_H #define __SORT_RJ_H #include #include #define cmp_2nums_proc(a, b) if((a) < (b)) return -1; else if((a) > (b)) return 1; #define num_cmp_script(e1, e2, obj, val_macro) ((val_macro(e1, obj) == val_macro(e2, obj))? 0 : ((val_macro(e1, obj) < val_macro(e2, obj))? -1 : 1)) #define cmpgt_2nums_proc(a, b) if((a) < (b)) return 0; else if((a) > (b)) return 1; #define define_bubble_sort(name, e_type, is_greater_func) \ static inline void name(e_type* list, size_t size, void *ref){ \ size_t i, j, n; \ e_type t; \ i = 0; \ while(i < size){ \ n = 0; \ for(j=size-1;j>i;j--){ \ if(is_greater_func(list[j-1], list[j], ref) > 0){ \ t = list[j-1]; list[j-1] = list[j]; list[j] = t; \ n = 1; \ } \ } \ if(n == 0) break; \ i ++; \ } \ if(ref == ref) return; \ } #define bubble_sort_array(rs, size, e_type, is_a_greater_than_b) \ do { \ size_t bubble_i, bubble_j, bubble_n, bubble_size; \ e_type a, b; \ bubble_size = size; \ for(bubble_i=0;bubble_ibubble_i;bubble_j--){ \ a = (rs)[bubble_j - 1]; \ b = (rs)[bubble_j]; \ if((int)(is_a_greater_than_b) > 0){ \ (rs)[bubble_j] = a; (rs)[bubble_j - 1] = b; \ bubble_n = 1; \ } \ } \ if(bubble_n == 0) break; \ } \ } while(0) #define divide_array(rs_ary, rs_size, e_type, is_a_greater_than_b, ret_val) \ do { \ e_type *_rs; \ _rs = (e_type*)(rs_ary); \ size_t s, e, i, j, m; \ e_type p, t, a, b; \ if((rs_size) < 2){ (ret_val) = 0; break; } \ { \ s = 0; \ e = (rs_size) - 1; \ m = s + (e - s) / 2; \ a = _rs[s]; b = _rs[m]; \ if(is_a_greater_than_b){ t = _rs[s]; _rs[s] = _rs[m]; _rs[m] = t; } \ a = _rs[m]; b = _rs[e]; \ if(is_a_greater_than_b){ \ t = _rs[e]; _rs[e] = _rs[m]; _rs[m] = t; \ a = _rs[s]; b = _rs[m]; \ if(is_a_greater_than_b){ t = _rs[s]; _rs[s] = _rs[m]; _rs[m] = t; } \ } \ p = _rs[m]; \ i = s + 1; j = e - 1; \ while(1){ \ a = p; \ while(b = _rs[i], (is_a_greater_than_b)) i ++; \ b = p; \ while(a = _rs[j], (is_a_greater_than_b)) j --; \ if(i < j){ \ t = _rs[i]; _rs[i] = _rs[j]; _rs[j] = t; \ i ++; j --; \ } else break; \ } \ if(i == j){ i ++; j --; } \ (ret_val) = i; \ } \ } while(0) #define sort_array(rs_ary, rs_size, e_type, is_a_greater_than_b) \ do { \ e_type *_rs; \ _rs = (e_type*)(rs_ary); \ size_t _qsort_n; \ _qsort_n = rs_size; \ size_t s, e, i, j, m, stack[64][2], x; \ e_type p, t, a, b; \ if(_qsort_n < 2) break; \ x = 0; \ stack[x][0] = 0; stack[x][1] = _qsort_n - 1; x ++; \ while(x){ \ x --; s = stack[x][0]; e = stack[x][1]; \ m = s + (e - s) / 2; \ a = _rs[s]; b = _rs[m]; \ if(is_a_greater_than_b){ t = _rs[s]; _rs[s] = _rs[m]; _rs[m] = t; } \ a = _rs[m]; b = _rs[e]; \ if(is_a_greater_than_b){ \ t = _rs[e]; _rs[e] = _rs[m]; _rs[m] = t; \ a = _rs[s]; b = _rs[m]; \ if(is_a_greater_than_b){ t = _rs[s]; _rs[s] = _rs[m]; _rs[m] = t; } \ } \ p = _rs[m]; \ i = s + 1; j = e - 1; \ while(1){ \ a = p; \ while(b = _rs[i], (is_a_greater_than_b)) i ++; \ b = p; \ while(a = _rs[j], (is_a_greater_than_b)) j --; \ if(i < j){ \ t = _rs[i]; _rs[i] = _rs[j]; _rs[j] = t; \ i ++; j --; \ } else break; \ } \ if(i == j){ i ++; j --; } \ if(j - s > e - i){ \ if(s + 4 < j){ stack[x][0] = s; stack[x][1] = j; x ++; } \ if(i + 4 < e){ stack[x][0] = i; stack[x][1] = e; x ++; } \ } else { \ if(i + 4 < e){ stack[x][0] = i; stack[x][1] = e; x ++; } \ if(s + 4 < j){ stack[x][0] = s; stack[x][1] = j; x ++; } \ } \ } \ for(i=0;i<_qsort_n;i++){ \ x = 0; \ for(j=_qsort_n-1;j>i;j--){ \ a = _rs[j - 1]; b = _rs[j]; \ if(is_a_greater_than_b){ t = _rs[j - 1]; _rs[j - 1] = _rs[j]; _rs[j] = t; x = 1; } \ } \ if(x == 0) break; \ } \ } while(0) #define sort_array_adv(rs_size, is_a_greater_than_b, swap_expr) \ do { \ size_t _qsort_n; \ _qsort_n = rs_size; \ size_t s, e, i, j, m, stack[64][2], x, a, b; \ if(_qsort_n < 2) break; \ x = 0; \ stack[x][0] = 0; stack[x][1] = _qsort_n - 1; x ++; \ while(x){ \ x --; s = stack[x][0]; e = stack[x][1]; \ m = s + (e - s) / 2; \ a = s; b = m; \ if(is_a_greater_than_b){ swap_expr; } \ a = m; b = e; \ if(is_a_greater_than_b){ \ swap_expr; \ a = s; b = m; \ if(is_a_greater_than_b){ swap_expr; } \ } \ i = s + 1; j = e - 1; \ while(1){ \ a = m; \ while(b = i, (is_a_greater_than_b)) i ++; \ b = m; \ while(a = j, (is_a_greater_than_b)) j --; \ if(i < j){ \ if(m == i) m = j; \ else if(m == j) m = i; \ a = i; b = j; \ swap_expr; \ i ++; j --; \ } else break; \ } \ if(i == j){ i ++; j --; } \ if(s + 4 < j){ stack[x][0] = s; stack[x][1] = j; x ++; } \ if(i + 4 < e){ stack[x][0] = i; stack[x][1] = e; x ++; } \ } \ for(i=0;i<_qsort_n;i++){ \ x = 0; \ for(j=_qsort_n-1;j>i;j--){ \ a = j - 1; b = j; \ if(is_a_greater_than_b){ swap_expr; x = 1; } \ } \ if(x == 0) break; \ } \ } while(0) // Must #include "thread.h" and "list.h" #define psort_array(rs_ary, rs_size, e_type, ncpu, is_a_greater_than_b) \ do { \ thread_beg_def(psrt); \ e_type *rs; \ size_t beg, end, div; \ int divide; \ thread_end_def(psrt); \ thread_beg_func_inline(psrt); \ thread_beg_loop(psrt); \ if(psrt->divide){ \ divide_array(psrt->rs + psrt->beg, psrt->end - psrt->beg, e_type, is_a_greater_than_b, psrt->div); \ psrt->div += psrt->beg; \ } else { \ sort_array(psrt->rs + psrt->beg, psrt->end - psrt->beg, e_type, is_a_greater_than_b); \ } \ thread_end_loop(psrt); \ thread_end_func(psrt); \ thread_preprocess(psrt); \ e_type *_rs; \ _rs = (e_type*)(rs_ary); \ size_t _qsort_n, _min_blk_size; \ _qsort_n = rs_size; \ _min_blk_size = _qsort_n / ncpu / 8; \ if(_min_blk_size < 1024) _min_blk_size = 1024; \ if(_qsort_n < ((uint32_t)(ncpu)) * 32){ \ sort_array(rs_ary, rs_size, e_type, is_a_greater_than_b); \ break; \ } \ thread_beg_init(psrt, (int)(ncpu)); \ psrt->rs = _rs; psrt->beg = psrt->end = psrt->div = 0; psrt->divide = 0; \ thread_end_init(psrt); \ u64list *stacks[2]; \ int x; \ stacks[0] = init_u64list(32); \ stacks[1] = init_u64list(32); \ push_u64list(stacks[0], 0); \ push_u64list(stacks[1], _qsort_n); \ x = 0; \ while(stacks[0]->size || x > 0){ \ thread_waitfor_one_idle(psrt); \ if(psrt->divide){ \ if(psrt->div - psrt->beg <= psrt->end - psrt->div){ \ push_u64list(stacks[0], psrt->beg); \ push_u64list(stacks[1], psrt->div); \ push_u64list(stacks[0], psrt->div); \ push_u64list(stacks[1], psrt->end); \ } else { \ push_u64list(stacks[0], psrt->div); \ push_u64list(stacks[1], psrt->end); \ push_u64list(stacks[0], psrt->beg); \ push_u64list(stacks[1], psrt->div); \ } \ x --; \ psrt->divide = 0; \ } else if(stacks[0]->size){ \ psrt->beg = stacks[0]->buffer[--stacks[0]->size]; \ psrt->end = stacks[1]->buffer[--stacks[1]->size]; \ psrt->divide = (psrt->end - psrt->beg > _min_blk_size); \ if(psrt->divide) x ++; \ thread_wake(psrt); \ } \ } \ thread_waitfor_all_idle(psrt); \ thread_beg_close(psrt); \ thread_end_close(psrt); \ free_u64list(stacks[0]); \ free_u64list(stacks[1]); \ } while(0) #define quick_median_array(_rs, _rs_size, e_type, expr) \ ({ \ e_type key; \ do { \ e_type *rs; \ rs = (e_type*)(_rs); \ size_t size; \ size = (size_t)(_rs_size); \ size_t i, j, beg, mid, end; \ if(size == 0){ \ memset(&key, 0, sizeof(e_type)); \ break; \ } \ beg = 0; \ end = size - 1; \ e_type tmp, a, b; \ while(beg < end){ \ mid = beg + (end - beg) / 2; \ a = rs[beg]; b = rs[mid]; \ if(expr){ tmp = rs[beg]; rs[beg] = rs[mid]; rs[mid] = tmp; } \ a = rs[mid]; b = rs[end]; \ if(expr){ \ tmp = rs[end]; rs[end] = rs[mid]; rs[mid] = tmp; \ a = rs[beg]; b = rs[mid]; \ if(expr){ tmp = rs[beg]; rs[beg] = rs[mid]; rs[mid] = tmp; } \ } \ key = rs[mid]; \ i = beg + 1; j = end - 1; \ while(1){ \ a = key; \ while(b = rs[i], (expr)) i ++; \ b = key; \ while(a = rs[j], (expr)) j --; \ if(i < j){ \ tmp = rs[i]; rs[i] = rs[j]; rs[j] = tmp; \ i ++; j --; \ } else break; \ } \ if(i == j){ i ++; j --; } \ if(i <= size / 2) beg = i; \ else end = j; \ } \ key = rs[size/2]; \ } while(0); \ key; \ }) #define apply_array(rs, rs_size, e_type, expression) \ do { \ size_t _i, _rs_size; \ e_type a; \ _rs_size = rs_size; \ for(_i=0;_i<_rs_size;_i++){ \ a = (rs)[_i]; \ expression; \ } \ } while(0) #define ref_apply_array(rs, rs_size, e_type, expression) \ do { \ size_t _i, _rs_size; \ e_type *a; \ _rs_size = rs_size; \ for(_i=0;_i<_rs_size;_i++){ \ a = (rs) + _i; \ (expression); \ } \ } while(0) #define locate_array(rs, rs_size, e_type, expr) \ ({ \ size_t _i, _size; \ e_type a; \ _size = rs_size; \ for(_i=0;_i<_size;_i++){ \ a = rs[_i]; \ if(expr) break; \ }; \ _i; \ }) // sort the array according to bool value (true then flase), and return the size of trues #define apply_xchg_array(rs, rs_size, e_type, expr) \ ({ \ size_t _i, _j, _size; \ e_type a; \ _size = rs_size; \ for(_i=_j=0;_i<_size;_i++){ \ a = (rs)[_i]; \ if(!(expr)) continue; \ if(_j < _i){ \ a = (rs)[_j]; \ (rs)[_j] = (rs)[_i]; \ (rs)[_i] = a; \ } \ _j ++; \ } \ _j; \ }) #define define_quick_sort(name, e_type, is_greater_func) \ static inline void name(e_type *rs, size_t n, void *obj){ \ size_t s, e, i, j, m, stack[64][2], x; \ e_type p, t; \ if(n < 2) return; \ x = 0; \ stack[x][0] = 0; stack[x][1] = n - 1; x ++; \ while(x){ \ x --; s = stack[x][0]; e = stack[x][1]; \ m = s + (e - s) / 2; \ if(is_greater_func(rs[s], rs[m], obj) > 0){ t = rs[s]; rs[s] = rs[m]; rs[m] = t; } \ if(is_greater_func(rs[m], rs[e], obj) > 0){ \ t = rs[e]; rs[e] = rs[m]; rs[m] = t; \ if(is_greater_func(rs[s], rs[m], obj) > 0){ t = rs[s]; rs[s] = rs[m]; rs[m] = t; } \ } \ p = rs[m]; \ i = s + 1; j = e - 1; \ while(1){ \ while(is_greater_func(p, rs[i], obj) > 0) i ++; \ while(is_greater_func(rs[j], p, obj) > 0) j --; \ if(i < j){ \ t = rs[i]; rs[i] = rs[j]; rs[j] = t; \ i ++; j --; \ } else break; \ } \ if(i == j){ i ++; j --; } \ if(j - s > e - i){ \ if(s + 4 < j){ stack[x][0] = s; stack[x][1] = j; x ++; } \ if(i + 4 < e){ stack[x][0] = i; stack[x][1] = e; x ++; } \ } else { \ if(i + 4 < e){ stack[x][0] = i; stack[x][1] = e; x ++; } \ if(s + 4 < j){ stack[x][0] = s; stack[x][1] = j; x ++; } \ } \ } \ for(i=0;ii;j--){ \ if(is_greater_func(rs[j - 1], rs[j], obj) > 0){ t = rs[j - 1]; rs[j - 1] = rs[j]; rs[j] = t; x = 1; } \ } \ if(x == 0) break; \ } \ if(obj == obj) return; \ } #define define_merge(name, e_type, cmp_func, output_func) \ static inline void name(e_type *list1, size_t size1, e_type *list2, size_t size2, void *ref){ \ size_t i, j; \ i = j = 0; \ while(i < size1 && j < size2){ \ if(cmp_func(list1[i], list2[j], ref) <= 0){ \ output_func(list1[i], ref); \ i ++; \ } else { \ output_func(list2[j], ref); \ j ++; \ } \ } \ while(i < size1){ output_func(list1[i++], ref); } \ while(j < size2){ output_func(list2[j++], ref); } \ } \ \ static inline size_t name##_files(FILE **files, int n, void *ref){ \ e_type *es; \ int *flags, i, min; \ size_t ret; \ ret = 0; \ es = malloc(sizeof(e_type) * n); \ flags = malloc(sizeof(int) * n); \ for(i=0;i>1;i++){ \ e = __rs[i]; __rs[i] = __rs[n-1-i]; __rs[n-1-i] = e; \ } \ } while(0) #define define_reverse_array(name, e_type) \ static inline void name(e_type *list, size_t size){ \ size_t i, j; \ e_type t; \ if(size == 0) return; \ i = 0; \ j = size - 1; \ while(i < j){ \ t = list[i]; list[i] = list[j]; list[j] = t; \ i ++; j --; \ } \ } #define define_apply_array(name, e_type, apply_func) \ static inline size_t name(e_type *list, size_t size, void *ref){ \ size_t i, ret; \ ret = 0; \ for(i=0;i * * * 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 3 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, see . */ #ifndef __THEAD_RJ_H #define __THEAD_RJ_H #include #include #include #define lock_cmpxchg(location, value, comparand) \ ({ \ __typeof (*location) _result; \ if(sizeof(*location) == 1){ \ __asm__ __volatile__ ( \ "lock\n\t" \ "cmpxchgb %b2,(%1)" \ :"=a" (_result) \ :"r" (location), "r" (value), "a" (comparand) \ :"memory", "cc"); \ } else if(sizeof(*location) == 2){ \ __asm__ __volatile__ ( \ "lock\n\t" \ "cmpxchgw %w2,(%1)" \ :"=a" (_result) \ :"r" (location), "r" (value), "a" (comparand) \ :"memory", "cc"); \ } else if(sizeof(*location) == 4){ \ __asm__ __volatile__ ( \ "lock\n\t" \ "cmpxchgl %w2,(%1)" \ :"=a" (_result) \ :"r" (location), "r" (value), "a" (comparand) \ :"memory", "cc"); \ } else { \ __asm__ __volatile__ ( \ "lock\n\t" \ "cmpxchgq %2,(%1)" \ :"=a" (_result) \ :"r" (location), "r" (value), "a" (comparand) \ :"memory", "cc"); \ } \ _result; \ }) #define thread_typeof(tname) (struct tname##_struct) #define thread_begin_def(tname) \ struct tname##_struct { \ struct tname##_struct *tname##_params; \ struct tname##_struct *tname##_array; \ int n_cpu; \ int t_idx; \ volatile int running; \ volatile int state; \ volatile int once; \ pthread_mutex_t *mutex_lock; \ pthread_rwlock_t *rw_lock; \ pthread_mutex_t _COND_LOCK; \ pthread_cond_t _COND #define thread_end_def(tname) } #define thread_def_shared_vars(tname) \ struct tname##_struct *tname##_params; \ pthread_t *tname##_pids; \ pthread_mutex_t *tname##_mlock; \ pthread_rwlock_t *tname##_rwlock; \ struct tname##_struct *tname; \ int tname##_i; \ int tname##_j; \ int tname##_var_next #define thread_beg_def(tname) thread_begin_def(tname) #define thread_begin_func_core(tname) inline void* thread_##tname##_func(void *obj){\ struct tname##_struct * tname = (struct tname##_struct *)obj;\ int tname##_var_i;\ struct tname##_struct * tname##_params; \ tname##_params = tname->tname##_params; \ if(tname##_params + tname->t_idx != tname){ \ fprintf(stderr, " -- Unexcepted error in thread [%s] in %s -- %s:%d --\n", #tname, __FUNCTION__, __FILE__, __LINE__); \ } #define thread_begin_func(tname) static thread_begin_func_core(tname) #define thread_beg_func(tname) thread_begin_func(tname) #define thread_beg_func_inline(tname) inline void* thread_##tname##_func(void *obj){\ struct tname##_struct * tname = (struct tname##_struct *)obj;\ int tname##_var_i;\ struct tname##_struct * tname##_params; \ tname##_params = tname->tname##_params; \ if(tname##_params + tname->t_idx != tname){ \ fprintf(stderr, " -- Unexcepted error in thread [%s] in %s -- %s:%d --\n", #tname, __FUNCTION__, __FILE__, __LINE__); \ } #define thread_begin_loop(tname) \ pthread_mutex_lock(&tname->_COND_LOCK); \ tname->state = 0; \ pthread_cond_signal(&tname->_COND); \ pthread_mutex_unlock(&tname->_COND_LOCK); \ while(tname->running){ \ if(tname->state != 1){ \ struct timespec _timeout; \ pthread_mutex_lock(&tname->_COND_LOCK); \ clock_gettime(CLOCK_REALTIME, &_timeout); \ _timeout.tv_nsec += 1000000; \ pthread_cond_timedwait(&tname->_COND, &tname->_COND_LOCK, &_timeout); \ pthread_mutex_unlock(&tname->_COND_LOCK); \ continue; \ } \ for(tname##_var_i=0;tname##_var_i<1;tname##_var_i++){ #define thread_beg_loop(tname) thread_begin_loop(tname) #define thread_begin_syn(tname) pthread_mutex_lock(tname->mutex_lock) #define thread_beg_syn(tname) thread_begin_syn(tname) #define thread_end_syn(tname) pthread_mutex_unlock(tname->mutex_lock) #define thread_beg_syn_read(tname) pthread_rwlock_rdlock(tname->rw_lock) #define thread_end_syn_read(tname) pthread_rwlock_unlock(tname->rw_lock) #define thread_beg_syn_write(tname) pthread_rwlock_wrlock(tname->rw_lock) #define thread_end_syn_write(tname) pthread_rwlock_unlock(tname->rw_lock) #define thread_end_loop(tname) \ } \ if(tname->once){ \ pthread_mutex_lock(&tname->_COND_LOCK); \ tname->state = 2; \ pthread_cond_signal(&tname->_COND); \ pthread_mutex_unlock(&tname->_COND_LOCK); \ } \ } \ pthread_mutex_lock(&tname->_COND_LOCK); \ tname->state = 2; \ pthread_cond_signal(&tname->_COND); \ pthread_mutex_unlock(&tname->_COND_LOCK) #define thread_end_func(tname) return NULL; } #define thread_preprocess(tname) \ thread_def_shared_vars(tname); \ (void)(tname##_params); \ (void)(tname##_pids); \ (void)(tname##_mlock); \ (void)(tname##_rwlock); \ (void)(tname); \ tname##_i = 0; \ tname##_j = 0; \ tname##_var_next = 0 #define thread_prepare(tname) thread_preprocess(tname) #define thread_begin_init(tname, n_thread) assert(n_thread > 0);\ tname##_params = (struct tname##_struct *)malloc(sizeof(struct tname##_struct) * n_thread);\ tname##_pids = (pthread_t *)malloc(sizeof(pthread_t) * n_thread); \ tname##_mlock = calloc(1, sizeof(pthread_mutex_t)); \ *tname##_mlock = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER; \ tname##_rwlock = calloc(1, sizeof(pthread_rwlock_t)); \ *tname##_rwlock = (pthread_rwlock_t)PTHREAD_RWLOCK_INITIALIZER; \ for(tname##_i=0,tname##_j=0;tname##_i<(int)(n_thread);tname##_i++){ \ tname = tname##_params + tname##_i;\ tname->mutex_lock = tname##_mlock;\ tname->rw_lock = tname##_rwlock;\ tname->_COND_LOCK = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER; \ tname->_COND = (pthread_cond_t)PTHREAD_COND_INITIALIZER; \ tname->n_cpu = n_thread;\ tname->t_idx = tname##_i;\ tname->running = 1;\ tname->state = 3;\ tname->once = 1;\ tname->tname##_params = (struct tname##_struct*)tname##_params;\ tname->tname##_array = (struct tname##_struct*)tname##_params #define thread_beg_init(tname, n_thread) thread_begin_init(tname, n_thread) #define thread_end_init(tname) \ if(pthread_create(tname##_pids + tname##_i, NULL, thread_##tname##_func, (void*)tname) != 0){\ fprintf(stderr, " -- Failed to create thread [%s, %04d] in %s -- %s:%d --\n", #tname, tname##_i, __FUNCTION__, __FILE__, __LINE__);\ exit(1);\ }\ while(1){ \ int _stop; \ _stop = 0; \ if(tname->state == 0) _stop = 1; \ else { \ struct timespec _timeout; \ pthread_mutex_lock(&tname->_COND_LOCK); \ clock_gettime(CLOCK_REALTIME, &_timeout); \ _timeout.tv_nsec += 1000000; \ pthread_cond_timedwait(&tname->_COND, &tname->_COND_LOCK, &_timeout); \ if(tname->state == 0) _stop = 1; \ pthread_mutex_unlock(&tname->_COND_LOCK); \ } \ if(_stop) break; \ } \ }\ tname = tname##_params + 0; \ tname##_var_next = 0; \ tname##_i = 0; \ tname##_j = 0 #define thread_export_core(tname, _tname, params, pids, mlock, rwlock, i, j, next) \ do { \ _tname = tname; \ params = tname##_params; \ pids = tname##_pids; \ mlock = tname##_mlock; \ rwlock = tname##_rwlock; \ i = tname##_i; \ j = tname##_j; \ next = tname##_var_next; \ } while(0) #define thread_export(tname, obj) thread_export_core(tname, (obj)->tname, (obj)->tname##_params, (obj)->tname##_pids, (obj)->tname##_mlock, (obj)->tname##_rwlock, (obj)->tname##_i, (obj)->tname##_j, (obj)->tname##_var_next) #define thread_import_core(tname, _tname, params, pids, mlock, rwlock, i, j, next) \ do { \ tname = _tname; \ tname##_params = params; \ tname##_pids = pids; \ tname##_mlock = mlock; \ tname##_rwlock = rwlock; \ tname##_i = i; \ tname##_j = j; \ tname##_var_next = next; \ } while(0) #define thread_import(tname, obj) thread_import_core(tname, (obj)->tname, (obj)->tname##_params, (obj)->tname##_pids, (obj)->tname##_mlock, (obj)->tname##_rwlock, (obj)->tname##_i, (obj)->tname##_j, (obj)->tname##_var_next) #define thread_begin_operate(tname, idx) tname = tname##_params + idx #define thread_beg_operate(tname, idx) thread_begin_operate(tname, idx) #define thread_wake(tname) do { pthread_mutex_lock(&tname->_COND_LOCK); tname->state = 1; pthread_cond_signal(&tname->_COND); pthread_mutex_unlock(&tname->_COND_LOCK); } while(0) #define thread_wake_all(tname) do { thread_beg_iter(tname); thread_wake(tname); thread_end_iter(tname); } while(0); #define thread_waitfor_idle(tname) \ while(1){ \ int _stop; \ _stop = 0; \ pthread_mutex_lock(&tname->_COND_LOCK); \ if(tname->state != 1) _stop = 1; \ else { \ struct timespec _timeout; \ clock_gettime(CLOCK_REALTIME, &_timeout); \ _timeout.tv_nsec += 1000; \ pthread_cond_timedwait(&tname->_COND, &tname->_COND_LOCK, &_timeout); \ if(tname->state != 1) _stop = 1; \ } \ pthread_mutex_unlock(&tname->_COND_LOCK); \ if(_stop) break; \ } \ tname->state = 0 #define thread_wait(tname) thread_waitfor_idle(tname) #define thread_wait_next(tname) do { thread_beg_operate(tname, tname##_var_next); thread_wait(tname); tname##_var_next = (tname##_var_next + 1) % tname##_params[0].n_cpu; } while(0) #define thread_end_operate(tname, idx) tname = NULL #define thread_begin_iter(tname) { struct tname##_struct * tname = NULL; int tname##_i; for(tname##_i=0;tname##_istate != 1) #define thread_n_cpus(tname) (tname->n_cpu) #define thread_index(tname) (tname->t_idx) #define thread_end_iter(tname) } } #define thread_access(tname, idx) (tname##_params + idx) #define thread_beg_monitor(tname, usec) \ while(1){ \ nano_sleep(usec) #define thread_end_monitor(tname) \ for(tname##_j=0;tname##_j= tname##_params[0].n_cpu){ \ tname##_j = 0; \ nano_sleep(10); \ } else { \ tname##_j = (tname##_j + 1) % tname##_params[0].n_cpu; \ break; \ } \ } \ tname->state = 0 #define thread_wait_one(tname) thread_waitfor_one_idle(tname) #define thread_wait_done(tname) \ while(1){ \ int _nrun_; \ _nrun_ = 0; \ for(tname##_j=0;tname##_j= tname##_params[0].n_cpu){ \ tname##_j = 0; \ if(_nrun_ == 0){ \ tname = tname##_params + tname##_j; \ tname##_j = (tname##_j + 1) % tname##_params[0].n_cpu; \ break; \ } else { \ nano_sleep(10); \ } \ } else { \ tname##_j = (tname##_j + 1) % tname##_params[0].n_cpu; \ break; \ } \ } \ tname->state = 0 #define thread_test_all(tname, expr) ({int ret = 1; thread_beg_iter(tname); if(!(expr)){ ret = 0; break;} thread_end_iter(tname); ret;}) #define thread_count_all(tname, expr) ({int ret = 0; thread_beg_iter(tname); if((expr)){ ret ++; } thread_end_iter(tname); ret;}) #define thread_all_idle(tname) thread_test_all(tname, (tname)->state != 1) #define thread_waitfor_all_idle(tname) { thread_begin_iter(tname); thread_waitfor_idle(tname); thread_end_iter(tname); } #define thread_wait_all(tname) thread_waitfor_all_idle(tname) #define thread_apply_all(tname, expr) { thread_begin_iter(tname); (expr); thread_wake(tname); thread_end_iter(tname); thread_waitfor_all_idle(tname); } #define thread_begin_close(tname) for(tname##_i=0;tname##_i_COND_LOCK); \ tname->running = 0; \ pthread_cond_signal(&tname->_COND); \ pthread_mutex_unlock(&tname->_COND_LOCK); \ thread_wait(tname);\ pthread_join(tname##_pids[tname##_i], NULL) #define thread_beg_close(tname) thread_begin_close(tname) #define thread_end_close(tname) } free((void*)tname##_params); free(tname##_pids); free(tname##_mlock); free(tname##_rwlock) #define thread_run(tname, ncpu, vars_expr, init_expr, free_expr, pre_expr, loop_expr, post_expr, invoke_expr) \ { \ thread_beg_def(tname); \ vars_expr \ thread_end_def(tname); \ thread_begin_func_core(tname); \ pre_expr \ thread_beg_loop(tname); \ loop_expr \ thread_end_loop(tname); \ post_expr \ thread_end_func(tname); \ { \ thread_preprocess(tname); \ thread_beg_init(tname, ncpu); \ init_expr \ thread_end_init(tname); \ invoke_expr \ thread_beg_close(tname); \ free_expr \ thread_end_close(tname); \ } \ } #define THREAD_EXPR(...) __VA_ARGS__ #define thread_fast_run(tname, ncpu, loop_expr) thread_run(tname, ncpu, , , , THREAD_EXPR(int NCPU; int TIDX; NCPU = tname->n_cpu; TIDX = tname->t_idx;), THREAD_EXPR(loop_expr;), , THREAD_EXPR(thread_wake_all(tname); thread_wait_all(tname);)) #define thread_fast_run2(tname, ncpu, expr) \ { \ thread_beg_def(tname); \ thread_end_def(tname); \ thread_begin_func_core(tname); \ int NCPU, TIDX; \ NCPU = tname->n_cpu; \ TIDX = tname->t_idx; \ UNUSED(NCPU); \ UNUSED(TIDX); \ thread_beg_loop(tname); \ (expr); \ thread_end_loop(tname); \ thread_end_func(tname); \ { \ thread_preprocess(tname); \ thread_beg_init(tname, ncpu); \ thread_end_init(tname); \ thread_wake_all(tname); \ thread_wait_all(tname); \ thread_beg_close(tname); \ thread_end_close(tname); \ } \ } #endif wtdbg2-2.5/tripoa.h000066400000000000000000000377351353664372200142520ustar00rootroot00000000000000/* * * Copyright (c) 2018, Jue Ruan * * * 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 3 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, see . */ #ifndef TRI_PO_MSA_CNS_RJ_H #define TRI_PO_MSA_CNS_RJ_H #include "poacns.h" #include "ksw.h" typedef struct { SeqBank *seqs; u2v *rbegs, *rends; u4i longest_idx, seqmax; int8_t matrix[16]; int fail_skip; u1i ksize; // 11 float kdup; // 0.1 float keqs; // 0.2 uuhash *khash; u1v *qry, *ref; u2i winlen, winmin; u2v *regs[2]; POG *pogs[3]; u4v *kidxs; f4v *kords; BaseBank *cns; int is_tripog, refmode; int shuffle; // 0: no shuffling, 1: by kmer, 2, random } TriPOG; //static inline TriPOG* init_tripog(u4i seqmax, int refmode, int winlen, int winmin, int fail_skip, int M, int X, int I, int D, int W, int use_sse, int rW, u4i min_cnt, float min_freq){ static inline TriPOG* init_tripog(u4i seqmax, int shuffle, int winlen, int winmin, int fail_skip, POGPar *par){ TriPOG *tp; u4i i; tp = malloc(sizeof(TriPOG)); tp->seqs = init_seqbank(); tp->rbegs = init_u2v(32); tp->rends = init_u2v(32); tp->seqmax = seqmax; tp->longest_idx = 0; tp->ksize = 11; tp->kdup = 0.1; tp->keqs = 0.2; tp->khash = init_uuhash(13); tp->ref = init_u1v(winlen); tp->qry = init_u1v(1024); tp->regs[0] = init_u2v(32); tp->regs[1] = init_u2v(32); tp->refmode = par->refmode; tp->fail_skip = fail_skip; tp->winlen = winlen; tp->winmin = winmin; tp->pogs[0] = init_pog(*par); #if 0 if(winlen > 0){ tp->winlen = winlen; tp->winmin = winmin; tp->pogs[0] = init_pog(refmode, M, X, I, D, 0, 0, use_sse, 0, min_cnt, min_freq); } else { tp->winlen = 0; tp->winmin = 0; tp->pogs[0] = init_pog(refmode, M, X, I, D, W, - winlen, use_sse, rW, min_cnt, min_freq); } #endif tp->pogs[1] = init_pog(*par); tp->pogs[1]->par->W_score = 0; tp->pogs[2] = init_pog(*par); tp->pogs[2]->par->W_score = 0; //tp->pogs[1] = init_pog(refmode, M, X, I, D, W, 0, use_sse, rW, min_cnt, min_freq); //tp->pogs[2] = init_pog(refmode, M, X, I, D, W, 0, use_sse, rW, min_cnt, min_freq); //tp->pogs[1]->near_dialog = 1; //tp->pogs[2]->near_dialog = 1; tp->kidxs = init_u4v(32); tp->kords = init_f4v(32); tp->cns = init_basebank(); for(i=0;i<16;i++){ tp->matrix[i] = ((i / 4) == (i % 4))? par->M : par->X; } tp->is_tripog = 0; tp->shuffle = shuffle; return tp; } static inline void free_tripog(TriPOG *tp){ free_seqbank(tp->seqs); free_u2v(tp->rbegs); free_u2v(tp->rends); free_uuhash(tp->khash); free_u1v(tp->qry); free_u1v(tp->ref); free_u2v(tp->regs[0]); free_u2v(tp->regs[1]); free_pog(tp->pogs[0]); free_pog(tp->pogs[1]); free_pog(tp->pogs[2]); free_u4v(tp->kidxs); free_f4v(tp->kords); free_basebank(tp->cns); free(tp); } static inline void beg_tripog(TriPOG *tp){ clear_seqbank(tp->seqs); clear_u2v(tp->rbegs); clear_u2v(tp->rends); tp->longest_idx = 0; tp->is_tripog = 0; } static inline void push_tripog(TriPOG *tp, char *seq, u4i len, u2i refbeg, u2i refend){ if(!tp->shuffle && tp->seqs->nseq >= tp->seqmax) return; push_seqbank(tp->seqs, NULL, 0, seq, len); push_u2v(tp->rbegs, refbeg); push_u2v(tp->rends, refend); if(tp->seqs->rdlens->buffer[tp->longest_idx] < len){ tp->longest_idx = tp->seqs->nseq - 1; } } static inline void fwdbitpush_tripog(TriPOG *tp, u8i *bits, u8i off, u4i len, u2i refbeg, u2i refend){ if(!tp->shuffle && tp->seqs->nseq >= tp->seqmax) return; fwdbitpush_seqbank(tp->seqs, NULL, 0, bits, off, len); push_u2v(tp->rbegs, refbeg); push_u2v(tp->rends, refend); if(tp->seqs->rdlens->buffer[tp->longest_idx] < len){ tp->longest_idx = tp->seqs->nseq - 1; } } static inline void revbitpush_tripog(TriPOG *tp, u8i *bits, u8i off, u4i len, u2i refbeg, u2i refend){ if(!tp->shuffle && tp->seqs->nseq >= tp->seqmax) return; revbitpush_seqbank(tp->seqs, NULL, 0, bits, off, len); push_u2v(tp->rbegs, refbeg); push_u2v(tp->rends, refend); if(tp->seqs->rdlens->buffer[tp->longest_idx] < len){ tp->longest_idx = tp->seqs->nseq - 1; } } static inline void direct_run_tripog(TriPOG *tp){ POG *g; u4i ridx; clear_basebank(tp->cns); if(tp->refmode){ } else { tp->pogs[0]->par->W = tp->pogs[1]->par->W; tp->pogs[0]->par->rW = tp->pogs[1]->par->rW; tp->pogs[0]->par->W_score = tp->pogs[1]->par->W * tp->pogs[1]->par->M * 8; } g = tp->pogs[0]; beg_pog(g); for(ridx=0;ridxseqs->nseq;ridx++){ fwdbitpush_pog_core(g, tp->seqs->rdseqs->bits, tp->seqs->rdoffs->buffer[ridx], tp->seqs->rdlens->buffer[ridx], tp->rbegs->buffer[ridx], tp->rends->buffer[ridx]); } end_pog(g); if(g->cns->size == 0){ fast_fwdbits2basebank(tp->cns, tp->seqs->rdseqs->bits, tp->seqs->rdoffs->buffer[tp->longest_idx], tp->seqs->rdlens->buffer[tp->longest_idx]); } else { fast_fwdbits2basebank(tp->cns, g->cns->bits, 0, g->cns->size); } if(tp->refmode){ } else { tp->pogs[0]->par->W = 0; tp->pogs[0]->par->rW = 0; tp->pogs[0]->par->W_score = 0; } } static inline void shuffle_reads_by_kmers_tripog(TriPOG *tp){ SeqBank *sb; uuhash *khash; u4v *kidxs; f4v *kords; u2v *rbegs, *rends; uuhash_t *u; u8i roff; u4i ridx, i, ksize, kmer, kmask, rlen, khit, mincnt; double logv; int exists; sb = tp->seqs; if(sb->nseq == 0) return; khash = tp->khash; kidxs = tp->kidxs; kords = tp->kords; rbegs = tp->rbegs; rends = tp->rends; ksize = tp->ksize; clear_u4v(kidxs); clear_f4v(kords); clear_uuhash(khash); kmask = MAX_U4 >> ((16 - ksize) << 1); mincnt = tp->refmode? 1 : 2; for(ridx=0;ridxnseq;ridx++){ rlen = sb->rdlens->buffer[ridx]; kmer = 0; roff = sb->rdoffs->buffer[ridx]; for(i=0;irdseqs, roff + i)) & kmask; if(i + 1 < ksize) continue; u = prepare_uuhash(khash, kmer, &exists); if(exists){ if(((u->val >> 16) & 0x7FFFU) == ridx + 1){ u->val |= 1U << 31; } else { u->val = (u->val & 0x8000FFFFU) | ((ridx + 1) << 16); } u->val ++; } else { u->key = kmer; u->val = (0U << 31) | ((ridx + 1) << 16) | 1; } } if(tp->refmode) break; } logv = log(1.2); for(ridx=0;ridxnseq;ridx++){ rlen = sb->rdlens->buffer[ridx]; kmer = 0; roff = sb->rdoffs->buffer[ridx]; khit = 0; for(i=0;irdseqs, roff + i)) & kmask; if(i + 1 < ksize) continue; u = get_uuhash(khash, kmer); if(u && (u->val & 0x80000000U) == 0 && (u->val & 0xFFFFU) >= mincnt){ khit ++; } } if(tp->refmode){ if(ridx == 0){ push_f4v(kords, 3e+38F); } else { push_f4v(kords, ((double)khit) * logv / log(num_max(rlen, sb->rdlens->buffer[0]))); } } else { push_f4v(kords, ((double)khit) * logv / log(rlen)); } push_u4v(kidxs, ridx); } sort_array(kidxs->buffer, kidxs->size, u4i, num_cmpgt(kords->buffer[b], kords->buffer[a])); if(cns_debug > 1){ for(i=0;isize;i++){ fprintf(stderr, "SHUFFLE[%u] %u\t%u\t%0.4f\n", i, kidxs->buffer[i], sb->rdlens->buffer[kidxs->buffer[i]], kords->buffer[kidxs->buffer[i]]); } } for(i=0;isize;i++){ push_u8v(sb->rdoffs, sb->rdoffs->buffer[kidxs->buffer[i]]); push_u4v(sb->rdlens, sb->rdlens->buffer[kidxs->buffer[i]]); push_u2v(rbegs, rbegs->buffer[kidxs->buffer[i]]); push_u2v(rends, rends->buffer[kidxs->buffer[i]]); } remove_array_u8v(sb->rdoffs, 0, kidxs->size); remove_array_u4v(sb->rdlens, 0, kidxs->size); remove_array_u2v(rbegs, 0, kidxs->size); remove_array_u2v(rends, 0, kidxs->size); if(tp->seqmax && sb->nseq > tp->seqmax){ if(cns_debug > 1){ fprintf(stderr, "SEQMAX: %u -> %u\n", sb->nseq, tp->seqmax); } sb->nseq = tp->seqmax; sb->rdoffs->size = tp->seqmax; sb->rdlens->size = tp->seqmax; rbegs->size = tp->seqmax; rends->size = tp->seqmax; } } static inline void subsample_reads_tripog(TriPOG *tp){ SeqBank *sb; u4v *kidxs; u2v *rbegs, *rends; f4v *kords; u4i ridx, i; f4i cutoff; sb = tp->seqs; if(sb->nseq == 0 || sb->nseq <= tp->seqmax) return; kidxs = tp->kidxs; kords = tp->kords; rbegs = tp->rbegs; rends = tp->rends; clear_u4v(kidxs); clear_f4v(kords); if(tp->refmode){ push_u4v(kidxs, 0); push_f4v(kords, 200.0); ridx = 1; } else { ridx = 0; } for(;ridxnseq;ridx++){ push_u4v(kidxs, ridx); push_f4v(kords, 100.0 * drand48()); } sort_array(kidxs->buffer, kidxs->size, u4i, num_cmpgt(kords->buffer[b], kords->buffer[a])); cutoff = kords->buffer[kidxs->buffer[tp->seqmax - 1]]; clear_u4v(kidxs); for(i=0;isize;i++){ if(kords->buffer[i] >= cutoff){ push_u4v(kidxs, i); } } if(cns_debug > 1){ fprintf(stderr, "RANDOM CUTOFF = %f\n", cutoff); for(i=0;isize;i++){ fprintf(stderr, "SHUFFLE[%u] %u\t%0.4f\n", i, kidxs->buffer[i], kords->buffer[kidxs->buffer[i]]); } } for(i=0;isize;i++){ push_u8v(sb->rdoffs, sb->rdoffs->buffer[kidxs->buffer[i]]); push_u4v(sb->rdlens, sb->rdlens->buffer[kidxs->buffer[i]]); push_u2v(rbegs, rbegs->buffer[kidxs->buffer[i]]); push_u2v(rends, rends->buffer[kidxs->buffer[i]]); } remove_array_u8v(sb->rdoffs, 0, kords->size); remove_array_u4v(sb->rdlens, 0, kords->size); remove_array_u2v(rbegs, 0, kords->size); remove_array_u2v(rends, 0, kords->size); if(cns_debug > 1){ fprintf(stderr, "SEQMAX: %u -> %u\n", sb->nseq, tp->seqmax); } sb->nseq = tp->seqmax; } static inline void end_tripog(TriPOG *tp){ POG *g; kswr_t R; u4i ridx, rlen, b, e, failed; switch(tp->shuffle){ case 1: shuffle_reads_by_kmers_tripog(tp); break; case 2: subsample_reads_tripog(tp); break; } if(tp->winlen == 0){ return direct_run_tripog(tp); } tp->longest_idx = 0; for(ridx=1;ridxseqs->nseq;ridx++){ if(tp->seqs->rdlens->buffer[ridx] > tp->seqs->rdlens->buffer[tp->longest_idx]){ tp->longest_idx = ridx; } } if(tp->seqs->nseq < 2){ return direct_run_tripog(tp); } rlen = tp->seqs->rdlens->buffer[0]; if(rlen < 2 * tp->winlen){ return direct_run_tripog(tp); } clear_u2v(tp->regs[0]); clear_u2v(tp->regs[1]); // selecting unique window { uuhash_t *u; u4i i, j, hit, nb, kmer, kcnt, kdup, keqs, ktot, kmask, roff; reset_iter_uuhash(tp->khash); while((u = ref_iter_uuhash(tp->khash))){ u->val &= 0xFFFFU; } kmask = MAX_U4 >> ((16 - tp->ksize) << 1); for(ridx=0;ridx<1;ridx++){ rlen = tp->seqs->rdlens->buffer[ridx]; kmer = 0; roff = tp->seqs->rdoffs->buffer[ridx]; for(i=0;iseqs->rdseqs, roff + i)) & kmask; if(i + 1 < tp->ksize) continue; u = get_uuhash(tp->khash, kmer); u->val += 1U << 16; } } nb = ((rlen - tp->winlen) * 2 / 3 / tp->winlen / 2) * 2; b = (rlen - tp->winlen) / 2; hit = 0; roff = tp->seqs->rdoffs->buffer[0]; for(j=0;jwinlen; kmer = 0; kdup = 0; keqs = 0; ktot = e - b + 1 - tp->ksize; for(i=b;iseqs->rdseqs, roff + i)) & kmask; if(i + 1 - b < tp->ksize) continue; kcnt = getval_uuhash(tp->khash, kmer); if((kcnt >> 16) > 1){ kdup ++; } else if((kcnt & 0xFFFFU) > 1){ keqs ++; } } if(cns_debug > 1){ fprintf(stderr, "Selecting anchor[%4d,%4d]: ktot=%d keqs=%d kdup=%d\n", b, e, ktot, keqs, kdup); } if(kdup < UInt(tp->kdup * ktot) && keqs >= UInt(tp->keqs * ktot)){ hit = 1; break; } j ++; if(j & 0x01){ b = (rlen - tp->winlen) / 2 + tp->winlen * ((j + 1) >> 1); } else { b = (rlen - tp->winlen) / 2 - tp->winlen * ((j + 1) >> 1); } } if(hit == 0){ return direct_run_tripog(tp); } } push_u2v(tp->regs[0], b); push_u2v(tp->regs[1], e); failed = 0; for(ridx=1;ridxseqs->nseq;ridx++){ clear_and_encap_u1v(tp->qry, tp->winlen); bitseq_basebank(tp->seqs->rdseqs, tp->seqs->rdoffs->buffer[0] + b, tp->winlen, tp->qry->buffer); rlen = tp->seqs->rdlens->buffer[ridx]; clear_and_encap_u1v(tp->ref, rlen); bitseq_basebank(tp->seqs->rdseqs, tp->seqs->rdoffs->buffer[ridx], rlen, tp->ref->buffer); R = ksw_align(tp->winlen, tp->qry->buffer, rlen, tp->ref->buffer, 4, tp->matrix, - (tp->pogs[0]->par->I + tp->pogs[0]->par->D)/2, 1, KSW_XSTART, NULL); if(R.qb <= -1 || R.tb <= -1 || R.qe <= -1 || R.te <= -1){ if(cns_debug > 1){ fprintf(stderr, "FAILED_ALIGN: READ%u [%d,%d=%d][%d,%d=%d]\n", ridx, R.qb, R.qe, R.qe - R.qb, R.tb, R.te, R.te - R.tb); } if(tp->fail_skip){ push_u2v(tp->regs[0], MAX_U2); push_u2v(tp->regs[1], MAX_U2); failed ++; continue; } else { return direct_run_tripog(tp); } } if(R.qe + 1 - R.qb < tp->winmin || R.te + 1 - R.tb < tp->winmin){ if(cns_debug > 1){ fprintf(stderr, "FAILED_ALIGN: READ%u [%d,%d=%d][%d,%d=%d]\n", ridx, R.qb, R.qe, R.qe - R.qb, R.tb, R.te, R.te - R.tb); } if(tp->fail_skip){ push_u2v(tp->regs[0], MAX_U2); push_u2v(tp->regs[1], MAX_U2); failed ++; continue; } else { return direct_run_tripog(tp); } } push_u2v(tp->regs[0], R.tb); push_u2v(tp->regs[1], R.te + 1); } if(failed * 2 >= tp->seqs->nseq){ return direct_run_tripog(tp); } // building cns for fast aligned regions g = tp->pogs[0]; g->par->alnmode = POG_ALNMODE_GLOBAL; beg_pog(g); for(ridx=0;ridxseqs->nseq;ridx++){ if(tp->regs[0]->buffer[ridx] == MAX_U2) continue; fwdbitpush_pog(g, tp->seqs->rdseqs->bits, tp->seqs->rdoffs->buffer[ridx] + tp->regs[0]->buffer[ridx], tp->regs[1]->buffer[ridx] - tp->regs[0]->buffer[ridx]); } if(0){ print_seqs_pog(g, "p0.fa", NULL); } end_pog(g); g->par->alnmode = POG_ALNMODE_OVERLAP; // finding a best break point { u2v *rs; u1i *s; u2i i, idx, bst, bsi, cnt; rs = init_u2v(256); bst = 0; bsi = MAX_U2; s = g->msa->buffer + g->msa_len * g->seqs->nseq; for(idx=0;idxmsa_len;idx++){ if(s[idx] == 4) continue; cnt = 0; for(ridx=0;ridxseqs->nseq;ridx++){ if(g->msa->buffer[g->msa_len * ridx + idx] == s[idx]) cnt ++; } if(cnt > bst){ bst = cnt; bsi = idx; clear_u2v(rs); push_u2v(rs, idx); } else if(cnt == bst){ push_u2v(rs, idx); } } if(rs->size){ bsi = rs->buffer[rs->size / 2]; } free_u2v(rs); if(bsi == MAX_U2){ return direct_run_tripog(tp); } if(cns_debug > 1){ fprintf(stderr, "BREAKPOINT[MSA]: %u/%u\n", bsi, g->msa_len); } // transform coordinate i = 0; for(ridx=0;ridxseqs->nseq;ridx++){ if(tp->regs[0]->buffer[ridx] == MAX_U2) continue; cnt = 0; s = g->msa->buffer + g->msa_len * i; for(idx=0;idxregs[0]->buffer[ridx] = tp->regs[0]->buffer[ridx] + cnt; tp->regs[1]->buffer[ridx] = tp->regs[0]->buffer[ridx]; if(cns_debug > 1){ fprintf(stderr, "BREAKPOINT[%u:%u]: %u/%u\n", i, ridx, tp->regs[0]->buffer[ridx], tp->seqs->rdlens->buffer[ridx]); } i ++; } } // forward cns to seqs' ends g = tp->pogs[2]; beg_pog(g); for(ridx=0;ridxseqs->nseq;ridx++){ if(tp->regs[0]->buffer[ridx] == MAX_U2) continue; fwdbitpush_pog(g, tp->seqs->rdseqs->bits, tp->seqs->rdoffs->buffer[ridx] + tp->regs[1]->buffer[ridx], tp->seqs->rdlens->buffer[ridx] - tp->regs[1]->buffer[ridx]); } if(0){ print_seqs_pog(g, "p2.fa", NULL); } end_pog(g); if(g->cns->size == 0){ return direct_run_tripog(tp); } // backward cns to seqs' begs g = tp->pogs[1]; beg_pog(g); for(ridx=0;ridxseqs->nseq;ridx++){ if(tp->regs[0]->buffer[ridx] == MAX_U2) continue; revbitpush_pog(g, tp->seqs->rdseqs->bits, tp->seqs->rdoffs->buffer[ridx], tp->regs[0]->buffer[ridx]); } if(0){ print_seqs_pog(g, "p1.fa", NULL); } end_pog(g); if(g->cns->size == 0){ return direct_run_tripog(tp); } // merge two parts clear_basebank(tp->cns); fast_revbits2basebank(tp->cns, tp->pogs[1]->cns->bits, 0, tp->pogs[1]->cns->size); fast_fwdbits2basebank(tp->cns, tp->pogs[2]->cns->bits, 0, tp->pogs[2]->cns->size); tp->is_tripog = 1; } #endif wtdbg2-2.5/txtplot.h000066400000000000000000000040321353664372200144520ustar00rootroot00000000000000/* * * Copyright (c) 2018, Jue Ruan * * * 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 3 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, see . */ #ifndef __TEXT_PLOT_RJ_H #define __TEXT_PLOT_RJ_H #include "list.h" static inline char* barplot_txt_u4_simple(u4i w, u4i h, u4i *vals, u4i size, u4i max_val){ char *g; double hdiv; u4i wdiv; u4i i, j, x, y; g = malloc((w + 1) * h + 1); memset(g, ' ', (w + 1) * h); for(i=1;i<=h;i++){ g[(w + 1) * i - 1] = '\n'; } g[(w + 1) * h] = 0; if(max_val == 0){ max_val = 1; for(i=0;i max_val) max_val = vals[i]; } } hdiv = 1.0 * max_val / h; wdiv = size / w; if(wdiv == 0) wdiv = 1; for(i=x=0;i h) y = h; for(j=1;j<=y;j++){ g[(h - j) * (w + 1) + x] = '|'; } } return g; } static inline char* barplot_txt_u8_simple(u4i w, u4i h, u8i *vals, u4i size, u8i max_val){ char *g; double hdiv; u8i wdiv; u4i i, j, x, y; g = malloc((w + 1) * h + 1); memset(g, ' ', (w + 1) * h); for(i=1;i<=h;i++){ g[(w + 1) * i - 1] = '\n'; } g[(w + 1) * h] = 0; if(max_val == 0){ max_val = 1; for(i=0;i max_val) max_val = vals[i]; } } hdiv = 1.0 * max_val / h; wdiv = size / w; if(wdiv == 0) wdiv = 1; for(i=x=0;i h) y = h; for(j=1;j<=y;j++){ g[(h - j) * (w + 1) + x] = '|'; } } return g; } #endif wtdbg2-2.5/wtdbg-cns.c000066400000000000000000000377441353664372200146370ustar00rootroot00000000000000/* * * Copyright (c) 2011, Jue Ruan * * * 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 3 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, see . */ #include "kswx.h" #include "dbgcns.h" #include "dagcns.h" #include "filereader.h" static int cns_debug = 0; #define MCNS_TASK_DBGCNS 1 #define MCNS_TASK_DAGCNS 2 #define MCNS_TASK_OVERLAP 3 thread_beg_def(mcns); uint32_t eid; CNS *cns; u1v *seq1, *seq2; u4i node1, node2; int reglen; int W, M, X, I, D, E; int candidate_mode; int corr_struct; f4i pM, pX, pI, pD; kswx_t ret; u32list *cigars; int task; thread_end_def(mcns); thread_beg_func(mcns); CNS *cns; DAGCNS *dag; GEGraph *g; bdpnodev *bnodes; bdpedgev *bedges; bdplinkv *linkstack; u8list *mem_cache; u1v *mem_buffer; u32list *cigars[2]; kswx_t *xs[2]; u4i i, nbeg; blk_t *blk; int qb, qe, tb, te; mem_cache = init_u8list(1024); cigars[0] = mcns->cigars; cigars[1] = NULL; xs[0] = malloc(sizeof(kswx_t)); xs[1] = NULL; cns = mcns->cns; dag = init_dagcns(mcns->W, mcns->M, mcns->X, mcns->I, mcns->D, mcns->E, mcns->pM, mcns->pX, mcns->pI, mcns->pD); g = init_gegraph(); bnodes = init_bdpnodev(32); bedges = init_bdpedgev(32); linkstack = init_bdplinkv(32); mem_buffer = init_u1v(1024); thread_beg_loop(mcns); if(mcns->task == MCNS_TASK_DBGCNS){ ready_cns(cns); run_cns(cns, mcns->candidate_mode, mcns->corr_struct); } else if(mcns->task == MCNS_TASK_DAGCNS){ // force mcns->candidate_mode to 2 // use data from DBGCNS struct ready_cns(cns); clear_u8list(dag->cns); blk = ref_blkv(cns->qblks, 0); append_array_u8list(dag->cns, cns->qseqs->buffer + blk->off, blk->len); gen_pregraph_dagcns(dag); for(i=1;iqblks->size;i++){ blk = ref_blkv(mcns->cns->qblks, i); nbeg = branched_dynamic_programming_alignment(dag, mcns->cns->qseqs->buffer + blk->off, blk->len, g, bnodes, bedges, mem_buffer); if(nbeg == 0){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); continue; } bdpgraph2dagcns(dag, g, bnodes, bedges, nbeg, linkstack); } merge_nodes_dagcns(dag); gen_consensus_dagcns(dag, NULL); if(cns_debug){ fprintf(stderr, "DAG%d\t%d\t", mcns->eid, (int)dag->cns->size); print_seq_dagcns(dag, stderr); fprintf(stderr, "\n"); } clear_u1v(mcns->cns->cns); append_u1v(mcns->cns->cns, (u1v*)dag->cns); clear_string(mcns->cns->seq); for(i=0;icns->size;i++) add_char_string(mcns->cns->seq, bit_base_table[dag->cns->buffer[i]]); } else if(mcns->task == MCNS_TASK_OVERLAP){ if(mcns->seq2->size == 0){ mcns->ret = KSWX_NULL; continue; } qb = 0; qe = mcns->seq1->size; tb = 0; te = mcns->seq2->size; if(qe > mcns->reglen) qb = qe - mcns->reglen; if(te > mcns->reglen) te = mcns->reglen; kswx_overlap_align_core(xs, cigars, qe - qb, mcns->seq1->buffer + qb, te - tb, mcns->seq2->buffer + tb, 1, mcns->M, mcns->X, mcns->I, mcns->D, mcns->E, mem_cache); xs[0]->qb += qb; xs[0]->qe += qb; xs[0]->tb += tb; xs[0]->te += tb; mcns->ret = *xs[0]; } thread_end_loop(mcns); free(xs[0]); free_u8list(mem_cache); free_u1v(mem_buffer); free_dagcns(dag); free_gegraph(g); free_bdpnodev(bnodes); free_bdpedgev(bedges); free_bdplinkv(linkstack); thread_end_func(mcns); int revise_joint_point(u32list *cigars, int *qe, int *te){ u4i i, op, ln, max; int qq, q, tt, t; q = t = 0; qq = tt = 0; max = 0; for(i=1;i<=cigars->size;i++){ op = cigars->buffer[cigars->size - i] & 0xF; ln = cigars->buffer[cigars->size - i] >> 4; if(op == 0){ if(ln > max){ qq = q; tt = t; max = ln; } q += ln; t += ln; } else if(op == 1){ q += ln; } else { t += ln; } } if(cns_debug){ fprintf(stderr, "qe = %d -> %d\n", *qe, (*qe) - qq); fprintf(stderr, "te = %d -> %d\n", *te, (*te) - tt); fflush(stderr); } *qe -= qq; *te -= tt; return 1; } int revise_joint_point2(u32list *cigars, int *qe, int *te, int overhang){ u4i i, op, ln; int qq, q, tt, t; q = t = 0; qq = tt = 0; for(i=1;i<=cigars->size;i++){ op = cigars->buffer[cigars->size - i] & 0xF; ln = cigars->buffer[cigars->size - i] >> 4; switch(op){ case 1: q += ln; break; case 2: t += ln; break; default: qq = q; tt = t; q += ln; t += ln; } if(q >= overhang && t >= overhang){ if(cns_debug){ fprintf(stderr, "qe = %d -> %d\n", *qe, (*qe) - qq); fprintf(stderr, "te = %d -> %d\n", *te, (*te) - tt); fflush(stderr); } *qe -= qq; *te -= tt; return 1; } } return 0; } uint32_t run(int reglen, int ksize, int Z, int W, int M, int X, int I, int D, int E, int H, int L, int XX, int OO, int EE, int cns_model, f4i pM, f4i pX, f4i pI, f4i pD, int candidate_mode, int corr_struct, uint32_t ncpu, FileReader *fr, FILE *out){ String *tag, *seq; u1v *cseqs; u4v *cxs, *cys, *tes, *qes; uint32_t i, m, eid, beg, end; int c, j, sl, b, e; char *ss; thread_preprocess(mcns); tag = init_string(32); seq = init_string(32); cseqs = init_u1v(32); cxs = init_u4v(32); cys = init_u4v(32); tes = init_u4v(32); qes = init_u4v(32); thread_beg_init(mcns, ncpu); mcns->eid = 0; mcns->cns = init_cns(ksize, Z, W, 0, X, I, D, E, H, L); mcns->seq1 = init_u1v(32); mcns->seq2 = init_u1v(32); mcns->node1 = 0; mcns->node2 = 0; mcns->reglen = reglen; mcns->W = 128; mcns->M = M; mcns->X = XX; mcns->I = OO; mcns->D = OO; mcns->E = EE; mcns->pM = pM; mcns->pX = pX; mcns->pI = pI; mcns->pD = pD; mcns->candidate_mode = candidate_mode; mcns->corr_struct = corr_struct; mcns->ret = KSWX_NULL; mcns->cigars = init_u32list(16); mcns->task = 0; thread_end_init(mcns); eid = 0; thread_wait_one(mcns); while(1){ c = readtable_filereader(fr); if(c == -1 || fr->line->string[0] == 'E' || fr->line->string[0] == '>'){ thread_wake(mcns); thread_wait_one(mcns); if(mcns->task == cns_model && mcns->cns->seq->size){ if(cns_debug){ fprintf(stderr, "%s_%d_N%u_N%u\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%s\n", tag->string, mcns->eid, mcns->node1, mcns->node2, mcns->cns->qlen, mcns->cns->seq->size, mcns->cns->max_score, mcns->cns->alns[0], mcns->cns->alns[1], mcns->cns->alns[2], mcns->cns->alns[3], mcns->cns->seq->string); } cxs->buffer[mcns->eid] = cseqs->size; for(j=0;jcns->seq->size;j++) push_u1v(cseqs, base_bit_table[(int)mcns->cns->seq->string[j]]); cys->buffer[mcns->eid] = cseqs->size; } reset_cns(mcns->cns); clear_string(mcns->cns->seq); mcns->task = cns_model; mcns->eid = eid ++; push_u4v(cxs, 0); push_u4v(cys, 0); if(fr->line->string[0] == 'E'){ mcns->node1 = atoll(get_col_str(fr, 2) + 1); mcns->node2 = atoll(get_col_str(fr, 4) + 1); continue; } if(tag->size){ thread_beg_iter(mcns); thread_wait(mcns); if(mcns->task == cns_model && mcns->cns->seq->size){ if(cns_debug){ //fprintf(stderr, "%s_%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%s\n", tag->string, mcns->eid, mcns->cns->qlen, mcns->cns->seq->size, mcns->cns->max_score, mcns->cns->alns[0], mcns->cns->alns[1], mcns->cns->alns[2], mcns->cns->alns[3], mcns->cns->seq->string); fprintf(stderr, "%s_%d_N%u_N%u\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%s\n", tag->string, mcns->eid, mcns->node1, mcns->node2, mcns->cns->qlen, mcns->cns->seq->size, mcns->cns->max_score, mcns->cns->alns[0], mcns->cns->alns[1], mcns->cns->alns[2], mcns->cns->alns[3], mcns->cns->seq->string); if(0){ u4i j, x; for(j=x=0;jcns->cigars->size;j++){ if(mcns->cns->cigars->buffer[j] == DBGCNS_PATH_I){ fputc('-', stderr); } else { fputc("ACGT"[mcns->cns->cns->buffer[x]], stderr); x ++; } } fputc('\n', stderr); for(j=0;jcns->cigars->size;j++){ fputc("MXID"[mcns->cns->cigars->buffer[j]], stderr); } fputc('\n', stderr); } } cxs->buffer[mcns->eid] = cseqs->size; for(j=0;jcns->seq->size;j++) push_u1v(cseqs, base_bit_table[(int)mcns->cns->seq->string[j]]); cys->buffer[mcns->eid] = cseqs->size; } reset_cns(mcns->cns); clear_string(mcns->cns->seq); mcns->eid = 0; mcns->task = 0; mcns->node1 = 0; mcns->node2 = 0; thread_end_iter(mcns); push_u4v(qes, 0); push_u4v(tes, 0); for(i=1;itask == MCNS_TASK_OVERLAP && mcns->ret.aln > 0){ if(cns_debug){ fprintf(stderr, "#%s_%d\t%d\t%d\t%d", tag->string, mcns->eid - 1, (int)mcns->seq1->size, mcns->ret.qb, mcns->ret.qe); fprintf(stderr, "\t%s_%d\t%d\t%d\t%d", tag->string, mcns->eid, (int)mcns->seq2->size, mcns->ret.tb, mcns->ret.te); fprintf(stderr, "\t%d\t%d\t%d\t%d\t%d\n", mcns->ret.aln, mcns->ret.mat, mcns->ret.mis, mcns->ret.ins, mcns->ret.del); } { b = mcns->ret.qe; e = mcns->ret.te; if(1){ revise_joint_point(mcns->cigars, &b, &e); } qes->buffer[mcns->eid] = b; tes->buffer[mcns->eid] = e; } } mcns->task = MCNS_TASK_OVERLAP; mcns->eid = i; clear_u1v(mcns->seq1); append_array_u1v(mcns->seq1, cseqs->buffer + cxs->buffer[i-1], cys->buffer[i-1] - cxs->buffer[i-1]); clear_u1v(mcns->seq2); append_array_u1v(mcns->seq2, cseqs->buffer + cxs->buffer[i], cys->buffer[i] - cxs->buffer[i]); mcns->ret = KSWX_NULL; push_u4v(qes, mcns->seq1->size); push_u4v(tes, 0); thread_wake(mcns); } push_u4v(qes, cys->buffer[eid-1] - cxs->buffer[eid-1]); push_u4v(tes, 0); thread_beg_iter(mcns); thread_wait(mcns); if(mcns->task == MCNS_TASK_OVERLAP && mcns->ret.aln > 0){ if(cns_debug){ fprintf(stderr, "#%s_%d\t%d\t%d\t%d", tag->string, mcns->eid - 1, (int)mcns->seq1->size, mcns->ret.qb, mcns->ret.qe); fprintf(stderr, "\t%s_%d\t%d\t%d\t%d", tag->string, mcns->eid, (int)mcns->seq2->size, mcns->ret.tb, mcns->ret.te); fprintf(stderr, "\t%d\t%d\t%d\t%d\t%d\n", mcns->ret.aln, mcns->ret.mat, mcns->ret.mis, mcns->ret.ins, mcns->ret.del); } { b = mcns->ret.qe; e = mcns->ret.te; if(1){ revise_joint_point(mcns->cigars, &b, &e); } qes->buffer[mcns->eid] = b; tes->buffer[mcns->eid] = e; } } mcns->ret = KSWX_NULL; mcns->eid = 0; mcns->task = 0; thread_end_iter(mcns); // generate contig seq clear_string(seq); for(i=0;ibuffer[i] + tes->buffer[i]; end = cxs->buffer[i] + qes->buffer[i + 1]; for(m=beg;mbuffer[m]]); } if(cns_debug){ fprintf(stderr, "=%s_%d\t%d\t%d\n", tag->string, i, seq->size - (end - beg), seq->size); } } fprintf(out, ">%s len=%d\n", tag->string, seq->size); for(j=0;jsize;j+=100){ sl = num_min(j + 100, seq->size); char ch = seq->string[sl]; seq->string[sl] = 0; fprintf(out, "%s\n", seq->string + j); seq->string[sl] = ch; } } if(c == -1) break; clear_string(tag); ss = get_col_str(fr, 0) + 1; sl = get_col_len(fr, 0) - 1; for(j=0;jline->string[0] == 'S' || fr->line->string[0] == 's'){ ss = get_col_str(fr, 5); sl = get_col_len(fr, 5); add_seq_cns(mcns->cns, ss, sl, (fr->line->string[0] == 'S')); } } thread_beg_close(mcns); free_cns(mcns->cns); free_u1v(mcns->seq1); free_u1v(mcns->seq2); free_u32list(mcns->cigars); thread_end_close(mcns); free_u1v(cseqs); free_u4v(cxs); free_u4v(cys); free_u4v(tes); free_u4v(qes); free_string(tag); free_string(seq); return 0; } int usage(){ printf( "WTDBG-CNS: Consensuser for wtdbg\n" "Author: Jue Ruan \n" "Version: 1.1\n" "Usage: wtdbg-cns [options]\n" "Options:\n" " -t Number of threads, [1]\n" " -i Input file(s) *.utg.cns from wtdbg, +, [STDIN]\n" " -o Output files, [STDOUT]\n" " -f Force overwrite\n" " -j Expected length of node, or say the overlap length of two adject units in layout file, [1000] bp\n" "-----------------BEG DBG options---------------------------------\n" " -k Kmer size for long reads, [15]\n" " -Z Z-cutoff, drop the lower (score / <-X>), [4]\n" " -W W-cutoff, drop the lagger (position), [48]\n" " In DAG correction, -W set the bandwidth of alignment\n" " -H High coverage bonus, [1]\n" " -L High coverage cutoff = avg_cov / <-L> [10]\n" " -c Candidate strategy, 0: best-kmers, 1: median length, 2: first (include), 3: first (exclude), 4: longest, 5, shortest, [0]\n" " In DAG correction, force to use strategy 2\n" "-----------------END DBG options---------------------------------\n" " -M Match score, [2]\n" " -X Mismatch score, [-7]\n" " -I Insertion score, [-3]\n" " -D Deletion score, [-4]\n" " -E Gap extension score, [-2]\n" " -m 1: DBG correction; 2: DAG correction, [1]\n" " -S whether to correct structure before error correction, [1]\n" " -v Verbose\n" " -V Print version information and then exit\n" "\n"); return 1; } int main(int argc, char **argv){ FileReader *fr; cplist *infs; FILE *out; char *outf; int c, ncpu, overwrite, reglen, ksize, Z, W, C, M, X, I, D, E, H, L, XX, OO, EE; int candidate_mode, cns_model, corr_struct; f4i pM, pX, pI, pD; ncpu = 1; reglen = 1000; ksize = 15; Z = 4; W = 48; C = 1; M = 2; X = -7; I = -3; D = -4; E = -2; H = 1; L = 10; XX = -4; OO = -2; EE = -1; candidate_mode = 0; cns_model = 1; corr_struct = 1; pM = log(0.85); pX = log(0.10); pI = log(0.03); pD = log(0.02); infs = init_cplist(4); outf = NULL; overwrite = 0; while((c = getopt(argc, argv, "hvVt:k:i:o:fj:Z:W:C:M:X:I:D:E:H:L:m:c:S:")) != -1){ switch(c){ case 'h': return usage(); case 't': ncpu = atoi(optarg); break; case 'k': ksize = atoi(optarg); break; case 'i': push_cplist(infs, optarg); break; case 'o': outf = optarg; break; case 'f': overwrite = 1; break; case 'j': reglen = atoi(optarg); break; case 'Z': Z = atoi(optarg); break; case 'W': W = atoi(optarg); break; case 'C': C = atoi(optarg); break; case 'M': M = atoi(optarg); break; case 'X': X = atoi(optarg); break; case 'I': I = atoi(optarg); break; case 'D': D = atoi(optarg); break; case 'E': E = atoi(optarg); break; case 'H': H = atoi(optarg); break; case 'L': L = atoi(optarg); break; case 'm': cns_model = atoi(optarg); break; case 'c': candidate_mode = atoi(optarg); break; case 'S': corr_struct = atoi(optarg); break; case 'v': cns_debug ++; break; case 'V': fprintf(stdout, "wtdbg-cns 1.1\n"); return 0; default: return usage(); } } BEG_STAT_PROC_INFO(stderr, argc, argv); if(cns_model != MCNS_TASK_DBGCNS && cns_model != MCNS_TASK_DAGCNS){ return usage(); } if(ncpu <= 0 && _sig_proc_deamon) ncpu = _sig_proc_deamon->ncpu; if(ncpu <= 0){ fprintf(stderr, " -- Invalid cpu number '%d' in %s -- %s:%d --\n", ncpu, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); return 1; } if(outf && !overwrite && file_exists(outf)){ fprintf(stderr, "File exists! '%s'\n\n", outf); return usage(); } if(cns_debug > 1) DBGCNS_DEBUG = 1; if(infs->size) fr = open_all_filereader(infs->size, infs->buffer, 1); else fr = open_filereader(NULL, 1); if(outf){ out = open_file_for_write(outf, NULL, 1); } else out = stdout; run(reglen, ksize, Z, W, M, X, I, D, E, H, L, XX, OO, EE, cns_model, pM, pX, pI, pD, candidate_mode, corr_struct, ncpu, fr, out); close_filereader(fr); if(outf) fclose(out); free_cplist(infs); END_STAT_PROC_INFO(stderr); return 0; } wtdbg2-2.5/wtdbg-graph.h000066400000000000000000004076451353664372200151630ustar00rootroot00000000000000/* * * Copyright (c) 2011, Jue Ruan * * * 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 3 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, see . */ #ifndef __WTDBG_GRAPH_RJ_H #define __WTDBG_GRAPH_RJ_H #include "wtdbg.h" #include "filewriter.h" #include "pgzf.h" static inline u8i print_local_dot_graph(Graph *g, char *prefix, char *suffix); static inline void print_node_edges_cov_graph(Graph *g, FILE *out){ node_t *n; edge_t *e; edge_ref_t *f; u8i idx, nid; u4i k, i; u4v *covs; covs = init_u4v(32); for(nid=0;nidnodes->size;nid++){ n = ref_nodev(g->nodes, nid); clear_u4v(covs); for(k=0;k<2;k++){ idx = n->edges[k].idx; while(idx){ f = ref_edgerefv(g->erefs, idx); e = ref_edgev(g->edges, f->idx); push_u4v(covs, e->cov); idx = f->next; } } if(covs->size == 0) continue; sort_array(covs->buffer, covs->size, u4i, num_cmpgt(b, a)); fprintf(out, "NODE_COV\tN%llu\t%u\t%u", nid, n->cov, n->regs.cnt); for(i=0;isize;i++){ fprintf(out, "\t%u", covs->buffer[i]); } fprintf(out, "\n"); } free_u4v(covs); } static inline void cut_edge_core_graph(Graph *g, edge_t *e, int closed_val){ //if(e->closed == closed_val) return; if(e->closed) return; e->closed = closed_val; ref_nodev(g->nodes, e->node1)->edges[e->dir1].cnt --; ref_nodev(g->nodes, e->node2)->edges[!e->dir2].cnt --; } #define cut_edge_graph(g, e) cut_edge_core_graph(g, e, 1) static inline void cut_lnk_core_graph(Graph *g, lnk_t *e, int closed_val){ if(e->closed) return; e->closed = closed_val; ref_frgv(g->frgs, e->frg1)->lnks[e->dir1].cnt --; ref_frgv(g->frgs, e->frg2)->lnks[!e->dir2].cnt --; } #define cut_lnk_graph(g, e) cut_lnk_core_graph(g, e, 1) static inline void revive_edge_graph(Graph *g, edge_t *e){ if(e->closed == WT_EDGE_CLOSED_NULL) return; e->closed = WT_EDGE_CLOSED_NULL; ref_nodev(g->nodes, e->node1)->edges[e->dir1].cnt ++; ref_nodev(g->nodes, e->node2)->edges[!e->dir2].cnt ++; } static inline void revive_lnk_graph(Graph *g, lnk_t *e){ if(e->closed == WT_EDGE_CLOSED_NULL) return; e->closed = WT_EDGE_CLOSED_NULL; ref_frgv(g->frgs, e->frg1)->lnks[e->dir1].cnt ++; ref_frgv(g->frgs, e->frg2)->lnks[!e->dir2].cnt ++; } static inline void del_node_edges_graph(Graph *g, node_t *n){ edge_ref_t *f; edge_t *e; u8i idx; u4i k; for(k=0;k<2;k++){ idx = n->edges[k].idx; while(idx){ f = ref_edgerefv(g->erefs, idx); idx = f->next; e = g->edges->buffer + f->idx; cut_edge_core_graph(g, e, WT_EDGE_CLOSED_HARD); } } } static inline void del_frg_lnks_graph(Graph *g, frg_t *n){ edge_ref_t *f; lnk_t *e; u8i idx; u4i k; for(k=0;k<2;k++){ idx = n->lnks[k].idx; while(idx){ f = ref_edgerefv(g->lrefs, idx); idx = f->next; e = g->lnks->buffer + f->idx; cut_lnk_core_graph(g, e, WT_EDGE_CLOSED_HARD); } } } static inline void del_node_graph(Graph *g, node_t *n){ del_node_edges_graph(g, n); n->closed = 1; } static inline u8i mask_nodes_by_edge_cov_graph(Graph *g, u4i min_node_cov, float min_edge_cov_ratio, FILE *out){ node_t *n; edge_t *e; edge_ref_t *f; u8i idx, nid, ret; u4i max, k; ret = 0; for(nid=0;nidnodes->size;nid++){ n = ref_nodev(g->nodes, nid); if(n->closed) continue; //if(n->regs.cnt < min_node_cov) continue; if(n->cov < min_node_cov) continue; max = 0; for(k=0;k<2;k++){ idx = n->edges[k].idx; while(idx){ f = ref_edgerefv(g->erefs, idx); e = ref_edgev(g->edges, f->idx); if(e->cov > max) max = e->cov; idx = f->next; } } if(max < (u4i)(n->regs.cnt * min_edge_cov_ratio)){ del_node_graph(g, n); if(out){ fprintf(out, "NODE_EDGE_COV\tN%llu\t%u\t%u\n", nid, n->regs.cnt, max); } ret ++; } } return ret; } #define MAX_BT_NIDX 0xFFFFFFU typedef struct { u8i node:46, visit:1, closed:1, cov:11, fix:1, sub_dir:1; u8i flag; u8i bt_dir:1, bt_open:10, bt_nidx:24, bt_score:20, bt_step:8, bt_hit:1; ptr_ref_t edges[2]; } subnode_t; define_list(subnodev, subnode_t); #define subnode_hashcode(E) u64hashcode((E).node) #define subnode_hashequals(E1, E2) (E1).node == (E2).node define_hashset(subnodehash, subnode_t, subnode_hashcode, subnode_hashequals); typedef struct { subnode_t *node; u4i cov:28, visit:1, fwd:1, dir:1, closed:1; int off; u4i next; } subedge_t; define_list(subedgev, subedge_t); static inline int evaluate_node_connectivity_graph(Graph *g, u8i nid, u4v *rds, subnodehash *nodes, subedgev *edges, ptrrefv *stack){ node_t *nd; read_t *rd; reg_t *rg; subnode_t N, *n, *n1, *n2; subedge_t *e; ptr_ref_t *p; u8i idx, edx, aim; u4i i, k, k1, k2, cnt; int exists; // collect reads containing nid clear_u4v(rds); nd = ref_nodev(g->nodes, nid); for(i=0;iregs.cnt;i++){ rg = ref_regv(g->regs, nd->regs.idx + i); push_u4v(rds, rg->rid); } // prepare nodes in subgraph clear_subnodehash(nodes); clear_subedgev(edges); next_ref_subedgev(edges); memset(&N, 0, sizeof(subnode_t)); N.cov = 1; for(i=0;isize;i++){ rd = ref_readv(g->reads, rds->buffer[i]); rg = NULL; idx = rd->regs.idx; while(idx){ rg = ref_regv(g->regs, idx); idx = rg->read_link; if(rg->closed) continue; N.node = rg->node; n = prepare_subnodehash(nodes, N, &exists); if(exists){ n->cov ++; } else { *n = N; } } } // mask low cov nodes reset_iter_subnodehash(nodes); while((n = ref_iter_subnodehash(nodes))){ if(n->cov < g->min_node_cov) n->closed = 1; } // build edges for(i=0;isize;i++){ rd = ref_readv(g->reads, rds->buffer[i]); n1 = NULL; k1 = 0; idx = rd->regs.idx; while(idx){ rg = ref_regv(g->regs, idx); idx = rg->read_link; if(rg->closed) continue; N.node = rg->node; n2 = get_subnodehash(nodes, N); k2 = rg->dir; if(n2->closed) continue; if(n1){ // link n1 to n2 edx = n1->edges[k1].idx; while(edx){ e = ref_subedgev(edges, edx); if(e->node == n2 && e->dir == k2){ e->cov ++; break; } edx = e->next; } if(edx == 0){ edx = edges->size; e = next_ref_subedgev(edges); e->node = n2; e->dir = k2; e->cov = 1; e->next = n1->edges[k1].idx; n1->edges[k1].idx = edx; n1->edges[k1].cnt ++; } // link rev n2 to rev n1 edx = n2->edges[!k2].idx; while(edx){ e = ref_subedgev(edges, edx); if(e->node == n1 && e->dir == !k1){ e->cov ++; break; } edx = e->next; } if(edx == 0){ edx = edges->size; e = next_ref_subedgev(edges); e->node = n1; e->dir = !k1; e->cov = 1; e->next = n2->edges[!k2].idx; n2->edges[!k2].idx = edx; n2->edges[!k2].cnt ++; } } n1 = n2; k1 = k2; } } // find the nid node N.node = nid; n = get_subnodehash(nodes, N); n->visit = 1; // checking whether its out-edges collapse into one node for(k=0;k<2;k++){ if(n->edges[k].cnt > 64) return 0; if(n->edges[k].cnt < 2) continue; idx = n->edges[k].idx; cnt = 0; while(idx){ e = ref_subedgev(edges, idx); idx = e->next; if(e->cov == 1) continue; // don't track low cov out-edges cnt ++; } aim = 0xFFFFFFFFFFFFFFFFLLU >> (64 - cnt); cnt = 0; exists = 0; if(k){ reset_iter_subnodehash(nodes); while((n1 = ref_iter_subnodehash(nodes))){ n1->flag = 0; } } idx = n->edges[k].idx; while(idx){ e = ref_subedgev(edges, idx); idx = e->next; if(e->cov == 1) continue; // don't track low cov out-edges e->node->flag |= 1LLU << cnt; cnt ++; reset_iter_subnodehash(nodes); while((n1 = ref_iter_subnodehash(nodes))){ n1->visit = 0; } n->visit = 1; clear_ptrrefv(stack); push_ptrrefv(stack, (ptr_ref_t){offset_subnodehash(nodes, e->node), e->dir}); while(stack->size){ p = peer_ptrrefv(stack); n1 = nodes->array + p->idx; k1 = p->cnt; stack->size --; if(n1->flag == aim){ exists = 1; break; } if(n1->visit) continue; n1->visit = 1; edx = n1->edges[k1].idx; while(edx){ e = ref_subedgev(edges, edx); edx = e->next; if(e->node->visit) continue; e->node->flag |= n1->flag; push_ptrrefv(stack, (ptr_ref_t){offset_subnodehash(nodes, e->node), e->dir}); } if(exists) break; } if(exists) break; } if(exists == 0) return 0; } return 1; } static inline void print_subgraph_dot(Graph *g, u8i id, subnodehash *nodes, subedgev *edges, FILE *out){ subnode_t *n; subedge_t *e; u8i idx; int k; UNUSED(g); fprintf(out, "digraph N%llu {\n", id); fprintf(out, " N%llu [style=filled fillcolor=yellow]\n", id); reset_iter_subnodehash(nodes); while((n = ref_iter_subnodehash(nodes))){ if(n->closed) continue; fprintf(out, "N%llu [label=\"N%llu%s(%u)\"]\n", (u8i)n->node, (u8i)n->node, n->closed? "*" : "", n->cov); for(k=0;k<2;k++){ idx = n->edges[k].idx; while(idx){ e = ref_subedgev(edges, idx); idx = e->next; fprintf(out, " N%llu -> N%llu [label=\"%c%c:%d:%d\"]\n", (u8i)n->node, (u8i)e->node->node, "+-"[k], "+-"[e->dir], e->cov, e->off); } } } fprintf(out, "}\n"); } static inline void fprint_subgraph_dot(Graph *g, u8i id, subnodehash *nodes, subedgev *edges, char *filename){ FILE *out; out = open_file_for_write(filename, NULL, 1); print_subgraph_dot(g, id, nodes, edges, out); fclose(out); } thread_beg_def(mrep); Graph *g; u8i ret; u8v *reps; thread_end_def(mrep); thread_beg_func(mrep); subnodehash *nodes; subedgev *edges; u4v *rds; ptrrefv *stack; u8i nid, tidx, ncpu; nodes = init_subnodehash(1023); edges = init_subedgev(32); rds = init_u4v(32); stack = init_ptrrefv(32); tidx = mrep->t_idx; ncpu = mrep->n_cpu; thread_beg_loop(mrep); for(nid=tidx;nidg->nodes->size;nid+=ncpu){ if(mrep->g->nodes->buffer[nid].closed) continue; if(evaluate_node_connectivity_graph(mrep->g, nid, rds, nodes, edges, stack) == 0){ if(0){ print_subgraph_dot(mrep->g, nid, nodes, edges, stdout); } mrep->g->nodes->buffer[nid].closed = 1; push_u8v(mrep->reps, nid); mrep->ret ++; } } thread_end_loop(mrep); free_subnodehash(nodes); free_subedgev(edges); free_u4v(rds); free_ptrrefv(stack); thread_end_func(mrep); static inline u8i mask_nodes_by_connectivity_graph(Graph *g, int ncpu, FILE *out){ node_t *n; u8i ret, i; thread_preprocess(mrep); ret = 0; thread_beg_init(mrep, ncpu); mrep->g = g; mrep->ret = 0; mrep->reps = init_u8v(32); thread_end_init(mrep); thread_wake_all(mrep); thread_wait_all(mrep); thread_beg_close(mrep); if(out){ for(i=0;ireps->size;i++){ n = ref_nodev(g->nodes, mrep->reps->buffer[i]); fprintf(out, "N%llu\t%u\tconn\n", (u8i)mrep->reps->buffer[i], (u4i)n->regs.cnt); } } ret += mrep->ret; free_u8v(mrep->reps); thread_end_close(mrep); return ret; } // remove regs which have no high cov edges with other regs in one read thread_beg_def(mrdk); Graph *g; u4i ridx; u8v *masks; thread_end_def(mrdk); thread_beg_func(mrdk); Graph *g; u4i ridx; u8v *regs; u4v *gidxs, *gcnts; UUhash *hash; UUhash_t *UU; read_t *rd; reg_t *reg; node_t *n; edge_ref_t *f; edge_t *e; u8i idx, fidx, nidx, hidx; u4i i, k, gid, max; g = mrdk->g; regs = init_u8v(32); gidxs = init_u4v(32); gcnts = init_u4v(32); hash = init_UUhash(1023); thread_beg_loop(mrdk); clear_u8v(mrdk->masks); ridx = mrdk->ridx; if(ridx == MAX_U4) continue; clear_u8v(regs); clear_u4v(gidxs); clear_u4v(gcnts); clear_UUhash(hash); rd = ref_readv(g->reads, ridx); idx = rd->regs.idx; while(idx){ push_u4v(gidxs, regs->size); push_u4v(gcnts, 0); reg = ref_regv(g->regs, idx); if(reg->closed == 0){ put_UUhash(hash, (UUhash_t){reg->node, regs->size}); push_u8v(regs, idx); } idx = reg->read_link; } for(i=0;isize;i++){ idx = regs->buffer[i]; gid = gidxs->buffer[i]; reg = ref_regv(g->regs, idx); n = ref_nodev(g->nodes, reg->node); for(k=0;k<2;k++){ fidx = n->edges[k].idx; while(fidx){ f = ref_edgerefv(g->erefs, fidx); fidx = f->next; e = ref_edgev(g->edges, f->idx); if(e->cov < g->min_edge_cov) continue; nidx = f->flg? e->node1 : e->node2; if((UU = get_UUhash(hash, nidx)) == NULL) continue; if((hidx = UU->val) <= i) continue; gidxs->buffer[hidx] = gid; } } } for(i=0;isize;i++) gcnts->buffer[gidxs->buffer[i]] ++; max = 0; gid = 0; for(i=0;isize;i++){ if(gcnts->buffer[i] > max){ max = gcnts->buffer[i]; gid = i; } } for(i=0;isize;i++){ if(gidxs->buffer[i] != gid){ push_u8v(mrdk->masks, regs->buffer[i]); } } thread_end_loop(mrdk); free_u8v(regs); free_u4v(gidxs); free_u4v(gcnts); free_UUhash(hash); thread_end_func(mrdk); static inline u8i mask_read_weak_regs_graph(Graph *g, int ncpu){ u8i i, ret; u4i j; thread_preprocess(mrdk); thread_beg_init(mrdk, ncpu); mrdk->g = g; mrdk->ridx = MAX_U4; mrdk->masks = init_u8v(32); thread_end_init(mrdk); ret = 0; for(i=0;ireads->size+ncpu;i++){ if(i < g->reads->size){ thread_wait_one(mrdk); } else { thread_wait_next(mrdk); } if(mrdk->masks->size){ for(j=0;jmasks->size;j++){ ref_regv(g->regs, mrdk->masks->buffer[j])->closed = 1; } ret += mrdk->masks->size; clear_u8v(mrdk->masks); } if(i < g->reads->size){ mrdk->ridx = i; thread_wake(mrdk); } } thread_beg_close(mrdk); free_u8v(mrdk->masks); thread_end_close(mrdk); return ret; } static inline u8i mask_possible_tip_nodes_graph(Graph *g){ node_t *n; reg_t *r; u8i ret, i; u4i j, cnt; ret = 0; for(i=0;inodes->size;i++){ n = ref_nodev(g->nodes, i); if(n->closed) continue; cnt = 0; for(j=0;jregs.cnt;j++){ r = ref_regv(g->regs, n->regs.idx + j); if(r->read_link == 0) continue; if(n->regs.idx + j == g->reads->buffer[r->rid].regs.idx) continue; cnt ++; } if(cnt < g->min_edge_cov){ n->closed = 1; ret ++; } } return ret; } static inline void print_node_edges_graph(Graph *g, u8i nid, int dir, FILE *out){ node_t *n; edge_ref_t *f; edge_t *e; u8i idx; n = ref_nodev(g->nodes, nid); idx = n->edges[dir].idx; while(idx){ f = ref_edgerefv(g->erefs, idx); idx = f->next; e = ref_edgev(g->edges, f->idx); if(f->flg){ fprintf(out, "N%llu\t%c\tN%llu\t%c\t%d\t%d\n", (u8i)e->node2, "+-"[!e->dir1], (u8i)e->node1, "+-"[e->dir1], e->cov, e->off); } else { fprintf(out, "N%llu\t%c\tN%llu\t%c\t%d\t%d\n", (u8i)e->node1, "+-"[e->dir1], (u8i)e->node2, "+-"[e->dir2], e->cov, e->off); } } } static inline edge_ref_t* first_living_edge_graph(Graph *g, node_t *n, int dir, int *info){ edge_ref_t *f, *ret; u8i idx; ret = NULL; if(info){ *info = WT_TRACE_MSG_ZERO; if(n->edges[dir].cnt == 0) return NULL; idx = n->edges[dir].idx; while(idx){ f = ref_edgerefv(g->erefs, idx); idx = f->next; if(g->edges->buffer[f->idx].closed) continue; if(ret){ *info = WT_TRACE_MSG_MORE; return NULL; } else { *info = WT_TRACE_MSG_ONE; ret = f; } } } else { if(n->edges[dir].cnt == 0) return NULL; idx = n->edges[dir].idx; while(idx){ f = ref_edgerefv(g->erefs, idx); idx = f->next; if(g->edges->buffer[f->idx].closed) continue; if(ret){ return NULL; } else { ret = f; } } } return ret; } static inline edge_ref_t* first_living_lnk_graph(Graph *g, frg_t *n, int dir, int *info){ edge_ref_t *f, *ret; u8i idx; ret = NULL; if(info){ *info = WT_TRACE_MSG_ZERO; if(n->lnks[dir].cnt == 0) return NULL; idx = n->lnks[dir].idx; while(idx){ f = ref_edgerefv(g->lrefs, idx); idx = f->next; if(g->lnks->buffer[f->idx].closed) continue; if(ret){ *info = WT_TRACE_MSG_MORE; return NULL; } else { *info = WT_TRACE_MSG_ONE; ret = f; } } } else { if(n->lnks[dir].cnt == 0) return NULL; idx = n->lnks[dir].idx; while(idx){ f = ref_edgerefv(g->erefs, idx); idx = f->next; if(g->lnks->buffer[f->idx].closed) continue; if(ret){ return NULL; } else { ret = f; } } } return ret; } #define count_living_edges_graph(g, n, dir) (n)->edges[dir].cnt #define count_living_lnks_graph(g, n, dir) (n)->lnks[dir].cnt // dir = 2 means either strand static inline edge_ref_t* edge_node2node_graph(Graph *g, u8i node1, int dir1, u8i node2, int dir2){ node_t *n; edge_ref_t *f; edge_t *e; u8i idx; int dire; n = ref_nodev(g->nodes, node1); if(dir1 > 1){ dir1 = 0; dire = 2; } else { dire = dir1 + 1; } while(dir1 < dire){ idx = n->edges[dir1].idx; while(idx){ f = ref_edgerefv(g->erefs, idx); idx = f->next; e = ref_edgev(g->edges, f->idx); if(f->flg){ if(e->node1 == node2 && (dir2 > 1? 1 : (dir2 == (!e->dir1)))) return f; } else { if(e->node2 == node2 && (dir2 > 1? 1 : (dir2 == e->dir2))) return f; } } dir1 ++; } return NULL; } static inline u8i linear_trace_graph(Graph *g, tracev *path, u8i max_step, int *msg){ trace_t *t; node_t *n; edge_t *e; edge_ref_t *f; u8i step; int dir, info; if(path->size == 0){ if(msg) *msg = 3; return 0; } t = ref_tracev(path, path->size - 1); step = 0; while(step < max_step){ f = first_living_edge_graph(g, ref_nodev(g->nodes, t->node), t->dir, &info); if(info != WT_TRACE_MSG_ONE){ if(msg) *msg = info; break; } e = g->edges->buffer + f->idx; n = ref_nodev(g->nodes, f->flg? e->node1 : e->node2); dir = f->flg? !e->dir1 : e->dir2; t->edges[t->dir] = *f; t = next_ref_tracev(path); t->node = n - g->nodes->buffer; t->dir = dir; t->edges[!t->dir] = (edge_ref_t){f->idx, !f->flg, 0}; t->edges[t->dir] = EDGE_REF_NULL; f = first_living_edge_graph(g, n, !dir, &info); if(info != WT_TRACE_MSG_ONE){ path->size --; if(msg) *msg = -1 - info; break; } step ++; } return step; } static inline u8i linear_path_graph(Graph *g, pathv *path, int max_len, int *msg){ path_t *t; frg_t *n; lnk_t *e; edge_ref_t *f; int len; int dir, info; if(path->size == 0){ if(msg) *msg = 3; return 0; } t = ref_pathv(path, path->size - 1); len = ref_frgv(g->frgs, t->frg)->len; while(len < max_len){ f = first_living_lnk_graph(g, ref_frgv(g->frgs, t->frg), t->dir, &info); if(info != WT_TRACE_MSG_ONE){ if(msg) *msg = info; break; } e = g->lnks->buffer + f->idx; len += e->off; n = ref_frgv(g->frgs, f->flg? e->frg1 : e->frg2); dir = f->flg? !e->dir1 : e->dir2; t->lnks[t->dir] = *f; t = next_ref_pathv(path); t->frg = n - g->frgs->buffer; t->dir = dir; t->lnks[!t->dir] = (edge_ref_t){f->idx, !f->flg, 0}; t->lnks[t->dir] = EDGE_REF_NULL; f = first_living_lnk_graph(g, n, !dir, &info); if(info != WT_TRACE_MSG_ONE){ path->size --; if(msg) *msg = -1 - info; break; } len += n->len; } return len; } static inline int wander_path_graph(Graph *g, u4i frg_idx, int frg_dir, pathv *heap, u8i vst, int max_len){ path_t T, S; frg_t *n, *w; lnk_t *e; edge_ref_t *f; u8i idx; int len; clear_pathv(heap); T.off = 0; T.frg = frg_idx; T.dir = frg_dir; ref_frgv(g->frgs, frg_idx)->bt_visit = vst; push_pathv(heap, T); while(heap->size){ S = heap->buffer[0]; array_heap_remove(heap->buffer, heap->size, heap->cap, path_t, 0, num_cmp(a.off, b.off)); n = ref_frgv(g->frgs, S.frg); idx = n->lnks[S.dir].idx; while(idx){ f = ref_edgerefv(g->lrefs, idx); idx = f->next; e = ref_lnkv(g->lnks, f->idx); if(e->closed) continue; if(e->weak) continue; w = ref_frgv(g->frgs, f->flg? e->frg1: e->frg2); if(w->bt_visit == vst) continue; w->bt_visit = vst; len = S.off + e->off + w->len; if(len >= max_len){ return len; } T.frg = f->flg? e->frg1: e->frg2; T.dir = f->flg? !e->dir1 : e->dir2; T.off = len; array_heap_push(heap->buffer, heap->size, heap->cap, path_t, T, num_cmp(a.off, b.off)); } } return 0; } static inline int cal_offset_traces_graph(Graph *g, tracev *path, u8i beg, u8i end, int offset){ trace_t *t; node_t *n; reg_t *r; edge_t *e; u8i i; int off; off = offset; for(i=beg;ioff = off; n = ref_nodev(g->nodes, t->node); r = ref_regv(g->regs, n->regs.idx); if(t->edges[t->dir].idx == EDGE_REF_NULL.idx){ off += r->end - r->beg; } else { e = ref_edgev(g->edges, t->edges[t->dir].idx); off += r->end - r->beg + e->off; } } return off; } static inline int cal_offset_paths_graph(Graph *g, pathv *path, u8i beg, u8i end){ path_t *t; frg_t *n; lnk_t *e; u8i i; int off; off = 0; for(i=beg;ioff = off; n = ref_frgv(g->frgs, t->frg); if(t->lnks[t->dir].idx == EDGE_REF_NULL.idx){ off += n->length; } else { e = ref_lnkv(g->lnks, t->lnks[t->dir].idx); off += ((i == beg)? n->length : n->len) + e->off; } } return off; } static inline u8i true_linear_unique_trace_graph(Graph *g, tracev *path, u8i max_step, u8i visit, int *msg){ trace_t *t; node_t *n; edge_t *e; edge_ref_t *f; u8i step; int dir, info; if(path->size == 0){ if(msg) *msg = WT_TRACE_MSG_ZERO; return 0; } step = 0; if(msg) *msg = WT_TRACE_MSG_ONE; while(step < max_step){ t = ref_tracev(path, path->size - 1); f = first_living_edge_graph(g, ref_nodev(g->nodes, t->node), !t->dir, &info); if(info == WT_TRACE_MSG_MORE){ if(path->size > 1) path->size --; if(msg) *msg = -1 - info; break; } n = ref_nodev(g->nodes, t->node); n->bt_visit = visit; f = first_living_edge_graph(g, ref_nodev(g->nodes, t->node), t->dir, &info); if(info == WT_TRACE_MSG_ZERO){ if(msg) *msg = info; break; } else if(info == WT_TRACE_MSG_MORE){ if(path->size > 1) path->size --; if(msg) *msg = info; break; } e = g->edges->buffer + f->idx; n = ref_nodev(g->nodes, f->flg? e->node1 : e->node2); if(n->bt_visit == visit){ if(msg) *msg = WT_TRACE_MSG_VISITED; break; } dir = f->flg? !e->dir1 : e->dir2; t->edges[t->dir] = *f; t = next_ref_tracev(path); t->node = n - g->nodes->buffer; t->dir = dir; t->edges[!t->dir] = (edge_ref_t){f->idx, !f->flg, 0}; t->edges[t->dir] = EDGE_REF_NULL; step ++; } return step; } static inline u8i true_linear_unique_path_graph(Graph *g, pathv *path, u8i max_step, u8i visit, int *msg){ path_t *t; frg_t *n; lnk_t *e; edge_ref_t *f; u8i step; int dir, info; if(path->size == 0){ if(msg) *msg = WT_TRACE_MSG_ZERO; return 0; } if(msg) *msg = WT_TRACE_MSG_ONE; step = 0; while(step < max_step){ t = ref_pathv(path, path->size - 1); f = first_living_lnk_graph(g, ref_frgv(g->frgs, t->frg), !t->dir, &info); if(info == WT_TRACE_MSG_MORE){ if(path->size > 1) path->size --; if(msg) *msg = -1 - info; break; } n = ref_frgv(g->frgs, t->frg); n->bt_visit = visit; f = first_living_lnk_graph(g, ref_frgv(g->frgs, t->frg), t->dir, &info); if(info == WT_TRACE_MSG_ZERO){ if(msg) *msg = info; break; } else if(info == WT_TRACE_MSG_MORE){ if(path->size > 1) path->size --; if(msg) *msg = info; break; } e = g->lnks->buffer + f->idx; n = ref_frgv(g->frgs, f->flg? e->frg1 : e->frg2); if(n->bt_visit == visit){ if(msg) *msg = WT_TRACE_MSG_VISITED; break; } dir = f->flg? !e->dir1 : e->dir2; t->lnks[t->dir] = *f; t = next_ref_pathv(path); t->frg = n - g->frgs->buffer; t->dir = dir; t->lnks[!t->dir] = (edge_ref_t){f->idx, !f->flg, 0}; t->lnks[t->dir] = EDGE_REF_NULL; step ++; } return step; } static inline u8i count_linear_trace_graph(Graph *g, trace_t *t, u8i max_step, int *msg){ node_t *n; edge_t *e; edge_ref_t *f; u8i step; int dir, info; step = 0; if(msg) *msg = WT_TRACE_MSG_ONE; while(step < max_step){ f = first_living_edge_graph(g, ref_nodev(g->nodes, t->node), t->dir, &info); if(info != WT_TRACE_MSG_ONE){ if(msg) *msg = info; break; } e = g->edges->buffer + f->idx; n = ref_nodev(g->nodes, f->flg? e->node1 : e->node2); dir = f->flg? !e->dir1 : e->dir2; t->node = n - g->nodes->buffer; t->dir = dir; f = first_living_edge_graph(g, n, !dir, &info); if(info != WT_TRACE_MSG_ONE){ if(msg) *msg = -1 - info; break; } step ++; } return step; } static inline int count_linear_path_graph(Graph *g, path_t *t, int max_len, int *msg){ frg_t *n; lnk_t *e; edge_ref_t *f; int len; int dir, info; if(msg) *msg = WT_TRACE_MSG_ONE; len = ref_frgv(g->frgs, t->frg)->len; while(len < max_len){ f = first_living_lnk_graph(g, ref_frgv(g->frgs, t->frg), t->dir, &info); if(info != WT_TRACE_MSG_ONE){ if(msg) *msg = info; break; } e = g->lnks->buffer + f->idx; len += e->off; n = ref_frgv(g->frgs, f->flg? e->frg1 : e->frg2); dir = f->flg? !e->dir1 : e->dir2; t->frg = n - g->frgs->buffer; t->dir = dir; f = first_living_lnk_graph(g, n, !dir, &info); if(info != WT_TRACE_MSG_ONE){ if(msg) *msg = -1 - info; break; } len += n->len; } return len; } static inline u4i del_isolated_nodes_graph(Graph *g, FILE *log){ node_t *n; u4i ret, i; int f, r; ret = 0; for(i=0;inodes->size;i++){ n = ref_nodev(g->nodes, i); if(n->closed) continue; first_living_edge_graph(g, n, 0, &f); if(f != WT_TRACE_MSG_ZERO) continue; first_living_edge_graph(g, n, 1, &r); if(r != WT_TRACE_MSG_ZERO) continue; n->closed = 1; if(log) fprintf(log, "DEL_ISO\tN%u\n", i); ret ++; } return ret; } static inline u8i cut_binary_edges_graph(Graph *g){ UUhash *hash; UUhash_t *u; node_t *n; edge_ref_t *f; edge_t *e, *p; u8i idx, nid, ret; ret = 0; hash = init_UUhash(15); for(nid=0;nidnodes->size;nid++){ n = ref_nodev(g->nodes, nid); if(n->closed) continue; clear_UUhash(hash); idx = n->edges[0].idx; while(idx){ f = ref_edgerefv(g->erefs, idx); idx = f->next; e = ref_edgev(g->edges, f->idx); if(e->closed < WT_EDGE_CLOSED_LESS){ put_UUhash(hash, (UUhash_t){f->flg? e->node1 : e->node2, f->idx}); } } idx = n->edges[1].idx; while(idx){ f = ref_edgerefv(g->erefs, idx); idx = f->next; e = ref_edgev(g->edges, f->idx); if(e->closed >= WT_EDGE_CLOSED_LESS) continue; if((u = get_UUhash(hash, f->flg? e->node1 : e->node2)) == NULL) continue; p = ref_edgev(g->edges, u->val); if(0){ if(p->cov > e->cov) cut_edge_core_graph(g, e, WT_EDGE_CLOSED_HARD); else cut_edge_core_graph(g, p, WT_EDGE_CLOSED_HARD); ret ++; } else { cut_edge_core_graph(g, e, WT_EDGE_CLOSED_HARD); cut_edge_core_graph(g, p, WT_EDGE_CLOSED_HARD); ret += 2; } } } free_UUhash(hash); return ret; } static inline u8i cut_binary_lnks_graph(Graph *g, FILE *info){ UUhash *hash; UUhash_t *u; frg_t *n; edge_ref_t *f; lnk_t *e, *p; u8i idx, nid, wid, ret; u4i k; int exists; ret = 0; hash = init_UUhash(15); for(nid=0;nidfrgs->size;nid++){ n = ref_frgv(g->frgs, nid); if(n->closed) continue; clear_UUhash(hash); for(k=0;k<2;k++){ idx = n->lnks[k].idx; while(idx){ f = ref_edgerefv(g->lrefs, idx); idx = f->next; e = ref_lnkv(g->lnks, f->idx); if(e->closed != WT_EDGE_CLOSED_HARD){ wid = f->flg? e->frg1 : e->frg2; u = prepare_UUhash(hash, wid, &exists); if(exists){ p = ref_lnkv(g->lnks, u->val); if(info){ fprintf(info, "BINARY_LINK\tF%d\t%c\tF%d\t%c\t%d\t%d\n", e->frg1, "+-"[e->dir1], e->frg2, "+-"[e->dir2], e->cov, e->off); fprintf(info, "BINARY_LINK\tF%d\t%c\tF%d\t%c\t%d\t%d\n", p->frg1, "+-"[p->dir1], p->frg2, "+-"[p->dir2], p->cov, p->off); } if(p->cov < e->cov){ cut_lnk_core_graph(g, p, WT_EDGE_CLOSED_HARD); u->val = f->idx; } else if(p->cov > e->cov){ cut_lnk_core_graph(g, e, WT_EDGE_CLOSED_HARD); } else { cut_lnk_core_graph(g, p, WT_EDGE_CLOSED_HARD); cut_lnk_core_graph(g, e, WT_EDGE_CLOSED_HARD); ret ++; } ret ++; } else { u->key = wid; u->val = f->idx; } } } } } free_UUhash(hash); return ret; } static inline u8i cut_low_cov_lnks_graph(Graph *g, int low_cov){ frg_t *n; edge_ref_t *f; lnk_t *e; u8i idx, nid, ret; u4i k; int max_cov; ret = 0; for(nid=0;nidfrgs->size;nid++){ n = ref_frgv(g->frgs, nid); if(n->closed) continue; for(k=0;k<2;k++){ max_cov = 0; idx = n->lnks[k].idx; while(idx){ f = ref_edgerefv(g->lrefs, idx); idx = f->next; e = ref_lnkv(g->lnks, f->idx); if(e->cov > max_cov) max_cov = e->cov; } if(max_cov <= low_cov || max_cov < (int)g->min_edge_cov) continue; idx = n->lnks[k].idx; while(idx){ f = ref_edgerefv(g->lrefs, idx); idx = f->next; e = ref_lnkv(g->lnks, f->idx); if(e->cov <= low_cov){ cut_lnk_core_graph(g, e, WT_EDGE_CLOSED_HARD); ret ++; } } } } return ret; } static inline u4i rescue_low_cov_transitive_edges_graph(Graph *g, u8i nid, u8v *edges, UUhash *hash){ node_t *n, *w, *v; edge_ref_t *f, *f2, *f3; edge_t *e, *e1, *e2; reg_t *r; UUhash_t *u; u8i idx, nid2, nid3; u4i i, k, k2, k3, k4, ret; int off1, off2, yes; n = ref_nodev(g->nodes, nid); if(n->closed) return 0; ret = 0; for(k=0;k<2;k++){ clear_UUhash(hash); clear_u8v(edges); idx = n->edges[k].idx; while(idx){ f = ref_edgerefv(g->erefs, idx); e = ref_edgev(g->edges, f->idx); //if(e->closed < WT_EDGE_CLOSED_LESS){ if(e->closed == 0){ put_UUhash(hash, (UUhash_t){f->flg? e->node1: e->node2, idx}); } else if(e->closed == WT_EDGE_CLOSED_LESS){ push_u8v(edges, idx); } idx = f->next; } if(edges->size <= 1) continue; for(i=0;isize;i++){ f = ref_edgerefv(g->erefs, edges->buffer[i]); e = ref_edgev(g->edges, f->idx); //if(e->status) continue; if(e->closed != WT_EDGE_CLOSED_LESS) continue; if(f->flg){ nid2 = e->node1; k2 = !e->dir1; } else { nid2 = e->node2; k2 = e->dir2; } yes = 0; w = ref_nodev(g->nodes, nid2); idx = w->edges[k2].idx; while(idx){ f2 = ref_edgerefv(g->erefs, idx); idx = f2->next; if(f2->flg){ nid3 = g->edges->buffer[f2->idx].node1; k3 = !g->edges->buffer[f2->idx].dir1; } else { nid3 = g->edges->buffer[f2->idx].node2; k3 = g->edges->buffer[f2->idx].dir2; } e2 = ref_edgev(g->edges, f2->idx); //if(e2->closed >= WT_EDGE_CLOSED_LESS) continue; if(e2->closed) continue; if((u = get_UUhash(hash, nid3)) == NULL) continue; f3 = ref_edgerefv(g->erefs, u->val); e1 = ref_edgev(g->edges, f3->idx); k4 = f3->flg? !e1->dir1 : e1->dir2; if(k3 != k4) continue; v = ref_nodev(g->nodes, nid3); off1 = off2 = (g->regs->buffer[n->regs.idx].end - g->regs->buffer[n->regs.idx].beg) + (g->regs->buffer[v->regs.idx].end - g->regs->buffer[v->regs.idx].beg); off1 += e1->off; off2 += e->off + e2->off + (g->regs->buffer[w->regs.idx].end - g->regs->buffer[w->regs.idx].beg); r = ref_regv(g->regs, w->regs.idx); //if(e->off + e2->off + (r->end - r->beg) >= longest) continue; if(num_diff(off1, off2) >= num_min(off1, off2)) continue; yes = 1; //revive_edge_graph(g, e); e->flag |= (1 << f->flg); ret ++; break; } if(0){ if(yes) continue; idx = w->edges[!k2].idx; while(idx){ f2 = ref_edgerefv(g->erefs, idx); idx = f2->next; if(f2->flg){ nid3 = g->edges->buffer[f2->idx].node1; k3 = !g->edges->buffer[f2->idx].dir1; } else { nid3 = g->edges->buffer[f2->idx].node2; k3 = g->edges->buffer[f2->idx].dir2; } e2 = ref_edgev(g->edges, f2->idx); if(e2->closed >= WT_EDGE_CLOSED_LESS) continue; if((u = get_UUhash(hash, nid3)) == NULL) continue; f3 = ref_edgerefv(g->erefs, u->val); e1 = ref_edgev(g->edges, f3->idx); k4 = f3->flg? !e1->dir1 : e1->dir2; if(k3 != k4) continue; v = ref_nodev(g->nodes, nid3); off1 = off2 = (g->regs->buffer[n->regs.idx].end - g->regs->buffer[n->regs.idx].beg) + (g->regs->buffer[w->regs.idx].end - g->regs->buffer[w->regs.idx].beg); off1 += e->off; off2 += e1->off + e2->off + (g->regs->buffer[v->regs.idx].end - g->regs->buffer[v->regs.idx].beg); r = ref_regv(g->regs, w->regs.idx); if(num_diff(off1, off2) >= num_min(off1, off2)) continue; yes = 1; //revive_edge_graph(g, e); e->flag |= (1 << f->flg); ret ++; break; } } } } return ret; } static inline u8i rescue_low_cov_edges_graph(Graph *g){ u8v *edges; UUhash *hash; u8i i, nid, ret; ret = 0; edges = init_u8v(32); hash = init_UUhash(13); for(i=0;iedges->size;i++) g->edges->buffer[i].flag = 0; for(nid=0;nidnodes->size;nid++){ rescue_low_cov_transitive_edges_graph(g, nid, edges, hash); } for(i=0;iedges->size;i++){ //if(g->edges->buffer[i].flag == 3){ if(g->edges->buffer[i].flag == 3){ revive_edge_graph(g, g->edges->buffer + i); ret ++; } g->edges->buffer[i].flag = 0; } free_u8v(edges); free_UUhash(hash); return ret; } static inline u8i rescue_high_cov_edges_graph(Graph *g, u4i max_step, u4i cov_cutoff){ tracev *path; trace_t *t; node_t *v, *w; edge_t *e; edge_ref_t *f; u8i node, vst, idx, fidx[3], ret; u4i k, d, i, cov[2]; for(node=0;nodenodes->size;node++){ v = ref_nodev(g->nodes, node); v->bt_visit = 0; } ret = 0; vst = 0; path = init_tracev(8); for(node=0;nodenodes->size;node++){ v = ref_nodev(g->nodes, node); if(v->closed) continue; for(k=0;k<2;k++){ if(v->edges[k].cnt != 1) continue; idx = v->edges[k].idx; cov[0] = cov[1] = 0; fidx[0] = fidx[1] = fidx[2] = 0; while(idx){ f = ref_edgerefv(g->erefs, idx); idx = f->next; e = ref_edgev(g->edges, f->idx); if(e->closed){ if(e->cov > cov[1]){ cov[1] = e->cov; fidx[1] = offset_edgerefv(g->erefs, f); } } else { cov[0] = e->cov; fidx[0] = offset_edgerefv(g->erefs, f); if(cov[0] >= cov_cutoff) break; } } if(cov[0] >= cov_cutoff){ continue; } if(cov[0] >= cov[1]){ continue; } clear_tracev(path); t = next_ref_tracev(path); t->node = node; t->dir = k; linear_trace_graph(g, path, max_step, NULL); if(path->size <= 2){ continue; } vst ++; for(i=1;isize;i++){ t = ref_tracev(path, i); w = ref_nodev(g->nodes, t->node); w->bt_visit = vst; } cov[1] = 0; fidx[1] = 0; idx = v->edges[k].idx; while(idx){ f = ref_edgerefv(g->erefs, idx); idx = f->next; e = ref_edgev(g->edges, f->idx); if(e->closed == 0) continue; w = ref_nodev(g->nodes, f->flg? e->node1 : e->node2); if(w->bt_visit == vst){ if(e->cov > cov[0]){ if(e->cov > cov[1]){ cov[1] = e->cov; fidx[1] = offset_edgerefv(g->erefs, f); } } } } if(fidx[1] == 0){ continue; } f = ref_edgerefv(g->erefs, fidx[1]); e = ref_edgev(g->edges, f->idx); if(f->flg){ w = ref_nodev(g->nodes, e->node1); d = e->dir1; } else { w = ref_nodev(g->nodes, e->node2); d = !e->dir2; } f = first_living_edge_graph(g, w, d, NULL); // assert f != NULL if(f == NULL){ continue; } fidx[2] = offset_edgerefv(g->erefs, f); { e = ref_edgev(g->edges, ref_edgerefv(g->erefs, fidx[0])->idx); cut_edge_graph(g, e); e = ref_edgev(g->edges, ref_edgerefv(g->erefs, fidx[2])->idx); cut_edge_graph(g, e); e = ref_edgev(g->edges, ref_edgerefv(g->erefs, fidx[1])->idx); revive_edge_graph(g, e); ret ++; } } } free_tracev(path); return ret; } static inline u8i cut_relative_low_cov_edges_graph(Graph *g, float lowf){ node_t *n; edge_t *e; edge_ref_t *f; u4v *ecovs, *emaxs; u8i idx, x, ret; u4i k, max, min, val, i; for(idx=0;idxedges->size;idx++){ e = ref_edgev(g->edges, idx); e->flag = 0; } ecovs = init_u4v(64); emaxs = init_u4v(64); ret = 0; for(idx=0;idxnodes->size;idx++){ n = ref_nodev(g->nodes, idx); if(n->closed) continue; clear_u4v(ecovs); max = 0; min = WT_MAX_EDGE_COV; for(k=0;k<2;k++){ x = n->edges[k].idx; while(x){ f = ref_edgerefv(g->erefs, x); x = f->next; e = ref_edgev(g->edges, f->idx); if(e->closed) continue; if(e->cov > max) max = e->cov; if(e->cov < min) min = e->cov; push_u4v(ecovs, (Int(e->off) << 12) | (e->cov)); } } if(min >= max * lowf){ continue; } min = max * lowf; sort_array(ecovs->buffer, ecovs->size, u4i, num_cmpgt(Int(a) >> 12, Int(b) >> 12)); clear_u4v(emaxs); max = 0; for(i=ecovs->size;i>0;i--){ val = ecovs->buffer[i - 1] & 0xFFF; if(val > max) max = val; push_u4v(emaxs, max); } reverse_u4v(emaxs); for(k=0;k<2;k++){ x = n->edges[k].idx; while(x){ f = ref_edgerefv(g->erefs, x); x = f->next; e = ref_edgev(g->edges, f->idx); if(e->closed) continue; if(e->cov >= min) continue; for(i=0;isize;i++){ if(e->off >= (Int(ecovs->buffer[i]) >> 12)){ break; } } if(i == ecovs->size) continue; // Never happen if(e->cov < lowf * emaxs->buffer[i]){ cut_edge_graph(g, e); ret ++; } } } } free_u4v(ecovs); free_u4v(emaxs); return ret; } static inline u4i rescue_low_cov_tip_edges_core(Graph *g, u8i nid){ node_t *n, *w, *ww; edge_t *e, *ee; edge_ref_t *f; u8i idx, wid; u4i k, dir, ret; n = ref_nodev(g->nodes, nid); if(n->closed) return 0; if(n->edges[0].cnt == 0 && n->edges[1].cnt == 0) return 0; ret = 0; for(k=0;k<2;k++){ if(n->edges[k].cnt) continue; idx = n->edges[k].idx; ee = NULL; ww = NULL; while(idx){ f = ref_edgerefv(g->erefs, idx); idx = f->next; e = ref_edgev(g->edges, f->idx); if(f->flg){ wid = e->node1; dir = !e->dir1; } else { wid = e->node2; dir = e->dir2; } w = ref_nodev(g->nodes, wid); //if(w->edges[!dir].cnt) continue; if(w->edges[dir].cnt == 0) continue; if(ee == NULL || e->cov > ee->cov || (e->cov == ee->cov && w->regs.cnt > ww->regs.cnt)){ ee = e; ww = w; } } if(ee){ revive_edge_graph(g, ee); ret ++; } } return ret; } static inline u8i rescue_low_cov_tip_edges_graph(Graph *g){ u8v *edges; UUhash *hash; u8i nid, ret; ret = 0; edges = init_u8v(32); hash = init_UUhash(13); for(nid=0;nidnodes->size;nid++){ ret += rescue_low_cov_tip_edges_core(g, nid); } free_u8v(edges); free_UUhash(hash); return ret; } static inline int rescue_mercy_edge_core_graph(Graph *g, u4i rid, BitVec *tips[2]){ read_t *rd; edge_t *e; edge_ref_t *f; reg_t *r, *s; u8i idx; int c, d, ret; rd = ref_readv(g->reads, rid); if(rd->regs.cnt < 2) return 0; idx = rd->regs.idx; s = NULL; c = 0; ret = 0; while(idx){ r = ref_regv(g->regs, idx); idx = r->read_link; if(r->closed) continue; if(!(r->beg >= rd->clps[0] && r->end <= rd->clps[1])) continue; if(g->nodes->buffer[r->node].closed) continue; d = 0; if(get_bitvec(tips[0], r->node)){ d |= 1; } if(get_bitvec(tips[1], r->node)){ d |= 2; } if(d == 3) continue; if(s){ if(d == (1 << (!r->dir))){ f = edge_node2node_graph(g, s->node, (0b100 >> c) & 0x01, r->node, !((0b100 >> d) & 0x01)); if(f){ e = ref_edgev(g->edges, f->idx); revive_edge_graph(g, e); zero_bitvec(tips[e->dir1], e->node1); zero_bitvec(tips[!e->dir2], e->node1); ret ++; #ifdef __DEBUG__ } else { fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); #endif } s = NULL; continue; } else { s = NULL; } } if(d == (1 << (r->dir))){ s = r; c = d; } } return ret; } static inline u8i rescue_mercy_edges_graph(Graph *g){ BitVec *tips[2]; node_t *n; u8i i, ret; ret = 0; tips[0] = init_bitvec(g->nodes->size); tips[1] = init_bitvec(g->nodes->size); for(i=0;inodes->size;i++){ n = ref_nodev(g->nodes, i); if(n->closed) continue; if(n->edges[0].cnt == 0) one_bitvec(tips[0], i); if(n->edges[1].cnt == 0) one_bitvec(tips[1], i); } for(i=0;ireads->size;i++){ ret += rescue_mercy_edge_core_graph(g, i, tips); } free_bitvec(tips[0]); free_bitvec(tips[1]); return ret; } static inline u4i rescue_weak_tip_lnks_core(Graph *g, u8i nid){ frg_t *n, *w, *ww; lnk_t *e, *ee; edge_ref_t *f; u8i idx, wid; u4i k, dir, ret; n = ref_frgv(g->frgs, nid); if(n->closed) return 0; if(n->lnks[0].cnt == 0 && n->lnks[1].cnt == 0) return 0; ret = 0; for(k=0;k<2;k++){ if(n->lnks[k].cnt) continue; idx = n->lnks[k].idx; ee = NULL; ww = NULL; while(idx){ f = ref_edgerefv(g->lrefs, idx); idx = f->next; e = ref_lnkv(g->lnks, f->idx); if(e->closed) continue; if(e->weak == 0) continue; if(f->flg){ wid = e->frg1; dir = !e->dir1; } else { wid = e->frg2; dir = e->dir2; } w = ref_frgv(g->frgs, wid); if(w->lnks[!dir].cnt) continue; if(ee == NULL){ ee = e; ww = w; } else { ee = NULL; break; } } if(ee){ revive_lnk_graph(g, ee); ret ++; } } return ret; } static inline u8i rescue_weak_tip_lnks2_graph(Graph *g){ u8i nid, ret; ret = 0; for(nid=0;nidfrgs->size;nid++){ ret += rescue_weak_tip_lnks_core(g, nid); } return ret; } static inline u8i rescue_weak_tip_lnks_graph(Graph *g){ pathv *heap; u8v *weaks[2]; frg_t *n; lnk_t *e; edge_ref_t *f; u8i nid, i, vst, idx, eidx, ret; u4i k; int max_len; weaks[0] = init_u8v(g->frgs->size); weaks[1] = init_u8v(g->frgs->size); ret = 0; for(nid=0;nidfrgs->size;nid++){ n = ref_frgv(g->frgs, nid); n->bt_visit = 0; } heap = init_pathv(32); vst = 1; for(nid=0;nidfrgs->size;nid++){ n = ref_frgv(g->frgs, nid); for(k=0;k<2;k++){ if(n->lnks[k].cnt){ eidx = 0; } else { idx = n->lnks[k].idx; eidx = 0; while(idx){ f = ref_edgerefv(g->lrefs, idx); e = ref_lnkv(g->lnks, f->idx); if(e->closed && e->weak){ if(eidx == 0) eidx = f->idx; else eidx = MAX_VALUE_U8; } idx = f->next; } } if(eidx != 0 && eidx != MAX_VALUE_U8){ e = ref_lnkv(g->lnks, eidx); max_len = wander_path_graph(g, nid, k, heap, vst, e->off); if(max_len >= e->off){ eidx |= 1LLU << 63; } } push_u8v(weaks[k], eidx); } } free_pathv(heap); for(k=0;k<2;k++){ for(i=0;isize;i++){ if(weaks[k]->buffer[i] == 0 || weaks[k]->buffer[i] == MAX_VALUE_U8) continue; e = ref_lnkv(g->lnks, weaks[k]->buffer[i] & (MAX_VALUE_U8 >> 1)); if(i != e->frg1) continue; if((weaks[0]->buffer[e->frg2] & (MAX_VALUE_U8 >> 1)) == (weaks[k]->buffer[i] & (MAX_VALUE_U8 >> 1))){ if(!(weaks[0]->buffer[e->frg2] & (1LLU < 63)) || !(weaks[k]->buffer[i] & (1LLU << 63))){ ret ++; revive_lnk_graph(g, e); } } if((weaks[1]->buffer[e->frg2] & (MAX_VALUE_U8 >> 1)) == (weaks[k]->buffer[i] & (MAX_VALUE_U8 >> 1))){ if(!(weaks[1]->buffer[e->frg2] & (1LLU < 63)) || !(weaks[k]->buffer[i] & (1LLU << 63))){ ret ++; revive_lnk_graph(g, e); } } } } free_u8v(weaks[0]); free_u8v(weaks[1]); return ret; } static inline int _scoring_edge_orders(Graph *g, u8i fidx){ edge_ref_t *f; edge_t *e; node_t *n; int score; f = ref_edgerefv(g->erefs, fidx); e = ref_edgev(g->edges, f->idx); n = ref_nodev(g->nodes, f->flg? e->node1 : e->node2); score = e->off + (n->regs.cnt * -5) + (e->cov * -5); return score; } static inline u4i reduce_transitive_edges_core_graph(Graph *g, u8i nid, u8v *edges, UUhash *hash, u4i closed_val){ node_t *n, *w, *v; edge_ref_t *f, *f2, *f3; edge_t *e, *e1, *e2; UUhash_t *u; u8i idx, nid2, nid3; u4i i, k, k2, k3, k4, ret; int off1, off2; n = ref_nodev(g->nodes, nid); if(n->closed) return 0; ret = 0; for(k=0;k<2;k++){ clear_UUhash(hash); clear_u8v(edges); idx = n->edges[k].idx; while(idx){ f = ref_edgerefv(g->erefs, idx); e = ref_edgev(g->edges, f->idx); if(e->closed < closed_val){ put_UUhash(hash, (UUhash_t){f->flg? e->node1: e->node2, (idx << 1) | e->closed}); push_u8v(edges, idx); } idx = f->next; } if(edges->size <= 1) continue; // sort the edges by composition of e->off and e->cov //sort_array(edges->buffer, edges->size, u8i, num_cmpgt(_scoring_edge_orders(g, a), _scoring_edge_orders(g, b))); for(i=0;isize;i++){ f = ref_edgerefv(g->erefs, edges->buffer[i]); e = ref_edgev(g->edges, f->idx); if(f->flg){ nid2 = e->node1; k2 = !e->dir1; } else { nid2 = e->node2; k2 = e->dir2; } w = ref_nodev(g->nodes, nid2); idx = w->edges[k2].idx; while(idx){ f2 = ref_edgerefv(g->erefs, idx); idx = f2->next; if(f2->flg){ nid3 = g->edges->buffer[f2->idx].node1; k3 = !g->edges->buffer[f2->idx].dir1; } else { nid3 = g->edges->buffer[f2->idx].node2; k3 = g->edges->buffer[f2->idx].dir2; } e2 = ref_edgev(g->edges, f2->idx); //if(e2->closed) continue; if(e2->closed >= closed_val) continue; if((u = get_UUhash(hash, nid3)) == NULL) continue; if(u->val & 0x01) continue; // already deleted f3 = ref_edgerefv(g->erefs, u->val >> 1); e1 = ref_edgev(g->edges, f3->idx); k4 = f3->flg? !e1->dir1 : e1->dir2; if(k3 != k4) continue; v = ref_nodev(g->nodes, nid3); off1 = off2 = (g->regs->buffer[n->regs.idx].end - g->regs->buffer[n->regs.idx].beg) + (g->regs->buffer[v->regs.idx].end - g->regs->buffer[v->regs.idx].beg); off1 += e1->off; off2 += e->off + e2->off + (g->regs->buffer[w->regs.idx].end - g->regs->buffer[w->regs.idx].beg); // check whether off1 and off2 diff too much if(num_diff(off1, off2) >= num_min(off1, off2)) continue; u->val |= 1; } } reset_iter_UUhash(hash); while((u = ref_iter_UUhash(hash))){ if(u->val & 0x01){ e = ref_edgev(g->edges, ref_edgerefv(g->erefs, u->val >> 1)->idx); if(e->closed == WT_EDGE_CLOSED_NULL){ cut_edge_graph(g, e); ret ++; } } } } return ret; } static inline u8i reduce_transitive_edges_graph(Graph *g){ u8v *edges; UUhash *hash; u8i nid, ret; ret = 0; edges = init_u8v(32); hash = init_UUhash(13); for(nid=0;nidnodes->size;nid++){ ret += reduce_transitive_edges_core_graph(g, nid, edges, hash, 2); } free_u8v(edges); free_UUhash(hash); return ret; } static inline void set_init_ends_graph(Graph *g){ node_t *n; u8i nid; for(nid=0;nidnodes->size;nid++){ n = ref_nodev(g->nodes, nid); if(n->edges[0].cnt == 0 || n->edges[1].cnt == 0){ n->init_end = 1; } } } // node_t->unvisit is used to indicate vacant, inplay and eliminated static inline u4i myers_transitive_reduction_core_graph(Graph *g, u8i nid, float _fuzz, int closed){ node_t *n, *w, *x; edge_ref_t *f, *f2; edge_t *e, *e2; u8i idx, idx2; u4i k, k2, ret; int longest, len, fuzz; n = ref_nodev(g->nodes, nid); if(n->closed) return 0; ret = 0; for(k=0;k<2;k++){ longest = 0; idx = n->edges[k].idx; while(idx){ f = ref_edgerefv(g->erefs, idx); e = ref_edgev(g->edges, f->idx); //if(e->closed == 0 && !(e->flag & (1 << f->flg))){ if(e->closed <= closed){ w = ref_nodev(g->nodes, f->flg? e->node1 : e->node2); w->unvisit = 1; // inplay len = e->off + g->reglen; if(len > longest) longest = len; } idx = f->next; } fuzz = (int)_fuzz; if(longest * (_fuzz - fuzz) > fuzz) fuzz = longest * (_fuzz - fuzz); longest += fuzz; idx = n->edges[k].idx; while(idx){ f = ref_edgerefv(g->erefs, idx); e = ref_edgev(g->edges, f->idx); //if(e->closed == 0 && !(e->flag & (1 << f->flg))){ if(e->closed <= closed){ w = ref_nodev(g->nodes, f->flg? e->node1 : e->node2); if(w->unvisit == 1){ k2 = f->flg? !e->dir1 : e->dir2; idx2 = w->edges[k2].idx; while(idx2){ f2 = ref_edgerefv(g->erefs, idx2); e2 = ref_edgev(g->edges, f2->idx); // TODO: check the strand //if(e2->closed == 0 && !(e2->flag & (1 << f2->flg))){ if(e2->closed <= closed){ x = ref_nodev(g->nodes, f2->flg? e2->node1 : e2->node2); if(x->unvisit == 1){ len = e->off + e2->off + g->reglen; if(len <= longest){ x->unvisit = 2; // eliminated } } } idx2 = f2->next; } } } idx = f->next; } idx = n->edges[k].idx; while(idx){ f = ref_edgerefv(g->erefs, idx); e = ref_edgev(g->edges, f->idx); //if(e->closed == 0 && !(e->flag & (1 << f->flg))){ if(e->closed <= closed){ w = ref_nodev(g->nodes, f->flg? e->node1 : e->node2); //if(w->unvisit == 1){ k2 = f->flg? !e->dir1 : e->dir2; idx2 = w->edges[k2].idx; while(idx2){ f2 = ref_edgerefv(g->erefs, idx2); e2 = ref_edgev(g->edges, f2->idx); //if(e2->closed == 0 && !(e2->flag & (1 << f2->flg))){ if(e2->closed <= closed){ x = ref_nodev(g->nodes, f2->flg? e2->node1 : e2->node2); if(x->unvisit == 1){ if(e2->off <= fuzz || idx2 == w->edges[k2].idx){ x->unvisit = 2; // eliminated } } } idx2 = f2->next; } //} } idx = f->next; } idx = n->edges[k].idx; while(idx){ f = ref_edgerefv(g->erefs, idx); e = ref_edgev(g->edges, f->idx); //if(e->closed == 0 && !(e->flag & (1 << f->flg))){ if(e->closed <= closed){ w = ref_nodev(g->nodes, f->flg? e->node1 : e->node2); if(w->unvisit == 2){ e->flag |= 1 << f->flg; ret ++; } w->unvisit = 0; } idx = f->next; } } return ret; } static inline u8i myers_transitive_reduction_graph(Graph *g, float fuzz){ node_t *n; edge_t *e; u8i nid, eid, ret; for(nid=0;nidnodes->size;nid++){ n = ref_nodev(g->nodes, nid); n->unvisit = 0; // vacant } for(eid=0;eidedges->size;eid++){ e = ref_edgev(g->edges, eid); e->flag = 0; } for(nid=0;nidnodes->size;nid++){ n = ref_nodev(g->nodes, nid); if(n->closed) continue; myers_transitive_reduction_core_graph(g, nid, fuzz, WT_EDGE_CLOSED_NULL); } ret = 0; for(eid=0;eidedges->size;eid++){ e = ref_edgev(g->edges, eid); if(e->flag == 3){ cut_edge_graph(g, e); ret ++; } e->flag = 0; } return ret; } static inline u4i myers_transitive_reduction_core_frg_graph(Graph *g, u8i nid, float _fuzz){ frg_t *n, *w, *x; edge_ref_t *f, *f2; lnk_t *e, *e2; u8i idx, idx2; u4i k, k2, ret; int longest, len, fuzz; n = ref_frgv(g->frgs, nid); if(n->closed) return 0; ret = 0; for(k=0;k<2;k++){ longest = 0; idx = n->lnks[k].idx; while(idx){ f = ref_edgerefv(g->lrefs, idx); e = ref_lnkv(g->lnks, f->idx); //if(e->closed == 0 && !(e->flag & (1 << f->flg))){ if(e->closed == 0){ w = ref_frgv(g->frgs, f->flg? e->frg1 : e->frg2); w->unvisit = 1; // inplay len = e->off + g->reglen; if(len > longest) longest = len; } idx = f->next; } fuzz = (int)_fuzz; if(longest * (_fuzz - fuzz) > fuzz) fuzz = longest * (_fuzz - fuzz); longest += fuzz; idx = n->lnks[k].idx; while(idx){ f = ref_edgerefv(g->lrefs, idx); e = ref_lnkv(g->lnks, f->idx); //if(e->closed == 0 && !(e->flag & (1 << f->flg))){ if(e->closed == 0){ w = ref_frgv(g->frgs, f->flg? e->frg1 : e->frg2); if(w->unvisit == 1){ k2 = f->flg? !e->dir1 : e->dir2; idx2 = w->lnks[k2].idx; while(idx2){ f2 = ref_edgerefv(g->lrefs, idx2); e2 = ref_lnkv(g->lnks, f2->idx); // TODO: check the strand //if(e2->closed == 0 && !(e2->flag & (1 << f2->flg))){ if(e2->closed == 0){ x = ref_frgv(g->frgs, f2->flg? e2->frg1 : e2->frg2); if(x->unvisit == 1){ len = e->off + e2->off + g->reglen; if(len <= longest){ x->unvisit = 2; // eliminated } } } idx2 = f2->next; } } } idx = f->next; } idx = n->lnks[k].idx; while(idx){ f = ref_edgerefv(g->lrefs, idx); e = ref_lnkv(g->lnks, f->idx); //if(e->closed == 0 && !(e->flag & (1 << f->flg))){ if(e->closed == 0){ w = ref_frgv(g->frgs, f->flg? e->frg1 : e->frg2); //if(w->unvisit == 1){ k2 = f->flg? !e->dir1 : e->dir2; idx2 = w->lnks[k2].idx; while(idx2){ f2 = ref_edgerefv(g->lrefs, idx2); e2 = ref_lnkv(g->lnks, f2->idx); //if(e2->closed == 0 && !(e2->flag & (1 << f2->flg))){ if(e2->closed == 0){ x = ref_frgv(g->frgs, f2->flg? e2->frg1 : e2->frg2); if(x->unvisit == 1){ if(e2->off <= fuzz || idx2 == w->lnks[k2].idx){ x->unvisit = 2; // eliminated } } } idx2 = f2->next; } //} } idx = f->next; } idx = n->lnks[k].idx; while(idx){ f = ref_edgerefv(g->lrefs, idx); e = ref_lnkv(g->lnks, f->idx); //if(e->closed == 0 && !(e->flag & (1 << f->flg))){ if(e->closed == 0){ w = ref_frgv(g->frgs, f->flg? e->frg1 : e->frg2); if(w->unvisit == 2){ e->flag |= 1 << f->flg; ret ++; } w->unvisit = 0; } idx = f->next; } } return ret; } static inline u8i myers_transitive_reduction_frg_graph(Graph *g, float fuzz){ frg_t *n; lnk_t *e; u8i nid, eid, ret; for(nid=0;nidfrgs->size;nid++){ n = ref_frgv(g->frgs, nid); n->unvisit = 0; // vacant } for(eid=0;eidlnks->size;eid++){ e = ref_lnkv(g->lnks, eid); e->flag = 0; } for(nid=0;nidfrgs->size;nid++){ n = ref_frgv(g->frgs, nid); if(n->closed) continue; myers_transitive_reduction_core_frg_graph(g, nid, fuzz); } ret = 0; for(eid=0;eidlnks->size;eid++){ e = ref_lnkv(g->lnks, eid); if(e->flag == 3){ cut_lnk_graph(g, e); ret ++; } e->flag = 0; } return ret; } static inline u4i detach_repetitive_frg_core_graph(Graph *g, u8i nid, u4i max_dist, u8i visit, u8v *nds, u8v *heap){ frg_t *n, *w, *x; edge_ref_t *f; lnk_t *e; u8i idx, wid, xid, eid; u4i k, i, j, bidx, bcnt[2]; int off; n = ref_frgv(g->frgs, nid); n->bt_visit = visit; clear_u8v(nds); clear_u8v(heap); for(k=0;k<2;k++){ bcnt[k] = 0; idx = n->lnks[k].idx; while(idx){ f = ref_edgerefv(g->lrefs, idx); e = ref_lnkv(g->lnks, f->idx); idx = f->next; if(e->closed) continue; wid = f->flg? e->frg1 : e->frg2; w = ref_frgv(g->frgs, wid); if(w->bt_visit == visit){ // TODO: remove the fprintf after debug fprintf(stderr, " -- F%llu:%c -> F%llu:%c already visited in %s -- %s:%d --\n", nid, "+-"[k], wid, "+-"[w->rep_dir], __FUNCTION__, __FILE__, __LINE__); fflush(stderr); return 0; } push_u8v(nds, wid); w->bt_visit = visit; w->rep_dir = f->flg? !e->dir1 : e->dir2; w->bt_idx = (bcnt[k] << 1) | k; bcnt[k] ++; off = n->len / 2 + e->off; if(off < 0) off = 0; w->rep_idx = off + w->len; // rep_idx is used as dist if(w->rep_idx < max_dist){ array_heap_push(heap->buffer, heap->size, heap->cap, u8i, wid, num_cmp(g->frgs->buffer[a].rep_idx, g->frgs->buffer[b].rep_idx)); } } } if(bcnt[0] == 0 || bcnt[1] == 0) return 0; if(bcnt[0] < 2 && bcnt[1] < 2) return 0; // extending branches to max_dist in length while(heap->size){ wid = heap->buffer[0]; array_heap_remove(heap->buffer, heap->size, heap->cap, u8i, 0, num_cmp(g->frgs->buffer[a].rep_idx, g->frgs->buffer[b].rep_idx)); w = ref_frgv(g->frgs, wid); idx = w->lnks[w->rep_dir].idx; while(idx){ f = ref_edgerefv(g->lrefs, idx); e = ref_lnkv(g->lnks, f->idx); idx = f->next; if(e->closed) continue; xid = f->flg? e->frg1 : e->frg2; x = ref_frgv(g->frgs, xid); if(x->bt_visit == visit) continue; off = w->rep_idx + e->off; if(off < 0) off = 0; if(off > (int)max_dist) continue; push_u8v(nds, xid); x->bt_visit = visit; x->rep_dir = f->flg? !e->dir1 : e->dir2; x->bt_idx = w->bt_idx; x->rep_idx = off + x->len; if(x->rep_idx < max_dist){ array_heap_push(heap->buffer, heap->size, heap->cap, u8i, xid, num_cmp(g->frgs->buffer[a].rep_idx, g->frgs->buffer[b].rep_idx)); } } } // find cross links encap_and_zeros_u8v(heap, bcnt[0] * bcnt[1]); // reuse heap as matrix for(i=0;isize;i++){ wid = nds->buffer[i]; w = ref_frgv(g->frgs, wid); idx = w->lnks[!w->rep_dir].idx; while(idx){ f = ref_edgerefv(g->lrefs, idx); e = ref_lnkv(g->lnks, f->idx); idx = f->next; if(e->closed == WT_EDGE_CLOSED_HARD) continue; xid = f->flg? e->frg1 : e->frg2; if(xid == nid) continue; x = ref_frgv(g->frgs, xid); if(x->bt_visit != visit) continue; if(((w->bt_idx ^ x->bt_idx) & 0x01) == 0) continue; if(w->bt_idx & 0x01){ if(x->bt_idx & 0x01){ continue; } else { bidx = (x->bt_idx >> 1) * bcnt[1] + (w->bt_idx >> 1); } } else { if(x->bt_idx & 0x01){ bidx = (w->bt_idx >> 1) * bcnt[1] + (x->bt_idx >> 1); } else { continue; } } eid = heap->buffer[bidx]; if(eid == 0 || e->cov > g->lnks->buffer[eid].cov){ heap->buffer[bidx] = eid = f->idx; } } } // find one-left to one-right links clear_u8v(nds); // will reuse nds to store bidx for(i=0;ibuffer[i * bcnt[1] + j]){ if(k < bcnt[1]){ k = bcnt[1]; break; } else { k = j; } } } for(j=0;kbuffer[j * bcnt[1] + k]){ k = bcnt[1]; break; } } if(k == bcnt[1]) continue; push_u8v(nds, i * bcnt[1] + k); } // detach repeats for(i=0;isize;i++){ //bid[0] = nds->buffer[i] / bcnt[0]; //bid[1] = nds->buffer[i] % bcnt[0]; for(k=0;k<2;k++){ idx = n->lnks[k].idx; bidx = k? (nds->buffer[i] % bcnt[0]) : (nds->buffer[i] / bcnt[0]); while(idx){ f = ref_edgerefv(g->lrefs, idx); e = ref_lnkv(g->lnks, f->idx); idx = f->next; if(e->closed) continue; wid = f->flg? e->frg1 : e->frg2; w = ref_frgv(g->frgs, wid); if((w->bt_idx >> 1) == bidx){ //cut_lnk_graph(g, e); cut_lnk_core_graph(g, e, WT_EDGE_CLOSED_HARD); // in case of loop cut and revive } } } } for(i=0;isize;i++){ eid = heap->buffer[nds->buffer[i]]; e = ref_lnkv(g->lnks, eid); revive_lnk_graph(g, e); } return nds->size; } static inline u4i detach_repetitive_frg_graph(Graph *g, u4i max_dist){ u8v *nds; u8v *heap; frg_t *n; u8i nid, visit; u4i ret; nds = init_u8v(32); heap = init_u8v(32); ret = 0; for(nid=0;nidfrgs->size;nid++){ n = ref_frgv(g->frgs, nid); n->bt_visit = 0; } visit = 0; ret = 0; for(nid=0;nidfrgs->size;nid++){ n = ref_frgv(g->frgs, nid); if(n->lnks[0].cnt == 0 || n->lnks[1].cnt == 0) continue; if(n->lnks[0].cnt < 2 && n->lnks[1].cnt < 2) continue; ret += detach_repetitive_frg_core_graph(g, nid, max_dist, ++visit, nds, heap); } free_u8v(nds); free_u8v(heap); for(nid=0;nidfrgs->size;nid++){ n = ref_frgv(g->frgs, nid); n->bt_visit = 0; } return ret; } static inline u4i reduce_transitive_lnks_core_graph(Graph *g, u8i nid, u8v *lnks, UUhash *hash, u4i closed_val){ frg_t *n, *w, *v; edge_ref_t *f, *f2, *f3; lnk_t *e, *e1, *e2; UUhash_t *u; u8i idx, nid2, nid3; u4i i, k, k2, k3, k4, ret; int off1, off2; n = ref_frgv(g->frgs, nid); if(n->closed) return 0; ret = 0; for(k=0;k<2;k++){ clear_UUhash(hash); clear_u8v(lnks); idx = n->lnks[k].idx; while(idx){ f = ref_edgerefv(g->lrefs, idx); e = ref_lnkv(g->lnks, f->idx); if(e->closed < closed_val){ put_UUhash(hash, (UUhash_t){f->flg? e->frg1: e->frg2, (idx << 1) | e->closed}); push_u8v(lnks, idx); } idx = f->next; } if(lnks->size <= 1) continue; // sort the lnks by composition of e->off and e->cov //sort_array(lnks->buffer, lnks->size, u8i, num_cmpgt(_scoring_lnk_orders(g, a), _scoring_lnk_orders(g, b))); for(i=0;isize;i++){ f = ref_edgerefv(g->lrefs, lnks->buffer[i]); e = ref_lnkv(g->lnks, f->idx); if(f->flg){ nid2 = e->frg1; k2 = !e->dir1; } else { nid2 = e->frg2; k2 = e->dir2; } w = ref_frgv(g->frgs, nid2); idx = w->lnks[k2].idx; while(idx){ f2 = ref_edgerefv(g->lrefs, idx); idx = f2->next; if(f2->flg){ nid3 = g->lnks->buffer[f2->idx].frg1; k3 = !g->lnks->buffer[f2->idx].dir1; } else { nid3 = g->lnks->buffer[f2->idx].frg2; k3 = g->lnks->buffer[f2->idx].dir2; } e2 = ref_lnkv(g->lnks, f2->idx); //if(e2->closed) continue; if(e2->closed >= closed_val) continue; if((u = get_UUhash(hash, nid3)) == NULL) continue; if(u->val & 0x01) continue; // already deleted f3 = ref_edgerefv(g->lrefs, u->val >> 1); e1 = ref_lnkv(g->lnks, f3->idx); k4 = f3->flg? !e1->dir1 : e1->dir2; if(k3 != k4) continue; v = ref_frgv(g->frgs, nid3); off1 = off2 = n->len + v->len; off1 += e1->off; off2 += e->off + e2->off + w->len; // check whether off1 and off2 diff too much if(num_diff(off1, off2) >= num_min(off1, off2)) continue; u->val |= 1; } } reset_iter_UUhash(hash); while((u = ref_iter_UUhash(hash))){ if(u->val & 0x01){ e = ref_lnkv(g->lnks, ref_edgerefv(g->lrefs, u->val >> 1)->idx); if(e->closed == WT_EDGE_CLOSED_NULL){ cut_lnk_graph(g, e); ret ++; } } } } return ret; } static inline u8i reduce_transitive_lnks_graph(Graph *g){ u8v *lnks; UUhash *hash; u8i nid, ret; ret = 0; lnks = init_u8v(32); hash = init_UUhash(13); for(nid=0;nidfrgs->size;nid++){ ret += reduce_transitive_lnks_core_graph(g, nid, lnks, hash, 2); } free_u8v(lnks); free_UUhash(hash); return ret; } static inline u8i trim_tip_core_graph(Graph *g, uint16_t max_step, tracev *path, u8i nid, int hard_trim){ trace_t *t, T; node_t *n; edge_ref_t *f; edge_t *e; u8i ret, idx; u4i i, dir, step, step2, found, n_in; int msg1, msg2; if(g->cut_tip == 0) return 0; ret = 0; n = ref_nodev(g->nodes, nid); if(n->closed) return 0; if(n->edges[0].cnt == 1 && n->edges[1].cnt == 0){ dir = 0; } else if(n->edges[0].cnt == 0 && n->edges[1].cnt == 1){ dir = 1; } else { return 0; } clear_tracev(path); t = next_ref_tracev(path); t->node = nid; t->edges[0] = EDGE_REF_NULL; t->edges[1] = EDGE_REF_NULL; t->dir = dir; msg1 = WT_TRACE_MSG_ZERO; step = linear_trace_graph(g, path, max_step, &msg1) + 1; if(step > max_step) return 0; //if(msg1 != -1 - WT_TRACE_MSG_MORE && msg1 != WT_TRACE_MSG_MORE) return 0; if(msg1 == WT_TRACE_MSG_MORE){ if(!hard_trim) return 0; path->size --; } else if(msg1 == -1 - WT_TRACE_MSG_MORE){ t = ref_tracev(path, path->size); // please see linear_trace_graph n = ref_nodev(g->nodes, t->node); dir = !t->dir; n_in = 0; idx = n->edges[dir].idx; found = 0; while(idx){ f = ref_edgerefv(g->erefs, idx); idx = f->next; if(f->idx == t->edges[dir].idx) continue; e = g->edges->buffer + f->idx; if(e->closed) continue; n_in ++; T.node = f->flg? e->node1 : e->node2; T.dir = f->flg? !e->dir1 : e->dir2; step2 = count_linear_trace_graph(g, &T, step + 1, &msg2) + 1; if(msg2 != WT_TRACE_MSG_ZERO) step2 ++; if(step2 > step){ found = 1; break; } else if(step2 == step && (e->cov > g->edges->buffer[t->edges[dir].idx].cov || (step == 1 && e->cov == g->edges->buffer[t->edges[dir].idx].cov && e->off >= g->edges->buffer[t->edges[dir].idx].off))){ found = 1; break; } //if(step2 + 1 >= step && msg2 != WT_TRACE_MSG_ZERO){ found = 1; break; } } if(!found) return 0; } else return 0; for(i=0;isize;i++){ del_node_graph(g, ref_nodev(g->nodes, path->buffer[i].node)); //del_node_edges_graph(g, ref_nodev(g->nodes, path->buffer[i].node)); ret ++; } return ret; } static inline u8i trim_tips_graph(Graph *g, uint16_t max_step, int hard_trim){ tracev *path; node_t *n; u8i ret, nid; ret = 0; path = init_tracev(32); for(nid=0;nidnodes->size;nid++){ n = ref_nodev(g->nodes, nid); if(n->closed) continue; if(trim_tip_core_graph(g, max_step, path, nid, hard_trim)) ret ++; } free_tracev(path); return ret; } // careful sharp_tip -> blunt_tip -> sharp_tip and so on static inline u4i trim_blunt_tip_core_graph(Graph *g, u8i nid){ node_t *n; int k; if(g->cut_tip == 0) return 0; n = ref_nodev(g->nodes, nid); if(n->edges[0].cnt && n->edges[1].cnt) return 0; k = (n->edges[0].cnt == 0); if(n->edges[k].cnt < 2) return 0; del_node_graph(g, n); return 1; } static inline u8i trim_blunt_tips_graph(Graph *g){ node_t *n; u8i ret, nid; ret = 0; for(nid=0;nidnodes->size;nid++){ n = ref_nodev(g->nodes, nid); if(n->closed) continue; if(trim_blunt_tip_core_graph(g, nid)) ret ++; } return ret; } static inline u8i trim_frgtip_core_graph(Graph *g, int max_len, pathv *path, u8i nid){ path_t *t, T; frg_t *n; edge_ref_t *f; lnk_t *e; u8i ret, idx; u4i i, dir, found, n_in; int len, len2; int msg1, msg2; if(g->cut_tip == 0) return 0; ret = 0; n = ref_frgv(g->frgs, nid); if(n->closed) return 0; first_living_lnk_graph(g, n, 0, &msg1); first_living_lnk_graph(g, n, 1, &msg2); if(msg1 != WT_TRACE_MSG_ZERO){ if(msg2 != WT_TRACE_MSG_ZERO) return 0; dir = 0; } else if(msg2 != WT_TRACE_MSG_ZERO){ dir = 1; } else return 0; clear_pathv(path); t = next_ref_pathv(path); t->frg = nid; t->lnks[0] = EDGE_REF_NULL; t->lnks[1] = EDGE_REF_NULL; t->dir = dir; len = linear_path_graph(g, path, max_len, &msg1) + 1; if(len > max_len) return 0; //if(msg1 != -1 - WT_TRACE_MSG_MORE && msg1 != WT_TRACE_MSG_MORE) return 0; if(msg1 == WT_TRACE_MSG_MORE){ path->size --; return 0; } else if(msg1 == -1 - WT_TRACE_MSG_MORE){ t = ref_pathv(path, path->size); // please see linear_path_graph n = ref_frgv(g->frgs, t->frg); dir = !t->dir; n_in = 0; idx = n->lnks[dir].idx; found = 0; while(idx){ f = ref_edgerefv(g->lrefs, idx); idx = f->next; if(f->idx == t->lnks[dir].idx) continue; e = g->lnks->buffer + f->idx; if(e->closed) continue; n_in ++; T.frg = f->flg? e->frg1 : e->frg2; T.dir = f->flg? !e->dir1 : e->dir2; len2 = count_linear_path_graph(g, &T, len + 1, &msg2) + 1; if(msg2 != WT_TRACE_MSG_ZERO) len2 ++; if(len2 >= len){ found = 1; break; } } if(!found) return 0; } else return 0; for(i=0;isize;i++){ del_frg_lnks_graph(g, ref_frgv(g->frgs, path->buffer[i].frg)); ret ++; } return ret; } static inline u8i trim_frgtips_graph(Graph *g, int max_len){ pathv *path; frg_t *n; u8i ret, nid; ret = 0; path = init_pathv(32); for(nid=0;nidfrgs->size;nid++){ n = ref_frgv(g->frgs, nid); if(n->closed) continue; if(trim_frgtip_core_graph(g, max_len, path, nid)) ret ++; } free_pathv(path); return ret; } typedef struct { node_t *n; edge_t *e; // incoming edge u8i dir:1, ind:1, step:8, bt:16, ending:16, keep:2; int score:20; } bt_t; define_list(btv, bt_t); #define WT_MAX_BTIDX 0xFFFF static inline u4i pop_bubble_backtrace_graph(Graph *g, btv *bts, u4i idx){ bt_t *bt; u4i ret; while(idx){ bt = ref_btv(bts, idx); bt->step = 0; idx = bt->bt; } ret = 0; for(idx=1;idxsize;idx++){ bt = ref_btv(bts, idx); if(bt->step == 0) continue; cut_edge_graph(g, bt->e); ret ++; } return ret; } typedef struct { frg_t *n; lnk_t *e; // incoming edge u8i dir:1, ind:1, step:8, bt:16, ending:16, score:22; } frg_bt_t; define_list(frgbtv, frg_bt_t); u4i pop_frg_bubble_backtrace_graph(Graph *g, frgbtv *bts, u4i idx){ frg_bt_t *bt; u4i ret; while(idx){ bt = ref_frgbtv(bts, idx); bt->step = 0; idx = bt->bt; } ret = 0; for(idx=1;idxsize;idx++){ bt = ref_frgbtv(bts, idx); if(bt->step == 0) continue; cut_lnk_graph(g, bt->e); ret ++; } return ret; } static inline u4i pop_bubble2_backtrace_graph(Graph *g, btv *bts, u4i _idx){ bt_t *bt; u4i ret, i, idx; for(i=1;isize;i++){ bt = ref_btv(bts, i); bt->keep = 2; } idx = _idx; while(idx){ bt = ref_btv(bts, idx); bt->keep = 1; idx = bt->bt; } for(i=1;isize;i++){ bt = ref_btv(bts, i); if(bt->keep == 1) continue; if(bt->ending == 0) continue; if(bts->buffer[bt->ending].keep == 1){ idx = i; while(idx){ bt = ref_btv(bts, idx); if(bt->keep != 2) break; idx = bt->bt; bt->keep = 0; } } } ret = 0; for(idx=1;idxsize;idx++){ bt = ref_btv(bts, idx); if(bt->keep) continue; cut_edge_graph(g, bt->e); ret ++; } return ret; } static inline u4i pop_frg_bubble2_backtrace_graph(Graph *g, frgbtv *bts, u4i _idx){ frg_bt_t *bt; u4i ret, i, idx; for(i=1;isize;i++){ bt = ref_frgbtv(bts, i); if(bt->ending == _idx){ idx = i; while(idx){ bt = ref_frgbtv(bts, idx); bt->step = 0; idx = bt->bt; } } } idx = _idx; while(idx){ bt = ref_frgbtv(bts, idx); bt->step = 1; idx = bt->bt; } ret = 0; for(idx=1;idxsize;idx++){ bt = ref_frgbtv(bts, idx); if(bt->step != 0) continue; cut_lnk_graph(g, bt->e); ret ++; } return ret; } static inline u4i safe_cut_redundant_edges_graph(Graph *g, btv *bts, bt_t *b1, bt_t *b2){ u4i ret; ret = 0; if(0){ ret = 1; cut_edge_graph(g, b1->e); b1 = ref_btv(bts, b1->bt); } while(1){ if(b1->step >= b2->step){ if(b1 == b2) break; ret ++; cut_edge_graph(g, b1->e); b1 = ref_btv(bts, b1->bt); } else { b2 = ref_btv(bts, b2->bt); } } return ret; } static inline u4i safe_cut_redundant_lnks_graph(Graph *g, frgbtv *bts, frg_bt_t *b1, frg_bt_t *b2){ u4i ret; ret = 0; if(0){ ret = 1; cut_lnk_graph(g, b1->e); b1 = ref_frgbtv(bts, b1->bt); } while(1){ if(b1->step >= b2->step){ if(b1 == b2) break; ret ++; cut_lnk_graph(g, b1->e); b1 = ref_frgbtv(bts, b1->bt); } else { b2 = ref_frgbtv(bts, b2->bt); } } return ret; } static inline u4i pop_bubble_core_graph(Graph *g, uint16_t max_step, btv *bts, u4v *heap, u8i nid, u4i dir, u8i visit, int safe){ bt_t *bt, *tb; node_t *n; edge_ref_t *f; edge_t *e; u8i ret, idx; u4i bidx, i, lst, unclosed; ret = 0; n = ref_nodev(g->nodes, nid); if(n->closed) return 0; if(count_living_edges_graph(g, n, dir) < 2) return 0; clear_btv(bts); next_ref_btv(bts); bt = next_ref_btv(bts); bt->n = n; bt->e = NULL; bt->dir = dir; bt->ind = safe? 0 : 1; bt->step = 0; bt->bt = 0; bt->score = 0; bt->ending = 0; clear_u4v(heap); array_heap_push(heap->buffer, heap->size, heap->cap, u4i, bts->size - 1, num_cmpx(bts->buffer[a].step, bts->buffer[b].step, bts->buffer[b].score, bts->buffer[a].score)); n->bt_visit = visit; n->bt_idx = bts->size - 1; n->single_in = 1; unclosed = 0; while(heap->size && heap->size < WT_MAX_BTIDX){ bidx = array_heap_pop(heap->buffer, heap->size, heap->cap, u4i, num_cmpx(bts->buffer[a].step, bts->buffer[b].step, bts->buffer[b].score, bts->buffer[a].score)); encap_btv(bts, bts->buffer[bidx].n->edges[bts->buffer[bidx].dir].cnt); bt = ref_btv(bts, bidx); if(bt->step >= max_step) return 0; if(bt->ind && bt->n->single_in == 0) bt->ind = 0; lst = bts->size; idx = bt->n->edges[bt->dir].idx; while(idx){ f = ref_edgerefv(g->erefs, idx); idx = f->next; e = g->edges->buffer + f->idx; if(e->closed) continue; tb = next_ref_btv(bts); tb->n = ref_nodev(g->nodes, f->flg? e->node1 : e->node2); if(tb->n == bts->buffer[1].n) return 0; tb->e = e; tb->dir = f->flg? !e->dir1 : e->dir2; tb->step = bt->step + 1; tb->bt = bidx; tb->ind = 0; //tb->score = bt->score + num_min(0, e->cov - 20); // set normal e->cov = 20 tb->score = bt->score + e->cov; tb->ending = 0; } if(bt->ind && (bt->bt == 0 || lst + 1 == bts->size)){ for(i=lst;isize;i++) bts->buffer[i].ind = 1; } for(i=lst;isize;i++){ tb = ref_btv(bts, i); if(tb->n->bt_visit != visit){ tb->n->bt_visit = visit; tb->n->unvisit = count_living_edges_graph(g, tb->n, !tb->dir); if(tb->n->unvisit == 1) tb->n->single_in = 1; else tb->n->single_in = 0; tb->n->bt_idx = i; unclosed ++; } else { tb->ending = tb->n->bt_idx; if(tb->dir == bts->buffer[tb->n->bt_idx].dir){ if(tb->ind && bts->buffer[tb->n->bt_idx].ind){ if(tb->step == bts->buffer[tb->n->bt_idx].step){ return safe_cut_redundant_edges_graph(g, bts, tb, ref_btv(bts, tb->n->bt_idx)); } else { return safe_cut_redundant_edges_graph(g, bts, ref_btv(bts, tb->n->bt_idx), tb); } } else if(tb->ind){ return safe_cut_redundant_edges_graph(g, bts, tb, ref_btv(bts, tb->n->bt_idx)); } else if(bts->buffer[tb->n->bt_idx].ind){ return safe_cut_redundant_edges_graph(g, bts, ref_btv(bts, tb->n->bt_idx), tb); } } else { // circle return 0; } } tb->n->unvisit --; if(tb->n->unvisit == 0){ //if(num_cmpgt(tb->score, bts->buffer[tb->n->bt_idx].score)){ if(tb->step > bts->buffer[tb->n->bt_idx].step){ bts->buffer[tb->n->bt_idx].ending = i; tb->n->bt_idx = i; tb->ending = 0; } if(count_living_edges_graph(g, tb->n, tb->dir)){ array_heap_push(heap->buffer, heap->size, heap->cap, u4i, tb->n->bt_idx, num_cmpx(bts->buffer[a].step, bts->buffer[b].step, bts->buffer[b].score, bts->buffer[a].score)); } unclosed --; } } if(heap->size == 1 && unclosed == 0){ return pop_bubble2_backtrace_graph(g, bts, heap->buffer[0]); } } return 0; } static inline u8i pop_bubbles_graph(Graph *g, uint16_t max_step, int safe){ btv *bts; u4v *heap; node_t *n; u8i nid, visit, ret, _ret; int dir; ret = 0; for(nid=0;nidnodes->size;nid++) g->nodes->buffer[nid].bt_visit = 0; bts = init_btv(32); heap = init_u4v(32); visit = 0; for(nid=0;nidnodes->size;nid++){ n = ref_nodev(g->nodes, nid); if(n->closed) continue; for(dir=0;dir<2;dir++){ _ret = pop_bubble_core_graph(g, max_step, bts, heap, nid, dir, ++visit, safe); if(_ret) ret ++; } } free_btv(bts); free_u4v(heap); return ret; } static inline u4i pop_frg_bubble_core_graph(Graph *g, uint16_t max_step, frgbtv *bts, u4v *heap, u8i nid, u4i dir, u8i visit){ frg_bt_t *bt, *tb; frg_t *n; edge_ref_t *f; lnk_t *e; u8i ret, idx; u4i bidx, i, lst, unclosed; ret = 0; n = ref_frgv(g->frgs, nid); if(n->closed) return 0; if(count_living_lnks_graph(g, n, dir) < 2) return 0; clear_frgbtv(bts); next_ref_frgbtv(bts); bt = next_ref_frgbtv(bts); bt->n = n; bt->e = NULL; bt->dir = dir; bt->ind = 1; //bt->ind = 0; bt->step = 0; bt->bt = 0; bt->score = 0; bt->ending = 0; clear_u4v(heap); array_heap_push(heap->buffer, heap->size, heap->cap, u4i, bts->size - 1, num_cmpx(bts->buffer[a].step, bts->buffer[b].step, bts->buffer[b].score, bts->buffer[a].score)); n->bt_visit = visit; n->bt_idx = bts->size - 1; n->single_in = 1; unclosed = 0; while(heap->size && heap->size < WT_MAX_BTIDX){ bidx = array_heap_pop(heap->buffer, heap->size, heap->cap, u4i, num_cmpx(bts->buffer[a].step, bts->buffer[b].step, bts->buffer[b].score, bts->buffer[a].score)); encap_frgbtv(bts, bts->buffer[bidx].n->lnks[bts->buffer[bidx].dir].cnt); bt = ref_frgbtv(bts, bidx); if(bt->step >= max_step) return 0; if(bt->ind && bt->n->single_in == 0) bt->ind = 0; lst = bts->size; idx = bt->n->lnks[bt->dir].idx; while(idx){ f = ref_edgerefv(g->lrefs, idx); idx = f->next; e = g->lnks->buffer + f->idx; if(e->closed) continue; tb = next_ref_frgbtv(bts); tb->n = ref_frgv(g->frgs, f->flg? e->frg1 : e->frg2); if(tb->n == bts->buffer[1].n) return 0; tb->e = e; tb->dir = f->flg? !e->dir1 : e->dir2; tb->step = bt->step + 1; tb->bt = bidx; tb->ind = 0; tb->score = bt->score + e->cov; tb->ending = 0; } if(bt->ind && (bt->bt == 0 || lst + 1 == bts->size)){ for(i=lst;isize;i++) bts->buffer[i].ind = 1; } for(i=lst;isize;i++){ tb = ref_frgbtv(bts, i); if(tb->n->bt_visit != visit){ tb->n->bt_visit = visit; tb->n->unvisit = count_living_lnks_graph(g, tb->n, !tb->dir); if(tb->n->unvisit == 1) tb->n->single_in = 1; else tb->n->single_in = 0; tb->n->bt_idx = i; unclosed ++; } else { tb->ending = tb->n->bt_idx; if(tb->dir == bts->buffer[tb->n->bt_idx].dir){ if(tb->ind && bts->buffer[tb->n->bt_idx].ind){ if(tb->step == bts->buffer[tb->n->bt_idx].step){ return safe_cut_redundant_lnks_graph(g, bts, tb, ref_frgbtv(bts, tb->n->bt_idx)); } else { return safe_cut_redundant_lnks_graph(g, bts, ref_frgbtv(bts, tb->n->bt_idx), tb); } } else if(tb->ind){ return safe_cut_redundant_lnks_graph(g, bts, tb, ref_frgbtv(bts, tb->n->bt_idx)); } else if(bts->buffer[tb->n->bt_idx].ind){ return safe_cut_redundant_lnks_graph(g, bts, ref_frgbtv(bts, tb->n->bt_idx), tb); } } } tb->n->unvisit --; if(tb->n->unvisit == 0){ if(tb->step > bts->buffer[tb->n->bt_idx].step) tb->n->bt_idx = i; if(count_living_lnks_graph(g, tb->n, tb->dir)){ array_heap_push(heap->buffer, heap->size, heap->cap, u4i, tb->n->bt_idx, num_cmpx(bts->buffer[a].step, bts->buffer[b].step, bts->buffer[b].score, bts->buffer[a].score)); } unclosed --; } } if(heap->size == 1 && unclosed == 0){ return pop_frg_bubble2_backtrace_graph(g, bts, heap->buffer[0]); } } return 0; } static inline u8i pop_frg_bubbles_graph(Graph *g, uint16_t max_step){ frgbtv *bts; u4v *heap; frg_t *n; u8i nid, visit, ret, _ret; int dir; ret = 0; for(nid=0;nidfrgs->size;nid++) g->frgs->buffer[nid].bt_visit = 0; bts = init_frgbtv(32); heap = init_u4v(32); visit = 0; for(nid=0;nidfrgs->size;nid++){ n = ref_frgv(g->frgs, nid); if(n->closed) continue; for(dir=0;dir<2;dir++){ _ret = pop_frg_bubble_core_graph(g, max_step, bts, heap, nid, dir, ++visit); if(_ret) ret ++; } } free_frgbtv(bts); free_u4v(heap); return ret; } static inline u4i resolve_yarn_core_graph(Graph *g, u4i max_step, btv *bts, u4v *heap, u8i nid, u4i dir, u8i visit){ bt_t *bt, *tb; node_t *n, *m; edge_ref_t *f; edge_t *e; u8i ret, idx, tip_idx; u4i bidx, i, lst, tip; int n_in; ret = 0; n = ref_nodev(g->nodes, nid); if(n->closed) return 0; if(count_living_edges_graph(g, n, dir) < 2) return 0; clear_btv(bts); next_ref_btv(bts); bt = next_ref_btv(bts); bt->n = n; bt->e = NULL; bt->dir = dir; bt->step = 0; bt->bt = 0; bt->score = 0; bt->ending = 0; clear_u4v(heap); array_heap_push(heap->buffer, heap->size, heap->cap, u4i, bts->size - 1, num_cmpx(bts->buffer[a].step, bts->buffer[b].step, bts->buffer[b].score, bts->buffer[a].score)); n->bt_visit = visit; n->bt_idx = bts->size - 1; tip = 0; tip_idx = WT_MAX_BTIDX; n_in = 1; while(heap->size && bts->size < WT_MAX_BTIDX){ bidx = array_heap_pop(heap->buffer, heap->size, heap->cap, u4i, num_cmpx(bts->buffer[a].step, bts->buffer[b].step, bts->buffer[b].score, bts->buffer[a].score)); encap_btv(bts, bts->buffer[bidx].n->edges[bts->buffer[bidx].dir].cnt); bt = ref_btv(bts, bidx); if(bt->step >= max_step){ return 0; } lst = bts->size; idx = bt->n->edges[bt->dir].idx; while(idx){ f = ref_edgerefv(g->erefs, idx); idx = f->next; e = g->edges->buffer + f->idx; if(e->closed) continue; tb = next_ref_btv(bts); tb->n = ref_nodev(g->nodes, f->flg? e->node1 : e->node2); //if(tb->n == bts->buffer[1].n){ //return 0; //} tb->e = e; tb->dir = f->flg? !e->dir1 : e->dir2; tb->step = bt->step + 1; tb->bt = bidx; tb->score = bt->score + e->cov; tb->ending = 0; } for(i=lst;isize;i++){ tb = ref_btv(bts, i); if(tb->n->bt_visit != visit){ tb->n->bt_visit = visit; tb->n->unvisit = count_living_edges_graph(g, tb->n, !tb->dir); n_in += tb->n->unvisit - 1; tb->n->bt_idx = i; if(count_living_edges_graph(g, tb->n, tb->dir)){ array_heap_push(heap->buffer, heap->size, heap->cap, u4i, tb->n->bt_idx, num_cmpx(bts->buffer[a].step, bts->buffer[b].step, bts->buffer[b].score, bts->buffer[a].score)); } else if(tip == 0){ tip = 1; tip_idx = i; } else { return 0; } } else { tb->ending = tb->n->bt_idx; n_in --; } } if(n_in == 1){ if(heap->size == 0 && tip == 1){ return pop_bubble_backtrace_graph(g, bts, tip? tip_idx : heap->buffer[0]); } else if(heap->size == 1 && tip == 0){ tip_idx = heap->buffer[0]; tb = ref_btv(bts, heap->buffer[0]); idx = tb->n->edges[tb->dir].idx; while(idx){ f = ref_edgerefv(g->erefs, idx); idx = f->next; e = g->edges->buffer + f->idx; if(e->closed) continue; m = ref_nodev(g->nodes, f->flg? e->node1 : e->node2); if(m->bt_visit == visit) continue; else tip ++; } if(tip == 0) return 0; return pop_bubble_backtrace_graph(g, bts, tip_idx); } } } return 0; } // very complicated local region, like yarn, but with Single In edge and Single Out edges static inline u8i resolve_yarns_graph(Graph *g, u4i max_step){ btv *bts; u4v *heap; tracev *path; trace_t *t; node_t *n; u8i nid, visit, ret, _ret; int dir; ret = 0; for(nid=0;nidnodes->size;nid++) g->nodes->buffer[nid].bt_visit = 0; bts = init_btv(32); heap = init_u4v(32); path = init_tracev(4); visit = 0; #if DEBUG if(max_step == 1000000){ // never happen print_local_dot_graph(g, "1.dot", NULL); } #endif for(nid=0;nidnodes->size;nid++){ n = ref_nodev(g->nodes, nid); if(n->closed) continue; if(n->edges[0].cnt <= 1 && n->edges[1].cnt > 1){ if(n->edges[0].cnt == 1){ clear_tracev(path); t = next_ref_tracev(path); t->node = nid; t->dir = 0; if(linear_trace_graph(g, path, 4, NULL) < 4){ // solve yarn from linear nodes continue; } } dir = 1; } else if(n->edges[1].cnt <= 1 && n->edges[0].cnt > 1){ if(n->edges[0].cnt == 1){ clear_tracev(path); t = next_ref_tracev(path); t->node = nid; t->dir = 1; if(linear_trace_graph(g, path, 4, NULL) < 4){ // solve yarn from linear nodes continue; } } dir = 0; } else continue; _ret = resolve_yarn_core_graph(g, max_step, bts, heap, nid, dir, ++visit); if(_ret) ret ++; } free_btv(bts); free_u4v(heap); free_tracev(path); return ret; } static inline u8i remove_boomerangs_frg_graph(Graph *g, u4i max_frg_len){ frg_t *frg; u8i i, ret; ret = 0; for(i=0;ifrgs->size;i++){ frg = ref_frgv(g->frgs, i); if(frg->closed) continue; if(frg->len > max_frg_len) continue; if(frg->lnks[0].cnt == 0 && frg->lnks[1].cnt > 1){ } else if(frg->lnks[1].cnt == 0 && frg->lnks[0].cnt > 1){ } else continue; ret ++; del_frg_lnks_graph(g, frg); } return ret; } static inline u8i cut_weak_branches_frg_graph(Graph *g){ frg_t *frg1, *frg2; lnk_t *lnk; u8v *cuts; u8i i, ret; cuts = init_u8v(32); for(i=0;ilnks->size;i++){ lnk = ref_lnkv(g->lnks, i); if(lnk->weak == 0) continue; frg1 = ref_frgv(g->frgs, lnk->frg1); frg2 = ref_frgv(g->frgs, lnk->frg2); if(frg1->lnks[lnk->dir1].cnt > 1){ push_u8v(cuts, i); } else if(frg2->lnks[!lnk->dir2].cnt > 1){ push_u8v(cuts, i); } } ret = cuts->size; for(i=0;isize;i++){ cut_lnk_graph(g, ref_lnkv(g->lnks, cuts->buffer[i])); } free_u8v(cuts); return ret; } static inline u8i mask_all_branching_nodes_graph(Graph *g){ node_t *n; u8i node, ret; ret = 0; for(node=0;nodenodes->size;node++){ n = ref_nodev(g->nodes, node); if(n->closed) continue; if(n->edges[0].cnt > 1 || n->edges[1].cnt > 1){ n->rep_idx = 1; ret ++; } else { n->rep_idx = 0; } } for(node=0;nodenodes->size;node++){ n = ref_nodev(g->nodes, node); if(n->closed) continue; if(n->rep_idx == 0) continue; del_node_graph(g, n); } return ret; } static inline u8i gen_unitigs_graph(Graph *g){ tracev *path; u4v *lens; trace_t *t; node_t *n; u8i nid, nutg, i; for(i=0;iutgs->size;i++) free_tracev(g->utgs->buffer[i]); clear_vplist(g->utgs); lens = init_u4v(1024); nutg = 0; for(nid=0;nidnodes->size;nid++){ g->nodes->buffer[nid].bt_visit = 0; g->nodes->buffer[nid].rep_idx = MAX_REP_IDX; } for(nid=0;nidnodes->size;nid++){ n = ref_nodev(g->nodes, nid); if(n->closed) continue; if(n->bt_visit) continue; path = init_tracev(4); nutg ++; t = next_ref_tracev(path); t->node = nid; t->edges[0] = EDGE_REF_NULL; t->edges[1] = EDGE_REF_NULL; t->dir = 0; true_linear_unique_trace_graph(g, path, 0xFFFFFFFFFFFFFFFFLLU, nutg, NULL); reverse_tracev(path); for(i=0;isize;i++) path->buffer[i].dir = !path->buffer[i].dir; true_linear_unique_trace_graph(g, path, 0xFFFFFFFFFFFFFFFFLLU, nutg, NULL); push_u4v(lens, cal_offset_traces_graph(g, path, 0, path->size, 0) * KBM_BIN_SIZE); for(i=0;isize;i++){ ref_nodev(g->nodes, path->buffer[i].node)->rep_idx = g->utgs->size; } push_vplist(g->utgs, path); } fprintf(KBM_LOGF, "[%s] ", date()); num_n50(lens, KBM_LOGF); fprintf(KBM_LOGF, "\n"); free_u4v(lens); return nutg; } static inline seqletv* path2seqlets_graph(Graph *g, pathv *path){ seqletv *qs; path_t *p1, *p2; frg_t *frg1, *frg2; edge_ref_t *f; lnk_t *l; trace_t *t1, *t2; b8i off; int len; u4i i, j; qs = init_seqletv(4); cal_offset_paths_graph(g, path, 0, path->size); p1 = NULL; frg1 = NULL; for(i=0;isize;i++){ p2 = ref_pathv(path, i); frg2 = ref_frgv(g->frgs, p2->frg); cal_offset_traces_graph(g, g->traces, frg2->toff, frg2->toff + frg2->tcnt, 0); p2->tx = 0; p2->ty = frg2->tcnt - 1; if(p1){ f = p1->lnks + p1->dir; l = ref_lnkv(g->lnks, f->idx); if(f->flg){ if(p1->dir){ p1->tx = l->tidx2; } else { p1->ty = frg1->tcnt - 1 - l->tidx2; } if(p2->dir){ p2->ty = frg2->tcnt - 1 - l->tidx1; } else { p2->tx = l->tidx1; } } else { if(p1->dir){ p1->tx = l->tidx1; } else { p1->ty = frg1->tcnt - 1 - l->tidx1; } if(p2->dir){ p2->ty = frg2->tcnt - 1 - l->tidx2; } else { p2->tx = l->tidx2; } } if(p1->ty >= frg1->tcnt || p2->ty >= frg2->tcnt){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); } off += l->off; } p1 = p2; frg1 = frg2; } p1 = NULL; frg1 = NULL; for(i=0;isize;i++){ p2 = ref_pathv(path, i); frg2 = ref_frgv(g->frgs, p2->frg); if(p1){ t1 = ref_tracev(g->traces, frg1->toff + (p1->dir? p1->tx : p1->ty)); t2 = ref_tracev(g->traces, frg2->toff + (p2->dir? p2->ty : p2->tx)); off = p1->off + (p1->dir? (int)(frg1->len - (t1->off + g->reglen)) : t1->off); f = p1->lnks + p1->dir; l = ref_lnkv(g->lnks, f->idx); len = l->off + (p1->dir? t1->off + g->reglen : frg1->len - t1->off) + (p2->dir? frg2->len - t2->off : t2->off + g->reglen); push_seqletv(qs, (seqlet_t){t1->node, p1->dir ^ t1->dir, t2->node, p2->dir ^ t2->dir, off, len}); } if(p2->dir){ //for(j=p2->tx+1;j<=p2->ty;j++){ //t1 = ref_tracev(g->traces, frg2->toff + frg2->tcnt - 1 - j); //t2 = ref_tracev(g->traces, frg2->toff + frg2->tcnt - 0 - j); for(j=p2->ty;j>p2->tx;j--){ t1 = ref_tracev(g->traces, frg2->toff + j - 1); t2 = ref_tracev(g->traces, frg2->toff + j); off = p2->off + frg2->len - (t2->off + g->reglen); len = t2->off - t1->off + g->reglen; push_seqletv(qs, (seqlet_t){t2->node, !t2->dir, t1->node, !t1->dir, off, len}); } } else { for(j=p2->tx+1;j<=p2->ty;j++){ t1 = ref_tracev(g->traces, frg2->toff + j - 1); t2 = ref_tracev(g->traces, frg2->toff + j); off = p2->off + t1->off; len = t2->off - t1->off + g->reglen; push_seqletv(qs, (seqlet_t){t1->node, t1->dir, t2->node, t2->dir, off, len}); } } p1 = p2; frg1 = frg2; } return qs; } static inline u8i gen_contigs_graph(Graph *g, FILE *out){ pathv *path; seqletv *qs; seqlet_t *q; path_t *t; frg_t *n; u8i nid, nctg, i, off; for(i=0;ictgs->size;i++) free_tracev(g->ctgs->buffer[i]); clear_vplist(g->ctgs); nctg = 0; for(nid=0;nidfrgs->size;nid++) g->frgs->buffer[nid].bt_visit = 0; path = init_pathv(4); for(nid=0;nidfrgs->size;nid++){ n = ref_frgv(g->frgs, nid); if(n->closed) continue; if(n->bt_visit) continue; nctg ++; clear_pathv(path); t = next_ref_pathv(path); t->frg = nid; t->lnks[0] = EDGE_REF_NULL; t->lnks[1] = EDGE_REF_NULL; t->dir = 0; true_linear_unique_path_graph(g, path, 0xFFFFFFFFFFFFFFFFLLU, nctg, NULL); reverse_pathv(path); for(i=0;isize;i++) path->buffer[i].dir = !path->buffer[i].dir; true_linear_unique_path_graph(g, path, 0xFFFFFFFFFFFFFFFFLLU, nctg, NULL); qs = path2seqlets_graph(g, path); if(qs->size + 1 < (u4i)g->min_ctg_nds){ free_seqletv(qs); continue; } q = ref_seqletv(qs, qs->size - 1); if(((int)q->off + (int)q->len) * KBM_BIN_SIZE < (int)g->min_ctg_len){ free_seqletv(qs); continue; } off = 0; for(i=0;isize;i++){ q = ref_seqletv(qs, i); q->off = off; off += q->len - g->reglen; } if(out){ for(i=0;isize;i++){ t = ref_pathv(path, i); fprintf(out, "ctg%d\tF%d\t%c\t%d\n", (int)g->ctgs->size, t->frg, "+-*@"[t->dir], t->off * KBM_BIN_SIZE); } } push_vplist(g->ctgs, qs); } free_pathv(path); g->major_nctg = g->ctgs->size; return nctg; } static inline u8i gen_complex_contigs_graph(Graph *g){ tracev *ts; trace_t *t; seqletv *qs; seqlet_t *q; node_t *n; edge_ref_t *f; edge_t *e; u8i i, idx, mi, cnt; u4i j, k, mk, mc; int mf; for(i=0;inodes->size;i++) g->nodes->buffer[i].unvisit = 1; cnt = 0; for(i=0;iutgs->size;i++){ ts = (tracev*)get_vplist(g->utgs, i); for(j=0;jsize;j++){ t = ref_tracev(ts, j); n = ref_nodev(g->nodes, t->node); n->unvisit = 0; } } for(i=0;inodes->size;i++){ n = ref_nodev(g->nodes, i); if(n->unvisit == 0) continue; if(n->regs.cnt < g->min_node_cov){ n->unvisit = 0; continue; } } cnt = 0; for(i=0;inodes->size;i++){ n = ref_nodev(g->nodes, i); if(n->unvisit == 0) continue; for(k=0;k<2;k++){ idx = n->edges[k].idx; mi = mk = mc = 0; mf = MAX_VALUE_B4; while(idx){ f = ref_edgerefv(g->erefs, idx); idx = f->next; e = g->edges->buffer + f->idx; if(e->node1 == e->node2) continue; if(e->cov < g->min_edge_cov) continue; if(e->off < mf){ mi = f - g->erefs->buffer; mk = k; mc = e->cov; mf = e->off; } } if(mf == MAX_VALUE_B4) continue; f = ref_edgerefv(g->erefs, mi); if(f->flg) continue; e = ref_edgev(g->edges, f->idx); if(g->nodes->buffer[e->node2].unvisit == 0) continue; qs = init_seqletv(1); q = next_ref_seqletv(qs); q->node1 = i; q->dir1 = k; q->node2 = e->node2; q->dir2 = e->dir2; q->off = 0; q->len = g->reglen * 2 + e->off; push_vplist(g->ctgs, qs); cnt ++; } } return cnt; } static inline void n50_stat_contigs_graph(Graph *g){ seqletv *qs; seqlet_t *q; u4v *lens; int len; u8i i; lens = init_u4v(g->major_nctg + 1); for(i=0;imajor_nctg;i++){ qs = (seqletv*)get_vplist(g->ctgs, i); q = ref_seqletv(qs, qs->size - 1); len = ((int)q->off + (int)q->len) * KBM_BIN_SIZE; if(len <= 0){ fprintf(stderr, " -- seqlet[ctg%llu off=%d, len=%d, sum=%d] in %s -- %s:%d --\n", i, (int)q->off, (int)q->len, len, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); continue; } push_u4v(lens, len); } fprintf(KBM_LOGF, "[%s] Estimated: ", date()); num_n50(lens, KBM_LOGF); fprintf(KBM_LOGF, "\n"); free_u4v(lens); } // after gen_contigs static inline u4i count_isolated_reads_graph(Graph *g){ seqletv *ts; seqlet_t *t; node_t *n; read_t *rd; reg_t *r; u8i i, j, cnt, idx; int fnd; for(i=0;inodes->size;i++) g->nodes->buffer[i].unvisit = 1; cnt = 0; for(i=0;ictgs->size;i++){ ts = (seqletv*)get_vplist(g->ctgs, i); for(j=0;jsize;j++){ t = ref_seqletv(ts, j); n = ref_nodev(g->nodes, t->node1); n->unvisit = 0; n = ref_nodev(g->nodes, t->node2); n->unvisit = 0; } } for(i=0;ireads->size;i++){ rd = ref_readv(g->reads, i); fnd = 0; idx = rd->regs.idx; while(idx){ r = ref_regv(g->regs, idx); idx = r->read_link; n = ref_nodev(g->nodes, r->node); if(n->unvisit == 0){ fnd = 1; break; } } if(fnd == 0) cnt ++; } return cnt; } static inline void print_dot_subgraph(Graph *g, subnodehash *nodes, subedgev *edges, FILE *out){ subnode_t *n1, *n2; subedge_t *e; u4i k, idx; fprintf(out, "digraph {\n"); fprintf(out, " rankdir=LR\n"); reset_iter_subnodehash(nodes); while((n1 = ref_iter_subnodehash(nodes))){ if(n1->closed) continue; fprintf(out, "N%llu [label=\"N%llu(%llu) %d:%d:%d\" style=filled fillcolor=\"%s\" color=\"%s\"]\n", (u8i)n1->node, (u8i)n1->node, (u8i)g->nodes->buffer[n1->node].rep_idx, n1->cov, n1->visit, n1->bt_open, n1->fix? "yellow" : "white", n1->visit? "green" : (n1->cov > 2? "blue" : "black")); } reset_iter_subnodehash(nodes); while((n1 = ref_iter_subnodehash(nodes))){ if(n1->closed) continue; for(k=0;k<2;k++){ idx = n1->edges[k].idx; while(idx){ e = ref_subedgev(edges, idx); idx = e->next; if(e->fwd == 0) continue; if(e->closed) continue; n2 = e->node; fprintf(out, " N%llu -> N%llu [label=\"%c%c:%d:%d\" color=\"%s\" %s]\n", (u8i)n1->node, (u8i)n2->node, "+-"[k], "+-"[e->dir], e->cov, e->visit, e->cov > 1? "blue" : "black", e->visit? "style=dashed":""); } } } fprintf(out, "}\n"); fflush(out); } static inline void fprintf_dot_subgraph(Graph *g, subnodehash *nodes, subedgev *edges, char *name_prefix, char *name_suffix){ FILE *out; out = open_file_for_write(name_prefix, name_suffix, 1); print_dot_subgraph(g, nodes, edges, out); fclose(out); } typedef struct { u4i node:31, dir:1; u4i flag; u4i prev; u4i step; int score; } sg_heap_t; define_list(sgheapv, sg_heap_t); typedef struct { u4i node:31, dir:1; u4i group:30, solid:1, closed:1; } sg_tip_t; define_list(sgtipv, sg_tip_t); static inline subedge_t* find_edge_subgraph(subnodehash *nodes, subedgev *edges, u4i node1, int dir1, u4i node2, int dir2){ subnode_t *n; subedge_t *e; u8i idx; n = ref_subnodehash(nodes, node1); idx = n->edges[dir1].idx; e = ref_subedgev(edges, idx); if(offset_subnodehash(nodes, e->node) == node2 && e->dir == dir2){ return e; } while((idx = e->next)){ e = ref_subedgev(edges, idx); if(offset_subnodehash(nodes, e->node) == node2 && e->dir == dir2){ return e; } } return NULL; } static inline int cut_edge_core_subgraph(subnodehash *nodes, subedgev *edges, u4i node1, int dir1, u4i node2, int dir2){ subnode_t *n; subedge_t *e, *p; u8i idx; n = ref_subnodehash(nodes, node1); idx = n->edges[dir1].idx; e = ref_subedgev(edges, idx); if(offset_subnodehash(nodes, e->node) == node2 && e->dir == dir2){ e->closed = 1; n->edges[dir1].idx = e->next; n->edges[dir1].cnt --; return 1; } while((idx = e->next)){ p = e; e = ref_subedgev(edges, idx); if(offset_subnodehash(nodes, e->node) == node2 && e->dir == dir2){ e->closed = 1; p->next = e->next; n->edges[dir1].cnt --; return 1; } } return 0; } static inline int cut_edge_subgraph(subnodehash *nodes, subedgev *edges, u4i node1, int dir1, u4i node2, int dir2){ return cut_edge_core_subgraph(nodes, edges, node1, dir1, node2, dir2) + cut_edge_core_subgraph(nodes, edges, node2, !dir2, node1, !dir1); } static inline u4i unitigs2frgs_graph(Graph *g, int ncpu){ frg_t *frg; node_t *n; tracev *ts; trace_t *t; u4i i, j, tid, ret; { clear_frgv(g->frgs); clear_lnkv(g->lnks); clear_edgerefv(g->lrefs); clear_tracev(g->traces); } ret = 0; for(tid=0;tidutgs->size;tid++){ ret ++; frg = next_ref_frgv(g->frgs); frg->toff = g->traces->size; frg->lnks[0] = PTR_REF_NULL; frg->lnks[1] = PTR_REF_NULL; frg->closed = 0; ts = (tracev*)get_vplist(g->utgs, tid); frg->tx = 0; frg->ty = ts->size; for(i=frg->tx;ity;i++) ts->buffer[i].cov = 0; append_array_tracev(g->traces, ts->buffer + frg->tx, frg->ty - frg->tx); frg->tcnt = frg->ty - frg->tx; frg->length = frg->len = cal_offset_traces_graph(g, g->traces, frg->toff + frg->tx, frg->toff + frg->ty, 0); } psort_array(g->frgs->buffer, g->frgs->size, frg_t, ncpu, num_cmpgt(b.length, a.length)); for(i=0;inodes->size;i++){ n = ref_nodev(g->nodes, i); n->unvisit = 1; n->rep_idx = MAX_REP_IDX; n->bt_visit = 0; } for(i=0;ifrgs->size;i++){ frg = ref_frgv(g->frgs, i); for(j=frg->tx;jty;j++){ t = ref_tracev(g->traces, frg->toff + j); n = ref_nodev(g->nodes, t->node); n->rep_idx = i; n->rep_dir = t->dir; n->bt_visit = j; } } return ret; } static inline int scan_rd_lnk_core(Graph *g, u4i rid, lnk_t *lnk, u8v *regids){ read_t *rd; reg_t *r, *rl, *rr; node_t *n, *nl, *nr; frg_t *fl, *fr; trace_t *tl, *tr; u8i idx; u4i i, tmp; rd = ref_readv(g->reads, rid); idx = rd->regs.idx; clear_u8v(regids); while(idx){ push_u8v(regids, idx); idx = ref_regv(g->regs, idx)->read_link; } if(regids->size < 2) return 0; rl = NULL; nl = NULL; for(i=0;isize;i++){ r = ref_regv(g->regs, regids->buffer[i]); n = ref_nodev(g->nodes, r->node); if(n->rep_idx == MAX_REP_IDX) continue; if(rl && n->rep_idx != nl->rep_idx) break; rl = r; nl = n; } if(i == regids->size) return 0; rr = NULL; nr = NULL; for(i=regids->size;i>0;i--){ r = ref_regv(g->regs, regids->buffer[i - 1]); n = ref_nodev(g->nodes, r->node); if(n->rep_idx == MAX_REP_IDX) continue; if(rr && n->rep_idx != nr->rep_idx) break; rr = r; nr = n; } fl = ref_frgv(g->frgs, nl->rep_idx); tl = ref_tracev(g->traces, fl->toff + nl->bt_visit); fr = ref_frgv(g->frgs, nr->rep_idx); tr = ref_tracev(g->traces, fr->toff + nr->bt_visit); lnk->frg1 = nl->rep_idx; lnk->frg2 = nr->rep_idx; if(lnk->frg1 == lnk->frg2) return 0; lnk->dir1 = rl->dir ^ nl->rep_dir; lnk->dir2 = rr->dir ^ nr->rep_dir; lnk->tidx1 = lnk->dir1? nl->bt_visit : fl->tcnt - 1 - nl->bt_visit; lnk->tidx2 = lnk->dir2? fr->tcnt - 1 - nr->bt_visit : nr->bt_visit; lnk->cov = 1; // directed link //ln->weak = 0; //lnk->closed = 0; lnk->off = rr->beg - rl->end; lnk->off -= lnk->dir1? tl->off : ((b4i)fl->len) - (tl->off + rl->end - rl->beg); lnk->off -= lnk->dir2? ((b4i)fr->len) - (tr->off + rr->end - rr->beg) : tr->off; if(lnk->off + (int)g->reglen < 0) return 0; if(lnk->frg1 > lnk->frg2){ swap_tmp(lnk->frg1, lnk->frg2, tmp); swap_tmp(lnk->dir1, lnk->dir2, tmp); lnk->dir1 = !lnk->dir1; lnk->dir2 = !lnk->dir2; swap_tmp(lnk->tidx1, lnk->tidx2, tmp); } return 1; } static inline int scan_nd_lnk_core(Graph *g, u8i nid, lnk_t *lnk){ node_t *n, *w; edge_ref_t *f; edge_t *e; frg_t *fl, *fr; trace_t *tl, *tr; u8i idx, wid; u4i fids[2], dirs[2], dir, covs[2], tidx[2], k; int offs[2]; n = ref_nodev(g->nodes, nid); if(n->rep_idx != MAX_REP_IDX) return 0; for(k=0;k<2;k++){ fids[k] = 0; dirs[k] = 0; covs[k] = 0; tidx[k] = 0; offs[k] = 0; idx = n->edges[k].idx; while(idx){ f = ref_edgerefv(g->erefs, idx); idx = f->next; e = ref_edgev(g->edges, f->idx); wid = f->flg? e->node1 : e->node2; w = ref_nodev(g->nodes, wid); if(w->rep_idx == MAX_REP_IDX) continue; dir = f->flg? !e->dir1 : e->dir2; dir = w->rep_dir ^ dir; if(fids[k] == 0){ fids[k] = w->rep_idx; dirs[k] = dir; covs[k] = 1; tidx[k] = w->bt_visit; // bt_visit is used to store nodes's tidx on frg offs[k] = e->off; } else if(fids[k] == w->rep_idx && dirs[k] == dir){ covs[k] ++; } else { fids[k] = MAX_U4; break; } } if(fids[k] == 0) return 0; if(fids[k] == MAX_U4) return 0; if(covs[k] < g->min_edge_cov) return 0; } if(fids[0] == fids[1]) return 0; lnk->cov = 0; // indirected link if(fids[0] < fids[1]){ lnk->frg1 = fids[0]; lnk->frg2 = fids[1]; lnk->dir1 = !dirs[0]; lnk->dir2 = dirs[1]; lnk->tidx1 = tidx[0]; lnk->tidx2 = tidx[1]; } else { lnk->frg1 = fids[1]; lnk->frg2 = fids[0]; lnk->dir1 = !dirs[1]; lnk->dir2 = dirs[0]; lnk->tidx1 = tidx[1]; lnk->tidx2 = tidx[0]; } lnk->off = offs[0] + offs[1] + g->reglen; fl = ref_frgv(g->frgs, lnk->frg1); fr = ref_frgv(g->frgs, lnk->frg2); tl = ref_tracev(g->traces, fl->toff + lnk->tidx1); tr = ref_tracev(g->traces, fr->toff + lnk->tidx2); lnk->off -= lnk->dir1? tl->off : ((int)fl->len) - (int)(tl->off + g->reglen); lnk->off -= lnk->dir2? ((int)fr->len) - (int)(tr->off + g->reglen) : tr->off; if(lnk->off + (int)g->reglen < 0) return 0; return 1; } thread_beg_def(mlnk); Graph *g; lnkv *lnks; int task; thread_end_def(mlnk); thread_beg_func(mlnk); u8v *regids; u8i nid; u4i rid; lnk_t LNK; memset(&LNK, 0, sizeof(lnk_t)); LNK.cov = 1; LNK.weak = 0; LNK.closed = 0; regids = init_u8v(32); thread_beg_loop(mlnk); if(mlnk->task == 1){ for(rid=mlnk->t_idx;ridg->reads->size;rid+=mlnk->n_cpu){ if(scan_rd_lnk_core(mlnk->g, rid, &LNK, regids)){ push_lnkv(mlnk->lnks, LNK); } } } else if(mlnk->task == 2){ for(nid=mlnk->t_idx;nidg->nodes->size;nid+=mlnk->n_cpu){ if(scan_nd_lnk_core(mlnk->g, nid, &LNK)){ push_lnkv(mlnk->lnks, LNK); } } } thread_end_loop(mlnk); free_u8v(regids); thread_end_func(mlnk); static inline u4i gen_lnks_graph(Graph *g, int ncpu, FILE *log){ frg_t *frg; trace_t *t; node_t *n; lnkv *lnks; lnk_t *l; edge_ref_t F1, F2; u8i lst, idx; u4i i, j, m, v1, v2, cnt, cov; int x; thread_preprocess(mlnk); clear_lnkv(g->lnks); memset(next_ref_lnkv(g->lnks), 0, sizeof(lnk_t)); clear_edgerefv(g->lrefs); push_edgerefv(g->lrefs, EDGE_REF_NULL); for(i=0;inodes->size;i++){ n = ref_nodev(g->nodes, i); n->unvisit = 1; n->rep_idx = MAX_REP_IDX; n->bt_visit = 0; } for(i=0;ifrgs->size;i++){ frg = ref_frgv(g->frgs, i); for(j=frg->tx;jty;j++){ t = ref_tracev(g->traces, frg->toff + j); n = ref_nodev(g->nodes, t->node); n->rep_idx = i; n->rep_dir = t->dir; n->bt_visit = j; } } thread_beg_init(mlnk, ncpu); mlnk->g = g; mlnk->lnks = init_lnkv(1024); mlnk->task = 0; thread_end_init(mlnk); thread_apply_all(mlnk, mlnk->task = 1); //thread_apply_all(mlnk, mlnk->task = 2); lnks = init_lnkv(1024); thread_beg_close(mlnk); append_lnkv(lnks, mlnk->lnks); free_lnkv(mlnk->lnks); thread_end_close(mlnk); psort_array(lnks->buffer, lnks->size, lnk_t, ncpu, num_cmpgtx(a.key, b.key, a.off, b.off)); if(log){ for(i=0;isize;i++){ l = ref_lnkv(lnks, i); fprintf(log, "F%d[%c:%d] -> F%d[%c:%d] = %d, cov=%d\n", l->frg1, "+-"[l->dir1], l->tidx1, l->frg2, "+-"[l->dir2], l->tidx2, l->off, l->cov); } } cov = 0; for(i=j=0;i<=lnks->size;i++){ if(i == lnks->size || lnks->buffer[i].key != lnks->buffer[j].key){ push_edgerefv(g->lrefs, (edge_ref_t){g->lnks->size, 0, 0}); push_edgerefv(g->lrefs, (edge_ref_t){g->lnks->size, 1, 0}); l = next_ref_lnkv(g->lnks); m = (((u8i)i) + j) / 2; if(cov && lnks->buffer[m].cov == 0){ for(v1=1;v1+j<=m;v1++){ if(lnks->buffer[m-v1].cov){ v1 |= 0x80000000U; break; } } for(v2=1;m+v2buffer[m+v2].cov){ v2 |= 0x80000000U; break; } } if(v1 & 0x80000000U){ if(v2 & 0x80000000U){ if((v1 & 0x7FFFFFFFU) <= (v2 & 0x7FFFFFFFU)){ m = m - (v1 & 0x7FFFFFFFU); } else { m = m + (v2 & 0x7FFFFFFFU); } } else { m = m - (v1 & 0x7FFFFFFFU); } } else { if(v2 & 0x80000000U){ m = m + (v2 & 0x7FFFFFFFU); } else { fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); } } } *l = lnks->buffer[m]; l->cov = cov; if(l->cov < g->max_node_cov_sg){ l->weak = 1; //l->closed = WT_EDGE_CLOSED_LESS; l->closed = 0; } else { l->weak = 0; l->closed = 0; } j = i; cov = lnks->buffer[i].cov; } else { cov += lnks->buffer[i].cov; } } free_lnkv(lnks); // sort lrefs psort_array(g->lrefs->buffer + 1, g->lrefs->size - 1, edge_ref_t, ncpu, num_cmpgt( (a.flg? ((g->lnks->buffer[a.idx].frg2 << 1) | !g->lnks->buffer[a.idx].dir2) : ((g->lnks->buffer[a.idx].frg1 << 1) | g->lnks->buffer[a.idx].dir1)), (b.flg? ((g->lnks->buffer[b.idx].frg2 << 1) | !g->lnks->buffer[b.idx].dir2) : ((g->lnks->buffer[b.idx].frg1 << 1) | g->lnks->buffer[b.idx].dir1)) )); push_edgerefv(g->lrefs, (edge_ref_t){g->lnks->size, 0, 0}); memset(next_ref_lnkv(g->lnks), 0, sizeof(lnk_t)); g->lnks->size --; g->lrefs->size --; F1.idx = g->lnks->size; F1.flg = 0; cnt = 0; // update frg->lnks for(lst=idx=1;idx<=g->lrefs->size;idx++){ if(g->lrefs->buffer[idx].flg){ F2.idx = g->lnks->buffer[g->lrefs->buffer[idx].idx].frg2; F2.flg = !g->lnks->buffer[g->lrefs->buffer[idx].idx].dir2; } else { F2.idx = g->lnks->buffer[g->lrefs->buffer[idx].idx].frg1; F2.flg = g->lnks->buffer[g->lrefs->buffer[idx].idx].dir1; } if(F1.idx == F2.idx && F1.flg == F2.flg) continue; if(lst < idx){ frg = ref_frgv(g->frgs, F1.idx); frg->lnks[F1.flg].idx = lst; for(x=lst;x+1<(int)idx;x++){ g->lrefs->buffer[x].next = x + 1; if(g->lnks->buffer[g->lrefs->buffer[x].idx].closed == WT_EDGE_CLOSED_NULL) frg->lnks[F1.flg].cnt ++; } if(g->lnks->buffer[g->lrefs->buffer[x].idx].closed == WT_EDGE_CLOSED_NULL) frg->lnks[F1.flg].cnt ++; } lst = idx; F1 = F2; } return g->lnks->size - 1; } static inline int gen_seq_traces_graph(Graph *g, tracev *path, String *seq){ trace_t *t1, *t2; reg_t *reg, *r1, *r2; edge_t *e; u4i i; int inc, found; clear_string(seq); t1 = NULL; for(i=0;isize;i++){ t2 = ref_tracev(path, i); if(t1){ inc = 0; r1 = ref_regv(g->regs, ref_nodev(g->nodes, t1->node)->regs.idx); r2 = ref_regv(g->regs, ref_nodev(g->nodes, t2->node)->regs.idx); e = ref_edgev(g->edges, t1->edges[t1->dir].idx); do { inc = 0; found = 0; while(r1->node == t1->node && r2->node == t2->node){ if(r1->rid > r2->rid){ r2 ++; } else if(r1->rid < r2->rid){ r1 ++; } else { if(r1->beg < r2->beg){ if(t1->dir ^ r1->dir){ r1++; r2++; continue; } inc = (r2->beg - r1->end) * KBM_BIN_SIZE; if(inc <= 0) break; encap_string(seq, inc); seq_basebank(g->kbm->rdseqs, g->kbm->reads->buffer[r1->rid].binoff * KBM_BIN_SIZE+ (r1->end * KBM_BIN_SIZE), inc, seq->string + seq->size); seq->size += inc; } else { if(!(t1->dir ^ r1->dir)){ r1++; r2++; continue; } inc = (r1->beg - r2->end) * KBM_BIN_SIZE; if(inc <= 0) break; encap_string(seq, inc); revseq_basebank(g->kbm->rdseqs, (g->kbm->reads->buffer[r1->rid].seqoff + r2->end) * KBM_BIN_SIZE, inc, seq->string + seq->size); seq->size += inc; } inc = 0; found = 1; break; } } if(found == 0){ inc = e->off; break; } } while(0); if(inc > 0){ inc = 0; while(inc++ < e->off * KBM_BIN_SIZE) add_char_string(seq, 'N'); } else if(inc < 0){ if(seq->size + inc < 0) seq->size = 0; else seq->size += inc; seq->string[seq->size] = '\0'; } } t1 = t2; reg = ref_regv(g->regs, ref_nodev(g->nodes, t1->node)->regs.idx); inc = (reg->end - reg->beg) * KBM_BIN_SIZE; encap_string(seq, inc); if(t1->dir ^ reg->dir) revseq_basebank(g->kbm->rdseqs, (g->kbm->reads->buffer[reg->rid].seqoff + reg->beg) * KBM_BIN_SIZE, inc, seq->string + seq->size); else seq_basebank(g->kbm->rdseqs, (g->kbm->reads->buffer[reg->rid].seqoff + reg->beg) * KBM_BIN_SIZE, inc, seq->string + seq->size); seq->size += inc; } return seq->size; } typedef struct { u8i rid:26, dir:1, beg:18, end:18, view:1; } lay_reg_t; define_list(layregv, lay_reg_t); typedef struct { seqlet_t edge; u8i roff:48, rcnt:16; } lay_t; define_list(layv, lay_t); static inline void gen_lay_regs_core_graph(Graph *g, seqlet_t *q, layregv *regs, BitVec *rdbits, int closed){ node_t *n1, *n2; reg_t *r1, *r2; u4i rid, beg, end; n1 = ref_nodev(g->nodes, q->node1); n2 = ref_nodev(g->nodes, q->node2); r1 = ref_regv(g->regs, n1->regs.idx); r2 = ref_regv(g->regs, n2->regs.idx); while(r1->node == q->node1 && r2->node == q->node2){ if(r1->rid > r2->rid){ r2 ++; } else if(r1->rid < r2->rid){ r1 ++; } else { rid = r1->rid; if((closed || (r1->closed == 0 && r2->closed == 0)) && (rdbits == NULL || get_bitvec(rdbits, rid))){ if(r1->beg < r2->beg){ if(q->dir1 ^ r1->dir){ r1 ++; r2 ++; continue; } beg = r1->beg; end = r2->end; push_layregv(regs, (lay_reg_t){rid, 0, beg, end, 0}); } else { if(!(q->dir1 ^ r1->dir)){ r1 ++; r2 ++; continue; } beg = r2->beg; end = r1->end; push_layregv(regs, (lay_reg_t){rid, 1, beg, end, 0}); } } r1 ++; r2 ++; } } } typedef struct { u4i rid, closed; u8i nodes[2]; } readreg_t; define_list(readregv, readreg_t); static inline u4i densify_seqlet_graph(Graph *g, seqlet_t *q, seqletv *qs, int minoff, readregv *rds, subnodehash *nodes, subedgev *edges, subnodev *heap, FILE *log){ seqlet_t *q2; node_t *nd; read_t *rd; reg_t *rg; readreg_t *rr; subnode_t N, *n, *n1, *n2; subedge_t *e; u8i idx, edx; u4i i, k, k1, k2, d, cov, flg, ret; int exists, off; if(q->len < minoff){ push_seqletv(qs, *q); return 1; } clear_readregv(rds); for(k=0;k<2;k++){ nd = ref_nodev(g->nodes, k? q->node2 : q->node1); d = k? !q->dir2 : q->dir1; for(i=0;iregs.cnt;i++){ rg = ref_regv(g->regs, nd->regs.idx + i); rr = next_ref_readregv(rds); rr->rid = rg->rid; rr->closed = 0; rr->nodes[d ^ rg->dir] = rg->node; rr->nodes[!d ^ rg->dir] = MAX_U8; } } sort_array(rds->buffer, rds->size, readreg_t, num_cmpgt(a.rid, b.rid)); for(i=1;isize;i++){ rr = ref_readregv(rds, i - 1); if(rr->rid == rds->buffer[i].rid){ if(rds->buffer[i].nodes[0] != MAX_U8) rr->nodes[0] = rds->buffer[i].nodes[0]; if(rds->buffer[i].nodes[1] != MAX_U8) rr->nodes[1] = rds->buffer[i].nodes[1]; rds->buffer[i].closed = 1; // max occ of rid is 2 } } // prepare nodes in subgraph clear_subnodehash(nodes); clear_subedgev(edges); next_ref_subedgev(edges); memset(&N, 0, sizeof(subnode_t)); N.cov = 1; N.bt_nidx = MAX_BT_NIDX; cov = 0; for(i=0;isize;i++){ rr = ref_readregv(rds, i); if(rr->closed) continue; if(rr->nodes[0] != MAX_U8 && rr->nodes[1] != MAX_U8){ cov ++; } rd = ref_readv(g->reads, rr->rid); flg = (rr->nodes[0] == MAX_U8); idx = rd->regs.idx; while(idx){ rg = ref_regv(g->regs, idx); idx = rg->read_link; if(flg == 0){ if(rg->node == rr->nodes[0]){ flg = 1; } } if(!flg) continue; N.node = rg->node; n = prepare_subnodehash(nodes, N, &exists); if(exists){ n->cov ++; } else { *n = N; } if(rg->node == rr->nodes[1]){ flg = 0; break; } } } // mask low cov nodes reset_iter_subnodehash(nodes); while((n = ref_iter_subnodehash(nodes))){ if(n->cov < cov) n->closed = 1; } // build edges for(i=0;isize;i++){ rr = ref_readregv(rds, i); if(rr->closed) continue; rd = ref_readv(g->reads, rr->rid); flg = (rr->nodes[0] == MAX_U8); n1 = NULL; k1 = 0; off = 0; idx = rd->regs.idx; while(idx){ rg = ref_regv(g->regs, idx); idx = rg->read_link; if(flg == 0){ if(rg->node == rr->nodes[0]){ flg = 1; } } if(!flg) continue; do { N.node = rg->node; n2 = get_subnodehash(nodes, N); k2 = rg->dir; if(n2->closed) break; if(n1){ // link n1 to n2 edx = n1->edges[k1].idx; while(edx){ e = ref_subedgev(edges, edx); if(e->node == n2 && e->dir == k2){ e->cov ++; break; } edx = e->next; } if(edx == 0){ edx = edges->size; e = next_ref_subedgev(edges); e->node = n2; e->dir = k2; e->cov = 1; e->off = rg->beg - off; e->next = n1->edges[k1].idx; n1->edges[k1].idx = edx; n1->edges[k1].cnt ++; } // link rev n2 to rev n1 edx = n2->edges[!k2].idx; while(edx){ e = ref_subedgev(edges, edx); if(e->node == n1 && e->dir == !k1){ e->cov ++; break; } edx = e->next; } if(edx == 0){ edx = edges->size; e = next_ref_subedgev(edges); e->node = n1; e->dir = !k1; e->cov = 1; e->off = rg->beg - off; e->next = n2->edges[!k2].idx; n2->edges[!k2].idx = edx; n2->edges[!k2].cnt ++; } } } while(0); n1 = n2; k1 = k2; off = rg->end; if(rg->node == rr->nodes[1]){ flg = 0; break; } } } // searching a most dense path from q->node1 to q->node2 N.node = q->node1; n = get_subnodehash(nodes, N); n->visit = 0; n->bt_step = 0; n->bt_score = 0; n->bt_dir = !q->dir1; n->bt_nidx = MAX_BT_NIDX; // NB: below codes cannot grant to find the most dense path, but just useful in many cases clear_subnodev(heap); array_heap_push(heap->buffer, heap->size, heap->cap, subnode_t, *n, num_cmp(a.bt_score, b.bt_score)); while(heap->size){ N = heap->buffer[0]; array_heap_remove(heap->buffer, heap->size, heap->cap, subnode_t, 0, num_cmp(a.bt_score, b.bt_score)); n1 = get_subnodehash(nodes, N); if(n1->visit){ if(n1->node == q->node2){ if(n1->bt_step < N.bt_step){ *n1 = N; n1->visit = 1; } } continue; } else { *n1 = N; n1->visit = 1; } k1 = !n1->bt_dir; idx = n1->edges[k1].idx; while(idx){ e = ref_subedgev(edges, idx); idx = e->next; n2 = e->node; if(n2->bt_step >= n1->bt_step + 1){ // init n2->bt_step = 0 continue; } if(n2->visit && n2->node != q->node2){ continue; } N = *n2; N.bt_dir = !e->dir; N.bt_nidx = offset_subnodehash(nodes, n1); N.bt_step = n1->bt_step + 1; N.bt_score = n1->bt_score + g->reglen + num_max(0, e->off); array_heap_push(heap->buffer, heap->size, heap->cap, subnode_t, N, num_cmp(a.bt_score, b.bt_score)); } } N.node = q->node2; n = get_subnodehash(nodes, N); if(n->visit == 0){ #if DEBUG if(nodes->count == 1000000){ fprint_subgraph_dot(g, 0, nodes, edges, "1.dot"); } #endif push_seqletv(qs, *q); return 1; } if(n->bt_dir == q->dir2){ push_seqletv(qs, *q); return 1; } n1 = NULL; while(1){ if(n->bt_nidx == MAX_BT_NIDX){ push_seqletv(qs, *q); return 1; } n2 = ref_subnodehash(nodes, n->bt_nidx); n->bt_dir = !n->bt_dir; n->bt_nidx = n1? offset_subnodehash(nodes, n1) : MAX_BT_NIDX; if(n->node == q->node1){ break; } n1 = n; n = n2; } ret = 0; while(1){ n2 = ref_subnodehash(nodes, n->bt_nidx); ret ++; q2 = next_ref_seqletv(qs); q2->node1 = n->node; q2->dir1 = n->bt_dir; q2->node2 = n2->node; q2->dir2 = n2->bt_dir; q2->off = 0; off = 0; edx = n->edges[n->bt_dir].idx; while(edx){ e = ref_subedgev(edges, edx); edx = e->next; if(e->node->node == q2->node2){ off = e->off; break; } } q2->len = 2 * g->reglen + off; if(n2->node == q->node2){ break; } n = n2; } if(ret > 1 && log){ fprintf(log, "N%llu -> N%llu edge_len=%d densified into %u\n", (u8i)q->node1, (u8i)q->node2, q->len, ret); } return ret; } thread_beg_def(mlay); Graph *g; seqletv *path; u8i div_idx; u8i pb, pe; layv *lays; layregv *regs; int all_regs; FILE *log; thread_end_def(mlay); thread_beg_func(mlay); subnodehash *nodes; subnodev *heap; subedgev *edges; readregv *rds; seqletv *lets; BitVec *rdbits; seqlet_t *_let, *let; lay_t *lay; u8i i; u4i j; lets = init_seqletv(4); nodes = init_subnodehash(13); edges = init_subedgev(32); rds = init_readregv(32); heap = init_subnodev(32); rdbits = init_bitvec(mlay->g->reads->size); thread_beg_loop(mlay); clear_layv(mlay->lays); clear_layregv(mlay->regs); for(i=mlay->pb;ipe;i++){ _let = ref_seqletv(mlay->path, i); clear_seqletv(lets); densify_seqlet_graph(mlay->g, _let, lets, 12, rds, nodes, edges, heap, mlay->log); if(lets->size > 1){ for(j=0;jsize;j++){ if(rds->buffer[j].closed == 0){ one_bitvec(rdbits, rds->buffer[j].rid); } } } for(j=0;jsize;j++){ let = ref_seqletv(lets, j); lay = next_ref_layv(mlay->lays); lay->edge = *let; lay->roff = mlay->regs->size; gen_lay_regs_core_graph(mlay->g, let, mlay->regs, lets->size > 1? rdbits : NULL, mlay->all_regs); lay->rcnt = mlay->regs->size - lay->roff; sort_array(mlay->regs->buffer + lay->roff, lay->rcnt, lay_reg_t, num_cmpgt(b.end - b.beg, a.end - a.beg)); if(lay->rcnt == 0 && mlay->log){ thread_beg_syn(mlay); fprintf(mlay->log, " -- N%llu(%c) -> N%llu(%c) has no read path --\n", (u8i)let->node1, "+-"[let->dir1], (u8i)let->node2, "+-"[let->dir2]); fflush(mlay->log); thread_end_syn(mlay); } } if(lets->size > 1){ for(j=0;jsize;j++){ if(rds->buffer[j].closed == 0){ zero_bitvec(rdbits, rds->buffer[j].rid); } } } } thread_end_loop(mlay); free_subnodev(heap); free_readregv(rds); free_subedgev(edges); free_subnodehash(nodes); thread_end_func(mlay); static inline u8i print_ctgs_graph(Graph *g, u8i uid, u8i beg, u8i end, char *prefix, char *lay_suffix, u4i ncpu, FILE *log){ FILE *o_lay; BufferedWriter *bw; layv *lays; layregv *regs; seqletv *path; u8v *divs; seqlet_t *t; lay_t *lay; lay_reg_t *reg; u8i i, pb, pe, d, div_idx, ret; u4i j, c, len, bsize, nrun; thread_preprocess(mlay); o_lay = open_file_for_write(prefix, lay_suffix, 1); bw = zopen_bufferedwriter(o_lay, 1024 * 1024, ncpu, 0); lays = init_layv(32); regs = init_layregv(32); thread_beg_init(mlay, ncpu); mlay->g = g; mlay->path = NULL; mlay->lays = init_layv(32); mlay->regs = init_layregv(32); mlay->pb = 0; mlay->pe = 0; mlay->div_idx = MAX_U8; mlay->all_regs = 1; mlay->log = log; thread_end_init(mlay); ret = 0; bsize = 100; divs = init_u8v(1024); for(i=beg;ictgs, i); if(path->size == 0) continue; len = path->buffer[path->size - 1].off + path->buffer[path->size - 1].len; len = len * KBM_BIN_SIZE; //clear_and_inc_layv(lays, path->size); clear_layv(lays); clear_u8v(divs); clear_layregv(regs); div_idx = 0; pe = 0; nrun = 0; while(1){ pb = pe; pe = num_min(pb + bsize, path->size); thread_wait_one(mlay); if(mlay->div_idx != MAX_U8){ nrun --; divs->buffer[mlay->div_idx * 2 + 0] = lays->size; divs->buffer[mlay->div_idx * 2 + 1] = lays->size + mlay->lays->size; for(j=0;jlays->size;j++){ mlay->lays->buffer[j].roff += regs->size; } append_layv(lays, mlay->lays); clear_layv(mlay->lays); append_layregv(regs, mlay->regs); clear_layregv(mlay->regs); mlay->pb = 0; mlay->pe = 0; mlay->div_idx = MAX_U8; } if(pb < pe){ inc_u8v(divs, 2); mlay->div_idx = div_idx ++; mlay->path = path; mlay->pb = pb; mlay->pe = pe; thread_wake(mlay); nrun ++; } else if(nrun == 0){ break; } } //thread_apply_all(mlay, EXPR(mlay->path = path)); uid ++; ret ++; { beg_bufferedwriter(bw); fprintf(bw->out, ">ctg%llu nodes=%llu len=%u\n", uid, (u8i)path->size + 1, len); if(log) fprintf(log, "OUTPUT_CTG\tctg%d -> ctg%d nodes=%llu len=%u\n", (int)i, (int)uid, (u8i)path->size + 1, len); for(d=0;dbuffer[d * 2 + 0]; pe = divs->buffer[d * 2 + 1]; flush_bufferedwriter(bw); for(j=pb;jrcnt == 0) continue; t = &lay->edge; fprintf(bw->out, "E\t%d\tN%llu\t%c\tN%llu\t%c\n", (int)t->off * KBM_BIN_SIZE, (u8i)t->node1, "+-"[t->dir1], (u8i)t->node2, "+-"[t->dir2]); for(c=0;crcnt;c++){ reg = ref_layregv(regs, lay->roff + c); fprintf(bw->out, "%c\t%s\t%c\t%d\t%d\t", "Ss"[reg->view], g->kbm->reads->buffer[reg->rid].tag, "+-"[reg->dir], reg->beg * KBM_BIN_SIZE, (reg->end - reg->beg) * KBM_BIN_SIZE); if(reg->dir){ print_revseq_basebank(g->kbm->rdseqs, (g->kbm->reads->buffer[reg->rid].seqoff + reg->beg) * KBM_BIN_SIZE, (reg->end - reg->beg) * KBM_BIN_SIZE, bw->out); } else { print_seq_basebank(g->kbm->rdseqs, (g->kbm->reads->buffer[reg->rid].seqoff + reg->beg) * KBM_BIN_SIZE, (reg->end - reg->beg) * KBM_BIN_SIZE, bw->out); } fprintf(bw->out, "\n"); } } } end_bufferedwriter(bw); } } close_bufferedwriter(bw); fclose(o_lay); thread_beg_close(mlay); free_layregv(mlay->regs); free_layv(mlay->lays); thread_end_close(mlay); fprintf(KBM_LOGF, "[%s] output %u contigs\n", date(), (u4i)ret); free_layv(lays); free_layregv(regs); free_u8v(divs); return uid; } static inline u4i print_traces_graph(Graph *g, tracev *path, FILE *out){ String *str; trace_t *t1, *t2; node_t *n1, *n2; reg_t *r1, *r2; edge_ref_t *f; edge_t *e; int offset, fst; u8i beg, end; u4i i, rid; if(path->size < 2) return 0; str = init_string(1024); offset = 0; t1 = ref_tracev(path, 0); for(i=1;isize;i++){ t2 = ref_tracev(path, i); { n1 = ref_nodev(g->nodes, t1->node); n2 = ref_nodev(g->nodes, t2->node); f = t1->edges + t1->dir; e = ref_edgev(g->edges, f->idx); r1 = ref_regv(g->regs, n1->regs.idx); r2 = ref_regv(g->regs, n2->regs.idx); fprintf(out, "E\t%d\tN%llu\t%c\tN%llu\t%c\n", offset, t1->node, "+-"[t1->dir], t2->node, "+-"[t2->dir]); fst = 1; while(r1->node == t1->node && r2->node == t2->node){ if(r1->rid > r2->rid){ r2 ++; } else if(r1->rid < r2->rid){ r1 ++; } else { rid = r1->rid; if(r1->beg < r2->beg){ if(t1->dir ^ r1->dir){ r1 ++; r2 ++; continue; } beg = r1->beg * KBM_BIN_SIZE; end = r2->end * KBM_BIN_SIZE; fprintf(out, "S\t%s\t", g->kbm->reads->buffer[rid].tag); fprintf(out, "+\t%d\t%d\t", (int)beg, (int)(end - beg)); encap_string(str, end - beg); fwdseq_basebank(g->kbm->rdseqs, g->kbm->reads->buffer[rid].seqoff * KBM_BIN_SIZE + beg, end - beg, str->string); fputs(str->string, out); } else { if(!(t1->dir ^ r1->dir)){ r1 ++; r2 ++; continue; } beg = r2->beg * KBM_BIN_SIZE; end = r1->end * KBM_BIN_SIZE; fprintf(out, "S\t%s\t", g->kbm->reads->buffer[rid].tag); fprintf(out, "-\t%d\t%d\t", (int)beg, (int)(end - beg)); encap_string(str, end - beg); revseq_basebank(g->kbm->rdseqs, g->kbm->reads->buffer[rid].seqoff * KBM_BIN_SIZE + beg, end - beg, str->string); fputs(str->string, out); } fputc('\n', out); if(fst){ offset += end - beg; fst = 0; } r1 ++; r2 ++; } } } t1 = t2; } free_string(str); return offset; } static inline u8i print_utgs_graph(Graph *g, char *prefix, char *utg, char *lay){ FILE *o_seq, *o_lay, *files[4]; tracev *path; String *seq; char *str; u8i i, uid, cnt, tot; char ch; int beg, end; files[0] = open_file_for_write(prefix, utg, 1); str = catstr(2, utg, ".filtered"); files[1] = open_file_for_write(prefix, str, 1); free(str); files[2] = open_file_for_write(prefix, lay, 1); str = catstr(2, lay, ".filtered"); files[3] = open_file_for_write(prefix, str, 1); free(str); seq = init_string(1024); tot = cnt = 0; for(i=uid=0;iutgs->size;i++){ path = (tracev*)get_vplist(g->utgs, i); if(gen_seq_traces_graph(g, path, seq) < g->min_ctg_len || (int)path->size < g->min_ctg_nds){ o_seq = files[1]; o_lay = files[3]; } else { o_seq = files[0]; o_lay = files[2]; cnt ++; tot += seq->size; } uid ++; fprintf(o_seq, ">utg%llu len=%d nodes=%llu beg=N%llu end=N%llu\n", (unsigned long long)uid, seq->size, (unsigned long long)path->size, path->buffer[0].node, path->buffer[path->size - 1].node); for(beg=0;begsize;beg+=100){ end = beg + 100; if(end > seq->size) end = seq->size; ch = seq->string[end]; seq->string[end] = '\0'; fprintf(o_seq, "%s\n", seq->string + beg); seq->string[end] = ch; } fprintf(o_lay, ">utg%llu len=%d nodes=%llu\n", (unsigned long long)uid, seq->size, (unsigned long long)path->size); print_traces_graph(g, path, o_lay); } free_string(seq); fprintf(KBM_LOGF, "[%s] %llu unitigs (>= %d bp), total %llu bp\n", date(), (unsigned long long)cnt, g->min_ctg_len, (unsigned long long)tot); fclose(files[0]); fclose(files[1]); fclose(files[2]); fclose(files[3]); return uid; } /* * For debug in GDB * local_dot_node, local_dot_step, and print_local_dot_graph() */ static u8i local_dot_node = 1; static u4i local_dot_step = 10; static inline void get_subgraph_nodes_graph(Graph *g, ptrrefhash *nodes, u8v *stack, uint16_t max_step, u4i closed_val){ node_t *n; edge_ref_t *f; edge_t *e; ptr_ref_t *p, *pp; u8i nid, idx; u4i k, cnt; int exists; clear_u8v(stack); reset_iter_ptrrefhash(nodes); while((p = ref_iter_ptrrefhash(nodes))){ p->cnt = 0; push_u8v(stack, p->idx); } while(stack->size){ p = get_ptrrefhash(nodes, (ptr_ref_t){stack->buffer[--stack->size], 0}); if(p->cnt >> 16) continue; if((p->cnt & 0xFFFF) >= max_step) continue; n = ref_nodev(g->nodes, p->idx); cnt = p->cnt; p->cnt |= 1U << 16; for(k=0;k<2;k++){ idx = n->edges[k].idx; while(idx){ f = ref_edgerefv(g->erefs, idx); idx = f->next; e = ref_edgev(g->edges, f->idx); if(e->closed >= closed_val) continue; nid = f->flg? e->node1 : e->node2; pp = prepare_ptrrefhash(nodes, (ptr_ref_t){nid, 0}, &exists); if(exists) continue; pp->idx = nid; pp->cnt = cnt + 1; push_u8v(stack, nid); } } } } static inline u8i print_local_dot_graph(Graph *g, char *prefix, char *suffix){ FILE *out; ptrrefhash *hash; u8v *stack; ptr_ref_t *p; node_t *n; reg_t *r, *rr; edge_ref_t *f; edge_t *e; unsigned long long i, idx; u4i j, k, max; out = open_file_for_write(prefix, suffix, 1); hash = init_ptrrefhash(1023); stack = init_u8v(32); put_ptrrefhash(hash, (ptr_ref_t){local_dot_node, 0}); get_subgraph_nodes_graph(g, hash, stack, local_dot_step, 1); fprintf(out, "digraph {\n"); fprintf(out, "node [shape=record]\n"); reset_iter_ptrrefhash(hash); while((p = ref_iter_ptrrefhash(hash))){ i = p->idx; n = ref_nodev(g->nodes, i); r = NULL; max = 0; for(j=0;jregs.cnt;j++){ rr = ref_regv(g->regs, n->regs.idx + j); if(g->reads->buffer[rr->rid].regs.cnt > max){ r = rr; max = g->reads->buffer[rr->rid].regs.cnt; } } if(r == NULL) continue; fprintf(out, "N%llu [label=\"{N%llu %d | %s | %c_%d_%d}\"]\n", i, i, n->regs.cnt, g->kbm->reads->buffer[r->rid].tag, "FR"[r->dir], r->beg, r->end - r->beg); } reset_iter_ptrrefhash(hash); while((p = ref_iter_ptrrefhash(hash))){ i = p->idx; n = ref_nodev(g->nodes, i); for(k=0;k<2;k++){ idx = n->edges[k].idx; while(idx){ f = ref_edgerefv(g->erefs, idx); idx = f->next; e = g->edges->buffer + f->idx; if(e->closed) continue; if(f->flg){ //if(!exists_ptrrefhash(hash, (ptr_ref_t){e->node1, 0})) continue; fprintf(out, "N%llu -> N%llu [label=\"%c%c:%d:%d\" color=%s]\n", i, (unsigned long long)e->node1, "+-"[k], "+-"[!e->dir1], e->cov, e->off, colors[k][!e->dir1]); } else { //if(!exists_ptrrefhash(hash, (ptr_ref_t){e->node2, 0})) continue; fprintf(out, "N%llu -> N%llu [label=\"%c%c:%d:%d\" color=%s]\n", i, (unsigned long long)e->node2, "+-"[k], "+-"[e->dir2], e->cov, e->off, colors[k][e->dir2]); } } } } fprintf(out, "}\n"); fclose(out); return 0; } static inline u8i print_dot_full_graph(Graph *g, FILE *out){ BufferedWriter *bw; node_t *n; reg_t *r, *rr; edge_ref_t *f; edge_t *e; unsigned long long i, idx; u4i j, k, max; bw = zopen_bufferedwriter(out, 1024 * 1024, 8, 0); beg_bufferedwriter(bw); fprintf(bw->out, "digraph {\n"); fprintf(bw->out, "node [shape=record]\n"); for(i=0;inodes->size;i++){ if((i % 1000) == 0) flush_bufferedwriter(bw); n = ref_nodev(g->nodes, i); //if(n->closed) continue; r = NULL; max = 0; for(j=0;jregs.cnt;j++){ rr = ref_regv(g->regs, n->regs.idx + j); if(g->reads->buffer[rr->rid].regs.cnt > max){ r = rr; max = g->reads->buffer[rr->rid].regs.cnt; } } if(r == NULL) continue; fprintf(bw->out, "N%llu [label=\"{N%llu %d | %s | %c_%d_%d}\"]\n", i, i, n->regs.cnt, g->kbm->reads->buffer[r->rid].tag, "FR"[r->dir], r->beg, r->end - r->beg); } for(i=0;inodes->size;i++){ if((i % 1000) == 0) flush_bufferedwriter(bw); n = ref_nodev(g->nodes, i); //if(n->closed) continue; for(k=0;k<2;k++){ idx = n->edges[k].idx; while(idx){ f = ref_edgerefv(g->erefs, idx); idx = f->next; e = g->edges->buffer + f->idx; //if(e->closed) continue; if(f->flg){ fprintf(bw->out, "N%llu -> N%llu [label=\"%c%c:%d:%d\" color=%s%s]\n", i, (unsigned long long)e->node1, "+-"[k], "+-"[!e->dir1], e->cov, e->off, colors[k][!e->dir1], e->closed? " style=dashed" : ""); } else { fprintf(bw->out, "N%llu -> N%llu [label=\"%c%c:%d:%d\" color=%s%s]\n", i, (unsigned long long)e->node2, "+-"[k], "+-"[e->dir2], e->cov, e->off, colors[k][e->dir2], e->closed? " style=dashed" : ""); } } } } fprintf(bw->out, "}\n"); end_bufferedwriter(bw); close_bufferedwriter(bw); return 0; } static inline u8i print_dot_graph(Graph *g, FILE *out){ BufferedWriter *bw; node_t *n; reg_t *r, *rr; edge_ref_t *f; edge_t *e; unsigned long long i, idx; u4i j, k, max; bw = zopen_bufferedwriter(out, 1024 * 1024, 8, 0); beg_bufferedwriter(bw); fprintf(bw->out, "digraph {\n"); fprintf(bw->out, "node [shape=record]\n"); for(i=0;inodes->size;i++){ if((i % 1000) == 0) flush_bufferedwriter(bw); n = ref_nodev(g->nodes, i); if(n->closed) continue; r = NULL; max = 0; for(j=0;jregs.cnt;j++){ rr = ref_regv(g->regs, n->regs.idx + j); if(g->reads->buffer[rr->rid].regs.cnt > max){ r = rr; max = g->reads->buffer[rr->rid].regs.cnt; } } if(r == NULL) continue; fprintf(bw->out, "N%llu [label=\"{N%llu %d | %s | %c_%d_%d}\"]\n", i, i, n->regs.cnt, g->kbm->reads->buffer[r->rid].tag, "FR"[r->dir], r->beg, r->end - r->beg); } for(i=0;inodes->size;i++){ if((i % 1000) == 0) flush_bufferedwriter(bw); n = ref_nodev(g->nodes, i); if(n->closed) continue; for(k=0;k<2;k++){ idx = n->edges[k].idx; while(idx){ f = ref_edgerefv(g->erefs, idx); idx = f->next; e = g->edges->buffer + f->idx; if(e->closed) continue; if(f->flg){ fprintf(bw->out, "N%llu -> N%llu [label=\"%c%c:%d:%d\" color=%s]\n", i, (unsigned long long)e->node1, "+-"[k], "+-"[!e->dir1], e->cov, e->off, colors[k][!e->dir1]); } else { fprintf(bw->out, "N%llu -> N%llu [label=\"%c%c:%d:%d\" color=%s]\n", i, (unsigned long long)e->node2, "+-"[k], "+-"[e->dir2], e->cov, e->off, colors[k][e->dir2]); } } } } fprintf(bw->out, "}\n"); end_bufferedwriter(bw); close_bufferedwriter(bw); return 0; } static inline u8i print_nodes_graph(Graph *g, FILE *out){ node_t *n; reg_t *r; unsigned long long i; u4i j; for(i=0;inodes->size;i++){ n = ref_nodev(g->nodes, i); if(n->closed){ fprintf(out, "N%llu*\t%u", i, n->regs.cnt); } else { fprintf(out, "N%llu\t%u", i, n->regs.cnt); } for(j=0;jregs.cnt;j++){ r = ref_regv(g->regs, n->regs.idx + j); fprintf(out, "\t%s_%c_%d_%d", g->kbm->reads->buffer[r->rid].tag, "FR"[r->dir], r->beg, r->end - r->beg); if(r->closed) fputc('*', out); } fprintf(out, "\n"); } return i; } static inline u8i print_reads_graph(Graph *g, FILE *out){ read_t *rd; reg_t *r; u8i idx; u4i i; for(i=0;ikbm->reads->size;i++){ rd = ref_readv(g->reads, i); fprintf(out, "%s\t%d\t%u", g->kbm->reads->buffer[i].tag, g->kbm->reads->buffer[i].bincnt * KBM_BIN_SIZE, rd->regs.cnt); idx = rd->regs.idx; while(idx){ r = ref_regv(g->regs, idx); fprintf(out, "\tN%llu%s:%c_%d_%d", (unsigned long long)r->node, (r->closed? "*" : (g->nodes->buffer[r->node].closed? "!" : "")), "FR"[r->dir], r->beg, r->end - r->beg); idx = r->read_link; } fprintf(out, "\n"); } return i; } static inline u8i print_frgs_nodes_graph(Graph *g, FILE *out){ frg_t *frg; trace_t *t; node_t *n; u4i i, j; for(i=0;ifrgs->size;i++){ frg = ref_frgv(g->frgs, i); if(frg->closed) continue; fprintf(out, "F%u\t%d\t%d\t%u\t%u", i, frg->length, frg->len, frg->tcnt, frg->ty - frg->tx); for(j=0;jtcnt;j++){ t = ref_tracev(g->traces, frg->toff + j); if(j < frg->tx || j >= frg->ty){ n = ref_nodev(g->nodes, t->node); if(n->rep_idx == MAX_REP_IDX){ fprintf(out, "\tn%llu:%c:%d:::%d", t->node, "+-"[t->dir], t->off, t->cov); } else { fprintf(out, "\tn%llu:%c:%d:F%llu:%c:%d", t->node, "+-"[t->dir], t->off, (u8i)n->rep_idx, "+-"[n->rep_dir], t->cov); } } else { fprintf(out, "\tN%llu:%c:%d", t->node, "+-"[t->dir], t->off); } } fprintf(out, "\n"); } return i; } static inline u8i print_frgs_dot_graph(Graph *g, FILE *_out){ BufferedWriter *bw; frg_t *frg; trace_t *t1, *t2; node_t *n1, *n2; reg_t *r1, *r2, *rr; edge_ref_t *f; lnk_t *e; unsigned long long i, idx; u4i j, k, max; bw = zopen_bufferedwriter(_out, 1024 * 1024, 8, 0); beg_bufferedwriter(bw); fprintf(bw->out, "digraph {\n"); fprintf(bw->out, "node [shape=record]\n"); for(i=0;ifrgs->size;i++){ if((i % 1000) == 0) flush_bufferedwriter(bw); frg = ref_frgv(g->frgs, i); if(frg->closed){ continue; } //if(frg->ty - frg->tx < (u4i)g->min_ctg_nds) continue; t1 = ref_tracev(g->traces, frg->toff + frg->tx); t2 = ref_tracev(g->traces, frg->toff + frg->ty - 1); n1 = ref_nodev(g->nodes, t1->node); n2 = ref_nodev(g->nodes, t2->node); r1 = NULL; max = 0; for(j=0;jregs.cnt;j++){ rr = ref_regv(g->regs, n1->regs.idx + j); if(g->reads->buffer[rr->rid].regs.cnt > max){ r1 = rr; max = g->reads->buffer[rr->rid].regs.cnt; } } if(r1 == NULL){ continue; } r2 = NULL; max = 0; for(j=0;jregs.cnt;j++){ rr = ref_regv(g->regs, n2->regs.idx + j); if(g->reads->buffer[rr->rid].regs.cnt > max){ r2 = rr; max = g->reads->buffer[rr->rid].regs.cnt; } } if(r2 == NULL){ continue; } fprintf(bw->out, "F%llu [label=\"{F%llu %u %u/%u | { {N%llu:%c | %s | %c_%d_%d} | {N%llu:%c | %s | %c_%d_%d}}}\"]\n", i, i, frg->ty - frg->tx, frg->len, frg->length, t1->node, "+-"[t1->dir], g->kbm->reads->buffer[r1->rid].tag, "FR"[r1->dir], r1->beg, r1->end - r1->beg, t2->node, "+-"[t2->dir], g->kbm->reads->buffer[r2->rid].tag, "FR"[r2->dir], r2->beg, r2->end - r2->beg); } for(i=0;ifrgs->size;i++){ if((i % 1000) == 0) flush_bufferedwriter(bw); frg = ref_frgv(g->frgs, i); if(frg->closed) continue; //if(frg->ty - frg->tx < (u4i)g->min_ctg_nds) continue; for(k=0;k<2;k++){ idx = frg->lnks[k].idx; while(idx){ f = ref_edgerefv(g->lrefs, idx); idx = f->next; e = g->lnks->buffer + f->idx; if(e->closed) continue; if(f->flg){ //if(g->frgs->buffer[e->frg1].ty - g->frgs->buffer[e->frg1].tx < (u4i)g->min_ctg_nds) continue; fprintf(bw->out, "F%llu -> F%llu [label=\"%c%c:%d:%d\" color=%s style=%s]\n", i, (u8i)e->frg1, "+-"[k], "+-"[!e->dir1], e->cov, e->off, colors[k][!e->dir1], e->weak? "dashed" : "solid"); } else { //if(g->frgs->buffer[e->frg2].ty - g->frgs->buffer[e->frg2].tx < (u4i)g->min_ctg_nds) continue; fprintf(bw->out, "F%llu -> F%llu [label=\"%c%c:%d:%d\" color=%s style=%s]\n", i, (u8i)e->frg2, "+-"[k], "+-"[e->dir2], e->cov, e->off, colors[k][e->dir2], e->weak? "dashed" : "solid"); } } } } fprintf(bw->out, "}\n"); end_bufferedwriter(bw); close_bufferedwriter(bw); return 0; } typedef u8i (*graph_print_func)(Graph *g, FILE *out); static inline u8i generic_print_graph(Graph *g, graph_print_func func, char *prefix, char *suffix){ FILE *out; char *file; u8i cnt; { fprintf(KBM_LOGF, "[%s] output \"%s%s\".", date(), prefix, suffix? suffix : ""); fflush(KBM_LOGF); file = malloc(strlen(prefix) + (suffix? strlen(suffix) : 0) + 2); sprintf(file, "%s%s", prefix, suffix? suffix : ""); out = fopen(file, "w"); cnt = func(g, out); fclose(out); free(file); fprintf(KBM_LOGF, " Done.\n"); fflush(KBM_LOGF); } return cnt; } #endif wtdbg2-2.5/wtdbg.c000066400000000000000000001423351353664372200140470ustar00rootroot00000000000000/* * * Copyright (c) 2011, Jue Ruan * * * 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 3 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, see . */ #include "wtdbg.h" #include "wtdbg-graph.h" #include #include #ifndef VERSION #define VERSION 0.0 #endif #ifndef RELEASE #define RELEASE 19830203 #endif static struct option prog_opts[] = { {"cpu", 1, 0, 't'}, {"input", 1, 0, 'i'}, {"err-free-seq", 1, 0, 'I'}, {"force", 0, 0, 'f'}, {"prefix", 1, 0, 'o'}, {"preset", 1, 0, 'x'}, {"kmer-fsize", 1, 0, 'k'}, {"kmer-psize", 1, 0, 'p'}, {"kmer-depth-max", 1, 0, 'K'}, {"kmer-depth-min", 1, 0, 'E'}, {"genome-size", 1, 0, 'g'}, {"rdcov-cutoff", 1, 0, 'X'}, {"rdname-filter", 1, 0, 3007}, {"rdname-includeonly", 1, 0, 3008}, {"rdcov-filter", 1, 0, 2009}, //{"kmer-depth-min-filter", 0, 0, 'F'}, {"kmer-subsampling", 1, 0, 'S'}, {"kbm-parts", 1, 0, 1035}, {"dp-max-gap", 1, 0, 2005}, {"dp-max-var", 1, 0, 2006}, {"dp-penalty-gap", 1, 0, 2007}, {"dp-penalty-var", 1, 0, 2008}, {"aln-min-length", 1, 0, 'l'}, {"aln-min-match", 1, 0, 'm'}, {"aln-min-similarity", 1, 0, 's'}, {"aln-max-var", 1, 0, 2004}, {"realign", 0, 0, 'R'}, {"realn-kmer-psize", 1, 0, 3001}, {"realn-kmer-subsampling", 1, 0, 3002}, {"realn-min-length", 1, 0, 3003}, {"realn-min-match", 1, 0, 3004}, {"realn-min-similarity", 1, 0, 3005}, {"realn-max-var", 1, 0, 3006}, //{"corr-mode", 1, 0, 2010}, //{"corr-min", 1, 0, 2012}, //{"corr-max", 1, 0, 2013}, //{"corr-cov", 1, 0, 2014}, //{"corr-block-size", 1, 0, 2015}, //{"corr-block-step", 1, 0, 2016}, {"keep-multiple-alignment-parts", 1, 0, 2011}, {"verbose", 0, 0, 'v'}, {"quiet", 0, 0, 'q'}, {"version", 0, 0, 'V'}, {"help", 0, 0, 1000}, // detailed document {"tidy-reads", 1, 0, 'L'}, {"tidy-name", 0, 0, 1001}, {"err-free-nodes", 0, 0, 1002}, {"limit-input", 1, 0, 1003}, {"node-len", 1, 0, 1004}, {"node-ovl", 1, 0, 1005}, {"node-drop", 1, 0, 1006}, {"edge-min", 1, 0, 'e'}, {"edge-max-span", 1, 0, 3009}, {"node-min", 1, 0, 1007}, {"node-max", 1, 0, 1008}, {"ttr-cutoff-depth", 1, 0, 1009}, {"ttr-cutoff-ratio", 1, 0, 1010}, {"dump-seqs", 1, 0, 1036}, {"dump-kbm", 1, 0, 1011}, {"load-seqs", 1, 0, 2002}, {"load-kbm", 1, 0, 1012}, {"load-alignments", 1, 0, 1013}, {"load-nodes", 1, 0, 2000}, {"load-clips", 1, 0, 2001}, {"aln-strand", 1, 0, 1014}, {"bubble-step", 1, 0, 1015}, {"tip-step", 1, 0, 1016}, {"ctg-min-length", 1, 0, 1017}, {"ctg-min-nodes", 1, 0, 1018}, {"minimal-output", 0, 0, 1019}, {"bin-complexity-cutoff", 1, 0, 1020}, {"aln-dovetail", 1, 0, 1021}, {"no-local-graph-analysis", 0, 0, 1022}, {"no-read-length-sort", 0, 0, 1023}, {"keep-isolated-nodes", 0, 0, 1024}, {"no-read-clip", 0, 0, 1025}, {"no-chainning-clip", 0, 0, 1026}, {"aln-bestn", 1, 0, 1027}, {"aln-maxhit", 1, 0, 1028}, {"aln-kmer-sampling", 1, 0, 1029}, {"aln-noskip", 0, 0, 'A'}, {"node-matched-bins", 1, 0, 1031}, {"rescue-low-cov-edges", 0, 0, 1032}, {"drop-low-cov-edges", 0, 0, 1033}, {"mem-stingy", 0, 0, 1034}, {0, 0, 0, 0} }; int usage(int level){ printf( "WTDBG: De novo assembler for long noisy sequences\n" "Author: Jue Ruan \n" "Version: %s (%s)\n" "Usage: wtdbg2 [options] -i -o [reads.fa ...]\n" "Options:\n" " -i Long reads sequences file (REQUIRED; can be multiple), []\n" " -o Prefix of output files (REQUIRED), []\n" " -t Number of threads, 0 for all cores, [4]\n" " -f Force to overwrite output files\n" " -x Presets, comma delimited, []\n" " preset1/rsII/rs: -p 21 -S 4 -s 0.05 -L 5000\n" " preset2: -p 0 -k 15 -AS 2 -s 0.05 -L 5000\n" " preset3: -p 19 -AS 2 -s 0.05 -L 5000\n" " sequel/sq\n" " nanopore/ont:\n" " (genome size < 1G: preset2) -p 0 -k 15 -AS 2 -s 0.05 -L 5000\n" " (genome size >= 1G: preset3) -p 19 -AS 2 -s 0.05 -L 5000\n" " preset4/corrected/ccs: -p 21 -k 0 -AS 4 -K 0.05 -s 0.5\n" " -g Approximate genome size (k/m/g suffix allowed) [0]\n" " -X Choose the best depth from input reads(effective with -g) [50.0]\n" " -L Choose the longest subread and drop reads shorter than (5000 recommended for PacBio) [0]\n" " Negative integer indicate tidying read names too, e.g. -5000.\n" " -k Kmer fsize, 0 <= k <= 23, [0]\n" " -p Kmer psize, 0 <= p <= 23, [21]\n" " k + p <= 25, seed is +\n" " -K Filter high frequency kmers, maybe repetitive, [1000.05]\n" " >= 1000 and indexing >= (1 - 0.05) * total_kmers_count\n" " -S Subsampling kmers, 1/(<-S>) kmers are indexed, [4.00]\n" " -S is very useful in saving memeory and speeding up\n" " please note that subsampling kmers will have less matched length\n" " -l Min length of alignment, [2048]\n" " -m Min matched length by kmer matching, [200]\n" " -R Enable realignment mode\n" " -A Keep contained reads during alignment\n" " -s Min similarity, calculated by kmer matched length / aligned length, [0.05]\n" " -e Min read depth of a valid edge, [3]\n" " -q Quiet\n" " -v Verbose (can be multiple)\n" " -V Print version information and then exit\n" " --help Show more options\n" , TOSTR(VERSION), TOSTR(RELEASE) ); if(level > 0){ printf( " ** more options **\n" " --cpu \n" " See -t 0, default: all cores\n" " --input +\n" " See -i\n" //" --err-free-seq +\n" //" See -I. Error-free sequences will be firstly token for nodes, if --err-free-nodes is specified, only select nodes from those sequences\n" " --force\n" " See -f\n" " --prefix \n" " See -o\n" " --preset \n" " See -x\n" " --kmer-fsize \n" " See -k 0\n" " --kmer-psize \n" " See -p 21\n" " --kmer-depth-max \n" " See -K 1000.05\n" " -E, --kmer-depth-min \n" " Min kmer frequency, [2]\n" //" --kmer-depth-min-filter\n" //" See -F\n" //" `wtdbg` uses a 4 Gbytes array to counting the occurence (0-3) of kmers in the way of counting-bloom-filter. It will reduce memory space largely\n" //" Orphaned kmers won't appear in building kbm-index\n" " --kmer-subsampling \n" " See -S 4.0\n" " --kbm-parts \n" " Split total reads into multiple parts, index one part by one to save memory, [1]\n" " --aln-kmer-sampling \n" " Select no more than n seeds in a query bin, default: 256\n" " --dp-max-gap \n" " Max number of bin(256bp) in one gap, [4]\n" " --dp-max-var \n" " Max number of bin(256bp) in one deviation, [4]\n" " --dp-penalty-gap \n" " Penalty for BIN gap, [-7]\n" " --dp-penalty-var \n" " Penalty for BIN deviation, [-21]\n" " --aln-min-length \n" " See -l 2048\n" " --aln-min-match \n" " See -m 200. Here the num of matches counting basepair of the matched kmer's regions\n" " --aln-min-similarity \n" " See -s 0.05\n" " --aln-max-var \n" " Max length variation of two aligned fragments, default: 0.25\n" " --aln-dovetail \n" " Retain dovetail overlaps only, the max overhang size is <--aln-dovetail>, the value should be times of 256, -1 to disable filtering, default: 256\n" " --aln-strand \n" " 1: forward, 2: reverse, 3: both. Please don't change the deault vaule 3, unless you exactly know what you are doing\n" " --aln-maxhit \n" " Max n hits for each read in build graph, default: 1000\n" " --aln-bestn \n" " Use best n hits for each read in build graph, 0: keep all, default: 500\n" " .alignments always store all alignments\n" " -R, --realign\n" " Enable re-alignment, see --realn-kmer-psize=15, --realn-kmer-subsampling=1, --realn-min-length=2048, --realn-min-match=200, --realn-min-similarity=0.1, --realn-max-var=0.25\n" " --realn-kmer-psize \n" " Set kmer-psize in realignment, (kmer-ksize always eq 0), default:15\n" " --realn-kmer-subsampling \n" " Set kmer-subsampling in realignment, default:1\n" " --realn-min-length \n" " Set aln-min-length in realignment, default: 2048\n" " --realn-min-match \n" " Set aln-min-match in realignment, default: 200\n" " --realn-min-similarity \n" " Set aln-min-similarity in realignment, default: 0.1\n" " --realn-max-var \n" " Set aln-max-var in realignment, default: 0.25\n" " -A, --aln-noskip\n" " Even a read was contained in previous alignment, still align it against other reads\n" //" --corr-mode \n" //" Default: 0.0. If set > 0 and set --g , will turn on correct-align mode.\n" //" Wtdbg will select * bases from reads of middle length, and align them aginst all reads.\n" //" Then, wtdbg will correct them using POACNS, and query corrected sequences against all reads again\n" //" In correct-align mode, --aln-bestn = unlimited, --no-read-clip, --no-chaining-clip. Will support those features in future\n" //" --corr-min \n" //" --corr-max \n" //" For each read to be corrected, uses at least alignments, and at most alignments\n" //" Default: --corr_min = 5, --corr-max = 10\n" //" --corr-cov \n" //" Default: 0.75. When aligning reads to be corrected, the alignments should cover at least of read length\n" //" --corr-block-size \n" //" Default: 2048. MUST be times of 256bp. Used in POACNS\n" //" --corr-block-step \n" //" Default: 1536. MUST be times of 256bp. Used in POACNS\n" " --keep-multiple-alignment-parts\n" " By default, wtdbg will keep only the best alignment between two reads after chainning. This option will disable it, and keep multiple\n" " --verbose +\n" " See -v. -vvvv will display the most detailed information\n" " --quiet\n" " See -q\n" " --limit-input \n" " Limit the input sequences to at most M bp. Usually for test\n" " -L , --tidy-reads \n" " Default: 0. Pick longest subreads if possible. Filter reads less than <--tidy-reads>. Please add --tidy-name or set --tidy-reads to nagetive value\n" " if want to rename reads. Set to 0 bp to disable tidy. Suggested value is 5000 for pacbio RSII reads\n" " --tidy-name\n" " Rename reads into 'S%%010d' format. The first read is named as S0000000001\n" " --rdname-filter \n" " A file contains lines of reads name to be discarded in loading. If you want to filter reads by yourself, please also set -X 0\n" " --rdname-includeonly \n" " Reverse manner with --rdname-filter\n" //" --keep-name\n" //" Keep orignal read names even with --tidy-reads, '-L 5000 --keep-name' equals '-L -5000'\n" " -g , --genome-size \n" " Provide genome size, e.g. 100.4m, 2.3g. In this version, it is used with -X/--rdcov-cutoff in selecting reads just after readed all.\n" " -X , --rdcov-cutoff \n" " Default: 50.0. Retaining 50.0 folds of genome coverage, combined with -g and --rdcov-filter.\n" " --rdcov-filter [0|1]\n" " Default 0. Strategy 0: retaining longest reads. Strategy 1: retaining medain length reads. \n" " --err-free-nodes\n" " Select nodes from error-free-sequences only. E.g. you have contigs assembled from NGS-WGS reads, and long noisy reads.\n" " You can type '--err-free-seq your_ctg.fa --input your_long_reads.fa --err-free-nodes' to perform assembly somehow act as long-reads scaffolding\n" " --node-len \n" " The default value is 1024, which is times of KBM_BIN_SIZE(always equals 256 bp). It specifies the length of intervals (or call nodes after selecting).\n" " kbm indexs sequences into BINs of 256 bp in size, so that many parameter should be times of 256 bp. There are: --node-len, --node-ovl, --aln-min-length, --aln-dovetail ." " Other parameters are counted in BINs, --dp-max-gap, --dp-max-var .\n" " --node-matched-bins \n" " Min matched bins in a node, default:1\n" " --node-ovl \n" " Default: 256. Max overlap size between two adjacent intervals in any read. It is used in selecting best nodes representing reads in graph\n" " --node-drop \n" " Default: 0.25. Will discard an node when has more this ratio intervals are conflicted with previous generated node\n" " -e , --edge-min=\n" " Default: 3. The minimal depth of a valid edge is set to 3. In another word, Valid edges must be supported by at least 3 reads\n" " When the sequence depth is low, have a try with --edge-min 2. Or very high, try --edge-min 4\n" " --edge-max-span \n" " Default: 1024 BINs. Program will build edges of length no large than 1024\n" " --drop-low-cov-edges\n" " Don't attempt to rescue low coverage edges\n" " --node-min \n" " Min depth of an interval to be selected as valid node. Defaultly, this value is automaticly the same with --edge-min.\n" " --node-max \n" " Nodes with too high depth will be regarded as repetitive, and be masked. Default: 200, more than 200 reads contain this node\n" " --ttr-cutoff-depth , 0\n" " --ttr-cutoff-ratio , 0.5\n" " Tiny Tandom Repeat. A node located inside ttr will bring noisy in graph, should be masked. The pattern of such nodes is:\n" " depth >= <--ttr-cutoff-depth>, and none of their edges have depth greater than depth * <--ttr-cutoff-ratio 0.5>\n" " set --ttr-cutoff-depth 0 to disable ttr masking\n" " --dump-kbm \n" " Dump kbm index into file for loaded by `kbm` or `wtdbg`\n" " --dump-seqs \n" " Dump kbm index (only sequences, no k-mer index) into file for loaded by `kbm` or `wtdbg`\n" " Please note: normally load it with --load-kbm, not with --load-seqs\n" " --load-kbm \n" " Instead of reading sequences and building kbm index, which is time-consumed, loading kbm-index from already dumped file.\n" " Please note that, once kbm-index is mmaped by kbm -R start, will just get the shared memory in minute time.\n" " See `kbm` -R [start | stop]\n" " --load-seqs \n" " Similar with --load-kbm, but only use the sequences in kbmidx, and rebuild index in process's RAM.\n" " --load-alignments +\n" " `wtdbg` output reads' alignments into <--prefix>.alignments, program can load them to fastly build assembly graph. Or you can offer\n" " other source of alignments to `wtdbg`. When --load-alignment, will only reading long sequences but skip building kbm index\n" " You can type --load-alignments more than once to load alignments from many files\n" " --load-clips \n" " Combined with --load-nodes. Load reads clips. You can find it in `wtdbg`'s <--prefix>.clps\n" " --load-nodes \n" " Load dumped nodes from previous execution for fast construct the assembly graph, should be combined with --load-clips. You can find it in `wtdbg`'s <--prefix>.1.nodes\n" " --bubble-step \n" " Max step to search a bubble, meaning the max step from the starting node to the ending node. Default: 40\n" " --tip-step \n" " Max step to search a tip, 10\n" " --ctg-min-length \n" " Min length of contigs to be output, 5000\n" " --ctg-min-nodes \n" " Min num of nodes in a contig to be ouput, 3\n" " --minimal-output\n" " Will generate as less output files (<--prefix>.*) as it can\n" " --bin-complexity-cutoff \n" " Used in filtering BINs. If a BIN has less indexed valid kmers than <--bin-complexity-cutoff 2>, masks it.\n" " --no-local-graph-analysis\n" " Before building edges, for each node, local-graph-analysis reads all related reads and according nodes, and builds a local graph to judge whether to mask it\n" " The analysis aims to find repetitive nodes\n" " --no-read-length-sort\n" " Defaultly, `wtdbg` sorts input sequences by length DSC. The order of reads affects the generating of nodes in selecting important intervals\n" " --keep-isolated-nodes\n" " In graph clean, `wtdbg` normally masks isolated (orphaned) nodes\n" " --no-read-clip\n" " Defaultly, `wtdbg` clips a input sequence by analyzing its overlaps to remove high error endings, rolling-circle repeats (see PacBio CCS), and chimera.\n" " When building edges, clipped region won't contribute. However, `wtdbg` will use them in the final linking of unitigs\n" " --no-chainning-clip\n" " Defaultly, performs alignments chainning in read clipping\n" " ** If '--aln-bestn 0 --no-read-clip', alignments will be parsed directly, and less RAM spent on recording alignments\n" "\n" ); } return (level < 0)? 1 : 0; } static inline int64_t mm_parse_num(const char *str) { double x; char *p; x = strtod(str, &p); if (*p == 'G' || *p == 'g') x *= 1e9; else if (*p == 'M' || *p == 'm') x *= 1e6; else if (*p == 'K' || *p == 'k') x *= 1e3; return (int64_t)(x + .499); } int main(int argc, char **argv){ Graph *g; KBMPar *par, *rpar; KBM *kbm; FileReader *fr; BioSequence *seqs[2], *seq; chash *rdtaghash[2]; cplist *pbs, *ngs, *pws; FILE *evtlog; char *prefix, *rdtag_filter[2], *dump_seqs, *load_seqs, *dump_kbm, *load_kbm, *load_nodes, *load_clips; char regtag[14]; int len, tag_size, asyn_read, preset; u8i tot_bp, cnt, bub, tip, rep, yarn, max_bp, max_idx_bp, nfix, opt_flags; uint32_t i, j, k; int c, opt_idx, ncpu, only_fix, realign, node_cov, max_node_cov, exp_node_cov, min_bins, edge_cov, edge_span, store_low_cov_edge, reglen, regovl, bub_step, tip_step, rep_step; int frgtip_len, ttr_n_cov; int quiet, tidy_reads, filter_rd_strategy, tidy_rdtag, less_out, tip_like, cut_tip, rep_filter, out_alns, cnn_filter, log_rep, rep_detach, del_iso, rdclip, chainning, uniq_hit, bestn, rescue_low_edges; int min_ctg_len, min_ctg_nds, max_trace_end, max_overhang, overwrite, node_order, fast_mode, corr_min, corr_max, corr_bsize, corr_bstep, mem_stingy, num_index; double genome_size, genome_depx; float node_drop, node_mrg, ttr_e_cov, fval, cut_low_edges, corr_mode, corr_cov; pbs = init_cplist(4); ngs = init_cplist(4); pws = init_cplist(4); asyn_read = 1; ncpu = 4; mem_stingy = 0; tidy_reads = 0; tidy_rdtag = -1; preset = 0; genome_size = 0; genome_depx = 50.0; num_index = 1; filter_rd_strategy = 0; fast_mode = 0; // no longer supports corr-mode corr_mode = 0; corr_min = 5; corr_max = 10; corr_cov = 0.75; corr_bsize = 2048; corr_bstep = 2048 - 512; // ------- max_bp = 0; max_idx_bp = 0LLU * 1000 * 1000 * 1000; // unlimited rdtag_filter[0] = NULL; rdtag_filter[1] = NULL; rdtaghash[0] = NULL; rdtaghash[1] = NULL; reglen = 1024; regovl = 256; node_drop = 0.25; node_mrg = 0.9; only_fix = 0; node_cov = 0; // will equal edge_cov, if no --node-cov max_node_cov = 200; exp_node_cov = 40; min_bins = 1; edge_cov = 0; // will be set to 3, if no genome_size available and no -e edge_span = 1024; rdclip = 1; chainning = 1; uniq_hit = 1; bestn = 500; ttr_n_cov = 0; ttr_e_cov = 0.5; dump_seqs = NULL; load_seqs = NULL; dump_kbm = NULL; load_kbm = NULL; load_clips = NULL; load_nodes = NULL; store_low_cov_edge = 1; cut_low_edges = 0.0; rescue_low_edges = 1; bub_step = 40; tip_step = 10; rep_step = 0; max_trace_end = 5; frgtip_len = 50000; prefix = NULL; overwrite = 0; less_out = 0; quiet = 0; rep_filter = 1; tip_like = 0; cut_tip = 1; cnn_filter = 1; log_rep = 1; rep_detach = 0; del_iso = 1; max_overhang = 256; min_ctg_len = 5000; min_ctg_nds = 3; node_order = 0; out_alns = 1; par = init_kbmpar(); par->ksize = 0; par->psize = 21; par->kmer_mod = KBM_N_HASH * 4; par->kmin = 2; par->max_bgap = 4; par->max_bvar = 4; par->self_aln = 1; // won't perform B->A when existing A->B par->rd_len_order = 1; par->min_aln = 2048 / KBM_BIN_SIZE; par->min_mat = 200; par->min_sim = 0.05; par->aln_var = 0.25; realign = 0; rpar = init_kbmpar(); rpar->ksize = 0; rpar->psize = 15; rpar->kmer_mod = KBM_N_HASH; rpar->kmin = 1; rpar->max_bgap = 4; rpar->max_bvar = 4; rpar->self_aln = 0; // won't perform B->A when existing A->B rpar->rd_len_order = 0; rpar->min_aln = 2048 / KBM_BIN_SIZE; rpar->min_mat = 200; rpar->min_sim = 0.1; rpar->aln_var = 0.25; opt_flags = 0; while((c = getopt_long(argc, argv, "ht:i:fo:x:E:k:p:K:S:l:m:s:RvqVe:L:Ag:X:", prog_opts, &opt_idx)) != -1){ switch(c){ case 't': ncpu = atoi(optarg); break; case 'i': push_cplist(pbs, optarg); break; //case 'I': push_cplist(ngs, optarg); par->rd_len_order = 0; break; case 'f': overwrite = 1; break; case 'o': prefix = optarg; break; case 'x': { char *ptr, *beg; beg = optarg; do { ptr = index(beg, ','); if(ptr) *ptr = 0; if(KBM_LOG){ fprintf(KBM_LOGF, " -- Preset: '%s' --", beg); fflush(KBM_LOGF); } if(strcasecmp(beg, "preset1") == 0 || strcasecmp(beg, "rs") == 0 || strcasecmp(beg, "rsII") == 0){ preset = 1; } else if(strcasecmp(beg, "preset2") == 0){ preset = 2; } else if(strcasecmp(beg, "preset3") == 0){ preset = 3; } else if(strcasecmp(beg, "sq") == 0 || strcasecmp(beg, "sequel") == 0){ preset = -1; } else if(strcasecmp(beg, "ont") == 0 || strcasecmp(beg, "nanopore") == 0){ preset = -1; } else if(strcasecmp(beg, "preset4") == 0 || strcasecmp(beg, "ccs") == 0 || strcasecmp(beg, "corrected") == 0){ preset = 4; } else { fprintf(stderr, " ** ERROR: cannot recognize '%s' in '-x %s'\n", beg, optarg); exit(1); } if(KBM_LOG){ fprintf(KBM_LOGF, "\n"); fflush(KBM_LOGF); } if(ptr){ *ptr = ','; beg = ptr + 1; } else { break; } } while(1); } break; case 'k': par->ksize = atoi(optarg); opt_flags |= (1 << 1); break; case 'p': par->psize = atoi(optarg); opt_flags |= (1 << 0); break; case 'K': fval = atof(optarg); par->kmax = fval; par->ktop = fval - par->kmax; opt_flags |= (1 << 6); break; case 'E': par->kmin = atoi(optarg); break; case 'S': par->kmer_mod = UInt(atof(optarg) * KBM_N_HASH); opt_flags |= (1 << 2);break; case 'g': genome_size = mm_parse_num(optarg); break; case 'X': genome_depx = atof(optarg); break; case 3007: rdtag_filter[0] = optarg; break; case 3008: rdtag_filter[1] = optarg; break; case 2009: filter_rd_strategy = atoi(optarg); break; case 2005: par->max_bgap = atoi(optarg); break; case 2006: par->max_bvar = atoi(optarg); break; case 2007: par->pgap = atoi(optarg); break; case 2008: par->pvar = atoi(optarg); break; case 'l': par->min_aln = atoi(optarg) / KBM_BIN_SIZE; break; case 'm': par->min_mat = atoi(optarg); break; case 2004: par->aln_var = atof(optarg); break; case 's': par->min_sim = atof(optarg); opt_flags |= (1 << 3); break; //case 2010: corr_mode = atof(optarg); break; //case 2012: corr_min = atoi(optarg); break; //case 2013: corr_max = atoi(optarg); break; //case 2014: corr_cov = atof(optarg); break; //case 2015: corr_bsize = atoi(optarg); break; //case 2016: corr_bstep = atoi(optarg); break; case 2011: uniq_hit = 0; break; case 'v': KBM_LOG ++; break; case 'q': quiet = 1; break; case 'h': return usage(0); case 1000: return usage(1); case 'L': tidy_reads = atoi(optarg); opt_flags |= (1 << 4); break; case 1001: tidy_rdtag = 1; break; case 1002: only_fix = 1; break; case 1003: max_bp = atol(optarg); break; case 1035: num_index = atoi(optarg); break; case 1004: reglen = atoi(optarg); break; case 1005: regovl = atoi(optarg); break; case 1006: node_drop = atof(optarg); break; case 'e': edge_cov = atoi(optarg); break; case 3009: edge_span = atoi(optarg); break; case 1007: node_cov = atoi(optarg); break; case 1008: max_node_cov = atoi(optarg); break; case 1009: ttr_n_cov = atoi(optarg); break; case 1010: ttr_e_cov = atof(optarg); break; case 1036: dump_seqs = optarg; break; case 2002: load_seqs = optarg; break; case 1011: dump_kbm = optarg; break; case 1012: load_kbm = optarg; break; case 2000: load_nodes = optarg; break; case 2001: load_clips = optarg; break; case 1013: push_cplist(pws, optarg); break; case 1014: par->strand_mask = atoi(optarg); break; case 1015: bub_step = atoi(optarg); break; case 1016: tip_step = atoi(optarg); break; case 1017: min_ctg_len = atoi(optarg); break; case 1018: min_ctg_nds = atoi(optarg); break; case 1019: less_out = 1; break; case 1020: par->min_bin_degree = atoi(optarg); break; case 1021: max_overhang = atoi(optarg); break; case 1022: cnn_filter = 0; break; case 1023: par->rd_len_order = 0; break; case 1024: del_iso = 0; break; case 1025: rdclip = 0; break; case 1026: chainning = 0; break; case 1027: bestn = atoi(optarg); break; case 1028: par->max_hit = atoi(optarg); break; case 1029: par->ksampling = atoi(optarg); break; case 'R': realign = 1; break; case 3001: rpar->psize = atoi(optarg); break; case 3002: rpar->kmer_mod = UInt(atof(optarg) * KBM_N_HASH); break; case 3003: rpar->min_aln = atoi(optarg) / KBM_BIN_SIZE; break; case 3004: rpar->min_mat = atoi(optarg); break; case 3005: rpar->min_sim = atof(optarg); break; case 3006: rpar->aln_var = atof(optarg); break; case 'A': par->skip_contained = 0; opt_flags |= (1 << 5); break; case 1031: min_bins = atoi(optarg); break; case 1032: rescue_low_edges = 1; break; case 1033: rescue_low_edges = 0; break; case 'V': fprintf(stdout, "wtdbg2 %s\n", TOSTR(VERSION)); return 0; case 1034: mem_stingy = 1; break; default: return usage(-1); } } if(optind == 1) return usage(-1); if(optind < argc){ fprintf(stderr, "WARNING: unused command-line arguments. For multiple input files, please apply multiple -i.\n"); fprintf(stderr, "WARNING: try to recognize and add to input files list\n"); for(c=optind;csize + ngs->size == 0) { fprintf(stderr, "ERROR: please specify the input with -i/--load-seqs/--load-kbm\n"); return 1; } if((reglen % KBM_BIN_SIZE)){ reglen = ((reglen + KBM_BIN_SIZE - 1) / KBM_BIN_SIZE) * KBM_BIN_SIZE; fprintf(stderr, " ** Adjust -j to %d\n", reglen); } if(!overwrite && file_exists(prefix)){ fprintf(stderr, "File exists! '%s'\n\n", prefix); return usage(-1); } if(max_idx_bp == 0) max_idx_bp = 0xFFFFFFFFFFFFFFFFLLU; if(preset == -1){ if(genome_size && genome_size < 1000000000LLU){ preset = 2; } else { preset = 3; } } switch(preset){ case 1: if(!(opt_flags & (1 << 1))) par->ksize = 0; if(!(opt_flags & (1 << 0))) par->psize = 21; if(!(opt_flags & (1 << 2))) par->kmer_mod = 4 * KBM_N_HASH; if(!(opt_flags & (1 << 3))) par->min_sim = 0.05; if(!(opt_flags & (1 << 5))) par->skip_contained = 1; if(!(opt_flags & (1 << 4))) tidy_reads = 5000; break; case 2: if(!(opt_flags & (1 << 1))) par->ksize = 15; if(!(opt_flags & (1 << 0))) par->psize = 0; if(!(opt_flags & (1 << 2))) par->kmer_mod = 2 * KBM_N_HASH; if(!(opt_flags & (1 << 3))) par->min_sim = 0.05; if(!(opt_flags & (1 << 5))) par->skip_contained = 0; if(!(opt_flags & (1 << 4))) tidy_reads = 5000; break; case 3: if(!(opt_flags & (1 << 1))) par->ksize = 0; if(!(opt_flags & (1 << 0))) par->psize = 19; if(!(opt_flags & (1 << 2))) par->kmer_mod = 2 * KBM_N_HASH; if(!(opt_flags & (1 << 3))) par->min_sim = 0.05; if(!(opt_flags & (1 << 5))) par->skip_contained = 0; if(!(opt_flags & (1 << 4))) tidy_reads = 5000; break; case 4: if(!(opt_flags & (1 << 1))) par->ksize = 0; if(!(opt_flags & (1 << 0))) par->psize = 21; if(!(opt_flags & (1 << 2))) par->kmer_mod = 4 * KBM_N_HASH; if(!(opt_flags & (1 << 3))) par->min_sim = 0.5; if(!(opt_flags & (1 << 5))) par->skip_contained = 0; if(!(opt_flags & (1 << 6))){ par->kmax = 0; par->ktop = 0.05; } //if(!(opt_flags & (1 << 4))) tidy_reads = 5000; break; } if(par->ksize + par->psize > KBM_MAX_KSIZE){ fprintf(stderr, " -- Invalid kmer size %d+%d=%d > %d in %s -- %s:%d --\n", par->ksize, par->psize, par->ksize + par->psize, KBM_MAX_KSIZE, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); return 1; } if(quiet){ int devnull; devnull = open("/dev/null", O_WRONLY); dup2(devnull, STDERR_FILENO); } if(tidy_rdtag == -1){ if(tidy_reads >= 0){ tidy_rdtag = 0; } else { tidy_rdtag = 1; } } if(tidy_reads < 0) tidy_reads = - tidy_reads; max_bp *= 1000000; BEG_STAT_PROC_INFO(stderr, argc, argv); if(ncpu <= 0 && _sig_proc_deamon) ncpu = _sig_proc_deamon->ncpu; if(ncpu <= 0){ fprintf(stderr, " -- Invalid cpu number '%d' in %s -- %s:%d --\n", ncpu, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); return 1; } if(load_kbm){ fprintf(KBM_LOGF, "[%s] loading kbm index from %s\n", date(), load_kbm); if((kbm = mem_find_obj_file(&kbm_obj_desc, load_kbm, NULL, NULL, NULL, NULL, 0)) == NULL){ fprintf(KBM_LOGF, " -- cannot find mmap object %s --\n", load_kbm); fprintf(KBM_LOGF, " -- try read from file --\n"); kbm = mem_read_obj_file(&kbm_obj_desc, load_kbm, NULL, NULL, NULL, NULL); } nfix = 0; tot_bp = 0; for(i=0;ireads->size;i++) tot_bp += kbm->reads->buffer[i].bincnt * KBM_BIN_SIZE; fprintf(KBM_LOGF, "[%s] Done. %u sequences, %llu bp, parameter('-S %d')\n", date(), (u4i)kbm->reads->size, tot_bp, kbm->par->kmer_mod / KBM_N_HASH); { // check KBMPar if((opt_flags >> 0) & 0x01){ if(kbm->par->psize != par->psize){ fprintf(KBM_LOGF, " ** -p is different, %d != %d\n", kbm->par->psize, par->psize); exit(1); } } else { par->psize = kbm->par->psize; } if((opt_flags >> 1) & 0x01){ if(kbm->par->ksize != par->ksize){ fprintf(KBM_LOGF, " ** -k is different, %d != %d\n", kbm->par->ksize, par->ksize); exit(1); } } else { par->ksize = kbm->par->ksize; } if((opt_flags >> 2) & 0x01){ if(kbm->par->kmer_mod != par->kmer_mod){ fprintf(KBM_LOGF, " ** -S is different, %d != %d\n", kbm->par->kmer_mod / KBM_N_HASH, par->kmer_mod / KBM_N_HASH); exit(1); } } else { par->kmer_mod = kbm->par->kmer_mod; } if((opt_flags >> 3) & 0x01){ if(kbm->par->rd_len_order != par->rd_len_order){ fprintf(KBM_LOGF, " ** par->rd_len_order is different, %d != %d\n", kbm->par->rd_len_order, par->rd_len_order); exit(1); } } else { par->rd_len_order = kbm->par->rd_len_order; } } } else if(load_seqs){ fprintf(KBM_LOGF, "[%s] loading kbm index from %s\n", date(), load_seqs); if((kbm = mem_find_obj_file(&kbm_obj_desc, load_seqs, NULL, NULL, NULL, NULL, 0)) == NULL){ fprintf(KBM_LOGF, " -- cannot find mmap object %s --\n", load_seqs); fprintf(KBM_LOGF, " -- try read from file --\n"); kbm = mem_read_obj_file(&kbm_obj_desc, load_seqs, NULL, NULL, NULL, NULL); } kbm = clone_seqs_kbm(kbm, par); nfix = 0; tot_bp = 0; for(i=0;ireads->size;i++) tot_bp += kbm->reads->buffer[i].bincnt * KBM_BIN_SIZE; fprintf(KBM_LOGF, "[%s] Done. %u sequences, %llu bp\n", date(), (u4i)kbm->reads->size, tot_bp); } else { kbm = init_kbm(par); for(i=0;i<2;i++){ if(rdtag_filter[i]){ rdtaghash[i] = init_chash(1023); fr = open_filereader(rdtag_filter[i], 0); while(readline_filereader(fr)){ char *str = strdup(fr->line->string); put_chash(rdtaghash[i], str); } close_filereader(fr); tidy_reads = 0; } else { rdtaghash[i] = NULL; } } fprintf(KBM_LOGF, "[%s] loading reads\n", date()); tot_bp = 0; nfix = 0; seqs[0] = init_biosequence(); seqs[1] = init_biosequence(); regex_t reg; regmatch_t mats[3]; int z; z = regcomp(®, "^(.+?)/[0-9]+_[0-9]+$", REG_EXTENDED); if(z){ regerror(z, ®, regtag, 13); fprintf(stderr, " -- REGCOMP: %s --\n", regtag); fflush(stderr); return 1; } for(j=0;j<2;j++){ if(j == 0){ if(ngs->size == 0){ continue; } else { fr = open_all_filereader(ngs->size, ngs->buffer, asyn_read); } } else { if(pbs->size == 0){ continue; } else { fr = open_all_filereader(pbs->size, pbs->buffer, asyn_read); } } k = 0; reset_biosequence(seqs[0]); reset_biosequence(seqs[1]); while(1){ int has = readseq_filereader(fr, seqs[k]); if(tidy_reads){ if(has){ if((z = regexec(®, seqs[k]->tag->string, 3, mats, 0)) == 0){ trunc_string(seqs[k]->tag, mats[1].rm_eo); } else if(z != REG_NOMATCH){ regerror(z, ®, regtag, 13); fprintf(stderr, " -- REGEXEC: %s --\n", regtag); fflush(stderr); } //fprintf(stderr, "1: %s len=%d\n", seqs[k]->tag->string, seqs[k]->seq->size); fflush(stderr); //fprintf(stderr, "2: %s len=%d\n", seqs[!k]->tag->string, seqs[!k]->seq->size); fflush(stderr); if(seqs[k]->tag->size == seqs[!k]->tag->size && strcmp(seqs[k]->tag->string, seqs[!k]->tag->string) == 0){ if(seqs[k]->seq->size > seqs[!k]->seq->size){ k = !k; } continue; } else { seq = seqs[!k]; k = !k; } } else { seq = seqs[!k]; } if(seq->seq->size < tidy_reads){ if(has) continue; else break; } if(tidy_rdtag){ sprintf(regtag, "S%010llu", (u8i)kbm->reads->size); clear_string(seq->tag); append_string(seq->tag, regtag, 11); } } else { if(has == 0) break; seq = seqs[k]; if(rdtaghash[0]){ if(exists_chash(rdtaghash[0], seq->tag->string)){ continue; } } if(rdtaghash[1]){ if(!exists_chash(rdtaghash[1], seq->tag->string)){ continue; } } } tag_size = seq->tag->size; for(i=0;(int)iseq->size;i+=WT_MAX_RDLEN){ len = num_min(seq->seq->size - i, WT_MAX_RDLEN); if(i){ append_string(seq->tag, "_V", 2); add_int_string(seq->tag, i / WT_MAX_RDLEN); } if(!KBM_LOG && (kbm->reads->size % 10000) == 0){ fprintf(KBM_LOGF, "\r%u", (u4i)kbm->reads->size); fflush(KBM_LOGF); } //fprintf(stderr, " -- %s len=%d in %s -- %s:%d --\n", seq->tag->string, seq->seq->size, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); if(kbm->reads->size >= WT_MAX_RD){ fprintf(stderr, " -- Read Number Out of Range: %u --\n", (u4i)kbm->reads->size); fflush(stderr); break; } push_kbm(kbm, seq->tag->string, seq->tag->size, seq->seq->string + i, len); if(i){ seq->tag->size = tag_size; seq->tag->string[tag_size] = '\0'; } if(j == 0) nfix ++; } tot_bp += seq->seq->size; if(max_bp && tot_bp >= max_bp){ break; } if(has == 0) break; if(kbm->reads->size >= WT_MAX_RD){ fprintf(stderr, " -- Read Number Out of Range: %u --\n", (u4i)kbm->reads->size); fflush(stderr); break; } } close_filereader(fr); for(i=0;i<2;i++){ if(rdtaghash[i]){ char **str; reset_iter_chash(rdtaghash[i]); while((str = ref_iter_chash(rdtaghash[i]))){ free(*str); } free_chash(rdtaghash[i]); } } } regfree(®); free_biosequence(seqs[0]); free_biosequence(seqs[1]); if(!KBM_LOG){ fprintf(KBM_LOGF, "\r%u reads", (unsigned)kbm->reads->size); fflush(KBM_LOGF); } { if(par->rd_len_order && genome_size > 0 && genome_depx > 0){ cnt = genome_size * genome_depx; if(cnt < tot_bp){ fprintf(KBM_LOGF, "\n[%s] filtering from %u reads (>=%u bp), %llu bp. Try selecting %llu bp", date(), (unsigned)kbm->reads->size, tidy_reads, tot_bp, cnt); fflush(KBM_LOGF); tot_bp = filter_reads_kbm(kbm, cnt, filter_rd_strategy); } } ready_kbm(kbm); fprintf(KBM_LOGF, "\n[%s] Done, %u reads (>=%u bp), %llu bp, %u bins\n", date(), (unsigned)kbm->reads->size, tidy_reads, tot_bp, (u4i)kbm->bins->size); fflush(KBM_LOGF); if(dump_seqs){ FILE *dump; fprintf(KBM_LOGF, "[%s] dump kbm-index (only seqs) to %s ...", date(), dump_seqs); fflush(KBM_LOGF); dump = open_file_for_write(dump_seqs, NULL, 1); mem_dump_obj_file(kbm, 1, &kbm_obj_desc, 1, 0, dump); fclose(dump); fprintf(KBM_LOGF, " Done\n"); fflush(KBM_LOGF); } } } print_proc_stat_info(0); if(edge_cov <= 0){ if(genome_size > 0){ float dep; dep = tot_bp / genome_size; if(dep <= 40){ edge_cov = 2; } else if(dep >= 80){ edge_cov = 4; } else { edge_cov = 3; } } else { edge_cov = 3; } fprintf(KBM_LOGF, "[%s] Set --edge-cov to %d\n", date(), edge_cov); fflush(KBM_LOGF); } //if(genome_size <= 0 && corr_mode > 0){ //fprintf(KBM_LOGF, "[%s] MUST set -g with --corr-mode %f\n", date(), corr_mode); fflush(KBM_LOGF); //return 1; //} if(node_cov == 0) node_cov = edge_cov; fprintf(KBM_LOGF, "KEY PARAMETERS: -k %d -p %d -K %f %s-S %f -s %f -g %llu -X %f -e %d -L %d\n", par->ksize, par->psize, par->kmax + par->ktop, par->skip_contained? "" : "-A ", ((double)par->kmer_mod) / KBM_N_HASH, par->min_sim, (u8i)genome_size, genome_depx, edge_cov, tidy_reads); g = init_graph(kbm); { g->rpar = realign? rpar : NULL; g->genome_size = genome_size; g->num_index = num_index; //g->corr_mode = (corr_mode > 0 && genome_size > 0)? 1 : 0; //g->corr_gcov = corr_mode; //g->corr_min = corr_min; //g->corr_max = corr_max; //g->corr_cov = corr_cov; //g->corr_bsize = corr_bsize; //g->corr_bstep = corr_bstep; g->node_order = node_order; g->mem_stingy = mem_stingy; g->reglen = reglen / KBM_BIN_SIZE; g->regovl = regovl / KBM_BIN_SIZE; g->max_overhang = max_overhang / KBM_BIN_SIZE; g->node_max_conflict = node_drop; g->node_merge_cutoff = node_mrg; g->min_node_cov = node_cov; g->max_node_cov_sg = node_cov; g->max_node_cov = max_node_cov; g->exp_node_cov = exp_node_cov; g->min_node_mats = min_bins; g->min_edge_cov = edge_cov; g->max_edge_span = edge_span; g->max_sg_end = max_trace_end; g->store_low_cov_edge = store_low_cov_edge; g->bub_step = bub_step; g->tip_step = tip_step; g->rep_step = rep_step; g->min_ctg_len = min_ctg_len; g->min_ctg_nds = min_ctg_nds; g->n_fix = nfix; g->only_fix = only_fix; g->rep_filter = rep_filter; g->rep_detach = rep_detach; g->cut_tip = cut_tip; g->chainning_hits = chainning; g->uniq_hit = uniq_hit; g->bestn = bestn; g->minimal_output = less_out; } g->par = par; if(log_rep && !less_out){ evtlog = open_file_for_write(prefix, ".events", 1); } else evtlog = NULL; if(load_nodes && load_clips){ fprintf(KBM_LOGF, "[%s] loading nodes from %s ... ", date(), load_nodes); fflush(KBM_LOGF); FileReader *clp = open_filereader(load_clips, asyn_read); FileReader *nds = open_filereader(load_nodes, asyn_read); load_nodes_graph(g, clp, nds); close_filereader(clp); close_filereader(nds); fprintf(KBM_LOGF, " %llu nodes\n", (u8i)g->nodes->size); print_proc_stat_info(0); } else if(pws->size){ fprintf(KBM_LOGF, "[%s] loading alignments from ", date()); for(i=0;isize;i++){ if(i){ fprintf(KBM_LOGF, ",\"%s\"", pws->buffer[i]); } else { fprintf(KBM_LOGF, "\"%s\"", pws->buffer[i]); } } fprintf(KBM_LOGF, "\n"); fr = open_all_filereader(pws->size, pws->buffer, asyn_read); build_nodes_graph(g, max_idx_bp, ncpu, fr, rdclip, prefix, NULL); close_filereader(fr); fprintf(KBM_LOGF, "[%s] Done, %llu nodes\n", date(), (unsigned long long)g->nodes->size); } else { fprintf(KBM_LOGF, "[%s] generating nodes, %d threads\n", date(), ncpu); build_nodes_graph(g, max_idx_bp, ncpu, NULL, rdclip, prefix, dump_kbm); fprintf(KBM_LOGF, "[%s] Done, %llu nodes\n", date(), (unsigned long long)g->nodes->size); } if(load_nodes == NULL || strlen(load_nodes) != strlen(prefix) + strlen(".1.nodes") || strncmp(load_nodes, prefix, strlen(prefix)) || strcmp(load_nodes + strlen(prefix), ".1.nodes")){ generic_print_graph(g, print_nodes_graph, prefix, ".1.nodes"); } if(1){ estimate_genome_size(g, tot_bp, KBM_LOGF); cnt = mask_nodes_by_cov_graph(g, evtlog); fprintf(KBM_LOGF, "[%s] masked %llu high coverage nodes (>%d or <%d)\n", date(), (unsigned long long)cnt, max_node_cov, node_cov); } if(cnn_filter){ cnt = mask_nodes_by_connectivity_graph(g, ncpu, evtlog); fprintf(KBM_LOGF, "[%s] masked %llu repeat-like nodes by local subgraph analysis\n", date(), (unsigned long long)cnt); } if(tip_like){ cnt = mask_possible_tip_nodes_graph(g); fprintf(KBM_LOGF, "[%s] masked %llu tip-like nodes\n", date(), (unsigned long long)cnt); } fprintf(KBM_LOGF, "[%s] generating edges\n", date()); build_edges_graph(g, ncpu, evtlog); fprintf(KBM_LOGF, "[%s] Done, %llu edges\n", date(), (unsigned long long)g->edges->size); if(ttr_n_cov){ //print_node_edges_cov_graph(g, evtlog); cnt = mask_nodes_by_edge_cov_graph(g, ttr_n_cov, ttr_e_cov, evtlog); fprintf(KBM_LOGF, "[%s] deleted %llu nodes, might be tandom repeats\n", date(), (unsigned long long)cnt); } if(!less_out) generic_print_graph(g, print_reads_graph, prefix, ".1.reads"); if(!less_out) generic_print_graph(g, print_dot_full_graph, prefix, ".1.dot.gz"); fprintf(KBM_LOGF, "[%s] graph clean\n", date()); fflush(KBM_LOGF); if(0){ cnt = mask_read_weak_regs_graph(g, ncpu); fprintf(KBM_LOGF, "[%s] masked %llu regions(%d bp) as unreliable, total regs %llu\n", date(), (unsigned long long)cnt, reglen, (u8i)g->regs->size); } if(cut_low_edges){ cnt = cut_relative_low_cov_edges_graph(g, cut_low_edges); fprintf(KBM_LOGF, "[%s] cut %llu low cov edges\n", date(), (unsigned long long)cnt); } if(rescue_low_edges){ //cnt = rescue_low_cov_tip_edges_graph(g); //cnt = rescue_low_cov_edges_graph(g); cnt = rescue_mercy_edges_graph(g); fprintf(KBM_LOGF, "[%s] rescued %llu low cov edges\n", date(), (unsigned long long)cnt); } cnt = cut_binary_edges_graph(g); fprintf(KBM_LOGF, "[%s] deleted %llu binary edges\n", date(), (unsigned long long)cnt); if(!g->rep_detach && del_iso){ cnt = del_isolated_nodes_graph(g, evtlog); fprintf(KBM_LOGF, "[%s] deleted %llu isolated nodes\n", date(), (unsigned long long)cnt); } //cnt = reduce_transitive_edges_graph(g); cnt = myers_transitive_reduction_graph(g, 1.2f); set_init_ends_graph(g); fprintf(KBM_LOGF, "[%s] cut %llu transitive edges\n", date(), (unsigned long long)cnt); if(del_iso){ cnt = del_isolated_nodes_graph(g, evtlog); if(cnt){ fprintf(KBM_LOGF, "[%s] deleted %llu isolated nodes\n", date(), (unsigned long long)cnt); } } if(!less_out) generic_print_graph(g, print_dot_graph, prefix, ".2.dot.gz"); { bub = tip = rep = yarn = 0; u8i high = 0; int safe = 1; do { c = 0; do { cnt = trim_tips_graph(g, tip_step, bub > 0); tip += cnt; if(cnt) c = 1; } while(cnt); do { cnt = pop_bubbles_graph(g, bub_step, safe); bub += cnt; if(cnt) c = 1; } while(cnt); do { cnt = trim_blunt_tips_graph(g); tip += cnt; if(cnt) c = 1; } while(cnt); do { cnt = pop_bubbles_graph(g, bub_step, safe); bub += cnt; if(cnt) c = 1; } while(cnt); if(c) continue; if(safe == 1){ safe = 0; c = 1; continue; } do { cnt = resolve_yarns_graph(g, bub_step * 5); yarn += cnt; if(cnt) c = 1; } while(cnt); } while(c); do { c = 0; cnt = rescue_high_cov_edges_graph(g, 2, 20); if(cnt){ high += cnt; c = 1; } } while(c); if(bub + tip + high){ fprintf(KBM_LOGF, "[%s] %llu bubbles; %llu tips; %llu yarns; rescued %llu high edges\n", date(), bub, tip, yarn, high); fflush(KBM_LOGF); } //if(bub + tip + yarn){ fprintf(KBM_LOGF, "[%s] %llu bubbles; %llu tips; %llu yarns\n", date(), bub, tip, yarn); fflush(KBM_LOGF); } } if(del_iso){ cnt = del_isolated_nodes_graph(g, evtlog); fprintf(KBM_LOGF, "[%s] deleted %llu isolated nodes\n", date(), (unsigned long long)cnt); } if(!less_out) generic_print_graph(g, print_dot_graph, prefix, ".3.dot.gz"); rep = mask_all_branching_nodes_graph(g); fprintf(KBM_LOGF, "[%s] cut %llu branching nodes\n", date(), rep); if(del_iso){ cnt = del_isolated_nodes_graph(g, evtlog); fprintf(KBM_LOGF, "[%s] deleted %llu isolated nodes\n", date(), (unsigned long long)cnt); } fprintf(KBM_LOGF, "[%s] building unitigs\n", date()); gen_unitigs_graph(g); //fprintf(KBM_LOGF, "[%s] trimming and extending unitigs by local assembly, %d threads\n", date(), ncpu); unitigs2frgs_graph(g, ncpu); if(!less_out) generic_print_graph(g, print_frgs_nodes_graph, prefix, ".frg.nodes"); fprintf(KBM_LOGF, "[%s] generating links\n", date()); cnt = gen_lnks_graph(g, ncpu, evtlog); fprintf(KBM_LOGF, "[%s] generated %llu links\n", date(), cnt); if(!less_out) generic_print_graph(g, print_frgs_dot_graph, prefix, ".frg.dot.gz"); if(1){ cnt = rescue_weak_tip_lnks_graph(g); fprintf(KBM_LOGF, "[%s] rescue %llu weak links\n", date(), (unsigned long long)cnt); } cnt = cut_binary_lnks_graph(g, evtlog); fprintf(KBM_LOGF, "[%s] deleted %llu binary links\n", date(), (unsigned long long)cnt); //cnt = reduce_transitive_lnks_graph(g); cnt = myers_transitive_reduction_frg_graph(g, 10000.1f / KBM_BIN_SIZE); fprintf(KBM_LOGF, "[%s] cut %llu transitive links\n", date(), (unsigned long long)cnt); cnt = remove_boomerangs_frg_graph(g, 30 * 1000 / KBM_BIN_SIZE); fprintf(KBM_LOGF, "[%s] remove %llu boomerangs\n", date(), (unsigned long long)cnt); cnt = cut_weak_branches_frg_graph(g); fprintf(KBM_LOGF, "[%s] remove %llu weak branches\n", date(), (unsigned long long)cnt); //cnt = cut_low_cov_lnks_graph(g, 1); //fprintf(KBM_LOGF, "[%s] deleted %llu low cov links\n", date(), (unsigned long long)cnt); //if(!less_out) generic_print_graph(g, print_frgs_dot_graph, prefix, ".frg.2.dot"); cnt = trim_frgtips_graph(g, frgtip_len); fprintf(KBM_LOGF, "[%s] cut %llu tips\n", date(), (unsigned long long)cnt); //if(!less_out) generic_print_graph(g, print_frgs_dot_graph, prefix, ".frg.3.dot"); bub = 0; do { cnt = pop_frg_bubbles_graph(g, bub_step); bub += cnt; } while(cnt); fprintf(KBM_LOGF, "[%s] pop %llu bubbles\n", date(), bub); { cnt = 0; while(1){ u8i c; if((c = detach_repetitive_frg_graph(g, 100 * 1000 / KBM_BIN_SIZE)) == 0){ break; } cnt += c; } fprintf(KBM_LOGF, "[%s] detached %llu repeat-associated paths\n", date(), (unsigned long long)cnt); } cnt = trim_frgtips_graph(g, frgtip_len); fprintf(KBM_LOGF, "[%s] cut %llu tips\n", date(), (unsigned long long)cnt); if(!less_out) generic_print_graph(g, print_frgs_dot_graph, prefix, ".ctg.dot.gz"); fprintf(KBM_LOGF, "[%s] building contigs\n", date()); cnt = gen_contigs_graph(g, evtlog); fprintf(KBM_LOGF, "[%s] searched %llu contigs\n", date(), (unsigned long long)cnt); if(0){ cnt = gen_complex_contigs_graph(g); u8i sum; seqletv *qs; sum = 0; for(i=g->major_nctg;ictgs->size;i++){ qs = (seqletv*)get_vplist(g->ctgs, i); sum += qs->buffer[qs->size - 1].off + qs->buffer[qs->size - 1].len; } fprintf(KBM_LOGF, "[%s] added %llu unsolved repetitive contigs, %llu bp\n", date(), (unsigned long long)cnt, sum); } n50_stat_contigs_graph(g); //cnt = generic_print_graph(g, print_isolated_nodes_dot_graph, prefix, ".4.dot"); //fprintf(KBM_LOGF, "[%s] %llu nodes not in contigs\n", date(), (unsigned long long)cnt); //cnt = count_isolated_reads_graph(g); //fprintf(KBM_LOGF, "[%s] %llu reads not in contigs\n", date(), (unsigned long long)cnt); cnt = print_ctgs_graph(g, 0, 0, g->major_nctg, prefix, ".ctg.lay.gz", ncpu, evtlog); if(0){ fprintf(KBM_LOGF, "[%s] outputing reptigs\n", date()); cnt = print_ctgs_graph(g, cnt, g->major_nctg, g->ctgs->size, prefix, ".rtg.lay", ncpu, evtlog); } if(evtlog) fclose(evtlog); free_cplist(pbs); free_cplist(ngs); free_cplist(pws); if(load_kbm == NULL) free_kbm(kbm); free_kbmpar(par); free_kbmpar(rpar); free_graph(g); fprintf(KBM_LOGF, "[%s] Program Done\n", date()); END_STAT_PROC_INFO(stderr); return 0; } wtdbg2-2.5/wtdbg.h000066400000000000000000002005641353664372200140530ustar00rootroot00000000000000/* * * Copyright (c) 2011, Jue Ruan * * * 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 3 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, see . */ #ifndef __WTDBG_H_RJ #define __WTDBG_H_RJ #include "kbm.h" #include "kbmpoa.h" #include "filewriter.h" #include "pgzf.h" #include #include #define WT_MAX_RD 0x3FFFFFFF // 1 G #define WT_MAX_RDLEN 0x00FFFFFF // 16 Mb #define WT_MAX_RDBIN 0x0000FFFF // 64 K bins #define WT_MAX_NODE 0x000000FFFFFFFFFFLLU #define WT_MAX_EDGE 0x000000FFFFFFFFFFLLU #define WT_MAX_NODE_EDGES 0xFFFF #define WT_MAX_EDGE_COV 0xFFF typedef struct { u8i rid:30, dir:1, beg:16, end:16, closed:1; } rd_frg_t; define_list(rdfrgv, rd_frg_t); typedef struct { u8i node; u8i rid:30, dir:1, beg:16, end:16, closed:1; } rd_reg_t; define_list(rdregv, rd_reg_t); typedef struct { u8i rid:30, dir:1, beg:16, end:16, closed:1; u8i read_link; } rd_rep_t; define_list(rdrepv, rd_rep_t); typedef struct { u8i node; u8i rid:30, dir:1, beg:16, end:16, closed:1; u8i read_link; } reg_t; define_list(regv, reg_t); typedef struct { uint32_t x, y; } xy_t; define_list(xyv, xy_t); typedef struct { uint64_t idx:46, cnt:18; } vec_ref_t; typedef struct { uint64_t idx:46, cnt:18; } ptr_ref_t; typedef struct { uint64_t idx:46, cnt:18, fix:1, rank:45, score:18; } rnk_ref_t; static const vec_ref_t VEC_REF_NULL = (vec_ref_t){0, 0}; static const ptr_ref_t PTR_REF_NULL = (ptr_ref_t){0, 0}; static const rnk_ref_t RNK_REF_NULL = (rnk_ref_t){0, 0, 0, 0, 0}; define_list(vecrefv, vec_ref_t); define_list(ptrrefv, ptr_ref_t); define_list(rnkrefv, rnk_ref_t); #define ptrref_hashcode(E) u64hashcode((E).idx) #define ptrref_hashequals(E1, E2) ((E1).idx == (E2).idx) define_hashset(ptrrefhash, ptr_ref_t, ptrref_hashcode, ptrref_hashequals); #define WT_EDGE_CLOSED_NULL 0 #define WT_EDGE_CLOSED_MASK 1 #define WT_EDGE_CLOSED_LESS 2 #define WT_EDGE_CLOSED_HARD 3 typedef struct { uint64_t node1:45, dir1:1, dir2:1, status:1, closed:2, flag:2, cov:12; uint64_t node2:45; int64_t off:19; } edge_t; define_list(edgev, edge_t); static inline uint64_t _edge_hashcode(edge_t e){ const uint64_t m = 0xc6a4a7935bd1e995LLU; const int r = 47; uint64_t h = 1023 ^ (16 * m); uint64_t k = (e.node1 << 1) | e.dir1; k *= m; k ^= k >> r; k *= m; h ^= k; h *= m; k = (e.node2 << 1) | e.dir2; k *= m; k ^= k >> r; k *= m; h ^= k; h *= m; h ^= h >> r; h *= m; h ^= h >> r; return h; } #define EDGEHASH(idx) ((edgev *)set->userdata)->buffer[idx] #define edge_hashcode(E) _edge_hashcode(EDGEHASH(E)) #define edge_hashequals(E1, E2) (EDGEHASH(E1).node1 == EDGEHASH(E2).node1 && EDGEHASH(E1).node2 == EDGEHASH(E2).node2 \ && EDGEHASH(E1).dir1 == EDGEHASH(E2).dir1 && EDGEHASH(E1).dir2 == EDGEHASH(E2).dir2) define_hashset(edgehash, uint64_t, edge_hashcode, edge_hashequals); typedef struct { uint64_t idx:63, flg:1; uint64_t next; } edge_ref_t; static const edge_ref_t EDGE_REF_NULL = (edge_ref_t){0x7FFFFFFFFFFFFFFLLU, 1, 0}; define_list(edgerefv, edge_ref_t); #define MAX_REP_IDX MAX_U4 typedef struct { u8i rep_idx:32; u4i unvisit:16, cov:16; u8i closed:1, single_in:1, bt_visit:45, rep_dir:1, bt_idx:16, init_end:1; vec_ref_t regs; ptr_ref_t edges[2]; } node_t; define_list(nodev, node_t); typedef struct { u8i idx:39, flg:1, cnt:24; } hit_lnk_t; define_list(hitlnkv, hit_lnk_t); typedef struct { rd_frg_t frgs[2]; hit_lnk_t lnks[2]; // idx+flg: link, cnt[0]: mat, cnt[1]:cglen } rd_hit_t; define_list(rdhitv, rd_hit_t); typedef struct { u8i visit:63, flag:1; hit_lnk_t hits; // point to the g->rdhits int clps[2]; ptr_ref_t regs; //u2i corr_bincnt; } read_t; define_list(readv, read_t); typedef struct { u8i node; //node_t *n; edge_ref_t edges[2]; u4i dir:2, cov:30; int off; } trace_t; define_list(tracev, trace_t); #define WT_TRACE_MSG_ZERO 0 #define WT_TRACE_MSG_ONE 1 #define WT_TRACE_MSG_MORE 2 #define WT_TRACE_MSG_VISITED 3 #define WT_TRACE_MSG_UNDEF 4 typedef struct { union { struct { u4i frg1:31, dir1:1; u4i frg2:31, dir2:1; }; u8i key; }; u4i cov:13, flag:2, tidx1:8, tidx2:8, weak:1, closed:2; b4i off; } lnk_t; define_list(lnkv, lnk_t); #define lnk_hashcode(E) (E).key #define lnk_hashequals(E1, E2) (E1).key == (E2).key define_hashset(lnkhash, lnk_t, lnk_hashcode, lnk_hashequals); typedef struct { u8i toff:46, tcnt:18; // extended traces and core traces u4i tx, ty; // core traces ptr_ref_t lnks[2]; u4i len, length; u8i rep_idx:48, unvisit:16; u8i closed:1, single_in:1, bt_visit:46, rep_dir:1, bt_idx:16; } frg_t; define_list(frgv, frg_t); typedef struct { edge_ref_t lnks[2]; u4i frg; u4i dir:2, cov:30; int off; u4i tx, ty; } path_t; define_list(pathv, path_t); #define WT_PATH_MSG_ZERO 0 #define WT_PATH_MSG_ONE 1 #define WT_PATH_MSG_MORE 2 #define WT_PATH_MSG_VISITED 3 #define WT_PATH_MSG_UNDEF 4 typedef struct { u8i node1:63, dir1:1; u8i node2:63, dir2:1; b8i off:42, len:22; } seqlet_t; define_list(seqletv, seqlet_t); typedef struct { KBM *kbm; KBMPar *par, *rpar; regv *regs; readv *reads; rdhitv *rdhits; BitsVec *cigars; nodev *nodes; edgev *edges; edgehash *ehash; edgerefv *erefs; frgv *frgs; lnkv *lnks; edgerefv *lrefs; tracev *traces; u8i genome_size; u4i num_index; //u4i corr_mode, corr_min, corr_max; //u4i corr_bsize, corr_bstep; //float corr_cov, corr_gcov; int node_order, mem_stingy; u4i n_fix, only_fix; // first n sequences are accurate contigs; only_fix means whether to include other pacbio sequenes u4i reglen, regovl, bestn; int min_node_mats; int max_overhang, chainning_hits, uniq_hit; float node_max_conflict; // 0.25 float node_merge_cutoff; uint32_t max_node_cov, min_node_cov, exp_node_cov, min_edge_cov, max_edge_span; u4i max_node_cov_sg, max_sg_end; int cut_tip; int store_low_cov_edge; int rep_filter, rep_detach; uint32_t bub_step, tip_step, rep_step; int min_ctg_len, min_ctg_nds, minimal_output; vplist *utgs; u4i major_nctg; vplist *ctgs; } Graph; static const char *colors[2][2] = {{"blue", "green"}, {"red", "gray"}}; static inline Graph* init_graph(KBM *kbm){ Graph *g; u4i rid; g = malloc(sizeof(Graph)); g->kbm = kbm; g->par = kbm->par; g->rpar = NULL; g->regs = init_regv(32); g->reads = init_readv(kbm->reads->size); g->reads->size = kbm->reads->size; for(rid=0;ridreads->size;rid++){ g->reads->buffer[rid].clps[0] = 0; g->reads->buffer[rid].clps[1] = g->kbm->reads->buffer[rid].bincnt; } g->nodes = init_nodev(32); g->rdhits = init_rdhitv(1024); g->cigars = init_bitsvec(1024, 3); g->edges = init_edgev(32); g->ehash = init_edgehash(1023); set_userdata_edgehash(g->ehash, g->edges); g->erefs = init_edgerefv(32); g->frgs = init_frgv(32); g->lnks = init_lnkv(32); g->lrefs = init_edgerefv(32); g->traces = init_tracev(32); g->genome_size = 1024 * 1024 * 1024LLU; g->num_index = 1; //g->corr_mode = 0; //g->corr_min = 5; //g->corr_max = 10; //g->corr_cov = 0.75; //g->corr_gcov = 5.0; //g->corr_bsize = 2048; //g->corr_bstep = 2048 - 512; g->node_order = 0; g->n_fix = 0; g->only_fix = 0; g->reglen = 1024; g->regovl = 256; g->node_max_conflict = 0.25; g->node_merge_cutoff = 0.8; g->max_overhang = -1; g->bestn = 0; g->min_node_mats = 1; g->chainning_hits = 0; g->uniq_hit = 0; g->min_node_cov = 4; g->max_node_cov = 60; g->exp_node_cov = 40; // expected node cov g->min_edge_cov = 4; g->max_edge_span = 1024; // 1024 * 256 = 256 kb g->max_node_cov_sg = 2; g->max_sg_end = 5; g->store_low_cov_edge = 1; g->rep_filter = 1; g->rep_detach = 1; g->bub_step = 10; g->tip_step = 5; g->rep_step = 20; g->cut_tip = 1; g->min_ctg_len = 10000; g->min_ctg_nds = 5; g->minimal_output = 0; g->utgs = init_vplist(32); g->ctgs = init_vplist(32); g->major_nctg = 0; return g; } static inline void free_graph(Graph *g){ u8i i; free_regv(g->regs); free_readv(g->reads); free_nodev(g->nodes); free_rdhitv(g->rdhits); free_bitsvec(g->cigars); free_edgev(g->edges); free_edgehash(g->ehash); free_edgerefv(g->erefs); free_frgv(g->frgs); free_lnkv(g->lnks); free_edgerefv(g->lrefs); free_tracev(g->traces); for(i=0;iutgs->size;i++) free_tracev(g->utgs->buffer[i]); free_vplist(g->utgs); for(i=0;ictgs->size;i++) free_tracev(g->ctgs->buffer[i]); free_vplist(g->ctgs); free(g); } #define KBM_MAP2RDHIT_QUICK static inline int map2rdhits_graph(Graph *g, kbm_map_t *hit){ u4i k, f, d, p, n, add; rd_hit_t *rh, *hp, *hn; read_t *rd; if(hit->mat == 0) return 0; rh = next_ref_rdhitv(g->rdhits); rh->frgs[0] = (rd_frg_t){hit->qidx, hit->qdir, hit->qb, hit->qe, 0}; rh->frgs[1] = (rd_frg_t){hit->tidx, hit->tdir, hit->tb, hit->te, 0}; rh->lnks[0].cnt = hit->mat; rh->lnks[1].cnt = hit->cglen; add = 0; for(k=0;k<2;k++){ rd = ref_readv(g->reads, rh->frgs[k].rid); #ifdef KBM_MAP2RDHIT_QUICK { // Just add it rh->lnks[k].idx = rd->hits.idx; rh->lnks[k].flg = rd->hits.flg; rd->hits.idx = offset_rdhitv(g->rdhits, rh); rd->hits.flg = k; rd->hits.cnt ++; add ++; continue; } #endif hn = ref_rdhitv(g->rdhits, rd->hits.idx); f = rd->hits.flg; hp = NULL; p = 0; n = 1; while(1){ if(hn->lnks[0].cnt <= rh->lnks[0].cnt){ // hit->mat break; } p = f; hp = hn; if(hn->lnks[f].idx == 0) break; f = hn->lnks[p].flg; hn = ref_rdhitv(g->rdhits, hn->lnks[p].idx); n ++; } if(g->bestn && n > g->bestn){ continue; } if(hp == NULL){ rh->lnks[k].idx = rd->hits.idx; rh->lnks[k].flg = rd->hits.flg; rd->hits.idx = offset_rdhitv(g->rdhits, rh); rd->hits.flg = k; } else { rh->lnks[k].idx = hp->lnks[p].idx; rh->lnks[k].flg = hp->lnks[p].flg; hp->lnks[p].idx = offset_rdhitv(g->rdhits, rh); hp->lnks[p].flg = k; } rd->hits.cnt ++; if(g->bestn && rd->hits.cnt > g->bestn){ hn = rh; p = k; while(n < g->bestn){ f = hn->lnks[p].flg; hn = ref_rdhitv(g->rdhits, hn->lnks[p].idx); p = f; n ++; } hp = hn; f = p; while(hn->lnks[f].idx){ d = hn->lnks[f].flg; hn = ref_rdhitv(g->rdhits, hn->lnks[f].idx); hn->frgs[f].closed = 1; f = d; } hp->lnks[p].idx = 0; hp->lnks[p].flg = 0; rd->hits.cnt = n; } add ++; } if(add == 0){ trunc_rdhitv(g->rdhits, 1); g->cigars->size -= hit->cglen; } return add; } static inline int is_dovetail_overlap(Graph *g, kbm_map_t *hit){ read_t *q, *t; int overhangs[2][2]; q = ref_readv(g->reads, hit->qidx); t = ref_readv(g->reads, hit->tidx); overhangs[1][0] = hit->tb - t->clps[0]; overhangs[1][1] = (t->clps[1] - t->clps[0]) - hit->te; if(hit->qdir){ overhangs[0][0] = (q->clps[1] - q->clps[0]) - hit->qe; overhangs[0][1] = hit->qb; } else { overhangs[0][0] = hit->qb; overhangs[0][1] = (q->clps[1] - q->clps[0]) - hit->qe; } if(overhangs[0][0] > g->max_overhang && overhangs[1][0] > g->max_overhang){ return 0; } if(overhangs[0][1] > g->max_overhang && overhangs[1][1] > g->max_overhang){ return 0; } return 1; } // qlen is measured by KBM_BIN_SIZE static inline int hit2rdregs_graph(Graph *g, rdregv *regs, int qlen, kbm_map_t *hit, BitsVec *cigars, u4v *maps[3]){ KBM *kbm; u8i ndoff; u4i bpos[2][2], npos[2][2], clen, ndbeg, qn, j, qbincnt; int tmp, bt, tlen, x, y, mat, beg, end, min_node_len, max_node_len; int mask, closed; kbm = g->kbm; mask = 0; if(g->max_overhang >= 0){ if(!is_dovetail_overlap(g, hit)){ mask = 1; } } qn = g->reglen; min_node_len = (qn - 1); max_node_len = (qn + 1); // translate into reverse sequence order if(qlen == 0){ qbincnt = kbm->reads->buffer[hit->qidx].bincnt; qlen = qbincnt; } else if(qlen > kbm->reads->buffer[hit->qidx].bincnt){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); abort(); } else { qbincnt = qlen; } tlen = kbm->reads->buffer[hit->tidx].bincnt; if(hit->qdir){ tmp = qlen - hit->qb; hit->qb = qlen - hit->qe; hit->qe = tmp; } { clear_u4v(maps[0]); clear_u4v(maps[1]); clear_u4v(maps[2]); clen = hit->cglen; x = -1; y = -1; while(clen){ bt = get_bitsvec(cigars, hit->cgoff + clen - 1); push_u4v(maps[2], !(bt >> 2)); bt = bt & 0x03; switch(bt){ case 0: x ++; y ++; break; case 1: x ++; break; case 2: y ++; break; } push_u4v(maps[0], (x < 0)? 0 : x); push_u4v(maps[1], (y < 0)? 0 : y); clen --; } push_u4v(maps[0], x + 1); push_u4v(maps[1], y + 1); push_u4v(maps[2], 0); #if DEBUG if(x + 1 + hit->qb != hit->qe || y + 1 + hit->tb != hit->te){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); print_hit_kbm(g->kbm, g->kbm->reads->buffer[hit->qidx].tag, g->kbm->reads->buffer[hit->qidx].bincnt * KBM_BIN_SIZE, hit, cigars, NULL, stderr); abort(); } #endif } bpos[0][0] = hit->qb; bpos[0][1] = hit->qe; bpos[1][0] = hit->tb; bpos[1][1] = hit->te; #if 0 fprintf(stdout, "BPOS\t%d\t%d\t%d\t%d\n", bpos[0][0], bpos[0][1], bpos[1][0], bpos[1][1]); for(j=0;jsize;j++){ fprintf(stdout, "%d,%d\t", maps[0]->buffer[j], maps[1]->buffer[j]); if((j % 10) == 9) fprintf(stdout, "\n"); } fprintf(stdout, "\n"); #endif { ndoff = kbm->reads->buffer[hit->qidx].binoff; if(hit->qdir){ ndbeg = qbincnt - bpos[0][0]; ndbeg = ndbeg % qn; ndoff = ndoff + ((qbincnt - (ndbeg + bpos[0][0])) / qn) - 1; } else { ndbeg = (bpos[0][0] % qn)? qn - (bpos[0][0] % qn) : 0; ndoff = ndoff + ((ndbeg + bpos[0][0]) / qn); } x = 0; for(j=ndbeg+bpos[0][0];j+qn<=bpos[0][1];j+=qn){ mat = 0; while(maps[0]->buffer[x] < j - bpos[0][0]){ x ++; } npos[0][0] = maps[1]->buffer[x]; while(maps[0]->buffer[x] == j - bpos[0][0]){ if(maps[2]->buffer[x]) mat ++; x ++; } npos[0][1] = maps[1]->buffer[x]; while(maps[0]->buffer[x] < j + qn - 1 - bpos[0][0]){ if(maps[2]->buffer[x]) mat ++; x ++; } npos[1][0] = maps[1]->buffer[x]; while(maps[0]->buffer[x + 1] == j + qn - 1 - bpos[0][0]){ if(maps[2]->buffer[x]) mat ++; x ++; } npos[1][1] = maps[1]->buffer[x]; // TODO: arbitrarily use outer boundary as matched region, need to test its effect // TODO: whether to remove regs outside clps if(mat >= g->min_node_mats){ beg = (npos[0][0] + bpos[1][0]); end = (npos[1][1] + bpos[1][0] + 1); if(end - beg >= min_node_len && end - beg <= max_node_len){ closed = 0; } else { closed = 1; } #if DEBUG if(beg >= end || beg < 0){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); abort(); } #endif push_rdregv(regs, (rd_reg_t){ndoff, hit->tidx, hit->qdir, beg, end, mask | closed}); } if(hit->qdir){ ndoff --; } else { ndoff ++; } #if 0 rd_reg_t *rg = ref_rdregv(regs, regs->size - 1); fprintf(stdout, "NPOS\tX=%d,%d\tY=%d,%d\t%d\t%d\t%d\t%d\n", j, j - bpos[0][0], j + qn - 1, j + qn - 1 - bpos[0][0], npos[0][0], npos[0][1], npos[1][0], npos[1][1]); fprintf(stdout, "REG\t%llu\t%s\t%c\t%d\t%d\t%d\n", rg->node, kbm->reads->buffer[rg->rid].tag, "+-"[rg->dir], rg->beg, rg->end, rg->end - rg->beg); #endif } } //if(!g->corr_mode){ { ndoff = kbm->reads->buffer[hit->tidx].binoff; ndbeg = (bpos[1][0] % qn)? qn - (bpos[1][0] % qn): 0; ndoff = ndoff + ((ndbeg + bpos[1][0]) / qn); x = 0; for(j=ndbeg+bpos[1][0];j+qn<=bpos[1][1];j+=qn){ mat = 0; while(maps[1]->buffer[x] < j - bpos[1][0]){ x ++; } npos[0][0] = maps[0]->buffer[x]; while(maps[1]->buffer[x] == j - bpos[1][0]){ if(maps[2]->buffer[x]) mat ++; x ++; } npos[0][1] = maps[0]->buffer[x]; while(maps[1]->buffer[x] < j + qn - 1 - bpos[1][0]){ if(maps[2]->buffer[x]) mat ++; x ++; } npos[1][0] = maps[0]->buffer[x]; while(maps[1]->buffer[x + 1] == j + qn - 1 - bpos[1][0]){ if(maps[2]->buffer[x]) mat ++; x ++; } npos[1][1] = maps[0]->buffer[x]; // TODO: arbitrarily use outer boundary as matched region, need to test its effect if(mat >= g->min_node_mats){ if(hit->qdir){ beg = qlen - (npos[1][1] + bpos[0][0] + 1); end = qlen - (npos[0][0] + bpos[0][0]); } else { beg = (npos[0][0] + bpos[0][0]); end = (npos[1][1] + bpos[0][0] + 1); } if(end - beg >= min_node_len && end - beg <= max_node_len){ closed = 0; } else { closed = 1; } #if DEBUG if(beg >= end || beg < 0){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); abort(); } #endif push_rdregv(regs, (rd_reg_t){ndoff, hit->qidx, hit->qdir, beg, end, mask | closed}); #if 0 fprintf(stdout, "NPOS\tX=%d,%d\tY=%d,%d\t%d\t%d\t%d\t%d\n", j, j - bpos[1][0], j + qn - 1, j + qn - 1 - bpos[1][0], npos[0][0], npos[0][1], npos[1][0], npos[1][1]); rd_reg_t *rg = ref_rdregv(regs, regs->size - 1); fprintf(stdout, "REG\t%llu\t%s\t%c\t%d\t%d\t%d\n", rg->node, kbm->reads->buffer[rg->rid].tag, "+-"[rg->dir], rg->beg, rg->end, rg->end - rg->beg); #endif } ndoff ++; } } if(hit->qdir){ tmp = qlen - hit->qb; hit->qb = qlen - hit->qe; hit->qe = tmp; } return !mask; } thread_beg_def(mdbg); Graph *g; KBMAux *aux, *raux; CTGCNS *cc; reg_t reg; rdregv *regs; BitVec *rdflags; u4i beg, end; int raw; FILE *alno; int task; thread_end_def(mdbg); thread_beg_func(mdbg); Graph *g; KBM *kbm; KBMAux *aux, *raux; rdregv *regs; BitVec *rdflags; u4v *maps[3], *tidxs; volatile reg_t *reg; g = mdbg->g; kbm = g->kbm; reg = (reg_t*)&mdbg->reg; aux = mdbg->aux; raux = mdbg->raux; regs = mdbg->regs; rdflags = mdbg->rdflags; maps[0] = init_u4v(32); maps[1] = init_u4v(32); maps[2] = init_u4v(32); tidxs = init_u4v(16); thread_beg_loop(mdbg); if(mdbg->task == 1){ if(reg->closed) continue; //if(g->corr_mode){ if(0){ } else { query_index_kbm(aux, NULL, reg->rid, kbm->rdseqs, (kbm->reads->buffer[reg->rid].seqoff + UInt(reg->beg)) * KBM_BIN_SIZE, UInt(reg->end - reg->beg) * KBM_BIN_SIZE); map_kbm(aux); } if(raux && aux->hits->size){ // refine kbm_read_t *rd; u4i i, j, tidx; clear_kbm(raux->kbm); bitpush_kbm(raux->kbm, NULL, 0, kbm->rdseqs->bits, (kbm->reads->buffer[reg->rid].seqoff + UInt(reg->beg)) * KBM_BIN_SIZE, UInt(reg->end - reg->beg) * KBM_BIN_SIZE); ready_kbm(raux->kbm); simple_index_kbm(raux->kbm, 0, raux->kbm->bins->size); clear_u4v(tidxs); sort_array(aux->hits->buffer, aux->hits->size, kbm_map_t, num_cmpgt(a.tidx, b.tidx)); for(i=0;ihits->size;i++){ if(i && tidxs->buffer[tidxs->size - 1] == aux->hits->buffer[i].tidx) continue; push_u4v(tidxs, aux->hits->buffer[i].tidx); } clear_kbmmapv(aux->hits); clear_bitsvec(aux->cigars); for(i=0;isize;i++){ tidx = get_u4v(tidxs, i); rd = ref_kbmreadv(aux->kbm->reads, tidx); query_index_kbm(raux, rd->tag, tidx, aux->kbm->rdseqs, rd->seqoff * KBM_BIN_SIZE, rd->bincnt * KBM_BIN_SIZE); map_kbm(raux); for(j=0;jhits->size;j++){ flip_hit_kbmaux(aux, raux, j); } } } sort_array(aux->hits->buffer, aux->hits->size, kbm_map_t, num_cmpgt(b.mat, a.mat)); } thread_end_loop(mdbg); free_u4v(maps[0]); free_u4v(maps[1]); free_u4v(maps[2]); free_u4v(tidxs); thread_end_func(mdbg); typedef struct { int pos:19; u4i dir:1, spur:1, dep:11; } rd_clp_t; define_list(rdclpv, rd_clp_t); static inline void clip_read_algo(int clps[2], rdclpv *brks, rdclpv *chis, int avg_dep, int min_dep){ rd_clp_t *c; u4i i; int dep, x, y, max, mx, my; sort_array(brks->buffer, brks->size, rd_clp_t, num_cmpgt((a.pos << 1) | a.dir, (b.pos << 1) | b.dir)); x = y = 0; max = 0; dep = 0; mx = my = 0; for(i=0;isize;i++){ c = ref_rdclpv(brks, i); if(dep >= min_dep){ y = c->pos; if(y - x > max){ max = y - x; mx = x; my = y; } } if(c->dir){ // end of overlap c->dep = dep; dep --; } else { dep ++; c->dep = dep; if(dep == min_dep){ x = c->pos; } } if(c->spur){ push_rdclpv(chis, (rd_clp_t){c->pos - KBM_BIN_SIZE, 0, 0, c->dep}); push_rdclpv(chis, (rd_clp_t){c->pos - 1, 1, 0, c->dep}); push_rdclpv(chis, (rd_clp_t){c->pos, 0, 1, c->dep}); push_rdclpv(chis, (rd_clp_t){c->pos + KBM_BIN_SIZE, 1, 0, c->dep}); } } clps[0] = mx / KBM_BIN_SIZE; clps[1] = my / KBM_BIN_SIZE; if((int)chis->size < avg_dep){ return; } sort_array(chis->buffer, chis->size, rd_clp_t, num_cmpgtx(a.pos, b.pos, b.dir, a.dir)); dep = 0; max = 0; mx = 0; for(i=0;isize;i++){ c = ref_rdclpv(chis, i); if(c->dir){ if(c->spur){ if(dep >= max){ max = dep; mx = i; } } dep --; } else { dep ++; if(c->spur){ if(dep >= max){ max = dep; mx = i; } } } } if(max * 2 < avg_dep){ return; } c = ref_rdclpv(chis, mx); if(c->dep >= avg_dep){ return; } if(2 * c->dep > max + 1){ return; } if(c->pos <= clps[0] * KBM_BIN_SIZE || c->pos >= clps[1] * KBM_BIN_SIZE){ return; } if(c->pos - clps[0] > clps[1] - c->pos){ clps[1] = (c->pos + 1) / KBM_BIN_SIZE; } else { clps[0] = (c->pos + 1) / KBM_BIN_SIZE; } } static inline void clip_read_core(Graph *g, u4i rid, hitlnkv *lnks, rdclpv *brks, rdclpv *chis){ read_t *rd; hit_lnk_t *lnk; rd_hit_t *hit; rd_frg_t *f1, *f2; u4i i; int rlen, dlen, margin, min_dep, dep, avg, x, y; rd = ref_readv(g->reads, rid); rlen = g->kbm->reads->buffer[rid].bincnt; if(rlen == 0){ return; } lnk = &rd->hits; clear_rdclpv(brks); margin = g->max_overhang > 0? g->max_overhang : 4; min_dep = 2; dep = 0; clear_hitlnkv(lnks); while(lnk->idx){ hit = ref_rdhitv(g->rdhits, lnk->idx); f1 = hit->frgs + lnk->flg; if(f1->closed == 0) push_hitlnkv(lnks, *lnk); lnk = hit->lnks + lnk->flg; } for(i=0;isize;i++){ lnk = ref_hitlnkv(lnks, i); hit = ref_rdhitv(g->rdhits, lnk->idx); f1 = hit->frgs + lnk->flg; if(f1->closed == 0){ // whether be contained if(f1->beg <= margin && f1->end + margin >= rlen){ rd->clps[0] = 0; rd->clps[1] = rlen; return; } f2 = hit->frgs + !lnk->flg; dlen = g->kbm->reads->buffer[f2->rid].bincnt; if(f1->dir ^ f2->dir){ x = (f1->beg > margin && f2->end + margin < dlen); y = (f1->end + margin < rlen && f2->beg > margin); } else { x = (f1->beg > margin && f2->beg > margin); y = (f1->end + margin < rlen && f2->end + margin < dlen); } if(x && y){ //push_rdclpv(brks, (rd_clp_t){f1->beg, 0, 1, 0}); //push_rdclpv(brks, (rd_clp_t){f1->end, 1, 1, 0}); } else if(x){ push_rdclpv(brks, (rd_clp_t){f1->beg * KBM_BIN_SIZE, 0, 1, 0}); push_rdclpv(brks, (rd_clp_t){f1->end * KBM_BIN_SIZE, 1, 0, 0}); } else if(y){ push_rdclpv(brks, (rd_clp_t){f1->beg * KBM_BIN_SIZE, 0, 0, 0}); push_rdclpv(brks, (rd_clp_t){f1->end * KBM_BIN_SIZE, 1, 1, 0}); } else { dep += f1->end - f1->beg; push_rdclpv(brks, (rd_clp_t){f1->beg * KBM_BIN_SIZE, 0, 0, 0}); push_rdclpv(brks, (rd_clp_t){f1->end * KBM_BIN_SIZE, 1, 0, 0}); } } } clear_rdclpv(chis); avg = (dep + rlen - 1) / rlen; clip_read_algo(rd->clps, brks, chis, avg, min_dep); } thread_beg_def(mclp); Graph *g; int task; thread_end_def(mclp); thread_beg_func(mclp); Graph *g; rdclpv *brks, *chis; hitlnkv *lnks; u4i rid; g = mclp->g; brks = init_rdclpv(32); chis = init_rdclpv(32); lnks = init_hitlnkv(32); thread_beg_loop(mclp); if(mclp->task == 1){ for(rid=mclp->t_idx;ridg->reads->size;rid+=mclp->n_cpu){ clip_read_core(mclp->g, rid, lnks, brks, chis); } } else if(mclp->task == 2){ hitlnkv *lnks, *chks; read_t *rd; hit_lnk_t *lnk; u4i i; lnks = init_hitlnkv(1024); chks = init_hitlnkv(1024); for(rid=mclp->t_idx;ridg->reads->size;rid+=mclp->n_cpu){ rd = ref_readv(g->reads, rid); if(rd->hits.idx == 0) continue; clear_hitlnkv(lnks); lnk = &rd->hits; while(1){ if(lnk->idx == 0) break; push_hitlnkv(lnks, *lnk); lnk = g->rdhits->buffer[lnk->idx].lnks + lnk->flg; } if(lnks->size < 2) continue; sort_array(lnks->buffer, lnks->size, hit_lnk_t, num_cmpgt(g->rdhits->buffer[b.idx].lnks[0].cnt, g->rdhits->buffer[a.idx].lnks[0].cnt)); lnk = &rd->hits; for(i=0;isize;i++){ lnk->idx = lnks->buffer[i].idx; lnk->flg = lnks->buffer[i].flg; lnk = g->rdhits->buffer[lnks->buffer[i].idx].lnks + lnks->buffer[i].flg; } lnk->idx = 0; lnk->flg = 0; { clear_hitlnkv(chks); lnk = &rd->hits; while(1){ if(lnk->idx == 0) break; push_hitlnkv(chks, *lnk); lnk = g->rdhits->buffer[lnk->idx].lnks + lnk->flg; } if(lnks->size != chks->size){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); abort(); } for(i=0;isize;i++){ if(lnks->buffer[i].idx != chks->buffer[i].idx || lnks->buffer[i].flg != chks->buffer[i].flg){ fprintf(stderr, " -- something wrong in %s -- %s:%d --\n", __FUNCTION__, __FILE__, __LINE__); fflush(stderr); abort(); } } } if(g->bestn && lnks->size > mclp->g->bestn){ lnk = lnks->buffer + g->bestn - 1; lnk = g->rdhits->buffer[lnk->idx].lnks + lnk->flg; lnk->idx = 0; lnk->flg = 0; for(i=g->bestn;isize;i++){ lnk = lnks->buffer + i; g->rdhits->buffer[lnk->idx].frgs[lnk->flg].closed = 1; } rd->hits.cnt = g->bestn; } } free_hitlnkv(lnks); free_hitlnkv(chks); } thread_end_loop(mclp); free_rdclpv(brks); free_rdclpv(chis); free_hitlnkv(lnks); thread_end_func(mclp); static inline u8i check_read_reg_conflict_core(Graph *g, rd_reg_t *hit, int *conflict){ read_t *rd; reg_t *reg; u8i idx, pre; int x, y; rd = ref_readv(g->reads, hit->rid); idx = rd->regs.idx; pre = 0; *conflict = 0; while(idx){ reg = ref_regv(g->regs, idx); if(hit->beg >= reg->beg) pre = idx; idx = reg->read_link; if(hit->end <= reg->beg) break; if(hit->beg >= reg->end) continue; if(reg->closed) continue; if(hit->beg <= reg->beg){ x = reg->beg; if(hit->end >= reg->end){ y = reg->end; } else y = hit->end; } else { x = hit->beg; if(hit->end <= reg->end){ y = hit->end; } else y = reg->end; } if(x < y){ if(x + (int)g->regovl < y) *conflict = 1; } } return pre; } thread_beg_def(mupd); Graph *g; rdregv *regs; rnk_ref_t *nd; u8v *ins; u8i vt; thread_end_def(mupd); thread_beg_func(mupd); Graph *g; rdregv *regs; rd_reg_t *hit; u8i pre; u4i i; int conflict; g = mupd->g; regs = mupd->regs; thread_beg_loop(mupd); if(mupd->nd == NULL) continue; clear_u8v(mupd->ins); if(1){ for(i=1;ind->cnt;i++){ if(regs->buffer[mupd->nd->idx + i].rid == regs->buffer[mupd->nd->idx + i - 1].rid){ regs->buffer[mupd->nd->idx + i].closed = 1; regs->buffer[mupd->nd->idx + i - 1].closed = 1; } } } for(i=0;ind->cnt;i++){ hit = ref_rdregv(regs, mupd->nd->idx + i); conflict = 0; pre = check_read_reg_conflict_core(g, hit, &conflict); if(conflict){ hit->closed = 1; } push_u8v(mupd->ins, pre); } thread_end_loop(mupd); thread_end_func(mupd); //TODO: reg_t to store regs, sort them by rank, and sort them by rid in another u4i/u8i array //TODO: fast generate nodes and read_link, then select important intervals static inline void mul_update_regs_graph(Graph *g, rdregv *regs, rnkrefv *nds, u4i ncpu, u8i upds[3]){ u8i idx, vt; u4i i, j, pass; read_t *rd; node_t *n; reg_t *reg, *r; rd_reg_t *hit; int conflict, closed; thread_prepare(mupd); for(i=0;ireads->size;i++){ g->reads->buffer[i].visit = 0; // in which round did the read be touched } encap_regv(g->regs, regs->size + 1); // make sure next_ref_regv in this function is thread-safe thread_beg_init(mupd, ncpu); mupd->g = g; mupd->regs = regs; mupd->nd = NULL; mupd->ins = init_u8v(64); mupd->vt = 0; thread_end_init(mupd); vt = 1; upds[0] = upds[1] = upds[2] = 0; for(idx=0;idxsize+ncpu;idx++){ thread_wait_next(mupd); if(mupd->nd){ pass = 0; for(j=0;jnd->cnt;j++){ hit = ref_rdregv(regs, mupd->nd->idx + j); rd = ref_readv(g->reads, hit->rid); if(rd->visit >= mupd->vt){ // previous node had changed the layout of this read, need to check conflict again mupd->ins->buffer[j] = check_read_reg_conflict_core(g, hit, &conflict); if(conflict){ hit->closed = 1; } } rd->visit = idx; if(hit->closed == 0) pass ++; } do { closed = 0; if(0 && mupd->nd->cnt > g->max_node_cov){ // Repetitive nodes should be in graph to avoid mis-assembling upds[1] ++; closed = 1; continue; } if(mupd->nd->fix){ if(pass == 0){ upds[1] ++; closed = 1; continue; } else { upds[0] ++; } } else { if(pass < g->min_node_cov || pass < (u4i)(mupd->nd->cnt * (1 - g->node_max_conflict))){ upds[1] ++; closed = 1; continue; } else { upds[0] ++; } } n = next_ref_nodev(g->nodes); n->rep_idx = MAX_REP_IDX; n->unvisit = 0; n->closed = 0; n->single_in = 0; n->bt_visit = 0; n->bt_idx = 0; n->init_end = 0; n->regs.idx = g->regs->size; n->regs.cnt = 0; n->cov = 0; n->edges[0] = PTR_REF_NULL; n->edges[1] = PTR_REF_NULL; for(j=0;jnd->cnt;j++){ hit = ref_rdregv(regs, mupd->nd->idx + j); rd = ref_readv(g->reads, hit->rid); n->regs.cnt ++; reg = next_ref_regv(g->regs); // Now, it is thread-safe reg->node = g->nodes->size - 1; reg->rid = hit->rid; reg->dir = hit->dir; reg->beg = hit->beg; reg->end = hit->end; reg->closed = hit->closed | closed; if(reg->closed == 0) n->cov ++; reg->read_link = 0; if(mupd->ins->buffer[j]){ r = ref_regv(g->regs, mupd->ins->buffer[j]); reg->read_link = r->read_link; r->read_link = g->regs->size - 1; } else { reg->read_link = rd->regs.idx; rd->regs.idx = g->regs->size - 1; } rd->regs.cnt ++; } } while(0); } if(idx < nds->size){ mupd->nd = ref_rnkrefv(nds, idx); mupd->vt = idx; thread_wake(mupd); } else { mupd->nd = NULL; } } thread_beg_close(mupd); free_u8v(mupd->ins); thread_end_close(mupd); } static inline u8i chainning_hits_core(kbmmapv *hits, BitsVec *cigars, int uniq_hit, float aln_var){ kbm_map_t HIT; u8i idx, bst, ite, lst, lsx, nrm; u4i state; sort_array(hits->buffer, hits->size, kbm_map_t, num_cmpgtxx(a.qidx, b.qidx, a.tidx, b.tidx, a.qdir, b.qdir)); nrm = 0; for(idx=lst=lsx=0;idx<=hits->size;idx++){ state = 0; if(idx == hits->size){ state = 1; } else if(hits->buffer[lst].qidx == hits->buffer[idx].qidx && hits->buffer[lst].tidx == hits->buffer[idx].tidx){ if(hits->buffer[lst].qdir == hits->buffer[idx].qdir){ state = 0; } else { state = 2; } } else { state = 1; } if(state){ if(idx > lst + 1){ if(simple_chain_all_maps_kbm(hits->buffer + lst, idx - lst, cigars, &HIT, cigars, aln_var)){ hits->buffer[lst++] = HIT; while(lst < idx){ hits->buffer[lst++].mat = 0; // closed = 1 nrm ++; } } } if(state == 1){ // Choose the best hit if(uniq_hit && idx > lsx + 1){ bst = lsx; for(bst=lsx;bstbuffer[bst].mat) break; } for(ite=bst+1;itebuffer[ite].mat == 0) continue; if((hits->buffer[ite].aln > hits->buffer[bst].aln) || (hits->buffer[ite].aln == hits->buffer[bst].aln && hits->buffer[ite].mat > hits->buffer[bst].mat)){ bst = ite; } } for(ite=lsx;itebuffer[ite].mat = 0; } for(ite=bst+1;itebuffer[ite].mat = 0; } nrm += idx - lsx - 1; } lsx = idx; } lst = idx; } } return nrm; } static inline u8i load_alignments_core(Graph *g, FileReader *pws, int raw, rdregv *regs, u4v *maps[3]){ kbmmapv *hits; BitsVec *cigars; u4v *cgs; kbm_map_t *hit, HIT, *h; cuhash_t *cu; u8i nhit; u4i i, rid; int qlen, val, flg, nwarn, mwarn, ncol; char *cgstr, *qtag; mwarn = 20; nwarn = 0; cgs = init_u4v(4); hits = init_kbmmapv(32); cigars = g->chainning_hits? init_bitsvec(1024, 3) : g->cigars; memset(&HIT, 0, sizeof(kbm_map_t)); hit = &HIT; nhit = 0; while((ncol = readtable_filereader(pws)) != -1){ if((pws->n_line % 100000) == 0){ fprintf(KBM_LOGF, "\r%llu", pws->n_line); fflush(KBM_LOGF); } if(pws->line->buffer[0] == '#'){ //if(strncasecmp(pws->line->buffer, "#corr_mode=1", 12) == 0){ //g->corr_mode = 1; //} continue; } if(ncol < 15) continue; if((cu = get_cuhash(g->kbm->tag2idx, get_col_str(pws, 0))) == NULL){ if(nwarn < mwarn){ fprintf(stderr, " -- Cannot find read \"%s\" in LINE:%llu in %s -- %s:%d --\n", get_col_str(pws, 0), pws->n_line, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); nwarn ++; } continue; } else rid = cu->val; hit->qidx = rid; qtag = get_col_str(pws, 0); hit->qdir = (get_col_str(pws, 1)[0] == '-'); qlen = atoi(get_col_str(pws, 2)); //if(g->corr_mode){ if(0){ //g->reads->buffer[hit->qidx].corr_bincnt = qlen / KBM_BIN_SIZE; } else if(qlen != (int)g->kbm->reads->buffer[hit->qidx].bincnt * KBM_BIN_SIZE){ if(nwarn < mwarn){ fprintf(stderr, " -- inconsisitent read length \"%s\" %d != %d in %s -- %s:%d --\n", qtag, qlen, g->kbm->reads->buffer[hit->qidx].bincnt * KBM_BIN_SIZE, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); nwarn ++; } } hit->qb = atoi(get_col_str(pws, 3)) / KBM_BIN_SIZE; hit->qe = atoi(get_col_str(pws, 4)) / KBM_BIN_SIZE; if((cu = get_cuhash(g->kbm->tag2idx, get_col_str(pws, 5))) == NULL){ if(nwarn < mwarn){ fprintf(stderr, " -- Cannot find read \"%s\" in LINE:%llu in %s -- %s:%d --\n", get_col_str(pws, 5), pws->n_line, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); nwarn ++; } continue; } else rid = cu->val; if(hit->qidx >= rid) continue; hit->tidx = rid; hit->tdir = 0; // col 6 always eq '+' // skil col 7 hit->tb = atoi(get_col_str(pws, 8)) / KBM_BIN_SIZE; hit->te = atoi(get_col_str(pws, 9)) / KBM_BIN_SIZE; // skip col 10-13 hit->mat = atoi(get_col_str(pws, 10)); if(hit->mat < g->par->min_mat) continue; hit->aln = atoi(get_col_str(pws, 11)) / KBM_BIN_SIZE; if(hit->aln < g->par->min_aln) continue; if(hit->mat < hit->aln * KBM_BIN_SIZE * g->par->min_sim) continue; if(num_diff(hit->qe - hit->qb, hit->te - hit->tb) > (int)num_max(g->par->aln_var * hit->aln, 1.0)) continue; hit->cnt = atoi(get_col_str(pws, 12)); hit->gap = atoi(get_col_str(pws, 13)); if(g->chainning_hits){ if(hits->size && peer_kbmmapv(hits)->qidx != hit->qidx){ chainning_hits_core(hits, cigars, g->uniq_hit, g->kbm->par->aln_var); for(i=0;isize;i++){ h = ref_kbmmapv(hits, i); if(h->mat == 0) continue; append_bitsvec(g->cigars, cigars, h->cgoff, h->cglen); h->cgoff = g->cigars->size - h->cglen; nhit ++; map2rdhits_graph(g, h); } clear_kbmmapv(hits); clear_bitsvec(cigars); } } hit->cgoff = cigars->size; clear_u4v(cgs); cgstr = get_col_str(pws, 14); if(cgstr[0] == '*'){ // no cigar continue; } val = 0; while(cgstr[0]){ if(cgstr[0] >= '0' && cgstr[0] <= '9'){ val = val * 10 + (cgstr[0] - '0'); } else { flg = -1; switch(cgstr[0]){ case 'M': flg = 0; break; case 'I': flg = 1; break; case 'D': flg = 2; break; case 'm': flg = 4; break; case 'i': flg = 5; break; case 'd': flg = 6; break; default: fprintf(stderr, " -- Bad cigar '%c' \"%s\" in LINE:%llu in %s -- %s:%d --\n", cgstr[0], get_col_str(pws, 14), pws->n_line, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); exit(1); } if(val == 0) val = 1; push_u4v(cgs, (val << 8) | flg); val = 0; } cgstr ++; } for(i=cgs->size;i>0;i--){ val = cgs->buffer[i - 1] >> 8; flg = cgs->buffer[i - 1] & 0xFF; pushs_bitsvec(cigars, flg, val); } hit->cglen = cigars->size - hit->cgoff; if(raw){ hit2rdregs_graph(g, regs, qlen / KBM_BIN_SIZE, hit, cigars, maps); clear_bitsvec(cigars); } else if(g->chainning_hits){ push_kbmmapv(hits, *hit); } else { map2rdhits_graph(g, hit); } } if(g->chainning_hits){ if(hits->size){ chainning_hits_core(hits, cigars, g->uniq_hit, g->kbm->par->aln_var); for(i=0;isize;i++){ h = ref_kbmmapv(hits, i); if(h->mat == 0) continue; append_bitsvec(g->cigars, cigars, h->cgoff, h->cglen); h->cgoff = g->cigars->size - h->cglen; nhit ++; map2rdhits_graph(g, h); } clear_kbmmapv(hits); clear_bitsvec(cigars); } } fprintf(KBM_LOGF, "\r%llu lines, %llu hits\n", pws->n_line, nhit); free_kbmmapv(hits); if(g->chainning_hits) free_bitsvec(cigars); free_u4v(cgs); return nhit; } static inline u8i proc_alignments_core(Graph *g, int ncpu, int raw, rdregv *regs, u4v *maps[3], char *prefix, char *dump_kbm){ kbm_map_t *hit; kbm_read_t *pb; BitVec *rdflags; BufferedWriter *bw; FILE *alno, *kmlog; u8i nbp, mbp, nhit; u8i i, ib, ie, ic; u4i rid, qb, qe, ii, in; int reset_kbm, n_cpu; thread_prepare(mdbg); if(KBM_LOG) n_cpu = 1; else n_cpu = ncpu; ic = (g->kbm->bins->size + g->num_index - 1) / g->num_index; ie = 0; UNUSED(mbp); #if 0 if(g->corr_mode){ mbp = g->genome_size * g->corr_gcov; qb = qe = g->kbm->reads->size / 2; nbp = g->kbm->reads->buffer[qb].bincnt * KBM_BIN_SIZE; while(nbp < mbp && qb && qe + 1 < g->kbm->reads->size){ qb --; qe ++; nbp += g->kbm->reads->buffer[qb].bincnt * KBM_BIN_SIZE; nbp += g->kbm->reads->buffer[qe].bincnt * KBM_BIN_SIZE; } if(qe < g->kbm->reads->size) qe ++; fprintf(KBM_LOGF, "[%s] turn correct-mode on, reads[%u ~ %u = %u] (%llu bp), genome-size=%llu, corr-gcov=%0.2f, corr-dep=[%d,%d,%0.2f]\n", date(), qb, qe, qe - qb, nbp, g->genome_size, g->corr_gcov, g->corr_min, g->corr_max, g->corr_cov); fflush(KBM_LOGF); } else { #else { #endif qb = 0; qe = g->reads->size; } alno = open_file_for_write(prefix, ".alignments.gz", 1); bw = zopen_bufferedwriter(alno, 1024 * 1024, ncpu, 0); #if 0 if(g->corr_mode){ beg_bufferedwriter(bw); fprintf(bw->out, "#corr_mode=1\n"); end_bufferedwriter(bw); } rdflags = (!g->corr_mode && g->par->skip_contained)? init_bitvec(g->kbm->reads->size) : NULL; in = g->corr_mode? 1 : g->num_index; #else rdflags = (g->par->skip_contained)? init_bitvec(g->kbm->reads->size) : NULL; in = g->num_index; #endif if(g->kbm->seeds->size){ reset_kbm = 0; if(in > 1){ fprintf(KBM_LOGF, " ** WARNNING: change number of kbm index to 1 **\n"); fflush(KBM_LOGF); in = 1; } } else { reset_kbm = 1; } //fix_node = 0; nhit = 0; for(ii=0;iikbm->bins->size); while(ie > 0 && ie < g->kbm->bins->size && g->kbm->bins->buffer[ie - 1].ridx == g->kbm->bins->buffer[ie].ridx) ie ++; #if 0 if(g->corr_mode == 0){ #else { #endif qb = 0; qe = ie? g->kbm->bins->buffer[ie - 1].ridx : 0; } nbp = ((u8i)(ie - ib)) * KBM_BIN_SIZE; if(reset_kbm){ reset_index_kbm(g->kbm); fprintf(KBM_LOGF, "[%s] indexing bins[(%llu,%llu)/%llu] (%llu/%llu bp), %d threads\n", date(), ib, ie, (u8i)g->kbm->bins->size, nbp, (u8i)g->kbm->rdseqs->size, ncpu); fflush(KBM_LOGF); kmlog = (in > 1)? NULL : open_file_for_write(prefix, ".kmerdep", 1); index_kbm(g->kbm, ib, ie, ncpu, kmlog); if(kmlog){ fclose(kmlog); kmlog = NULL; } fprintf(KBM_LOGF, "[%s] Done\n", date()); fflush(KBM_LOGF); if(in == 1 && dump_kbm){ FILE *dump; fprintf(KBM_LOGF, "[%s] dump kbm-index to %s ...", date(), dump_kbm); fflush(KBM_LOGF); dump = open_file_for_write(dump_kbm, NULL, 1); mem_dump_obj_file(g->kbm, 1, &kbm_obj_desc, 1, 0, dump); fclose(dump); fprintf(KBM_LOGF, " Done\n"); fflush(KBM_LOGF); } if(in == 1){ u4i *deps; u8i hidx; kmlog = open_file_for_write(prefix, ".binkmer", 1); deps = calloc(KBM_BIN_SIZE + 1, 4); for(hidx=0;hidxkbm->bins->size;hidx++){ deps[g->kbm->bins->buffer[hidx].degree] ++; } for(hidx=0;hidxminimal_output && 0){ kbm_bin_t *bn; kmlog = open_file_for_write(prefix, ".closed_bins", 1); for(hidx=0;hidxkbm->bins->size;hidx++){ bn = ref_kbmbinv(g->kbm->bins, hidx); if(bn->closed){ fprintf(kmlog, "%s_F_%d_%d\t%d\n", g->kbm->reads->buffer[bn->ridx].tag, bn->off * KBM_BIN_SIZE, KBM_BIN_SIZE, bn->degree); } } fclose(kmlog); } } } { { thread_beg_init(mdbg, n_cpu); mdbg->g = g; memset((void*)&mdbg->reg, 0, sizeof(reg_t)); mdbg->reg.closed = 1; mdbg->aux = init_kbmaux(g->kbm); if(g->rpar){ mdbg->raux = init_kbmaux(init_kbm(g->rpar)); } else { mdbg->raux = NULL; } #if 0 if(g->corr_mode){ KBMBlock *kb; POGPar par; kb = init_kbmblock(g->corr_bsize, g->corr_bstep); //mdbg->cc = init_ctgcns(kb, iter_kbmblock, info_kbmblock, 1, 1, 1, g->corr_max, 200, 100, 1, 96, 2, -5, -2, -4, -1, 16, 3, 0.5, g->corr_bsize - g->corr_bstep + KBM_BIN_SIZE); par = DEFAULT_POG_PAR; par.refmode = 1; mdbg->cc = init_ctgcns(kb, iter_kbmblock, info_kbmblock, 1, 1, g->corr_max, 200, 100, 1, g->corr_bsize - g->corr_bstep + KBM_BIN_SIZE, &par); } else { #else { #endif mdbg->cc = NULL; } mdbg->aux->par = (KBMPar*)malloc(sizeof(KBMPar)); memcpy(mdbg->aux->par, g->par, sizeof(KBMPar)); mdbg->regs = regs; mdbg->rdflags = rdflags; mdbg->beg = 0; mdbg->end = 0; mdbg->raw = raw; mdbg->alno = alno; thread_end_init(mdbg); } thread_beg_iter(mdbg); mdbg->task = 1; thread_end_iter(mdbg); for(rid=qb;rid<=qe+ncpu;rid++){ if(rid < qe){ if(!KBM_LOG && ((rid - qb) % 2000) == 0){ fprintf(KBM_LOGF, "\r%u|%llu", rid - qb, nhit); fflush(KBM_LOGF); } thread_wait_one(mdbg); } else { thread_wait_next(mdbg); pb = NULL; } if(mdbg->reg.closed == 0){ KBMAux *aux = mdbg->aux; //if(g->corr_mode && mdbg->cc->cns->size){ //g->reads->buffer[mdbg->reg.rid].corr_bincnt = mdbg->cc->cns->size / KBM_BIN_SIZE; //} if(alno){ beg_bufferedwriter(bw); //if(g->corr_mode && mdbg->aux->cns->size){ //fprintf(bw->out, "#corrected\t%s\t%u\t", mdbg->cc->tag->string, (u4i)mdbg->cc->cns->size); //println_fwdseq_basebank(mdbg->cc->cns, 0, mdbg->cc->cns->size, bw->out); //} for(i=0;iaux->hits->size;i++){ hit = ref_kbmmapv(mdbg->aux->hits, i); fprint_hit_kbm(mdbg->aux, i, bw->out); } end_bufferedwriter(bw); } for(i=0;iaux->hits->size;i++){ hit = ref_kbmmapv(mdbg->aux->hits, i); if(hit->mat == 0) continue; if(rdflags && g->kbm->reads->buffer[hit->tidx].bincnt < g->kbm->reads->buffer[hit->qidx].bincnt && (hit->tb <= 1 && hit->te + 1 >= (int)(g->kbm->reads->buffer[hit->tidx].bincnt)) && (hit->qb > 1 || hit->qe + 1 < (int)(g->kbm->reads->buffer[hit->qidx].bincnt)) ){ one_bitvec(rdflags, hit->tidx); } } if(g->chainning_hits){ chainning_hits_core(aux->hits, aux->cigars, g->uniq_hit, g->kbm->par->aln_var); } for(i=0;ihits->size;i++){ hit = ref_kbmmapv(aux->hits, i); if(hit->mat == 0) continue; //hit->qb /= KBM_BIN_SIZE; //hit->qe /= KBM_BIN_SIZE; //hit->tb /= KBM_BIN_SIZE; //hit->te /= KBM_BIN_SIZE; //hit->aln /= KBM_BIN_SIZE; nhit ++; append_bitsvec(g->cigars, aux->cigars, hit->cgoff, hit->cglen); hit->cgoff = g->cigars->size - hit->cglen; if(raw){ //hit2rdregs_graph(g, regs, g->corr_mode? mdbg->cc->cns->size / KBM_BIN_SIZE : 0, hit, mdbg->aux->cigars, maps); hit2rdregs_graph(g, regs, 0, hit, mdbg->aux->cigars, maps); } else { map2rdhits_graph(g, hit); } } if(KBM_LOG){ fprintf(KBM_LOGF, "QUERY: %s\t+\t%d\t%d\n", g->kbm->reads->buffer[mdbg->reg.rid].tag, mdbg->reg.beg, mdbg->reg.end); for(i=0;iaux->hits->size;i++){ hit = ref_kbmmapv(mdbg->aux->hits, i); fprintf(KBM_LOGF, "\t%s\t%c\t%d\t%d\t%d\t%d\t%d\n", g->kbm->reads->buffer[hit->tidx].tag, "+-"[hit->qdir], g->kbm->reads->buffer[hit->tidx].bincnt * KBM_BIN_SIZE, hit->tb * KBM_BIN_SIZE, hit->te * KBM_BIN_SIZE, hit->aln * KBM_BIN_SIZE, hit->mat); } } mdbg->reg.closed = 1; } if(rid < qe && (rdflags == NULL || get_bitvec(rdflags, rid) == 0)){ pb = ref_kbmreadv(g->kbm->reads, rid); mdbg->reg = (reg_t){0, rid, 0, 0, pb->bincnt, 0, 0}; thread_wake(mdbg); } } { thread_beg_close(mdbg); free(mdbg->aux->par); free_kbmaux(mdbg->aux); //if(g->corr_mode){ //free_kbmblock((KBMBlock*)mdbg->cc->obj); //free_ctgcns(mdbg->cc); //} if(mdbg->raux){ free_kbm(mdbg->raux->kbm); free_kbmaux(mdbg->raux); } thread_end_close(mdbg); } } if(!KBM_LOG) fprintf(KBM_LOGF, "\r%u reads|total hits %llu\n", qe - qb, nhit); if(reset_kbm){ reset_index_kbm(g->kbm); } } if(bw) close_bufferedwriter(bw); if(alno) fclose(alno); if(rdflags) free_bitvec(rdflags); return nhit; } static inline void build_nodes_graph(Graph *g, u8i maxbp, int ncpu, FileReader *pws, int rdclip, char *prefix, char *dump_kbm){ kbm_map_t *hit, HIT; BitVec *rks; u4v *maps[3]; FILE *clplog; u8i idx, rank, kcnts[256], upds[3], fix_node, nhit; u4i rid, i, dep; int raw; rdregv *regs; rnkrefv *nds; rnk_ref_t *nd; thread_preprocess(mclp); regs = init_rdregv(1024); nds = init_rnkrefv(1024); renew_rdhitv(g->rdhits, 1024); maps[0] = init_u4v(4); maps[1] = init_u4v(4); maps[2] = init_u4v(4); clear_regv(g->regs); next_ref_regv(g->regs); clear_rdhitv(g->rdhits); ZEROS(next_ref_rdhitv(g->rdhits)); //clear_kbmmapv(g->pwalns); clear_bitsvec(g->cigars); raw = !((g->bestn > 0) || rdclip); //if(g->corr_mode){ //raw = 1; //} fix_node = 0; // TODO: new code hasn't coped with contigs+longreads mode if(pws){ nhit = load_alignments_core(g, pws, raw, regs, maps); } else { UNUSED(maxbp); nhit = proc_alignments_core(g, ncpu, raw, regs, maps, prefix, dump_kbm); } print_proc_stat_info(0); if(raw){ fprintf(KBM_LOGF, "[%s] generated %llu regs\n", date(), (u8i)regs->size); } else { #ifdef KBM_MAP2RDHIT_QUICK // sort rdhits and pick bestn { fprintf(KBM_LOGF, "[%s] sorting rdhits ... ", date()); fflush(KBM_LOGF); thread_beg_init(mclp, ncpu); mclp->g = g; mclp->task = 2; thread_end_init(mclp); thread_wake_all(mclp); thread_beg_close(mclp); thread_end_close(mclp); fprintf(KBM_LOGF, "Done\n"); fflush(KBM_LOGF); } #endif // clip reads if(rdclip){ fprintf(KBM_LOGF, "[%s] clipping ... ", date()); fflush(KBM_LOGF); clplog = open_file_for_write(prefix, ".clps", 1); thread_beg_init(mclp, ncpu); mclp->g = g; mclp->task = 1; thread_end_init(mclp); thread_wake_all(mclp); thread_beg_close(mclp); thread_end_close(mclp); u8i tot, clp; tot = clp = 0; for(rid=0;ridreads->size;rid++){ tot += g->kbm->reads->buffer[rid].bincnt * KBM_BIN_SIZE; clp += (g->reads->buffer[rid].clps[1] - g->reads->buffer[rid].clps[0]) * KBM_BIN_SIZE; fprintf(clplog, "%s\t%d\t%d\t%d\n", g->kbm->reads->buffer[rid].tag, g->kbm->reads->buffer[rid].bincnt * KBM_BIN_SIZE, g->reads->buffer[rid].clps[0] * KBM_BIN_SIZE, g->reads->buffer[rid].clps[1] * KBM_BIN_SIZE); } fclose(clplog); fprintf(KBM_LOGF, "%.2f%% bases\n", ((tot - clp) * 100.0) / tot); fflush(KBM_LOGF); } fprintf(KBM_LOGF, "[%s] generating regs ... ", date()); fflush(KBM_LOGF); rd_hit_t *rh; u8i cgoff; cgoff = 0; hit = &HIT; hit->cnt = 0; hit->gap = 0; for(idx=0;idxrdhits->size;idx++){ rh = ref_rdhitv(g->rdhits, idx); hit->cgoff = cgoff; hit->cglen = rh->lnks[1].cnt; cgoff += hit->cglen; if(rh->frgs[0].closed && rh->frgs[1].closed){ continue; } hit->qidx = rh->frgs[0].rid; hit->tidx = rh->frgs[1].rid; hit->qdir = rh->frgs[0].dir; hit->tdir = rh->frgs[1].dir; hit->qb = rh->frgs[0].beg; hit->qe = rh->frgs[0].end; hit->tb = rh->frgs[1].beg; hit->te = rh->frgs[1].end; hit->mat = rh->lnks[0].cnt; hit->aln = num_min(hit->qe - hit->qb, hit->te - hit->tb); //hit2rdregs_graph(g, regs, g->reads->buffer[hit->qidx].corr_bincnt, hit, g->cigars, maps); hit2rdregs_graph(g, regs, g->kbm->reads->buffer[hit->qidx].bincnt, hit, g->cigars, maps); } free_bitsvec(g->cigars); g->cigars = init_bitsvec(1024, 3); fprintf(KBM_LOGF, "%llu\n", (u8i)regs->size); fflush(KBM_LOGF); } free_u4v(maps[0]); free_u4v(maps[1]); free_u4v(maps[2]); // add node itself //if(!g->corr_mode){ { rks = init_bitvec(g->kbm->bins->size); for(idx=0;idxsize;idx++){ one_bitvec(rks, regs->buffer[idx].node); } for(idx=0;idxkbm->bins->size;idx++){ if(get_bitvec(rks, idx)){ rid = g->kbm->bins->buffer[idx].ridx; kbm_read_t *rd = ref_kbmreadv(g->kbm->reads, rid); push_rdregv(regs, (rd_reg_t){idx, rid, 0, (idx - rd->binoff) * g->reglen, (idx + 1 - rd->binoff) * g->reglen, 0}); } } free_bitvec(rks); } // generating nodes fprintf(KBM_LOGF, "[%s] sorting regs ... ", date()); fflush(KBM_LOGF); psort_array(regs->buffer, regs->size, rd_reg_t, ncpu, num_cmpgtxx((a.node << 30) | a.rid, (b.node << 30) | b.rid, a.beg, b.beg, b.end, a.end)); fprintf(KBM_LOGF, " Done\n"); fflush(KBM_LOGF); u4v *kbcnts; kbcnts = init_u4v(1024); rank = 0xFFFFFFFFFFFFFFFFLLU; nd = NULL; fprintf(KBM_LOGF, "[%s] generating intervals ... ", date()); fflush(KBM_LOGF); for(idx=0;idxsize;idx++){ if(0){ kbm_read_t *rd1, *rd2; rd_reg_t *r; r = ref_rdregv(regs, idx); rd1 = ref_kbmreadv(g->kbm->reads, g->kbm->bins->buffer[r->node].ridx); rd2 = ref_kbmreadv(g->kbm->reads, r->rid); fprintf(stdout, "%s\t%c\t%d\t%d\t%s\t%c\t%d\t%d\n", rd1->tag, '+', (int)((r->node) - rd1->binoff) * g->reglen, (int)(r->node - rd1->binoff + 1) * g->reglen, rd2->tag, "+-"[r->dir], r->beg, r->end); } if(regs->buffer[idx].node != rank){ if(nd){ while(nd->cnt >= kbcnts->size) push_u4v(kbcnts, 0); kbcnts->buffer[nd->cnt] ++; } nd = next_ref_rnkrefv(nds); nd->idx = idx; nd->rank = regs->buffer[idx].node; nd->fix = regs->buffer[idx].node < fix_node; nd->cnt = 1; //nd->score = (regs->buffer[idx].beg >= g->reads->buffer[regs->buffer[idx].rid].clps[0] && regs->buffer[idx].end <= g->reads->buffer[regs->buffer[idx].rid].clps[1]); rank = regs->buffer[idx].node; } else { nd->cnt ++; //nd->score += (regs->buffer[idx].beg >= g->reads->buffer[regs->buffer[idx].rid].clps[0] && regs->buffer[idx].end <= g->reads->buffer[regs->buffer[idx].rid].clps[1]); } } if(nd){ while(nd->cnt >= kbcnts->size) push_u4v(kbcnts, 0); kbcnts->buffer[nd->cnt] ++; } // find medean k-bin depth u4i gcov; for(gcov=0,rank=0;gcovsize&&ranksize;gcov++){ rank += kbcnts->buffer[gcov]; } //psort_array(nds->buffer, nds->size, rnk_ref_t, ncpu, num_cmpgtx(b.cnt, a.cnt, a.rank, b.rank)); psort_array(nds->buffer, nds->size, rnk_ref_t, ncpu, num_cmpgtx(num_diff(a.cnt, gcov), num_diff(b.cnt, gcov), a.rank, b.rank)); fprintf(KBM_LOGF, " %llu intervals\n", (u8i)nds->size); fflush(KBM_LOGF); //psort_array(nds->buffer, nds->size, rnk_ref_t, ncpu, num_cmpgtx(b.score, a.score, a.rank, b.rank)); if(0){ memset(kcnts, 0, sizeof(uint64_t) * 256); for(idx=0;idxsize;idx++){ dep = num_min(nds->buffer[idx].cnt, 255); kcnts[dep] ++; } for(i=1;i<51;i++){ fprintf(KBM_LOGF, "%10llu", (long long unsigned int)kcnts[i]); if(((i - 1) % 10) == 9) fprintf(KBM_LOGF, "\n"); } if(((i - 1) % 10) != 0) fprintf(KBM_LOGF, "\n"); } fprintf(KBM_LOGF, "[%s] selecting important intervals from %llu intervals\n", date(), (u8i)nds->size); mul_update_regs_graph(g, regs, nds, ncpu, upds); free_rdregv(regs); free_rnkrefv(nds); encap_regv(g->regs, 1); memset(g->regs->buffer + g->regs->size, 0xFF, sizeof(reg_t)); if(!KBM_LOG) fprintf(KBM_LOGF, "[%s] Intervals: kept %llu, discarded %llu\n", date(), upds[0], upds[1]); print_proc_stat_info(0); } uint32_t estimate_genome_size(Graph *g, unsigned long long tot_bp, FILE *out){ uint64_t kcnts[256]; node_t *n; uint64_t nid, sum, ncnt, pmax; uint32_t i, dep, peak, mid; float avg; ncnt = g->nodes->size; memset(kcnts, 0, sizeof(uint64_t) * 256); sum = 0; for(nid=0;nidnodes, nid); dep = num_min(n->regs.cnt, 255); sum += n->regs.cnt; kcnts[dep] ++; } mid = pmax = 0; while(mid < 255){ pmax += kcnts[mid]; if(pmax >= ncnt / 2) break; mid ++; } avg = 1.0 * sum / (ncnt + 1); fprintf(out, "[%s] median node depth = %d\n", date(), mid); return mid; //TODO: calculate the genome coverage for(i=1;i<51;i++){ fprintf(out, "%10llu", (long long unsigned int)kcnts[i]); if(((i - 1) % 10) == 9) fprintf(out, "\n"); } if(((i - 1) % 10) != 0) fprintf(out, "\n"); return avg; pmax = 0; peak = avg; for(i=g->min_node_cov+1;i<256;i++){ if(kcnts[i] > pmax){ peak = i; pmax = kcnts[i]; } else if(i > avg && kcnts[i] < 0.8 * pmax) break; } fprintf(out, "[%s] depth peak = %d\n", date(), peak); fprintf(out, "[%s] genome size = %llu\n", date(), tot_bp / peak); return peak; } // MUST be called before build_edges static u8i mask_nodes_by_cov_graph(Graph *g, FILE *out){ node_t *n; u8i ret, i; ret = 0; for(i=0;inodes->size;i++){ n = ref_nodev(g->nodes, i); if(n->regs.cnt > g->max_node_cov || n->regs.cnt < g->min_node_cov){ n->closed = 1; ret ++; if(out) fprintf(out, "MASK_COV\tN%llu\t%u\t%u\n", (u8i)i, (u4i)n->regs.cnt, n->cov); } } return ret; } static inline void remove_all_edges_graph(Graph *g){ node_t *n; uint64_t nid; free_edgev(g->edges); g->edges = init_edgev(32); free_edgehash(g->ehash); g->ehash = init_edgehash(1023); set_userdata_edgehash(g->ehash, g->edges); free_edgerefv(g->erefs); g->erefs = init_edgerefv(32); for(nid=0;nidnodes->size;nid++){ n = ref_nodev(g->nodes, nid); n->edges[0] = n->edges[1] = PTR_REF_NULL; } } typedef struct { uint64_t idx:46; int off:18; } edge_off_t; define_list(edgeoffv, edge_off_t); static inline int estimate_edge_length(edge_off_t *ps, uint32_t size, uint32_t idxs[2]){ int64_t tot, var; uint32_t i, b, e, mi; int v, max, len, avg, std; idxs[0] = 0; idxs[1] = size; if(size == 0){ return 0; } if(size <= 2){ return ps[size/2].off; } b = 0; e = size; for(i=b,tot=0;i max){ max = ps[i].off - ps[i-1].off; mi = i; } } if(max < len * 0.5) break; else if(max < 100) break; if(mi - b > e - mi) e = mi; else b = mi; for(i=b,tot=0;i 3 * std) b ++; while(b < e && num_diff(ps[e - 1].off, len) > 3 * std) e --; } idxs[0] = b; idxs[1] = e; } return len; } static inline int calculate_edge_cov_off_graph(Graph *g, edge_t *e, edgeoffv *offs){ node_t *n1, *n2; reg_t *r1, *r2; uint32_t dir1, dir2, cov, idxs[2]; int off; n1 = ref_nodev(g->nodes, e->node1); n2 = ref_nodev(g->nodes, e->node2); r1 = ref_regv(g->regs, n1->regs.idx); r2 = ref_regv(g->regs, n2->regs.idx); cov = e->cov; clear_edgeoffv(offs); while(1){ if(r1->rid > r2->rid){ r2 ++; if(r2->node != e->node2) break; } else if(r1->rid < r2->rid){ r1 ++; if(r1->node != e->node1) break; } else { if(r1->beg < r2->beg){ if(r1->node < r2->node){ dir1 = r1->dir; dir2 = r2->dir; } else { dir1 = !r2->dir; dir2 = !r1->dir; } off = r2->beg - r1->end; } else { if(r2->node < r1->node){ dir1 = r2->dir; dir2 = r1->dir; } else { dir1 = !r1->dir; dir2 = !r2->dir; } off = ((int)r1->beg) - r2->end; } if(dir1 == e->dir1 && dir2 == e->dir2){ push_edgeoffv(offs, (edge_off_t){e - g->edges->buffer, off}); } r1 ++; if(r1->node != e->node1) break; r2 ++; if(r2->node != e->node2) break; } } e->off = estimate_edge_length(offs->buffer, offs->size, idxs); e->cov = idxs[1] - idxs[0]; if(cov != e->cov) return 1; else return 0; } static inline void build_edges_graph(Graph *g, int ncpu, FILE *log){ read_t *rd; node_t *n; edge_t *E, *e; vplist *regs; reg_t *r1, *r2; edge_ref_t f1, f2; edgeoffv *offs; uint64_t idx, lst, cnt, x, *u; uint32_t rid, i, idxs[2]; int exists; UNUSED(log); clear_edgev(g->edges); E = next_ref_edgev(g->edges); memset(E, 0, sizeof(edge_t)); E->closed = WT_EDGE_CLOSED_MASK; E->cov = 1; //E->status = 0; clear_edgehash(g->ehash); offs = init_edgeoffv(32); regs = init_vplist(32); for(rid=0;ridkbm->reads->size;rid++){ rd = ref_readv(g->reads, rid); if(rd->regs.cnt < 2) continue; clear_vplist(regs); idx = rd->regs.idx; while(idx){ r2 = ref_regv(g->regs, idx); idx = r2->read_link; if(g->nodes->buffer[r2->node].closed) continue; if(r2->closed) continue; if(!(r2->beg >= rd->clps[0] && r2->end <= rd->clps[1])) continue; for(i=regs->size;i>0;i--){ r1 = (reg_t*)get_vplist(regs, i - 1); if(r1->end + g->max_edge_span < r2->beg) break; E = ref_edgev(g->edges, 0); if(r1->node < r2->node){ E->node1 = r1->node; E->node2 = r2->node; E->dir1 = r1->dir; E->dir2 = r2->dir; } else { E->node1 = r2->node; E->node2 = r1->node; E->dir1 = !r2->dir; E->dir2 = !r1->dir; } E->off = ((int)r2->beg) - r1->end; u = prepare_edgehash(g->ehash, 0, &exists); if(exists){ //if(g->edges->buffer[*u].cov < WT_MAX_EDGE_COV) g->edges->buffer[*u].cov ++; } else { *u = g->edges->size; push_edgev(g->edges, *E); } if(i == regs->size){ e = ref_edgev(g->edges, *u); //if(e->cov < WT_MAX_EDGE_COV) e->cov ++; //if(e->cov >= 1){ e->closed = 0; //} } push_edgeoffv(offs, (edge_off_t){*u, ((int)r2->beg) - r1->end}); } push_vplist(regs, r2); } } free_vplist(regs); if(g->edges->size == 0){ free_edgeoffv(offs); return; } psort_array(offs->buffer, offs->size, edge_off_t, ncpu, num_cmpgtx(a.idx, b.idx, a.off, b.off)); lst = 0; for(idx=1;idx<=offs->size;idx++){ if(idx < offs->size && offs->buffer[idx].idx == offs->buffer[lst].idx) continue; if(1){ g->edges->buffer[offs->buffer[lst].idx].off = offs->buffer[(lst+idx)/2].off; g->edges->buffer[offs->buffer[lst].idx].cov = idx - lst; } else { g->edges->buffer[offs->buffer[lst].idx].off = estimate_edge_length(offs->buffer + lst, idx - lst, idxs); g->edges->buffer[offs->buffer[lst].idx].cov = idxs[1] - idxs[0]; } if(0){ uint64_t m; for(m=lst;mbuffer[m].off); fprintf(stdout, "\n"); for(m=lst+idxs[0];mbuffer[m].off); fprintf(stdout, "\n"); } lst = idx; } free_edgeoffv(offs); clear_edgerefv(g->erefs); push_edgerefv(g->erefs, EDGE_REF_NULL); for(idx=1;idxedges->size;idx++){ if(g->edges->buffer[idx].cov < g->min_edge_cov){ if(g->store_low_cov_edge) g->edges->buffer[idx].closed = WT_EDGE_CLOSED_LESS; else continue; } if(g->nodes->buffer[g->edges->buffer[idx].node1].closed || g->nodes->buffer[g->edges->buffer[idx].node2].closed){ g->edges->buffer[idx].closed = WT_EDGE_CLOSED_HARD; } else if(g->edges->buffer[idx].closed == WT_EDGE_CLOSED_MASK){ g->edges->buffer[idx].closed = WT_EDGE_CLOSED_LESS; //} else { //g->edges->buffer[idx].closed = WT_EDGE_CLOSED_NULL; } push_edgerefv(g->erefs, (edge_ref_t){idx, 0, 0}); push_edgerefv(g->erefs, (edge_ref_t){idx, 1, 0}); } psort_array(g->erefs->buffer + 1, g->erefs->size - 1, edge_ref_t, ncpu, num_cmpgtx( (a.flg? ((g->edges->buffer[a.idx].node2 << 1) | !g->edges->buffer[a.idx].dir2) : ((g->edges->buffer[a.idx].node1 << 1) | g->edges->buffer[a.idx].dir1)), (b.flg? ((g->edges->buffer[b.idx].node2 << 1) | !g->edges->buffer[b.idx].dir2) : ((g->edges->buffer[b.idx].node1 << 1) | g->edges->buffer[b.idx].dir1)), g->edges->buffer[a.idx].off, g->edges->buffer[b.idx].off)); f1.idx = g->nodes->size; f1.flg = 0; cnt = 0; for(lst=idx=1;idxerefs->size;idx++){ if(g->erefs->buffer[idx].flg){ f2.idx = g->edges->buffer[g->erefs->buffer[idx].idx].node2; f2.flg = !g->edges->buffer[g->erefs->buffer[idx].idx].dir2; } else { f2.idx = g->edges->buffer[g->erefs->buffer[idx].idx].node1; f2.flg = g->edges->buffer[g->erefs->buffer[idx].idx].dir1; } if(f1.idx == f2.idx && f1.flg == f2.flg) continue; if(lst < idx){ n = ref_nodev(g->nodes, f1.idx); n->edges[f1.flg].idx = lst; n->edges[f1.flg].cnt = 0; for(x=lst;x+1erefs->buffer[x].next = x + 1; if(g->edges->buffer[g->erefs->buffer[x].idx].closed == WT_EDGE_CLOSED_NULL) n->edges[f1.flg].cnt ++; } if(g->edges->buffer[g->erefs->buffer[x].idx].closed == WT_EDGE_CLOSED_NULL) n->edges[f1.flg].cnt ++; } lst = idx; f1 = f2; } if(lst < idx){ n = ref_nodev(g->nodes, f1.idx); n->edges[f1.flg].idx = lst; n->edges[f1.flg].cnt = 0; for(x=lst;x+1erefs->buffer[x].next = x + 1; if(g->edges->buffer[g->erefs->buffer[x].idx].closed == WT_EDGE_CLOSED_NULL) n->edges[f1.flg].cnt ++; } if(g->edges->buffer[g->erefs->buffer[x].idx].closed == WT_EDGE_CLOSED_NULL) n->edges[f1.flg].cnt ++; } } static inline void load_nodes_graph(Graph *g, FileReader *clp, FileReader *nds){ read_t *rd; node_t *n; reg_t *reg, *r; uint64_t nid; uint32_t i, nreg, rid; char *str, *tok; int ncol, closed, nwarn; clear_nodev(g->nodes); clear_regv(g->regs); next_ref_regv(g->regs); nwarn = 0; while((ncol = readtable_filereader(clp)) != -1){ if(clp->line->string[0] == '#') continue; if(ncol < 4) continue; if((rid = getval_cuhash(g->kbm->tag2idx, get_col_str(clp, 0))) == MAX_U4){ if(nwarn < 10){ fprintf(stderr, " -- Cannot find read \"%s\" in LINE:%llu in %s -- %s:%d --\n", get_col_str(clp, 0), clp->n_line, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); nwarn ++; } continue; } rd = ref_readv(g->reads, rid); rd->clps[0] = atoi(get_col_str(clp, 2)) / KBM_BIN_SIZE; rd->clps[1] = atoi(get_col_str(clp, 3)) / KBM_BIN_SIZE; } nwarn = 0; while((ncol = readtable_filereader(nds)) != -1){ if(nds->line->string[0] == '#') continue; if(ncol < 2) continue; nreg = atoi(get_col_str(nds, 1)); //if(nreg == 0) continue; //if(nreg < g->min_node_cov) continue; //node_id ~ N(\d+)(\*?) nid = atol(get_col_str(nds, 0) + 1); if(get_col_str(nds, 0)[get_col_len(nds, 0) - 1] == '*'){ // assert get_col_len(nds, 0) > 0 closed = 1; } else { closed = 0; } while(g->nodes->size < nid){ n = next_ref_nodev(g->nodes); ZEROS(n); n->closed = 1; } n = next_ref_nodev(g->nodes); ZEROS(n); n->closed = closed; n->regs.idx = g->regs->size; n->regs.cnt = nreg; for(i=0;iregs); reg->node = nid; reg->closed = 0; reg->read_link = 0; str = get_col_str(nds, 2 + i); if(0){ if(str[get_col_len(nds, 2 + i)-1] == '*'){ reg->closed = 1; } tok = index(str, '_'); *tok = '\0'; reg->rid = getval_cuhash(g->kbm->tag2idx, str); str = tok + 1; *tok = '_'; tok = index(str, '_'); *tok = '\0'; reg->dir = (str[0] == 'R'); str = tok + 1; *tok = '_'; tok = index(str, '_'); *tok = '\0'; reg->beg = atoi(str); str = tok + 1; reg->end = atoi(str); reg->end += reg->beg; } else { if(str[get_col_len(nds, 2 + i)-1] == '*'){ reg->closed = 1; } tok = rindex(str, '_'); *tok = '\0'; tok ++; reg->end = atoi(tok); tok = rindex(str, '_'); *tok = '\0'; tok ++; reg->beg = atoi(tok); reg->end += reg->beg; tok = rindex(str, '_'); *tok = '\0'; tok ++; reg->dir = (tok[0] == 'R'); if((reg->rid = getval_cuhash(g->kbm->tag2idx, str)) == MAX_U4){ g->regs->size --; if(nwarn < 10){ fprintf(stderr, " -- Cannot find read \"%s\" in LINE:%llu in %s -- %s:%d --\n", str, nds->n_line, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); nwarn ++; } continue; } } rd = ref_readv(g->reads, reg->rid); if(rd->regs.idx){ r = ref_regv(g->regs, rd->regs.idx); if(r->beg > reg->beg){ reg->read_link = rd->regs.idx; rd->regs.idx = g->regs->size - 1; } else { while(1){ if(r->read_link == 0) break; if(g->regs->buffer[r->read_link].beg > reg->beg) break; r = ref_regv(g->regs, r->read_link); } reg->read_link = r->read_link; r->read_link = g->regs->size - 1; } } else { rd->regs.idx = g->regs->size - 1; } rd->regs.cnt ++; } } encap_regv(g->regs, 1); g->regs->buffer[g->regs->size].node = WT_MAX_NODE; } #endif wtdbg2-2.5/wtdbg2.pl000077500000000000000000000066261353664372200143270ustar00rootroot00000000000000#!/usr/bin/env perl use strict; use warnings; use Getopt::Std; my %opts = (t=>4, m=>"2g"); getopts('t:x:o:a:g:X:M:OPp:k:', \%opts); die (qq/Usage: wtdbg2.pl [options] Options: -o STR output prefix [first input] -t INT number of threads [$opts{t}] -x STR preset: rs, ont, sq, ccs [] -g NUM estimated genome size [] -X FLOAT coverage cutoff [wtdbg2 default] -k INT k-mer length [wtdbg2 default] -p INT length of HPC k-mers [wtdbg2 default] -a STR additional wtdbg2 options [] -M STR minimap2 preset, according to -x when set [] -m NUM samtools sort block size [$opts{m}] -P skip minimap2-based polishing -O output without execution /) if (@ARGV == 0); $opts{asm} = gwhich("wtdbg2") || die; $opts{cns} = gwhich("wtpoa-cns") || die; unless (defined $opts{P}) { $opts{smt} = gwhich("samtools") || die; $opts{mm2} = gwhich("minimap2") || die; } my $prefix = defined($opts{o})? $opts{o} : $ARGV[0]; my $smt_threads = $opts{t} < 4? 4 : $opts{t}; my $asm_opt = ""; $asm_opt .= " -x $opts{x}" if defined($opts{x}); $asm_opt .= " -g $opts{g}" if defined($opts{g}) && $opts{g} =~ /^\d/; $asm_opt .= " -X $opts{X}" if defined($opts{X}); $asm_opt .= " -k $opts{k}" if defined($opts{k}) && $opts{k} =~ /^\d+$/; $asm_opt .= " -p $opts{p}" if defined($opts{p}) && $opts{p} =~ /^\d+$/; $asm_opt .= " $opts{a}" if defined($opts{a}); $asm_opt .= " -t $opts{t} -fo $prefix"; $asm_opt .= " -i $ARGV[$_]" for (0 .. @ARGV-1); my %map_opts = ( rs=>'map-pb', rsII=>'map-pb', sq=>'map-pb', sequel=>'map-pb', ont=>'map-ont', nanopore=>'map-ont', ccs=>'asm20', corrected=>'asm20' ); if (not defined $opts{M}) { if (defined $opts{x}) { $opts{M} = $map_opts{lc $opts{x}}; $opts{M} = 'map-ont' unless(defined $opts{M}); } else { $opts{M} = 'map-ont'; } } my $mm2_input = join(' ', @ARGV); my @lines = (); push(@lines, qq/$opts{asm} $asm_opt/); push(@lines, qq/$opts{cns} -t $opts{t} -i $prefix.ctg.lay.gz -fo $prefix.raw.fa/); unless (defined $opts{P}) { push(@lines, qq/$opts{mm2} -ax $opts{M} -t$opts{t} -r2k $prefix.raw.fa $mm2_input | $opts{smt} sort -m $opts{m} -\@$smt_threads -o $prefix.bam/); push(@lines, qq/$opts{smt} view -F0x900 $prefix.bam | $opts{cns} -t $opts{t} -d $prefix.raw.fa -i - -fo $prefix.cns.fa/); } if (defined $opts{O}) { print "$_\n" for (@lines); } else { for (@lines) { system($_) == 0 || die "The following command returns non-zero code:\n $_\n"; } } sub which { my $file = shift; my $path = (@_)? shift : $ENV{PATH}; return if (!defined($path)); foreach my $x (split(":", $path)) { $x =~ s/\/$//; return "$x/$file" if (-x "$x/$file") && (-f "$x/$file"); } return; } sub gwhich { my $progname = shift; my $addtional_path = shift if (@_); my $dirname = &dirname($0); my $tmp; chomp($dirname); if ($progname =~ /^\// && (-x $progname) && (-f $progname)) { return $progname; } elsif (defined($addtional_path) && ($tmp = &which($progname, $addtional_path))) { return $tmp; } elsif (defined($dirname) && (-x "$dirname/$progname") && (-f "$dirname/$progname")) { return "$dirname/$progname"; } elsif ((-x "./$progname") && (-f "./$progname")) { return "./$progname"; } elsif (($tmp = &which($progname))) { return $tmp; } else { return; } } sub dirname { my $prog = shift; return '.' unless ($prog =~ /\//); $prog =~ s/\/[^\s\/]+$//g; return $prog; } wtdbg2-2.5/wtpoa-cns.c000066400000000000000000000223551353664372200146520ustar00rootroot00000000000000/* * * Copyright (c) 2011, Jue Ruan * * * 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 3 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, see . */ #include "wtpoa.h" #ifndef VERSION #define VERSION 0.0 #endif #ifndef RELEASE #define RELEASE 19830203 #endif int usage(){ printf( "WTPOA-CNS: Consensuser for wtdbg using PO-MSA\n" "Author: Jue Ruan \n" "Version: %s (%s)\n" "Usage: wtpoa-cns [options]\n" "Options:\n" " -t Number of threads, [4]\n" " -d Reference sequences for SAM input, will invoke sorted-SAM input mode\n" " -u XORed flags to handle SAM input. [0]\n" " 0x1: Only process reference regions present in/between SAM alignments\n" " 0x2: Don't fileter secondary/supplementary SAM records with flag (0x100 | 0x800)\n" " -r Force to use reference mode\n" " -p Similar with -d, but translate SAM into wtdbg layout file\n" " -i Input file(s) *.ctg.lay from wtdbg, +, [STDIN]\n" " Or sorted SAM files when having -d/-p\n" " -o Output files, [STDOUT]\n" " -f Force overwrite\n" " -j Expected max length of node, or say the overlap length of two adjacent units in layout file, [1500] bp\n" " overlap will be default to 1500(or 150 for sam-sr) when having -d/-p, block size will be 2.5 * overlap\n" " -b Bonus for tri-bases match, [0]\n" " -M Match score, [2]\n" " -X Mismatch score, [-5]\n" " -I Insertion score, [-2]\n" " -D Deletion score, [-4]\n" " -H Homopolymer merge score used in dp-call-cns mode, [-3]\n" " -B Bandwidth in POA, [Wmin[,Wmax[,mat_rate]]], mat_rate = matched_bases/total_bases [64,1024,0.92]\n" " Program will double bandwidth from Wmin to Wmax when mat_rate is lower than setting\n" " -W Window size in the middle of the first read for fast align remaining reads, [200]\n" " If $W is negative, will disable fast align, but use the abs($W) as Band align score cutoff\n" " -w Min size of aligned size in window, [$W * 0.5]\n" " -A Abort TriPOA when any read cannot be fast aligned, then try POA\n" " -S Shuffle mode, 0: don't shuffle reads, 1: by shared kmers, 2: subsampling. [1]\n" " -R Realignment bandwidth, 0: disable, [16]\n" " -c Consensus mode: 0, run-length; 1, dp-call-cns, [0]\n" " -C Min count of bases to call a consensus base, [3]\n" " -F Min frequency of non-gap bases to call a consensus base, [0.5]\n" " -N Max number of reads in PO-MSA [20]\n" " Keep in mind that I am not going to generate high accurate consensus sequences here\n" " -x Presets, []\n" " sam-sr: polishs contigs from short reads mapping, accepts sorted SAM files\n" " shorted for '-j 50 -W 0 -R 0 -b 1 -c 1 -N 50 -rS 2'\n" " -q Quiet\n" " -v Verbose\n" " -V Print version information and then exit\n" "\n", TOSTR(VERSION), TOSTR(RELEASE)); return 1; } int main(int argc, char **argv){ POGPar par; CTGCNS *cc; ctg_cns_t *ctg; SeqBank *refs; FileReader *fr, *db; cplist *infs, *dbfs; FILE *out; char *outf; u4i i; int reglen, shuffle, winlen, winmin, fail_skip; int seqmax, wsize, print_lay, flags; int c, ncpu, overwrite, quiet; par = DEFAULT_POG_PAR; ncpu = 4; quiet = 0; shuffle = 1; seqmax = 20; winlen = 200; winmin = 0; fail_skip = 1; reglen = 0; infs = init_cplist(4); dbfs = init_cplist(4); outf = NULL; overwrite = 0; print_lay = 0; flags = 0; while((c = getopt(argc, argv, "hqvVt:d:rp:u:i:o:fj:S:B:W:w:Ab:M:X:I:D:E:H:R:c:C:F:N:x:")) != -1){ switch(c){ case 'h': return usage(); case 't': ncpu = atoi(optarg); break; case 'p': print_lay = 1; case 'd': push_cplist(dbfs, optarg); break; case 'u': flags = atoi(optarg); break; case 'r': par.refmode = 1; break; case 'i': push_cplist(infs, optarg); break; case 'o': outf = optarg; break; case 'f': overwrite = 1; break; case 'j': reglen = atoi(optarg); break; case 'S': shuffle = atoi(optarg); break; case 'B': { char *ptr; par.W = strtol(optarg, &ptr, 10); if(ptr && ptr[0] == ','){ par.Wmax = strtol(ptr + 1, &ptr, 10); if(ptr && ptr[0] == ','){ par.W_mat_rate = atof(ptr + 1); } } } break; case 'W': winlen = atoi(optarg); break; case 'w': winmin = atoi(optarg); break; case 'A': fail_skip = 0; break; case 'b': par.tribase = atoi(optarg); break; case 'M': par.M = atoi(optarg); break; case 'X': par.X = atoi(optarg); break; case 'I': par.I = atoi(optarg); break; case 'D': par.D = atoi(optarg); break; case 'E': par.E = atoi(optarg); break; case 'H': par.H = atof(optarg); break; case 'R': par.rW = atoi(optarg); break; case 'c': par.cnsmode = atoi(optarg); break; case 'C': par.msa_min_cnt = atoi(optarg); break; case 'F': par.msa_min_freq = atof(optarg); break; case 'N': seqmax = atoi(optarg); break; case 'x': if(strcasecmp(optarg, "sam-sr") == 0){ winlen = 0; reglen = 150; par.rW = 0; par.tribase = 1; par.cnsmode = 1; seqmax = 50; par.refmode = 1; shuffle = 2; } else { fprintf(stderr, "Unknown preset[%s]\n", optarg); return 1; } break; case 'q': quiet = 1; break; case 'v': cns_debug ++; break; case 'V': fprintf(stdout, "wtpoa-cns %s\n", TOSTR(VERSION)); return 0; default: return usage(); } } if(quiet){ int devnull; devnull = open("/dev/null", O_WRONLY); dup2(devnull, STDERR_FILENO); } BEG_STAT_PROC_INFO(stderr, argc, argv); //SET_PROC_LIMIT(10 * 1024 * 1024 * 1024ULL, 0); // TODO: remove it after debug if(reglen == 0){ reglen = 1500; } wsize = 2.5 * reglen; if(winlen < 0){ par.W_score = - winlen; winlen = 0; } if(winmin <= 0){ winmin = winlen * 0.5; } if(seqmax <= 0 || seqmax >= POG_RDCNT_MAX){ seqmax = POG_RDCNT_MAX; } if(ncpu <= 0 && _sig_proc_deamon) ncpu = _sig_proc_deamon->ncpu; if(ncpu <= 0){ fprintf(stderr, " -- Invalid cpu number '%d' in %s -- %s:%d --\n", ncpu, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); return 1; } if(outf && !overwrite && file_exists(outf)){ fprintf(stderr, "File exists! '%s'\n\n", outf); return usage(); } if(infs->size) fr = open_all_filereader(infs->size, infs->buffer, 1); else fr = open_filereader(NULL, 1); if(outf){ out = open_file_for_write(outf, NULL, 1); } else out = stdout; if(shuffle == 2){ srand48(13); } if(dbfs->size == 0){ WTLAYBlock *wb; wb = init_wtlayblock(fr); cc = init_ctgcns(wb, iter_wtlayblock, info_wtlayblock, ncpu, shuffle, seqmax, winlen, winmin, fail_skip, reglen, &par); cc->print_progress = 100; if(print_lay){ print_lays_ctgcns(cc, out); } else { while((ctg = iter_ctgcns(cc))){ fprintf(out, ">%s len=%d\n", ctg->tag->string, (u4i)ctg->cns->size); for(i=0;icns->size;i+=100){ if(i + 100 <= ctg->cns->size){ println_seq_basebank(ctg->cns, i, 100, out); } else { println_seq_basebank(ctg->cns, i, ctg->cns->size - i, out); } } fflush(out); if(cc->cycs->size){ // keep only one for reuse free_ctg(ctg); } else { repay_ctgcns(cc, ctg); } } } free_ctgcns(cc); free_wtlayblock(wb); } else { SAMBlock *sb; BioSequence *seq; if(2 * reglen >= wsize){ fprintf(stderr, " -- SAM Input mode: -w wsize(%d), -j reglen(%d), MUST has 2 * reglen >= wsize in %s -- %s:%d --\n", wsize, reglen, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); return 1; } refs = init_seqbank(); db = open_all_filereader(dbfs->size, dbfs->buffer, 1); seq = init_biosequence(); while(readseq_filereader(db, seq)){ push_seqbank(refs, seq->tag->string, seq->tag->size, seq->seq->string, seq->seq->size); } free_biosequence(seq); close_filereader(db); sb = init_samblock(refs, fr, wsize, reglen * 2 / 3, flags); cc = init_ctgcns(sb, iter_samblock, info_samblock, ncpu, shuffle, seqmax, winlen, winmin, fail_skip, reglen, &par); cc->print_progress = 100; if(print_lay){ print_lays_ctgcns(cc, out); } else { while((ctg = iter_ctgcns(cc))){ fprintf(out, ">%s len=%d\n", ctg->tag->string, (u4i)ctg->cns->size); for(i=0;icns->size;i+=100){ if(i + 100 <= ctg->cns->size){ println_seq_basebank(ctg->cns, i, 100, out); } else { println_seq_basebank(ctg->cns, i, ctg->cns->size - i, out); } } fflush(out); if(cc->cycs->size){ // keep only one for reuse free_ctg(ctg); } else { repay_ctgcns(cc, ctg); } } } free_ctgcns(cc); free_samblock(sb); free_seqbank(refs); } close_filereader(fr); if(outf) fclose(out); free_cplist(infs); free_cplist(dbfs); END_STAT_PROC_INFO(stderr); return 0; } wtdbg2-2.5/wtpoa.h000066400000000000000000001017021353664372200140700ustar00rootroot00000000000000/* * * Copyright (c) 2011, Jue Ruan * * * 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 3 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, see . */ #ifndef __WTDBG_POA_CNS_RJ_H #define __WTDBG_POA_CNS_RJ_H #include "tripoa.h" #include "kswx.h" #include "filereader.h" typedef struct { char *reftag; u4i reflen, refoff; u4i node1, node2; } lay_blk_t; typedef struct { u4i chridx, bidx; // block idx u4i rdidx, rdoff:31, rddir:1; char *rdtag; BaseBank *seq; u4i rbeg, rend; } lay_seq_t; static inline void _init_lay_seq_t(lay_seq_t *sq){ ZEROS(sq); sq->seq = init_basebank(); } static inline void _free_lay_seq_t(lay_seq_t *sq){ free_basebank(sq->seq); } define_recycle_list(layseqr, lay_seq_t, u4i, _init_lay_seq_t(a), _free_lay_seq_t(a)); typedef lay_seq_t* (*iter_cns_block)(void *obj); typedef void (*info_cns_block)(void *obj, lay_seq_t *sq, lay_blk_t *bk); typedef struct { u4i cidx, eidx; u4i node1, node2, soff, slen; int beg, end; } edge_cns_t; define_list(edgecnsv, edge_cns_t); typedef struct { u4i cidx; edgecnsv *rs; String *tag; BaseBank *seq, *cns; u4i cnt; } ctg_cns_t; define_list(ctgcnsv, ctg_cns_t*); static inline ctg_cns_t* init_ctg(u4i cidx){ ctg_cns_t *ctg; ctg = malloc(sizeof(ctg_cns_t)); ctg->cidx = cidx; ctg->rs = init_edgecnsv(2); ctg->tag = init_string(32); ctg->seq = init_basebank(2048); ctg->cns = init_basebank(2048); ctg->cnt = 0; return ctg; } static inline void clear_ctg(ctg_cns_t *ctg){ ctg->cidx = MAX_U4; ctg->cnt = 0; clear_edgecnsv(ctg->rs); clear_string(ctg->tag); clear_basebank(ctg->seq); clear_basebank(ctg->cns); } static inline void free_ctg(ctg_cns_t *ctg){ free_edgecnsv(ctg->rs); free_string(ctg->tag); free_basebank(ctg->seq); free_basebank(ctg->cns); free(ctg); } typedef struct { u4i cidx, eidx; int type; // 0, none; 1, edge cns; 2, edges aligning; 3, merging into cns } cns_evt_t; define_list(cnsevtv, cns_evt_t); struct CTGCNS; thread_beg_def(mcns); struct CTGCNS *cc; TriPOG *g; cns_evt_t task; edge_cns_t edges[2]; u1v *seq1, *seq2; thread_end_def(mcns); typedef struct CTGCNS { void *obj; iter_cns_block itercns; info_cns_block infocns; lay_seq_t *sq; lay_blk_t BK; u4i ncpu; ctgcnsv *ctgs, *cycs; u4i nctg; cnsevtv *evts; u8i ridx, bases; u4i chridx, bidx; int state; u4i seqmax, inpmax; int winlen, winmin, fail_skip; int M, X, I, D, E, reglen; u8i tri_rets[2]; u4i print_progress; thread_def_shared_vars(mcns); } CTGCNS; static inline int revise_joint_point(u32list *cigars, int *qe, int *te){ u4i i, op, ln, max; int qq, q, tt, t; q = t = 0; qq = tt = 0; max = 0; for(i=1;i<=cigars->size;i++){ op = cigars->buffer[cigars->size - i] & 0xF; ln = cigars->buffer[cigars->size - i] >> 4; if(op == 0){ if(ln > max){ qq = q; tt = t; max = ln; } q += ln; t += ln; } else if(op == 1){ q += ln; } else { t += ln; } } *qe -= qq; *te -= tt; return 1; } thread_beg_func(mcns); struct CTGCNS *cc; TriPOG *g; ctg_cns_t *ctg; edge_cns_t *edge; u1v *seq1, *seq2; kswx_t XX, *xs[2]; u8list *mem_cache; u32list *cigars[2]; u4i i; int qb, qe, tb, te, b, e, ol; cc = mcns->cc; g = mcns->g; seq1 = mcns->seq1; seq2 = mcns->seq2; mem_cache = init_u8list(1024); cigars[0] = init_u32list(64); cigars[1] = NULL; xs[0] = &XX; xs[1] = NULL; thread_beg_loop(mcns); if(mcns->task.type == 1){ if(g->seqs->nseq){ end_tripog(g); } } else if(mcns->task.type == 2){ qb = 0; qe = seq1->size; tb = 0; te = seq2->size; if(qe > cc->reglen) qb = qe - cc->reglen; if(te > cc->reglen) te = cc->reglen; ol = num_min(qe -qb, te - tb); kswx_overlap_align_core(xs, cigars, qe - qb, seq1->buffer + qb, te - tb, seq2->buffer + tb, 1, cc->M, cc->X, (cc->I + cc->D) / 2, (cc->I + cc->D) / 2, cc->E, mem_cache); if(XX.aln < Int(0.5 * cc->reglen) || XX.mat < Int(XX.aln * 0.9)){ // full length alignment int maxl; maxl = num_min(seq1->size, seq2->size); maxl = num_min(maxl, cc->reglen * 4); qb = 0; qe = seq1->size; tb = 0; te = seq2->size; if(qe > maxl) qb = qe - maxl; if(te > maxl) te = maxl; ol = num_min(qe -qb, te - tb); kswx_overlap_align_core(xs, cigars, qe - qb, seq1->buffer + qb, te - tb, seq2->buffer + tb, 1, cc->M, cc->X, (cc->I + cc->D) / 2, (cc->I + cc->D) / 2, cc->E, mem_cache); } XX.qb += qb; XX.qe += qb; XX.tb += tb; XX.te += tb; b = XX.qe; e = XX.te; revise_joint_point(cigars[0], &b, &e); mcns->edges[0].end = b; mcns->edges[1].beg = e; if(cns_debug){ thread_beg_syn(mcns); fprintf(stderr, "JOINT\tC%u\tE%u\tqe = %d -> %d\tte = %d -> %d\t[%5d,%5d]\t[%5d,%5d,%d,%d,%d]\n", mcns->edges[0].cidx, mcns->edges[0].eidx, XX.qe, b, XX.te, e, (int)seq1->size, (int)seq2->size, XX.aln, XX.mat, XX.mis, XX.ins, XX.del); fflush(stderr); thread_end_syn(mcns); } } else if(mcns->task.type == 3){ ctg = get_ctgcnsv(cc->ctgs, mcns->task.cidx); clear_basebank(ctg->cns); for(i=0;irs->size;i++){ edge = ref_edgecnsv(ctg->rs, i); if(edge->end > edge->beg){ fast_fwdbits2basebank(ctg->cns, ctg->seq->bits, edge->soff + edge->beg, edge->end - edge->beg); } else if(Int(ctg->cns->size) + edge->end > edge->beg){ ctg->cns->size = ctg->cns->size + edge->end - edge->beg; normalize_basebank(ctg->cns); } else { clear_basebank(ctg->cns); } } } thread_end_loop(mcns); free_u8list(mem_cache); free_u32list(cigars[0]); thread_end_func(mcns); static inline CTGCNS* init_ctgcns(void *obj, iter_cns_block itercns, info_cns_block infocns, u4i ncpu, int shuffle_rds, u4i seqmax, int winlen, int winmin, int fail_skip, int reglen, POGPar *par){ CTGCNS *cc; thread_prepare(mcns); cc = malloc(sizeof(CTGCNS)); cc->obj = obj; cc->itercns = itercns; cc->infocns = infocns; cc->sq = NULL; ZEROS(&cc->BK); cc->ncpu = ncpu; cc->ctgs = init_ctgcnsv(8); cc->cycs = init_ctgcnsv(8); cc->evts = init_cnsevtv(64); cc->nctg = 0; cc->ridx = 0; cc->bases = 0; cc->state = 1; cc->seqmax = seqmax; cc->inpmax = seqmax * 5; cc->winlen = winlen; cc->winmin = winmin; cc->fail_skip = fail_skip; cc->M = par->M; cc->X = par->X; cc->I = par->I; cc->D = par->D; cc->E = par->E; cc->reglen = reglen; thread_beg_init(mcns, ncpu); mcns->cc = cc; mcns->g = init_tripog(seqmax, shuffle_rds, winlen, winmin, fail_skip, par); ZEROS(&mcns->task); mcns->seq1 = init_u1v(1024); mcns->seq2 = init_u1v(1024); ZEROS(&(mcns->edges[0])); ZEROS(&(mcns->edges[1])); mcns->edges[0].eidx = MAX_U4; mcns->edges[1].eidx = MAX_U4; thread_end_init(mcns); cc->tri_rets[0] = 0; cc->tri_rets[1] = 0; cc->print_progress = 0; cc->chridx = MAX_U4; cc->bidx = MAX_U4; thread_export(mcns, cc); return cc; } static inline void reset_ctgcns(CTGCNS *cc, void *obj, iter_cns_block itercns, info_cns_block infocns){ ctg_cns_t *ctg; u4i i; cc->obj = obj; cc->itercns = itercns; cc->infocns = infocns; cc->sq = NULL; ZEROS(&cc->BK); cc->ridx = 0; cc->state = 1; cc->chridx = MAX_U4; cc->bidx = MAX_U4; for(i=0;ictgs->size;i++){ ctg = get_ctgcnsv(cc->ctgs, i); if(ctg == NULL) continue; free_ctg(ctg); } clear_ctgcnsv(cc->ctgs); cc->nctg = 0; clear_cnsevtv(cc->evts); cc->bases = 0; } static inline void free_ctgcns(CTGCNS *cc){ ctg_cns_t *ctg; u4i i; thread_prepare(mcns); thread_import(mcns, cc); thread_beg_close(mcns); free_tripog(mcns->g); free_u1v(mcns->seq1); free_u1v(mcns->seq2); thread_end_close(mcns); for(i=0;ictgs->size;i++){ ctg = get_ctgcnsv(cc->ctgs, i); if(ctg == NULL) continue; free_ctg(ctg); } free_ctgcnsv(cc->ctgs); for(i=0;icycs->size;i++){ ctg = get_ctgcnsv(cc->cycs, i); if(ctg == NULL) continue; free_ctg(ctg); } free_ctgcnsv(cc->cycs); free_cnsevtv(cc->evts); free(cc); } static inline void print_lays_ctgcns(CTGCNS *cc, FILE *out){ lay_blk_t *bk; bk = &cc->BK; while((cc->sq = cc->itercns(cc->obj))){ if(cc->sq->chridx != cc->chridx){ cc->chridx = cc->sq->chridx; cc->bidx = MAX_U4; cc->infocns(cc->obj, cc->sq, bk); fflush(out); fprintf(out, ">%s len=%u\n", bk->reftag, bk->reflen); } if(cc->sq->bidx != cc->bidx){ cc->bidx = cc->sq->bidx; cc->infocns(cc->obj, cc->sq, bk); fprintf(out, "E\t%u\tN%u\t+\tN%u\t+\n", bk->refoff, bk->node1, bk->node2); } { if(cc->sq->rdtag){ fprintf(out, "S\t%s\t%c\t%u\t%u\t", cc->sq->rdtag, "+-"[cc->sq->rddir], cc->sq->rdoff, (u4i)cc->sq->seq->size); } else { fprintf(out, "S\tR%llu\t%c\t%u\t%u\t", (u8i)cc->sq->rdidx, "+-"[cc->sq->rddir], cc->sq->rdoff, (u4i)cc->sq->seq->size); } print_seq_basebank(cc->sq->seq, 0, cc->sq->seq->size, out); fprintf(out, "\t%u\t%u\n", cc->sq->rbeg, cc->sq->rend); } } } static inline void repay_ctgcns(CTGCNS *cc, ctg_cns_t *ctg){ clear_ctg(ctg); push_ctgcnsv(cc->cycs, ctg); } static inline ctg_cns_t* iter_ctgcns(CTGCNS *cc){ ctg_cns_t *ctg, *ret; edge_cns_t *edge; cns_evt_t EVT; lay_blk_t *bk; u8i eidx; thread_prepare(mcns); thread_import(mcns, cc); bk = &cc->BK; ret = NULL; while(1){ cc->sq = cc->itercns(cc->obj); if(cc->sq){ if(cc->sq->chridx != cc->chridx){ if(cc->cycs->size){ pop_ctgcnsv(cc->cycs, &ctg); ctg->cidx = cc->ctgs->size; } else { ctg = init_ctg(cc->ctgs->size); } push_ctgcnsv(cc->ctgs, ctg); cc->chridx = cc->sq->chridx; cc->bidx = MAX_U4; cc->infocns(cc->obj, cc->sq, bk); if(bk->reftag){ append_string(ctg->tag, bk->reftag, strlen(bk->reftag)); } else { append_string(ctg->tag, "anonymous", 10); } } if(cc->sq->bidx != cc->bidx){ cc->ridx ++; if(!cns_debug && cc->print_progress && (cc->ridx % cc->print_progress) == 0){ fprintf(stderr, "\r%u contigs %llu edges %llu bases", (u4i)cc->ctgs->size, cc->ridx, cc->bases); fflush(stderr); } } else { if(mcns->g->seqs->nseq < cc->inpmax){ fwdbitpush_tripog(mcns->g, cc->sq->seq->bits, 0, cc->sq->seq->size, cc->sq->rbeg, cc->sq->rend); } continue; } } if(mcns->task.type != 0){ thread_wake(mcns); } while(1){ thread_wait_one(mcns); if(mcns->task.type == 2){ ctg = get_ctgcnsv(cc->ctgs, mcns->task.cidx); ctg->rs->buffer[mcns->edges[0].eidx].end = mcns->edges[0].end; ctg->rs->buffer[mcns->edges[1].eidx].beg = mcns->edges[1].beg; mcns->edges[0].eidx = MAX_U4; mcns->edges[1].eidx = MAX_U4; mcns->task.type = 0; ctg->cnt ++; if(ctg->cnt + 1 == ctg->rs->size && (ctg->cidx + 1 < cc->ctgs->size || cc->sq == NULL)){ EVT.cidx = ctg->cidx; EVT.eidx = MAX_U4; EVT.type = 3; array_heap_push(cc->evts->buffer, cc->evts->size, cc->evts->cap, cns_evt_t, EVT, num_cmpxx(b.type, a.type, a.cidx, b.cidx, a.eidx, b.eidx)); } } else if(mcns->task.type == 1){ ctg = get_ctgcnsv(cc->ctgs, mcns->task.cidx); cc->tri_rets[mcns->g->is_tripog] ++; if(cns_debug){ thread_beg_syn(mcns); fprintf(stderr, "%u_%s_N%u_N%u\t%d\t%d\t", mcns->task.eidx, ctg->tag->string, mcns->edges[0].node1, mcns->edges[0].node2, mcns->g->seqs->nseq, (u4i)mcns->g->cns->size); println_seq_basebank(mcns->g->cns, 0, mcns->g->cns->size, stderr); thread_end_syn(mcns); } mcns->edges[0].soff = ctg->seq->size; mcns->edges[0].slen = mcns->g->cns->size; mcns->edges[0].beg = 0; mcns->edges[0].end = mcns->g->cns->size; fast_fwdbits2basebank(ctg->seq, mcns->g->cns->bits, 0, mcns->g->cns->size); eidx = mcns->task.eidx; ctg->rs->buffer[eidx] = mcns->edges[0]; mcns->edges[0].eidx = MAX_U4; mcns->task.type = 0; if(eidx && ctg->rs->buffer[eidx - 1].eidx != MAX_U4){ EVT.cidx = ctg->cidx; EVT.eidx = eidx - 1; EVT.type = 2; array_heap_push(cc->evts->buffer, cc->evts->size, cc->evts->cap, cns_evt_t, EVT, num_cmpxx(b.type, a.type, a.cidx, b.cidx, a.eidx, b.eidx)); } if(eidx + 1 < ctg->rs->size && ctg->rs->buffer[eidx + 1].eidx != MAX_U4){ EVT.cidx = ctg->cidx; EVT.eidx = eidx; EVT.type = 2; array_heap_push(cc->evts->buffer, cc->evts->size, cc->evts->cap, cns_evt_t, EVT, num_cmpxx(b.type, a.type, a.cidx, b.cidx, a.eidx, b.eidx)); } if(ctg->rs->size == 1 && (ctg->cidx + 1 < cc->ctgs->size || cc->sq == NULL)){ EVT.cidx = ctg->cidx; EVT.eidx = MAX_U4; EVT.type = 3; array_heap_push(cc->evts->buffer, cc->evts->size, cc->evts->cap, cns_evt_t, EVT, num_cmpxx(b.type, a.type, a.cidx, b.cidx, a.eidx, b.eidx)); } } else if(mcns->task.type == 3){ ctg = get_ctgcnsv(cc->ctgs, mcns->task.cidx); cc->bases += ctg->cns->size; cc->nctg ++; ret = ctg; set_ctgcnsv(cc->ctgs, mcns->task.cidx, NULL); mcns->task.type = 0; break; } if(cc->evts->size){ EVT = cc->evts->buffer[0]; array_heap_remove(cc->evts->buffer, cc->evts->size, cc->evts->cap, cns_evt_t, 0, num_cmpxx(b.type, a.type, a.cidx, b.cidx, a.eidx, b.eidx)); mcns->task = EVT; if(EVT.type == 2){ ctg = get_ctgcnsv(cc->ctgs, EVT.cidx); mcns->edges[0] = ctg->rs->buffer[EVT.eidx]; mcns->edges[0].eidx = EVT.eidx; clear_and_inc_u1v(mcns->seq1, mcns->edges[0].slen); bitseq_basebank(ctg->seq, mcns->edges[0].soff, mcns->edges[0].slen, mcns->seq1->buffer); mcns->edges[1] = ctg->rs->buffer[EVT.eidx + 1]; mcns->edges[1].eidx = EVT.eidx + 1; clear_and_inc_u1v(mcns->seq2, mcns->edges[1].slen); bitseq_basebank(ctg->seq, mcns->edges[1].soff, mcns->edges[1].slen, mcns->seq2->buffer); } thread_wake(mcns); } else { break; } } if(cc->sq){ ctg = get_ctgcnsv(cc->ctgs, cc->ctgs->size - 1); cc->bidx = cc->sq->bidx; cc->infocns(cc->obj, cc->sq, bk); mcns->task.cidx = ctg->cidx; mcns->task.eidx = ctg->rs->size; mcns->task.type = 1; mcns->edges[1].eidx = MAX_U4; edge = next_ref_edgecnsv(ctg->rs); edge->cidx = ctg->cidx; edge->eidx = MAX_U4; edge->node1 = bk->node1; edge->node2 = bk->node2; edge->soff = 0; edge->slen = 0; edge->beg = 0; edge->end = 0; mcns->edges[0] = *edge; mcns->edges[0].eidx = offset_edgecnsv(ctg->rs, edge); beg_tripog(mcns->g); fwdbitpush_tripog(mcns->g, cc->sq->seq->bits, 0, cc->sq->seq->size, cc->sq->rbeg, cc->sq->rend); } if(ret){ break; } else if(cc->sq == NULL){ if(cc->nctg == cc->ctgs->size){ // all finished if(!cns_debug && cc->print_progress){ fprintf(stderr, "\r%u contigs %llu edges %llu bases\n", (u4i)cc->ctgs->size, cc->ridx, cc->bases); fflush(stderr); } break; } } } thread_export(mcns, cc); return ret; } /* static inline int iter_ctgcns2(CTGCNS *cc){ edge_cns_t *edge; lay_blk_t *bk; u8i i, eidx; int next, waitall; thread_prepare(mcns); thread_import(mcns, cc); next = 0; waitall = 0; bk = &cc->BK; while(cc->state){ if(cc->state == 1){ if(cc->sq == NULL){ cc->sq = cc->itercns(cc->obj); } if(cc->sq == NULL || cc->sq->chridx != cc->chridx){ if(cc->chridx != MAX_U4){ if(mcns->edges[0].idx != MAX_U8){ thread_wake(mcns); cc->erun ++; } cc->state = 2; next = 4; waitall = 1; } else if(cc->sq){ cc->state = 5; } else { thread_export(mcns, cc); return 0; } } else if(cc->sq->bidx != cc->bidx){ cc->ridx ++; if(mcns->edges[0].idx != MAX_U8){ thread_wake(mcns); cc->erun ++; } cc->state = 2; next = 3; waitall = 0; if(!cns_debug && cc->print_progress && (cc->ridx % cc->print_progress) == 0){ fprintf(stderr, "\r%u contigs %llu edges %llu bases", (u4i)cc->ctgs->size, cc->ridx, cc->bases); fflush(stderr); } } else { if(0){ if(cc->sq->rdtag){ fprintf(stdout, "S\t%s\t%c\t%u\t%u\t", cc->sq->rdtag, "+-"[cc->sq->rddir], cc->sq->rdoff, (u4i)cc->sq->seq->size); } else { fprintf(stdout, "S\tR%llu\t%c\t%u\t%u\t", (u8i)cc->sq->rdidx, "+-"[cc->sq->rddir], cc->sq->rdoff, (u4i)cc->sq->seq->size); } print_seq_basebank(cc->sq->seq, 0, cc->sq->seq->size, stdout); fprintf(stdout, "\t%u\t%u\n", cc->sq->rbeg, cc->sq->rend); } if(mcns->g->seqs->nseq < cc->inpmax){ fwdbitpush_tripog(mcns->g, cc->sq->seq->bits, 0, cc->sq->seq->size, cc->sq->rbeg, cc->sq->rend); } cc->sq = NULL; } } else if(cc->state == 2){ while(1){ if(waitall){ if(cc->tasks->size == 0){ thread_wait_done(mcns); } else { thread_wait_one(mcns); } } else { thread_wait_one(mcns); } if(mcns->edges[1].idx != MAX_U8){ cc->erun --; cc->rs->buffer[mcns->edges[0].idx].end = mcns->edges[0].end; cc->rs->buffer[mcns->edges[1].idx].beg = mcns->edges[1].beg; mcns->edges[0].idx = MAX_U8; mcns->edges[1].idx = MAX_U8; } else if(mcns->edges[0].idx != MAX_U8){ cc->erun --; cc->tri_rets[mcns->g->is_tripog] ++; if(cns_debug){ thread_beg_syn(mcns); fprintf(stderr, "%llu_%s_N%u_N%u\t%d\t%d\t", mcns->edges[0].idx, cc->tag->string, mcns->edges[0].node1, mcns->edges[0].node2, mcns->g->seqs->nseq, (u4i)mcns->g->cns->size); println_seq_basebank(mcns->g->cns, 0, mcns->g->cns->size, stderr); thread_end_syn(mcns); } mcns->edges[0].soff = cc->seq->size; mcns->edges[0].slen = mcns->g->cns->size; mcns->edges[0].beg = 0; mcns->edges[0].end = mcns->g->cns->size; fast_fwdbits2basebank(cc->seq, mcns->g->cns->bits, 0, mcns->g->cns->size); eidx = mcns->edges[0].idx; cc->rs->buffer[eidx] = mcns->edges[0]; mcns->edges[0].idx = MAX_U8; if(eidx && cc->rs->buffer[eidx - 1].idx != MAX_U8){ push_u8v(cc->tasks, eidx - 1); } if(eidx + 1 < cc->rs->size && cc->rs->buffer[eidx + 1].idx != MAX_U8){ push_u8v(cc->tasks, eidx); } } if(pop_u8v(cc->tasks, &eidx)){ mcns->edges[0] = cc->rs->buffer[eidx]; mcns->edges[0].idx = eidx; clear_and_inc_u1v(mcns->seq1, mcns->edges[0].slen); bitseq_basebank(cc->seq, mcns->edges[0].soff, mcns->edges[0].slen, mcns->seq1->buffer); mcns->edges[1] = cc->rs->buffer[eidx + 1]; mcns->edges[1].idx = eidx + 1; clear_and_inc_u1v(mcns->seq2, mcns->edges[1].slen); bitseq_basebank(cc->seq, mcns->edges[1].soff, mcns->edges[1].slen, mcns->seq2->buffer); thread_wake(mcns); cc->erun ++; } else { if(waitall){ if(cc->erun == 0){ break; } } else { break; } } } cc->state = next; } else if(cc->state == 3){ cc->bidx = cc->sq->bidx; cc->infocns(cc->obj, cc->sq, bk); mcns->edges[1].idx = MAX_U8; edge = next_ref_edgecnsv(cc->rs); edge->idx = MAX_U8; edge->node1 = bk->node1; edge->node2 = bk->node2; edge->soff = 0; edge->slen = 0; edge->beg = 0; edge->end = 0; mcns->edges[0] = *edge; mcns->edges[0].idx = offset_edgecnsv(cc->rs, edge); beg_tripog(mcns->g); cc->state = 1; if(0){ fprintf(stdout, "E\t%u\tN%u\t+\tN%u\t+\n", bk->refoff, bk->node1, bk->node2); } } else if(cc->state == 4){ clear_basebank(cc->cns); for(i=0;irs->size;i++){ edge = ref_edgecnsv(cc->rs, i); if(edge->end > edge->beg){ fast_fwdbits2basebank(cc->cns, cc->seq->bits, edge->soff + edge->beg, edge->end - edge->beg); } else if(Int(cc->cns->size) + edge->end > edge->beg){ cc->cns->size = cc->cns->size + edge->end - edge->beg; normalize_basebank(cc->cns); } else { clear_basebank(cc->cns); } } cc->bases += cc->cns->size; if(cc->sq == NULL){ if(!cns_debug && cc->print_progress){ fprintf(stderr, "\r%u contigs %llu edges %llu bases\n", (u4i)cc->ctgs->size, cc->ridx, cc->bases); fflush(stderr); } cc->state = 0; } else { cc->state = 5; } thread_export(mcns, cc); return 1; } else if(cc->state == 5){ cc->chridx = cc->sq->chridx; //cc->cidx ++; cc->bidx = MAX_U4; cc->infocns(cc->obj, cc->sq, bk); clear_string(cc->tag); if(bk->reftag){ append_string(cc->tag, bk->reftag, strlen(bk->reftag)); } else { append_string(cc->tag, "anonymous", 10); } clear_basebank(cc->seq); clear_u8v(cc->tasks); clear_edgecnsv(cc->rs); cc->state = 1; if(0){ fflush(stdout); fprintf(stdout, ">%s len=%u\n", bk->reftag, bk->reflen); } } } thread_export(mcns, cc); return 0; } */ typedef struct { u4i chridx; u4v *chrs; SeqBank *refs; BitVec *vsts; FileReader *fr; layseqr *seqs; u4v *heap; u8i rdidx; u4i cidx, bidx, sidx, lidx; u2i bsize, bstep; // block size, and slide steps int flags; // if flags & 0x1, only polish reference presented in SAM lines. 0x2: Don't filter secondary/supplementary alignments u4i bidx2; } SAMBlock; static inline SAMBlock* init_samblock(SeqBank *refs, FileReader *fr, u2i bsize, u2i bovlp, int flags){ SAMBlock *sb; lay_seq_t *stop; u2i bstep; bstep = bsize - bovlp; assert(bstep <= bsize && 2 * bstep >= bsize); sb = malloc(sizeof(SAMBlock)); sb->chridx = 0; sb->chrs = init_u4v(32); push_u4v(sb->chrs, MAX_U4); sb->refs = refs; sb->vsts = init_bitvec(sb->refs->nseq); sb->fr = fr; sb->seqs = init_layseqr(1024); sb->heap = init_u4v(1024); sb->rdidx = 0; sb->cidx = 1; sb->bidx = 0; sb->bidx2 = MAX_U4; sb->bsize = bsize; sb->bstep = bstep; sb->sidx = MAX_U4; // last output lay_seq sb->lidx = MAX_U4; // last input lay_seq sb->flags = flags; stop = pop_layseqr(sb->seqs); stop->chridx = refs->nseq + 1; stop->bidx = 0; return sb; } static inline void free_samblock(SAMBlock *sb){ free_u4v(sb->chrs); free_bitvec(sb->vsts); free_layseqr(sb->seqs); free_u4v(sb->heap); free(sb); } static inline lay_seq_t* _push_padding_ref_samblock(SAMBlock *sb, lay_seq_t *sq){ lay_seq_t *st; u8i off; u4i sqidx, len, i; if(sb->cidx > sb->refs->nseq) return sq; sqidx = offset_layseqr(sb->seqs, sq); if((sb->flags & 0x1) && sb->bidx2 == MAX_U4){ sb->bidx = sq->bidx; } sb->bidx2 = sb->bidx; while(sb->cidx < sq->chridx || (sb->cidx == sq->chridx && sb->bidx <= sq->bidx)){ st = pop_layseqr(sb->seqs); st->chridx = sb->cidx; st->bidx = sb->bidx; st->rdidx = 0; st->rddir = 0; st->rdoff = st->bidx * sb->bstep; st->rbeg = st->rdoff; if(sb->chrs->size <= sb->cidx){ for(i=0;irefs->nseq;i++){ if(get_bitvec(sb->vsts, i) == 0) break; } if(i == sb->refs->nseq) break; push_u4v(sb->chrs, i); one_bitvec(sb->vsts, i); } off = sb->refs->rdoffs->buffer[sb->chrs->buffer[sb->cidx]]; len = sb->refs->rdlens->buffer[sb->chrs->buffer[sb->cidx]]; st->rend = num_min(st->rbeg + sb->bsize, len); clear_basebank(st->seq); fast_fwdbits2basebank(st->seq, sb->refs->rdseqs->bits, off + st->rdoff, st->rend - st->rbeg); array_heap_push(sb->heap->buffer, sb->heap->size, sb->heap->cap, u4i, offset_layseqr(sb->seqs, st), num_cmpxx(ref_layseqr(sb->seqs, a)->chridx, ref_layseqr(sb->seqs, b)->chridx, ref_layseqr(sb->seqs, a)->bidx, ref_layseqr(sb->seqs, b)->bidx, ref_layseqr(sb->seqs, a)->rdidx, ref_layseqr(sb->seqs, b)->rdidx)); if(st->rend >= len){ sb->cidx ++; sb->bidx = 0; sb->bidx2 = sb->bidx; if(sb->cidx >= sb->refs->nseq) break; } else { sb->bidx ++; } sq = ref_layseqr(sb->seqs, sqidx); } sq = ref_layseqr(sb->seqs, sqidx); return sq; } static inline lay_seq_t* iter_samblock(void *obj){ SAMBlock *sb; lay_seq_t *sc, *sl; u4i chr, chridx, scidx, off, minlen, rddir, rdoff, nxt, val, len, op; char *ptr, *str; int c, samflag; sb = (SAMBlock*)obj; if(sb->sidx != MAX_U4){ recyc_layseqr(sb->seqs, sb->sidx); sb->sidx = MAX_U4; } do { if(sb->heap->size == 0){ sb->lidx = MAX_U4; } while(sb->lidx == MAX_U4){ c = readtable_filereader(sb->fr); if(c == -1){ if(sb->flags & 0x1){ } else { sc = ref_layseqr(sb->seqs, 0); sc = _push_padding_ref_samblock(sb, sc); } break; } if(sb->fr->line->string[0] == '@') continue; if(c < 11) continue; samflag = atoi(get_col_str(sb->fr, 1)); if(samflag & 0x004) continue; //if(get_col_str(sb->fr, 9)[0] == '*') continue; if(!(sb->flags & 0x2)){ if(samflag & (0x100 | 0x800)) continue; // filter secondary/supplementary alignments } // chr if((chr = getval_cuhash(sb->refs->rdhash, get_col_str(sb->fr, 2))) == MAX_U4){ continue; } if(chr != sb->chrs->buffer[sb->chridx]){ chridx = ++ sb->chridx; push_u4v(sb->chrs, chr); one_bitvec(sb->vsts, chr); } else { chridx = sb->chridx; } off = atol(get_col_str(sb->fr, 3)) - 1; ptr = get_col_str(sb->fr, 5); if((*ptr) == '*') continue; sb->rdidx ++; rdoff = 0; minlen = num_min(get_col_len(sb->fr, 9), sb->bsize) / 2; rddir = (atol(get_col_str(sb->fr, 1)) & 0x10) >> 4; str = get_col_str(sb->fr, 9); { encap_layseqr(sb->seqs, 2); sc = pop_layseqr(sb->seqs); sc->chridx = chridx; sc->bidx = (off / sb->bstep); sc->rdidx = sb->rdidx; sc->rddir = rddir; sc->rdoff = rdoff; sc->rbeg = off; sc->rend = 0; clear_basebank(sc->seq); } sl = NULL; // parse SAM cigar { nxt = (off / sb->bstep) * sb->bstep; if(nxt && off - nxt < UInt(sb->bsize - sb->bstep)){ if(sc->bidx){ scidx = offset_layseqr(sb->seqs, sc); sl = pop_layseqr(sb->seqs); sc = ref_layseqr(sb->seqs, scidx); sl->chridx = chridx; sl->bidx = sc->bidx - 1; sl->rdidx = sb->rdidx; sl->rddir = rddir; sl->rdoff = rdoff; sl->rbeg = off; sl->rend = 0; clear_basebank(sl->seq); } nxt += sb->bsize - sb->bstep; } else { nxt += sb->bstep; } } val = 0; while(*ptr){ op = MAX_U4; switch(*ptr){ case '0' ... '9': val = val * 10 + (*ptr) - '0'; break; case 'X': case '=': case 'M': op = 0b111; break; case 'I': op = 0b110; break; case 'D': op = 0b101; break; case 'N': op = 0b001; break; case 'S': op = 0b010; break; case 'H': case 'P': op = 0b000; break; default: fprintf(stderr, " -- %s\n", get_col_str(sb->fr, 5)); fprintf(stderr, " -- Bad cigar %d '%c' in %s -- %s:%d --\n", (int)(ptr - get_col_str(sb->fr, 5)), *ptr, __FUNCTION__, __FILE__, __LINE__); fflush(stderr); abort(); } ptr ++; if(op == MAX_U4) continue; if(val == 0) val = 1; while(val){ if(op & 0b001){ len = num_min(val, nxt - off); off += len; } else { len = val; } val -= len; if(op & 0b010){ rdoff += len; if(op & 0b100){ if(sc){ if(sc->seq->size == 0){ sc->rbeg = (op & 0b001)? off - len : off; } seq2basebank(sc->seq, str, len); sc->rend = off; } if(sl){ if(sl->seq->size == 0){ sl->rbeg = (op & 0b001)? off - len : off; } seq2basebank(sl->seq, str, len); sl->rend = off; } } str += len; } if(off == nxt){ if(sl){ if(sl->rend >= sl->rbeg + minlen){ scidx = offset_layseqr(sb->seqs, sc); sl = _push_padding_ref_samblock(sb, sl); sc = ref_layseqr(sb->seqs, scidx); if(sb->lidx == MAX_U4){ sb->lidx = offset_layseqr(sb->seqs, sl); } array_heap_push(sb->heap->buffer, sb->heap->size, sb->heap->cap, u4i, offset_layseqr(sb->seqs, sl), num_cmpxx(ref_layseqr(sb->seqs, a)->chridx, ref_layseqr(sb->seqs, b)->chridx, ref_layseqr(sb->seqs, a)->bidx, ref_layseqr(sb->seqs, b)->bidx, ref_layseqr(sb->seqs, a)->rdidx, ref_layseqr(sb->seqs, b)->rdidx)); } else { push_layseqr(sb->seqs, sl); } sl = NULL; nxt += 2 * sb->bstep - sb->bsize; } else { scidx = offset_layseqr(sb->seqs, sc); encap_layseqr(sb->seqs, 1); sl = ref_layseqr(sb->seqs, scidx); sc = pop_layseqr(sb->seqs); sc->chridx = chridx; sc->bidx = sl->bidx + 1; sc->rdidx = sb->rdidx; sc->rddir = rddir; sc->rdoff = rdoff; sc->rbeg = off; sc->rend = 0; clear_basebank(sc->seq); nxt += sb->bsize - sb->bstep; } } } } if(sl){ if(sl->rend >= sl->rbeg + minlen){ u4i scidx; scidx = sc? offset_layseqr(sb->seqs, sc) : MAX_U4; sl = _push_padding_ref_samblock(sb, sl); sc = scidx == MAX_U4? NULL : ref_layseqr(sb->seqs, scidx); if(sb->lidx == MAX_U4){ sb->lidx = offset_layseqr(sb->seqs, sl); } array_heap_push(sb->heap->buffer, sb->heap->size, sb->heap->cap, u4i, offset_layseqr(sb->seqs, sl), num_cmpxx(ref_layseqr(sb->seqs, a)->chridx, ref_layseqr(sb->seqs, b)->chridx, ref_layseqr(sb->seqs, a)->bidx, ref_layseqr(sb->seqs, b)->bidx, ref_layseqr(sb->seqs, a)->rdidx, ref_layseqr(sb->seqs, b)->rdidx)); } else { push_layseqr(sb->seqs, sl); } } if(sc){ if(sc->rend >= sc->rbeg + minlen){ scidx = sl? offset_layseqr(sb->seqs, sl) : MAX_U4; sc = _push_padding_ref_samblock(sb, sc); sl = scidx == MAX_U4? NULL : ref_layseqr(sb->seqs, scidx); if(sb->lidx == MAX_U4){ sb->lidx = offset_layseqr(sb->seqs, sc); } array_heap_push(sb->heap->buffer, sb->heap->size, sb->heap->cap, u4i, offset_layseqr(sb->seqs, sc), num_cmpxx(ref_layseqr(sb->seqs, a)->chridx, ref_layseqr(sb->seqs, b)->chridx, ref_layseqr(sb->seqs, a)->bidx, ref_layseqr(sb->seqs, b)->bidx, ref_layseqr(sb->seqs, a)->rdidx, ref_layseqr(sb->seqs, b)->rdidx)); } else { push_layseqr(sb->seqs, sc); } } } if(sb->heap->size == 0) break; if(sb->lidx != MAX_U4){ sl = ref_layseqr(sb->seqs, sb->lidx); sb->sidx = sb->heap->buffer[0]; sc = ref_layseqr(sb->seqs, sb->sidx); if(sc->chridx == sl->chridx && sc->bidx + 1 >= sl->bidx){ sb->lidx = MAX_U4; continue; } array_heap_remove(sb->heap->buffer, sb->heap->size, sb->heap->cap, u4i, 0, num_cmpxx(ref_layseqr(sb->seqs, a)->chridx, ref_layseqr(sb->seqs, b)->chridx, ref_layseqr(sb->seqs, a)->bidx, ref_layseqr(sb->seqs, b)->bidx, ref_layseqr(sb->seqs, a)->rdidx, ref_layseqr(sb->seqs, b)->rdidx)); sc->rbeg -= sc->bidx * sb->bstep; sc->rend -= sc->bidx * sb->bstep; } else { sb->sidx = sb->heap->buffer[0]; array_heap_remove(sb->heap->buffer, sb->heap->size, sb->heap->cap, u4i, 0, num_cmpxx(ref_layseqr(sb->seqs, a)->chridx, ref_layseqr(sb->seqs, b)->chridx, ref_layseqr(sb->seqs, a)->bidx, ref_layseqr(sb->seqs, b)->bidx, ref_layseqr(sb->seqs, a)->rdidx, ref_layseqr(sb->seqs, b)->rdidx)); sc = ref_layseqr(sb->seqs, sb->sidx); sc->rbeg -= sc->bidx * sb->bstep; sc->rend -= sc->bidx * sb->bstep; } return sc; } while(1); sb->sidx = MAX_U4; return NULL; } static inline void info_samblock(void *obj, lay_seq_t *sq, lay_blk_t *bk){ SAMBlock *sb; sb = (SAMBlock*)obj; if(sq == NULL) return; bk->node1 = sq->bidx; bk->node2 = sq->bidx + 1; bk->reftag = sb->refs->rdtags->buffer[sb->chrs->buffer[sq->chridx]]; bk->reflen = sb->refs->rdlens->buffer[sb->chrs->buffer[sq->chridx]]; bk->refoff = sq->bidx * sb->bstep; } typedef struct { String *tag; FileReader *fr; u4i chridx, bidx; u8i rdidx; lay_seq_t *key; lay_blk_t *blk; } WTLAYBlock; static inline WTLAYBlock* init_wtlayblock(FileReader *fr){ WTLAYBlock *wb; wb = malloc(sizeof(WTLAYBlock)); wb->tag = init_string(32); append_string(wb->tag, "annonymous", 10); wb->fr = fr; wb->chridx = 0; wb->bidx = 0; wb->rdidx = 0; wb->key = calloc(1, sizeof(lay_seq_t)); wb->key->seq = init_basebank(); wb->blk = calloc(1, sizeof(lay_blk_t)); return wb; } static inline void free_wtlayblock(WTLAYBlock *wb){ free_string(wb->tag); free_basebank(wb->key->seq); free(wb->key); free(wb->blk); free(wb); } static inline lay_seq_t* iter_wtlayblock(void *obj){ WTLAYBlock *wb; char *ss; int c, sl; wb = (WTLAYBlock*)obj; clear_basebank(wb->key->seq); while((c = readtable_filereader(wb->fr)) != -1){ switch(wb->fr->line->string[0]){ case '>': wb->chridx ++; wb->bidx = 0; clear_string(wb->tag); ss = get_col_str(wb->fr, 0) + 1; for(sl=0;ss[sl] && ss[sl] != ' ' && ss[sl] != '\t';sl++){ } append_string(wb->tag, ss, sl); wb->blk->node1 = 0; wb->blk->node2 = 0; ss = strstr(ss + sl, "len="); if(ss){ wb->blk->reflen = atol(ss); } else { wb->blk->reflen = 0; } wb->blk->reftag = wb->tag->string; break; case 'E': wb->bidx ++; wb->blk->refoff = atoll(get_col_str(wb->fr, 1)); wb->blk->node1 = atoll(get_col_str(wb->fr, 2) + 1); wb->blk->node2 = atoll(get_col_str(wb->fr, 4) + 1); wb->blk->reftag = wb->tag->string; break; case 'S': case 's': ss = get_col_str(wb->fr, 5); sl = get_col_len(wb->fr, 5); wb->key->chridx = wb->chridx; wb->key->bidx = wb->bidx; wb->key->rdidx = wb->rdidx ++; wb->key->rddir = (get_col_str(wb->fr, 2)[0] == '-'); wb->key->rdoff = atoi(get_col_str(wb->fr, 3)); if(c >= 8){ wb->key->rbeg = atoi(get_col_str(wb->fr, 6)); wb->key->rend = atoi(get_col_str(wb->fr, 7)); } else { wb->key->rbeg = 0; wb->key->rend = 0; } seq2basebank(wb->key->seq, ss, sl); return wb->key; } } return NULL; } static inline void info_wtlayblock(void *obj, lay_seq_t *sq, lay_blk_t *bk){ if(sq == NULL) return; memcpy(bk, ((WTLAYBlock*)obj)->blk, sizeof(lay_blk_t)); } #endif