BELFEM
0.9.3
Berkeley Lab Finite Element Framework
Toggle main menu visibility
Loading...
Searching...
No Matches
fn_ferrari.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,
4
* through 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
8
*
9
* See the top-level LICENSE file for the complete license and disclaimer.
10
*/
11
12
#ifndef BELFEM_FN_FERRARI_HPP
13
#define BELFEM_FN_FERRARI_HPP
14
15
#include "
typedefs.hpp
"
16
#include "
assert.hpp
"
17
#include "
cl_Vector.hpp
"
18
#include "
fn_cardano.hpp
"
19
20
namespace
belfem
21
{
22
//------------------------------------------------------------------------------
50
template
<
typename
T >
51
void
52
ferrari
(
const
Vector< T >
& A,
Vector< T >
& X )
53
{
54
BELFEM_ASSERT
( A.
length
() == 5,
55
"coefficient vector needs to have a length of 5"
);
56
57
// quartic degenerates to a cubic
58
if
( std::abs( A( 0 ) ) <
BELFEM_EPSILON
)
59
{
60
cardano
( A( 1 ), A( 2 ), A( 3 ), A( 4 ), X );
61
return ;
62
}
63
64
// normalize to x^4 + a*x^3 + b*x^2 + c*x + d = 0
65
const
T a = A( 1 ) / A( 0 );
66
const
T b = A( 2 ) / A( 0 );
67
const
T c = A( 3 ) / A( 0 );
68
const
T d = A( 4 ) / A( 0 );
69
70
// depress with x = y - lambda : y^4 + p*y^2 + q*y + r = 0
71
const
T lambda = 0.25 * a ;
72
const
T p = b - 0.375 * a * a ;
73
const
T
q
= c - 0.5 * a * b + 0.125 * a * a * a ;
74
const
T r = d - 0.25 * a * c + 0.0625 * a * a * b
75
- ( 3.0 / 256.0 ) * a * a * a * a ;
76
77
// real roots in y, at most four
78
T Y[4];
79
80
uint
tCount = 0 ;
81
82
// the biquadratic path handles q ~ 0. It also serves as the
83
// fallback when roundoff collapses the clamped resolvent root
84
// s^2 to zero on an ill-conditioned cubic. Then q/s would be Inf/NaN.
85
// In exact arithmetic, that occurs only
86
// when q is negligible anyway
87
bool
biquadratic = std::abs(
q
) <
BELFEM_EPSILON
;
88
89
T z = 0.0 ;
90
T s = 0.0 ;
91
92
if
( ! biquadratic )
93
{
94
// resolvent cubic in z = s^2, temporarily using X as scratch
95
Vector< T >
& Z = X ;
96
cardano
( T( 1 ), 2.0 * p, p * p - 4.0 * r, -
q
*
q
, Z );
97
98
// cardano sorts ascending; the largest root is >= 0 in exact
99
// arithmetic (the cubic evaluates to -q^2 < 0 at z = 0) and is
100
// the numerically robust choice for s
101
z = std::max( Z( Z.
length
() - 1 ), T( 0 ) );
102
s = std::sqrt( z );
103
104
biquadratic = ( s <
BELFEM_EPSILON
);
105
}
106
107
if
( biquadratic )
108
{
109
// biquadratic: z^2 + P*z + R = 0 with z = y^2.
110
T D = p * p - 4.0 * r ;
111
112
if
( D > -
BELFEM_EPSILON
)
113
{
114
D = std::sqrt( std::max( D, T( 0 ) ) );
115
116
// stable quadratic: avoid cancellation in the smaller root.
117
// the sign must come from p, the linear coefficient of
118
// z^2 + p*z + r ( q is ~0 in this branch )
119
const
T w = -0.5 * ( p + std::copysign( D, p ) );
120
121
// the two z-candidates ( w == 0 only if p = D = 0 )
122
const
T z0 = w ;
123
const
T z1 = std::abs( w ) >
BELFEM_EPSILON
? r / w : w ;
124
125
for
(
const
T zk : { z0, z1 } )
126
{
127
if
( zk >
BELFEM_EPSILON
)
128
{
129
const
T tS = std::sqrt( zk );
130
Y[ tCount++ ] = -tS ;
131
Y[ tCount++ ] = tS ;
132
}
133
else
if
( zk > -
BELFEM_EPSILON
)
134
{
135
Y[ tCount++ ] = 0.0 ;
136
}
137
}
138
}
139
// D < 0 : no real roots
140
}
141
else
142
{
143
// constant terms of the two quadratic factors
144
const
T t1 = 0.5 * ( p + z -
q
/ s );
145
const
T t2 = 0.5 * ( p + z +
q
/ s );
146
147
// y^2 + s*y + t1 = 0
148
T D = s * s - 4.0 * t1 ;
149
150
if
( D >
BELFEM_EPSILON
)
151
{
152
D = std::sqrt( D );
153
Y[ tCount++ ] = 0.5 * ( -s - D );
154
Y[ tCount++ ] = 0.5 * ( -s + D );
155
}
156
else
if
( D > -
BELFEM_EPSILON
)
157
{
158
// double root (clamped)
159
Y[ tCount++ ] = -0.5 * s ;
160
}
161
162
// y^2 - s*y + t2 = 0
163
D = s * s - 4.0 * t2 ;
164
if
( D >
BELFEM_EPSILON
)
165
{
166
D = std::sqrt( D );
167
Y[ tCount++ ] = 0.5 * ( s - D );
168
Y[ tCount++ ] = 0.5 * ( s + D );
169
}
170
else
if
( D > -
BELFEM_EPSILON
)
171
{
172
Y[ tCount++ ] = 0.5 * s ;
173
}
174
}
175
176
// shift back ( x = y - lambda ), sort ascending (insertion sort,
177
// at most four entries), and drop duplicates from multiple roots
178
for
(
uint
i = 0 ; i < tCount ; ++i )
179
{
180
Y[ i ] -= lambda ;
181
}
182
for
(
uint
i = 1 ; i < tCount ; ++i )
183
{
184
const
T v = Y[ i ];
185
uint
j = i ;
186
while
( j > 0 && Y[ j - 1 ] > v )
187
{
188
Y[ j ] = Y[ j - 1 ];
189
--j ;
190
}
191
Y[ j ] = v ;
192
}
193
194
uint
tNumRoots = 0 ;
195
for
(
uint
i = 0 ; i < tCount ; ++i )
196
{
197
if
( tNumRoots == 0 || std::abs( Y[ i ] - Y[ tNumRoots - 1 ] )
198
>
BELFEM_EPSILON
* std::max( T( 1 ), std::abs( Y[ i ] ) ) )
199
{
200
Y[ tNumRoots++ ] = Y[ i ];
201
}
202
}
203
204
X.
set_size
( tNumRoots );
205
for
(
uint
i = 0 ; i < tNumRoots ; ++i )
206
{
207
X( i ) = Y[ i ];
208
}
209
}
210
//------------------------------------------------------------------------------
211
}
212
#endif
//BELFEM_FN_FERRARI_HPP
assert.hpp
BELFEM_ASSERT
#define BELFEM_ASSERT(aCheck,...)
Definition
assert.hpp:244
cl_Vector.hpp
belfem::Vector
Column vector.
Definition
cl_BZ_Vector.hpp:41
belfem::Vector::set_size
void set_size(const size_t aNumRows)
change the size of the vector
Definition
cl_AR_Vector.hpp:215
belfem::Vector::length
size_t length() const
get the length of the vector
Definition
cl_AR_Vector.hpp:235
fn_cardano.hpp
belfem
USER GUIDES:
Definition
cl_Capacitor.cpp:16
belfem::ferrari
void ferrari(const Vector< T > &A, Vector< T > &X)
solve a quartic equation A(0)*x^4 + A(1)*x^3 + A(2)*x^2 + A(3)*x + A(4) = 0 for its real roots using ...
Definition
fn_ferrari.hpp:52
belfem::uint
unsigned int uint
Definition
typedefs.hpp:30
belfem::cardano
void cardano(const T a, const T b, const T c, const T d, Vector< T > &X)
solve a cubic equation a*x^3 + b*x^2 + c*x + d = 0 for its real roots (Cardano / trigonometric method...
Definition
fn_cardano.hpp:65
belfem::BELFEM_EPSILON
constexpr real BELFEM_EPSILON
Definition
typedefs.hpp:89
belfem::MaterialProperty::q
@ q
Definition
cl_Material.hpp:176
typedefs.hpp
src
math
tools
fn_ferrari.hpp
Generated by
1.18.0