Skip to content

Commit c62a4bc

Browse files
authored
Add sysGmres example (#401)
* Add sysGmres example * Add getter for memspace to the ExampleHelper
1 parent 084d01a commit c62a4bc

File tree

4 files changed

+334
-0
lines changed

4 files changed

+334
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,5 @@ It is seamless from the user perspective and fixed many bugs.
6161
13. Added LUSOL direct solver, which can factorize matrices and extract factors independently of KLU.
6262

6363
14. Various Spack updates.
64+
65+
15. Added examples/sysGmres.cpp to demonstrate how to use SystemSolver with GMRES.

examples/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
add_executable(rand_gmres.exe randGmres.cpp)
1111
target_link_libraries(rand_gmres.exe PRIVATE ReSolve)
1212

13+
# Build an example with a system GMRES solver
14+
add_executable(sysGmres.exe sysGmres.cpp)
15+
target_link_libraries(sysGmres.exe PRIVATE ReSolve)
16+
1317
if(RESOLVE_USE_KLU)
1418

1519
# Build example with KLU factorization on CPU
@@ -46,6 +50,8 @@ set(installable_executables "")
4650
# Install all examples in bin directory
4751
list(APPEND installable_executables rand_gmres.exe)
4852

53+
list(APPEND installable_executables sysGmres.exe)
54+
4955
if(RESOLVE_USE_KLU)
5056
list(APPEND installable_executables kluFactor.exe kluRefactor.exe
5157
sysRefactor.exe

examples/ExampleHelper.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,18 @@ namespace ReSolve
9999
}
100100
}
101101

102+
/// Returns the configured hardware backend
102103
std::string getHardwareBackend() const
103104
{
104105
return hardware_backend_;
105106
}
106107

108+
/// Returns the configured memory space
109+
ReSolve::memory::MemorySpace getMemspace() const
110+
{
111+
return memspace_;
112+
}
113+
107114
/**
108115
* @brief Set the new linear system together with its computed solution
109116
* and compute solution error and residual norms.

examples/sysGmres.cpp

Lines changed: 319 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,319 @@
1+
/**
2+
* @file sysGmres.cpp
3+
* @author Kakeru Ueda (ueda.k.2290@m.isct.ac.jp)
4+
* @brief Example of solving a linear system with GMRES using SystemSolver.
5+
*/
6+
7+
#include <iomanip>
8+
#include <iostream>
9+
#include <string>
10+
11+
#include "ExampleHelper.hpp"
12+
#include <resolve/SystemSolver.hpp>
13+
#include <resolve/matrix/Csr.hpp>
14+
#include <resolve/matrix/io.hpp>
15+
#include <resolve/utilities/params/CliOptions.hpp>
16+
#include <resolve/vector/Vector.hpp>
17+
#include <resolve/workspace/LinAlgWorkspace.hpp>
18+
19+
// Uses ReSolve data types
20+
using namespace ReSolve;
21+
using namespace ReSolve::examples;
22+
using namespace ReSolve::memory;
23+
using vector_type = ReSolve::vector::Vector;
24+
25+
/// Prints help message describing system usage
26+
void printHelpInfo()
27+
{
28+
std::cout << "\nsysGmres.exe loads a linear system from files and solves it using GMRES.\n\n";
29+
std::cout << "Usage:\n\t./";
30+
std::cout << "sysGmres.exe -m <matrix file> -r <rhs file>\n\n";
31+
std::cout << "Optional features:\n";
32+
std::cout << "\t-b <cpu|cuda|hip> \tSelects hardware backend.\n";
33+
std::cout << "\t-h \tPrints this message.\n";
34+
std::cout << "\t-i <iter method> \tIterative method: randgmres or fgmres (default 'randgmres').\n";
35+
std::cout << "\t-g <gs method> \tGram-Schmidt method: cgs1, cgs2, or mgs (default 'cgs2').\n";
36+
std::cout << "\t-s <sketching method> \tSketching method: count or fwht (default 'count')\n";
37+
std::cout << "\t-x <flexible> \tEnable flexible: yes or no (default 'yes')\n\n";
38+
}
39+
40+
//
41+
// Forward declarations of functions
42+
//
43+
44+
/**
45+
* @brief Example of solving a linear system with GMRES using SystemSolver.
46+
*
47+
* @tparam workspace_type - Type of the workspace to use
48+
* @param[in] argc - Number of command line arguments
49+
* @param[in] argv - Command line arguments
50+
* @return 0 if the example ran successfully, 1 otherwise
51+
*/
52+
template <class workspace_type>
53+
static int sysGmres(int argc, char* argv[]);
54+
55+
/// Checks if inputs for GMRES are valid, otherwise sets defaults
56+
static void processInputs(std::string& method,
57+
std::string& gs,
58+
std::string& sketch,
59+
std::string& flexible);
60+
61+
/// Main function selects example to be run
62+
int main(int argc, char* argv[])
63+
{
64+
CliOptions options(argc, argv);
65+
66+
bool is_help = options.hasKey("-h");
67+
if (is_help)
68+
{
69+
printHelpInfo();
70+
return 0;
71+
}
72+
73+
auto opt = options.getParamFromKey("-b");
74+
if (!opt)
75+
{
76+
std::cout << "No backend option provided. Defaulting to CPU.\n";
77+
return sysGmres<ReSolve::LinAlgWorkspaceCpu>(argc, argv);
78+
}
79+
#ifdef RESOLVE_USE_CUDA
80+
else if (opt->second == "cuda")
81+
{
82+
return sysGmres<ReSolve::LinAlgWorkspaceCUDA>(argc, argv);
83+
}
84+
#endif
85+
#ifdef RESOLVE_USE_HIP
86+
else if (opt->second == "hip")
87+
{
88+
return sysGmres<ReSolve::LinAlgWorkspaceHIP>(argc, argv);
89+
}
90+
#endif
91+
else if (opt->second == "cpu")
92+
{
93+
return sysGmres<ReSolve::LinAlgWorkspaceCpu>(argc, argv);
94+
}
95+
else
96+
{
97+
std::cout << "Re::Solve is not build with support for " << opt->second;
98+
std::cout << " backend.\n";
99+
return 1;
100+
}
101+
102+
return 0;
103+
}
104+
105+
//
106+
// Definitions of functions
107+
//
108+
109+
template <class workspace_type>
110+
int sysGmres(int argc, char* argv[])
111+
{
112+
// return_code is used as a failure flag.
113+
int return_code = 0;
114+
int status = 0;
115+
116+
// Collect all CLI
117+
CliOptions options(argc, argv);
118+
119+
bool is_help = options.hasKey("-h");
120+
if (is_help)
121+
{
122+
printHelpInfo();
123+
return 0;
124+
}
125+
126+
// Read matrix file
127+
auto opt = options.getParamFromKey("-m");
128+
std::string matrix_pathname("");
129+
if (opt)
130+
{
131+
matrix_pathname = opt->second;
132+
}
133+
else
134+
{
135+
std::cout << "Incorrect input!\n";
136+
printHelpInfo();
137+
return 1;
138+
}
139+
140+
// Read right-hand-side vector file
141+
std::string rhs_pathname("");
142+
opt = options.getParamFromKey("-r");
143+
if (opt)
144+
{
145+
rhs_pathname = opt->second;
146+
}
147+
else
148+
{
149+
std::cout << "Incorrect input!\n";
150+
printHelpInfo();
151+
return 1;
152+
}
153+
154+
// Read GMRES-related options
155+
opt = options.getParamFromKey("-i");
156+
std::string method = opt ? (*opt).second : "randgmres";
157+
158+
opt = options.getParamFromKey("-g");
159+
std::string gs = opt ? (*opt).second : "cgs2";
160+
161+
opt = options.getParamFromKey("-s");
162+
std::string sketch = opt ? (*opt).second : "count";
163+
164+
opt = options.getParamFromKey("-x");
165+
std::string flexible = opt ? (*opt).second : "yes";
166+
167+
processInputs(method, gs, sketch, flexible);
168+
169+
std::cout << "Matrix file: " << matrix_pathname << "\n"
170+
<< "RHS file: " << rhs_pathname << "\n";
171+
172+
// Create workspace
173+
workspace_type workspace;
174+
workspace.initializeHandles();
175+
176+
// Create a helper object (computing errors, printing summaries, etc.)
177+
ExampleHelper<workspace_type> helper(workspace);
178+
std::string hw_backend = helper.getHardwareBackend();
179+
std::cout << "sysGmres with " << hw_backend << " backend\n";
180+
181+
// Set memory space
182+
MemorySpace memspace = helper.getMemspace();
183+
184+
// Set solver
185+
SystemSolver solver(&workspace,
186+
"none",
187+
"none",
188+
method,
189+
"ilu0",
190+
"none");
191+
192+
solver.setGramSchmidtMethod(gs);
193+
194+
// Read and open matrix and right-hand-side vector
195+
std::ifstream mat_file(matrix_pathname);
196+
if (!mat_file.is_open())
197+
{
198+
std::cout << "Failed to open matrix file: " << matrix_pathname << "\n";
199+
return 1;
200+
}
201+
std::ifstream rhs_file(rhs_pathname);
202+
if (!rhs_file.is_open())
203+
{
204+
std::cout << "Failed to open RHS file: " << rhs_pathname << "\n";
205+
return 1;
206+
}
207+
208+
bool is_expand_symmetric = true;
209+
210+
// Load system matrix and RHS vector from input files
211+
matrix::Csr* A = io::createCsrFromFile(mat_file, is_expand_symmetric);
212+
vector_type* vec_rhs = io::createVectorFromFile(rhs_file);
213+
214+
// Create solution vector
215+
vector_type* vec_x = new vector_type(A->getNumRows());
216+
vec_x->allocate(memspace);
217+
218+
if (memspace == memory::DEVICE)
219+
{
220+
// Copy data to the device
221+
A->syncData(memspace);
222+
vec_rhs->syncData(memspace);
223+
}
224+
225+
mat_file.close();
226+
rhs_file.close();
227+
228+
// Set iterative solver options
229+
solver.getIterativeSolver().setCliParam("maxit", "2500");
230+
solver.getIterativeSolver().setCliParam("tol", "1e-12");
231+
232+
status = solver.setMatrix(A);
233+
std::cout << "solver.setMatrix returned status: " << status << "\n";
234+
if (status != 0)
235+
{
236+
return_code = 1;
237+
}
238+
239+
// Set GMRES solver options
240+
if (method == "randgmres")
241+
{
242+
solver.setSketchingMethod(sketch);
243+
}
244+
solver.getIterativeSolver().setCliParam("flexible", flexible);
245+
solver.getIterativeSolver().setCliParam("restart", "200");
246+
247+
// Set up the preconditioner
248+
if (return_code == 0)
249+
{
250+
status = solver.preconditionerSetup();
251+
std::cout << "solver.preconditionerSetup returned status: " << status << "\n";
252+
if (status != 0)
253+
{
254+
return_code = 1;
255+
}
256+
}
257+
258+
// Solve the system
259+
if (return_code == 0)
260+
{
261+
status = solver.solve(vec_rhs, vec_x);
262+
std::cout << "solver.solve returned status: " << status << "\n";
263+
if (status != 0)
264+
{
265+
return_code = 1;
266+
}
267+
}
268+
269+
if (return_code == 0)
270+
{
271+
helper.resetSystem(A, vec_rhs, vec_x);
272+
273+
// Get reference to iterative solver and print results
274+
LinSolverIterative& iter_solver = solver.getIterativeSolver();
275+
helper.printIterativeSolverSummary(&iter_solver);
276+
}
277+
278+
// Free matrix/vector objects.
279+
delete A;
280+
delete vec_rhs;
281+
delete vec_x;
282+
283+
return return_code;
284+
}
285+
286+
void processInputs(std::string& method, std::string& gs, std::string& sketch, std::string& flexible)
287+
{
288+
if (method == "randgmres")
289+
{
290+
if ((sketch != "count") && (sketch != "fwht"))
291+
{
292+
std::cout << "Sketching method " << sketch << " not recognized.\n";
293+
std::cout << "Setting sketch to the default (count).\n\n";
294+
sketch = "count";
295+
}
296+
}
297+
298+
if ((method != "randgmres") && (method != "fgmres"))
299+
{
300+
std::cout << "Iterative method " << method << " not recognized.\n";
301+
std::cout << "Setting iterative solver method to the default (RANDGMRES).\n\n";
302+
method = "randgmres";
303+
}
304+
305+
if (gs != "cgs1" && gs != "cgs2" && gs != "mgs" && gs != "mgs_two_sync"
306+
&& gs != "mgs_pm")
307+
{
308+
std::cout << "Orthogonalization method " << gs << " not recognized.\n";
309+
std::cout << "Setting orthogonalization to the default (CGS2).\n\n";
310+
gs = "cgs2";
311+
}
312+
313+
if ((flexible != "yes") && (flexible != "no"))
314+
{
315+
std::cout << "Flexible option " << flexible << " not recognized.\n";
316+
std::cout << "Setting flexible to the default (yes).\n\n";
317+
flexible = "yes";
318+
}
319+
}

0 commit comments

Comments
 (0)