Skip to content

Commit

Permalink
Fix functions to detect eclipse (#75)
Browse files Browse the repository at this point in the history
* Update TPM_Didymos.jl

* Update energy_flux.jl

- Change the names of functions (`binary_is_aligned`)

* Update energy_flux.jl

* Update energy_flux.jl

Fix `find_eclipse!`

* Update energy_flux.jl

* Update energy_flux.jl

* Update energy_flux.jl

* Rename `find_eclipse!` to `mutual_shadowing!`
  • Loading branch information
MasanoriKanamaru authored Oct 14, 2023
1 parent 58e9f70 commit ffbb861
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 50 deletions.
4 changes: 2 additions & 2 deletions src/TPM.jl
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,8 @@ function run_TPM!(btpm::BinaryTPM, ephem, savepath)
update_flux_scat_single!(btpm)
update_flux_rad_single!(btpm, nₜ)

## Mutual-shadowing
find_eclipse!(btpm, r☉₁, sec_from_pri, R₂₁)
## Mutual-shadowing (eclipse)
mutual_shadowing!(btpm, r☉₁, sec_from_pri, R₂₁)

## Mutual-heating
#
Expand Down
174 changes: 129 additions & 45 deletions src/energy_flux.jl
Original file line number Diff line number Diff line change
Expand Up @@ -270,57 +270,141 @@ end
# Eclipse of binary asteroid
# ****************************************************************

"""
The secondary is within the critical angle to detect an eclipse event.
"""
function eclipse_is_possible(btpm::BinaryTPM, sun_from_pri, sec_from_pri)

R₁ = maximum_radius(btpm.pri.shape)
R₂ = maximum_radius(btpm.sec.shape)
θ_crit = asin((R₁ + R₂) / norm(sec_from_pri))

r̂☉ = SVector{3}(normalize(sun_from_pri))
r̂ₛ = SVector{3}(normalize(sec_from_pri))
θ = acos(r̂☉ r̂ₛ) # Angle of Sun-Primary-Secondary

θ_crit < θ < π - θ_crit ? false : true
end


"""
find_eclipse!(shapes, sun_from_pri, sec_from_pri, R₂₁)

- `shapes`
- `sun_from_pri`
- `sec_from_pri` : Position of the secondary relative to primary
- `R₂₁` : Rotation matrix from secondary to primary
"""
function find_eclipse!(btpm::BinaryTPM, sun_from_pri, sec_from_pri, R₂₁)
mutual_shadowing!(btpm::BinaryTPM, r☉, rₛ, R₂₁)
r̂☉ = SVector{3}(normalize(sun_from_pri))
# r̂ₛ = SVector{3}(normalize(sec_from_pri))
rₛ = SVector{3}(sec_from_pri)
Detect eclipse events between the primary and secondary, and update the solar fluxes of the faces.
eclipse_is_possible(btpm, r̂☉, rₛ) == false && return

for i in eachindex(btpm.pri.shape.faces)
btpm.pri.flux[i, 1] == 0 && continue # something wrong?
A₁, B₁, C₁ = btpm.pri.shape.nodes[btpm.pri.shape.faces[i]] # △ABC in primary
G₁ = btpm.pri.shape.face_centers[i] # Center of △ABC in primary

for j in eachindex(btpm.sec.shape.faces)
btpm.sec.flux[j, 1] == 0 && continue # something wrong?
A₂, B₂, C₂ = btpm.sec.shape.nodes[btpm.sec.shape.faces[j]] # △ABC in secondary
G₂ = btpm.sec.shape.face_centers[j] # Center of △ABC in secondary
# Arguments
- `btpm` : Thermophysical model for a binary asteroid
- `r☉` : Position of the sun relative to the primary (NOT normalized)
- `rₛ` : Position of the secondary relative to the primary (NOT normalized)
- `R₂₁` : Rotation matrix from secondary to primary
"""
function mutual_shadowing!(btpm::BinaryTPM, r☉, rₛ, R₂₁)

shape1 = btpm.pri.shape
shape2 = btpm.sec.shape
r̂☉ = normalize(r☉)

θ = acos((r☉ rₛ) / (norm(r☉) * norm(rₛ))) # Angle of Sun-Primary-Secondary

R₁ = maximum_radius(shape1)
R₂ = maximum_radius(shape2)
R₁ < R₂ && error("Error: The primary radius is smaller than the secondary.")

θ₊ = asin((R₁ + R₂) / norm(rₛ)) # Critical angle at which partial ecripse can occur
θ₋ = asin((R₁ - R₂) / norm(rₛ)) # Critical angle at which total ecripse can occur

#### Partital eclipse of the primary ####
if 0 θ < θ₊
r₂ = minimum_radius(shape2)

for i in eachindex(shape1.faces)
G₁ = shape1.face_centers[i] # Center of △A₁B₁C₁ in primary
n̂₁ = shape1.face_normals[i] # Normal vector of △A₁B₁C₁ in primary

## if △A₁B₁C₁ is NOT facing the sun
if r̂☉ n̂₁ < 0
btpm.pri.flux[i, 1] = 0
continue
end

d₁ₛ = rₛ - G₁ # Vector from △A₁B₁C₁ to secondary center
θ₁ = acos(r̂☉ normalize(d₁ₛ)) # Angle of Sun-△A₁B₁C₁-Secondary
θ_R₂ = asin(R₂ / norm(d₁ₛ)) # Critical angle related to the maximum radius of the secondary
θ_r₂ = asin(r₂ / norm(d₁ₛ)) # Critical angle related to the minimum radius of the secondary

## In the secondary shadow
if θ₁ < θ_r₂
btpm.pri.flux[i, 1] = 0
continue
## Out of the secondary shadow
elseif θ₁ > θ_R₂
continue
else
for j in eachindex(shape2.faces)
A₂, B₂, C₂ = shape2.nodes[shape2.faces[j]] # △A₂B₂C₂ in secondary
G₂ = shape2.face_centers[j] # Center of △A₂B₂C₂
n̂₂ = shape2.face_normals[j] # Normal vector of △A₂B₂C₂

## Transform coordinates from secondary- to primary-fixed frame
A₂ = R₂₁ * A₂ + rₛ
B₂ = R₂₁ * B₂ + rₛ
C₂ = R₂₁ * C₂ + rₛ
## Transformation from secondary to primary frame
A₂ = R₂₁ * A₂ + rₛ
B₂ = R₂₁ * B₂ + rₛ
C₂ = R₂₁ * C₂ + rₛ
G₂ = R₂₁ * G₂ + rₛ
n̂₂ = R₂₁ * n̂₂

d₁₂ = G₂ - G₁ # Vector from primary face i to secondary face j

## if △A₁B₁C₁ and △A₂B₂C₂ are facing each other
if d₁₂ n̂₁ > 0 && d₁₂ n̂₂ < 0
if raycast(A₂, B₂, C₂, r̂☉, G₁)
btpm.pri.flux[i, 1] = 0
break
end
end
end
end
end

#### No eclipse ####
# elseif θ₊ ≤ θ < π - θ₊
# Do nothing

#### Partial eclipse of the secondary ####
elseif π - θ₊ θ < π - θ₋
r₁ = minimum_radius(shape1)

for j in eachindex(shape2.faces)
G₂ = shape2.face_centers[j] # Center of △A₂B₂C₂ in secondary
n̂₂ = shape2.face_normals[j] # Normal vector of △A₂B₂C₂ in secondary

## Transformation from secondary to primary frame
G₂ = R₂₁ * G₂ + rₛ

raycast(A₂, B₂, C₂, r̂☉, G₁) && (btpm.pri.flux[i, 1] = 0) # something wrong?
raycast(A₁, B₁, C₁, r̂☉, G₂) && (btpm.sec.flux[j, 1] = 0) # something wrong?
n̂₂ = R₂₁ * n̂₂

## if △A₂B₂C₂ is NOT facing the sun
if r̂☉ n̂₂ < 0
btpm.sec.flux[j, 1] = 0
continue
end

d₂ₚ = - G₂ # Vector from △A₂B₂C₂ to primary center (origin)
θ₂ = acos(r̂☉ normalize(d₂ₚ)) # Angle of Sun-△A₂B₂C₂-Primary
θ_R₁ = asin(R₁ / norm(d₂ₚ)) # Critical angle related to the maximum radius of the primary
θ_r₁ = asin(r₁ / norm(d₂ₚ)) # Critical angle related to the minimum radius of the primary

## In the primary shadow
if θ₂ < θ_r₁
btpm.sec.flux[j, 1] = 0
continue
## Out of the primary shadow
elseif θ₂ > θ_R₁
continue
else
for i in eachindex(shape1.faces)
A₁, B₁, C₁ = shape1.nodes[shape1.faces[i]] # △A₁B₁C₁ in primary
G₁ = shape1.face_centers[i] # Center of △A₁B₁C₁
n̂₁ = shape1.face_normals[i] # Normal vector of △A₁B₁C₁

d₁₂ = G₂ - G₁ # Vector from primary face i to secondary face j

## if △A₁B₁C₁ and △A₂B₂C₂ are facing each other
if d₁₂ n̂₁ > 0 && d₁₂ n̂₂ < 0
if raycast(A₁, B₁, C₁, r̂☉, G₂)
btpm.sec.flux[j, 1] = 0
break
end
end
end
end
end

#### Total eclipse of the secondary ####
elseif π - θ₋ θ < π
btpm.sec.flux[:, 1] .= 0
end
end

7 changes: 4 additions & 3 deletions test/TPM_Didymos.jl
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@
end

##= Ephemerides =##
et_begin = SPICE.utc2et("2027-02-18T00:00:00")
et_end = SPICE.utc2et("2027-02-19T00:00:00")
step = 300
P = SPICE.convrt(AsteroidThermoPhysicalModels.DIDYMOS[:P], "hours", "seconds") # Rotation period of Didymos
et_begin = SPICE.utc2et("2027-02-18T00:00:00") # Start time of TPM
et_end = et_begin + 10P # End time of TPM
step = P / 72 # Time step of TPM
et_range = et_begin : step : et_end
@show length(et_range)

Expand Down

0 comments on commit ffbb861

Please sign in to comment.