BELFEM 0.9.0
Berkeley Lab Finite Element Framework
Loading...
Searching...
No Matches
fn_gees.hpp
Go to the documentation of this file.
1/*
2 * BELFEM -- The Berkeley Lab Finite Element Framework
3 * Copyright (c) 2026, The Regents of the University of California, through
4 * Lawrence Berkeley National Laboratory (subject to receipt of any required
5 * approvals from the U.S. Dept. of Energy). All rights reserved.
6 *
7 * Developers: Christian Messe, Gregory Giard
8 *
9 * See the top-level LICENSE file for the complete license and disclaimer.
10 */
11
21
22#ifndef BELFEM_FN_GEES_HPP
23#define BELFEM_FN_GEES_HPP
24
25#include "assert.hpp"
26#include "lapacktools.hpp"
27#include "cl_Vector.hpp"
28
29//------------------------------------------------------------------------------
30namespace belfem
31{
32 namespace lapack
33 {
34//------------------------------------------------------------------------------
35#ifdef __cplusplus
36 extern "C"
37 {
38#endif
39//------------------------------------------------------------------------------
40
41 // gees particularities: like geev, the real flavors return the
42 // eigenvalues as wr/wi and have no rwork, while the complex ones
43 // take one complex w plus a REAL rwork ( size n, not 2*n ). The
44 // sort callback SELECT is a Fortran LOGICAL function that takes
45 // its arguments by reference: two reals for s/d, one complex for
46 // c/z. bwork is a LOGICAL array, referenced only when sorting.
47
48 typedef int_t ( * sgees_select_t )( const float *, const float * );
49 typedef int_t ( * dgees_select_t )( const double *, const double * );
50 typedef int_t ( * cgees_select_t )( const cplx_float_t * );
51 typedef int_t ( * zgees_select_t )( const cplx_double_t * );
52
53//------------------------------------------------------------------------------
54
55 void sgees_(
56 char * jobvs,
57 char * sort,
58 sgees_select_t select,
59 int_t * n,
60 float * a,
61 int_t * lda,
62 int_t * sdim,
63 float * wr,
64 float * wi,
65 float * vs,
66 int_t * ldvs,
67 float * work,
68 int_t * lwork,
69 int_t * bwork,
70 int_t * info,
73
74//------------------------------------------------------------------------------
75
76 void dgees_(
77 char * jobvs,
78 char * sort,
79 dgees_select_t select,
80 int_t * n,
81 double * a,
82 int_t * lda,
83 int_t * sdim,
84 double * wr,
85 double * wi,
86 double * vs,
87 int_t * ldvs,
88 double * work,
89 int_t * lwork,
90 int_t * bwork,
91 int_t * info,
94
95//------------------------------------------------------------------------------
96
97 void cgees_(
98 char * jobvs,
99 char * sort,
100 cgees_select_t select,
101 int_t * n,
102 cplx_float_t * a,
103 int_t * lda,
104 int_t * sdim,
105 cplx_float_t * w,
106 cplx_float_t * vs,
107 int_t * ldvs,
108 cplx_float_t * work,
109 int_t * lwork,
110 float * rwork,
111 int_t * bwork,
112 int_t * info,
115
116//------------------------------------------------------------------------------
117
118 void zgees_(
119 char * jobvs,
120 char * sort,
121 zgees_select_t select,
122 int_t * n,
123 cplx_double_t * a,
124 int_t * lda,
125 int_t * sdim,
126 cplx_double_t * w,
127 cplx_double_t * vs,
128 int_t * ldvs,
129 cplx_double_t * work,
130 int_t * lwork,
131 double * rwork,
132 int_t * bwork,
133 int_t * info,
136
137//------------------------------------------------------------------------------
138#ifdef __cplusplus
139 }
140#endif
141//------------------------------------------------------------------------------
142
143 // user-facing select callback type: two real arguments for the real
144 // flavors, one complex argument for the complex ones ( Fortran
145 // passes by reference in both cases )
146 template< typename T >
148 {
149 typedef int_t ( * type )( const T *, const T * ) ;
150 };
151
152 template< typename R >
153 struct gees_select< std::complex< R > >
154 {
155 typedef int_t ( * type )( const std::complex< R > * ) ;
156 };
157
158 template< typename T >
160
161//------------------------------------------------------------------------------
162
163 // unified dispatch. As in geev, rwork is the real scratch: wr/wi
164 // ( 2*n ) for the real flavors, LAPACK's rwork ( n ) for the
165 // complex ones.
166
167 template< typename T >
168 void gees(
169 const char * jobvs,
170 const char * sort,
171 gees_select_t< T > select,
172 const int_t * n,
173 T * a,
174 const int_t * lda,
175 int_t * sdim,
176 cplx_t< T > * w,
177 T * vs,
178 const int_t * ldvs,
179 T * work,
180 const int_t * lwork,
181 real_t< T > * rwork,
182 int_t * bwork,
183 int_t * info )
184 {
185 static_assert( dependent_false< T >,
186 "gees not implemented for selected data type" );
187 }
188
189// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
190
191 template<>
192 inline void gees(
193 const char * jobvs,
194 const char * sort,
195 sgees_select_t select,
196 const int_t * n,
197 float * a,
198 const int_t * lda,
199 int_t * sdim,
200 std::complex< float > * w,
201 float * vs,
202 const int_t * ldvs,
203 float * work,
204 const int_t * lwork,
205 float * rwork,
206 int_t * bwork,
207 int_t * info )
208 {
209 sgees_(
210 const_cast< char * >( jobvs ),
211 const_cast< char * >( sort ),
212 select,
213 const_cast< int_t * >( n ),
214 a,
215 const_cast< int_t * >( lda ),
216 sdim,
217 rwork,
218 rwork + *n,
219 vs,
220 const_cast< int_t * >( ldvs ),
221 work,
222 const_cast< int_t * >( lwork ),
223 bwork,
224 info,
225 1, 1 );
226
227 // pack wr/wi into the complex eigenvalue vector; a workspace
228 // query does not touch wr/wi, so there is nothing to pack
229 if ( *lwork != -1 )
230 {
231 for ( int_t k = 0; k < *n; ++k )
232 {
233 w[ k ] = std::complex< float >( rwork[ k ], rwork[ k + *n ] );
234 }
235 }
236 }
237
238// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
239
240 template<>
241 inline void gees(
242 const char * jobvs,
243 const char * sort,
244 dgees_select_t select,
245 const int_t * n,
246 double * a,
247 const int_t * lda,
248 int_t * sdim,
249 std::complex< double > * w,
250 double * vs,
251 const int_t * ldvs,
252 double * work,
253 const int_t * lwork,
254 double * rwork,
255 int_t * bwork,
256 int_t * info )
257 {
258 dgees_(
259 const_cast< char * >( jobvs ),
260 const_cast< char * >( sort ),
261 select,
262 const_cast< int_t * >( n ),
263 a,
264 const_cast< int_t * >( lda ),
265 sdim,
266 rwork,
267 rwork + *n,
268 vs,
269 const_cast< int_t * >( ldvs ),
270 work,
271 const_cast< int_t * >( lwork ),
272 bwork,
273 info,
274 1, 1 );
275
276 if ( *lwork != -1 )
277 {
278 for ( int_t k = 0; k < *n; ++k )
279 {
280 w[ k ] = std::complex< double >( rwork[ k ], rwork[ k + *n ] );
281 }
282 }
283 }
284
285// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
286
287 template<>
288 inline void gees(
289 const char * jobvs,
290 const char * sort,
291 gees_select_t< std::complex< float > > select,
292 const int_t * n,
293 std::complex< float > * a,
294 const int_t * lda,
295 int_t * sdim,
296 std::complex< float > * w,
297 std::complex< float > * vs,
298 const int_t * ldvs,
299 std::complex< float > * work,
300 const int_t * lwork,
301 float * rwork,
302 int_t * bwork,
303 int_t * info )
304 {
305 cgees_(
306 const_cast< char * >( jobvs ),
307 const_cast< char * >( sort ),
308 // function-pointer type pun: the callback parameter is
309 // layout-compatible ( std::complex< float > vs
310 // cplx_float_t ), same cast direction as the data arrays;
311 // strictly UB in ISO C++, universally sound on the SysV
312 // ABI ( one pointer argument, integer-width return )
313 reinterpret_cast< cgees_select_t >( select ),
314 const_cast< int_t * >( n ),
315 reinterpret_cast< cplx_float_t * >( a ),
316 const_cast< int_t * >( lda ),
317 sdim,
318 reinterpret_cast< cplx_float_t * >( w ),
319 reinterpret_cast< cplx_float_t * >( vs ),
320 const_cast< int_t * >( ldvs ),
321 reinterpret_cast< cplx_float_t * >( work ),
322 const_cast< int_t * >( lwork ),
323 rwork,
324 bwork,
325 info,
326 1, 1 );
327 }
328
329// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
330
331 template<>
332 inline void gees(
333 const char * jobvs,
334 const char * sort,
335 gees_select_t< std::complex< double > > select,
336 const int_t * n,
337 std::complex< double > * a,
338 const int_t * lda,
339 int_t * sdim,
340 std::complex< double > * w,
341 std::complex< double > * vs,
342 const int_t * ldvs,
343 std::complex< double > * work,
344 const int_t * lwork,
345 double * rwork,
346 int_t * bwork,
347 int_t * info )
348 {
349 zgees_(
350 const_cast< char * >( jobvs ),
351 const_cast< char * >( sort ),
352 reinterpret_cast< zgees_select_t >( select ),
353 const_cast< int_t * >( n ),
354 reinterpret_cast< cplx_double_t * >( a ),
355 const_cast< int_t * >( lda ),
356 sdim,
357 reinterpret_cast< cplx_double_t * >( w ),
358 reinterpret_cast< cplx_double_t * >( vs ),
359 const_cast< int_t * >( ldvs ),
360 reinterpret_cast< cplx_double_t * >( work ),
361 const_cast< int_t * >( lwork ),
362 rwork,
363 bwork,
364 info,
365 1, 1 );
366 }
367
368//------------------------------------------------------------------------------
369 } /* end namespace lapack */
370
411 template< typename T >
412 int_t
414 Matrix< T > & A,
416 Matrix< T > & VS,
417 Vector< lapack::real_t< T > > & Work,
418 Vector< int_t > & BWork,
419 lapack::gees_select_t< T > select = nullptr,
420 const char jobvs = 'V',
421 const char sort = 'N',
422 int_t * aSdim = nullptr,
423 const bool AbortOnError = true )
424 {
425 BELFEM_ASSERT( A.n_rows() == A.n_cols(),
426 "Matrix A must be square ( is %lu x %lu )",
427 ( long unsigned int ) A.n_rows(),
428 ( long unsigned int ) A.n_cols() );
429 BELFEM_ASSERT( jobvs == 'V' || jobvs == 'N',
430 "unsupported jobvs flag '%c'", jobvs );
431 BELFEM_ASSERT( sort == 'S' || sort == 'N',
432 "unsupported sort flag '%c'", sort );
433 BELFEM_ASSERT( ( sort == 'S' ) == ( select != nullptr ),
434 "sort = 'S' requires a select callback, sort = 'N' forbids it" );
435
436 // reals per LAPACK work entry
437 constexpr int_t tRealsPerT =
438 std::is_same< T, lapack::real_t< T > >::value ? 1 : 2 ;
439
440 int_t n = ( int_t ) A.n_rows();
442
443 W.set_size( n );
444
445 // lapack requires ldvs >= 1 even when not referenced
446 int_t ldvs = 1 ;
447 if ( jobvs == 'V' )
448 {
449 VS.set_size( n, n );
450 ldvs = lapack::leading_dimension( VS );
451 }
452
453 // the LOGICAL scratch is referenced only when sorting
454 if ( sort == 'S' && static_cast< int_t >( BWork.length() ) < n )
455 {
456 BWork.set_size( n );
457 }
458
459 // real tail: wr/wi for the real flavors, rwork for the complex ones
460 const int_t tTail = ( tRealsPerT == 1 ) ? 2 * n : n ;
461
462 // minimum work sizes: real flavors 3n, complex 2n
463 int_t lwork = std::max< int_t >( 1, tRealsPerT == 1 ? 3 * n : 2 * n );
464
465 int_t sdim = 0 ;
466 int_t info = 0 ;
467
468 // check length of work array: lwork entries of T plus the tail
469 if ( static_cast< int_t >( Work.length() ) < tRealsPerT * lwork + tTail )
470 {
471 // ask lapack for the optimal size; one T entry plus the tail
472 Work.set_size( tRealsPerT + tTail );
473
474 int_t query = -1 ;
475
476 lapack::gees( &jobvs, &sort, select, &n, A.data(), &lda, &sdim,
477 W.data(), VS.data(), &ldvs,
478 reinterpret_cast< T * >( Work.data() ), &query,
479 Work.data() + tRealsPerT, BWork.data(), &info );
480
481 BELFEM_ERROR( info == 0 || ! AbortOnError,
482 "LAPACK gees workspace query has thrown an error: %i", ( int ) info );
483
484 if ( info != 0 ) return info ;
485
486 // the optimal size sits in the real part of the first entry
487 lwork = lapack::work_size( Work( 0 ) );
488
489 Work.set_size( tRealsPerT * lwork + tTail );
490 }
491 else
492 {
493 // use the full buffer the caller has provided
494 lwork = ( ( int_t ) Work.length() - tTail ) / tRealsPerT ;
495 }
496
497 // work segment in the head, real scratch in the tail
498 lapack::gees( &jobvs, &sort, select, &n, A.data(), &lda, &sdim,
499 W.data(), VS.data(), &ldvs,
500 reinterpret_cast< T * >( Work.data() ), &lwork,
501 Work.data() + tRealsPerT * lwork, BWork.data(), &info );
502
503 BELFEM_ERROR( info == 0 || ! AbortOnError,
504 "LAPACK gees has thrown an error: %i", ( int ) info );
505
506 if ( aSdim != nullptr )
507 {
508 *aSdim = sdim ;
509 }
510
511 return info ;
512 }
513
514//------------------------------------------------------------------------------
515}
516#endif //BELFEM_FN_GEES_HPP
#define BELFEM_ERROR(aCheck,...)
Definition assert.hpp:264
#define BELFEM_ASSERT(aCheck,...)
Definition assert.hpp:244
Dense column-major matrix.
Definition cl_BZ_Matrix.hpp:28
void set_size(const size_t aNumRows, const size_t aNumCols)
Definition cl_AR_Matrix.hpp:186
size_t n_rows() const
Definition cl_AR_Matrix.hpp:205
size_t n_cols() const
Definition cl_AR_Matrix.hpp:213
T * data()
Definition cl_AR_Matrix.hpp:135
Column vector.
Definition cl_BZ_Vector.hpp:41
T * data()
expose the underlying raw pointer ( writable version )
Definition cl_AR_Vector.hpp:182
void set_size(const size_t aNumRows)
change the size of the vector
Definition cl_AR_Vector.hpp:237
size_t length() const
get the length of the vector
Definition cl_AR_Vector.hpp:257
Shared helpers for the LAPACK wrappers, such as leading_dimension().
Definition fn_gees.hpp:33
void sgees_(char *jobvs, char *sort, sgees_select_t select, int_t *n, float *a, int_t *lda, int_t *sdim, float *wr, float *wi, float *vs, int_t *ldvs, float *work, int_t *lwork, int_t *bwork, int_t *info, fortran_charlen_t lj, fortran_charlen_t ls)
constexpr bool dependent_false
Definition lapacktools.hpp:49
float cplx_float_t
Definition lapacktools.hpp:90
int_t leading_dimension(const Vector< T > &A)
logical length of a vector operand, as passed to LAPACK as LDB; vector storage is contiguous under bo...
Definition lapacktools.hpp:143
void zgees_(char *jobvs, char *sort, zgees_select_t select, int_t *n, cplx_double_t *a, int_t *lda, int_t *sdim, cplx_double_t *w, cplx_double_t *vs, int_t *ldvs, cplx_double_t *work, int_t *lwork, double *rwork, int_t *bwork, int_t *info, fortran_charlen_t lj, fortran_charlen_t ls)
int_t work_size(const float &aValue)
lapack reports the optimal work size in the first entry of the work array, which stays real valued fo...
Definition lapacktools.hpp:191
void dgees_(char *jobvs, char *sort, dgees_select_t select, int_t *n, double *a, int_t *lda, int_t *sdim, double *wr, double *wi, double *vs, int_t *ldvs, double *work, int_t *lwork, int_t *bwork, int_t *info, fortran_charlen_t lj, fortran_charlen_t ls)
size_t fortran_charlen_t
Definition lapacktools.hpp:100
void gees(const char *jobvs, const char *sort, gees_select_t< T > select, const int_t *n, T *a, const int_t *lda, int_t *sdim, cplx_t< T > *w, T *vs, const int_t *ldvs, T *work, const int_t *lwork, real_t< T > *rwork, int_t *bwork, int_t *info)
Definition fn_gees.hpp:168
int_t(*) sgees_select_t(const float *, const float *)
Definition fn_gees.hpp:48
double cplx_double_t
Definition lapacktools.hpp:91
typename real_type< T >::type real_t
Definition lapacktools.hpp:63
int_t(*) dgees_select_t(const double *, const double *)
Definition fn_gees.hpp:49
void cgees_(char *jobvs, char *sort, cgees_select_t select, int_t *n, cplx_float_t *a, int_t *lda, int_t *sdim, cplx_float_t *w, cplx_float_t *vs, int_t *ldvs, cplx_float_t *work, int_t *lwork, float *rwork, int_t *bwork, int_t *info, fortran_charlen_t lj, fortran_charlen_t ls)
typename gees_select< T >::type gees_select_t
Definition fn_gees.hpp:159
typename cplx_type< T >::type cplx_t
Definition lapacktools.hpp:75
int_t(*) zgees_select_t(const cplx_double_t *)
Definition fn_gees.hpp:51
int_t(*) cgees_select_t(const cplx_float_t *)
Definition fn_gees.hpp:50
USER GUIDES:
Definition cl_Capacitor.cpp:16
std::pair< real, unit > value
Definition typedefs.hpp:74
int_t gees(Matrix< T > &A, Vector< lapack::cplx_t< T > > &W, Matrix< T > &VS, Vector< lapack::real_t< T > > &Work, Vector< int_t > &BWork, lapack::gees_select_t< T > select=nullptr, const char jobvs='V', const char sort='N', int_t *aSdim=nullptr, const bool AbortOnError=true)
Schur decomposition of a general square matrix via LAPACK ?gees: A = Z * T * Z^T for the real flavors...
Definition fn_gees.hpp:413
void sort(Cell< T > &aCell)
Definition cl_Cell.hpp:455
int32_t int_t
Definition typedefs.hpp:51
int_t(*) type(const std::complex< R > *)
Definition fn_gees.hpp:155
Definition fn_gees.hpp:148
int_t(*) type(const T *, const T *)
Definition fn_gees.hpp:149