Skip to content

Commit aa4f05a

Browse files
Quadric surface (#135)
Adds a general quadratic shape. Also removed dotProduct from surfaces in favour of intrinsic dot_product.
1 parent b07a2c3 commit aa4f05a

File tree

10 files changed

+470
-20
lines changed

10 files changed

+470
-20
lines changed

Geometry/Surfaces/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ add_sources(./surface_inter.f90
33
./QuadSurfaces/cylinder_class.f90
44
./QuadSurfaces/aPlane_class.f90
55
./QuadSurfaces/plane_class.f90
6+
./QuadSurfaces/quadric_class.f90
67
./CompositeSurfaces/box_class.f90
78
./CompositeSurfaces/truncCone_class.f90
89
./CompositeSurfaces/truncCylinder_class.f90
@@ -16,6 +17,7 @@ add_unit_tests( ./Tests/sphere_test.f90
1617
./Tests/cylinder_test.f90
1718
./Tests/aPlane_test.f90
1819
./Tests/plane_test.f90
20+
./Tests/quadric_test.f90
1921
./Tests/box_test.f90
2022
./Tests/squareCylinder_test.f90
2123
./Tests/truncCylinder_test.f90

Geometry/Surfaces/CompositeSurfaces/truncCone_class.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module truncCone_class
22

33
use numPrecision
44
use universalVariables, only : SURF_TOL, INF, X_AXIS, Y_AXIS, Z_AXIS
5-
use genericProcedures, only : fatalError, numToChar, dotProduct
5+
use genericProcedures, only : fatalError, numToChar
66
use dictionary_class, only : dictionary
77
use surface_inter, only : surface, kill_super => kill
88

Geometry/Surfaces/QuadSurfaces/cylinder_class.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module cylinder_class
22

33
use numPrecision
44
use universalVariables, only : SURF_TOL, INF, X_AXIS, Y_AXIS, Z_AXIS
5-
use genericProcedures, only : fatalError, numToChar, dotProduct
5+
use genericProcedures, only : fatalError, numToChar
66
use dictionary_class, only : dictionary
77
use surface_inter, only : surface, kill_super => kill
88

Geometry/Surfaces/QuadSurfaces/plane_class.f90

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module plane_class
22

33
use numPrecision
44
use universalVariables, only : X_AXIS, Y_AXIS, Z_AXIS, INF
5-
use genericProcedures, only : fatalError, dotProduct, numToChar
5+
use genericProcedures, only : fatalError, numToChar
66
use dictionary_class, only : dictionary
77
use surface_inter, only : surface, kill_super => kill
88
implicit none
@@ -124,7 +124,7 @@ pure function evaluate(self, r) result(c)
124124
real(defReal), dimension(3), intent(in) :: r
125125
real(defReal) :: c
126126

127-
c = dotProduct(r, self % norm) - self % offset
127+
c = dot_product(r, self % norm) - self % offset
128128

129129
end function evaluate
130130

@@ -147,7 +147,7 @@ pure function distance(self, r, u) result(d)
147147
real(defReal) :: d
148148
real(defReal) :: k, c
149149

150-
k = dotProduct(u, self % norm)
150+
k = dot_product(u, self % norm)
151151
c = self % evaluate(r)
152152

153153
if ( k == ZERO .or. abs(c) < self % surfTol()) then ! Parallel or at the surface
@@ -176,7 +176,7 @@ pure function going(self, r, u) result(halfspace)
176176
logical(defBool) :: halfspace
177177
real(defReal) :: proj
178178

179-
proj = dotProduct(u, self % norm)
179+
proj = dot_product(u, self % norm)
180180
halfspace = proj > ZERO
181181

182182
! Special case of parallel direction
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
module quadric_class
2+
3+
use numPrecision
4+
use universalVariables, only : SURF_TOL, INF, X_AXIS, Y_AXIS, Z_AXIS
5+
use genericProcedures, only : fatalError, numToChar
6+
use dictionary_class, only : dictionary
7+
use surface_inter, only : surface, kill_super => kill
8+
9+
implicit none
10+
private
11+
12+
!!
13+
!! General quadratic surface - also known as a quadric
14+
!!
15+
!! F(x,y,z) = Ax^2 + By^2 + Cz^2 + Dxy + Eyz + Fzx + Gx + Hy + Iz + J
16+
!!
17+
!! Surface tolerance: 2 * max(coeffs) * SURF_TOL
18+
!!
19+
!! Sample dictionary input:
20+
!! quad { type quadric;
21+
!! id 3;
22+
!! coeffs (1 -2.3 0.4 20 7.7777 0.004 6E9 -4.20 0 11);
23+
!! // correspond to(A B C D E F G H I J)
24+
!! }
25+
!!
26+
!! Private Members:
27+
!! coeffs -> Quadric coefficients
28+
!!
29+
!! Interface:
30+
!! surface interface
31+
!!
32+
type, public, extends(surface) :: quadric
33+
private
34+
real(defReal), dimension(10) :: coeffs = ZERO
35+
contains
36+
! Superclass procedures
37+
procedure :: myType
38+
procedure :: init
39+
procedure :: boundingBox
40+
procedure :: evaluate
41+
procedure :: distance
42+
procedure :: going
43+
procedure :: kill
44+
45+
end type quadric
46+
47+
contains
48+
49+
!!
50+
!! Return surface type name
51+
!!
52+
!! See surface_inter for more details
53+
!!
54+
pure function myType(self) result(str)
55+
class(quadric), intent(in) :: self
56+
character(:), allocatable :: str
57+
58+
str = 'quadric'
59+
60+
end function myType
61+
62+
!!
63+
!! Initialise quadric from a dictionary
64+
!!
65+
!! See surface_inter for more details
66+
!!
67+
!! Errors:
68+
!! fatalError if id < 0 or incorrect size of coeffs
69+
!!
70+
subroutine init(self, dict)
71+
class(quadric), intent(inout) :: self
72+
class(dictionary), intent(in) :: dict
73+
integer(shortInt) :: id
74+
real(defReal), dimension(:), allocatable :: coeffs
75+
character(100), parameter :: Here = 'init (quadric_class.f90)'
76+
77+
! Get from dictionary
78+
call dict % get(id, 'id')
79+
call dict % get(coeffs, 'coeffs')
80+
81+
! Check ID validity
82+
if (id < 1) call fatalError(Here,'Invalid surface id provided. ID must be > 1')
83+
84+
! Check origin size
85+
if (size(coeffs) /= 10) then
86+
call fatalError(Here,'coeffs needs to have size 10. Has: '//numToChar(size(coeffs)))
87+
end if
88+
89+
call self % setID(id)
90+
self % coeffs = coeffs
91+
92+
! Set surface tolerance - what should this be?
93+
! Could choose alternatively to be equivalent to the
94+
! sphere case, i.e., 2 * coeffs(10) = 2*R
95+
call self % setTol( TWO * maxval(abs(coeffs)) * SURF_TOL)
96+
97+
end subroutine init
98+
99+
!!
100+
!! Return axis-aligned bounding box for the surface
101+
!!
102+
!! Not attempted - may be unbounded, depending on the coefficients.
103+
!! Would generally require checking the Jacobian of the surface and
104+
!! finding critical points.
105+
!! I think this only matters if we wanted to use this as a boundary.
106+
!!
107+
!! TODO: This
108+
!! See surface_inter for details
109+
!!
110+
pure function boundingBox(self) result(aabb)
111+
class(quadric), intent(in) :: self
112+
real(defReal), dimension(6) :: aabb
113+
114+
aabb(1:3) = -INF
115+
aabb(4:6) = INF
116+
117+
end function boundingBox
118+
119+
!!
120+
!! Evaluate surface expression c = F(r)
121+
!!
122+
!! See surface_inter for details
123+
!!
124+
pure function evaluate(self, r) result(c)
125+
class(quadric), intent(in) :: self
126+
real(defReal), dimension(3), intent(in) :: r
127+
real(defReal) :: c
128+
129+
associate(a => self % coeffs, x => r(1), y => r(2), z => r(3))
130+
c = x * (a(1)*x + a(4)*y + a(6)*z + a(7)) + &
131+
y * (a(2)*y + a(5)*z + a(8)) + &
132+
z * (a(3)*z + a(9)) + a(10)
133+
end associate
134+
135+
end function evaluate
136+
137+
!!
138+
!! Return distance to the surface
139+
!!
140+
!! See surface_inter for details
141+
!!
142+
!! Converts the general quadric to a 1D quadratic to solve
143+
!! ad^2 + 2kd + c = 0
144+
!! c = F(r)
145+
!! k = A*u1*r1 + B*u2*r2 + C*u3*r3 +
146+
!! (D(u1*r2 + u2*r1) + E(u2*r3 + u3*r2) + F(u3*r1 + u1*r3)
147+
!! + G*u1 + H*u2 + I*u3) / 2
148+
!! a = A*u1*u1 + B*u2*u2 + C*u3*u3 + D*u1*u2 + E*u2*u3 + F*u1*u3
149+
!!
150+
pure function distance(self, r, u) result(d)
151+
class(quadric), intent(in) :: self
152+
real(defReal), dimension(3), intent(in) :: r
153+
real(defReal), dimension(3), intent(in) :: u
154+
real(defReal) :: d
155+
real(defReal) :: a, c, k, delta
156+
157+
c = self % evaluate(r)
158+
associate(cf => self % coeffs, x => r(1), y => r(2), z => r(3), &
159+
u1 => u(1), u2 => u(2), u3 => u(3))
160+
k = cf(1)*u1*x + cf(2)*u2*y + cf(3)*u3*z + &
161+
HALF * (cf(4) * (u1*y + u2*x) + &
162+
cf(5) * (u2*z + u3*y) + cf(6) * (u3*x + u1*z) + &
163+
cf(7) * u1 + cf(8)*u2 + cf(9)*u3)
164+
a = u1 * (cf(1) * u1 + cf(4) * u2 + cf(6) * u3) + &
165+
u2 * (cf(2) * u2 + cf(5) * u3) + &
166+
cf(3) * u3 * u3
167+
end associate
168+
delta = k*k - a*c ! Technically delta/4 - quadratic discriminant
169+
170+
! Calculate the distance
171+
if (delta < ZERO .or. a == ZERO) then ! No intersection
172+
d = INF
173+
174+
else if (abs(c) < self % surfTol()) then ! Point at a surface
175+
if ( k >= ZERO) then
176+
d = INF
177+
else
178+
d = -k + sqrt(delta)
179+
d = d/a
180+
end if
181+
182+
else if (c < ZERO) then ! Point inside the surface
183+
d = -k + sqrt(delta)
184+
d = d/a
185+
186+
else ! Point outside the surface
187+
d = -k - sqrt(delta)
188+
d = d/a
189+
if (d <= ZERO) d = INF
190+
191+
end if
192+
193+
! Cap distance at Infinity
194+
d = min(d, INF)
195+
196+
end function distance
197+
198+
!!
199+
!! Returns TRUE if particle is going into +ve halfspace
200+
!!
201+
!! See surface_inter for details
202+
!!
203+
pure function going(self, r, u) result(halfspace)
204+
class(quadric), intent(in) :: self
205+
real(defReal), dimension(3), intent(in) :: r
206+
real(defReal), dimension(3), intent(in) :: u
207+
logical(defBool) :: halfspace
208+
real(defReal), dimension(3) :: grad
209+
210+
associate(a => self % coeffs)
211+
grad(1) = TWO * a(1) * r(1) + a(4) * r(2) + a(5) * r(3)
212+
grad(2) = TWO * a(2) * r(2) + a(4) * r(1) + a(6) * r(3)
213+
grad(3) = TWO * a(3) * r(3) + a(5) * r(1) + a(6) * r(2)
214+
end associate
215+
halfspace = dot_product(grad, u) >= ZERO
216+
217+
end function going
218+
219+
!!
220+
!! Return to uninitialised state
221+
!!
222+
elemental subroutine kill(self)
223+
class(quadric), intent(inout) :: self
224+
225+
! Superclass
226+
call kill_super(self)
227+
228+
! Local
229+
self % coeffs = ZERO
230+
231+
end subroutine kill
232+
233+
end module quadric_class

Geometry/Surfaces/QuadSurfaces/sphere_class.f90

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module sphere_class
22

33
use numPrecision
44
use universalVariables, only : INF, SURF_TOL
5-
use genericProcedures, only : fatalError, dotProduct, numToChar
5+
use genericProcedures, only : fatalError, numToChar
66
use dictionary_class, only : dictionary
77
use surface_inter, only : surface, kill_super => kill
88

@@ -134,7 +134,7 @@ pure function evaluate(self, r) result(c)
134134

135135
diff = r - self % origin
136136

137-
c = dotProduct(diff, diff) - self % r_sq
137+
c = dot_product(diff, diff) - self % r_sq
138138

139139
end function evaluate
140140

@@ -157,7 +157,7 @@ pure function distance(self, r, u) result(d)
157157

158158
! Calculate quadratic components
159159
c = self % evaluate(r)
160-
k = dotProduct(r - self % origin, u)
160+
k = dot_product(r - self % origin, u)
161161
delta = k*k - c ! Technically delta/4
162162

163163
! Calculate the distance
@@ -192,7 +192,7 @@ pure function going(self, r, u) result(halfspace)
192192
real(defReal), dimension(3), intent(in) :: u
193193
logical(defBool) :: halfspace
194194

195-
halfspace = dotProduct(r - self % origin, u) >= ZERO
195+
halfspace = dot_product(r - self % origin, u) >= ZERO
196196

197197
end function going
198198

0 commit comments

Comments
 (0)