Skip to content

Commit b1bb2b3

Browse files
committed
a unit test for NNLSSolver::solve_parallel_with_scalapack.
1 parent e8ee2d1 commit b1bb2b3

File tree

3 files changed

+143
-1
lines changed

3 files changed

+143
-1
lines changed

.github/workflows/run_tests/action.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ runs:
2424
mpirun -n 3 --oversubscribe tests/test_StaticSVD
2525
./tests/test_IncrementalSVDBrand
2626
mpirun -n 3 --oversubscribe tests/test_IncrementalSVDBrand
27+
./tests/test_NNLS
28+
mpirun -n 3 --oversubscribe tests/test_NNLS
2729
2830
shell: bash
2931

CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,8 @@ if(GTEST_FOUND)
275275
RandomizedSVD
276276
IncrementalSVD
277277
IncrementalSVDBrand
278-
GreedyCustomSampler)
278+
GreedyCustomSampler
279+
NNLS)
279280
foreach(stem IN LISTS unit_test_stems)
280281
add_executable(test_${stem} unit_tests/test_${stem}.cpp)
281282
target_link_libraries(test_${stem} PRIVATE ROM

unit_tests/test_NNLS.cpp

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/******************************************************************************
2+
*
3+
* Copyright (c) 2013-2024, Lawrence Livermore National Security, LLC
4+
* and other libROM project developers. See the top-level COPYRIGHT
5+
* file for details.
6+
*
7+
* SPDX-License-Identifier: (Apache-2.0 OR MIT)
8+
*
9+
*****************************************************************************/
10+
11+
#ifdef CAROM_HAS_GTEST
12+
13+
#include<gtest/gtest.h>
14+
#include "linalg/NNLS.h"
15+
#include <algorithm>
16+
#include <cmath>
17+
#include <cstdio>
18+
#include <cstring> // for memcpy
19+
#include <random>
20+
#include "mpi.h"
21+
#include "utils/mpi_utils.h"
22+
23+
/**
24+
* Simple smoke test to make sure Google Test is properly linked
25+
*/
26+
TEST(GoogleTestFramework, GoogleTestFrameworkFound) {
27+
SUCCEED();
28+
}
29+
30+
TEST(NNLS, solve_nnls_with_parallel)
31+
{
32+
int nproc;
33+
int rank;
34+
MPI_Comm_size(MPI_COMM_WORLD, &nproc);
35+
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
36+
37+
const int nrow = 12;
38+
const int ncol = 18;
39+
const int ncol_local = CAROM::split_dimension(ncol);
40+
std::vector<int> row_offset(nproc + 1);
41+
const int total_cols = CAROM::get_global_offsets(ncol_local, row_offset,
42+
MPI_COMM_WORLD);
43+
const double rel_tol = 0.3;
44+
const double nnls_tol = 1.0e-11;
45+
46+
std::default_random_engine generator;
47+
generator.seed(1234); // fix the seed to keep the same result for different nproc.
48+
std::uniform_real_distribution<> uniform_distribution(0.0, 1.0);
49+
std::normal_distribution<double> normal_distribution(0.0, 1.0);
50+
51+
// distribute from a global matrix to keep the same system for different nproc.
52+
CAROM::Matrix Gt(ncol, nrow, false);
53+
for (int i = 0; i < ncol; i++)
54+
for (int j = 0; j < nrow; j++)
55+
Gt(i, j) = normal_distribution(generator);
56+
Gt.distribute(ncol_local);
57+
58+
CAROM::Vector fom_sol(ncol_local, true);
59+
CAROM::Vector rom_sol(ncol_local, true);
60+
CAROM::Vector rhs(nrow, false);
61+
62+
// distribute from a global matrix to keep the same system for different nproc.
63+
CAROM::Vector fom_sol_serial(ncol, false);
64+
for (int c = 0; c < ncol; c++)
65+
fom_sol_serial(c) = uniform_distribution(generator);
66+
for (int c = 0; c < ncol_local; c++)
67+
fom_sol(c) = fom_sol_serial(row_offset[rank] + c);
68+
69+
Gt.transposeMult(fom_sol, rhs);
70+
rom_sol = 0.0;
71+
72+
CAROM::Vector rhs_lb(rhs);
73+
CAROM::Vector rhs_ub(rhs);
74+
75+
for (int i = 0; i < rhs.dim(); ++i)
76+
{
77+
double delta = rel_tol * abs(rhs(i));
78+
rhs_lb(i) -= delta;
79+
rhs_ub(i) += delta;
80+
}
81+
82+
CAROM::NNLSSolver nnls(nnls_tol, 0, 0, 2);
83+
nnls.solve_parallel_with_scalapack(Gt, rhs_lb, rhs_ub, rom_sol);
84+
85+
int nnz = 0;
86+
for (int i = 0; i < rom_sol.dim(); ++i)
87+
{
88+
if (rom_sol(i) != 0.0)
89+
{
90+
nnz++;
91+
}
92+
}
93+
94+
std::cout << rank << ": Number of nonzeros in NNLS solution: " << nnz
95+
<< ", out of " << rom_sol.dim() << std::endl;
96+
97+
MPI_Allreduce(MPI_IN_PLACE, &nnz, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
98+
99+
if (rank == 0)
100+
std::cout << "Global number of nonzeros in NNLS solution: " << nnz << std::endl;
101+
102+
// Check residual of NNLS solution
103+
CAROM::Vector res(Gt.numColumns(), false);
104+
Gt.transposeMult(rom_sol, res);
105+
106+
const double normGsol = res.norm();
107+
const double normRHS = rhs.norm();
108+
109+
res -= rhs;
110+
const double relNorm = res.norm() / std::max(normGsol, normRHS);
111+
std::cout << rank << ": relative residual norm for NNLS solution of Gs = Gw: " <<
112+
relNorm << std::endl;
113+
114+
for (int k = 0; k < res.dim(); k++)
115+
{
116+
// printf("rank %d, error(%d): %.3e\n", rank, k, abs(res(k) / rhs(k)));
117+
EXPECT_TRUE(abs(res(k)) < rel_tol * abs(rhs(k)) + nnls_tol);
118+
}
119+
}
120+
121+
int main(int argc, char* argv[])
122+
{
123+
::testing::InitGoogleTest(&argc, argv);
124+
MPI_Init(&argc, &argv);
125+
int result = RUN_ALL_TESTS();
126+
MPI_Finalize();
127+
return result;
128+
}
129+
130+
#else // #ifndef CAROM_HAS_GTEST
131+
132+
int main()
133+
{
134+
std::cout << "libROM was compiled without Google Test support, so unit "
135+
<< "tests have been disabled. To enable unit tests, compile "
136+
<< "libROM with Google Test support." << std::endl;
137+
}
138+
139+
#endif // #endif CAROM_HAS_GTEST

0 commit comments

Comments
 (0)