├── CMakeLists.txt ├── LICENSE.txt ├── README.md ├── _config.yml ├── doc └── theory.tex └── src ├── AsciiParser.hpp ├── AsciiParser.hxx ├── CMakeLists.txt ├── covariance.cpp ├── covariance.hpp ├── errors.cpp ├── errors.hpp ├── fastpca.cpp ├── file_io.cpp ├── file_io.hpp ├── file_io.hxx ├── matrix.cpp ├── matrix.hpp ├── matrix.hxx ├── util.cpp ├── util.hpp ├── util.hxx └── xdrfile ├── CMakeLists.txt ├── trr2xtc.c ├── xdrfile.c ├── xdrfile.h ├── xdrfile_c_test.c ├── xdrfile_trr.c ├── xdrfile_trr.h ├── xdrfile_xtc.c └── xdrfile_xtc.h /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.8) 2 | project (FastPCA) 3 | 4 | set (CMAKE_CXX_FLAGS "-std=c++11 -fopenmp -O2 -g") 5 | 6 | find_package (Boost COMPONENTS program_options REQUIRED) 7 | include_directories (${Boost_INCLUDE_DIR}) 8 | 9 | find_package (LAPACK REQUIRED) 10 | 11 | add_subdirectory (src) 12 | 13 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | ########################################################### 3 | FastCA - a parallelizing Principal Component Analysis tool 4 | ########################################################### 5 | 6 | Copyright (c) 2014, Florian Sittel (www.lettis.net) 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | 12 | 1. Redistributions of source code must retain the above copyright notice, this 13 | list of conditions and the following disclaimer. 14 | 2. Redistributions in binary form must reproduce the above copyright notice, 15 | this list of conditions and the following disclaimer in the documentation 16 | and/or other materials provided with the distribution. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 22 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | ############################################ 30 | 31 | The folder ./src/xdrfile contains the xdrfile-library of GROMACS which is licensed separately 32 | under the GNU Lesser General Public License. 33 | Please refer to the contained source/header files for more detailed information 34 | about usage and licensing. 35 | 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # About 2 | 3 | *FastPCA* is a PCA-calculator programmed in C++11 parallelized with OpenMP. 4 | 5 | The *FastPCA* package is an implementation of the principal component analysis of large MD data sets, using either Cartesian atom coordinates, interatom distances or backbone dihedral angles as input coordinates. In particular, it features the dihedral angle PCA on a torus (dPCA+) by Sittel et al., 2017, which performs maximal gap shifting to treat periodic data correctly. It is optimized and parallelized with constant memory consumption for large data sets. 6 | 7 | For fast matrix diagonalization, LAPACK is used (and needed, of course). 8 | 9 | The project includes the 'xdrfile' library of GROMACS. Thus, you can 10 | use data files written as ASCII data as well as .xtc-trajectories. 11 | 12 | For bug-reports just open an issue. 13 | 14 | Happy Computing. 15 | 16 | # Licensing 17 | The code is published "AS IS" under the simplified BSD license. 18 | For details, please see LICENSE.txt 19 | 20 | If you use the code for published works, please cite as 21 | 22 | - F. Sittel et al., *Principal component analysis on a torus: Theory and application to protein dynamics*, J. Chem. Phys 147, 244101, 2017; DOI:10.1063/1.4998259 23 | 24 | # Installation (Linux only!) 25 | This package can be installed with conda via 26 | ``` 27 | conda install fastpca -c conda-forge 28 | ``` 29 | If conda is not available, it can be compiled as well. 30 | 31 | # Compilation 32 | Download this repo 33 | ``` 34 | git clone https://github.com/moldyn/FastPCA.git 35 | ``` 36 | If `gcc = 7.x.x - 8.x.x` is used, please use the following branch 37 | ``` 38 | git clone --branch fix_gcc8 https://github.com/moldyn/FastPCA.git 39 | ``` 40 | For `gcc > 9.x.x` please use the following branch 41 | ``` 42 | git clone --branch fix_gcc10 https://github.com/moldyn/FastPCA.git 43 | ``` 44 | Create a build-directory in the project root and change into 45 | that directory: 46 | ``` 47 | mkdir build 48 | cd build 49 | ``` 50 | Run cmake, based on the underlying project: 51 | ``` 52 | cmake .. 53 | ``` 54 | Hopefully, everything went right. 55 | If not, carefully read the error messages. 56 | Typical errors are missing dependencies... 57 | 58 | If everything is o.k., run make (on multicore machines, use '-j' to parallelize 59 | compilation, e.g. 'make -j 4' for up to four parallel jobs): 60 | ``` 61 | make 62 | ``` 63 | Now, you should find the 'fastca' binary in the 'src' folder. 64 | 65 | ## Requirements 66 | * LAPACK 67 | * Boost (program_options), min. version 1.49 68 | * cmake, min. version 2.8 69 | * g++ <= 7.x.x (otherwise use [fix_gcc8](../../tree/fix_gcc8) branch) 70 | 71 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-minimal -------------------------------------------------------------------------------- /doc/theory.tex: -------------------------------------------------------------------------------- 1 | \documentclass[a4paper]{article} 2 | 3 | \usepackage{amsmath} 4 | \usepackage{amsfonts} 5 | \usepackage{bbm} 6 | \usepackage{color} 7 | \usepackage{graphicx} 8 | \usepackage{caption} 9 | \usepackage{subcaption} 10 | 11 | \newcommand{\X} {\mathbf{X}} 12 | 13 | \newcommand{\todo}[1] { \emph{ {\color{red}TODO: #1} } } 14 | 15 | \begin{document} 16 | 17 | \section{Incremental calculation of a covariance matrix} 18 | Given a $T\times N$ matrix $m$ of measurements in $N$ variables 19 | at $T$ timesteps, the covariance matrix of all variables is given by 20 | \begin{align} 21 | C_{ij} &= \left<\left(\X_i- \left<\X_i\right>\right) \left(\X_j-\left<\X_j\right>\right)\right>, 22 | \end{align} 23 | where $\X_i \in \mathbb{R}^T$ denotes column $i$ of matrix $m$ with all observations 24 | of variable $i$ and $\left< \dots \right>$ is the average of the given observations. 25 | Using the definition 26 | \begin{align} 27 | \mu_i := \left< \X_i \right>, 28 | \end{align} 29 | the construction of the covariance matrix can be expressed as 30 | \begin{align} 31 | C_{ij} &= \left<\left(\X_i - \mu_i\right) \left(\X_j - \mu_j\right)\right>\\ 32 | &= \left<\X_i \X_j\right> - \left< \mu_i \X_j \right> - \left< \mu_j \X_i \right> + \left< \mu_i \mu_j \right>\\ 33 | &= \left<\X_i \X_j\right> - \mu_i \left<\X_j \right> - \mu_j \left<\X_i\right> + \left< \mu_i \mu_j \right>\\ 34 | &= \left<\X_i \X_j\right> - \mu_i \mu_j - \mu_j \mu_i + \mu_i \mu_j\\ 35 | &= \left<\X_i \X_j\right> - \mu_i \mu_j\\ 36 | &= \frac{1}{T} \sum_t m_{ti} m_{tj} - \mu_i \mu_j\\ 37 | &= \frac{1}{T-1}\left( \sum_t m_{ti} m_{tj} - \frac{1}{T} \left(\sum_t m_{ti}\right) \left(\sum_t m_{tj}\right) \right) 38 | \label{eq:cov_standard}. 39 | \end{align} 40 | Following this expression, we see that the covariance matrix can be 41 | constructed incrementally by summing over the observations with constant memory consumption. 42 | The used memory will be of order 43 | \begin{align} 44 | \mathcal{O}_M &= \mathcal{O}_C + N\mathcal{O}_\mu\\ 45 | &= \mathcal{O}\left( (N-1)(N-2) / 2 \right) + N\mathcal{O}\left(1\right)\\ 46 | &= \mathcal{O}\left( N^2 \right), 47 | \end{align} 48 | with the memory consumption $\mathcal{O}_C$ of the (symmetric) covariance matrix and 49 | the memory consumption $\mathcal{O}_\mu$ per observable average. 50 | The runtime behavior will be of order 51 | \begin{align} 52 | \mathcal{O}_R &= \mathcal{O}\left(T N\left(N-1\right)\right). 53 | \end{align} 54 | Assuming the number of observations $T$ is much greater than the number of variables $N$, i.e. $T \gg N$, 55 | the runtime behavior may be described as being linear in $T$: 56 | \begin{align} 57 | \mathcal{O}_R &= \mathcal{O}\left(T\right). 58 | \end{align} 59 | 60 | \subsection{Weighted variables} 61 | To construct a covariance matrix with weighted variables (e.g. a mass-weighted covariance of molecular coordinates), 62 | one previously defines a set of $N$ weights $w_i$ and expands the given incremental form (\ref{eq:cov_standard}) to 63 | \begin{align} 64 | \tilde{C}_{ij} &= \frac{1}{T}\left( \sum_t w_i m_{ti} w_j m_{tj} - \frac{1}{T} \left(\sum_t w_i m_{ti}\right) \left(\sum_t w_j m_{tj}\right) \right)\\ 65 | &= \frac{1}{T}\left( w_i w_j \sum_t m_{ti} m_{tj} - \frac{1}{T} \left(w_i \sum_t m_{ti}\right) \left(w_j \sum_t m_{tj}\right) \right)\\ 66 | &= \frac{w_i w_j}{T}\left(\sum_t m_{ti} m_{tj} - \frac{1}{T} \left(\sum_t m_{ti}\right) \left(\sum_t m_{tj}\right) \right). 67 | \end{align} 68 | Here, it is assumed that all the weights are normalized, i.e. that they fulfill the relation 69 | \begin{align} 70 | \sum_i^N w_i = 1, 71 | \end{align} 72 | with $0 \le w_i \le 1$. 73 | If this is not the case, one can trivially transform the set of weights to a normalized one by dividing the weights by their sum. 74 | 75 | \subsection{Weighted observations} 76 | To construct a covariance matrix based on observations of different quality, we introduce the weights $\nu\left(t\right)$, defined 77 | for an observation at time $t$. 78 | Again, one can extend eq. (\ref{eq:cov_standard}) to a weighted form: 79 | \begin{align} 80 | \hat{C}_{ij} &= \frac{1}{\tau}\left( \sum_t \nu\left(t\right) m_{ti} m_{tj} 81 | - \frac{1}{\tau} \left(\sum_t \nu\left(t\right) m_{ti}\right) \left(\sum_t \nu\left(t\right) m_{tj}\right) \right), 82 | \end{align} 83 | with $\tau = \sum_t \nu\left(t\right)$ being the total weight. 84 | In the case of unweighted observations, i.e. for $\nu\left(t\right) = 1 \; \forall \; t$, this reduces to the standard definition 85 | of a covariance matrix (eq. (\ref{eq:cov_standard})). 86 | 87 | \end{document} 88 | -------------------------------------------------------------------------------- /src/AsciiParser.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | /* 3 | Copyright (c) 2014, Florian Sittel (www.lettis.net) 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | #include 27 | #include 28 | #include 29 | 30 | namespace LTS { 31 | 32 | template 33 | class AsciiParser { 34 | public: 35 | enum Flags { 36 | ROW_MAJOR, 37 | COL_MAJOR 38 | }; 39 | 40 | AsciiParser(); 41 | AsciiParser(const std::string filename); 42 | ~AsciiParser(); 43 | // open file for reading 44 | void open(const std::string filename); 45 | // return number of columns in file 46 | std::size_t n_cols(); 47 | // return next value 48 | T next(); 49 | // return next line 50 | std::vector next_line(); 51 | // return n lines as STL vector of lines 52 | // TODO n as reference 53 | std::vector> next_n_lines(std::size_t n); 54 | // return n lines coninues in one STL vector 55 | // addressing in ROW_MAJOR format: elem(i,j) = block[i*n_cols+j] 56 | // addressing in COL_MAJOR format: elem(i,j) = block[j*n+i] 57 | // if less then n lines can be read (e.g. in case of EOF), n will 58 | // be reset to the actual number of lines read. 59 | // If n is initialized to 0, read all lines until EOF. 60 | std::vector next_n_lines_continuous(std::size_t& n, Flags mode=AsciiParser::ROW_MAJOR); 61 | // EOF reached? 62 | bool eof(); 63 | private: 64 | // parse first line that is not empty 65 | // nor comment to get number of columns 66 | void _n_cols_from_first_line(); 67 | // cycle through lines in opened file, halting every 68 | // time there are actual values and not just empty lines 69 | // or comments. 70 | // used internally as helper function for linewise parsing. 71 | bool _comments_ignored(); 72 | std::ifstream _fh_in; 73 | std::size_t _n_cols; 74 | }; 75 | 76 | } // end namespace LTS 77 | 78 | #include "AsciiParser.hxx" 79 | 80 | -------------------------------------------------------------------------------- /src/AsciiParser.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014, Florian Sittel (www.lettis.net) 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | #include 26 | #include 27 | 28 | namespace LTS { 29 | 30 | template 31 | AsciiParser::AsciiParser() 32 | : _n_cols(0) { 33 | } 34 | 35 | template 36 | AsciiParser::AsciiParser(const std::string filename) 37 | : _n_cols(0) { 38 | this->_fh_in.open(filename.c_str(), std::ios::in); 39 | this->_n_cols_from_first_line(); 40 | this->_fh_in.seekg(this->_fh_in.beg); 41 | } 42 | 43 | template 44 | AsciiParser::~AsciiParser() { 45 | this->_fh_in.close(); 46 | } 47 | 48 | template 49 | void AsciiParser::open(const std::string filename) { 50 | this->_fh_in.open(filename.c_str(), std::ios::in); 51 | this->_n_cols_from_first_line(); 52 | this->_fh_in.seekg(this->_fh_in.beg); 53 | } 54 | 55 | template 56 | std::size_t AsciiParser::n_cols() { 57 | return this->_n_cols; 58 | } 59 | 60 | template 61 | T AsciiParser::next() { 62 | T buf=0; 63 | while (this->_comments_ignored()) { 64 | this->_fh_in >> buf; 65 | } 66 | return buf; 67 | } 68 | 69 | template 70 | std::vector AsciiParser::next_line() { 71 | while (this->_comments_ignored()) { 72 | std::vector res(this->_n_cols); 73 | for (std::size_t j=0; j < this->_n_cols; ++j) { 74 | this->_fh_in >> res[j]; 75 | } 76 | return res; 77 | } 78 | } 79 | 80 | template 81 | std::vector< std::vector > AsciiParser::next_n_lines(std::size_t n) { 82 | std::vector< std::vector > res(n, std::vector(this->_n_cols)); 83 | std::size_t i=0; 84 | while (this->_comments_ignored()) { 85 | if (i < n) { 86 | for (std::size_t j=0; j < this->_n_cols; ++j) { 87 | this->_fh_in >> res[i][j]; 88 | } 89 | ++i; 90 | } else { 91 | break; 92 | } 93 | } 94 | return res; 95 | } 96 | 97 | template 98 | std::vector AsciiParser::next_n_lines_continuous(std::size_t& n, AsciiParser::Flags mode) { 99 | // use result-vector directly if n is known 100 | std::vector res(n * _n_cols); 101 | // use this, if n == 0, i.e. if number of rows is unknown 102 | std::vector> res_infty_n(_n_cols, std::vector()); 103 | std::size_t i=0; 104 | while (this->_comments_ignored()) { 105 | if (n == 0) { 106 | // read complete file 107 | for (std::size_t j=0; j < _n_cols; ++j) { 108 | T buf; 109 | _fh_in >> buf; 110 | res_infty_n[j].push_back(buf); 111 | } 112 | } else if (i < n) { 113 | // read until max number of rows is reached 114 | for (std::size_t j=0; j < _n_cols; ++j) { 115 | if (mode == ROW_MAJOR) { 116 | this->_fh_in >> res[i*_n_cols+j]; 117 | } else if (mode == COL_MAJOR) { 118 | this->_fh_in >> res[j*n+i]; 119 | } 120 | } 121 | } else { 122 | break; 123 | } 124 | ++i; 125 | } 126 | // handle case that less than n lines have been read 127 | if (i != n) { 128 | if (mode == ROW_MAJOR) { 129 | // trivial, just shorten vector 130 | res.resize(i * _n_cols); 131 | if (n == 0) { 132 | for (std::size_t ii=0; ii < i; ++ii) { 133 | for (std::size_t jj=0; jj < _n_cols; ++jj) { 134 | res[ii*_n_cols+jj] = res_infty_n[jj][ii]; 135 | } 136 | } 137 | } 138 | } else if (mode == COL_MAJOR) { 139 | // recopy to new, smaller vector 140 | std::vector buf(i * _n_cols); 141 | for (std::size_t ii=0; ii < i; ++ii) { 142 | for (std::size_t jj=0; jj < _n_cols; ++jj) { 143 | if (n == 0) { 144 | buf[jj*i+ii] = res_infty_n[jj][ii]; 145 | } else { 146 | buf[jj*i+ii] = res[jj*n+ii]; 147 | } 148 | } 149 | } 150 | res = buf; 151 | } 152 | n = i; 153 | } 154 | return res; 155 | } 156 | 157 | template 158 | bool AsciiParser::eof() { 159 | return this->_fh_in.eof(); 160 | } 161 | 162 | //// private 163 | 164 | template 165 | void AsciiParser::_n_cols_from_first_line() { 166 | while(this->_fh_in) { 167 | char c = this->_fh_in.peek(); 168 | if (c == '#' || c == '\n' || c == '@') { 169 | this->_fh_in.ignore(std::numeric_limits::max(), '\n'); 170 | } else { 171 | std::string buf, fake; 172 | std::getline(this->_fh_in, buf); 173 | std::stringstream ss(buf, std::stringstream::in); 174 | this->_n_cols = 0; 175 | while (ss >> fake) { 176 | this->_n_cols++; 177 | } 178 | break; 179 | } 180 | } 181 | } 182 | 183 | template 184 | bool AsciiParser::_comments_ignored() { 185 | while (this->_fh_in) { 186 | char c = this->_fh_in.peek(); 187 | if (c == '#' || c == '\n' || c == '@') { 188 | this->_fh_in.ignore(std::numeric_limits::max(), '\n'); 189 | } else { 190 | break; 191 | } 192 | } 193 | return this->_fh_in.good(); 194 | } 195 | 196 | } // end namespace LTS 197 | 198 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014, Florian Sittel 2 | # All rights reserved. 3 | # 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions are met: 6 | # 7 | # 1. Redistributions of source code must retain the above copyright notice, this 8 | # list of conditions and the following disclaimer. 9 | # 2. Redistributions in binary form must reproduce the above copyright notice, 10 | # this list of conditions and the following disclaimer in the documentation 11 | # and/or other materials provided with the distribution. 12 | # 13 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | add_library(covariance covariance.cpp file_io.cpp util.cpp matrix.cpp errors.cpp) 25 | 26 | add_subdirectory(xdrfile) 27 | 28 | add_executable (fastpca fastpca.cpp) 29 | target_link_libraries (fastpca covariance xdrfile ${Boost_LIBRARIES} ${LAPACK_LIBRARIES}) 30 | 31 | install(TARGETS fastpca RUNTIME DESTINATION .) 32 | 33 | -------------------------------------------------------------------------------- /src/covariance.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Copyright (c) 2014, Florian Sittel (www.lettis.net) 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #include "covariance.hpp" 28 | #include "file_io.hpp" 29 | #include "errors.hpp" 30 | #include "util.hpp" 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | 40 | extern "C" { 41 | // use xdrfile library to read/write xtc and trr files from gromacs 42 | #include "xdrfile/xdrfile.h" 43 | #include "xdrfile/xdrfile_xtc.h" 44 | #include "xdrfile/xdrfile_trr.h" 45 | } 46 | 47 | 48 | namespace FastPCA { 49 | 50 | namespace { 51 | 52 | _CovAccumulation::_CovAccumulation(SymmetricMatrix m 53 | , std::size_t n) 54 | : m(m), 55 | n_observations(n) { 56 | } 57 | 58 | _CovAccumulation::_CovAccumulation(std::size_t n_observations 59 | , std::size_t n_observables) 60 | : m(SymmetricMatrix(n_observables)), 61 | n_observations(n_observations) { 62 | } 63 | 64 | _CovAccumulation 65 | _accumulate_covariance(const Matrix& m) { 66 | const std::size_t nr = m.n_rows(); 67 | const std::size_t nc = m.n_cols(); 68 | _CovAccumulation c(nr, nc); 69 | std::size_t i, j, t; 70 | double cc; 71 | // calculate (i,j)-part of covariances 72 | for (i = 0; i < nc; ++i) { 73 | for (j = 0; j <= i; ++j) { 74 | cc = 0.0; 75 | #pragma omp parallel for default(none)\ 76 | firstprivate(i,j)\ 77 | private(t)\ 78 | shared(m,c)\ 79 | reduction(+:cc) 80 | for (t = 0; t < nr; ++t) { 81 | cc += (m(t,i) * m(t,j)); 82 | } 83 | c.m(i,j) = cc; 84 | } 85 | } 86 | c.n_observations = nr; 87 | return c; 88 | } 89 | 90 | _CovAccumulation 91 | _join_accumulations(const _CovAccumulation& c1 92 | , const _CovAccumulation& c2) { 93 | assert(c1.m.n_cols() == c2.m.n_cols()); 94 | return {c1.m+c2.m, c1.n_observations+c2.n_observations}; 95 | } 96 | 97 | SymmetricMatrix 98 | _get_covariance(const _CovAccumulation& acc) { 99 | std::size_t i, j; 100 | SymmetricMatrix sm = acc.m; 101 | for (i = 0; i < sm.n_cols(); ++i) { 102 | for (j = 0; j <= i; ++j) { 103 | sm(i,j) /= (acc.n_observations-1); 104 | } 105 | } 106 | return sm; 107 | } 108 | 109 | SymmetricMatrix 110 | _covariance_matrix(const std::string filename 111 | , const std::size_t max_chunk_size 112 | , bool use_correlation 113 | , bool periodic 114 | , Matrix stats) { 115 | std::size_t n_variables = stats.n_rows(); 116 | std::vector means(n_variables); 117 | std::vector shifts(n_variables); 118 | std::vector inverse_sigmas(n_variables); 119 | for (std::size_t i=0; i < n_variables; ++i) { 120 | means[i] = stats(i,0); 121 | inverse_sigmas[i] = 1.0 / stats(i,1); 122 | if (periodic) { 123 | shifts[i] = stats(i,2); 124 | } 125 | } 126 | // take only half size because of intermediate results. 127 | std::size_t chunk_size = max_chunk_size / 2; 128 | // data files are often to big to read into RAM completely. 129 | // thus, we read the data blockwise, calculate the temporary 130 | // covariance data and accumulate the results. 131 | DataFileReader input_file(filename, chunk_size); 132 | std::size_t n_cols = input_file.n_cols(); 133 | _CovAccumulation acc(0, n_cols); 134 | Matrix m = std::move(input_file.next_block()); 135 | while (m.n_rows() > 0) { 136 | // periodic correction 137 | if (periodic) { 138 | FastPCA::deg2rad_inplace(m); 139 | FastPCA::Periodic::shift_matrix_columns_inplace(m 140 | , shifts); 141 | } 142 | // center data 143 | FastPCA::shift_matrix_columns_inplace(m, means); 144 | // normalize columns by dividing by sigma 145 | if (use_correlation) { 146 | FastPCA::scale_matrix_columns_inplace(m 147 | , inverse_sigmas); 148 | } 149 | acc = _join_accumulations(acc, _accumulate_covariance(m)); 150 | m = std::move(input_file.next_block()); 151 | } 152 | // last, we calculate the total covariance from the 153 | // accumulated data. 154 | return _get_covariance(acc); 155 | } 156 | } // end local namespace 157 | 158 | 159 | namespace Periodic { 160 | // compute covariance matrix for periodic data 161 | SymmetricMatrix 162 | covariance_matrix(const std::string filename 163 | , const std::size_t max_chunk_size 164 | , bool use_correlation 165 | , Matrix stats) { 166 | return _covariance_matrix(filename 167 | , max_chunk_size 168 | , use_correlation 169 | , true 170 | , stats); 171 | } 172 | } // end namespace FastPCA::Periodic 173 | 174 | SymmetricMatrix 175 | covariance_matrix(const std::string filename 176 | , const std::size_t max_chunk_size 177 | , bool use_correlation 178 | , Matrix stats) { 179 | return _covariance_matrix(filename 180 | , max_chunk_size 181 | , use_correlation 182 | , false 183 | , stats); 184 | } 185 | } // end namespace FastPCA 186 | 187 | -------------------------------------------------------------------------------- /src/covariance.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | /* 3 | Copyright (c) 2014, Florian Sittel (www.lettis.net) 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | 28 | #include "matrix.hpp" 29 | 30 | namespace FastPCA { 31 | namespace { 32 | struct _CovAccumulation { 33 | _CovAccumulation(SymmetricMatrix m, std::size_t n); 34 | _CovAccumulation(std::size_t n_observations, std::size_t n_observables); 35 | SymmetricMatrix m; 36 | std::size_t n_observations; 37 | }; 38 | 39 | _CovAccumulation 40 | _accumulate_covariance(const Matrix& m); 41 | 42 | _CovAccumulation 43 | _join_accumulations(const _CovAccumulation& c1, const _CovAccumulation& c2); 44 | 45 | SymmetricMatrix 46 | _get_covariance(const _CovAccumulation& acc); 47 | } // end local namespace 48 | 49 | SymmetricMatrix 50 | covariance_matrix(const std::string filename 51 | , const std::size_t max_chunk_size 52 | , bool use_correlation 53 | , Matrix stats); 54 | 55 | namespace Periodic { 56 | SymmetricMatrix 57 | covariance_matrix(const std::string filename 58 | , const std::size_t max_chunk_size 59 | , bool use_correlation 60 | , Matrix stats); 61 | }; // end namespace FastPCA::Periodic 62 | 63 | } // end namespace FastPCA 64 | 65 | -------------------------------------------------------------------------------- /src/errors.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Copyright (c) 2014, Florian Sittel (www.lettis.net) 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | 28 | #include "errors.hpp" 29 | 30 | namespace FastPCA { 31 | 32 | const char* FileFormatError::what() const noexcept { 33 | return "unsupported file format"; 34 | } 35 | 36 | 37 | const char* FileNotFoundError::what() const noexcept { 38 | return "file not found"; 39 | } 40 | 41 | 42 | const char* MatrixNotAlignedError::what() const noexcept { 43 | return "matrices are not aligned"; 44 | } 45 | 46 | } // end namespace FastPCA 47 | 48 | -------------------------------------------------------------------------------- /src/errors.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | Copyright (c) 2014, Florian Sittel (www.lettis.net) 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | namespace FastPCA { 33 | 34 | class FileFormatError : public std::exception { 35 | virtual const char* what() const noexcept; 36 | }; 37 | 38 | class FileNotFoundError : public std::exception { 39 | virtual const char* what() const noexcept; 40 | }; 41 | 42 | class MatrixNotAlignedError : public std::exception { 43 | virtual const char* what() const noexcept; 44 | }; 45 | 46 | } // end namespace FastPCA 47 | 48 | -------------------------------------------------------------------------------- /src/fastpca.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Copyright (c) 2014, Florian Sittel (www.lettis.net) 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | 28 | #include "covariance.hpp" 29 | #include "file_io.hpp" 30 | #include "matrix.hpp" 31 | #include "util.hpp" 32 | 33 | #include 34 | #include 35 | #include 36 | 37 | namespace b_po = boost::program_options; 38 | 39 | int main(int argc, char* argv[]) { 40 | bool verbose = false; 41 | bool periodic = false; 42 | bool dynamic_shift = false; 43 | bool use_correlation = false; 44 | 45 | b_po::options_description desc (std::string(argv[0]).append( 46 | "\n\n" 47 | "Calculate principle components from large data files.\n" 48 | "Input data should be given as textfiles\n" 49 | "with whitespace separated columns or," 50 | " alternatively as GROMACS .xtc-files.\n" 51 | "\n" 52 | "options")); 53 | 54 | desc.add_options() 55 | ("help,h", "show this help") 56 | // input 57 | ("file,f", b_po::value(), 58 | "input (required): either whitespace-separated ASCII" 59 | " or GROMACS xtc-file.") 60 | ("cov-in,C", b_po::value()->default_value(""), 61 | "input (optional): file with already calculated covariance matrix") 62 | ("vec-in,V", b_po::value()->default_value(""), 63 | "input (optional): file with already computed eigenvectors") 64 | ("stats-in,S", b_po::value()->default_value(""), 65 | "input (optional): mean values, sigmas and boundary shifts" 66 | " (shifts only for periodic)." 67 | " Provide this, if you want to project new data onto a previously" 68 | " computed principal space." 69 | " If you do not define the stats of the previous run, means," 70 | " sigmas and shifts" 71 | " will be re-computed and the resulting projections" 72 | " will not be comparable to the previous ones.") 73 | // output 74 | ("proj,p", b_po::value()->default_value(""), 75 | "output (optional): file for projected data") 76 | ("cov,c", b_po::value()->default_value(""), 77 | "output (optional): file for covariance matrix") 78 | ("vec,v", b_po::value()->default_value(""), 79 | "output (optional): file for eigenvectors") 80 | ("stats,s", b_po::value()->default_value(""), 81 | "output (optional): mean values, sigmas and boundary shifts" 82 | " (shifts only for periodic)") 83 | ("val,l", b_po::value()->default_value(""), 84 | "output (optional): file for eigenvalues") 85 | // parameters 86 | ("norm,N", b_po::value(&use_correlation)->zero_tokens(), 87 | "if set, use correlation instead of covariance by" 88 | " normalizing input (default: false)") 89 | ("buf,b", b_po::value()->default_value(2), 90 | "max. allocatable RAM [Gb] (default: 2)") 91 | ("periodic,P", b_po::value(&periodic)->zero_tokens(), 92 | "compute covariance and PCA on a torus" 93 | " (i.e. for periodic data like dihedral angles)") 94 | ("dynamic-shift,D", b_po::value(&dynamic_shift)->zero_tokens(), 95 | "use dynamic shifting for periodic projection correction." 96 | " (default: fale, i.e. simply shift to region of lowest density)") 97 | ("verbose", b_po::value(&verbose)->zero_tokens(), 98 | "verbose mode (default: not set)") 99 | ("nthreads,n", b_po::value()->default_value(0), 100 | "number of OpenMP threads to use." 101 | " if set to zero, will use value of OMP_NUM_THREADS (default: 0)"); 102 | 103 | b_po::variables_map args; 104 | try { 105 | b_po::store(b_po::parse_command_line(argc, argv, desc), args); 106 | } catch (b_po::error e) { 107 | std::cerr << e.what() << std::endl; 108 | } 109 | b_po::notify(args); 110 | 111 | if (args.count("help")) { 112 | std::cerr << desc << std::endl; 113 | return 1; 114 | } 115 | 116 | //// 117 | 118 | try { 119 | if (args.count("file")) { 120 | auto check_file_given = [&args](std::string opt) { 121 | return (args[opt].as().compare("") != 0); 122 | }; 123 | bool projection_file_given = check_file_given("proj"); 124 | bool eigenvec_file_given = check_file_given("vec"); 125 | bool eigenval_file_given = check_file_given("val"); 126 | bool covmat_file_given = check_file_given("cov"); 127 | bool stats_file_given = check_file_given("stats"); 128 | bool input_covmat_file_given = check_file_given("cov-in"); 129 | bool input_eigenvec_file_given = check_file_given("vec-in"); 130 | bool input_stats_file_given = check_file_given("stats-in"); 131 | 132 | bool need_covmat = projection_file_given 133 | || eigenval_file_given 134 | || eigenvec_file_given 135 | || covmat_file_given; 136 | if ( need_covmat 137 | || stats_file_given) { 138 | 139 | std::size_t nthreads = args["nthreads"].as(); 140 | if (nthreads > 0) { 141 | // if not set explicitly (i.e. nthreads == 0), num_threads will 142 | // be initialized to value of environment variable OMP_NUM_THREADS 143 | omp_set_num_threads(nthreads); 144 | } 145 | std::string file_input = args["file"].as(); 146 | std::size_t mem_buf_size = FastPCA::gigabytes_to_bytes( 147 | args["buf"].as()); 148 | FastPCA::SymmetricMatrix cov; 149 | FastPCA::Matrix vecs; 150 | FastPCA::Matrix stats; 151 | //// input 152 | if (input_stats_file_given) { 153 | // -S ? 154 | verbose 155 | && std::cerr << "loading stats (shifts, means, sigmas) from file" 156 | << std::endl; 157 | FastPCA::DataFileReader 158 | fh_shifts(args["stats-in"].as()); 159 | stats = fh_shifts.next_block(); 160 | } else { 161 | verbose 162 | && std::cerr << "computing stats (means, sigmas, ...)" 163 | << std::endl; 164 | if (periodic) { 165 | verbose 166 | && dynamic_shift 167 | && std::cerr << "using dynamic shifting"; 168 | verbose 169 | && ( ! dynamic_shift) 170 | && std::cerr << "using static shifting"; 171 | verbose && std::cerr <<" for periodic barrier correction" 172 | << std::endl; 173 | stats = FastPCA::Periodic::stats(file_input 174 | , mem_buf_size 175 | , dynamic_shift); 176 | } else { 177 | stats = FastPCA::stats(file_input 178 | , mem_buf_size); 179 | } 180 | } 181 | if (input_eigenvec_file_given && input_covmat_file_given) { 182 | // -V and -C ? 183 | std::cerr << "error: Providing the covariance matrix and" 184 | " the eigenvectors does not make sense." 185 | << std::endl 186 | << " If we have the vectors, we do not need" 187 | " the covariance matrix," 188 | << std::endl 189 | << " therefore the options '-C' and '-V'" 190 | " are mutually exclusive." 191 | << std::endl; 192 | return EXIT_FAILURE; 193 | } else if (input_eigenvec_file_given) { 194 | // -V ? 195 | verbose && std::cerr << "loading eigenvectors from file" 196 | << std::endl; 197 | FastPCA::DataFileReader 198 | fh_vecs(args["vec-in"].as()); 199 | vecs = fh_vecs.next_block(); 200 | if (projection_file_given && (! input_stats_file_given)) { 201 | std::cerr << "warning: You specified a projection output and gave" 202 | << std::endl 203 | << " pre-computed eigenvectors." 204 | << std::endl 205 | << " Projection is, however," 206 | " centered to the mean." 207 | << std::endl 208 | << " Without stats (means, sigma," 209 | " [dihedral shifts])," 210 | << std::endl 211 | << " you will in general get" 212 | " non-comparable results" 213 | << std::endl 214 | << " to previous projections!" 215 | << std::endl; 216 | } 217 | } else { 218 | if (need_covmat) { 219 | if (input_covmat_file_given) { 220 | // -C ? 221 | verbose 222 | && std::cerr << "loading covariance matrix from file" 223 | << std::endl; 224 | FastPCA::DataFileReader 225 | cov_in(args["cov-in"].as()); 226 | cov = FastPCA::SymmetricMatrix( 227 | cov_in.next_block(cov_in.n_cols())); 228 | } else { 229 | if (periodic) { 230 | verbose 231 | && ( ! use_correlation) 232 | && std::cerr << "constructing covariance matrix" 233 | " for periodic data" 234 | << std::endl; 235 | verbose 236 | && use_correlation 237 | && std::cerr << "constructing correlation matrix" 238 | " for periodic data" 239 | << std::endl; 240 | cov = FastPCA::Periodic::covariance_matrix(file_input 241 | , mem_buf_size 242 | , use_correlation 243 | , stats); 244 | } else { 245 | verbose 246 | && ( ! use_correlation) 247 | && std::cerr << "constructing covariance matrix" 248 | << std::endl; 249 | verbose 250 | && use_correlation 251 | && std::cerr << "constructing correlation matrix" 252 | << std::endl; 253 | cov = FastPCA::covariance_matrix(file_input 254 | , mem_buf_size 255 | , use_correlation 256 | , stats); 257 | } 258 | } 259 | vecs = cov.eigenvectors(); 260 | } 261 | } 262 | //// output 263 | // -c ? 264 | if (covmat_file_given) { 265 | verbose 266 | && ( ! use_correlation) 267 | && std::cerr << "writing covariance matrix" 268 | << std::endl; 269 | verbose 270 | && use_correlation 271 | && std::cerr << "writing correlation matrix" 272 | << std::endl; 273 | std::string covmat_file = args["cov"].as(); 274 | FastPCA::DataFileWriter(covmat_file) 275 | .write(FastPCA::Matrix(cov)); 276 | } 277 | // -v ? 278 | if (eigenvec_file_given) { 279 | verbose 280 | && std::cerr << "solving eigensystem/writing eigenvectors matrix" 281 | << std::endl; 282 | std::string eigenvec_file = args["vec"].as(); 283 | FastPCA::DataFileWriter(eigenvec_file) 284 | .write(cov.eigenvectors()); 285 | } 286 | // -l ? 287 | if (eigenval_file_given) { 288 | verbose 289 | && std::cerr << "solving eigensystem/writing eigenvalues matrix" 290 | << std::endl; 291 | std::string eigenval_file = args["val"].as(); 292 | FastPCA::DataFileWriter(eigenval_file) 293 | .write(cov.eigenvalues()); 294 | } 295 | // -p ? 296 | if (projection_file_given) { 297 | std::string projection_file = args["proj"].as(); 298 | if (periodic) { 299 | verbose 300 | && std::cerr << "computing projections for periodic data" 301 | << std::endl; 302 | FastPCA::Periodic::calculate_projections(file_input 303 | , projection_file 304 | , vecs 305 | , mem_buf_size 306 | , use_correlation 307 | , stats); 308 | } else { 309 | verbose 310 | && std::cerr << "computing projections" 311 | << std::endl; 312 | FastPCA::calculate_projections(file_input 313 | , projection_file 314 | , vecs 315 | , mem_buf_size 316 | , use_correlation 317 | , stats); 318 | } 319 | } 320 | // -s ? 321 | if (stats_file_given) { 322 | verbose 323 | && std::cerr << "writing stats" 324 | << std::endl; 325 | FastPCA::DataFileWriter(args["stats"].as()) 326 | .write(stats); 327 | } 328 | } else { 329 | std::cerr << "please specify at least one output file!" 330 | << std::endl 331 | << desc 332 | << std::endl; 333 | return EXIT_FAILURE; 334 | } 335 | } else { 336 | std::cerr << desc << std::endl; 337 | return EXIT_FAILURE; 338 | } 339 | } catch (const std::exception& e) { 340 | std::cerr << e.what() << std::endl; 341 | std::cerr << desc << std::endl; 342 | return EXIT_FAILURE; 343 | } 344 | return EXIT_SUCCESS; 345 | } 346 | 347 | -------------------------------------------------------------------------------- /src/file_io.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Copyright (c) 2014, Florian Sittel (www.lettis.net) 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | 28 | #include 29 | #include 30 | 31 | #include "file_io.hpp" 32 | #include "covariance.hpp" 33 | 34 | namespace FastPCA { 35 | 36 | AsciiLineWriter::AsciiLineWriter(std::string filename) 37 | : _filename(filename) 38 | , _fh(filename) { 39 | } 40 | 41 | void 42 | AsciiLineWriter::write(std::vector v) { 43 | for (double val: v) { 44 | _fh << " " << val; 45 | } 46 | _fh << "\n"; 47 | } 48 | 49 | FileType 50 | filename_suffix(const std::string filename) { 51 | const int equal = 0; 52 | const std::size_t pos_dot = filename.rfind("."); 53 | if (pos_dot == filename.npos) { 54 | return UNKNOWN; 55 | } else { 56 | const std::string suffix = filename.substr(pos_dot+1); 57 | if (suffix.compare("xtc") == equal) { 58 | return XTC; 59 | } else if (suffix.compare("gro") == equal) { 60 | return GRO; 61 | } else if (suffix.compare("pdb") == equal) { 62 | return PDB; 63 | } else { 64 | return UNKNOWN; 65 | } 66 | } 67 | } 68 | 69 | void 70 | calculate_projections(const std::string file_in, 71 | const std::string file_out, 72 | Matrix eigenvecs, 73 | std::size_t mem_buf_size, 74 | bool use_correlation, 75 | Matrix stats) { 76 | // calculating the projection, we need twice the space 77 | // (original data + result) 78 | mem_buf_size /= 4; 79 | std::size_t n_variables = stats.n_rows(); 80 | std::vector means(n_variables); 81 | std::vector inverse_sigmas(n_variables); 82 | for (std::size_t i=0; i < n_variables; ++i) { 83 | means[i] = stats(i,0); 84 | inverse_sigmas[i] = 1.0 / stats(i,1); 85 | } 86 | bool append_to_file = false; 87 | DataFileReader fh_file_in(file_in, mem_buf_size); 88 | DataFileWriter fh_file_out(file_out); 89 | read_blockwise(fh_file_in, [&](Matrix& m) { 90 | FastPCA::shift_matrix_columns_inplace(m, means); 91 | if (use_correlation) { 92 | FastPCA::scale_matrix_columns_inplace(m, inverse_sigmas); 93 | } 94 | fh_file_out.write(std::move(m*eigenvecs), append_to_file); 95 | append_to_file = true; 96 | }); 97 | } 98 | 99 | void 100 | read_blockwise(DataFileReader& ifile 101 | , std::function&)> acc) { 102 | Matrix m = std::move(ifile.next_block()); 103 | while (m.n_rows() > 0) { 104 | acc(m); 105 | m = std::move(ifile.next_block()); 106 | } 107 | } 108 | 109 | namespace Periodic { 110 | void 111 | calculate_projections(const std::string file_in, 112 | const std::string file_out, 113 | Matrix eigenvecs, 114 | std::size_t mem_buf_size, 115 | bool use_correlation, 116 | Matrix stats) { 117 | mem_buf_size /= 4; 118 | std::size_t n_variables = stats.n_rows(); 119 | std::vector means(n_variables); 120 | std::vector inverse_sigmas(n_variables); 121 | std::vector shifts(n_variables); 122 | for (std::size_t i=0; i < n_variables; ++i) { 123 | means[i] = stats(i,0); 124 | inverse_sigmas[i] = 1.0 / stats(i,1); 125 | shifts[i] = stats(i,2); 126 | } 127 | // projections 128 | bool append_to_file = false; 129 | DataFileReader fh_file_in(file_in, mem_buf_size); 130 | DataFileWriter fh_file_out(file_out); 131 | read_blockwise(fh_file_in, [&](Matrix& m) { 132 | // convert degrees to radians 133 | FastPCA::deg2rad_inplace(m); 134 | FastPCA::Periodic::shift_matrix_columns_inplace(m, shifts); 135 | if (use_correlation) { 136 | // scale data by sigmas for correlated projections 137 | FastPCA::scale_matrix_columns_inplace(m, inverse_sigmas); 138 | } 139 | // output 140 | fh_file_out.write(m*eigenvecs, append_to_file); 141 | append_to_file = true; 142 | }); 143 | } 144 | } // end namespace FastPCA::Periodic 145 | } // end namespace FastPCA 146 | 147 | -------------------------------------------------------------------------------- /src/file_io.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | /* 3 | Copyright (c) 2014, Florian Sittel (www.lettis.net) 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "matrix.hpp" 33 | #include "util.hpp" 34 | 35 | #include "AsciiParser.hpp" 36 | 37 | extern "C" { 38 | // use xdrfile library to read/write xtc and trr files from gromacs 39 | #include "xdrfile/xdrfile.h" 40 | #include "xdrfile/xdrfile_xtc.h" 41 | #include "xdrfile/xdrfile_trr.h" 42 | } 43 | 44 | 45 | namespace FastPCA { 46 | namespace { 47 | namespace UseCSV { 48 | template 49 | Matrix read_chunk(std::ifstream& fh, std::size_t n_cols, std::size_t n_lines); 50 | 51 | template 52 | void write_vector(std::ofstream& fh, std::vector v, bool in_line=false); 53 | 54 | template 55 | void write_vector(std::string file_out, std::vector v, bool append); 56 | 57 | template 58 | void write_matrix(std::string file_out, Matrix m, bool append); 59 | } // end namespace UseCSV 60 | 61 | namespace UseXTC { 62 | class RvecArray { 63 | public: 64 | RvecArray(std::size_t n_atoms); 65 | ~RvecArray(); 66 | 67 | std::size_t n_atoms; 68 | rvec* values; 69 | }; 70 | 71 | std::size_t n_atoms(std::string file_in); 72 | 73 | template 74 | Matrix read_chunk(std::shared_ptr file, std::size_t n_cols, std::size_t n_lines); 75 | 76 | template 77 | void write_vector(std::string file_out, std::vector v, bool append); 78 | 79 | template 80 | void write_matrix(std::string file_out, Matrix m, bool append); 81 | } // end namespace UseXTC 82 | } // end local namespace 83 | 84 | 85 | enum FileType { 86 | UNKNOWN, XTC, GRO, PDB 87 | }; 88 | 89 | template 90 | class DataFileReader { 91 | public: 92 | DataFileReader(std::string filename); 93 | DataFileReader(std::string filename, std::size_t buf_size_bytes); 94 | 95 | Matrix next_block(std::size_t n_rows=0); 96 | std::size_t n_cols(); 97 | 98 | bool eof() const; 99 | 100 | private: 101 | std::string _filename; 102 | std::size_t _buf_size_bytes; 103 | FileType _ftype; 104 | std::size_t _n_cols; 105 | bool _eof; 106 | LTS::AsciiParser _parser; 107 | std::shared_ptr _fh_xtc; 108 | }; 109 | 110 | template 111 | class DataFileWriter { 112 | public: 113 | DataFileWriter(std::string filename); 114 | 115 | void write(std::vector v, bool append=false); 116 | void write(Matrix m, bool append=false); 117 | 118 | private: 119 | std::string _filename; 120 | FileType _ftype; 121 | }; 122 | 123 | class AsciiLineWriter { 124 | public: 125 | AsciiLineWriter(std::string filename); 126 | void write(std::vector v); 127 | private: 128 | std::string _filename; 129 | std::ofstream _fh; 130 | }; 131 | 132 | 133 | FileType filename_suffix(const std::string filename); 134 | 135 | void calculate_projections(const std::string file_in, 136 | const std::string file_out, 137 | Matrix eigenvecs, 138 | std::size_t mem_buf_size, 139 | bool use_correlation, 140 | Matrix stats); 141 | 142 | /** 143 | * read input file blockwise and pass reference of current matrix 144 | * to accumulator function. 145 | */ 146 | void 147 | read_blockwise(DataFileReader& ifile 148 | , std::function&)> acc); 149 | 150 | namespace Periodic { 151 | void calculate_projections(const std::string file_in, 152 | const std::string file_out, 153 | Matrix eigenvecs, 154 | std::size_t mem_buf_size, 155 | bool use_correlation, 156 | Matrix stats); 157 | } // end namespace FastPCA::Periodic 158 | } // end namespace FastPCA 159 | 160 | // load template implementations 161 | #include "file_io.hxx" 162 | 163 | -------------------------------------------------------------------------------- /src/file_io.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014, Florian Sittel (www.lettis.net) 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #include "file_io.hpp" 27 | 28 | #include 29 | 30 | 31 | namespace FastPCA { 32 | namespace { // begin local namespace 33 | namespace UseCSV { 34 | template 35 | Matrix read_chunk(LTS::AsciiParser& parser, std::size_t n_lines) { 36 | std::size_t n_read_lines = n_lines; 37 | std::vector m = std::move(parser.next_n_lines_continuous(n_read_lines, 38 | LTS::AsciiParser::COL_MAJOR)); 39 | return Matrix(m, n_read_lines, parser.n_cols()); 40 | } 41 | 42 | template 43 | void write_vector(std::ofstream& fh, std::vector v, bool in_line) { 44 | if (fh.good()) { 45 | //int n_digits = std::numeric_limits::digits10; 46 | int n_digits = 6; 47 | fh.precision(n_digits); 48 | fh.setf(std::ios::scientific); 49 | for (auto it=v.begin(); it != v.end(); ++it) { 50 | fh.width(n_digits+10); // 8 extra chars for spacing, +/- and scientific formatting 51 | if (in_line) { 52 | fh << " "; 53 | } 54 | fh << (double) *it; 55 | if ( ! in_line) { 56 | fh << std::endl; 57 | } 58 | } 59 | if (in_line) { 60 | fh << std::endl; 61 | } 62 | } else { 63 | throw FileNotFoundError(); 64 | } 65 | } 66 | 67 | template 68 | void write_vector(std::string file_out, std::vector v, bool append) { 69 | std::ofstream fh; 70 | if (append) { 71 | fh.open(file_out, std::ios::out | std::ios::app); 72 | } else { 73 | fh.open(file_out, std::ios::out); 74 | } 75 | write_vector(fh, v); 76 | } 77 | 78 | template 79 | void write_matrix(std::string file_out, Matrix m, bool append) { 80 | std::ofstream fh; 81 | if (append) { 82 | fh.open(file_out, std::ios::out | std::ios::app); 83 | } else { 84 | fh.open(file_out, std::ios::out); 85 | } 86 | if (fh.is_open()) { 87 | int n_digits = 6; 88 | fh.precision(n_digits); 89 | fh.setf(std::ios::scientific); 90 | for (std::size_t i=0; i < m.n_rows(); ++i) { 91 | for (std::size_t j=0; j < m.n_cols(); ++j) { 92 | fh.width(n_digits+8); // 8 extra chars for spacing, +/- and scientific formatting 93 | fh << m(i, j); 94 | } 95 | fh << std::endl; 96 | } 97 | } else { 98 | throw FileNotFoundError(); 99 | } 100 | } 101 | } // end namespace UseCSV 102 | 103 | namespace UseXTC { 104 | RvecArray::RvecArray(std::size_t n_atoms) 105 | : n_atoms(n_atoms) { 106 | if (this->n_atoms > 0) { 107 | this->values = static_cast(calloc(this->n_atoms, sizeof(this->values[0]))); 108 | } 109 | } 110 | 111 | RvecArray::~RvecArray() { 112 | free(this->values); 113 | } 114 | 115 | std::size_t n_atoms(std::string file_in) { 116 | int n_atoms=0; 117 | read_xtc_natoms(file_in.c_str(), &n_atoms); 118 | return (std::size_t) n_atoms; 119 | } 120 | 121 | template 122 | Matrix read_chunk(std::shared_ptr file, std::size_t n_cols, std::size_t n_lines) { 123 | int n_fake_atoms = n_cols/3; 124 | int return_code = 0; 125 | int n_step = 0; 126 | float time_step = 1.0; 127 | matrix box_vec; 128 | RvecArray coords(n_fake_atoms); 129 | float prec = 1000.0; 130 | Matrix m(n_lines, n_cols); 131 | 132 | std::size_t n_lines_0 = n_lines; 133 | for (; n_lines > 0; --n_lines) { 134 | // read next frame 135 | return_code = read_xtc(file.get(), n_fake_atoms, &n_step, 136 | &time_step, box_vec, coords.values, &prec); 137 | if (return_code == exdrOK) { 138 | // add next frame to input matrix 139 | std::vector r(n_cols); 140 | for (int i = 0; i < n_fake_atoms; ++i) { 141 | for (int j = 0; j < 3; ++j) { 142 | m(n_lines_0-n_lines, i*3+j) = (T) coords.values[i][j]; 143 | } 144 | } 145 | } else if (return_code == exdrENDOFFILE) { 146 | //EOF: if no line has been read, just return an empty matrix. 147 | // (i.e. return 'm' as initialized) 148 | break; 149 | } else if (return_code == exdrFILENOTFOUND) { 150 | throw std::runtime_error("xtc file not found"); 151 | break; 152 | } else { 153 | throw std::runtime_error("strange error while reading xtc file"); 154 | break; 155 | } 156 | } 157 | if (n_lines != 0) { 158 | // resize m if needed 159 | m = std::move(m.limited_rows(n_lines_0-n_lines)); 160 | } 161 | return m; 162 | } 163 | 164 | template 165 | void write_vector(std::string file_out, std::vector v, bool append) { 166 | // write vector into column, keeping two additional columns empty. 167 | // this is needed since xtc files only can store cartesian coordinates, 168 | // i.e. packets of three numbers. 169 | // vectors will be written in first 'x' field with values in different 170 | // rows (aka time-frames) to get it column-oriented as first column, 171 | // if xtc-data is dumped (e.g. with gmxdump). 172 | Matrix m(v.size(), 3); 173 | for (std::size_t i=0; i < v.size(); ++i) { 174 | m(i,0) = v[i]; 175 | m(i,1) = 0.0; 176 | m(i,2) = 0.0; 177 | } 178 | write_matrix(file_out, m, append); 179 | } 180 | 181 | template 182 | void write_matrix(std::string file_out, Matrix m, bool append) { 183 | std::shared_ptr file(xdrfile_open(file_out.c_str(), append ? "a" : "w"), 184 | // deleter function called when pointer goes out of scope 185 | [=](XDRFILE* f) { 186 | xdrfile_close(f); 187 | }); 188 | // faked box matrix for xtc-file 189 | float fake_box_matrix[3][3] = {{0,0,0}, {0,0,0}, {0,0,0}}; 190 | // xtc-files are only readable/writable in 3D cartesian coordinates 191 | // for atoms. if the number of matrix columns is not divisable by three, 192 | // add zero-valued columns to fill. 193 | int n_fake_atoms = m.n_cols() / 3; 194 | if (m.n_cols() % 3 == 0) { 195 | ++n_fake_atoms; 196 | } 197 | std::size_t n_fake_cols = 3*n_fake_atoms; 198 | std::size_t n_cols = m.n_cols(); 199 | RvecArray buf(3*n_fake_atoms); 200 | for (std::size_t r=0; r < m.n_rows(); ++r) { 201 | for (std::size_t c=0; c < n_fake_cols; ++c) { 202 | if (c < n_cols) { 203 | buf.values[c/3][c%3] = m(r,c); 204 | } else { 205 | buf.values[c/3][c%3] = 0.0; 206 | } 207 | } 208 | write_xtc(file.get(), n_fake_atoms, r, 1.0, fake_box_matrix, buf.values, 1000.0); 209 | } 210 | } 211 | } // end UseXTC namespace 212 | } // end local namespace 213 | 214 | 215 | template 216 | DataFileReader::DataFileReader(std::string filename, std::size_t buf_size_bytes) 217 | : _filename(filename), 218 | _buf_size_bytes(buf_size_bytes), 219 | _n_cols(0), 220 | _eof(false) { 221 | this->_ftype = filename_suffix(filename); 222 | if (this->_ftype == XTC) { 223 | // use XTC file 224 | this->_fh_xtc = std::shared_ptr(xdrfile_open(filename.c_str(), "r"), 225 | // deleter function called when pointer goes out of scope 226 | [](XDRFILE* f) { 227 | xdrfile_close(f); 228 | }); 229 | this->_n_cols = 3*UseXTC::n_atoms(filename); 230 | } else { 231 | this->_parser.open(filename); 232 | this->_n_cols = this->_parser.n_cols(); 233 | } 234 | } 235 | 236 | template 237 | DataFileReader::DataFileReader(std::string filename) 238 | // zero byte buffer: read everything at once 239 | : DataFileReader(filename, 0) { 240 | } 241 | 242 | template 243 | Matrix DataFileReader::next_block(std::size_t n_rows) { 244 | std::size_t n_possible_rows; 245 | if (n_rows == 0){ 246 | n_possible_rows = this->_buf_size_bytes / (sizeof(T) * this->_n_cols); 247 | } else { 248 | n_possible_rows = n_rows; 249 | } 250 | if (this->_ftype == XTC) { 251 | if (this->_n_cols == 0) { 252 | throw FileFormatError(); 253 | } 254 | Matrix m = UseXTC::read_chunk(this->_fh_xtc, this->_n_cols, n_possible_rows); 255 | if (m.n_rows() == 0) { 256 | this->_eof = true; 257 | return Matrix(); 258 | } else { 259 | return m; 260 | } 261 | } else { 262 | // assume ASCII file 263 | if (this->_parser.eof()) { 264 | this->_eof = true; 265 | return Matrix(); 266 | } else { 267 | if (this->_n_cols == 0) { 268 | throw FileFormatError(); 269 | } 270 | return UseCSV::read_chunk(this->_parser, n_possible_rows); 271 | } 272 | } 273 | } 274 | 275 | template 276 | std::size_t DataFileReader::n_cols() { 277 | return this->_n_cols; 278 | } 279 | 280 | template 281 | bool DataFileReader::eof() const { 282 | return this->_eof; 283 | } 284 | 285 | //// 286 | 287 | template 288 | DataFileWriter::DataFileWriter(std::string filename) 289 | : _filename(filename) { 290 | this->_ftype = filename_suffix(filename); 291 | } 292 | 293 | template 294 | void DataFileWriter::write(std::vector v, bool append) { 295 | switch (this->_ftype) { 296 | case XTC: 297 | UseXTC::write_vector(this->_filename, v, append); 298 | break; 299 | case UNKNOWN: 300 | UseCSV::write_vector(this->_filename, v, append); 301 | break; 302 | default: 303 | throw std::runtime_error("unknown file type to write vector"); 304 | } 305 | } 306 | 307 | template 308 | void DataFileWriter::write(Matrix m, bool append) { 309 | switch (this->_ftype) { 310 | case XTC: 311 | UseXTC::write_matrix(this->_filename, m, append); 312 | break; 313 | case UNKNOWN: 314 | UseCSV::write_matrix(this->_filename, m, append); 315 | break; 316 | default: 317 | throw std::runtime_error("unknown file type given to write matrix"); 318 | } 319 | } 320 | 321 | } // end namespace FastPCA 322 | 323 | -------------------------------------------------------------------------------- /src/matrix.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Copyright (c) 2014, Florian Sittel (www.lettis.net) 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | 28 | #include "matrix.hpp" 29 | 30 | namespace FastPCA { 31 | 32 | namespace { 33 | 34 | extern "C" { 35 | // LAPACK SSYEV and DSYEV prototypes 36 | void ssyev_(char* jobz, char* uplo, int* n, 37 | float* a, int* lda, float* w, 38 | float* work, int* lwork, int*info); 39 | void dsyev_(char* jobz, char* uplo, int* n, 40 | double* a, int* lda, double* w, 41 | double* work, int* lwork, int*info); 42 | } 43 | 44 | } // end local namespace 45 | 46 | template <> 47 | void SymmetricMatrix::_solve_eigensystem() { 48 | SyevData dat; 49 | // prepare with lwork=-1: probe for optimal workspace size 50 | _prepareSyevData(dat, (*this), -1); 51 | ssyev_(&dat.jobz, &dat.uplo, &dat.n, &dat.a[0], &dat.lda, &dat.w[0], &dat.work[0], &dat.lwork, &dat.info); 52 | // run syev 53 | _prepareSyevData(dat, (*this), dat.work[0]); 54 | ssyev_(&dat.jobz, &dat.uplo, &dat.n, &dat.a[0], &dat.lda, &dat.w[0], &dat.work[0], &dat.lwork, &dat.info); 55 | // extract data 56 | _eigenvalues = _extractEigenvalues(dat); 57 | _eigenvectors = _extractEigenvectors(dat); 58 | // enforce ordering from highest to lowest eigenvalue; 59 | _enforce_eigval_order(); 60 | } 61 | 62 | template <> 63 | void SymmetricMatrix::_solve_eigensystem() { 64 | SyevData dat; 65 | // prepare with lwork=-1: probe for optimal workspace size 66 | _prepareSyevData(dat, (*this), -1); 67 | dsyev_(&dat.jobz, &dat.uplo, &dat.n, &dat.a[0], &dat.lda, &dat.w[0], &dat.work[0], &dat.lwork, &dat.info); 68 | // run syev 69 | _prepareSyevData(dat, (*this), dat.work[0]); 70 | dsyev_(&dat.jobz, &dat.uplo, &dat.n, &dat.a[0], &dat.lda, &dat.w[0], &dat.work[0], &dat.lwork, &dat.info); 71 | // extract data 72 | _eigenvalues = _extractEigenvalues(dat); 73 | _eigenvectors = _extractEigenvectors(dat); 74 | _enforce_eigval_order(); 75 | } 76 | 77 | } // end namespace FastPCA 78 | 79 | -------------------------------------------------------------------------------- /src/matrix.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | /* 3 | Copyright (c) 2014, Florian Sittel (www.lettis.net) 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | #include 27 | #include 28 | 29 | namespace FastPCA { 30 | 31 | template class SymmetricMatrix; 32 | 33 | template 34 | class Matrix { 35 | public: 36 | Matrix(); 37 | Matrix(Matrix&& m); 38 | Matrix(const Matrix& m); 39 | Matrix(std::size_t n_rows, std::size_t n_cols); 40 | // data must be given in column-major order 41 | Matrix(std::vector data, std::size_t n_rows, std::size_t n_cols); 42 | Matrix(const SymmetricMatrix& sym); 43 | 44 | T& operator()(const std::size_t i, const std::size_t j); 45 | const T& operator()(const std::size_t i, const std::size_t j) const; 46 | 47 | Matrix& operator=(const Matrix& m); 48 | Matrix& operator=(Matrix&& m); 49 | 50 | std::size_t n_rows() const; 51 | std::size_t n_cols() const; 52 | 53 | Matrix operator*(const Matrix& other); 54 | Matrix limited_rows(std::size_t n_rows) const; 55 | 56 | private: 57 | std::vector _m; 58 | std::size_t _n_rows; 59 | std::size_t _n_cols; 60 | }; 61 | 62 | template 63 | class SymmetricMatrix { 64 | public: 65 | SymmetricMatrix(); 66 | SymmetricMatrix(std::size_t n); 67 | SymmetricMatrix(const Matrix& m); 68 | 69 | T& operator()(const std::size_t i, const std::size_t j); 70 | const T& operator()(const std::size_t i, const std::size_t j) const; 71 | std::size_t n_rows() const; 72 | std::size_t n_cols() const; 73 | 74 | std::vector eigenvalues(); 75 | Matrix eigenvectors(); 76 | 77 | template 78 | friend SymmetricMatrix operator+(const SymmetricMatrix& s1, const SymmetricMatrix& s2); 79 | 80 | template 81 | friend std::ostream& operator<< (std::ostream& out, SymmetricMatrix& s); 82 | 83 | private: 84 | std::vector _m; 85 | std::size_t _n_rows; 86 | 87 | bool _eigensystem_is_solved; 88 | void _solve_eigensystem(); 89 | void _enforce_eigval_order(); 90 | 91 | std::vector _eigenvalues; 92 | Matrix _eigenvectors; 93 | }; 94 | 95 | 96 | namespace { 97 | template 98 | struct SyevData { 99 | // compute eigenvectors and eigenvalues ('V') 100 | // or eigenvalues only ('N') 101 | char jobz; 102 | // store symmetric matrix in upper (='U') or lower (='L') triangle. 103 | // beware: FORTRAN uses column-major matrix indices, 104 | // thus FORTRAN-matrices are transposed! 105 | char uplo; 106 | // matrix order 107 | int n; 108 | // array for input data; later contains eigenvectors 109 | std::vector a; 110 | // leading dimension 111 | int lda; 112 | // array for eigenvalues (in ascending order) 113 | std::vector w; 114 | // size of work array 115 | int lwork; 116 | // array for temporary data 117 | std::vector work; 118 | // == 0: success, < 0: |info|-th argument had illegal value, > 0 convergence failure 119 | int info; 120 | }; 121 | 122 | // set lwork = -1 to query for optimal workspace size. 123 | // then re-prepare with dat.lwork = dat.work[0] 124 | template 125 | void _prepareSyevData(SyevData& dat, SymmetricMatrix& m, int lwork); 126 | 127 | template 128 | Matrix _extractEigenvectors(const SyevData& dat); 129 | 130 | template 131 | std::vector _extractEigenvalues(const SyevData& dat); 132 | } // end local namespace 133 | 134 | 135 | 136 | template 137 | void 138 | copy_column(const Matrix& m_from, std::size_t i_col_from, Matrix& m_to, std::size_t i_col_to); 139 | 140 | } // end namespace FastPCA 141 | 142 | // template implementations 143 | #include "matrix.hxx" 144 | 145 | -------------------------------------------------------------------------------- /src/matrix.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014, Florian Sittel (www.lettis.net) 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | #include "errors.hpp" 26 | #include "matrix.hpp" 27 | #include "util.hpp" 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | // disable assertions 35 | //#define NDEBUG 36 | #include 37 | 38 | namespace FastPCA { 39 | 40 | namespace { 41 | 42 | template 43 | void _prepareSyevData(SyevData& dat, SymmetricMatrix& m, int lwork) { 44 | // compute eigenvectors and eigenvalues 45 | dat.jobz = 'V'; 46 | // store symmetric matrix in upper triangle. 47 | // our data will be written to lower triangle, but FORTRAN uses 48 | // column-major matrix indices, thus FORTRAN-matrices are transposed! 49 | dat.uplo = 'U'; 50 | // matrix order 51 | dat.n = m.n_rows(); 52 | // leading dimension; here equal to matrix order 53 | dat.lda = dat.n; 54 | // array for eigenvalues (in ascending order) 55 | dat.w.resize(dat.n, (T) 0); 56 | // size of work array 57 | dat.lwork = lwork; 58 | if (lwork > 0) { 59 | // array for temporary data 60 | dat.work.resize(lwork); 61 | } else { 62 | dat.work.resize(1); 63 | } 64 | // == 0: success, < 0: |info|-th argument had illegal value, > 0 convergence failure 65 | dat.info = 0; 66 | // array for input data; later contains eigenvectors 67 | dat.a.resize(dat.n*dat.n, 0); 68 | for (std::size_t i=0; i < dat.n; ++i) { 69 | for (std::size_t j=0; j < dat.n; ++j) { 70 | if (j > i) { 71 | dat.a[i*dat.n+j] = 0; 72 | } else { 73 | dat.a[i*dat.n+j] = m(i, j); 74 | } 75 | } 76 | } 77 | } 78 | 79 | template 80 | Matrix _extractEigenvectors(const SyevData& dat) { 81 | // the eigenvectors from lapack are row-oriented 82 | // and (mostly!) ordered from lowest to highest eigenvalue. 83 | // we want a matrix with column-oriented eigenvectors 84 | // ordered from highest to lowest eigenvalue. 85 | Matrix v(dat.n, dat.n); 86 | for (std::size_t i=0; i < dat.n; ++i) { 87 | for (std::size_t j=0; j < dat.n; ++j) { 88 | v(i,j) = dat.a[(dat.n-j-1)*dat.n+i]; 89 | } 90 | } 91 | return v; 92 | } 93 | 94 | template 95 | std::vector _extractEigenvalues(const SyevData& dat) { 96 | std::vector eigenvals = dat.w; 97 | std::reverse(eigenvals.begin(), eigenvals.end()); 98 | return eigenvals; 99 | } 100 | 101 | } // end local namespace 102 | 103 | // Matrix 104 | template 105 | Matrix::Matrix() 106 | : _n_rows(0), 107 | _n_cols(0) { 108 | } 109 | 110 | template 111 | Matrix::Matrix(const SymmetricMatrix& sym) { 112 | this->_n_rows = sym.n_rows(); 113 | this->_n_cols = sym.n_rows(); 114 | this->_m = std::vector(this->_n_cols*this->_n_rows); 115 | for (std::size_t i=0; i < this->_n_rows; ++i) { 116 | for (std::size_t j=0; j <= i ; ++j) { 117 | (*this)(i,j) = sym(i,j); 118 | if (i != j) { 119 | (*this)(j,i) = sym(i,j); 120 | } 121 | } 122 | } 123 | } 124 | 125 | 126 | template 127 | Matrix::Matrix(const Matrix& other) { 128 | this->_n_rows = other._n_rows; 129 | this->_n_cols = other._n_cols; 130 | this->_m = other._m; 131 | } 132 | 133 | 134 | template 135 | Matrix::Matrix(Matrix&& m) 136 | : _n_rows(0), 137 | _n_cols(0) { 138 | *this = std::move(m); 139 | } 140 | 141 | template 142 | Matrix& Matrix::operator=(Matrix&& m) { 143 | // clear existing data 144 | this->_m.clear(); 145 | // copy rhs values 146 | this->_m = m._m; 147 | this->_n_rows = m._n_rows; 148 | this->_n_cols = m._n_cols; 149 | // clear rhs object 150 | m._m.clear(); 151 | m._n_rows = 0; 152 | m._n_cols = 0; 153 | return *this; 154 | } 155 | 156 | template 157 | Matrix& Matrix::operator=(const Matrix& m) { 158 | this->_m = m._m; 159 | this->_n_rows = m._n_rows; 160 | this->_n_cols = m._n_cols; 161 | return *this; 162 | } 163 | 164 | template 165 | Matrix::Matrix(std::size_t n_rows, std::size_t n_cols) 166 | : _n_rows(n_rows), 167 | _n_cols(n_cols){ 168 | this->_m = std::vector(n_cols*n_rows); 169 | } 170 | 171 | template 172 | Matrix::Matrix(std::vector data, std::size_t n_rows, std::size_t n_cols) 173 | : _n_rows(n_rows), 174 | _n_cols(n_cols), 175 | _m(data) { 176 | } 177 | 178 | template 179 | inline T& Matrix::operator()(const std::size_t i, const std::size_t j) { 180 | assert(i < this->_n_rows); 181 | assert(j < this->_n_cols); 182 | // addressing in column-major order for fast column traversal 183 | return this->_m[j*this->_n_rows+i]; 184 | } 185 | 186 | template 187 | inline const T& Matrix::operator()(const std::size_t i, const std::size_t j) const { 188 | assert(i < this->_n_rows); 189 | assert(j < this->_n_cols); 190 | // addressing in column-major order for fast column traversal 191 | return this->_m[j*this->_n_rows+i]; 192 | } 193 | 194 | 195 | template 196 | inline std::size_t Matrix::n_rows() const { 197 | return this->_n_rows; 198 | } 199 | 200 | template 201 | inline std::size_t Matrix::n_cols() const { 202 | return this->_n_cols; 203 | } 204 | 205 | template 206 | Matrix Matrix::operator*(const Matrix& other) { 207 | if (other._n_rows != this->_n_cols) { 208 | throw MatrixNotAlignedError(); 209 | } else { 210 | Matrix c(this->_n_rows, other._n_cols); 211 | std::size_t i, j, k; 212 | #pragma omp parallel for collapse(2) default(none) private(i,j,k) shared(c,other) 213 | for (i=0; i < this->_n_rows; ++i) { 214 | for (j=0; j < this->_n_cols; ++j) { 215 | for (k=0; k < this->_n_cols; ++k) { 216 | c(i,j) += (*this)(i,k) * other(k,j); 217 | } 218 | } 219 | } 220 | return c; 221 | } 222 | } 223 | 224 | template 225 | Matrix Matrix::limited_rows(std::size_t n_rows) const { 226 | Matrix m(n_rows, this->_n_cols); 227 | for (std::size_t i=0; i < n_rows; ++i) { 228 | for (std::size_t j=0; j < this->_n_cols; ++j) { 229 | m(i,j) = (*this)(i,j); 230 | } 231 | } 232 | return m; 233 | } 234 | 235 | // SymmetricMatrix 236 | 237 | template 238 | SymmetricMatrix::SymmetricMatrix() 239 | : _n_rows(0), 240 | _eigensystem_is_solved(false) { 241 | } 242 | 243 | template 244 | SymmetricMatrix::SymmetricMatrix(std::size_t n) 245 | : _n_rows(n), 246 | _eigensystem_is_solved(false) { 247 | // allocate memory for n * (n+1) / 2 elements of T (lower triangle of matrix) 248 | this->_m = std::vector(n*(n+1)/2); 249 | } 250 | 251 | template 252 | SymmetricMatrix::SymmetricMatrix(const Matrix& m) 253 | : _n_rows(m.n_cols()), 254 | _eigensystem_is_solved(false) { 255 | std::size_t n = this->_n_rows; 256 | this->_m = std::vector(n*(n+1)/2); 257 | for (std::size_t i=0; i < this->_n_rows; ++i) { 258 | for (std::size_t j=0; j <= i; ++j) { 259 | (*this)(i,j) = m(i,j); 260 | } 261 | } 262 | } 263 | 264 | template 265 | T& SymmetricMatrix::operator()(std::size_t i, std::size_t j) { 266 | // store data as lower triangular matrix; addressing begins in top-left corner. 267 | // * 268 | // * * 269 | // * * * 270 | // * * * * 271 | // [...] 272 | if (j > i) { 273 | std::swap(i, j); 274 | } 275 | assert(i < this->_n_rows); 276 | // this is needed, since returning a reference may lead to change in data 277 | this->_eigensystem_is_solved = false; 278 | return this->_m[i*(i+1)/2 + j]; 279 | } 280 | 281 | template 282 | const T& SymmetricMatrix::operator()(std::size_t i, std::size_t j) const { 283 | // store data as lower triangular matrix; addressing begins in top-left corner. 284 | // * 285 | // * * 286 | // * * * 287 | // * * * * 288 | // [...] 289 | if (j > i) { 290 | std::swap(i, j); 291 | } 292 | assert(i < this->_n_rows); 293 | // this is needed, since returning a reference may lead to change in data 294 | return this->_m[i*(i+1)/2 + j]; 295 | } 296 | 297 | template 298 | std::size_t SymmetricMatrix::n_rows() const { 299 | return this->_n_rows; 300 | } 301 | 302 | template 303 | std::size_t SymmetricMatrix::n_cols() const { 304 | return this->_n_rows; 305 | } 306 | 307 | template 308 | std::vector SymmetricMatrix::eigenvalues() { 309 | if ( ! this->_eigensystem_is_solved) { 310 | this->_solve_eigensystem(); 311 | } 312 | return this->_eigenvalues; 313 | } 314 | 315 | template 316 | Matrix SymmetricMatrix::eigenvectors() { 317 | if ( ! this->_eigensystem_is_solved) { 318 | this->_solve_eigensystem(); 319 | } 320 | return this->_eigenvectors; 321 | } 322 | 323 | template 324 | void 325 | SymmetricMatrix::_enforce_eigval_order() { 326 | std::vector ordered_indeces = FastPCA::sorted_index(_eigenvalues, true); 327 | std::vector buf_eigvals = _eigenvalues; 328 | Matrix buf_eigvectors(_eigenvectors.n_rows(), _eigenvectors.n_cols()); 329 | for (std::size_t i=0; i < _eigenvalues.size(); ++i) { 330 | _eigenvalues[i] = buf_eigvals[ordered_indeces[i]]; 331 | FastPCA::copy_column(_eigenvectors, i, buf_eigvectors, ordered_indeces[i]); 332 | } 333 | _eigenvectors = buf_eigvectors; 334 | } 335 | 336 | 337 | template 338 | SymmetricMatrix operator+(const SymmetricMatrix& s1, const SymmetricMatrix& s2) { 339 | assert(s1.n_rows() == s2.n_rows()); 340 | std::size_t nr = s1.n_rows(); 341 | SymmetricMatrix r(nr); 342 | std::transform(s1._m.begin(), s1._m.end(), s2._m.begin(), r._m.begin(), std::plus()); 343 | return r; 344 | } 345 | 346 | template 347 | std::ostream& operator<< (std::ostream& out, SymmetricMatrix& s) { 348 | const int precision = 10; 349 | for (std::size_t r = 0; r < s.n_rows(); ++r) { 350 | for (std::size_t c = 0; c < s.n_cols(); ++c) { 351 | out << std::setw(precision+4) << std::setprecision(precision) << std::fixed << s(r,c); 352 | } 353 | if (r != s.n_rows()-1) { 354 | out << std::endl; 355 | } 356 | } 357 | return out; 358 | } 359 | 360 | 361 | 362 | template 363 | void 364 | copy_column(const Matrix& m_from, std::size_t i_col_from, Matrix& m_to, std::size_t i_col_to) { 365 | for (std::size_t i=0; i < m_from.n_rows(); ++i) { 366 | m_to(i, i_col_to) = m_from(i, i_col_from); 367 | } 368 | } 369 | 370 | } // end namespace FastPCA 371 | 372 | -------------------------------------------------------------------------------- /src/util.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Copyright (c) 2014, Florian Sittel (www.lettis.net) 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | 28 | #include "util.hpp" 29 | #include "file_io.hpp" 30 | 31 | #include 32 | #include 33 | 34 | namespace FastPCA { 35 | 36 | namespace { 37 | std::tuple> 38 | _means(const std::string filename 39 | , const std::size_t max_chunk_size 40 | , std::vector shifts = {}) { 41 | DataFileReader input_file(filename, max_chunk_size); 42 | std::size_t n_cols = input_file.n_cols(); 43 | std::size_t n_rows = 0; 44 | std::vector means(n_cols); 45 | Matrix m = std::move(input_file.next_block()); 46 | while (m.n_rows() > 0) { 47 | n_rows += m.n_rows(); 48 | // correction for periodic data 49 | if (shifts.size() > 0) { 50 | FastPCA::deg2rad_inplace(m); 51 | FastPCA::Periodic::shift_matrix_columns_inplace(m, shifts); 52 | } 53 | for (std::size_t i=0; i < m.n_rows(); ++i) { 54 | for (std::size_t j=0; j < n_cols; ++j) { 55 | means[j] += m(i,j); 56 | } 57 | } 58 | m = std::move(input_file.next_block()); 59 | } 60 | for (std::size_t j=0; j < n_cols; ++j) { 61 | means[j] /= n_rows; 62 | } 63 | return std::make_tuple(n_rows, n_cols, means); 64 | } 65 | 66 | // compute circular means by averaging sines and cosines 67 | // and resolving the mean angle with the atan2 function. 68 | // additionally, return number of observations. 69 | // std::tuple> 70 | // _circular_means(const std::string filename 71 | // , const std::size_t max_chunk_size) { 72 | // DataFileReader input_file(filename, max_chunk_size); 73 | // Matrix m = std::move(input_file.next_block()); 74 | // FastPCA::deg2rad_inplace(m); 75 | // std::size_t i, j; 76 | // std::size_t nr = m.n_rows(); 77 | // std::size_t nc = m.n_cols(); 78 | // std::vector means(nc, 0.0); 79 | // std::vector means_sin(nc, 0.0); 80 | // std::vector means_cos(nc, 0.0); 81 | // std::size_t n_rows_total = 0; 82 | // while (nr > 0) { 83 | // for (j=0; j < nc; ++j) { 84 | // for (i=0; i < nr; ++i) { 85 | // means_sin[j] += sin(m(i,j)); 86 | // means_cos[j] += cos(m(i,j)); 87 | // } 88 | // } 89 | // n_rows_total += nr; 90 | // m = std::move(input_file.next_block()); 91 | // FastPCA::deg2rad_inplace(m); 92 | // nr = m.n_rows(); 93 | // } 94 | // for (j=0; j < nc; ++j) { 95 | // means[j] = std::atan2(means_sin[j]/n_rows_total 96 | // , means_cos[j]/n_rows_total); 97 | // } 98 | // return std::make_tuple(n_rows_total, nc, means); 99 | // } 100 | 101 | std::vector 102 | _sigmas(const std::string filename 103 | , const std::size_t max_chunk_size 104 | , std::vector means 105 | , std::vector shifts = {}) { 106 | DataFileReader input_file(filename, max_chunk_size); 107 | std::size_t n_cols = means.size(); 108 | std::size_t n_rows = 0; 109 | std::vector sigmas(n_cols, 0.0); 110 | Matrix m = std::move(input_file.next_block()); 111 | while (m.n_rows() > 0) { 112 | n_rows += m.n_rows(); 113 | // periodic correction 114 | if (shifts.size() > 0) { 115 | FastPCA::deg2rad_inplace(m); 116 | FastPCA::Periodic::shift_matrix_columns_inplace(m, shifts); 117 | } 118 | FastPCA::shift_matrix_columns_inplace(m, means); 119 | // compute variances 120 | for (std::size_t i=0; i < m.n_rows(); ++i) { 121 | for (std::size_t j=0; j < n_cols; ++j) { 122 | sigmas[j] += m(i,j)*m(i,j); 123 | } 124 | } 125 | m = std::move(input_file.next_block()); 126 | } 127 | // compute sigmas from variances 128 | for (std::size_t j=0; j < n_cols; ++j) { 129 | sigmas[j] = sqrt(sigmas[j] / (n_rows-1)); 130 | } 131 | return sigmas; 132 | } 133 | 134 | double 135 | _periodic_shift_to_barrier_deg(double theta, double shift) { 136 | theta -= (shift + 180.0); 137 | if (theta < -180.0) { 138 | return theta + 360.0; 139 | } else if (theta > 180.0) { 140 | return theta - 360.0; 141 | } else { 142 | return theta; 143 | } 144 | } 145 | 146 | unsigned int 147 | _count_jumps_deg(const Matrix& m, std::size_t i_col, double shift) { 148 | unsigned int sum = 0; 149 | for (std::size_t i=0; i < m.n_rows()-1; ++i) { 150 | double theta1 = _periodic_shift_to_barrier_deg(m(i,i_col), shift); 151 | double theta2 = _periodic_shift_to_barrier_deg(m(i+1,i_col), shift); 152 | if (std::abs(theta1 - theta2) > 180.0) { 153 | ++sum; 154 | } 155 | } 156 | return sum; 157 | } 158 | 159 | std::size_t 160 | _n_cols(const std::string filename) { 161 | return DataFileReader(filename, 1024).n_cols(); 162 | } 163 | 164 | std::vector> 165 | _shift_hists(const std::string filename 166 | , std::size_t max_chunk_size 167 | , std::size_t n_bins 168 | , std::size_t binwidth) { 169 | std::size_t n_cols = _n_cols(filename); 170 | // result 171 | std::vector> 172 | hists(n_cols 173 | , std::vector(n_bins)); 174 | // compute histograms 175 | DataFileReader input_file(filename, max_chunk_size/2); 176 | read_blockwise(input_file 177 | , [&hists,binwidth,n_bins](Matrix& m) { 178 | std::size_t i, j, i_bin; 179 | #pragma omp parallel for default(none)\ 180 | private(j,i,i_bin)\ 181 | firstprivate(n_cols,n_bins,binwidth)\ 182 | shared(hists,m) 183 | for (j=0; j < m.n_cols(); ++j) { 184 | for (i=0; i < m.n_rows(); ++i) { 185 | for (i_bin=0; i_bin < n_bins; ++i_bin) { 186 | if (m(i,j) <= -180.0f + (i_bin+1)*binwidth) { 187 | ++hists[j][i_bin]; 188 | break; 189 | } 190 | } 191 | } 192 | } 193 | }); 194 | return hists; 195 | } 196 | 197 | std::vector 198 | _shift_barrier(std::vector barriers) { 199 | // shift not to center, but to barrier 200 | for (double& b: barriers) { 201 | b += 180.0; 202 | if (b > 180.0) { 203 | b -= 360.0; 204 | } 205 | } 206 | deg2rad_inplace(barriers); 207 | return barriers; 208 | } 209 | 210 | std::vector 211 | _dih_shifts_static(const std::string filename 212 | , std::size_t max_chunk_size) { 213 | max_chunk_size /= 2; 214 | // get number of columns from file 215 | std::size_t n_cols = _n_cols(filename); 216 | // histograms of degree populations 217 | // (72 bins of 5 degrees width, [-180, 180]) 218 | const std::size_t n_bins = 72; 219 | const float binwidth = 5.0; 220 | std::vector> hists = 221 | _shift_hists(filename 222 | , max_chunk_size 223 | , n_bins 224 | , binwidth); 225 | // periodic index correction 226 | auto periodic = [n_bins](int i) -> int { 227 | if (i < 0) { 228 | return n_bins + i; 229 | } else if (i >= n_bins) { 230 | return i - n_bins; 231 | } else { 232 | return i; 233 | } 234 | }; 235 | // find barriers per column 236 | std::vector barriers(n_cols); 237 | for (unsigned int i_col=0; i_col < n_cols; ++i_col) { 238 | // bin statistics for comparison 239 | // (pop of bin and sum(pops) over 3, 5, 7 neighboring bins) 240 | std::vector>> bin_stats(n_bins); 242 | for (int i=0; i < n_bins; ++i) { 243 | bin_stats[i].first = i; 244 | // bin itself 245 | bin_stats[i].second[0] = hists[i_col][i]; 246 | // sum 3 neighbors 247 | bin_stats[i].second[1] = bin_stats[i].second[0] 248 | + hists[i_col][periodic(i-1)] 249 | + hists[i_col][periodic(i+1)]; 250 | // sum 5 neighbors 251 | bin_stats[i].second[2] = bin_stats[i].second[1] 252 | + hists[i_col][periodic(i-2)] 253 | + hists[i_col][periodic(i+2)]; 254 | // sum 7 neighbors 255 | bin_stats[i].second[3] = bin_stats[i].second[2] 256 | + hists[i_col][periodic(i-3)] 257 | + hists[i_col][periodic(i+3)]; 258 | } 259 | // comparator: a < b ? 260 | auto bin_stats_comp = [](std::pair> a 262 | , std::pair> b) { 264 | return (a.second[0] < b.second[0]) 265 | || ((a.second[0] == b.second[0]) 266 | && (a.second[1] < b.second[1])) 267 | || ((a.second[0] == b.second[0]) 268 | && (a.second[1] == b.second[1]) 269 | && (a.second[2] < b.second[2])) 270 | || ((a.second[0] == b.second[0]) 271 | && (a.second[1] == b.second[1]) 272 | && (a.second[2] == b.second[2]) 273 | && (a.second[3] < b.second[3])); 274 | }; 275 | unsigned int best_bin = (*std::min_element(bin_stats.begin() 276 | , bin_stats.end() 277 | , bin_stats_comp)).first; 278 | // compute best shift 279 | barriers[i_col] = -180 + (best_bin * binwidth) + 0.5 * binwidth; 280 | } 281 | return _shift_barrier(barriers); 282 | } 283 | 284 | std::vector 285 | _dih_shifts_dynamic(const std::string filename 286 | , std::size_t max_chunk_size) { 287 | // get number of columns from file 288 | std::size_t n_cols; 289 | { 290 | DataFileReader input_file(filename, max_chunk_size); 291 | n_cols = input_file.n_cols(); 292 | } 293 | // histogram for first guess (72 bins of 5 degrees width, [-180, 180]) 294 | const std::size_t n_bins = 72; 295 | const float binwidth = 5.0; 296 | std::vector> hists = 297 | _shift_hists(filename 298 | , max_chunk_size 299 | , n_bins 300 | , binwidth); 301 | // compute min-shift candidates from histograms 302 | const int n_min_bins = 5; 303 | const int n_values_per_bin = 5; 304 | const int n_candidates_per_col = n_min_bins * n_values_per_bin; 305 | std::vector> 306 | candidates(n_cols 307 | , std::vector(n_candidates_per_col)); 308 | for (std::size_t j=0; j < n_cols; ++j) { 309 | // 5 smallest bins 310 | std::vector min_bins(5, 0); 311 | for (std::size_t i_bin=1; i_bin < n_bins; ++i_bin) { 312 | for (std::size_t k=0; k < n_min_bins; ++k) { 313 | if (hists[j][i_bin] < hists[j][min_bins[k]]) { 314 | min_bins[k] = i_bin; 315 | break; 316 | } 317 | } 318 | } 319 | // compute degree values of candidates 320 | // candidates: 5 values for 5 bins = 25 values. 321 | // compute by: deg(bin), deg(bin)+1.0, deg(bin)+2.0, ..., deg(bin)+4.0 322 | // with deg(bin) degree value of bin (lower boundary). 323 | for (std::size_t i_min_bin=0; i_min_bin < n_min_bins; ++i_min_bin) { 324 | for (std::size_t k=0; k < n_values_per_bin; ++k) { 325 | candidates[j][i_min_bin*n_min_bins + k] = 326 | min_bins[i_min_bin]*binwidth + k -180.0f; 327 | } 328 | } 329 | } 330 | // compute ranking for different shifts 331 | std::vector> 332 | n_jumps(n_cols 333 | , std::vector(n_candidates_per_col)); 334 | { 335 | DataFileReader input_file(filename, max_chunk_size/2); 336 | read_blockwise(input_file 337 | , [&n_jumps 338 | , &candidates 339 | , n_cols 340 | , n_candidates_per_col] (Matrix& m) { 341 | std::size_t j; 342 | std::size_t ic; 343 | #pragma omp parallel for default(none)\ 344 | private(j,ic)\ 345 | firstprivate(n_cols,n_candidates_per_col)\ 346 | shared(m,candidates,n_jumps) 347 | for (j=0; j < n_cols; ++j) { 348 | for (ic=0; ic < n_candidates_per_col; ++ic) { 349 | n_jumps[j][ic] = _count_jumps_deg(m, j, candidates[j][ic]); 350 | } 351 | } 352 | }); 353 | } 354 | // shifts: minimal jumps win 355 | std::vector shifts(n_cols); 356 | for (std::size_t j=0; j < n_cols; ++j) { 357 | unsigned int jumps_min = n_jumps[j][0]; 358 | std::size_t i_min = 0; 359 | for (std::size_t i=1; i < n_candidates_per_col; ++i) { 360 | if (n_jumps[j][i] < jumps_min) { 361 | i_min = i; 362 | jumps_min = n_jumps[j][i]; 363 | } 364 | } 365 | shifts[j] = candidates[j][i_min]; 366 | } 367 | // put cut points on periodic barriers 368 | return _shift_barrier(shifts); 369 | } 370 | 371 | Matrix 372 | _stats(const std::string filename 373 | , const std::size_t max_chunk_size 374 | , bool periodic 375 | , bool dynamic_shift) { 376 | std::vector means; 377 | std::vector sigmas; 378 | std::size_t n_rows, n_cols; 379 | // shifts 380 | std::vector shifts; 381 | if (periodic && dynamic_shift) { 382 | shifts = _dih_shifts_dynamic(filename 383 | , max_chunk_size); 384 | } else if (periodic && ( ! dynamic_shift)) { 385 | shifts = _dih_shifts_static(filename 386 | , max_chunk_size); 387 | } 388 | // means & sigmas 389 | if (periodic) { 390 | std::tie(n_rows, n_cols, means) = _means(filename 391 | , max_chunk_size 392 | , shifts); 393 | sigmas = _sigmas(filename 394 | , max_chunk_size 395 | , means 396 | , shifts); 397 | } else { 398 | std::tie(n_rows, n_cols, means) = _means(filename 399 | , max_chunk_size); 400 | sigmas = _sigmas(filename 401 | , max_chunk_size 402 | , means); 403 | } 404 | // output 405 | int n_cols_out; 406 | if (periodic) { 407 | n_cols_out = 3; 408 | } else { 409 | n_cols_out = 2; 410 | } 411 | Matrix stats(n_cols, n_cols_out); 412 | for (std::size_t i=0; i < n_cols; ++i) { 413 | stats(i, 0) = means[i]; 414 | stats(i, 1) = sigmas[i]; 415 | if (periodic) { 416 | stats(i, 2) = shifts[i]; 417 | } 418 | } 419 | return stats; 420 | } 421 | 422 | } // end local namespace 423 | 424 | 425 | bool is_comment_or_empty(std::string line) { 426 | std::size_t pos = line.find_first_not_of(" "); 427 | if (pos == std::string::npos) { 428 | // empty string 429 | return true; 430 | } else if (line[pos] == '#' or line[pos] == '@') { 431 | // comment 432 | return true; 433 | } else { 434 | return false; 435 | } 436 | } 437 | 438 | Matrix 439 | stats(const std::string filename 440 | , const std::size_t max_chunk_size) { 441 | return _stats(filename 442 | , max_chunk_size 443 | , false 444 | , false); 445 | } 446 | 447 | 448 | namespace Periodic { 449 | double 450 | distance(double theta1, double theta2) { 451 | double abs_diff = std::abs(theta1 - theta2); 452 | if (abs_diff <= M_PI) { 453 | return abs_diff; 454 | } else { 455 | return abs_diff - (2*M_PI); 456 | } 457 | } 458 | 459 | Matrix 460 | stats(const std::string filename 461 | , const std::size_t max_chunk_size 462 | , const bool dynamic_shift) { 463 | return _stats(filename, max_chunk_size, true, dynamic_shift); 464 | } 465 | 466 | } // end namespace FastPCA::Periodic 467 | } // end namespace FastPCA 468 | 469 | -------------------------------------------------------------------------------- /src/util.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | /* 3 | Copyright (c) 2014, Florian Sittel (www.lettis.net) 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #include 28 | #include 29 | 30 | // resolve circular dependency 31 | namespace FastPCA { 32 | // used in file_io 33 | constexpr std::size_t 34 | gigabytes_to_bytes(std::size_t gb) { 35 | return gb * 1073741824; 36 | } 37 | // used in matrix 38 | template 39 | std::vector 40 | sorted_index(const std::vector &v, bool reverse_sorting=false); 41 | } 42 | 43 | #include "matrix.hpp" 44 | #include "file_io.hpp" 45 | 46 | namespace FastPCA { 47 | 48 | bool 49 | is_comment_or_empty(std::string line); 50 | 51 | template 52 | std::vector 53 | parse_line(std::string line); 54 | 55 | template 56 | void 57 | deg2rad_inplace(Matrix& m); 58 | 59 | template 60 | void 61 | deg2rad_inplace(std::vector& v); 62 | 63 | template 64 | void 65 | rad2deg_inplace(Matrix& m); 66 | 67 | template 68 | void 69 | shift_matrix_columns_inplace(Matrix& m, std::vector shifts); 70 | 71 | template 72 | void 73 | scale_matrix_columns_inplace(Matrix& m, std::vector factors); 74 | 75 | // statistical attributes in three columns: 76 | // - means 77 | // - sigmas 78 | Matrix stats(const std::string filename 79 | , const std::size_t max_chunk_size); 80 | 81 | namespace Periodic { 82 | /** 83 | * angular distance between two angles 84 | */ 85 | double 86 | distance(double theta1, double theta2); 87 | 88 | /** 89 | * return corresponding number restricted to 90 | * periodic interval inside boundaries of 91 | * [-periodicity/2, +periodicity/2]. 92 | */ 93 | template 94 | T 95 | normalized(T var, T periodicity); 96 | 97 | template 98 | void 99 | shift_matrix_columns_inplace(Matrix& m 100 | , std::vector shifts 101 | , std::vector periodicities); 102 | 103 | template 104 | void 105 | shift_matrix_columns_inplace(Matrix& m, std::vector shifts); 106 | 107 | // statistical attributes in three columns: 108 | // - means 109 | // - sigmas 110 | // - optimal shifts 111 | Matrix 112 | stats(const std::string filename 113 | , const std::size_t max_chunk_size 114 | , const bool dynamic_shift); 115 | } // end namespace FastPCA::Periodic 116 | 117 | } // end namespace FastPCA 118 | 119 | // template implementations 120 | #include "util.hxx" 121 | 122 | -------------------------------------------------------------------------------- /src/util.hxx: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Copyright (c) 2014, Florian Sittel (www.lettis.net) 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | 28 | #include "util.hpp" 29 | #include "errors.hpp" 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | namespace FastPCA { 36 | 37 | namespace { 38 | template 39 | void 40 | _elementwise_mult(Matrix& m, T factor) { 41 | std::size_t nr = m.n_rows(); 42 | std::size_t nc = m.n_cols(); 43 | std::size_t i,j; 44 | for (j=0; j < nc; ++j) { 45 | for (i=0; i < nr; ++i) { 46 | m(i,j) *= factor; 47 | } 48 | } 49 | } 50 | 51 | template 52 | T 53 | _sign(T v) { 54 | return (v < 0) ? -1.0 : 1.0; 55 | } 56 | } // end local namespace 57 | 58 | template 59 | std::vector 60 | sorted_index(const std::vector &v, bool reverse_sorting) { 61 | std::vector indeces(v.size()); 62 | for (std::size_t i = 0; i != v.size(); ++i) { 63 | indeces[i] = i; 64 | } 65 | if (reverse_sorting) { 66 | std::sort(indeces.begin(), indeces.end(), [&v](std::size_t i1, std::size_t i2) {return v[i1] > v[i2];}); 67 | } else { 68 | std::sort(indeces.begin(), indeces.end(), [&v](std::size_t i1, std::size_t i2) {return v[i1] < v[i2];}); 69 | } 70 | return indeces; 71 | } 72 | 73 | template 74 | void 75 | deg2rad_inplace(Matrix& m) { 76 | _elementwise_mult(m, M_PI / 180.0); 77 | } 78 | 79 | template 80 | void 81 | deg2rad_inplace(std::vector& v) { 82 | for (std::size_t i=0; i < v.size(); ++i) { 83 | v[i] *= M_PI / 180.0; 84 | } 85 | } 86 | 87 | template 88 | void 89 | rad2deg_inplace(Matrix& m) { 90 | _elementwise_mult(m, 180.0 / M_PI); 91 | } 92 | 93 | template 94 | void 95 | shift_matrix_columns_inplace(Matrix& m, std::vector shifts) { 96 | std::size_t i,j; 97 | const std::size_t n_rows = m.n_rows(); 98 | const std::size_t n_cols = m.n_cols(); 99 | #pragma omp parallel for default(none)\ 100 | private(i,j)\ 101 | firstprivate(n_rows,n_cols)\ 102 | shared(m,shifts) 103 | for (j=0; j < n_cols; ++j) { 104 | for (i=0; i < n_rows; ++i) { 105 | m(i,j) = m(i,j) - shifts[j]; 106 | } 107 | } 108 | } 109 | 110 | template 111 | void 112 | scale_matrix_columns_inplace(Matrix& m, std::vector factors) { 113 | std::size_t i,j; 114 | const std::size_t n_rows = m.n_rows(); 115 | const std::size_t n_cols = m.n_cols(); 116 | #pragma omp parallel for default(none)\ 117 | private(i,j)\ 118 | firstprivate(n_rows,n_cols)\ 119 | shared(m,factors) 120 | for (j=0; j < n_cols; ++j) { 121 | for (i=0; i < n_rows; ++i) { 122 | m(i,j) = m(i,j) * factors[j]; 123 | } 124 | } 125 | } 126 | 127 | template 128 | std::vector parse_line(std::string line) { 129 | std::vector out; 130 | std::size_t len = line.length(); 131 | const char* last_start = &line[0]; 132 | std::size_t j=0; 133 | bool whitespace_before = true; 134 | while (j < len) { 135 | if (line[j] == ' ') { 136 | if ( ! whitespace_before) { 137 | line[j] = '\0'; 138 | out.push_back(atof(last_start)); 139 | whitespace_before = true; 140 | } 141 | } else { 142 | // now we have some character which is no whitespace 143 | if (whitespace_before) { 144 | last_start = &line[j]; 145 | } 146 | whitespace_before = false; 147 | } 148 | ++j; 149 | } 150 | out.push_back(atof(last_start)); 151 | return out; 152 | } 153 | 154 | namespace Periodic { 155 | template 156 | T 157 | normalized(T var, T periodicity) { 158 | periodicity *= 0.5; 159 | T var1 = std::fmod(var, periodicity); 160 | T var2 = std::fmod(var, 2*periodicity); 161 | return (var1 == var2) ? var1 : (var1 - _sign(var2-var1) * periodicity); 162 | } 163 | 164 | template 165 | void 166 | shift_matrix_columns_inplace(Matrix& m 167 | , std::vector shifts 168 | , std::vector periodicities) { 169 | std::size_t i,j; 170 | const std::size_t n_rows = m.n_rows(); 171 | const std::size_t n_cols = m.n_cols(); 172 | #pragma omp parallel for default(none)\ 173 | private(i,j)\ 174 | firstprivate(n_rows,n_cols)\ 175 | shared(m,shifts, periodicities) 176 | for (j=0; j < n_cols; ++j) { 177 | for (i=0; i < n_rows; ++i) { 178 | m(i,j) = m(i,j) - shifts[j]; 179 | // periodic boundary checks 180 | m(i,j) = FastPCA::Periodic::normalized(m(i,j), periodicities[j]); 181 | } 182 | } 183 | } 184 | 185 | template 186 | void 187 | shift_matrix_columns_inplace(Matrix& m 188 | , std::vector shifts) { 189 | std::vector p(shifts.size(), 2*M_PI); 190 | FastPCA::Periodic::shift_matrix_columns_inplace(m, shifts, p); 191 | } 192 | } // FastPCA::Periodic 193 | 194 | } // namespace FastPCA 195 | 196 | -------------------------------------------------------------------------------- /src/xdrfile/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | add_library(xdrfile xdrfile.c xdrfile_xtc.c) 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/xdrfile/trr2xtc.c: -------------------------------------------------------------------------------- 1 | /* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- 2 | * 3 | * $Id: trr2xtc.c,v 1.3 2009/05/18 09:06:38 spoel Exp $ 4 | * 5 | * Copyright (c) Erik Lindahl, David van der Spoel 2003,2004. 6 | * Coordinate compression (c) by Frans van Hoesel. 7 | * 8 | * This program is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public License 10 | * as published by the Free Software Foundation; either version 3 11 | * of the License, or (at your option) any later version. 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #include "xdrfile.h" 19 | #include "xdrfile_trr.h" 20 | #include "xdrfile_xtc.h" 21 | 22 | 23 | /* This program tests reading and writing to XDR files */ 24 | 25 | static void _die(char *msg, int line, char *file) { 26 | fprintf(stderr, "Fatal error: %s\n", msg); 27 | fprintf(stderr, "Death occurred at %s, line %d\n", file, line); 28 | exit(1); 29 | } 30 | #define die(msg) _die(msg,__LINE__,__FILE__) 31 | 32 | static void _die_r(char *msg, int result, int line, char *file) { 33 | fprintf(stderr, "Fatal error: %s\n", msg); 34 | fprintf(stderr,"result = %d\n", result); 35 | fprintf(stderr, "Death occurred at %s, line %d\n", file, line); 36 | exit(1); 37 | } 38 | #define die_r(msg,res) _die_r(msg,res,__LINE__,__FILE__) 39 | 40 | 41 | void ReadWrite(char *rfile, char *wfile, int in_xtcBool, int out_xtcBool, int in_trrBool, int out_trrBool) 42 | { 43 | XDRFILE *xd_read, *xd_write; 44 | int result_xtc, result_trr; 45 | int natoms_xtc, natoms_trr; 46 | int step_xtc, step_trr; 47 | float time_xtc, time_trr; 48 | matrix box_xtc, box_trr; 49 | rvec *x_xtc, *x_trr, *v_trr, *f_trr; 50 | float prec_xtc = 1000.0; 51 | float lambda_trr = 0.0; 52 | 53 | 54 | xd_read = xdrfile_open(rfile, "r"); 55 | if (NULL == xd_read) 56 | die("Opening xdrfile for reading"); 57 | 58 | /* Test whether output file exists */ 59 | if ((xd_write = xdrfile_open(wfile,"r")) != NULL) { 60 | xdrfile_close(xd_write); 61 | die("Output file exists."); 62 | } 63 | 64 | /* Output file does not exist. Now we can open it for writing */ 65 | xd_write = xdrfile_open(wfile, "w"); 66 | if (NULL == xd_write) 67 | die("Opening xdrfile for writing"); 68 | 69 | 70 | /* .xtc -> .xtc */ 71 | if(in_xtcBool && out_xtcBool) 72 | { 73 | result_xtc = read_xtc_natoms(rfile, &natoms_xtc); 74 | if (exdrOK != result_xtc) 75 | die_r("read_xtc_natoms",result_xtc); 76 | 77 | x_xtc = calloc(natoms_xtc, sizeof(x_xtc[0])); 78 | 79 | while(1) 80 | { 81 | result_xtc = read_xtc(xd_read, natoms_xtc, &step_xtc, &time_xtc, 82 | box_xtc, x_xtc, &prec_xtc); 83 | 84 | if (result_xtc == 0) // if not reach the end of file, write it to the output.xtc file 85 | { 86 | if (exdrOK != result_xtc) 87 | die_r("Reading xtc file", result_xtc); 88 | 89 | result_xtc = write_xtc(xd_write, natoms_xtc, step_xtc, time_xtc, 90 | box_xtc, x_xtc, prec_xtc); 91 | 92 | if (result_xtc != 0) 93 | die_r("Writing xtc file", result_xtc); 94 | } 95 | else 96 | break; 97 | } 98 | } 99 | 100 | 101 | /* .xtc -> .trr */ 102 | if(in_xtcBool && out_trrBool) 103 | { 104 | result_xtc = read_xtc_natoms(rfile, &natoms_xtc); 105 | if (exdrOK != result_xtc) 106 | die_r("read_xtc_natoms",result_xtc); 107 | 108 | x_xtc = calloc(natoms_xtc, sizeof(x_xtc[0])); 109 | 110 | while(1) 111 | { 112 | result_xtc = read_xtc(xd_read, natoms_xtc, &step_xtc, &time_xtc, 113 | box_xtc, x_xtc, &prec_xtc); 114 | 115 | if (result_xtc == 0) // if not reach the end of file, write it to the output.trr file 116 | { 117 | if (exdrOK != result_xtc) 118 | die_r("Reading xtc file", result_xtc); 119 | 120 | result_trr = write_trr(xd_write, natoms_xtc, step_xtc, time_xtc, lambda_trr, 121 | box_xtc, x_xtc, NULL, NULL); 122 | 123 | if (0 != result_trr) 124 | die_r("Writing trr file",result_trr); 125 | 126 | } 127 | else 128 | break; 129 | } 130 | } 131 | 132 | 133 | /* .trr -> .trr */ 134 | if(in_trrBool && out_trrBool) 135 | { 136 | result_trr = read_trr_natoms(rfile, &natoms_trr); 137 | 138 | if (exdrOK != result_trr) 139 | die_r("read_trr_natoms",result_trr); 140 | 141 | x_trr = calloc(natoms_trr, sizeof(x_trr[0])); 142 | v_trr = calloc(natoms_trr, sizeof(v_trr[0])); 143 | f_trr = calloc(natoms_trr, sizeof(f_trr[0])); 144 | 145 | while (1) 146 | { 147 | result_trr = read_trr(xd_read, natoms_trr, &step_trr, &time_trr, &lambda_trr, 148 | box_trr, x_trr, v_trr, f_trr); 149 | 150 | int ii_trr, jj_trr, x_ck=0, v_ck=0, f_ck=0; 151 | int x_ck_bool=0, v_ck_bool=0, f_ck_bool=0; 152 | 153 | for (ii_trr = 0; ii_trr < natoms_trr; ii_trr++) 154 | { 155 | for(jj_trr = 0; jj_trr < DIM; jj_trr++) 156 | { 157 | if (x_trr[ii_trr][jj_trr] == 0) 158 | x_ck++; 159 | if (v_trr[ii_trr][jj_trr] == 0) 160 | v_ck++; 161 | if (f_trr[ii_trr][jj_trr] == 0) 162 | f_ck++; 163 | } 164 | } 165 | 166 | if (x_ck == natoms_trr*DIM) 167 | x_ck_bool = 1; 168 | if (v_ck == natoms_trr*DIM) 169 | v_ck_bool = 1; 170 | if (f_ck == natoms_trr*DIM) 171 | f_ck_bool = 1; 172 | 173 | if (result_trr == 0) // if not reach the end of file, write it to the output.trr file 174 | { 175 | if (exdrOK != result_trr) 176 | die_r("Reading trr file",result_trr); 177 | 178 | if(v_ck_bool && f_ck_bool) 179 | result_trr = write_trr(xd_write, natoms_trr, step_trr, time_trr, lambda_trr, 180 | box_trr, x_trr, NULL, NULL); 181 | else if(v_ck_bool) 182 | result_trr = write_trr(xd_write, natoms_trr, step_trr, time_trr, lambda_trr, 183 | box_trr, x_trr, NULL, f_trr); 184 | else if(f_ck_bool) 185 | result_trr = write_trr(xd_write, natoms_trr, step_trr, time_trr, lambda_trr, 186 | box_trr, x_trr, v_trr, NULL); 187 | else 188 | result_trr = write_trr(xd_write, natoms_trr, step_trr, time_trr, lambda_trr, 189 | box_trr, x_trr, v_trr, f_trr); 190 | 191 | if (0 != result_trr) 192 | die_r("Writing trr file",result_trr); 193 | 194 | } 195 | else 196 | break; 197 | } 198 | } 199 | 200 | 201 | /* .trr -> .xtc */ 202 | if(in_trrBool && out_xtcBool) 203 | { 204 | result_trr = read_trr_natoms(rfile, &natoms_trr); 205 | 206 | if (exdrOK != result_trr) 207 | die_r("read_trr_natoms",result_trr); 208 | 209 | x_trr = calloc(natoms_trr, sizeof(x_trr[0])); 210 | v_trr = calloc(natoms_trr, sizeof(v_trr[0])); 211 | f_trr = calloc(natoms_trr, sizeof(f_trr[0])); 212 | 213 | while(1) 214 | { 215 | result_trr = read_trr(xd_read, natoms_trr, &step_trr, &time_trr, &lambda_trr, 216 | box_trr, x_trr, v_trr, f_trr); 217 | 218 | if (result_trr == 0) // if not reach the end of file, write it to the output.trr file 219 | { 220 | if (exdrOK != result_trr) 221 | die_r("Reading trr file", result_trr); 222 | 223 | result_xtc = write_xtc(xd_write, natoms_trr, step_trr, time_trr, 224 | box_trr, x_trr, prec_xtc); 225 | 226 | if (result_xtc != 0) 227 | die_r("Writing xtc file", result_xtc); 228 | } 229 | else 230 | break; 231 | } 232 | } 233 | 234 | xdrfile_close(xd_read); 235 | xdrfile_close(xd_write); 236 | 237 | } 238 | 239 | 240 | 241 | int main(int argc, char *argv[]) 242 | { 243 | int inFileBool = 0; 244 | int outFileBool = 0; 245 | int in_xtcBool = 0; 246 | int out_xtcBool = 0; 247 | int in_trrBool = 0; 248 | int out_trrBool = 0; 249 | char *rfile=NULL, *wfile=NULL; 250 | 251 | 252 | if(argc != 5) 253 | { 254 | fprintf(stderr,"Usage: %s -i inFile -o outFile\n",argv[0]); 255 | exit(1); 256 | } 257 | else 258 | { 259 | int ii = 1; 260 | 261 | while(ii < argc) 262 | { 263 | if(strcmp(argv[ii], "-i") == 0) // if (argv[ii] == "-i") 264 | { 265 | ii++; 266 | inFileBool = 1; 267 | 268 | if(strstr(argv[ii], ".xtc") != NULL) 269 | { 270 | in_xtcBool = 1; 271 | in_trrBool = 0; 272 | } 273 | if(strstr(argv[ii], ".trr") != NULL) 274 | { 275 | in_trrBool = 1; 276 | in_xtcBool = 0; 277 | } 278 | 279 | rfile = argv[ii]; 280 | } 281 | 282 | if(strcmp(argv[ii], "-o") == 0) 283 | { 284 | ii++; 285 | outFileBool = 1; 286 | 287 | if(strstr(argv[ii], ".xtc") != NULL) 288 | { 289 | out_xtcBool = 1; 290 | out_trrBool = 0; 291 | } 292 | if(strstr(argv[ii], ".trr") != NULL) 293 | { 294 | out_trrBool = 1; 295 | out_xtcBool = 0; 296 | } 297 | 298 | wfile = argv[ii]; 299 | } 300 | 301 | ii++; 302 | } 303 | } 304 | 305 | if(!inFileBool || !outFileBool) 306 | { 307 | perror("Usage : ./ReadWrite -i inFile -o outFile"); 308 | exit(1); 309 | } 310 | 311 | ReadWrite(rfile, wfile, in_xtcBool, out_xtcBool, in_trrBool, out_trrBool); 312 | 313 | 314 | return 0; 315 | } 316 | -------------------------------------------------------------------------------- /src/xdrfile/xdrfile.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- 2 | * 3 | * $Id: xdrfile.h,v 1.6 2009/05/18 09:06:38 spoel Exp $ 4 | * 5 | * Copyright (c) Erik Lindahl, David van der Spoel 2003,2004. 6 | * Coordinate compression (c) by Frans van Hoesel. 7 | * 8 | * This program is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public License 10 | * as published by the Free Software Foundation; either version 3 11 | * of the License, or (at your option) any later version. 12 | */ 13 | 14 | /*! \file xdrfile.h 15 | * \brief Interface to read/write portabile binary files using XDR. 16 | * 17 | * This file provides an interface to read & write portably binary files, 18 | * using XDR - the external data representation standard defined in RFC 1014. 19 | * 20 | * There are several advantages to the XDR approach: 21 | * 22 | * -# It is portable. And not just portable between big/small integer endian, 23 | * but truly portable if you have system XDR routines. For example: 24 | * - It doesn't matter if the character representation is ASCII or EBCDIC. 25 | * - Some systems are small endian but use big endian order of the two 26 | * dword in a double precision floating-point variable. The system XDR 27 | * libraries will read/write this correctly. 28 | * - Some systems (VAX...) don't use IEEE floating point. Their system 29 | * XDR libraries will convert to/from this automatically. 30 | * -# XDR libraries are required for NFS and lots of other network functions. 31 | * This means there isn't a single Unix-like system that doesn't have them. 32 | * -# There is NO extra metadata whatsoever, and we write plain XDR files. 33 | * If you write a float, it will take exactly 4 bytes in the file. 34 | * (All basic datatypes are 4 bytes, double fp 8 bytes). 35 | * -# You can read/write the files by calling the system XDR routines directly 36 | * too - you don't have to use the routines defined in this file. 37 | * -# It is no problem if your system doesn't have XDR libraries (MS Windows). 38 | * We have written our own versions of the necessary routines that work if 39 | * your system uses ASCII for strings and IEEE floating-point. All types 40 | * of byte and dword endian for integer and floating-point are supported. 41 | * -# You can use these routines for any type of data, but since we designed 42 | * them for Gromacs we also provide a special routine to write coordinates 43 | * with (adjustable) lossy compression. The default precision will give you 44 | * three decimals guaranteed accuracy, and reduces the filesize to 1/10th 45 | * of normal binary data. 46 | * 47 | * We do not support getting or setting positions in XDR files, since it can 48 | * break in horrible ways for large (64-bit) files, resulting in silent data 49 | * corruption. Note that it works great to open/read/write 64-bit files if 50 | * your system supports it; it is just the random access we cannot trust! 51 | * 52 | * We also provide wrapper routines so this module can be used from FORTRAN - 53 | * see the file xdrfile_fortran.txt in the Gromacs distribution for 54 | * documentation on the FORTRAN interface! 55 | */ 56 | 57 | 58 | #ifndef _XDRFILE_H_ 59 | #define _XDRFILE_H_ 60 | 61 | #ifdef CPLUSPLUS 62 | extern "C" 63 | { 64 | #endif 65 | 66 | /*! \brief Abstract datatype for an portable binary file handle 67 | * 68 | * This datatype essentially works just like the standard FILE type in C. 69 | * The actual contents is hidden in the implementation, so you can only 70 | * define pointers to it, for use with the xdrfile routines. 71 | * 72 | * If you \a really need to see the definition it is in xdrfile.c, but you 73 | * cannot access elements of the structure outside that file. 74 | * 75 | * \warning The implementation is completely different from the C standard 76 | * library FILE, so don't even think about using an XDRFILE pointer as an 77 | * argument to a routine that needs a standard FILE pointer. 78 | */ 79 | typedef struct XDRFILE XDRFILE; 80 | 81 | enum { exdrOK, exdrHEADER, exdrSTRING, exdrDOUBLE, 82 | exdrINT, exdrFLOAT, exdrUINT, exdr3DX, exdrCLOSE, exdrMAGIC, 83 | exdrNOMEM, exdrENDOFFILE, exdrFILENOTFOUND, exdrNR }; 84 | 85 | extern char *exdr_message[exdrNR]; 86 | 87 | #define DIM 3 88 | typedef float matrix[DIM][DIM]; 89 | typedef float rvec[DIM]; 90 | typedef int mybool; 91 | 92 | 93 | /*! \brief Open a portable binary file, just like fopen() 94 | * 95 | * Use this routine much like calls to the standard library function 96 | * fopen(). The only difference is that the returned pointer should only 97 | * be used with routines defined in this header. 98 | * 99 | * \param path Full or relative path (including name) of the file 100 | * \param mode "r" for reading, "w" for writing, "a" for append. 101 | * 102 | * \return Pointer to abstract xdr file datatype, or NULL if an error occurs. 103 | * 104 | */ 105 | XDRFILE * 106 | xdrfile_open (const char * path, 107 | const char * mode); 108 | 109 | 110 | /*! \brief Close a previously opened portable binary file, just like fclose() 111 | * 112 | * Use this routine much like calls to the standard library function 113 | * fopen(). The only difference is that it is used for an XDRFILE handle 114 | * instead of a FILE handle. 115 | * 116 | * \param xfp Pointer to an abstract XDRFILE datatype 117 | * 118 | * \return 0 on success, non-zero on error. 119 | */ 120 | int 121 | xdrfile_close (XDRFILE * xfp); 122 | 123 | 124 | 125 | 126 | /*! \brief Read one or more \a char type variable(s) 127 | * 128 | * \param ptr Pointer to memory where data should be written 129 | * \param ndata Number of characters to read 130 | * \param xfp Handle to portable binary file, created with xdrfile_open() 131 | * 132 | * \return Number of characters read 133 | */ 134 | int 135 | xdrfile_read_char(char * ptr, 136 | int ndata, 137 | XDRFILE * xfp); 138 | 139 | 140 | 141 | /*! \brief Write one or more \a characters type variable(s) 142 | * 143 | * \param ptr Pointer to memory where data should be read 144 | * \param ndata Number of characters to write. 145 | * \param xfp Handle to portable binary file, created with xdrfile_open() 146 | * 147 | * \return Number of characters written 148 | */ 149 | int 150 | xdrfile_write_char(char * ptr, 151 | int ndata, 152 | XDRFILE * xfp); 153 | 154 | 155 | 156 | /*! \brief Read one or more \a unsigned \a char type variable(s) 157 | * 158 | * \param ptr Pointer to memory where data should be written 159 | * \param ndata Number of unsigned characters to read 160 | * \param xfp Handle to portable binary file, created with xdrfile_open() 161 | * 162 | * \return Number of unsigned characters read 163 | */ 164 | int 165 | xdrfile_read_uchar(unsigned char * ptr, 166 | int ndata, 167 | XDRFILE * xfp); 168 | 169 | 170 | 171 | /*! \brief Write one or more \a unsigned \a characters type variable(s) 172 | * 173 | * \param ptr Pointer to memory where data should be read 174 | * \param ndata Number of unsigned characters to write. 175 | * \param xfp Handle to portable binary file, created with xdrfile_open() 176 | * 177 | * \return Number of unsigned characters written 178 | */ 179 | int 180 | xdrfile_write_uchar(unsigned char * ptr, 181 | int ndata, 182 | XDRFILE * xfp); 183 | 184 | 185 | 186 | /*! \brief Read one or more \a short type variable(s) 187 | * 188 | * \param ptr Pointer to memory where data should be written 189 | * \param ndata Number of shorts to read 190 | * \param xfp Handle to portable binary file, created with xdrfile_open() 191 | * 192 | * \return Number of shorts read 193 | */ 194 | int 195 | xdrfile_read_short(short * ptr, 196 | int ndata, 197 | XDRFILE * xfp); 198 | 199 | 200 | 201 | /*! \brief Write one or more \a short type variable(s) 202 | * 203 | * \param ptr Pointer to memory where data should be read 204 | * \param ndata Number of shorts to write. 205 | * \param xfp Handle to portable binary file, created with xdrfile_open() 206 | * 207 | * \return Number of shorts written 208 | */ 209 | int 210 | xdrfile_write_short(short * ptr, 211 | int ndata, 212 | XDRFILE * xfp); 213 | 214 | 215 | 216 | /*! \brief Read one or more \a unsigned \a short type variable(s) 217 | * 218 | * \param ptr Pointer to memory where data should be written 219 | * \param ndata Number of unsigned shorts to read 220 | * \param xfp Handle to portable binary file, created with xdrfile_open() 221 | * 222 | * \return Number of unsigned shorts read 223 | */ 224 | int 225 | xdrfile_read_ushort(unsigned short * ptr, 226 | int ndata, 227 | XDRFILE * xfp); 228 | 229 | 230 | 231 | /*! \brief Write one or more \a unsigned \a short type variable(s) 232 | * 233 | * \param ptr Pointer to memory where data should be read 234 | * \param ndata Number of unsigned shorts to write. 235 | * \param xfp Handle to portable binary file, created with xdrfile_open() 236 | * 237 | * \return Number of unsigned shorts written 238 | */ 239 | int 240 | xdrfile_write_ushort(unsigned short * ptr, 241 | int ndata, 242 | XDRFILE * xfp); 243 | 244 | 245 | /*! \brief Read one or more \a integer type variable(s) 246 | * 247 | * \param ptr Pointer to memory where data should be written 248 | * \param ndata Number of integers to read 249 | * \param xfp Handle to portable binary file, created with xdrfile_open() 250 | * 251 | * \return Number of integers read 252 | * 253 | * The integer data type is assumed to be less than or equal to 32 bits. 254 | * 255 | * We do not provide any routines for reading/writing 64-bit integers, since 256 | * - Not all XDR implementations support it 257 | * - Not all machines have 64-bit integers 258 | * 259 | * Split your 64-bit data into two 32-bit integers for portability! 260 | */ 261 | int 262 | xdrfile_read_int(int * ptr, 263 | int ndata, 264 | XDRFILE * xfp); 265 | 266 | 267 | 268 | /*! \brief Write one or more \a integer type variable(s) 269 | * 270 | * \param ptr Pointer to memory where data should be read 271 | * \param ndata Number of integers to write. 272 | * \param xfp Handle to portable binary file, created with xdrfile_open() 273 | * 274 | * \return Number of integers written 275 | * 276 | * The integer data type is assumed to be less than or equal to 32 bits. 277 | * 278 | * We do not provide any routines for reading/writing 64-bit integers, since 279 | * - Not all XDR implementations support it 280 | * - Not all machines have 64-bit integers 281 | * 282 | * Split your 64-bit data into two 32-bit integers for portability! 283 | */ 284 | int 285 | xdrfile_write_int(int * ptr, 286 | int ndata, 287 | XDRFILE * xfp); 288 | 289 | /*! \brief Read one or more \a unsigned \a integers type variable(s) 290 | * 291 | * \param ptr Pointer to memory where data should be written 292 | * \param ndata Number of unsigned integers to read 293 | * \param xfp Handle to portable binary file, created with xdrfile_open() 294 | * 295 | * \return Number of unsigned integers read 296 | * 297 | * The integer data type is assumed to be less than or equal to 32 bits. 298 | * 299 | * We do not provide any routines for reading/writing 64-bit integers, since 300 | * - Not all XDR implementations support it 301 | * - Not all machines have 64-bit integers 302 | * 303 | * Split your 64-bit data into two 32-bit integers for portability! 304 | */ 305 | int 306 | xdrfile_read_uint(unsigned int * ptr, 307 | int ndata, 308 | XDRFILE * xfp); 309 | 310 | 311 | 312 | /*! \brief Write one or more \a unsigned \a integer type variable(s) 313 | * 314 | * \param ptr Pointer to memory where data should be read 315 | * \param ndata Number of unsigned integers to write. 316 | * \param xfp Handle to portable binary file, created with xdrfile_open() 317 | * 318 | * \return Number of unsigned integers written 319 | * 320 | * The integer data type is assumed to be less than or equal to 32 bits. 321 | * 322 | * We do not provide any routines for reading/writing 64-bit integers, since 323 | * - Not all XDR implementations support it 324 | * - Not all machines have 64-bit integers 325 | * 326 | * Split your 64-bit data into two 32-bit integers for portability! 327 | */ 328 | int 329 | xdrfile_write_uint(unsigned int * ptr, 330 | int ndata, 331 | XDRFILE * xfp); 332 | 333 | 334 | 335 | /*! \brief Read one or more \a float type variable(s) 336 | * 337 | * \param ptr Pointer to memory where data should be written 338 | * \param ndata Number of floats to read 339 | * \param xfp Handle to portable binary file, created with xdrfile_open() 340 | * 341 | * \return Number of floats read 342 | */ 343 | int 344 | xdrfile_read_float(float * ptr, 345 | int ndata, 346 | XDRFILE * xfp); 347 | 348 | 349 | 350 | /*! \brief Write one or more \a float type variable(s) 351 | * 352 | * \param ptr Pointer to memory where data should be read 353 | * \param ndata Number of floats to write. 354 | * \param xfp Handle to portable binary file, created with xdrfile_open() 355 | * 356 | * \return Number of floats written 357 | */ 358 | int 359 | xdrfile_write_float(float * ptr, 360 | int ndata, 361 | XDRFILE * xfp); 362 | 363 | 364 | 365 | /*! \brief Read one or more \a double type variable(s) 366 | * 367 | * \param ptr Pointer to memory where data should be written 368 | * \param ndata Number of doubles to read 369 | * \param xfp Handle to portable binary file, created with xdrfile_open() 370 | * 371 | * \return Number of doubles read 372 | */ 373 | int 374 | xdrfile_read_double(double * ptr, 375 | int ndata, 376 | XDRFILE * xfp); 377 | 378 | 379 | 380 | /*! \brief Write one or more \a double type variable(s) 381 | * 382 | * \param ptr Pointer to memory where data should be read 383 | * \param ndata Number of double to write. 384 | * \param xfp Handle to portable binary file, created with xdrfile_open() 385 | * 386 | * \return Number of doubles written 387 | */ 388 | int 389 | xdrfile_write_double(double * ptr, 390 | int ndata, 391 | XDRFILE * xfp); 392 | 393 | 394 | 395 | /*! \brief Read a string (array of characters) 396 | * 397 | * \param ptr Pointer to memory where data should be written 398 | * \param maxlen Maximum length of string. If no end-of-string is encountered, 399 | * one byte less than this is read and end-of-string appended. 400 | * \param xfp Handle to portable binary file, created with xdrfile_open() 401 | * 402 | * \return Number of characters read, including end-of-string 403 | */ 404 | int 405 | xdrfile_read_string(char * ptr, 406 | int maxlen, 407 | XDRFILE * xfp); 408 | 409 | 410 | 411 | /*! \brief Write a string (array of characters) 412 | * 413 | * \param ptr Pointer to memory where data should be read 414 | * \param xfp Handle to portable binary file, created with xdrfile_open() 415 | * 416 | * \return Number of characters written, including end-of-string 417 | */ 418 | int 419 | xdrfile_write_string(char * ptr, 420 | XDRFILE * xfp); 421 | 422 | 423 | 424 | /*! \brief Read raw bytes from file (unknown datatype) 425 | * 426 | * \param ptr Pointer to memory where data should be written 427 | * \param nbytes Number of bytes to read. No conversion whatsoever is done. 428 | * \param xfp Handle to portable binary file, created with xdrfile_open() 429 | * 430 | * \return Number of bytes read from file 431 | */ 432 | int 433 | xdrfile_read_opaque(char * ptr, 434 | int nbytes, 435 | XDRFILE * xfp); 436 | 437 | 438 | 439 | 440 | /*! \brief Write raw bytes to file (unknown datatype) 441 | * 442 | * \param ptr Pointer to memory where data should be read 443 | * \param nbytes Number of bytes to write. No conversion whatsoever is done. 444 | * \param xfp Handle to portable binary file, created with xdrfile_open() 445 | * 446 | * \return Number of bytes written to file 447 | */ 448 | int 449 | xdrfile_write_opaque(char * ptr, 450 | int nbytes, 451 | XDRFILE * xfp); 452 | 453 | 454 | 455 | 456 | 457 | 458 | /*! \brief Compress coordiates in a float array to XDR file 459 | * 460 | * This routine will perform \a lossy compression on the three-dimensional 461 | * coordinate data data specified and store it in the XDR file. 462 | * 463 | * The lossy part of the compression consists of multiplying each 464 | * coordinate with the precision argument and then rounding to integers. 465 | * We suggest a default value of 1000.0, which means you are guaranteed 466 | * three decimals of accuracy. The only limitation is that scaled coordinates 467 | * must still fit in an integer variable, so if the precision is 1000.0 the 468 | * coordinate magnitudes must be less than +-2e6. 469 | * 470 | * \param ptr Pointer to coordinates to compress (length 3*ncoord) 471 | * \param ncoord Number of coordinate triplets in data 472 | * \param precision Scaling factor for lossy compression. If it is <=0, 473 | * the default value of 1000.0 is used. 474 | * \param xfp Handle to portably binary file 475 | * 476 | * \return Number of coordinate triplets written. 477 | * IMPORTANT: Check that this is equal to ncoord - if it is 478 | * negative, an error occured. This should not happen with 479 | * normal data, but if your coordinates are NaN or very 480 | * large (>1e6) it is not possible to use the compression. 481 | * 482 | * \warning The compression algorithm is not part of the XDR standard, 483 | * and very complicated, so you will need this xdrfile module 484 | * to read it later. 485 | */ 486 | int 487 | xdrfile_compress_coord_float(float * ptr, 488 | int ncoord, 489 | float precision, 490 | XDRFILE * xfp); 491 | 492 | 493 | 494 | 495 | /*! \brief Decompress coordiates from XDR file to array of floats 496 | * 497 | * This routine will decompress three-dimensional coordinate data previously 498 | * stored in an XDR file and store it in the specified array of floats. 499 | * 500 | * The precision used during the earlier compression is read from the file 501 | * and returned - you cannot adjust the accuracy at this stage. 502 | * 503 | * \param ptr Pointer to coordinates to compress (length>= 3*ncoord) 504 | * \param ncoord Max number of coordinate triplets to read on input, actual 505 | * number of coordinate triplets read on return. If this 506 | * is smaller than the number of coordinates in the frame an 507 | * error will occur. 508 | * \param precision The precision used in the previous compression will be 509 | * written to this variable on return. 510 | * \param xfp Handle to portably binary file 511 | * 512 | * \return Number of coordinate triplets read. If this is negative, 513 | * an error occured. 514 | * 515 | * \warning Since we cannot count on being able to set/get the 516 | * position of large files (>2Gb), it is not possible to 517 | * recover from errors by re-reading the frame if the 518 | * storage area you provided was too small. To avoid this 519 | * from happening, we recommend that you store the number of 520 | * coordinates triplet as an integer either in a header or 521 | * just before the compressed coordinate data, so you can 522 | * read it first and allocated enough memory. 523 | */ 524 | int 525 | xdrfile_decompress_coord_float(float * ptr, 526 | int * ncoord, 527 | float * precision, 528 | XDRFILE * xfp); 529 | 530 | 531 | 532 | 533 | /*! \brief Compress coordiates in a double array to XDR file 534 | * 535 | * This routine will perform \a lossy compression on the three-dimensional 536 | * coordinate data data specified and store it in the XDR file. Double will 537 | * NOT give you any extra precision since the coordinates are compressed. This 538 | * routine just avoids allocating a temporary array of floats. 539 | * 540 | * The lossy part of the compression consists of multiplying each 541 | * coordinate with the precision argument and then rounding to integers. 542 | * We suggest a default value of 1000.0, which means you are guaranteed 543 | * three decimals of accuracy. The only limitation is that scaled coordinates 544 | * must still fit in an integer variable, so if the precision is 1000.0 the 545 | * coordinate magnitudes must be less than +-2e6. 546 | * 547 | * \param ptr Pointer to coordinates to compress (length 3*ncoord) 548 | * \param ncoord Number of coordinate triplets in data 549 | * \param precision Scaling factor for lossy compression. If it is <=0, the 550 | * default value of 1000.0 is used. 551 | * \param xfp Handle to portably binary file 552 | * 553 | * \return Number of coordinate triplets written. 554 | * IMPORTANT: Check that this is equal to ncoord - if it is 555 | * negative, an error occured. This should not happen with 556 | * normal data, but if your coordinates are NaN or very 557 | * large (>1e6) it is not possible to use the compression. 558 | * 559 | * \warning The compression algorithm is not part of the XDR standard, 560 | * and very complicated, so you will need this xdrfile module 561 | * to read it later. 562 | */ 563 | int 564 | xdrfile_compress_coord_double(double * ptr, 565 | int ncoord, 566 | double precision, 567 | XDRFILE * xfp); 568 | 569 | 570 | 571 | 572 | /*! \brief Decompress coordiates from XDR file to array of doubles 573 | * 574 | * This routine will decompress three-dimensional coordinate data previously 575 | * stored in an XDR file and store it in the specified array of doubles. 576 | * Double will NOT give you any extra precision since the coordinates are 577 | * compressed. This routine just avoids allocating a temporary array of floats. 578 | * 579 | * The precision used during the earlier compression is read from the file 580 | * and returned - you cannot adjust the accuracy at this stage. 581 | * 582 | * \param ptr Pointer to coordinates to compress (length>= 3*ncoord) 583 | * \param ncoord Max number of coordinate triplets to read on input, actual 584 | * number of coordinate triplets read on return. If this 585 | * is smaller than the number of coordinates in the frame an 586 | * error will occur. 587 | * \param precision The precision used in the previous compression will be 588 | * written to this variable on return. 589 | * \param xfp Handle to portably binary file 590 | * 591 | * \return Number of coordinate triplets read. If this is negative, 592 | * an error occured. 593 | * 594 | * \warning Since we cannot count on being able to set/get the 595 | * position of large files (>2Gb), it is not possible to 596 | * recover from errors by re-reading the frame if the 597 | * storage area you provided was too small. To avoid this 598 | * from happening, we recommend that you store the number of 599 | * coordinates triplet as an integer either in a header or 600 | * just before the compressed coordinate data, so you can 601 | * read it first and allocated enough memory. 602 | */ 603 | int 604 | xdrfile_decompress_coord_double(double * ptr, 605 | int * ncoord, 606 | double * precision, 607 | XDRFILE * xfp); 608 | 609 | 610 | 611 | #ifdef CPLUSPLUS 612 | } 613 | #endif 614 | 615 | #endif /* _XDRFILE_H_ */ 616 | 617 | -------------------------------------------------------------------------------- /src/xdrfile/xdrfile_c_test.c: -------------------------------------------------------------------------------- 1 | /* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- 2 | * 3 | * $Id: xdrfile_c_test.c,v 1.7 2009/05/18 09:06:38 spoel Exp $ 4 | * 5 | * Copyright (c) Erik Lindahl, David van der Spoel 2003,2004. 6 | * Coordinate compression (c) by Frans van Hoesel. 7 | * 8 | * This program is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public License 10 | * as published by the Free Software Foundation; either version 3 11 | * of the License, or (at your option) any later version. 12 | */ 13 | 14 | /* Get HAVE_RPC_XDR_H, F77_FUNC from config.h if available */ 15 | #ifdef HAVE_CONFIG_H 16 | #include 17 | #endif 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #ifdef HAVE_UNISTD 25 | #include "unistd.h" 26 | #endif 27 | 28 | /* get fixed-width types if we are using ANSI C99 */ 29 | #ifdef HAVE_STDINT_H 30 | # include 31 | #elif (defined HAVE_INTTYPES_H) 32 | # include 33 | #endif 34 | 35 | #ifdef HAVE_RPC_XDR_H 36 | # include 37 | # include 38 | #endif 39 | 40 | #include 41 | #include 42 | #include "xdrfile.h" 43 | #include "xdrfile_trr.h" 44 | #include "xdrfile_xtc.h" 45 | 46 | /* This program tests reading and writing to XDR files */ 47 | 48 | static void _die(char *msg, int line, char *file) { 49 | fprintf(stderr, "Fatal error: %s\n", msg); 50 | fprintf(stderr, "Death occurred at %s, line %d\n", file, line); 51 | exit(1); 52 | } 53 | #define die(msg) _die(msg,__LINE__,__FILE__) 54 | 55 | static void _die_r(char *msg, int result,int line, char *file) { 56 | fprintf(stderr, "Fatal error: %s\n", msg); 57 | fprintf(stderr,"result = %d\n",result); 58 | fprintf(stderr, "Death occurred at %s, line %d\n", file, line); 59 | exit(1); 60 | } 61 | #define die_r(msg,res) _die_r(msg,res,__LINE__,__FILE__) 62 | 63 | static void test_xtc() 64 | { 65 | char *testfn = "test.xtc"; 66 | XDRFILE *xd; 67 | int result,i,j,k,nframes=13; 68 | int natoms2,natoms1=173; 69 | int step2,step1=1993; 70 | float time2,time1=1097.23; 71 | matrix box2,box1; 72 | rvec *x2,*x1; 73 | float prec2,prec1=1000; 74 | float toler=1e-3; 75 | 76 | printf("Testing xtc functionality:"); 77 | for(i=0; (i toler) 125 | die("incorrect time"); 126 | if (fabs(prec2-prec1) > toler) 127 | die("incorrect precision"); 128 | for(i=0; (i toler) 131 | die("box incorrect"); 132 | for(i=0; (i toler) 135 | die("x incorrect"); 136 | } 137 | k++; 138 | } while (result == exdrOK); 139 | 140 | xdrfile_close(xd); 141 | #ifdef HAVE_UNISTD 142 | unlink(testfn); 143 | #endif 144 | printf(" PASSED\n"); 145 | } 146 | 147 | static void test_trr() 148 | { 149 | char *testfn = "test.trr"; 150 | XDRFILE *xd; 151 | int result,i,j,k,nframes=13; 152 | int natoms2,natoms1=173; 153 | int step2,step1=1993; 154 | float time2,time1=1097.23; 155 | matrix box2,box1; 156 | rvec *x2,*x1; 157 | float lambda2,lambda1=0.4; 158 | float toler=1e-3; 159 | 160 | printf("Testing trr functionality:"); 161 | for(i=0; (i toler) 206 | die("incorrect time"); 207 | if (fabs(lambda2-lambda2) > toler) 208 | die("incorrect lambda"); 209 | for(i=0; (i toler) 212 | die("box incorrect"); 213 | for(i=0; (i toler) 216 | die("x incorrect"); 217 | } 218 | 219 | xdrfile_close(xd); 220 | #ifdef HAVE_UNISTD 221 | unlink(testfn); 222 | #endif 223 | printf(" PASSED\n"); 224 | } 225 | 226 | static void test_basic() 227 | { 228 | float test_ii; // 7 significant digits 229 | double test_jj; // 16 significant digits 230 | #define EPSILON_1 1e-7 231 | #define EPSILON_2 1e-4 232 | 233 | printf("Testing basic xdrfile library:"); 234 | for (test_ii = 1.0e1; test_ii < 1.0e2; (test_ii = test_ii + pow(M_PI, 0.00011))) 235 | { 236 | 237 | #define BUFLEN 37 238 | XDRFILE *xfp; 239 | int i, j, k, len, ncoord = BUFLEN/3; 240 | char ptr[BUFLEN], *buf = "abcdefghijklmnopqrstuvwxyz"; 241 | char *testfn = "test.xdr"; 242 | unsigned char uptr[BUFLEN]; 243 | short sptr[BUFLEN], sptr2[BUFLEN]; 244 | unsigned short usptr[BUFLEN], usptr2[BUFLEN]; 245 | int iptr[BUFLEN], iptr2[BUFLEN]; 246 | unsigned int uiptr[BUFLEN], uiptr2[BUFLEN]; 247 | float fptr[BUFLEN], fptr2[BUFLEN]; 248 | double dptr[BUFLEN], dptr2[BUFLEN]; 249 | char optr[BUFLEN], optr2[BUFLEN]; 250 | #define NPREC 1 251 | 252 | float fprec[] = {234.45}; 253 | double dprec[] = {234.45}; 254 | 255 | /* Can not write a string that's on the stack since all data is 256 | treated as variables. 257 | */ 258 | len = strlen(buf) + 1; 259 | if (len >= BUFLEN) 260 | die("Increase BUFLEN"); 261 | strcpy(ptr, buf); 262 | strcpy((char *) uptr, buf); 263 | /* Initiate float arrays */ 264 | for (i = 0; (i < BUFLEN); i++) 265 | { 266 | fptr[i] = cos(i * 13.0 / M_PI); 267 | dptr[i] = sin(i * 13.0 / M_PI); 268 | } 269 | /* Initiate opaque array */ 270 | memcpy(optr, dptr, BUFLEN); 271 | 272 | /*************************************/ 273 | /* WRITING BIT */ 274 | /*************************************/ 275 | 276 | if ((xfp = xdrfile_open("test.xdr", "w")) == NULL) 277 | die("Can not open file for writing"); 278 | 279 | if (xdrfile_write_char(ptr, len, xfp) != len) 280 | die("Writing char string"); 281 | if (xdrfile_write_uchar(uptr, len, xfp) != len) 282 | die("Writing uchar string"); 283 | if (xdrfile_write_short(sptr, BUFLEN,xfp) != BUFLEN) 284 | die("Writing short array"); 285 | if (xdrfile_write_ushort(usptr, BUFLEN,xfp) != BUFLEN) 286 | die("Writing ushort array"); 287 | if (xdrfile_write_int(iptr, BUFLEN,xfp) != BUFLEN) 288 | die("Writing int array"); 289 | if (xdrfile_write_uint(uiptr, BUFLEN,xfp) != BUFLEN) 290 | die("Writing uint array"); 291 | if (xdrfile_write_float(fptr, BUFLEN,xfp) != BUFLEN) 292 | die("Writing float array"); 293 | if (xdrfile_write_double(dptr, BUFLEN,xfp) != BUFLEN) 294 | die("Writing double array"); 295 | if (xdrfile_write_string(buf, xfp) != len) 296 | die("Writing string"); 297 | if (xdrfile_write_opaque(optr, BUFLEN,xfp) != BUFLEN) 298 | die("Writing opaque"); 299 | for (k = 0; (k < NPREC); k++) { 300 | if (xdrfile_compress_coord_float(fptr, ncoord, fprec[k], xfp) 301 | != ncoord) 302 | die("Writing compress_coord_float"); 303 | if (xdrfile_compress_coord_double(dptr, ncoord, dprec[k], xfp) 304 | != ncoord) 305 | die("Writing compress_coord_double"); 306 | } 307 | if (xdrfile_close(xfp) != 0) 308 | die("Can not close xdr file"); 309 | 310 | /*************************************/ 311 | /* READING BIT */ 312 | /*************************************/ 313 | if ((xfp = xdrfile_open(testfn, "r")) == NULL) 314 | die("Can not open file for reading"); 315 | 316 | if ((xdrfile_read_char(ptr, len, xfp)) != len) 317 | die("Not the right number of chars read from string"); 318 | if (strcmp(ptr, buf) != 0) 319 | printf("did not read the expected chars"); 320 | if (xdrfile_read_uchar(uptr, len, xfp) != len) 321 | die("Not the right number of uchars read from string"); 322 | if (strcmp((char *) uptr, buf) != 0) 323 | printf("did not read the expected uchars"); 324 | if (xdrfile_read_short(sptr2, BUFLEN,xfp) != BUFLEN) 325 | die("Reading short array"); 326 | for (i = 0; (i < BUFLEN); i++) 327 | if (sptr2[i] != sptr[i]) { 328 | fprintf(stderr, "i: %5d, wrote: %10d, read: %10d\n", i, sptr[i], 329 | sptr2[i]); 330 | die("Comparing short array"); 331 | } 332 | if (xdrfile_read_ushort(usptr2, BUFLEN,xfp) != BUFLEN) 333 | die("Reading ushort array"); 334 | for (i = 0; (i < BUFLEN); i++) 335 | if (usptr2[i] != usptr[i]) { 336 | fprintf(stderr, "i: %5d, wrote: %10d, read: %10d\n", i, usptr[i], 337 | usptr2[i]); 338 | die("Comparing ushort array"); 339 | } 340 | if (xdrfile_read_int(iptr2, BUFLEN,xfp) != BUFLEN) 341 | die("Reading int array"); 342 | for (i = 0; (i < BUFLEN); i++) 343 | if (iptr2[i] != iptr[i]) { 344 | fprintf(stderr, "i: %5d, wrote: %10d, read: %10d\n", i, iptr[i], 345 | iptr2[i]); 346 | die("Comparing int array"); 347 | } 348 | if (xdrfile_read_uint(uiptr2, BUFLEN,xfp) != BUFLEN) 349 | die("Reading uint array"); 350 | for (i = 0; (i < BUFLEN); i++) 351 | if (uiptr2[i] != uiptr[i]) { 352 | fprintf(stderr, "i: %5d, wrote: %10d, read: %10d\n", i, uiptr[i], 353 | uiptr2[i]); 354 | die("Comparing uint array"); 355 | } 356 | if (xdrfile_read_float(fptr2, BUFLEN,xfp) != BUFLEN) 357 | die("Reading float array"); 358 | for (i = 0; (i < BUFLEN); i++) 359 | if (fptr2[i] != fptr[i]) { 360 | fprintf(stderr, "i: %5d, wrote: %12g, read: %12g\n", i, fptr[i], 361 | fptr2[i]); 362 | die("Comparing float array"); 363 | } 364 | if (xdrfile_read_double(dptr2, BUFLEN,xfp) != BUFLEN) 365 | die("Reading double array"); 366 | for (i = 0; (i < BUFLEN); i++) 367 | if (dptr2[i] != dptr[i]) { 368 | fprintf(stderr, "i: %5d, wrote: %12g, read: %12g\n", i, dptr[i], 369 | dptr2[i]); 370 | die("Comparing double array"); 371 | } 372 | if (xdrfile_read_string(ptr, BUFLEN,xfp) != len) 373 | die("Reading string"); 374 | if (strcmp(ptr, buf) != 0) 375 | die("Comparing strings"); 376 | if (xdrfile_read_opaque(optr2, BUFLEN,xfp) != BUFLEN) 377 | die("Reading opaque array"); 378 | for (i = 0; (i < BUFLEN); i++) 379 | if (optr2[i] != optr[i]) { 380 | fprintf(stderr, "i: %5d, wrote: %2d, read: %2d\n", i, optr[i], 381 | optr2[i]); 382 | die("Comparing opaque array"); 383 | } 384 | for (k = 0; (k < NPREC); k++) { 385 | float ff, fx; 386 | double dd, dx; 387 | int nc = ncoord; 388 | if (xdrfile_decompress_coord_float(fptr2, &nc, &ff, xfp) != ncoord) 389 | die("Reading compress_coord_float"); 390 | if (fabs(ff - fprec[k]) > EPSILON_1) 391 | { 392 | printf("Found precision %f, expected %f\n", ff, fprec[k]); 393 | die("Float precision"); 394 | } 395 | if (ff <= 0) 396 | ff = 1000; 397 | 398 | 399 | for (i = 0; (i < ncoord); i++) 400 | for (j = 0; (j < 3); j++) { 401 | fx = rint(fptr[3 * i + j] * ff) / ff; 402 | if (fabs(fx - fptr2[3 * i + j]) > EPSILON_1) { 403 | printf( "prec: %10g, i: %3d, j: %d, fx: %10g, fptr2: %12g, fptr: %12g\n", 404 | ff, i, j, fx, fptr2[3 * i + j], fptr[3 * i + j]); 405 | die("Reading decompressed float coordinates"); 406 | } 407 | } 408 | if (xdrfile_decompress_coord_double(dptr2, &nc, &dd, xfp) != ncoord) 409 | die("Reading compress_coord_double"); 410 | 411 | if (fabs(dd - dprec[k]) > EPSILON_2) 412 | die("Double precision"); 413 | 414 | for (i = 0; (i < ncoord); i++) 415 | for (j = 0; (j < 3); j++) { 416 | dx = rint(dptr[3 * i + j] * dd) / dd; 417 | if (fabs(dx - dptr2[3 * i + j]) > EPSILON_2) { 418 | printf( "prec: %10g, i: %3d, j: %d, dx: %10g, dptr2: %12g, dptr: %12g\n", 419 | dd, i, j, dx, dptr2[3 * i + j], dptr[3 * i + j]); 420 | die("Reading decompressed double coordinates"); 421 | } 422 | } 423 | } 424 | 425 | if (xdrfile_close(xfp) != 0) 426 | die("Can not close xdr file"); 427 | } 428 | #ifdef HAVE_UNISTD 429 | unlink(testfn); 430 | #endif 431 | printf(" PASSED\n"); 432 | } 433 | 434 | int main(int argc, char *argv[]) 435 | { 436 | /* Test basic stuff */ 437 | test_basic(); 438 | /* Now test writing a complete xtc file */ 439 | test_xtc(); 440 | 441 | test_trr(); 442 | 443 | return 0; 444 | } 445 | -------------------------------------------------------------------------------- /src/xdrfile/xdrfile_trr.c: -------------------------------------------------------------------------------- 1 | /* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- 2 | * 3 | * $Id: xdrfile_trr.c,v 1.7 2009/05/18 09:06:38 spoel Exp $ 4 | * 5 | * Copyright (c) Erik Lindahl, David van der Spoel 2003,2004. 6 | * Coordinate compression (c) by Frans van Hoesel. 7 | * 8 | * This program is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public License 10 | * as published by the Free Software Foundation; either version 3 11 | * of the License, or (at your option) any later version. 12 | */ 13 | 14 | #include 15 | #include 16 | 17 | #ifdef HAVE_CONFIG_H 18 | #include "config.h" 19 | #endif 20 | 21 | #include "xdrfile.h" 22 | #include "xdrfile_trr.h" 23 | 24 | #define BUFSIZE 128 25 | #define GROMACS_MAGIC 1993 26 | 27 | typedef struct /* This struct describes the order and the */ 28 | /* sizes of the structs in a trjfile, sizes are given in bytes. */ 29 | { 30 | mybool bDouble; /* Double precision? */ 31 | int ir_size; /* Backward compatibility */ 32 | int e_size; /* Backward compatibility */ 33 | int box_size; /* Non zero if a box is present */ 34 | int vir_size; /* Backward compatibility */ 35 | int pres_size; /* Backward compatibility */ 36 | int top_size; /* Backward compatibility */ 37 | int sym_size; /* Backward compatibility */ 38 | int x_size; /* Non zero if coordinates are present */ 39 | int v_size; /* Non zero if velocities are present */ 40 | int f_size; /* Non zero if forces are present */ 41 | 42 | int natoms; /* The total number of atoms */ 43 | int step; /* Current step number */ 44 | int nre; /* Backward compatibility */ 45 | float tf; /* Current time */ 46 | float lambdaf; /* Current value of lambda */ 47 | double td; /* Current time */ 48 | double lambdad; /* Current value of lambda */ 49 | } t_trnheader; 50 | 51 | static int nFloatSize(t_trnheader *sh,int *nflsz) 52 | { 53 | int nflsize=0; 54 | 55 | if (sh->box_size) 56 | nflsize = sh->box_size/(DIM*DIM); 57 | else if (sh->x_size) 58 | nflsize = sh->x_size/(sh->natoms*DIM); 59 | else if (sh->v_size) 60 | nflsize = sh->v_size/(sh->natoms*DIM); 61 | else if (sh->f_size) 62 | nflsize = sh->f_size/(sh->natoms*DIM); 63 | else 64 | return exdrHEADER; 65 | 66 | if (((nflsize != sizeof(float)) && (nflsize != sizeof(double)))) 67 | return exdrHEADER; 68 | 69 | *nflsz = nflsize; 70 | 71 | return exdrOK; 72 | } 73 | 74 | static int do_trnheader(XDRFILE *xd,mybool bRead,t_trnheader *sh) 75 | { 76 | int magic=GROMACS_MAGIC; 77 | int nflsz,slen,result; 78 | char *version = "GMX_trn_file"; 79 | char buf[BUFSIZE]; 80 | 81 | if (xdrfile_read_int(&magic,1,xd) != 1) 82 | return exdrINT; 83 | 84 | if (bRead) 85 | { 86 | if (xdrfile_read_int(&slen,1,xd) != 1) 87 | return exdrINT; 88 | if (slen != strlen(version)+1) 89 | return exdrSTRING; 90 | if (xdrfile_read_string(buf,BUFSIZE,xd) <= 0) 91 | return exdrSTRING; 92 | } 93 | else 94 | { 95 | slen = strlen(version)+1; 96 | if (xdrfile_read_int(&slen,1,xd) != 1) 97 | return exdrINT; 98 | if (xdrfile_write_string(version,xd) != (strlen(version)+1) ) 99 | return exdrSTRING; 100 | } 101 | if (xdrfile_read_int(&sh->ir_size,1,xd) != 1) 102 | return exdrINT; 103 | if (xdrfile_read_int(&sh->e_size,1,xd) != 1) 104 | return exdrINT; 105 | if (xdrfile_read_int(&sh->box_size,1,xd) != 1) 106 | return exdrINT; 107 | if (xdrfile_read_int(&sh->vir_size,1,xd) != 1) 108 | return exdrINT; 109 | if (xdrfile_read_int(&sh->pres_size,1,xd) != 1) 110 | return exdrINT; 111 | if (xdrfile_read_int(&sh->top_size,1,xd) != 1) 112 | return exdrINT; 113 | if (xdrfile_read_int(&sh->sym_size,1,xd) != 1) 114 | return exdrINT; 115 | if (xdrfile_read_int(&sh->x_size,1,xd) != 1) 116 | return exdrINT; 117 | if (xdrfile_read_int(&sh->v_size,1,xd) != 1) 118 | return exdrINT; 119 | if (xdrfile_read_int(&sh->f_size,1,xd) != 1) 120 | return exdrINT; 121 | if (xdrfile_read_int(&sh->natoms,1,xd) != 1) 122 | return exdrINT; 123 | 124 | if ((result = nFloatSize(sh,&nflsz)) != exdrOK) 125 | return result; 126 | sh->bDouble = (nflsz == sizeof(double)); 127 | 128 | if (xdrfile_read_int(&sh->step,1,xd) != 1) 129 | return exdrINT; 130 | if (xdrfile_read_int(&sh->nre,1,xd) != 1) 131 | return exdrINT; 132 | if (sh->bDouble) 133 | { 134 | if (xdrfile_read_double(&sh->td,1,xd) != 1) 135 | return exdrDOUBLE; 136 | sh->tf = sh->td; 137 | if (xdrfile_read_double(&sh->lambdad,1,xd) != 1) 138 | return exdrDOUBLE; 139 | sh->lambdaf = sh->lambdad; 140 | } 141 | else 142 | { 143 | if (xdrfile_read_float(&sh->tf,1,xd) != 1) 144 | return exdrFLOAT; 145 | sh->td = sh->tf; 146 | if (xdrfile_read_float(&sh->lambdaf,1,xd) != 1) 147 | return exdrFLOAT; 148 | sh->lambdad = sh->lambdaf; 149 | } 150 | 151 | return exdrOK; 152 | } 153 | 154 | static int do_htrn(XDRFILE *xd,mybool bRead,t_trnheader *sh, 155 | matrix box,rvec *x,rvec *v,rvec *f) 156 | { 157 | double pvd[DIM*DIM]; 158 | double *dx=NULL; 159 | float pvf[DIM*DIM]; 160 | float *fx=NULL; 161 | int i,j; 162 | 163 | if (sh->bDouble) 164 | { 165 | if (sh->box_size != 0) 166 | { 167 | if (!bRead) 168 | { 169 | for(i=0; (ivir_size != 0) 190 | { 191 | if (xdrfile_read_double(pvd,DIM*DIM,xd) != DIM*DIM) 192 | return exdrDOUBLE; 193 | } 194 | 195 | if (sh->pres_size!= 0) 196 | { 197 | if (xdrfile_read_double(pvd,DIM*DIM,xd) != DIM*DIM) 198 | return exdrDOUBLE; 199 | } 200 | 201 | if ((sh->x_size != 0) || (sh->v_size != 0) || (sh->f_size != 0)) { 202 | dx = calloc(sh->natoms*DIM,sizeof(dx[0])); 203 | if (NULL == dx) 204 | return exdrNOMEM; 205 | } 206 | if (sh->x_size != 0) 207 | { 208 | if (!bRead) 209 | { 210 | for(i=0; (inatoms); i++) 211 | for(j=0; (jnatoms*DIM,xd) == sh->natoms*DIM) 218 | { 219 | if (bRead) 220 | { 221 | for(i=0; (inatoms); i++) 222 | for(j=0; (jv_size != 0) 233 | { 234 | if (!bRead) 235 | { 236 | for(i=0; (inatoms); i++) 237 | for(j=0; (jnatoms*DIM,xd) == sh->natoms*DIM) 244 | { 245 | for(i=0; (inatoms); i++) 246 | for(j=0; (jf_size != 0) 256 | { 257 | if (!bRead) 258 | { 259 | for(i=0; (inatoms); i++) 260 | for(j=0; (jnatoms*DIM,xd) == sh->natoms*DIM) 267 | { 268 | for(i=0; (inatoms); i++) 269 | { 270 | for(j=0; (jx_size != 0) || (sh->v_size != 0) || (sh->f_size != 0)) { 283 | free(dx); 284 | } 285 | } 286 | else 287 | /* Float */ 288 | { 289 | if (sh->box_size != 0) 290 | { 291 | if (!bRead) 292 | { 293 | for(i=0; (ivir_size != 0) 318 | { 319 | if (xdrfile_read_float(pvf,DIM*DIM,xd) != DIM*DIM) 320 | return exdrFLOAT; 321 | } 322 | 323 | if (sh->pres_size!= 0) 324 | { 325 | if (xdrfile_read_float(pvf,DIM*DIM,xd) != DIM*DIM) 326 | return exdrFLOAT; 327 | } 328 | 329 | if ((sh->x_size != 0) || (sh->v_size != 0) || (sh->f_size != 0)) { 330 | fx = calloc(sh->natoms*DIM,sizeof(fx[0])); 331 | if (NULL == fx) 332 | return exdrNOMEM; 333 | } 334 | if (sh->x_size != 0) 335 | { 336 | if (!bRead) 337 | { 338 | for(i=0; (inatoms); i++) 339 | for(j=0; (jnatoms*DIM,xd) == sh->natoms*DIM) 346 | { 347 | if (bRead) 348 | { 349 | for(i=0; (inatoms); i++) 350 | for(j=0; (jv_size != 0) 359 | { 360 | if (!bRead) 361 | { 362 | for(i=0; (inatoms); i++) 363 | for(j=0; (jnatoms*DIM,xd) == sh->natoms*DIM) 370 | { 371 | for(i=0; (inatoms); i++) 372 | for(j=0; (jf_size != 0) 380 | { 381 | if (!bRead) 382 | { 383 | for(i=0; (inatoms); i++) 384 | for(j=0; (jnatoms*DIM,xd) == sh->natoms*DIM) 391 | { 392 | for(i=0; (inatoms); i++) 393 | for(j=0; (jx_size != 0) || (sh->v_size != 0) || (sh->f_size != 0)) { 401 | free(fx); 402 | } 403 | } 404 | return exdrOK; 405 | } 406 | 407 | static int do_trn(XDRFILE *xd,mybool bRead,int *step,float *t,float *lambda, 408 | matrix box,int *natoms,rvec *x,rvec *v,rvec *f) 409 | { 410 | t_trnheader *sh; 411 | int result; 412 | 413 | sh = calloc(1,sizeof(*sh)); 414 | 415 | if (!bRead) { 416 | sh->box_size = (NULL != box) ? sizeof(matrix):0; 417 | sh->x_size = ((NULL != x) ? (*natoms*sizeof(x[0])):0); 418 | sh->v_size = ((NULL != v) ? (*natoms*sizeof(v[0])):0); 419 | sh->f_size = ((NULL != f) ? (*natoms*sizeof(f[0])):0); 420 | sh->natoms = *natoms; 421 | sh->step = *step; 422 | sh->nre = 0; 423 | sh->td = *t; 424 | sh->lambdad = *lambda; 425 | sh->tf = *t; 426 | sh->lambdaf = *lambda; 427 | } 428 | if ((result = do_trnheader(xd,bRead,sh)) != exdrOK) 429 | return result; 430 | if (bRead) { 431 | *natoms = sh->natoms; 432 | *step = sh->step; 433 | *t = sh->td; 434 | *lambda = sh->lambdad; 435 | } 436 | if ((result = do_htrn(xd,bRead,sh,box,x,v,f)) != exdrOK) 437 | return result; 438 | 439 | free(sh); 440 | 441 | return exdrOK; 442 | } 443 | 444 | /************************************************************ 445 | * 446 | * The following routines are the exported ones 447 | * 448 | ************************************************************/ 449 | 450 | int read_trr_natoms(char *fn,int *natoms) 451 | { 452 | XDRFILE *xd; 453 | t_trnheader sh; 454 | int result; 455 | 456 | xd = xdrfile_open(fn,"r"); 457 | if (NULL == xd) 458 | return exdrFILENOTFOUND; 459 | if ((result = do_trnheader(xd,1,&sh)) != exdrOK) 460 | return result; 461 | xdrfile_close(xd); 462 | *natoms = sh.natoms; 463 | 464 | return exdrOK; 465 | } 466 | 467 | int write_trr(XDRFILE *xd,int natoms,int step,float t,float lambda, 468 | matrix box,rvec *x,rvec *v,rvec *f) 469 | { 470 | return do_trn(xd,0,&step,&t,&lambda,box,&natoms,x,v,f); 471 | } 472 | 473 | int read_trr(XDRFILE *xd,int natoms,int *step,float *t,float *lambda, 474 | matrix box,rvec *x,rvec *v,rvec *f) 475 | { 476 | return do_trn(xd,1,step,t,lambda,box,&natoms,x,v,f); 477 | } 478 | 479 | -------------------------------------------------------------------------------- /src/xdrfile/xdrfile_trr.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- 2 | * 3 | * $Id: xdrfile_trr.h,v 1.2 2009/05/18 09:06:38 spoel Exp $ 4 | * 5 | * Copyright (c) Erik Lindahl, David van der Spoel 2003,2004. 6 | * Coordinate compression (c) by Frans van Hoesel. 7 | * 8 | * This program is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public License 10 | * as published by the Free Software Foundation; either version 3 11 | * of the License, or (at your option) any later version. 12 | */ 13 | 14 | #ifndef _xdrfile_trr_h 15 | #define _xdrfile_trr_h 16 | 17 | #ifdef CPLUSPLUS 18 | extern "C" { 19 | #endif 20 | 21 | #include "xdrfile.h" 22 | 23 | /* All functions return exdrOK if succesfull. 24 | * (error codes defined in xdrfile.h). 25 | */ 26 | 27 | /* This function returns the number of atoms in the xtc file in *natoms */ 28 | extern int read_trr_natoms(char *fn,int *natoms); 29 | 30 | /* Read one frame of an open xtc file. If either of x,v,f,box are 31 | NULL the arrays will be read from the file but not used. */ 32 | extern int read_trr(XDRFILE *xd,int natoms,int *step,float *t,float *lambda, 33 | matrix box,rvec *x,rvec *v,rvec *f); 34 | 35 | /* Write a frame to xtc file */ 36 | extern int write_trr(XDRFILE *xd,int natoms,int step,float t,float lambda, 37 | matrix box,rvec *x,rvec *v,rvec *f); 38 | 39 | 40 | #ifdef CPLUSPLUS 41 | } 42 | #endif 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /src/xdrfile/xdrfile_xtc.c: -------------------------------------------------------------------------------- 1 | /* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- 2 | * 3 | * $Id: xdrfile_xtc.c,v 1.5 2009/05/18 09:06:38 spoel Exp $ 4 | * 5 | * Copyright (c) Erik Lindahl, David van der Spoel 2003,2004. 6 | * Coordinate compression (c) by Frans van Hoesel. 7 | * 8 | * This program is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public License 10 | * as published by the Free Software Foundation; either version 3 11 | * of the License, or (at your option) any later version. 12 | */ 13 | 14 | #include 15 | #include "xdrfile.h" 16 | #include "xdrfile_xtc.h" 17 | 18 | #define MAGIC 1995 19 | 20 | enum { FALSE, TRUE }; 21 | 22 | static int xtc_header(XDRFILE *xd,int *natoms,int *step,float *time,mybool bRead) 23 | { 24 | int result,magic,n=1; 25 | 26 | /* Note: read is same as write. He he he */ 27 | magic = MAGIC; 28 | if ((result = xdrfile_write_int(&magic,n,xd)) != n) 29 | { 30 | if (bRead) 31 | return exdrENDOFFILE; 32 | else 33 | return exdrINT; 34 | } 35 | if (magic != MAGIC) 36 | return exdrMAGIC; 37 | if ((result = xdrfile_write_int(natoms,n,xd)) != n) 38 | return exdrINT; 39 | if ((result = xdrfile_write_int(step,n,xd)) != n) 40 | return exdrINT; 41 | if ((result = xdrfile_write_float(time,n,xd)) != n) 42 | return exdrFLOAT; 43 | 44 | return exdrOK; 45 | } 46 | 47 | static int xtc_coord(XDRFILE *xd,int *natoms,matrix box,rvec *x,float *prec, 48 | mybool bRead) 49 | { 50 | int i,j,result; 51 | 52 | /* box */ 53 | result = xdrfile_read_float(box[0],DIM*DIM,xd); 54 | if (DIM*DIM != result) 55 | return exdrFLOAT; 56 | else 57 | { 58 | if (bRead) 59 | { 60 | result = xdrfile_decompress_coord_float(x[0],natoms,prec,xd); 61 | if (result != *natoms) 62 | return exdr3DX; 63 | } 64 | else 65 | { 66 | result = xdrfile_compress_coord_float(x[0],*natoms,*prec,xd); 67 | if (result != *natoms) 68 | return exdr3DX; 69 | } 70 | } 71 | return exdrOK; 72 | } 73 | 74 | int read_xtc_natoms(const char *fn,int *natoms) 75 | { 76 | XDRFILE *xd; 77 | int step,result; 78 | float time; 79 | 80 | xd = xdrfile_open(fn,"r"); 81 | if (NULL == xd) 82 | return exdrFILENOTFOUND; 83 | result = xtc_header(xd,natoms,&step,&time,TRUE); 84 | xdrfile_close(xd); 85 | 86 | return result; 87 | } 88 | 89 | int read_xtc(XDRFILE *xd, 90 | int natoms,int *step,float *time, 91 | matrix box,rvec *x,float *prec) 92 | /* Read subsequent frames */ 93 | { 94 | int result; 95 | 96 | if ((result = xtc_header(xd,&natoms,step,time,TRUE)) != exdrOK) 97 | return result; 98 | 99 | if ((result = xtc_coord(xd,&natoms,box,x,prec,1)) != exdrOK) 100 | return result; 101 | 102 | return exdrOK; 103 | } 104 | 105 | int write_xtc(XDRFILE *xd, 106 | int natoms,int step,float time, 107 | matrix box,rvec *x,float prec) 108 | /* Write a frame to xtc file */ 109 | { 110 | int result; 111 | 112 | if ((result = xtc_header(xd,&natoms,&step,&time,FALSE)) != exdrOK) 113 | return result; 114 | 115 | if ((result = xtc_coord(xd,&natoms,box,x,&prec,0)) != exdrOK) 116 | return result; 117 | 118 | return exdrOK; 119 | } 120 | -------------------------------------------------------------------------------- /src/xdrfile/xdrfile_xtc.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- 2 | * 3 | * $Id: xdrfile_xtc.h,v 1.5 2009/05/18 09:06:38 spoel Exp $ 4 | * 5 | * Copyright (c) Erik Lindahl, David van der Spoel 2003,2004. 6 | * Coordinate compression (c) by Frans van Hoesel. 7 | * 8 | * This program is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public License 10 | * as published by the Free Software Foundation; either version 3 11 | * of the License, or (at your option) any later version. 12 | */ 13 | 14 | #ifndef _xdrfile_xtc_h 15 | #define _xdrfile_xtc_h 16 | 17 | #ifdef CPLUSPLUS 18 | extern "C" { 19 | #endif 20 | 21 | #include "xdrfile.h" 22 | 23 | /* All functions return exdrOK if succesfull. 24 | * (error codes defined in xdrfile.h). 25 | */ 26 | 27 | /* This function returns the number of atoms in the xtc file in *natoms */ 28 | extern int read_xtc_natoms(const char *fn,int *natoms); 29 | 30 | /* Read one frame of an open xtc file */ 31 | extern int read_xtc(XDRFILE *xd,int natoms,int *step,float *time, 32 | matrix box,rvec *x,float *prec); 33 | 34 | /* Write a frame to xtc file */ 35 | extern int write_xtc(XDRFILE *xd, 36 | int natoms,int step,float time, 37 | matrix box,rvec *x,float prec); 38 | 39 | #ifdef CPLUSPLUS 40 | } 41 | #endif 42 | 43 | #endif 44 | --------------------------------------------------------------------------------