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