Compadre  1.5.9
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Compadre_LinearAlgebra_Definitions.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Compadre: COMpatible PArticle Discretization and REmap Toolkit
4 //
5 // Copyright 2018 NTESS and the Compadre contributors.
6 // SPDX-License-Identifier: BSD-2-Clause
7 // *****************************************************************************
8 // @HEADER
9 #ifndef _COMPADRE_LINEAR_ALGEBRA_DEFINITIONS_HPP_
10 #define _COMPADRE_LINEAR_ALGEBRA_DEFINITIONS_HPP_
11 
13 
14 namespace Compadre {
15 namespace GMLS_LinearAlgebra {
16 
17 KOKKOS_INLINE_FUNCTION
18 void largestTwoEigenvectorsThreeByThreeSymmetric(const member_type& teamMember, scratch_matrix_right_type V, scratch_matrix_right_type PtP, const int dimensions, pool_type& random_number_pool) {
19 
20  Kokkos::single(Kokkos::PerTeam(teamMember), [&] () {
21 
22  double maxRange = 100;
23 
24  generator_type rand_gen = random_number_pool.get_state();
25  // put in a power method here and a deflation by first found eigenvalue
26  double eigenvalue_relative_tolerance = 1e-6; // TODO: use something smaller, but really anything close is acceptable for this manifold
27 
28 
29  double v[3] = {rand_gen.drand(maxRange),rand_gen.drand(maxRange),rand_gen.drand(maxRange)};
30  double v_old[3] = {v[0], v[1], v[2]};
31 
32  double error = 1;
33  double norm_v;
34 
35  while (error > eigenvalue_relative_tolerance) {
36 
37  double tmp1 = v[0];
38  v[0] = PtP(0,0)*tmp1 + PtP(0,1)*v[1];
39  if (dimensions>2) v[0] += PtP(0,2)*v[2];
40 
41  double tmp2 = v[1];
42  v[1] = PtP(1,0)*tmp1 + PtP(1,1)*tmp2;
43  if (dimensions>2) v[1] += PtP(1,2)*v[2];
44 
45  if (dimensions>2)
46  v[2] = PtP(2,0)*tmp1 + PtP(2,1)*tmp2 + PtP(2,2)*v[2];
47 
48  norm_v = v[0]*v[0] + v[1]*v[1];
49  if (dimensions>2) norm_v += v[2]*v[2];
50  norm_v = std::sqrt(norm_v);
51 
52  v[0] = v[0] / norm_v;
53  v[1] = v[1] / norm_v;
54  if (dimensions>2) v[2] = v[2] / norm_v;
55 
56  error = (v[0]-v_old[0])*(v[0]-v_old[0]) + (v[1]-v_old[1])*(v[1]-v_old[1]);
57  if (dimensions>2) error += (v[2]-v_old[2])*(v[2]-v_old[2]);
58  error = std::sqrt(error);
59  error /= norm_v;
60 
61 
62  v_old[0] = v[0];
63  v_old[1] = v[1];
64  if (dimensions>2) v_old[2] = v[2];
65  }
66 
67  double dot_product;
68  double norm;
69 
70  // if 2D, orthonormalize second vector
71  if (dimensions==2) {
72 
73  for (int i=0; i<2; ++i) {
74  V(0,i) = v[i];
75  }
76 
77  // orthonormalize second eigenvector against first
78  V(1,0) = 1.0; V(1,1) = 1.0;
79  dot_product = V(0,0)*V(1,0) + V(0,1)*V(1,1);
80  V(1,0) -= dot_product*V(0,0);
81  V(1,1) -= dot_product*V(0,1);
82 
83  norm = std::sqrt(V(1,0)*V(1,0) + V(1,1)*V(1,1));
84  V(1,0) /= norm;
85  V(1,1) /= norm;
86 
87  } else { // otherwise, work on second eigenvalue
88 
89  for (int i=0; i<3; ++i) {
90  V(0,i) = v[i];
91  for (int j=0; j<3; ++j) {
92  PtP(i,j) -= norm_v*v[i]*v[j];
93  }
94  }
95 
96  error = 1;
97  v[0] = rand_gen.drand(maxRange); v[1] = rand_gen.drand(maxRange); v[2] = rand_gen.drand(maxRange);
98  v_old[0] = v[0]; v_old[1] = v[1]; v_old[2] =v[2];
99  while (error > eigenvalue_relative_tolerance) {
100 
101  double tmp1 = v[0];
102  v[0] = PtP(0,0)*tmp1 + PtP(0,1)*v[1] + PtP(0,2)*v[2];
103 
104  double tmp2 = v[1];
105  v[1] = PtP(1,0)*tmp1 + PtP(1,1)*tmp2 + PtP(1,2)*v[2];
106 
107  v[2] = PtP(2,0)*tmp1 + PtP(2,1)*tmp2 + PtP(2,2)*v[2];
108 
109  norm_v = std::sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
110 
111  v[0] = v[0] / norm_v;
112  v[1] = v[1] / norm_v;
113  v[2] = v[2] / norm_v;
114 
115  error = std::sqrt((v[0]-v_old[0])*(v[0]-v_old[0]) + (v[1]-v_old[1])*(v[1]-v_old[1]) + (v[2]-v_old[2])*(v[2]-v_old[2])) / norm_v;
116 
117  v_old[0] = v[0];
118  v_old[1] = v[1];
119  v_old[2] = v[2];
120  }
121 
122  for (int i=0; i<3; ++i) {
123  V(1,i) = v[i];
124  }
125 
126  // orthonormalize second eigenvector against first
127  dot_product = V(0,0)*V(1,0) + V(0,1)*V(1,1) + V(0,2)*V(1,2);
128 
129  V(1,0) -= dot_product*V(0,0);
130  V(1,1) -= dot_product*V(0,1);
131  V(1,2) -= dot_product*V(0,2);
132 
133  norm = std::sqrt(V(1,0)*V(1,0) + V(1,1)*V(1,1) + V(1,2)*V(1,2));
134  V(1,0) /= norm;
135  V(1,1) /= norm;
136  V(1,2) /= norm;
137 
138  // get normal from cross product
139  V(2,0) = V(0,1)*V(1,2) - V(1,1)*V(0,2);
140  V(2,1) = V(1,0)*V(0,2) - V(0,0)*V(1,2);
141  V(2,2) = V(0,0)*V(1,1) - V(1,0)*V(0,1);
142 
143  // orthonormalize third eigenvector (just to be sure)
144  norm = std::sqrt(V(2,0)*V(2,0) + V(2,1)*V(2,1) + V(2,2)*V(2,2));
145  V(2,0) /= norm;
146  V(2,1) /= norm;
147  V(2,2) /= norm;
148 
149  }
150 
151  random_number_pool.free_state(rand_gen);
152  });
153 
154 }
155 
156 } // GMLS_LinearAlgebra
157 } // Compadre
158 
159 #endif
160 
pool_type::generator_type generator_type
team_policy::member_type member_type
KOKKOS_INLINE_FUNCTION void largestTwoEigenvectorsThreeByThreeSymmetric(const member_type &teamMember, scratch_matrix_right_type V, scratch_matrix_right_type PtP, const int dimensions, pool_type &random_number_pool)
Calculates two eigenvectors corresponding to two dominant eigenvalues.
Kokkos::View< double **, layout_right, Kokkos::MemoryTraits< Kokkos::Unmanaged > > scratch_matrix_right_type
Kokkos::Random_XorShift64_Pool pool_type