Line data Source code
1 : /*
2 : * Copyright (c) 2012-2015: G-CSC, Goethe University Frankfurt
3 : * Author: Torbjörn Klatt
4 : *
5 : * This file is part of UG4.
6 : *
7 : * UG4 is free software: you can redistribute it and/or modify it under the
8 : * terms of the GNU Lesser General Public License version 3 (as published by the
9 : * Free Software Foundation) with the following additional attribution
10 : * requirements (according to LGPL/GPL v3 §7):
11 : *
12 : * (1) The following notice must be displayed in the Appropriate Legal Notices
13 : * of covered and combined works: "Based on UG4 (www.ug4.org/license)".
14 : *
15 : * (2) The following notice must be displayed at a prominent place in the
16 : * terminal output of covered works: "Based on UG4 (www.ug4.org/license)".
17 : *
18 : * (3) The following bibliography is recommended for citation and must be
19 : * preserved in all covered files:
20 : * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively
21 : * parallel geometric multigrid solver on hierarchically distributed grids.
22 : * Computing and visualization in science 16, 4 (2013), 151-164"
23 : * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel
24 : * flexible software system for simulating pde based models on high performance
25 : * computers. Computing and visualization in science 16, 4 (2013), 165-179"
26 : *
27 : * This program is distributed in the hope that it will be useful,
28 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 : * GNU Lesser General Public License for more details.
31 : */
32 :
33 : #include "matrix_io_mtx.h"
34 :
35 : namespace ug
36 : {
37 :
38 : // /////////////////////////////////////////////////////////////////////////////
39 : // Constructor / Destructor
40 2 : MatrixIOMtx::MatrixIOMtx() :
41 2 : m_pMatFileName( NULL ), m_matFileStream(), m_firstDataLine(0),
42 : m_matFileType( MatrixFileType::MATRIX_MARKET ),
43 : m_mmTypeCode( MMTypeCode() ),
44 2 : m_rows( 0 ), m_cols( 0 ), m_lines( 0 )
45 2 : {}
46 :
47 10 : MatrixIOMtx::MatrixIOMtx( std::string mFile, int openMode ) :
48 10 : m_matFileStream(), m_firstDataLine(0),
49 : m_matFileType( MatrixFileType::MATRIX_MARKET ),
50 20 : m_mmTypeCode( MMTypeCode() ), m_rows( 0 ), m_cols( 0 ), m_lines( 0 )
51 : {
52 : PROFILE_FUNC();
53 : // set the file name
54 10 : set_mat_file_name( mFile, openMode );
55 :
56 10 : if ( openMode == MatrixIO::EXISTING ) {
57 : // read matrix type information
58 7 : query_matrix_type();
59 :
60 : // read matrix size information
61 7 : query_matrix_characteristics();
62 : }
63 10 : }
64 :
65 12 : MatrixIOMtx::~MatrixIOMtx()
66 : {
67 12 : close_file();
68 23 : delete m_pMatFileName;
69 12 : }
70 :
71 : // /////////////////////////////////////////////////////////////////////////////
72 : // Public Functions
73 11 : void MatrixIOMtx::set_mat_file_name( std::string mFile, int openMode )
74 : {
75 : PROFILE_FUNC();
76 11 : if( !mFile.empty() ) {
77 11 : if ( openMode == MatrixIO::EXISTING ) {
78 : UG_ASSERT( FileExists( mFile.c_str() ),
79 : "File " << mFile.c_str() << " could not be found." );
80 3 : } else if( openMode == MatrixIO::NEW ) {
81 3 : std::ofstream createFile;
82 3 : createFile.open( mFile.c_str(), std::ios_base::out );
83 : UG_ASSERT( createFile.is_open(), "File could not be created." );
84 3 : createFile.close();
85 3 : } else {
86 0 : UG_THROW( "Invalid open mode specified: " << openMode );
87 : }
88 22 : m_pMatFileName = new std::string( mFile );
89 : }
90 11 : }
91 :
92 1 : std::string MatrixIOMtx::get_mat_file_name() const
93 : {
94 1 : return std::string( *m_pMatFileName );
95 : }
96 :
97 10 : void MatrixIOMtx::set_mat_dims( size_t rows, size_t cols, size_t lines )
98 : {
99 : PROFILE_FUNC();
100 : UG_ASSERT( rows > 0, "Number rows must be positive." );
101 : UG_ASSERT( cols > 0, "Number columns must be positive." );
102 : UG_ASSERT( lines > 0, "Number data lines must be positive." );
103 :
104 10 : m_rows = rows;
105 10 : m_cols = cols;
106 10 : m_lines = lines;
107 10 : }
108 :
109 4 : size_t MatrixIOMtx::get_num_rows() const
110 : {
111 4 : return (size_t)m_rows;
112 : }
113 :
114 4 : size_t MatrixIOMtx::get_num_cols() const
115 : {
116 4 : return (size_t)m_cols;
117 : }
118 :
119 4 : size_t MatrixIOMtx::get_num_lines() const
120 : {
121 4 : return (size_t)m_lines;
122 : }
123 :
124 15722 : bool MatrixIOMtx::is_sparse() const
125 : {
126 15722 : return m_mmTypeCode.is_sparse();
127 : }
128 :
129 :
130 : // /////////////////////////////////////////////////////////////////////////////
131 : // Private Functions
132 26 : void MatrixIOMtx::open_file( std::ios_base::openmode mode )
133 : {
134 : UG_ASSERT( !m_pMatFileName->empty(), "Matrix File not set." );
135 :
136 : UG_ASSERT( !m_matFileStream.is_open(), "File alread open." );
137 :
138 26 : m_matFileStream.open( m_pMatFileName->c_str(), mode );
139 : UG_ASSERT( !m_matFileStream.fail() || !m_matFileStream.bad(),
140 : "Matrix File could not be opend for reading/writing.\n"
141 : << "iostate: " << m_matFileStream.rdstate() );
142 26 : }
143 :
144 38 : void MatrixIOMtx::close_file()
145 : {
146 38 : if( m_matFileStream.is_open() ) {
147 : // m_pMatFileStream->flush();
148 26 : m_matFileStream.close();
149 : }
150 38 : }
151 :
152 7 : void MatrixIOMtx::query_matrix_type()
153 : {
154 : PROFILE_FUNC();
155 : // open the file
156 7 : open_file();
157 :
158 7 : std::stringstream first_line;
159 : // make sure we are at the beginning of the file
160 7 : m_matFileStream.seekg( 0 );
161 :
162 : // get the first line
163 : std::string s;
164 7 : std::getline( m_matFileStream, s );
165 : first_line.str( s );
166 :
167 : // split the line into its specified parts
168 7 : std::string buffer_str = "";
169 : std::vector<std::string> banner_items;
170 42 : while( first_line >> buffer_str ) {
171 35 : banner_items.push_back( buffer_str );
172 : };
173 :
174 : // and make sure the file is a valid MatrixMarket file
175 : // a) Banner
176 : UG_ASSERT( banner_items.at( 0 ).compare( MM_BANNER_STR ) == 0,
177 : "Given file is not a valid Matrix Market file.\n\t"
178 : << "First line must start with '" << MM_BANNER_STR
179 : << "' and not with '" << banner_items.at( 0 ) << "'." );
180 : // b) matrix
181 : UG_ASSERT( banner_items.at( 1 ).compare( MM_MTX_STR ) == 0,
182 : "Given file is not a valid Matrix Market file.\n\t"
183 : << "First line must contain '" << MM_MTX_STR
184 : << "' as second element and not '" << banner_items.at( 1 ) << "'." );
185 :
186 : // c) coordinate / array
187 21 : m_mmTypeCode.set_class_type( banner_items.at( 2 ) );
188 :
189 : // d) data type
190 14 : m_mmTypeCode.set_numeric_type( banner_items.at( 3 ) );
191 :
192 : // e) algebraic type
193 7 : m_mmTypeCode.set_algebraic_type( banner_items.at( 4 ) );
194 :
195 : // close it
196 7 : close_file();
197 14 : }
198 :
199 7 : void MatrixIOMtx::query_matrix_characteristics()
200 : {
201 : PROFILE_FUNC();
202 : // open the file
203 7 : open_file();
204 :
205 : // reach end of comments
206 : std::string str;
207 : do {
208 : UG_ASSERT( !m_matFileStream.eof(), "Unexpected end of file." );
209 14 : std::getline( m_matFileStream, str );
210 14 : m_firstDataLine++;
211 14 : } while( str.at( 0 ) == '%' );
212 :
213 : // get next non-empty line
214 : while( str.empty() ) {
215 : UG_ASSERT( !m_matFileStream.eof(), "Unexpected end of file." );
216 : std::getline( m_matFileStream, str );
217 : m_firstDataLine++;
218 : }
219 :
220 : // split the line
221 : std::vector<std::string> entriesVec;
222 7 : if( m_mmTypeCode.is_sparse() ) {
223 14 : boost::algorithm::split( entriesVec, str, boost::is_any_of( " " ),
224 : boost::algorithm::token_compress_on );
225 : } else {
226 0 : UG_THROW( "Other than sparse MatrixMarket matrices are not yet implemented." );
227 : }
228 :
229 14 : set_mat_dims( boost::lexical_cast<int>( entriesVec.at( 0 ) ),
230 7 : boost::lexical_cast<int>( entriesVec.at( 1 ) ),
231 7 : boost::lexical_cast<int>( entriesVec.at( 2 ) ) );
232 :
233 : // close the file
234 7 : close_file();
235 14 : }
236 :
237 :
238 : //template<typename matrix_type>
239 : // std::vector< std::vector<size_t> > determine_matrix_characteristics(const matrix_type &matrix );
240 :
241 15722 : void MatrixIOMtx::read_entry( size_t *m, size_t *n,
242 : CPUAlgebra::matrix_type::value_type *val )
243 : {
244 : PROFILE_FUNC();
245 : // make sure, the file is open
246 : UG_ASSERT( m_matFileStream.is_open(), "File is not open." );
247 :
248 : // get the data line and split it
249 : std::string line;
250 15722 : std::getline( m_matFileStream, line );
251 : std::vector<std::string> elements;
252 15722 : boost::algorithm::split( elements, line, boost::is_any_of(" "), boost::algorithm::token_compress_on );
253 :
254 : // parse it according to the matrix type
255 15722 : if( is_sparse() ) {
256 : UG_ASSERT( elements.size() == 3,
257 : "Sparse matrix requires three values per line. Found: "
258 : << elements.size() );
259 15722 : *m = boost::lexical_cast<size_t>( elements.at( 0 ) );
260 15722 : *n = boost::lexical_cast<size_t>( elements.at( 1 ) );
261 15722 : *val = boost::lexical_cast<CPUAlgebra::matrix_type::value_type>( elements.at( 2 ) );
262 : } else {
263 0 : UG_THROW( "Other than sparse MatrixMarket matrices are not yet implemented." );
264 : }
265 31444 : }
266 :
267 3 : void MatrixIOMtx::write_banner()
268 : {
269 : // Write the first lines (banner, comment, characteristics)
270 3 : open_file( std::ios_base::out | std::ios_base::trunc );
271 :
272 : // print out the banner
273 : m_matFileStream << MM_BANNER_STR << " " << MM_MTX_STR << " "
274 6 : << MM_COORDINATE_STR << " " << MM_REAL_STR << " ";
275 3 : if ( m_mmTypeCode.is_general() ) {
276 1 : m_matFileStream << MM_GENERAL_STR;
277 2 : } else if ( m_mmTypeCode.is_symmetric() ) {
278 1 : m_matFileStream << MM_SYMMETRIC_STR;
279 1 : } else if ( m_mmTypeCode.is_skew_symmetric() ) {
280 1 : m_matFileStream << MM_SKEW_STR;
281 : }
282 3 : m_matFileStream << "\n";
283 :
284 3 : close_file();
285 3 : }
286 :
287 7861 : void MatrixIOMtx::write_entry( size_t m, size_t n ,
288 : CPUAlgebra::matrix_type::value_type val )
289 : {
290 : PROFILE_FUNC();
291 : UG_ASSERT( m_matFileStream.is_open(), "File is not open." );
292 : UG_ASSERT( m > 0, "Row index not positive." );
293 : UG_ASSERT( n > 0, "Column index not positive." );
294 : m_matFileStream.unsetf( std::ios_base::scientific );
295 7861 : m_matFileStream << m << " " << n;
296 10430 : m_matFileStream << ( (val < 0) ? " " : " " );
297 : m_matFileStream.setf( std::ios_base::scientific);
298 : m_matFileStream << std::setprecision(13);
299 7861 : m_matFileStream << val << "\n";
300 7861 : m_matFileStream.flush();
301 7861 : }
302 :
303 : } // namespace ug
304 :
305 : // EOF
|