diff --git a/LICENSE-THIRD-PARTY.txt b/LICENSE-THIRD-PARTY.txt new file mode 100644 index 0000000..b87fc52 --- /dev/null +++ b/LICENSE-THIRD-PARTY.txt @@ -0,0 +1,828 @@ +================================================================================================ +BRUKER SOFTWARE LICENSE AGREEMENT +(with the right to link to other software) +------------------------------------------------------------------------------------------------ +Bruker Daltonik GmbH (hereinafter referred to as "Licensor") has developed the software program +TDF Software Development Kit (hereinafter referred to as “Software”), +which consists of software libraries (hereinafter referred to as “Software Libraries”), as well as +documentation, header files and example programs. These license terms constitute an agreement (hereinafter +referred to as the "Agreement") between you and Licensor and shall be the legal basis for any noncommercial +or commercial usage of Licensor’s Software. These license terms also apply to any updates or +supplements for the Software or separable parts of the Software such as Software Libraries, unless other +terms accompany those items, in which case those terms apply. +You may only use the Software as a whole, if you have downloaded it from Licensor’s Webserver at +https://www.bruker.com/service/support-upgrades/software-downloads/mass-spectrometry.html +and accepted this Agreement as binding between Licensor and you. However, certain individual Software +Libraries might be conveyed to you by others. In both cases, you may only legally use Software or any of the +Software Libraries conveyed to you after having accepted this Agreement as binding between Licensor and +you. +1. Purpose of Software and License +The Software is provided as it is, without any warranties regarding fitness for any purpose whatsoever. It may +contain errors and defects. It is, inter alia but not limited to, not designed, manufactured or intended for any +use requiring fail-safe performance in which the failure of the Software could lead to death, personal injury or +physical and environmental damage, such as the operation of medical facilities. Nor is it, inter alia but not +limited to, designed to perform any queries or operations which might require reliable results and/or which +might be the basis for business and/or medical decisions. You agree not to use the Software in connection +with any such activities. +2. Rights Granted +2.1 You may install and use the Software on any of your computing devices. +2.2 You may commercially exploit products that require the usage of or link to the Software Libraries and +files as defined in section 4.3. Commercial exploitation includes, but is not limited to, charging a purchase +price, license fee, maintenance fee, or subscription fee. +3. Use Restrictions +3.1 You may not decompile, disassemble, reverse engineer or modify the Software. +3.2 You may not distribute the Software to others, breach of which terminates the rights granted under this +Agreement. This also applies to any integration or implementation of the Software to software developed by +you or by others on your behalf (hereinafter referred to as “Own Software”) or any distribution of which the +Software is part. However, you may distribute Own Software which requires the usage of or links to Software +Libraries if you comply with the requirements set down in Section 4 of this Agreement. +4. Requirements for Distribution of your own Software using Software Libraries +You may only distribute Software Libraries to others if all of the following conditions are met: +4.1 You distribute Software Libraries as part of Own Software which you license to third parties (hereinafter +"Your Licensees"); +4.2 Your Own Software requires all the Software Libraries distributed by you in order to function properly +when used by Your Licensees; +4.3 You may distribute only those Software Libraries and files specifically listed in the redist.txt file inside the +Software distribution archive; furthermore, there are several files that you must distribute, also listed in the +redist.txt file. +4.4 In your Own Software’s “About” box the following text is displayed: “This software uses Software +software. Copyright © 2019 by Bruker Daltonik GmbH. All rights reserved.” +5. Restrictions for Distribution of your own Products +5.1 You may not use the Licensor’s trademarks in a way that suggests your software components and/or +programs are provided by or are endorsed by the Licensor. +5.2 Your rights to the Software do not include any license, right, power or authority to subject the Software in +whole or in part to any of the terms of an Excluded License. "Excluded License" means any license that +requires as a condition of use, modification and/or distribution of software that such software or other +software combined and/or distributed with such software shall be (a) disclosed or distributed in source code +form; or (b) licensed for the purpose of making derivative works. Without limiting the foregoing obligation, +you are specifically prohibited from distributing the Software or Software Libraries with any software that is +subject to the GNU General Public License (GPL) or similar license in a manner that would create a +combined work. +6. Liability +6.1 As Licensor delivers the software for free, Licensor is not liable for any kind of damage, direct or indirect, +which may arise due to simple negligence (Section 521 German Civil Code). In the event, that there should be +– for whatever reason – a statutory liability of Licensor for simple negligence, the aforementioned exclusion +of liability applies nevertheless, but with the exception of damages to life, body or health. +6.2 You indemnify, defend and hold harmless the Licensor from any liability claims, including attorney fees, +of third parties in connection with any usage of the Software as well as the distribution of your Own Software +which requires usage of or links to Software Libraries and other circumstances for which you are responsible. +7. Additional Terms Applicable to the Software +7.1 The Software is licensed, not sold. This License only gives you some rights to use the Software and the +Software Libraries; the Licensor reserves all other rights. Unless applicable law gives you more rights despite +this limitation, you may use the Software and the Software Libraries only as expressly permitted in this +License. +7.2 Licensor has no obligation to fix, update, supplement or support the Software and/or the Software +Libraries. +7.3 Your rights under this License terminate automatically if you breach this License in any way. Termination +of this License will not affect any of your obligations or liabilities arising prior to termination. The following +sections of this License shall survive termination: 2.1, 3.1, 3.2, 5.1, 5.2, 6.1, and 6.2. +7.4 No subsidiary agreements of this Agreement have been made. Supplements and amendments to this +Agreement must be made in writing as prescribed by law in order to be valid. The requirement of written +form under this Agreement may be waived in writing only. +7.5 This Agreement is governed by German law to the exclusion of the UN Convention on Contracts for the +International Sale of Goods. If you are a consumer, this does not apply if legal provisions, in particular +consumer protection legislation, conflict with this choice. The courts of Bremen shall have exclusive +jurisdiction. If you are not a merchant, a legal entity under public law or a public-law special fund in the sense +Section 38 of the German Code of Civil Procedure (ZPO), the agreement on the place of jurisdiction is +replaced by the legal provisions. +7.6 If individual provisions of this Agreement are or become invalid or contain a gap which needs to be filled, +the validity of the remaining provisions of the Agreement will not be affected thereby. The Parties hereby +undertake to substitute the invalid or lacking provision with a valid provision which comes closest to the +documented intentions of the Parties. + + +================================================================================================ + + + +The following software might be used in this product: + +====================================== + +Intel® Math Kernel Library, http://www.intel.com/software/products/mkl + +End User License Agreement for the Intel(R) Software Development Products +(Version May 2012) + +1. LICENSE DEFINITIONS: + +A. "Materials" are defined as the software, documentation, license key +codes (if applicable) and other materials, including any updates and upgrade +thereto, that are provided to you under this Agreement. Materials also +include the Redistributables, Cluster OpenMP Library, and Sample Source +as defined below. + +B. "Redistributables" are the files listed in the following text files that +may be included in the Materials for the applicable Intel Software Development +Product: clredist.txt, credist.txt, fredist.txt, redist.txt, redist-rt.txt. + +C. "Cluster OpenMP Library", is comprised of the files listed in the +"clredist.txt" file specified above, is the Intel(R) Cluster OpenMP* Library +add-on option to the Intel(R) C++ Compiler for Linux* and +Intel(R) Fortran Compiler for Linux* products ("Intel Compiler for Linux"). +The use of the Cluster OpenMP Library is conditioned on having a valid license +from Intel for the Cluster OpenMP Library and for either Intel(R) C++ Compiler +for Linux or Intel(R) Fortran Compiler for Linux, and further is governed by the +terms and conditions of the license agreement for applicable the Intel Compiler +for Linux. + +D. "Source Code" is defined as the Materials provided in human readable +format, and includes modification that you make or are made on your behalf. + +E. "Sample Source" is the Source Code file(s) that: (i) demonstrate certain +limited functions included in the binary libraries of the Intel(R) Integrated +Performance Primitives ("Intel(R) IPPs"); (ii) are identified as Intel IPP +sample source code; (iii) are obtained separately from Intel after you register +your copy of the Intel(R) IPPs product with Intel; and (iv) are subject to all +of the terms and conditions of this Agreement. + +F. "Microsoft Platforms" means any current and future Microsoft operating +system products, Microsoft run-time technologies (such as the .NET Framework), +and Microsoft application platforms +(such as Microsoft Office or Microsoft Dynamics) that Microsoft offers. + +2. LICENSE GRANT: + +A. Subject to all of the terms and conditions of this Agreement, +Intel Corporation ("Intel") grants to you a non-exclusive, non-assignable, +copyright license to use the Materials. + +B. Subject to all of the terms and conditions of this Agreement, Intel +grants to you a non-exclusive, non-assignable copyright license to modify the +Materials, or any portions thereof, that are (i) provided in Source Code form +or, (ii) are defined as Redistributables and are provided in text form. + +C. Subject to all of the terms and conditions of this Agreement and any +specific restrictions which may appear in the Redistributables text files, Intel +grants to you a non-exclusive, non-assignable, fully-paid copyright license to +distribute (except if you received the Materials under an Evaluation License +as specified below) the Redistributables, including any modifications pursuant +to Section 2.B, or any portions thereof, as part of the product or application +you developed using the Materials. If such application is a software +development library, then attribution, as specified in the product release notes +of the corresponding Materials shall be displayed prominently in that product's +or application's associated documentation and on the product or application's +web site (if any). + +3. LICENSE RESTRICTIONS: + +A. If you receive your first copy of the Materials electronically, and a +second copy on media, then you may use the second copy only in accordance with +your applicable license stated in this Agreement, or for backup or archival +purposes. You may not provide the second copy to another user. + +B. You may NOT: (i) use, copy, distribute, or publicly display the +Materials except as provided in this Agreement; (ii) rent or lease the Materials +to any third party; (iii) assign this Agreement or transfer the Materials +without the express written consent of Intel; (iv) modify, adapt, or translate +the Materials in whole or in part except as provided in this Agreement; +(v) reverse engineer, decompile, or disassemble the Materials; (vi) attempt to +modify or tamper with the normal function of a license manager that regulates +usage of the Materials; (vii) distribute, sublicense or transfer the Source +Code form of any components of the Materials or derivatives thereof to any third +party except as provided in this Agreement; (viii) distribute Redistributables +except as part of a larger program that adds significant primary functionality +different from that of the Redistributables; (ix) distribute the +Redistributables to run on a platform other than a Microsoft Platform if per the +accompanying user documentation the Materials are meant to execute only on a +Microsoft Platform; (x) include the Redistributables in malicious, deceptive, +or unlawful programs; or (xi) modify or distribute the Source Code of any +Redistributable so that any part of it becomes subject to an Excluded License. +An "Excluded License" is one that requires, as a condition of use, modification, +or distribution, that the licensed software or other software incorporated into, +derived from or distributed with such software (a) be disclosed or distributed +in Source Code form; (b) be licensed by the user to third parties for the +purpose of making and/or distributing derivative works; +or (c) be redistributable at no charge. Open source software includes, without +limitation, software licensed or distributed under any of the +following licenses or distribution models, or licenses or distribution models +substantially similar to any of the following: (a) GNU's General Public License +(GPL) or Lesser/Library GPL (LGPL), (b) the Artistic License (e.g., PERL), +(c) the Mozilla Public License, (d) the Netscape Public License, (e) the Sun +Community Source License (SCSL), (f) the Sun Industry Source License (SISL), +and (g) the Common Public License (CPL). + +C. The scope and term of your license depends on the type of license you +are provided by Intel. The variety of license types are set forth below, which +may not be available for all "Intel(R) Software Development Products" and +therefore may not apply to the Materials. For more information on the types of +licenses, please contact Intel or your sales representative. + +i. PRE-RELEASE LICENSE: If you are using the Materials under the control +of a pre-release license, (a) the Materials are deemed to be pre-release code +(e.g., alpha or beta release, etc), which may not be fully functional and which +Intel may substantially modify in development of a commercial version, and for +which Intel makes no assurances that it will ever develop or make generally +available a commercial version, and (b) if you are an individual, you have the +right to use the Materials only for the duration of the pre-release term, which +is specified in the Materials, or until the commercial release, if any, of the +Materials, whichever is shorter. You may install copies of the Materials on an +unlimited number of computers provided that you are the only individual using +the Materials and only one copy of the Materials is in use at any one time. +A separate license is required for each additional use and/or individual user +in all other cases, including without limitation, use by persons, computer +systems, and other use methods known now and in the future. If you are an +entity, Intel grants you the right to designate one individual within your +organization to have the sole right to use the Materials in the manner +specified provided above. + +ii. EVALUATION LICENSE: If you are using the Materials under the control +of an evaluation license, you as an individual may use the Materials only for +internal evaluation purposes and only for the term of the evaluation, which +may be controlled by the license key code for the Materials. +NOTWITHSTANDING ANYTHING TO THE CONTRARY ELSEWHERE IN THIS +AGREEMENT, YOU MAY NOT DISTRIBUTE ANY PORTION OF THE MATERIALS, AND THE +APPLICATION AND/OR PRODUCT DEVELOPED BY YOU MAY ONLY BE USED FOR +EVALUATION PURPOSES AND ONLY FOR THE TERM OF THE EVALUATION. You may +install copies of the Materials on a reasonable number of computers to conduct +your evaluation provided that you are the only individual using the Materials +and only one copy of the Materials is in use at any one time. A separate +license is required for each additional use and/or individual user in all other +cases, including without limitation, use by persons, computer systems, and other +use methods known now and in the future. Intel may provide you with a license +code key that enables the Materials for an evaluation license. If you are an +entity, Intel grants you the right to designate one individual within your +organization to have the sole right to use the Materials in the manner +provided above. + +iii. NONCOMMERCIAL-USE LICENSE: If you are using the Materials under the +control of a noncommercial-use license, if you are an individual, you as an +individual may use the Materials only for non-commercial use where you receive +no fee, salary or any other form of compensation. The Materials may not be used +for any other purpose, whether "for profit" or "not for profit." Any work +performed or produced as a result of use of the Materials cannot be performed +or produced for the benefit of other parties for a fee, compensation or any +other +reimbursement or remuneration. You may install copies of the Materials on an +unlimited number of computers provided that you are the only individual using +the Materials and only one copy of the Materials is in use at any one time. +A separate license is required for each additional use and/or individual user +in all other cases, including without limitation, use by persons, computer +systems, and other methods of use known now and in the future. Intel will +provide you with a license code key that enables the Materials for a +noncommercial-use license. If you obtained a time-limited noncommercial-use +license, the duration (time period) of your license and your ability to use the +Materials is limited to the time period of the obtained license, which is +controlled by the license key code for the Materials. If you are an entity, +Intel grants you the right to designate one individual within your organization +to have the sole right to use the Materials in the manner provided above. + +iv. SINGLE-USER LICENSE: If you are using the Materials under the control +of a single-user license, you as an individual may install and use the Materials +on an unlimited number of computers provided that you are the only individual +using the Materials and only one copy of the Materials is in use at any one +time. A separate license is required for each additional use and/or individual +user in all other cases, including without limitation, use by persons, computer +systems, and other methods of use known now and in the future. Intel will +provide you with a license code key that enables the Materials for a single-user +license. If you obtained a time-limited single-user license, the term of your +license and your ability to use the Materials is limited to the specified time +period, which is controlled by the license key code for the Materials. If you +are an entity, Intel grants you the right to designate one individual within +your organization to have the sole right to use the Materials in the manner +provided above. + +v. NODE-LOCKED LICENSE: If you are using the Materials under the control of + a node-locked license, you may use the Materials only on a single designated +computer by no more than the authorized number of concurrent users. A separate +license is required for each additional concurrent user and use, and/or computer +systems in all other cases, including without limitation, use by persons, +computer systems, and other methods of use known now and in the future. Intel +will provide you with a license code key that enables the Materials for a Node- +Locked license up to the authorized number of concurrent users. If you obtained +a time-limited node-locked license, the term of your license and your ability to +use the Materials is limited to the specified time, which is controlled by the +license key code for the Materials. + +vi. FLOATING LICENSE: If you are using the Materials under the control of a +floating license, you may (a) install the Materials on an unlimited number of +computers that are connected to the designated network and (b) use the Material +by no more than the authorized number of concurrent individual users. +A separate license is required for each additional concurrent individual user +and each additional use by a computer system and/or network on which the +Materials are used. You understand that you must obtain a separate license for +every and any use of the Materials under a floating license, regardless of +whether such use is, without limitation, by persons, computer systems, and other +methods of use known now and in the future. Intel will provide you with a +license code key that enables the Materials for a floating license up to the +authorized number of concurrent users. If you obtained a time-limited Floating +license, the duration (time period) of your license and your ability to use the +Materials is limited to the time period of the obtained license, which is +controlled by the license key code for the Materials. Intel Library Floating +License: If the Materials are the Intel(R) Math Kernel Library or the Intel(R) +Integrated Performance Primitives Library or the Intel(R) Threading Building +Blocks (either "Intel Library"), then the Intel Library is provided to you as an +add-on option to either the Intel(R) C++ Compiler product or the Intel(R) +Fortran Compiler product (either, an "Intel Compiler") for which you have a +Floating license, and as such, in addition to the terms and conditions above, +the Intel Library may only be used by the authorized concurrent users (as noted +above) of that Intel Compiler Floating license. + +D. DISTRIBUTION: Distribution of the Redistributables is also subject to +the following limitations: You (i) shall be solely responsible to your +customers for any update or support obligation or other liability which may +arise from the distribution, (ii) shall not make any statement that your product +is "certified", or that its performance is guaranteed, by Intel, (iii) shall not +use Intel's name or trademarks to market your product without written +permission, (iv) shall use a license agreement that prohibits disassembly and +reverse engineering of the Redistributables, (v) shall indemnify, hold harmless, +and defend Intel and its suppliers from and against any claims or lawsuits, +including attorney's fees, that arise or result from your distribution of +any product. + +E. Intel(R) Integrated Performance Primitives (Intel IPP). The following +terms and conditions apply only to the Intel IPP. + +i. Notwithstanding anything in this Agreement to the contrary, if you +implement the Sample Sources in your application or if you use Intel IPP to +implement algorithms that are protected by others' licenses then you may need +additional licenses from various entities. Should any such additional licenses +be required, you are solely responsible for obtaining any such licenses and +agree to obtain any such licenses at your own expense. + +ii. Notwithstanding anything herein to the contrary, a valid license to +Intel IPP is a prerequisite to any license for Sample Source, and possession of +Sample Source does not grant any license to Intel IPP (or any portion thereof). +To access Sample Source, you must first register your licensed copy of the Intel +IPP with Intel. By downloading, installing or copying any Sample Source file, +you agree to be bound by terms of this Agreement. + +F. SOFTWARE TRANSFER: Except for Pre-Release Licenses or Evaluation +Licenses or Non-Commercial Licenses, as specified above, you may permanently +transfer the Materials you received pursuant to a license type listed in +Section 3(C) above, and all of your rights under this Agreement, to another +party ("Recipient") solely in conjunction with a change of ownership, merger, +acquisition, sale or transfer of all, substantially all or any part of your +business or assets or otherwise, either voluntarily, by operation of law of +otherwise subject to the following: You must notify Intel of the transfer by +sending a letter to Intel (i) identifying the legal entities of Recipient and +you, (ii) identifying the Materials (i.e., the specific Intel software products) +and the associated serial numbers to be transferred, (iii) certifying that you +retain no copies of the Materials, (iv) certifying that the Recipient has agreed +in writing to be bound by all of the terms and conditions of this Agreement, (v) +certifying that the Recipient has been notified that in order to receive support +from Intel for the Materials they must notify Intel in writing of the transfer +and provide Intel with the information specified in subsection (ii) above along +with the name and email address of the individual assigned to use the Materials, +and (vi) providing your email address so that we may confirm receipt of your +letter. Please send such letter to: + +Intel Corporation +2111 NE 25th Avenue +Hillsboro, OR 97124 +Attn: DPD Contracts Management, JF1-15 + +4. COPYRIGHT: Title to the Materials, modifications thereto provided by +Intel and all copies thereof remain with Intel or its suppliers. The Materials +are protected by intellectual property rights, including without limitation, +United States copyright laws and international treaty provisions. You will not +remove any copyright or other proprietary notice from the Materials. You agree +to prevent any unauthorized copying of the Materials. Except as expressly +provided herein, no license or right is granted to you directly or by +implication, inducement, estoppel or otherwise; specifically Intel does not +grant any express or implied right to you under Intel patents, copyrights, +trademarks, or trade secrets. + +5. NO WARRANTY, NO SUPPORT AND LIMITED REPLACEMENT: THE MATERIALS AND +INFORMATION ARE PROVIDED "AS IS" WITH NO WARRANTIES, EXPRESS OR IMPLIED. INTEL +SPECIFICALLY DISCLAIMS ANY AND ALL WARRANTIES, INCLUDING WITHOUT LIMITATION, +ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, +NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY OTHERWISE +ARISING OUT OF ANY PROPOSAL, SPECIFICATION, OR SAMPLE. If the media on which +the Materials are furnished are found to be defective in material or workmanship +under normal use for a period of ninety (90) days from the date of receipt, +Intel's entire liability and your exclusive remedy shall be the replacement of +the media. This offer is void if the media defect results from accident, abuse, +or misapplication. + +Intel may make changes to the Materials, or to items referenced therein, at any +time without notice, but is not obligated to support, update or provide training +for the Materials. Intel may in its sole discretion offer such support, update +or training services under separate terms at Intel's then-current rates. You may +request additional information on Intel's service offerings from an Intel sales +representative. + +6. LIMITATION OF LIABILITY: NEITHER INTEL NOR ITS SUPPLIERS SHALL BE +LIABLE FOR ANY DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR +LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, +OR OTHER LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE THE SOFTWARE, EVEN +IF INTEL HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. BECAUSE SOME +JURISDICTIONS PROHIBIT THE EXCLUSION OR LIMITATION OF LIABILITY FOR +CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE LIMITATION MAY NOT APPLY TO +YOU. + +7. UNAUTHORIZED USE: THE MATERIALS ARE NOT DESIGNED, INTENDED, OR +AUTHORIZED FOR USE IN ANY TYPE OF SYSTEM OR APPLICATION IN WHICH THE FAILURE OF +THE MATERIALS COULD CREATE A SITUATION WHERE PERSONAL INJURY OR DEATH MAY OCCUR +(e.g., MEDICAL SYSTEMS, LIFE SUSTAINING OR LIFE SAVING SYSTEMS). Should you +use the Materials for any such unintended or unauthorized use, you hereby +indemnify, defend, and hold Intel and its officers, subsidiaries and affiliates +harmless against all claims, costs, damages, and expenses, and reasonable +attorney fees arising out of, directly or indirectly, such use and any claim of +product liability, personal injury or death associated with such unintended or +unauthorized use, even if such claim alleges that Intel was negligent regarding +the design or manufacture of the Materials. + +8. USER SUBMISSIONS: This Agreement does not obligate you to provide Intel +with materials, information, comments, suggestions or other communication +regarding the Materials. However, you agree that any material, information, +comments, suggestions or other communication you transmit or post to an Intel +website (including but not limited to, submissions to the Intel Premier Support +and/or other customer support websites or online portals) or provide to Intel +under this Agreement related to the features, functions, performance or use +of the Materials are deemed non-confidential and non-proprietary +("Communications"). Intel will have no obligations with respect to the +Communications. You hereby grant to Intel a non-exclusive, perpetual, +irrevocable, royalty-free, copyright license to copy, modify, create derivative +works, publicly display, disclose, distribute, license and sublicense through +multiple tiers of distribution and licensees, incorporate and otherwise use the +Communications and all data, images, sounds, text, and other things embodied +therein, including derivative works thereto, for any and all commercial or +non-commercial purposes. You are prohibited from posting or transmitting to or +from an Intel website or provide to Intel any unlawful, threatening, libelous, +defamatory, obscene, pornographic, or other material that would violate any law. +If you wish to provide Intel with information that you intend to be treated as +confidential information, Intel requires that such confidential information be +provided pursuant to a non-disclosure agreement ("NDA"), so please contact your +Intel representative to ensure the proper NDA is in place. + +Nothing in this Agreement will be construed as preventing Intel from reviewing +your Communications and errors or defects in Intel products discovered while +reviewing your Communications. Furthermore, nothing in this Agreement will be +construed as preventing Intel from implementing independently-developed +enhancements to Intel's own error diagnosis methodology to detect errors or +defects in Intel products discovered while reviewing your Communications or to +implement bug fixes or enhancements in Intel products. The foregoing may include +the right to include your Communications in regression test suites. + +9. CONSENT. You agree that Intel, its subsidiaries or suppliers may +collect and use technical and related information, including but not limited to +technical information about your computer, system and application software, and +peripherals, that is gathered periodically to facilitate the provision of +software updates, product support and other services to you (if any) related to +the Materials, and to verify compliance with the terms of this Agreement. Intel +may use this information, as long as it is in a form that does not personally +identify you, to improve our products or to develop and provide services or +technologies to you. + +10. TERMINATION OF THIS LICENSE: This Agreement becomes effective on the +date you accept this Agreement and will continue until terminated as provided +for in this Agreement. If you are using the Materials under the control of a +time-limited license, for example an Evaluation License, this Agreement +terminates without notice on the last day of the time period, which is specified +in the Materials, and/or controlled by the license key code for the Materials. +Intel may terminate this license immediately if you are in breach of any of its +terms and conditions and such breach is not cured within thirty (30) days of +written notice from Intel. Upon termination, you will immediately return to +Intel or destroy the Materials and all copies thereof. In the event of +termination of this Agreement, the license grant to any Redistributables +distributed by you in accordance with the terms and conditions of this +Agreement, prior to the effective date of such termination, shall survive any +such termination of this Agreement + +11. U.S. GOVERNMENT RESTRICTED RIGHTS: The technical data and computer +software covered by this license is a "Commercial Item," as such term is defined +by the FAR 2.101 (48 C.F.R. 2.101) and is "commercial computer software" and +"commercial computer software documentation" as specified under FAR 12.212 +(48 C.F.R. 12.212) or DFARS 227.7202 (48 C.F.R. 227.7202), as applicable. This +commercial computer software and related documentation is provided to end users +for use by and on behalf of the U.S. Government, with only those rights as are +granted to all other end users pursuant to the terms and conditions herein. Use +for or on behalf of the U.S. Government is permitted only if the party acquiring +or using this software is properly authorized by an appropriate U.S. Government +official. This use by or for the U.S. Government clause is in lieu of, and +supersedes, any other FAR, DFARS, or other provision that addresses Government +rights in the computer software or documentation covered by this license. All +copyright licenses granted to the U.S. Government are coextensive with the +technical data and computer software licenses granted herein. The U.S. +Government shall only have the right to reproduce, distribute, perform, display, +and prepare derivative works as needed to implement those rights. + +12. GENERAL PROVISIONS + +A. ENTIRE AGREEMENT: This Agreement is intended to be the entire agreement +between you and Intel with respect to matters contained herein, and supersedes +all prior or contemporaneous agreements and negotiations with respect to those +matters. No waiver of any breach or default shall constitute a waiver of any +subsequent breach or default. If any provision of this Agreement is determined +by a court to be unenforceable, you and Intel will deem the provision to be +modified to the extent necessary to allow it to be enforced to the extent +permitted by law, or if it cannot be modified, the provision will be severed and +deleted from this Agreement, and the remainder of the Agreement will continue in +effect. Any change, modification or waiver to this Agreement must be in writing +and signed by an authorized representative of you and an officer (or delegate) +of Intel, and must specifically identify this Agreement by its title (e.g., +"End User License Agreement for the Intel(R) Software Development Products") and +version, i.e., May 2012). + +B. APPLICABLE LAWS: Any claim arising under or relating to this Agreement +shall be governed by the internal substantive laws of the State of Delaware, +without regard to principles of conflict of laws. You agree that the terms of +the United Nations Convention on Contracts for the Sale of Goods do not apply +to this Agreement. You agree that your distribution and export/re-export of the +Software and permitted modifications shall be in compliance with the laws, +regulations, orders or other restrictions of applicable export laws. + +13. THIRD PARTY PROGRAMS. The Materials may include third party programs +or materials that are governed by the third party's license terms, including +without limitation, open source software. The license terms associated with +such third party programs or materials govern your use of same, and Intel is +not liable for such third party programs or materials. + +* Other names and brands may be claimed as the property of others + +====================================== + +zlib, http://www.zlib.org + +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.8, April 28th, 2013 + + Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +*/ + +====================================== + +Numeric Library Bindings for Boost UBlas, http://mathema.tician.de/software/boost-numeric-bindings/ + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +====================================== + +Boost.Process, http://www.highscore.de/boost/process/ + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +====================================== + +boost, http://www.boost.org/ + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +====================================== + +UTF8-CPP, http://utfcpp.sourceforge.net/ + +// Copyright 2006 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +====================================== + +SQLite, http://www.sqlite.org/ + +All of the code and documentation in SQLite has been dedicated to the +public domain by the authors. All code authors, and representatives of +the companies they work for, have signed affidavits dedicating their +contributions to the public domain and originals of those signed +affidavits are stored in a firesafe at the main offices of +Hwaci. Anyone is free to copy, modify, publish, use, compile, sell, or +distribute the original SQLite code, either in source code form or as +a compiled binary, for any purpose, commercial or non-commercial, and +by any means. + +The previous paragraph applies to the deliverable code and +documentation in SQLite - those parts of the SQLite library that you +actually bundle and ship with a larger application. Some scripts used +as part of the build process (for example the "configure" scripts +generated by autoconf) might fall under other open-source +licenses. Nothing from these build scripts ever reaches the final +deliverable SQLite library, however, and so the licenses associated +with those scripts should not be a factor in assessing your rights to +copy and use the SQLite library. + +All of the deliverable code in SQLite has been written from +scratch. No code has been taken from other projects or from the open +internet. Every line of code can be traced back to its original +author, and all of those authors have public domain dedications on +file. So the SQLite code base is clean and is uncontaminated with +licensed code from other projects. + +====================================== + +CppSQLite V3.2, http://www.codeproject.com/Articles/6343/CppSQLite-C-Wrapper-for-SQLite + +Copyright (c) 2004..2007 Rob Groves. All Rights Reserved. rob.groves@btinternet.com + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose, without fee, and without a written +agreement, is hereby granted, provided that the above copyright notice, +this paragraph and the following two paragraphs appear in all copies, +modifications, and distributions. + +IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, +INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST +PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, +EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF +ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". THE AUTHOR HAS NO OBLIGATION +TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +====================================== + +The VIGRA Computer Vision Library, http://ukoethe.github.io/vigra/ + +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. + +====================================== + +Zstandard, http://facebook.github.io/zstd/ + +BSD License + +For Zstandard software + +Copyright (c) 2016-present, Facebook, Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name Facebook nor the names of its contributors may be used to + endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +====================================== + +timsdata is provided under the terms of 2-clause BSD licence. +If you require other licensing terms, please contact the authors. + +We would appreciate if you let us know if you use this library in +your own software, but you are under no legal obligation to do so. + + +------------------------------------------------------------------------- + + +Copyright (c) 2015-2018, Mateusz Krzysztof Lacki + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/MANIFEST.in b/MANIFEST.in index 3bf116f..00fb2d2 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,6 @@ recursive-include alpharaw * include LICENSE.txt +include LICENSE-THIRD-PARTY.txt include README.md recursive-exclude logs * diff --git a/README.md b/README.md index d54055e..6ba1518 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,9 @@ with an [Apache License](LICENSE.txt). External Python packages (available in the [requirements](requirements) folder) have their own licenses, which can be consulted on their respective websites. +Since AlphaRaw uses Bruker libraries for reading Bruker data (available in the [alpharaw/ext/bruker](alpharaw/ext/bruker) folder) additional +[third-party licenses](LICENSE-THIRD-PARTY.txt) are applicable in case you are using this functionality. + ------------------------------------------------------------------------ ## Installation @@ -196,6 +199,10 @@ notebook with the command `import alpharaw`. A brief [Jupyter notebook tutorial](nbs/tutorial.ipynb) on how to use the API is also present in the [nbs folder](nbs). +### Bruker data + +The [AlphaTims](https://github.com/mannlabs/alphatims) package provides additional functionality, tutorials and visualizations when it comes to reading Bruker data. + ------------------------------------------------------------------------ ## Troubleshooting @@ -214,6 +221,11 @@ In case of issues, check out the following: There are currently no plans to draft a manuscript. +If you are using AlphaRaw to access Bruker data, please cite the original source of the corresponding code: +> **AlphaTims: Indexing Trapped Ion Mobility Spectrometry–TOF Data for Fast and Easy Accession and Visualization** +> Sander Willems, Eugenia Voytik, Patricia Skowronek, Maximilian T. Strauss, Matthias Mann, +> Molecular & Cellular Proteomics, Volume 20, 2021, 100149, https://doi.org/10.1016/j.mcpro.2021.100149. + ------------------------------------------------------------------------ ## How to contribute diff --git a/alpharaw/bruker/__init__.py b/alpharaw/bruker/__init__.py new file mode 100644 index 0000000..aeb08ff --- /dev/null +++ b/alpharaw/bruker/__init__.py @@ -0,0 +1,5 @@ +"""Bruker TimsTOF data reading. + +This package provides the TimsTOF class for reading +Bruker TimsTOF LC-IMS-MS/MS data from .d folders or HDF5 files. +""" diff --git a/alpharaw/bruker/dll.py b/alpharaw/bruker/dll.py new file mode 100644 index 0000000..bb2081b --- /dev/null +++ b/alpharaw/bruker/dll.py @@ -0,0 +1,115 @@ +"""Bruker timsdata DLL/SO interface for native library access.""" + +import contextlib +import logging +import os +import sys + +from alpharaw.utils.pjit import MAX_THREADS + +BASE_PATH = os.path.dirname(__file__) +EXT_PATH = os.path.abspath(os.path.join(BASE_PATH, "..", "ext", "bruker")) + +if sys.platform[:5] == "win32": + BRUKER_DLL_FILE_NAME = os.path.join(EXT_PATH, "timsdata.dll") +elif sys.platform[:5] == "linux": + BRUKER_DLL_FILE_NAME = os.path.join(EXT_PATH, "timsdata.so") +else: + BRUKER_DLL_FILE_NAME = "" + + +def init_bruker_dll(bruker_dll_file_name: str = BRUKER_DLL_FILE_NAME): + """Open a bruker.dll in Python. + + Five functions are defined for this dll: + + - tims_open: [c_char_p, c_uint32] -> c_uint64 + - tims_close: [c_char_p, c_uint32] -> c_uint64 + - tims_read_scans_v2: [c_uint64, c_int64, c_uint32, c_uint32, c_void_p, c_uint32] -> c_uint32 + - tims_index_to_mz: [c_uint64, c_int64, POINTER(c_double), POINTER(c_double), c_uint32] -> None + - tims_scannum_to_oneoverk0: Same as "tims_index_to_mz" + + Parameters + ---------- + bruker_dll_file_name : str + The absolute path to the timsdata.dll. + Default is BRUKER_DLL_FILE_NAME. + + Returns + ------- + : ctypes.cdll + The Bruker dll library. + """ + import ctypes + + bruker_dll = ctypes.cdll.LoadLibrary(os.path.realpath(bruker_dll_file_name)) + bruker_dll.tims_open.argtypes = [ctypes.c_char_p, ctypes.c_uint32] + bruker_dll.tims_open.restype = ctypes.c_uint64 + bruker_dll.tims_close.argtypes = [ctypes.c_uint64] + bruker_dll.tims_close.restype = None + bruker_dll.tims_read_scans_v2.argtypes = [ + ctypes.c_uint64, + ctypes.c_int64, + ctypes.c_uint32, + ctypes.c_uint32, + ctypes.c_void_p, + ctypes.c_uint32, + ] + bruker_dll.tims_read_scans_v2.restype = ctypes.c_uint32 + bruker_dll.tims_index_to_mz.argtypes = [ + ctypes.c_uint64, + ctypes.c_int64, + ctypes.POINTER(ctypes.c_double), + ctypes.POINTER(ctypes.c_double), + ctypes.c_uint32, + ] + bruker_dll.tims_index_to_mz.restype = ctypes.c_uint32 + bruker_dll.tims_scannum_to_oneoverk0.argtypes = [ + ctypes.c_uint64, + ctypes.c_int64, + ctypes.POINTER(ctypes.c_double), + ctypes.POINTER(ctypes.c_double), + ctypes.c_uint32, + ] + bruker_dll.tims_scannum_to_oneoverk0.restype = ctypes.c_uint32 + bruker_dll.tims_set_num_threads.argtypes = [ctypes.c_uint64] + bruker_dll.tims_set_num_threads.restype = None + bruker_dll.tims_set_num_threads(MAX_THREADS) + # multiple threads is equally fast as just 1 for io? + # bruker_dll.tims_set_num_threads(1) + return bruker_dll + + +@contextlib.contextmanager +def open_bruker_d_folder( + bruker_d_folder_name: str, + bruker_dll_file_name=BRUKER_DLL_FILE_NAME, +) -> tuple: + """A context manager for a bruker dll connection to a .d folder. + + Parameters + ---------- + bruker_d_folder_name : str + The name of a Bruker .d folder. + bruker_dll_file_name : str, ctypes.cdll + The path to Bruker' timsdata.dll library. + Alternatively, the library itself can be passed as argument. + Default is BRUKER_DLL_FILE_NAME, + which in itself is dependent on the OS. + + Returns + ------- + : tuple (ctypes.cdll, int). + The opened bruker dll and identifier of the .d folder. + """ + try: + if isinstance(bruker_dll_file_name, str): + bruker_dll = init_bruker_dll(bruker_dll_file_name) + logging.info(f"Opening handle for {bruker_d_folder_name}") + bruker_d_folder_handle = bruker_dll.tims_open( + bruker_d_folder_name.encode("utf-8"), 0 + ) + yield bruker_dll, bruker_d_folder_handle + finally: + logging.info(f"Closing handle for {bruker_d_folder_name}") + bruker_dll.tims_close(bruker_d_folder_handle) diff --git a/alpharaw/bruker/read.py b/alpharaw/bruker/read.py new file mode 100644 index 0000000..4db0e2a --- /dev/null +++ b/alpharaw/bruker/read.py @@ -0,0 +1,417 @@ +"""Reading Bruker .d folders: SQL metadata and binary scan data.""" + +import logging +import os +from typing import Callable + +import numpy as np +import pandas as pd + +from alpharaw.bruker.dll import BRUKER_DLL_FILE_NAME +from alpharaw.utils.pjit import njit, threadpool + + +def read_bruker_sql( + bruker_d_folder_name: str, + add_zeroth_frame: bool = True, + drop_polarity: bool = True, + convert_polarity_to_int: bool = True, +) -> tuple: + """Read metadata, (fragment) frames and precursors from a Bruker .d folder. + + Parameters + ---------- + bruker_d_folder_name : str + The name of a Bruker .d folder. + add_zeroth_frame : bool + Bruker uses 1-indexing for frames. + If True, a zeroth frame is added without any TOF detections to + make Python simulate this 1-indexing. + If False, frames are 0-indexed. + Default is True. + drop_polarity : bool + The polarity column of the frames table contains "+" or "-" and + is not numerical. + If True, the polarity column is dropped from the frames table. + this ensures a fully numerical pd.DataFrame. + If False, this column is kept, resulting in a pd.DataFrame with + dtype=object. + Default is True. + convert_polarity_to_int : bool + Convert the polarity to int (-1 or +1). + This allows to keep it in numerical form. + This is ignored if the polarity is dropped. + Default is True. + + Returns + ------- + : tuple + (str, dict, pd.DataFrame, pd.DataFrame, pd.DataFrame, bool). + The acquisition_mode, global_meta_data, frames, fragment_frames, + precursors and calibration availability. + For diaPASEF, precursors is None. + """ + import sqlite3 + + logging.info(f"Reading frame metadata for {bruker_d_folder_name}") + with sqlite3.connect( + os.path.join(bruker_d_folder_name, "analysis.tdf") + ) as sql_database_connection: + global_meta_data = pd.read_sql_query( + "SELECT * from GlobalMetaData", sql_database_connection + ) + frames = pd.read_sql_query("SELECT * FROM Frames", sql_database_connection) + if 9 in frames.MsMsType.values: + acquisition_mode = "diaPASEF" + fragment_frames = pd.read_sql_query( + "SELECT * FROM DiaFrameMsMsInfo", sql_database_connection + ) + fragment_frame_groups = pd.read_sql_query( + "SELECT * from DiaFrameMsMsWindows", sql_database_connection + ) + fragment_frames = fragment_frames.merge(fragment_frame_groups, how="left") + fragment_frames.rename(columns={"WindowGroup": "Precursor"}, inplace=True) + precursors = None + elif 8 in frames.MsMsType.values: + acquisition_mode = "ddaPASEF" + fragment_frames = pd.read_sql_query( + "SELECT * from PasefFrameMsMsInfo", sql_database_connection + ) + precursors = pd.read_sql_query( + "SELECT * from Precursors", sql_database_connection + ) + else: + acquisition_mode = "noPASEF" + fragment_frames = pd.DataFrame( + { + "Frame": np.array([0]), + "ScanNumBegin": np.array([0]), + "ScanNumEnd": np.array([0]), + "IsolationWidth": np.array([0]), + "IsolationMz": np.array([0]), + "Precursor": np.array([0]), + } + ) + precursors = None + # raise ValueError("Scan mode is not ddaPASEF or diaPASEF") + calibration_available = BRUKER_DLL_FILE_NAME != "" + try: + pd.read_sql_query("SELECT * from CalibrationInfo", sql_database_connection) + except pd.io.sql.DatabaseError: + calibration_available = False + if add_zeroth_frame: + frames = pd.concat( + [ + pd.DataFrame(frames.iloc[0]).T, + frames, + ], + ignore_index=True, + ) + frames.Id[0] = 0 + frames.Time[0] = 0 + frames.MaxIntensity[0] = 0 + frames.SummedIntensities[0] = 0 + frames.NumPeaks[0] = 0 + frames.MsMsType[0] = 0 + polarity_col = frames["Polarity"].copy() + frames = pd.DataFrame( + {col: pd.to_numeric(frames[col]) for col in frames if col != "Polarity"} + ) + if not drop_polarity: + if convert_polarity_to_int: + frames["Polarity"] = polarity_col.apply( + lambda x: 1 if x == "+" else -1 + ).astype(np.int8) + else: + frames["Polarity"] = polarity_col + return ( + acquisition_mode, + global_meta_data, + frames, + fragment_frames, + precursors, + calibration_available, + ) + + +def read_bruker_binary( + frames: np.ndarray, + bruker_d_folder_name: str, + compression_type: int, + max_peaks_per_scan: int, + mmap_detector_events: bool = None, + empty_array_constructor_function: Callable = np.empty, +) -> tuple: + """Read all data from an "analysis.tdf_bin" of a Bruker .d folder. + + Parameters + ---------- + frames : pd.DataFrame + The frames from the "analysis.tdf" SQL database of a Bruker .d folder. + These can be acquired with e.g. read_bruker_sql(). + bruker_d_folder_name : str + The full path to a Bruker .d folder. + compression_type : int + The compression type. This must be either 1 or 2. + max_peaks_per_scan : int + The maximum number of peaks per scan. + Should be treieved from the global metadata. + mmap_detector_events : bool + Do not save the intensity_values and tof_indices in memory, + but use an mmap instead. Set empty_array_constructor_function accordingly. + Default is True + empty_array_constructor_function : Callable + The function to use to construct empty arrays for intensities and tof_indices. + Used only if mmap_detector_events is True. + Default is np.empty, but can be set to a function that creates memory-mapped arrays. + + Returns + ------- + : tuple (np.int64[:], np.uint32[:], np.uint16[:]). + The scan_indptr, tof_indices and intensities. + """ + frame_indptr = np.empty(frames.shape[0] + 1, dtype=np.int64) + frame_indptr[0] = 0 + frame_indptr[1:] = np.cumsum(frames.NumPeaks.values) + max_scan_count = frames.NumScans.max() + 1 + scan_count = max_scan_count * frames.shape[0] + scan_indptr = np.zeros(scan_count + 1, dtype=np.int64) + if mmap_detector_events: + intensities = empty_array_constructor_function( + int(frame_indptr[-1]), dtype=np.uint16 + ) + tof_indices = empty_array_constructor_function( + int(frame_indptr[-1]), dtype=np.uint32 + ) + else: + intensities = np.empty(int(frame_indptr[-1]), dtype=np.uint16) + tof_indices = np.empty(int(frame_indptr[-1]), dtype=np.uint32) + tdf_bin_file_name = os.path.join(bruker_d_folder_name, "analysis.tdf_bin") + tims_offset_values = frames.TimsId.values + logging.info( + f"Reading {frame_indptr.size - 2:,} frames with " + f"{frame_indptr[-1]:,} detector events for {bruker_d_folder_name}" + ) + if compression_type == 1: + process_frame_func = threadpool(process_frame, thread_count=1) + else: + process_frame_func = threadpool(process_frame) + process_frame_func( + range(1, len(frames)), + tdf_bin_file_name, + tims_offset_values, + scan_indptr, + intensities, + tof_indices, + frame_indptr, + max_scan_count, + compression_type, + max_peaks_per_scan, + ) + scan_indptr[1:] = np.cumsum(scan_indptr[:-1]) + scan_indptr[0] = 0 + return scan_indptr, tof_indices, intensities + + +def process_frame( + frame_id: int, + tdf_bin_file_name: str, + tims_offset_values: np.ndarray, + scan_indptr: np.ndarray, + intensities: np.ndarray, + tof_indices: np.ndarray, + frame_indptr: np.ndarray, + max_scan_count: int, + compression_type: int, + max_peaks_per_scan: int, +) -> None: + """Read and parse a frame directly from a Bruker .d.analysis.tdf_bin. + + Parameters + ---------- + frame_id : int + The frame number that should be processed. + Note that this is interpreted as 1-indixed instead of 0-indexed, + so that it is compatible with Bruker. + tdf_bin_file_name : str + The full file name of the SQL database "analysis.tdf_bin" in a Bruker + .d folder. + tims_offset_values : np.int64[:] + The offsets that indicate the starting indices of each frame in the + binary. + These are contained in the "TimsId" column of the frames table in + "analysis.tdf_bin". + scan_indptr : np.int64[:] + A buffer containing zeros that can store the cumulative number of + detections per scan. + The size should be equal to max_scan_count * len(frames) + 1. + A dummy 0-indexed frame is required to be present for len(frames). + The last + 1 allows to explicitly interpret the end of a scan as + the start of a subsequent scan. + intensities : np.uint16[:] + A buffer that can store the intensities of all detections. + It's size can be determined by summing the "NumPeaks" column from + the frames table in "analysis.tdf_bin". + tof_indices : np.uint32[:] + A buffer that can store the tof indices of all detections. + It's size can be determined by summing the "NumPeaks" column from + the frames table in "analysis.tdf_bin". + frame_indptr : np.int64[:] + The cumulative sum of the number of detections per frame. + The size should be equal to len(frames) + 1. + A dummy 0-indexed frame is required to be present for len(frames). + The last + 1 allows to explicitly interpret the end of a frame as + the start of a subsequent frame. + max_scan_count : int + The maximum number of scans a single frame can have. + compression_type : int + The compression type. This must be either 1 or 2. + Should be treieved from the global metadata. + max_peaks_per_scan : int + The maximum number of peaks per scan. + Should be retrieved from the global metadata. + """ + with open(tdf_bin_file_name, "rb") as infile: + frame_start = frame_indptr[frame_id] + frame_end = frame_indptr[frame_id + 1] + if frame_start != frame_end: + offset = tims_offset_values[frame_id] + infile.seek(offset) + bin_size = int.from_bytes(infile.read(4), "little") + scan_count = int.from_bytes(infile.read(4), "little") + max_peak_count = min(max_peaks_per_scan, frame_end - frame_start) + if compression_type == 1: + try: + import lzf + except (ImportError, ModuleNotFoundError) as e: + raise ImportError( + "The lzf package is required to read Bruker binary files with compression type 1. " + "Please install it with `pip install python-lzf`." + ) from e + + compression_offset = 8 + (scan_count + 1) * 4 + scan_offsets = ( + np.frombuffer(infile.read((scan_count + 1) * 4), dtype=np.int32) + - compression_offset + ) + compressed_data = infile.read(bin_size - compression_offset) + scan_indices_ = np.zeros(scan_count, dtype=np.int64) + tof_indices_ = np.empty(frame_end - frame_start, dtype=np.uint32) + intensities_ = np.empty(frame_end - frame_start, dtype=np.uint16) + scan_start = 0 + for scan_index in range(scan_count): + start = scan_offsets[scan_index] + end = scan_offsets[scan_index + 1] + if start == end: + continue + decompressed_bytes = lzf.decompress( + compressed_data[start:end], max_peak_count * 4 * 2 + ) + scan_start += parse_decompressed_bruker_binary_type1( + decompressed_bytes, + scan_indices_, + tof_indices_, + intensities_, + scan_start, + scan_index, + ) + elif compression_type == 2: + import pyzstd + + compressed_data = infile.read(bin_size - 8) + decompressed_bytes = pyzstd.decompress(compressed_data) + (scan_indices_, tof_indices_, intensities_) = ( + parse_decompressed_bruker_binary_type2(decompressed_bytes) + ) + else: + raise ValueError("TimsCompressionType is not 1 or 2.") + scan_start = frame_id * max_scan_count + scan_end = scan_start + scan_count + scan_indptr[scan_start:scan_end] = scan_indices_ + tof_indices[frame_start:frame_end] = tof_indices_ + intensities[frame_start:frame_end] = intensities_ + + +@njit(nogil=True) +def parse_decompressed_bruker_binary_type1( + decompressed_bytes: bytes, + scan_indices_: np.ndarray, + tof_indices_: np.ndarray, + intensities_: np.ndarray, + scan_start: int, + scan_index: int, +) -> int: + """Parse a Bruker binary scan buffer into tofs and intensities. + + Parameters + ---------- + decompressed_bytes : bytes + A Bruker scan binary buffer that is already decompressed with lzf. + scan_indices_ : np.ndarray + The scan_indices_ buffer array. + tof_indices_ : np.ndarray + The tof_indices_ buffer array. + intensities_ : np.ndarray + The intensities_ buffer array. + scan_start : int + The offset where to start new tof_indices and intensity_values. + scan_index : int + The scan index. + + Returns + ------- + : int + The number of peaks in this scan. + """ + buffer = np.frombuffer(decompressed_bytes, dtype=np.int32) + tof_index = 0 + previous_was_intensity = True + current_index = scan_start + for value in buffer: + if value >= 0: + if previous_was_intensity: + tof_index += 1 + tof_indices_[current_index] = tof_index + intensities_[current_index] = value + previous_was_intensity = True + current_index += 1 + else: + tof_index -= value + previous_was_intensity = False + scan_size = current_index - scan_start + scan_indices_[scan_index] = scan_size + return scan_size + + +@njit(nogil=True) +def parse_decompressed_bruker_binary_type2(decompressed_bytes: bytes) -> tuple: + """Parse a Bruker binary frame buffer into scans, tofs and intensities. + + Parameters + ---------- + decompressed_bytes : bytes + A Bruker frame binary buffer that is already decompressed with pyzstd. + + Returns + ------- + : tuple (np.uint32[:], np.uint32[:], np.uint32[:]). + The scan_indices, tof_indices and intensities present in this binary + array + """ + temp = np.frombuffer(decompressed_bytes, dtype=np.uint8) + buffer = np.frombuffer(temp.reshape(4, -1).T.flatten(), dtype=np.uint32) + scan_count = buffer[0] + scan_indices = buffer[:scan_count].copy() // 2 + intensities = buffer[scan_count + 1 :: 2] + last_scan = len(intensities) - np.sum(scan_indices[1:]) + scan_indices[:-1] = scan_indices[1:] + scan_indices[-1] = last_scan + tof_indices = buffer[scan_count::2].copy() + index = 0 + for size in scan_indices: + current_sum = 0 + for _ in range(size): + current_sum += tof_indices[index] + tof_indices[index] = current_sum + index += 1 + return scan_indices, tof_indices - 1, intensities diff --git a/alpharaw/bruker/timstof.py b/alpharaw/bruker/timstof.py new file mode 100644 index 0000000..9c1e2d4 --- /dev/null +++ b/alpharaw/bruker/timstof.py @@ -0,0 +1,615 @@ +"""This module provides functions to handle Bruker data. +It primarily implements the TimsTOF class, that acts as an in-memory container +for Bruker data storage. + +Note: this code has been moved from the AlphaTims package and does not comply to the MSData_Base contract. +For the full functionality in terms of fast data access, please use the TimsTOF class from the AlphaTims package, which inherits from this TimsTOFBase class. +""" + +import logging +import os +from typing import Callable + +import numpy as np + +from alpharaw.bruker.dll import BRUKER_DLL_FILE_NAME, open_bruker_d_folder +from alpharaw.bruker.read import read_bruker_binary, read_bruker_sql + + +class TimsTOFBase: + """A class that reads Bruker TimsTOF data. + + Data can be read directly from a Bruker .d folder. + All OS's are supported, + but reading mz_values and mobility_values from a .d folder + requires Windows or Linux due to availability of Bruker libraries. + On MacOS, they are estimated based on metadata, + but these values are not guaranteed to be correct. + Often they fall within 0.02 Th, but errors up to 6 Th have already + been observed! + """ + + @property + def sample_name(self): + """: str : The sample name of this TimsTOF object.""" + file_name = os.path.basename(self.bruker_d_folder_name) + return ".".join(file_name.split(".")[:-1]) + + @property + def directory(self): + """: str : The directory of this TimsTOF object.""" + return os.path.dirname(self.bruker_d_folder_name) + + @property + def version(self): + """: str : AlphaTims version used to create this TimsTOF object.""" + return self._version + + @property + def acquisition_mode(self): + """: str : The acquisition mode.""" + return self._acquisition_mode + + @property + def meta_data(self): + """: dict : The metadata for the acquisition.""" + return self._meta_data + + @property + def rt_values(self): + """: np.ndarray : np.float64[:] : The rt values.""" + return self._rt_values + + @property + def mobility_values(self): + """: np.ndarray : np.float64[:] : The mobility values.""" + return self._mobility_values + + @property + def cycle(self): + """: np.ndarray : np.float64[:,:,:,:] : The quad values.""" + return self._cycle + + @property + def mz_values(self): + """: np.ndarray : np.float64[:] : The mz values.""" + return self._mz_values + + @property + def quad_mz_values(self): + """: np.ndarray : np.float64[:, 2] : The (low, high) quad mz values.""" + return self._quad_mz_values + + @property + def intensity_values(self): + """: np.ndarray : np.uint16[:] : The intensity values.""" + return self._intensity_values + + @property + def frame_max_index(self): + """: int : The maximum frame index.""" + return self._frame_max_index + + @property + def scan_max_index(self): + """: int : The maximum scan index.""" + return self._scan_max_index + + @property + def tof_max_index(self): + """: int : The maximum tof index.""" + return self._tof_max_index + + @property + def precursor_max_index(self): + """: int : The maximum precursor index.""" + return self._precursor_max_index + + @property + def mz_min_value(self): + """: float : The minimum mz value.""" + return self.mz_values[0] + + @property + def mz_max_value(self): + """: float : The maximum mz value.""" + return self.mz_values[-1] + + @property + def rt_max_value(self): + """: float : The maximum rt value.""" + return self.rt_values[-1] + + @property + def quad_mz_min_value(self): + """: float : The minimum quad mz value.""" + return self._quad_min_mz_value + + @property + def quad_mz_max_value(self): + """: float : The maximum quad mz value.""" + return self._quad_max_mz_value + + @property + def mobility_min_value(self): + """: float : The minimum mobility value.""" + return self._mobility_min_value + + @property + def mobility_max_value(self): + """: float : The maximum mobility value.""" + return self._mobility_max_value + + @property + def intensity_min_value(self): + """: float : The minimum intensity value.""" + return self._intensity_min_value + + @property + def intensity_max_value(self): + """: float : The maximum intensity value.""" + return self._intensity_max_value + + @property + def frames(self): + """: pd.DataFrame : The frames table of the analysis.tdf SQL.""" + return self._frames + + @property + def fragment_frames(self): + """: pd.DataFrame : The fragment frames table.""" + return self._fragment_frames + + @property + def precursors(self): + """: pd.DataFrame : The precursor table.""" + return self._precursors + + @property + def tof_indices(self): + """: np.ndarray : np.uint32[:] : The tof indices.""" + return self._tof_indices + + @property + def push_indptr(self): + """: np.ndarray : np.int64[:] : The tof indptr.""" + return self._push_indptr + + @property + def quad_indptr(self): + """: np.ndarray : np.int64[:] : The quad indptr (tof_indices).""" + return self._quad_indptr + + @property + def raw_quad_indptr(self): + """: np.ndarray : np.int64[:] : The raw quad indptr (push indices).""" + return self._raw_quad_indptr + + @property + def precursor_indices(self): + """: np.ndarray : np.int64[:] : The precursor indices.""" + return self._precursor_indices + + @property + def dia_precursor_cycle(self): + """: np.ndarray : np.int64[:] : The precursor indices of a DIA cycle.""" + return self._dia_precursor_cycle + + @property + def dia_mz_cycle(self): + """: np.ndarray : np.float64[:, 2] : The mz_values of a DIA cycle.""" + return self._dia_mz_cycle + + @property + def zeroth_frame(self): + """: bool : A blank zeroth frame is present so frames are 1-indexed.""" + return self._zeroth_frame + + @property + def max_accumulation_time(self): + """: float : The maximum accumulation time of all frames.""" + return self._max_accumulation_time + + @property + def accumulation_times(self): + """: np.ndarray : The accumulation times of all frames.""" + return self._accumulation_times + + @property + def intensity_corrections(self): + """: np.ndarray : The intensity_correction per frame.""" + return self._intensity_corrections + + def __init__( + self, + bruker_d_folder_name: str, + *, + mz_estimation_from_frame: int = 1, + mobility_estimation_from_frame: int = 1, + drop_polarity: bool = True, + convert_polarity_to_int: bool = True, + ): + """Create a Bruker TimsTOF object that contains all data in-memory. + + Parameters + ---------- + bruker_d_folder_name : str + The full file name to a Bruker .d folder. + Alternatively, the full file name of an already exported .hdf + can be provided as well. + mz_estimation_from_frame : int + If larger than 0, mz_values from this frame are read as + default mz_values with the Bruker library. + If 0, mz_values are being estimated with the metadata + based on "MzAcqRangeLower" and "MzAcqRangeUpper". + IMPORTANT NOTE: MacOS defaults to 0, as no Bruker library + is available. + Default is 1. + mobility_estimation_from_frame : int + If larger than 0, mobility_values from this frame are read as + default mobility_values with the Bruker library. + If 0, mobility_values are being estimated with the metadata + based on "OneOverK0AcqRangeLower" and "OneOverK0AcqRangeUpper". + IMPORTANT NOTE: MacOS defaults to 0, as no Bruker library + is available. + Default is 1. + drop_polarity : bool + The polarity column of the frames table contains "+" or "-" and + is not numerical. + If True, the polarity column is dropped from the frames table. + this ensures a fully numerical pd.DataFrame. + If False, this column is kept, resulting in a pd.DataFrame with + dtype=object. + Default is True. + convert_polarity_to_int : bool + Convert the polarity to int (-1 or +1). + This allows to keep it in numerical form. + This is ignored if the polarity is dropped. + Default is True. + """ + # Log a warning if there was not a valid DLL filename + if BRUKER_DLL_FILE_NAME == "": + logging.warning( + "WARNING: " + "No Bruker libraries are available for this operating system. " + "Mobility and m/z values need to be estimated. " + "While this estimation often returns acceptable results with errors " + "< 0.02 Th, huge errors (e.g. offsets of 6 Th) have already been " + "observed for some samples!" + ) + logging.info("") + + # initialize only if not set by subclass + if not hasattr(self, "_mmap_detector_events"): + self._mmap_detector_events = False + + self._load_data( + bruker_d_folder_name, + mz_estimation_from_frame, + mobility_estimation_from_frame, + drop_polarity, + convert_polarity_to_int, + ) + + logging.info(f"Successfully imported data from {bruker_d_folder_name}") + + def _load_data( + self, + bruker_d_folder_name: str, + mz_estimation_from_frame: int, + mobility_estimation_from_frame: int, + drop_polarity: bool, + convert_polarity_to_int: bool, + ) -> None: + """Load data from disk.""" + + if bruker_d_folder_name.endswith("/"): + bruker_d_folder_name = bruker_d_folder_name[:-1] + + logging.info(f"Importing data from {bruker_d_folder_name}") + if bruker_d_folder_name.endswith(".d"): + self.bruker_d_folder_name = os.path.abspath(bruker_d_folder_name) + self._import_data_from_d_folder( + bruker_d_folder_name, + mz_estimation_from_frame, + mobility_estimation_from_frame, + drop_polarity, + convert_polarity_to_int, + ) + else: + raise NotImplementedError( + "WARNING: file extension not understood. This class only supports import from .d folders. Use TimsTOF class from alphatims to enable import from .hdf files." + ) + + def __len__(self): + return len(self.intensity_values) + + def __hash__(self): + return hash(self.bruker_d_folder_name) + + def _import_data_from_d_folder( + self, + bruker_d_folder_name: str, + mz_estimation_from_frame: int, + mobility_estimation_from_frame: int, + drop_polarity: bool = True, + convert_polarity_to_int: bool = True, + ): + logging.info(f"Using .d import for {bruker_d_folder_name}") + self._version = None + self._zeroth_frame = True + ( + self._acquisition_mode, + global_meta_data, + self._frames, + self._fragment_frames, + self._precursors, + calibration_available, + ) = read_bruker_sql( + bruker_d_folder_name, + self._zeroth_frame, + drop_polarity, + convert_polarity_to_int, + ) + self._meta_data = dict(zip(global_meta_data.Key, global_meta_data.Value)) + ( + self._push_indptr, + self._tof_indices, + self._intensity_values, + ) = read_bruker_binary( + self.frames, + bruker_d_folder_name, + int(self._meta_data["TimsCompressionType"]), + int(self._meta_data["MaxNumPeaksPerScan"]), + self._mmap_detector_events, + self._get_empty_array_constructor_function(), + ) + logging.info(f"Indexing {bruker_d_folder_name}...") + self._use_calibrated_mz_values_as_default = False + self._frame_max_index = self.frames.shape[0] + self._scan_max_index = int(self.frames.NumScans.max()) + 1 + self._tof_max_index = int(self.meta_data["DigitizerNumSamples"]) + 1 + self._rt_values = self.frames.Time.values.astype(np.float64) + self._mobility_min_value = float(self.meta_data["OneOverK0AcqRangeLower"]) + self._mobility_max_value = float(self.meta_data["OneOverK0AcqRangeUpper"]) + self._accumulation_times = self.frames.AccumulationTime.values.astype( + np.float64 + ) + self._max_accumulation_time = np.max(self._accumulation_times) + self._intensity_corrections = ( + self._max_accumulation_time / self._accumulation_times + ) + if (mobility_estimation_from_frame != 0) and calibration_available: + import ctypes + + with open_bruker_d_folder(bruker_d_folder_name) as ( + bruker_dll, + bruker_d_folder_handle, + ): + logging.info(f"Fetching mobility values from {bruker_d_folder_name}") + indices = np.arange(self.scan_max_index).astype(np.float64) + self._mobility_values = np.empty_like(indices) + bruker_dll.tims_scannum_to_oneoverk0( + bruker_d_folder_handle, + mobility_estimation_from_frame, + indices.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), + self.mobility_values.ctypes.data_as( + ctypes.POINTER(ctypes.c_double) + ), + self.scan_max_index, + ) + else: + if mobility_estimation_from_frame != 0: + logging.info("Bruker DLL not available, estimating mobility values") + self._mobility_values = self.mobility_max_value - ( + self.mobility_max_value - self.mobility_min_value + ) / self.scan_max_index * np.arange(self.scan_max_index) + mz_min_value = float(self.meta_data["MzAcqRangeLower"]) + mz_max_value = float(self.meta_data["MzAcqRangeUpper"]) + if self.meta_data["AcquisitionSoftware"] == "Bruker otofControl": + logging.warning( + "WARNING: Acquisition software is Bruker otofControl, " + "mz min/max values are assumed to be 5 m/z wider than " + "defined in analysis.tdf!" + ) + mz_min_value -= 5 + mz_max_value += 5 + tof_intercept = np.sqrt(mz_min_value) + tof_slope = (np.sqrt(mz_max_value) - tof_intercept) / self.tof_max_index + if (mz_estimation_from_frame != 0) and calibration_available: + import ctypes + + with open_bruker_d_folder(bruker_d_folder_name) as ( + bruker_dll, + bruker_d_folder_handle, + ): + logging.info(f"Fetching mz values from {bruker_d_folder_name}") + indices = np.arange(self.tof_max_index).astype(np.float64) + self._mz_values = np.empty_like(indices) + bruker_dll.tims_index_to_mz( + bruker_d_folder_handle, + mz_estimation_from_frame, + indices.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), + self._mz_values.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), + self.tof_max_index, + ) + else: + if mz_estimation_from_frame != 0: + logging.info("Bruker DLL not available, estimating mz values") + self._mz_values = ( + tof_intercept + tof_slope * np.arange(self.tof_max_index) + ) ** 2 + self._parse_quad_indptr() + self._intensity_min_value = int(np.min(self.intensity_values)) + self._intensity_max_value = int(np.max(self.intensity_values)) + if self.acquisition_mode == "diaPASEF": + self.set_cycle() + + def _get_empty_array_constructor_function(self) -> Callable: + """Get the function to create empty arrays for this class. + + This is used to allow subclasses to override the array creation with memory-mapped arrays.""" + return np.empty + + def _parse_quad_indptr(self) -> None: + logging.info("Indexing quadrupole dimension") + frame_ids = self.fragment_frames.Frame.values + 1 + scan_begins = self.fragment_frames.ScanNumBegin.values + scan_ends = self.fragment_frames.ScanNumEnd.values + isolation_mzs = self.fragment_frames.IsolationMz.values + isolation_widths = self.fragment_frames.IsolationWidth.values + precursors = self.fragment_frames.Precursor.values + if precursors[0] is None: + if self.zeroth_frame: + frame_groups = self.frames.MsMsType.values[1:] + else: + frame_groups = self.frames.MsMsType.values + precursor_frames = np.flatnonzero(frame_groups == 0) + group_sizes = np.diff(precursor_frames) + group_size = group_sizes[0] + if np.any(group_sizes != group_size): + raise ValueError("Sample type not understood") + precursors = (1 + frame_ids - frame_ids[0]) % group_size + if self.zeroth_frame: + precursors[0] = 0 + self.fragment_frames.Precursor = precursors + self._acquisition_mode = "diaPASEF" + scan_max_index = self.scan_max_index + frame_max_index = self.frame_max_index + quad_indptr = [0] + quad_low_values = [] + quad_high_values = [] + precursor_indices = [] + high = -1 + for ( + frame_id, + scan_begin, + scan_end, + isolation_mz, + isolation_width, + precursor, + ) in zip( + frame_ids - 1, + scan_begins, + scan_ends, + isolation_mzs, + isolation_widths / 2, + precursors, + ): + low = frame_id * scan_max_index + scan_begin + # TODO: CHECK? + # if low < high: + # print(frame_id, low, frame_id * scan_max_index + scan_end, high, low - high) + if low != high: + quad_indptr.append(low) + quad_low_values.append(-1) + quad_high_values.append(-1) + precursor_indices.append(0) + high = frame_id * scan_max_index + scan_end + quad_indptr.append(high) + quad_low_values.append(isolation_mz - isolation_width) + quad_high_values.append(isolation_mz + isolation_width) + precursor_indices.append(precursor) + quad_max_index = scan_max_index * frame_max_index + if high < quad_max_index: + quad_indptr.append(quad_max_index) + quad_low_values.append(-1) + quad_high_values.append(-1) + precursor_indices.append(0) + self._quad_mz_values = np.stack([quad_low_values, quad_high_values]).T + self._precursor_indices = np.array(precursor_indices) + self._raw_quad_indptr = np.array(quad_indptr) + self._quad_indptr = self.push_indptr[self._raw_quad_indptr] + self._quad_max_mz_value = np.max(self.quad_mz_values[:, 1]) + self._quad_min_mz_value = np.min( + self.quad_mz_values[self.quad_mz_values[:, 0] >= 0, 0] + ) + self._precursor_max_index = int(np.max(self.precursor_indices)) + 1 + if self._acquisition_mode == "diaPASEF": + offset = int(self.zeroth_frame) + cycle_index = ( + np.searchsorted( + self.raw_quad_indptr, + (self.scan_max_index) * (self.precursor_max_index + offset), + "r", + ) + + 1 + ) + repeats = np.diff(self.raw_quad_indptr[:cycle_index]) + if self.zeroth_frame: + repeats[0] -= self.scan_max_index + cycle_length = self.scan_max_index * self.precursor_max_index + repeat_length = np.sum(repeats) + if repeat_length != cycle_length: + repeats[-1] -= repeat_length - cycle_length + self._dia_mz_cycle = np.empty((cycle_length, 2)) + self._dia_mz_cycle[:, 0] = np.repeat( + self.quad_mz_values[: cycle_index - 1, 0], repeats + ) + self._dia_mz_cycle[:, 1] = np.repeat( + self.quad_mz_values[: cycle_index - 1, 1], repeats + ) + self._dia_precursor_cycle = np.repeat( + self.precursor_indices[: cycle_index - 1], repeats + ) + else: + self._dia_mz_cycle = np.empty((0, 2)) + self._dia_precursor_cycle = np.empty(0, dtype=np.int64) + + def set_cycle(self) -> None: + """Set the quad cycle for diaPASEF data.""" + ms1_diffs = np.diff( + np.flatnonzero(self.frames.MsMsType[int(self.zeroth_frame) :] == 0) + ) + subcycle_length_count = np.bincount(ms1_diffs) + if np.all(subcycle_length_count[:-1] != 0): + raise ValueError("No consistent subcycle length") + subcycle_length = len(subcycle_length_count) - 1 + max_precursor = len(self.fragment_frames.Precursor.unique()) + subcycle_count = max_precursor // (subcycle_length - 1) + frame_count = subcycle_length * subcycle_count + cycle = np.zeros( + ( + frame_count, + self.scan_max_index, + 2, + ) + ) + precursor_frames = np.ones(frame_count, dtype=np.bool_) + + subframes = self.fragment_frames.drop("Frame", axis=1) + for max_index in range(1, len(subframes)): + subframe = subframes.iloc[max_index] + if subframe.equals(subframes.iloc[0]): + break + for _, row in self.fragment_frames[:max_index].iterrows(): + frame = int(row.Frame - self.zeroth_frame) + scan_begin = int(row.ScanNumBegin) + scan_end = int(row.ScanNumEnd) + low_mz = row.IsolationMz - row.IsolationWidth / 2 + high_mz = row.IsolationMz + row.IsolationWidth / 2 + cycle[ + frame, + scan_begin:scan_end, + ] = (low_mz, high_mz) + precursor_frames[frame] = False + + cycle[precursor_frames] = (-1, -1) + cycle = cycle.reshape((subcycle_count, subcycle_length, *cycle.shape[1:])) + self._cycle = cycle + + def use_calibrated_mz_values_as_default( + self, use_calibrated_mz_values: int + ) -> None: + """Override the default mz_values with the global calibrated_mz_values.""" + raise NotImplementedError( + "Not implemented for TimsTOFBase. Use TimsTOF class from alphatims to enable use_calibrated_mz_values_as_default." + ) + + def _import_data_from_hdf_file( + self, + bruker_d_folder_name: str, + ): + raise NotImplementedError( + "Not implemented for TimsTOFBase. Use TimsTOF class from alphatims to enable import_data_from_hdf_file." + ) diff --git a/alpharaw/ext/bruker/timsdata.dll b/alpharaw/ext/bruker/timsdata.dll new file mode 100644 index 0000000..628f64f Binary files /dev/null and b/alpharaw/ext/bruker/timsdata.dll differ diff --git a/alpharaw/ext/bruker/timsdata.so b/alpharaw/ext/bruker/timsdata.so new file mode 100644 index 0000000..8d5bb93 Binary files /dev/null and b/alpharaw/ext/bruker/timsdata.so differ diff --git a/alpharaw/feature/centroids.py b/alpharaw/feature/centroids.py index a8ba8ba..9fc7abe 100644 --- a/alpharaw/feature/centroids.py +++ b/alpharaw/feature/centroids.py @@ -1,7 +1,8 @@ import numpy as np -from alphatims.utils import threadpool from numba import njit +from alpharaw.utils.pjit import threadpool + @threadpool @njit diff --git a/alpharaw/feature/hills.py b/alpharaw/feature/hills.py index 296948a..7268dd4 100644 --- a/alpharaw/feature/hills.py +++ b/alpharaw/feature/hills.py @@ -1,9 +1,9 @@ import numpy as np import pandas as pd -from alphatims.utils import threadpool from numba import njit from alpharaw.feature.centroids import connect_centroids +from alpharaw.utils.pjit import threadpool @threadpool(include_progress_callback=False) diff --git a/alpharaw/feature/isotope_pattern.py b/alpharaw/feature/isotope_pattern.py index fe3552c..451afbd 100644 --- a/alpharaw/feature/isotope_pattern.py +++ b/alpharaw/feature/isotope_pattern.py @@ -2,7 +2,6 @@ import numpy as np import pandas as pd -from alphatims.utils import threadpool from numba import njit from numba.typed import Dict, List @@ -13,6 +12,7 @@ M_PROTON, mass_to_dist, ) +from alpharaw.utils.pjit import threadpool def find_connected_components(edges, min_size=2): diff --git a/alpharaw/match/psm_match.py b/alpharaw/match/psm_match.py index 16f0bde..b0f0e4d 100644 --- a/alpharaw/match/psm_match.py +++ b/alpharaw/match/psm_match.py @@ -19,9 +19,5 @@ def load_ms_data(*args, **kwargs): raise DeprecationWarning(f"load_ms_data {_DEPRECATION_MSG}") -def get_best_matched_intens(*args, **kwargs): - raise DeprecationWarning(f"get_best_matched_intens {_DEPRECATION_MSG}") - - def get_ion_count_scores(*args, **kwargs): raise DeprecationWarning(f"get_ion_count_scores {_DEPRECATION_MSG}") diff --git a/alpharaw/utils/df_processing.py b/alpharaw/utils/df_processing.py index ea77c3d..545ffc4 100644 --- a/alpharaw/utils/df_processing.py +++ b/alpharaw/utils/df_processing.py @@ -3,5 +3,5 @@ def remove_unused_peaks(*args, **kwargs): raise DeprecationWarning( - "remove_unused_peaks has been moved to alphatims and will be removed from alpharaw in a future version." + "remove_unused_peaks has been moved to peptdeep and will be removed from alpharaw in a future version." ) diff --git a/alpharaw/utils/pjit.py b/alpharaw/utils/pjit.py index 5fb3235..7ea6748 100644 --- a/alpharaw/utils/pjit.py +++ b/alpharaw/utils/pjit.py @@ -9,7 +9,7 @@ from collections.abc import Iterable from typing import Callable -_MAX_THREADS = multiprocessing.cpu_count() +MAX_THREADS = multiprocessing.cpu_count() _PROGRESS_CALLBACK = True @@ -41,8 +41,8 @@ def set_threads(threads: int, *, set_global: bool = True) -> int: while threads <= 0: threads += max_cpu_count if set_global: - global _MAX_THREADS # noqa: PLW0603 - _MAX_THREADS = threads + global MAX_THREADS # noqa: PLW0603 + MAX_THREADS = threads return threads @@ -52,7 +52,7 @@ def threadpool( thread_count: int | None = None, include_progress_callback: bool = True, return_results: bool = False, -) -> None: +) -> Callable: """A decorator that parallelizes a function with threads and callback. The original function should accept a single element as its first argument. @@ -65,7 +65,7 @@ def threadpool( The function to decorate. thread_count : int, None The number of threads to use. - This is always parsed with alphatims.utils.set_threads. + This is always parsed with set_threads(). Not possible as positional arguments, it always needs to be an explicit keyword argument. Default is None. @@ -103,7 +103,7 @@ def starfunc(iterable): # noqa: ANN001, ANN202 except TypeError: return func(iterable, *args, **kwargs) if thread_count is None: - current_thread_count = _MAX_THREADS + current_thread_count = MAX_THREADS else: current_thread_count = set_threads(thread_count, set_global=False) with multiprocessing.pool.ThreadPool(current_thread_count) as pool: @@ -178,7 +178,7 @@ def pjit( # noqa: ANN201, D417, C901 _func : callable, None The function to decorate. Default is None. thread_count : int, None - The number of threads to use. This is always parsed with alphatims.utils.set_threads. + The number of threads to use. This is always parsed with set_threads(). Default is None. include_progress_callback : bool If True, the default progress callback will be used as callback. (See "progress_callback" function and @@ -247,7 +247,7 @@ def wrapper(iterable, *args) -> None: # noqa: ANN001 subsequently passed to the original function. """ if thread_count is None: - current_thread_count = _MAX_THREADS + current_thread_count = MAX_THREADS else: current_thread_count = set_threads(thread_count, set_global=False) @@ -374,3 +374,28 @@ def set_progress_callback(progress_callback) -> None: # noqa: ANN001 """ global _PROGRESS_CALLBACK # noqa: PLW0603 _PROGRESS_CALLBACK = progress_callback + + +def njit(_func: Callable | None = None, *args, **kwargs) -> Callable: + """A wrapper for the numba.njit decorator. + + This can be overriden with kwargs. + + Parameters + ---------- + _func : callable, None + The function to decorate. + *args + See numba.njit decorator. + **kwargs + See numba.njit decorator. + + Returns + ------- + : function + A numba.njit decorated function. + + """ + import numba + + return numba.njit(_func, *args, **kwargs) diff --git a/alpharaw/utils/timstof.py b/alpharaw/utils/timstof.py index 5807edd..a6075e3 100644 --- a/alpharaw/utils/timstof.py +++ b/alpharaw/utils/timstof.py @@ -3,5 +3,5 @@ def convert_to_alphatims(*args, **kwargs): raise DeprecationWarning( - "convert_to_alphatims has been moved to alphatims and will be removed from alpharaw in a future version." + "convert_to_alphatims has been moved to peptdeep and will be removed from alpharaw in a future version." ) diff --git a/alpharaw/viz/plot_utils.py b/alpharaw/viz/plot_utils.py index 7498d9b..5eb0bc5 100644 --- a/alpharaw/viz/plot_utils.py +++ b/alpharaw/viz/plot_utils.py @@ -51,13 +51,13 @@ def plot_scatter( def plot_line_tims(*args, **kwargs) -> go.Figure: raise DeprecationWarning( - "plot_line_tims has been moved to alphaviz and will be removed from alpharaw in a future version." + "plot_line_tims has been moved to alphatims and will be removed from alpharaw in a future version." ) def plot_line_tims_fast(*args, **kwargs) -> go.Figure: raise DeprecationWarning( - "plot_line_tims_fast has been moved to alphaviz and will be removed from alpharaw in a future version." + "plot_line_tims_fast has been moved to alphatims and will be removed from alpharaw in a future version." ) diff --git a/alpharaw/viz/xic_plot_tims.py b/alpharaw/viz/xic_plot_tims.py index b9dfee1..20f1bab 100644 --- a/alpharaw/viz/xic_plot_tims.py +++ b/alpharaw/viz/xic_plot_tims.py @@ -1,5 +1,5 @@ _DEPRECATION_MSG = ( - "has been moved to alphaviz and will be removed from alpharaw in a future version." + "has been moved to alphatims and will be removed from alpharaw in a future version." ) diff --git a/alpharaw/wrappers/alphatims_wrapper.py b/alpharaw/wrappers/alphatims_wrapper.py index 31dc76b..fafd093 100644 --- a/alpharaw/wrappers/alphatims_wrapper.py +++ b/alpharaw/wrappers/alphatims_wrapper.py @@ -1,7 +1,7 @@ -"""Deprecated wrapper for AlphaTimsReader and AlphaTimsWrapper. These classes have been moved to the alphatims package.""" +"""Deprecated wrapper for AlphaTimsReader and AlphaTimsWrapper. These classes have been moved to the peptdeep package.""" _DEPRECATION_MSG = ( - "has been moved to alphatims and will be removed from alpharaw in a future version." + "has been moved to peptdeep and will be removed from alpharaw in a future version." ) diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 6294b1d..78d9628 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -12,6 +12,6 @@ pyteomics==4.7.2 lxml==5.2.2 owlready2==0.48 #sqlalchemy +pyzstd==0.15.3 alphabase>=1.5.0 # test: tolerate_version -alphatims>=0.0.1 # test: tolerate_version diff --git a/requirements/requirements_loose.txt b/requirements/requirements_loose.txt index 63c8660..d88f130 100644 --- a/requirements/requirements_loose.txt +++ b/requirements/requirements_loose.txt @@ -11,6 +11,6 @@ numpy pyteomics lxml owlready2 +pyzstd alphabase>=1.5.0 # test: tolerate_version -alphatims diff --git a/ruff-lint-strict.toml b/ruff-lint-strict.toml index d5b11e3..7e99303 100644 --- a/ruff-lint-strict.toml +++ b/ruff-lint-strict.toml @@ -7,6 +7,7 @@ select = [ # TODO excluding explicity is not great but it is a workaround for now exclude = [ "alpharaw/__init__.py", +"alpharaw/bruker/**.py", "alpharaw/wrappers/alphatims_wrapper.py", "alpharaw/wrappers/alphapept_wrapper.py", "alpharaw/raw_access/pysciexwifffilereader.py",