LifeV
MultiscaleAlgorithmBroyden.cpp
Go to the documentation of this file.
1 //@HEADER
2 /*
3 *******************************************************************************
4 
5  Copyright (C) 2004, 2005, 2007 EPFL, Politecnico di Milano, INRIA
6  Copyright (C) 2010 EPFL, Politecnico di Milano, Emory University
7 
8  This file is part of LifeV.
9 
10  LifeV is free software; you can redistribute it and/or modify
11  it under the terms of the GNU Lesser General Public License as published by
12  the Free Software Foundation, either version 3 of the License, or
13  (at your option) any later version.
14 
15  LifeV is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  Lesser General Public License for more details.
19 
20  You should have received a copy of the GNU Lesser General Public License
21  along with LifeV. If not, see <http://www.gnu.org/licenses/>.
22 
23 *******************************************************************************
24 */
25 //@HEADER
26 
27 /*!
28  * @file
29  * @brief File containing the Multiscale Broyden Algorithm
30  *
31  * @date 26-10-2009
32  * @author Cristiano Malossi <cristiano.malossi@epfl.ch>
33  *
34  * @maintainer Cristiano Malossi <cristiano.malossi@epfl.ch>
35  */
36 
37 #include <lifev/multiscale/algorithms/MultiscaleAlgorithmBroyden.hpp>
38 
39 namespace LifeV
40 {
41 namespace Multiscale
42 {
43 
44 // ===================================================
45 // Constructors & Destructor
46 // ===================================================
49  M_solver (),
50  M_jacobian (),
52  M_iterationsLimitReached ( false ),
54  M_orthogonalization ( false ),
57  M_truncate ( true )
58 {
59 
60 #ifdef HAVE_LIFEV_DEBUG
61  debugStream ( 8014 ) << "MultiscaleAlgorithmBroyden::MultiscaleAlgorithmBroyden() \n";
62 #endif
63 
64  M_type = Broyden;
65 }
66 
67 // ===================================================
68 // Multiscale Algorithm Virtual Methods
69 // ===================================================
70 void
71 MultiscaleAlgorithmBroyden::setupData ( const std::string& fileName )
72 {
73 
74 #ifdef HAVE_LIFEV_DEBUG
75  debugStream ( 8014 ) << "MultiscaleAlgorithmBroyden::setupData( fileName ) \n";
76 #endif
77 
78  // Read parameters
79  multiscaleParameterListPtr_Type solverParametersList = Teuchos::rcp ( new Teuchos::ParameterList );
80  solverParametersList = Teuchos::getParametersFromXmlFile ( fileName );
81 
82  // Set main parameters
83  setAlgorithmName ( solverParametersList->sublist ( "Multiscale", true, "" ) );
84  setAlgorithmParameters ( solverParametersList->sublist ( "Multiscale Algorithm", true, "" ) );
85 
86  // Set main parameters
87  M_solver.setCommunicator ( M_comm );
88  M_solver.setParameters ( solverParametersList->sublist ( "Linear Solver List", true, "" ) );
89 }
90 
91 void
92 MultiscaleAlgorithmBroyden::setupAlgorithm()
93 {
94 
95 #ifdef HAVE_LIFEV_DEBUG
96  debugStream ( 8014 ) << "MultiscaleAlgorithmBroyden::setupAlgorithm() \n";
97 #endif
98 
99  multiscaleAlgorithm_Type::setupAlgorithm();
100 
101 #ifdef HAVE_HDF5
102 #if ( H5_VERS_MAJOR > 1 || ( H5_VERS_MAJOR == 1 && H5_VERS_MINOR > 8 ) || ( H5_VERS_MAJOR == 1 && H5_VERS_MINOR == 8 && H5_VERS_RELEASE >= 7 ) )
103 #ifdef BROYDEN_IMPORTJACOBIAN
104  // Import Jacobian from previous simulation
105  if ( multiscaleProblemStep > 0 )
106  {
107  importJacobianFromHDF5();
108  }
109 #endif
110 #endif
111 #endif
112 }
113 
114 void
115 MultiscaleAlgorithmBroyden::subIterate()
116 {
117 
118 #ifdef HAVE_LIFEV_DEBUG
119  debugStream ( 8014 ) << "MultiscaleAlgorithmBroyden::subIterate() \n";
120 #endif
121 
122  multiscaleAlgorithm_Type::subIterate();
123 
124  // Verify tolerance
125  if ( checkResidual ( 0 ) )
126  {
127 #ifdef HAVE_HDF5
128 #if ( H5_VERS_MAJOR > 1 || ( H5_VERS_MAJOR == 1 && H5_VERS_MINOR > 8 ) || ( H5_VERS_MAJOR == 1 && H5_VERS_MINOR == 8 && H5_VERS_RELEASE >= 7 ) )
129  exportJacobianToHDF5();
130 #endif
131 #endif
132  return;
133  }
134 
135  M_multiscale->exportCouplingVariables ( *M_couplingVariables );
136 
137  multiscaleVectorPtr_Type delta ( new multiscaleVector_Type ( *M_couplingResiduals, Unique ) );
138  *delta = 0.0;
139 
140  for ( UInt subIT (1); subIT <= M_subiterationsMaximumNumber; ++subIT )
141  {
142  // Compute the Jacobian
143  if ( subIT == 1 )
144  {
145  if ( M_jacobian.get() == 0 || M_iterationsLimitReached || M_multiscale->topologyChange() )
146  {
147  assembleJacobianMatrix();
148  M_iterationsLimitReached = false;
149  }
150  }
151  else
152  {
153  broydenJacobianUpdate ( *delta );
154  }
155 
156  // Set matrix and RHS
157  M_solver.setOperator ( M_jacobian );
158  M_solver.setRightHandSide ( M_couplingResiduals );
159 
160  // Solve Newton (without changing the sign of the residual)
161  M_solver.solve ( delta );
162 
163  // Changing the sign of the solution (this is important for the broydenJacobianUpdate method)
164  *delta *= -1;
165 
166  // Update Coupling Variables using the Broyden Method
167  *M_couplingVariables += *delta;
168 
169  // Import Coupling Variables inside the coupling blocks
170  M_multiscale->importCouplingVariables ( *M_couplingVariables );
171 
172  if ( subIT >= M_iterationsLimitForReset )
173  {
174  M_iterationsLimitReached = true;
175  }
176 
177  // Verify tolerance
178  if ( checkResidual ( subIT ) )
179  {
180 #ifdef HAVE_HDF5
181 #if ( H5_VERS_MAJOR > 1 || ( H5_VERS_MAJOR == 1 && H5_VERS_MINOR > 8 ) || ( H5_VERS_MAJOR == 1 && H5_VERS_MINOR == 8 && H5_VERS_RELEASE >= 7 ) )
182  exportJacobianToHDF5();
183 #endif
184 #endif
185  return;
186  }
187  }
188 
189  save ( M_subiterationsMaximumNumber, M_couplingResiduals->norm2() );
190 
191  multiscaleErrorCheck ( Tolerance, "Broyden algorithm residual: " + number2string ( M_couplingResiduals->norm2() ) +
192  " (required: " + number2string ( M_tolerance ) + ")\n", M_multiscale->communicator() == 0 );
193 }
194 
195 void
196 MultiscaleAlgorithmBroyden::showMe()
197 {
198  if ( M_comm->MyPID() == 0 )
199  {
200  multiscaleAlgorithm_Type::showMe();
201 
202  std::cout << "Initialize as identity matrix = " << M_initializeAsIdentityMatrix << std::endl;
203  std::cout << "Reset limit = " << M_iterationsLimitForReset << std::endl;
204  std::cout << "Enable orthogonalization = " << M_orthogonalization << std::endl;
205  std::cout << "Orthogonalization memory size = " << M_orthogonalizationSize << std::endl;
206  std::cout << std::endl << std::endl;
207  }
208 }
209 
210 // ===================================================
211 // Set Methods
212 // ===================================================
213 void
214 MultiscaleAlgorithmBroyden::setAlgorithmParameters ( const multiscaleParameterList_Type& parameterList )
215 {
216  multiscaleAlgorithm_Type::setAlgorithmParameters ( parameterList );
217 
218  M_initializeAsIdentityMatrix = parameterList.get<bool> ( "Initialize as identity matrix" );
219  M_iterationsLimitForReset = static_cast <UInt> ( M_subiterationsMaximumNumber
220  * parameterList.get<Real> ( "Iterations limit for reset" ) );
221 
222  M_orthogonalization = parameterList.get<bool> ( "Orthogonalization" );
223  M_orthogonalizationSize = parameterList.get<UInt> ( "Orthogonalization size" );
224 }
225 
226 // ===================================================
227 // Private Methods
228 // ===================================================
229 void
230 MultiscaleAlgorithmBroyden::assembleJacobianMatrix()
231 {
232  // Compute the Jacobian matrix
233  M_jacobian.reset ( new multiscaleMatrix_Type ( M_couplingVariables->map(), 50 ) );
234 
235  if ( M_initializeAsIdentityMatrix )
236  {
237  M_jacobian->insertValueDiagonal ( 1 );
238  }
239  else
240  {
241  M_multiscale->exportJacobian ( *M_jacobian );
242  }
243 
244  M_jacobian->globalAssemble();
245 
246  //M_jacobian->spy( "Jacobian" );
247 
248  // Reset orthogonalization
249  M_orthogonalizationContainer.clear();
250 }
251 
252 void
253 MultiscaleAlgorithmBroyden::broydenJacobianUpdate ( const multiscaleVector_Type& delta )
254 {
255  M_jacobian->openCrsMatrix();
256 
257  // Compute the Broyden update
258  if ( M_orthogonalization )
259  {
260  // Orthogonalize the vector
261  multiscaleVector_Type orthogonalization ( delta, Unique );
262  for ( containerIterator_Type i = M_orthogonalizationContainer.begin(); i != M_orthogonalizationContainer.end() ; ++i )
263  {
264  orthogonalization -= orthogonalization.dot ( *i ) * *i;
265  }
266  orthogonalization /= orthogonalization.norm2();
267 
268  // Update orthogonalization
269  orthogonalizationUpdate ( delta );
270 
271  // Update the Jacobian
272  M_jacobian->addDyadicProduct ( ( *M_couplingResiduals ) / orthogonalization.dot ( delta ), orthogonalization );
273  }
274  else
275  {
276  // Update the Jacobian
277  //M_jacobian->addDyadicProduct( ( *M_couplingResiduals + minusCouplingResidual - *M_jacobian * delta ) / delta.dot( delta ), delta );
278  M_jacobian->addDyadicProduct ( ( *M_couplingResiduals ) / delta.dot ( delta ), delta );
279  }
280 
281  M_jacobian->globalAssemble();
282 
283  //M_jacobian->spy( "Jacobian" );
284 }
285 
286 void
287 MultiscaleAlgorithmBroyden::orthogonalizationUpdate ( const multiscaleVector_Type& delta )
288 {
289  if ( M_orthogonalizationContainer.size() < M_orthogonalizationSize )
290  {
291  M_orthogonalizationContainer.push_back ( delta );
292  }
293  else
294  {
295  M_orthogonalizationContainer.pop_front();
296  M_orthogonalizationContainer.push_back ( delta );
297  }
298 }
299 
300 #ifdef HAVE_HDF5
301 
302 void
303 MultiscaleAlgorithmBroyden::exportJacobianToHDF5()
304 {
305  // If no coupling variable are present, the Jacobian is 0x0
306  if ( M_couplingVariables->size() == 0 )
307  {
308  return;
309  }
310 
311  if ( M_multiscale->globalData()->dataTime()->timeStepNumber() % multiscaleSaveEachNTimeSteps == 0 || M_multiscale->globalData()->dataTime()->isLastTimeStep() )
312  if ( M_jacobian.get() != nullptr )
313  {
314  if ( M_comm->MyPID() == 0 )
315  {
316  std::cout << " MS- Exporting Jacobian matrix ... " << std::flush;
317  }
318 
319  LifeChrono exportJacobianChrono;
320  exportJacobianChrono.start();
321 
322  M_jacobian->exportToHDF5 ( multiscaleProblemFolder + multiscaleProblemPrefix + "_AlgorithmJacobian" + "_" + number2string ( multiscaleProblemStep ), number2string ( M_multiscale->globalData()->dataTime()->timeStepNumber() ), M_truncate );
323  M_truncate = false;
324 
325  exportJacobianChrono.stop();
326  Real jacobianChrono ( exportJacobianChrono.globalDiff ( *M_comm ) );
327  if ( M_comm->MyPID() == 0 )
328  {
329  std::cout << "done in " << jacobianChrono << " s." << std::endl;
330  }
331 
332  //M_jacobian->spy( multiscaleProblemFolder + multiscaleProblemPrefix + "_AlgorithmJacobianBroydenExported" + "_" + number2string( multiscaleProblemStep ) + "_" + number2string( M_multiscale->globalData()->dataTime()->timeStepNumber() ) );
333  }
334 }
335 
336 void
337 MultiscaleAlgorithmBroyden::importJacobianFromHDF5()
338 {
339  // If no coupling variable are present, the Jacobian is 0x0
340  if ( M_couplingVariables->size() == 0 )
341  {
342  return;
343  }
344 
345  if ( M_comm->MyPID() == 0 )
346  {
347  std::cout << " MS- Importing Jacobian matrix " << std::flush;
348  }
349 
350  LifeChrono importJacobianChrono;
351  importJacobianChrono.start();
352 
353  M_jacobian.reset ( new multiscaleMatrix_Type ( M_couplingVariables->map(), 50 ) );
354  M_jacobian->importFromHDF5 ( multiscaleProblemFolder + multiscaleProblemPrefix + "_AlgorithmJacobian" + "_" + number2string ( multiscaleProblemStep - 1 ), number2string ( M_multiscale->globalData()->dataTime()->timeStepNumber() ) );
355 
356  importJacobianChrono.stop();
357  Real jacobianChrono ( importJacobianChrono.globalDiff ( *M_comm ) );
358  if ( M_comm->MyPID() == 0 )
359  {
360  std::cout << "done in " << jacobianChrono << " s. (Time " << M_multiscale->globalData()->dataTime()->time() << ", Iteration " << M_multiscale->globalData()->dataTime()->timeStepNumber() << ")" << std::endl;
361  }
362 
363  //M_jacobian->spy( multiscaleProblemFolder + multiscaleProblemPrefix + "_AlgorithmJacobianImported" + "_" + number2string( multiscaleProblemStep ) + "_" + number2string( timeInteger ) );
364 }
365 
366 #endif
367 
368 } // Namespace Multiscale
369 } // Namespace LifeV
void importJacobianFromHDF5()
Import Jacobian matrix from an HDF5 file.
void setupData(const std::string &fileName)
Setup the data of the algorithm using a data file.
MultiscaleAlgorithm multiscaleAlgorithm_Type
LinearSolver::parameterListPtr_Type multiscaleParameterListPtr_Type