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