Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement segmented ridges with flexible positioning #153

Merged
merged 22 commits into from
Jan 28, 2025

Conversation

adbayonao
Copy link
Contributor

@adbayonao adbayonao commented Dec 11, 2024

I added a new feature to the compute_thermal_structure function by creating an additional function that allows for the creation of segmented ridges. Previously, only a single ridge segment could be placed at the boundary of the box. Now, it is possible to position the ridge at any location within the domain, and the ridge can consist of multiple segments. Each segment has its own thermal profile.

The new functionality works as follows: First, the coordinates of the ridge segments are used, where each segment has two parts: the start and end coordinates. Using these coordinates, delimiters are created, where the end of one segment aligns with the start of the next. These delimiters divide the domain into distinct regions, with each region corresponding to a specific ridge segment. To assign coordinates to these regions, the function determines which side of each delimiter a given point lies on, considering the direction of the delimiter. Once the domain is divided, the perpendicular distance from each point to the corresponding ridge segment is calculated, which in turn generates the thermal profile for that region. Each region is influenced by only one ridge segment.

This new functionality was implemented using multiple dispatch. Depending on the parameters provided by the user, either the original or the new version of the function is executed. This allows the function to handle both single ridge segment configurations and multiple segment configurations, providing greater flexibility in modeling ridge structures.

Additionally, I modified the add_box function to integrate this new feature, enabling the inclusion of segmented ridges within the box configuration.

Screenshot from 2025-01-08 07-11-10
Screenshot from 2025-01-08 07-10-44

@adbayonao adbayonao closed this Dec 11, 2024
@adbayonao adbayonao reopened this Dec 11, 2024
@boriskaus
Copy link
Member

boriskaus commented Dec 11, 2024

thanks for your contribution - can you make the title of this PR a bit clearer so it reflects what this is about?

Also, if it is not yet ready to be reviewed you can mark it as draft (upper right corner)

# This script creates 3D polygons from "x" and "y" coordinates, and allows you to define a depth range for the polygon.
# It assigns phase and temperature values to the grid within the polygon.

using GeophysicalModelGenerator
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you want this routine to be accessible in the GMG package, this file needs two be loaded in one of the other files with include("Polygon3D.jl")

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am going to review this.

@adbayonao adbayonao changed the title Contribution_1 Add 3D Polygon for Defining Phase and Temperature Based on Coordinates Dec 11, 2024
@boriskaus
Copy link
Member

Note that we have a function add_polygon! already with test defined in test/test_setup_geometry.jl.

Which functionality does this PR add that is not yet possible with the existing routine?
And is it perhaps possible to extend the existing routine (and test file)?

@adbayonao
Copy link
Contributor Author

Note that we have a function add_polygon! already with test defined in test/test_setup_geometry.jl.

Which functionality does this PR add that is not yet possible with the existing routine? And is it perhaps possible to extend the existing routine (and test file)?

I am going to try to extend the existing routine to add the new functionality

@adbayonao
Copy link
Contributor Author

thanks for your contribution - can you make the title of this PR a bit clearer so it reflects what this is about?

Also, if it is not yet ready to be reviewed you can mark it as draft (upper right corner)

Ok, thank you. I changed the title.

@adbayonao adbayonao marked this pull request as draft December 12, 2024 13:38
@adbayonao adbayonao changed the title Add 3D Polygon for Defining Phase and Temperature Based on Coordinates Implement segmented ridges with thermal profile and flexible positioning Jan 8, 2025
@adbayonao adbayonao changed the title Implement segmented ridges with thermal profile and flexible positioning Implement segmented ridges and flexible positioning Jan 8, 2025
@adbayonao adbayonao changed the title Implement segmented ridges and flexible positioning Implement segmented ridges with flexible positioning Jan 8, 2025
@adbayonao adbayonao marked this pull request as ready for review January 8, 2025 19:40
Project.toml Outdated Show resolved Hide resolved
src/.Setup_geometry.jl.swo Outdated Show resolved Hide resolved
@adbayonao adbayonao marked this pull request as draft January 20, 2025 08:57
@adbayonao adbayonao marked this pull request as ready for review January 20, 2025 08:59
@adbayonao adbayonao marked this pull request as draft January 20, 2025 09:57
@adbayonao adbayonao marked this pull request as ready for review January 20, 2025 15:46
@adbayonao adbayonao marked this pull request as draft January 22, 2025 16:17
@aelligp aelligp marked this pull request as ready for review January 23, 2025 14:39
Copy link

github-actions bot commented Jan 23, 2025

Your PR requires formatting changes to meet the project's style guidelines.
Please consider running Runic (git runic main) to apply these changes.

Click here to view the suggested changes.
diff --git a/ext/GMT_utils.jl b/ext/GMT_utils.jl
index 98998b7..14885d9 100644
--- a/ext/GMT_utils.jl
+++ b/ext/GMT_utils.jl
@@ -158,12 +158,12 @@ function import_GeoTIFF(fname::String; fieldname = :layer1, negative = false, is
         if length(size(G.image)) == 3
             data = permutedims(G.image, [2, 1, 3])
         elseif length(size(G.image)) == 2
-            if size(G.image)==(nx,ny)
-              data[:,:,1] = G.image
-            elseif size(G.image)==(ny,nx)
-              data[:,:,1] = G.image'
+            if size(G.image) == (nx, ny)
+                data[:, :, 1] = G.image
+            elseif size(G.image) == (ny, nx)
+                data[:, :, 1] = G.image'
             else
-              error("unknown size; ")
+                error("unknown size; ")
             end
         end
 
diff --git a/src/Setup_geometry.jl b/src/Setup_geometry.jl
index b33c0a1..d796006 100644
--- a/src/Setup_geometry.jl
+++ b/src/Setup_geometry.jl
@@ -243,13 +243,15 @@ julia> write_paraview(Grid, "Ridge_Thermal_Structure")  # Save model to Paraview
 1-element Vector{String}:
  "Ridge_Thermal_Structure.vts"
 """
-function add_box!(Phase, Temp, Grid::AbstractGeneralGrid;       # required input
-        xlim::Tuple = (20,100), ylim=nothing, zlim::Tuple = (10,80),     # limits of the box
-        Origin=nothing, StrikeAngle=0, DipAngle=0,      # origin & dip/strike
+function add_box!(
+        Phase, Temp, Grid::AbstractGeneralGrid;       # required input
+        xlim::Tuple = (20, 100), ylim = nothing, zlim::Tuple = (10, 80),     # limits of the box
+        Origin = nothing, StrikeAngle = 0, DipAngle = 0,      # origin & dip/strike
         phase = ConstantPhase(1),                       # Sets the phase number(s) in the box
-        T=nothing,                              # Sets the thermal structure (various functions are available)
-        segments=nothing,                       # Allows defining multiple ridge segments  
-        cell=false )                            # if true, Phase and Temp are defined on cell centers
+        T = nothing,                              # Sets the thermal structure (various functions are available)
+        segments = nothing,                       # Allows defining multiple ridge segments
+        cell = false
+    )                            # if true, Phase and Temp are defined on cell centers
 
 
     # Retrieve 3D data arrays for the grid
@@ -1148,31 +1150,31 @@ Note: the thermal age at the mid oceanic ridge is set to 1 year to avoid divisio
     MORside = "left"   # side of box where the MOR is located
     SpreadingVel = 3   # spreading velocity [cm/yr]
     AgeRidge = 0       # Age of the ridge [Myrs
-    maxAge  = 60       # maximum thermal age of plate [Myrs]
+    maxAge = 60       # maximum thermal age of plate [Myrs]
 end
 
 function compute_thermal_structure(Temp, X, Y, Z, Phase, s::SpreadingRateTemp)
-    @unpack Tsurface, Tmantle, Adiabat, MORside, SpreadingVel, AgeRidge, maxAge  = s
-
-    kappa       =   1e-6;
-    SecYear     =   3600*24*365
-    dz          =   Z[end]-Z[1];
-
-    MantleAdiabaticT    =   Tmantle .+ Adiabat*abs.(Z);   # Adiabatic temperature of mantle
-           
-    if MORside=="left"
-        Distance = X .- X[1,1,1];
-    elseif MORside=="right"
-        Distance = X[end,1,1] .- X;
-    elseif MORside=="front"
-        Distance = Y .- Y[1,1,1];
-    elseif MORside=="back"
-        Distance = Y[1,end,1] .- Y;
+    @unpack Tsurface, Tmantle, Adiabat, MORside, SpreadingVel, AgeRidge, maxAge = s
+
+    kappa = 1.0e-6
+    SecYear = 3600 * 24 * 365
+    dz = Z[end] - Z[1]
+
+    MantleAdiabaticT = Tmantle .+ Adiabat * abs.(Z)    # Adiabatic temperature of mantle
+
+    if MORside == "left"
+        Distance = X .- X[1, 1, 1]
+    elseif MORside == "right"
+        Distance = X[end, 1, 1] .- X
+    elseif MORside == "front"
+        Distance = Y .- Y[1, 1, 1]
+    elseif MORside == "back"
+        Distance = Y[1, end, 1] .- Y
 
     else
         error("unknown side")
     end
-        
+
     for i in eachindex(Temp)
         ThermalAge = abs(Distance[i] * 1.0e3 * 1.0e2) / SpreadingVel + AgeRidge * 1.0e6    # Thermal age in years
         if ThermalAge > maxAge * 1.0e6
@@ -1187,7 +1189,7 @@ function compute_thermal_structure(Temp, X, Y, Z, Phase, s::SpreadingRateTemp)
         Temp[i] = (Tsurface .- Tmantle) * erfc((abs.(Z[i]) * 1.0e3) ./ (2 * sqrt(kappa * ThermalAge))) + MantleAdiabaticT[i]
 
     end
-        
+
     return Temp
 end
 
@@ -1218,14 +1220,14 @@ The thermal age is capped at `maxAge` years, and the temperature is adjusted bas
 
 function compute_thermal_structure(Temp, X, Y, Z, Phase, s::SpreadingRateTemp, segments::Vector{Tuple{Tuple{Float64, Float64}, Tuple{Float64, Float64}}})
     @unpack Tsurface, Tmantle, Adiabat, SpreadingVel, AgeRidge, maxAge = s
-    kappa = 1e-6;
+    kappa = 1.0e-6
     SecYear = 3600 * 24 * 365
-    dz = Z[end]-Z[1];
+    dz = Z[end] - Z[1]
 
     MantleAdiabaticT = Tmantle .+ Adiabat * abs.(Z)
 
     #Create delimiters
-    delimiters = [(segments[i][2], segments[i + 1][1]) for i in 1:length(segments) - 1] 
+    delimiters = [(segments[i][2], segments[i + 1][1]) for i in 1:(length(segments) - 1)]
 
     for I in eachindex(X)
         px, py, pz = X[I], Y[I], Z[I]
@@ -1241,18 +1243,18 @@ function compute_thermal_structure(Temp, X, Y, Z, Phase, s::SpreadingRateTemp, s
         Distance = perpendicular_distance_to_segment(px, py, x1, y1, x2, y2)
 
         # Calculate thermal age
-        ThermalAge = abs(Distance * 1e5) / SpreadingVel + AgeRidge * 1e6  # Thermal age in years
-        if ThermalAge > maxAge * 1e6
-            ThermalAge = maxAge * 1e6
+        ThermalAge = abs(Distance * 1.0e5) / SpreadingVel + AgeRidge * 1.0e6  # Thermal age in years
+        if ThermalAge > maxAge * 1.0e6
+            ThermalAge = maxAge * 1.0e6
         end
 
         ThermalAge = ThermalAge * SecYear  # Convert to seconds
         if ThermalAge == 0
-            ThermalAge = 1e-6  # Avoid zero
+            ThermalAge = 1.0e-6  # Avoid zero
         end
 
         # Calculate temperature
-        Temp[I] = (Tsurface - Tmantle) * erfc(abs(pz) * 1e3 / (2 * sqrt(kappa * ThermalAge))) + MantleAdiabaticT[I]
+        Temp[I] = (Tsurface - Tmantle) * erfc(abs(pz) * 1.0e3 / (2 * sqrt(kappa * ThermalAge))) + MantleAdiabaticT[I]
     end
 
     return Temp
@@ -1271,7 +1273,7 @@ end
 # Function to determine the side of a point with respect to a line (adjusted for segment direction)
 function side_of_line(x, y, x1, y1, x2, y2, direction)
     side = (x2 - x1) * (y - y1) - (y2 - y1) * (x - x1)
-    direction == :left ? side > 0 : side < 0
+    return direction == :left ? side > 0 : side < 0
 end
 
 # Function to determine in which region a point lies (based on delimiters)
diff --git a/test/runtests.jl b/test/runtests.jl
index 91cb814..0a4b346 100644
--- a/test/runtests.jl
+++ b/test/runtests.jl
@@ -75,7 +75,7 @@ using Test
     end
 
     @testset "Ridge Thermal Structure Tests" begin
-    	include("test_ridge_segments.jl")
+        include("test_ridge_segments.jl")
     end
 
     @testset "Waterflow" begin
diff --git a/test/test_ridge_segments.jl b/test/test_ridge_segments.jl
index 36b530a..d394c38 100644
--- a/test/test_ridge_segments.jl
+++ b/test/test_ridge_segments.jl
@@ -4,9 +4,9 @@ using Test
 @testset "Ridge Thermal Structure Tests" begin
     # Grid parameters
     nx, ny, nz = 512, 512, 128
-    x = range(-1000, 1000, length=nx)
-    y = range(-1000, 1000, length=ny)
-    z = range(-660, 0, length=nz)
+    x = range(-1000, 1000, length = nx)
+    y = range(-1000, 1000, length = ny)
+    z = range(-660, 0, length = nz)
     Grid = CartData(xyz_grid(x, y, z))
 
     # Phases and temperature
@@ -17,12 +17,12 @@ using Test
     segments = [
         ((-500.0, -1000.0), (-500.0, 0.0)),  # Segment 1
         ((-250.0, 0.0), (-250.0, 200.0)),    # Segment 2
-        ((-750.0, 200.0), (-750.0, 1000.0))  # Segment 3
+        ((-750.0, 200.0), (-750.0, 1000.0)),  # Segment 3
     ]
 
     # Lithospheric phases
-    lith = LithosphericPhases(Layers=[15 55], Phases=[1 2], Tlab=1250)
-    add_box!(Phases, Temp, Grid; xlim=(-1000.0,0.0), ylim=(-500.0, 500.0), zlim=(-80.0, 0.0), phase = lith, T=SpreadingRateTemp(SpreadingVel=3), segments=segments)
+    lith = LithosphericPhases(Layers = [15 55], Phases = [1 2], Tlab = 1250)
+    add_box!(Phases, Temp, Grid; xlim = (-1000.0, 0.0), ylim = (-500.0, 500.0), zlim = (-80.0, 0.0), phase = lith, T = SpreadingRateTemp(SpreadingVel = 3), segments = segments)
 
     # Add and save results
     Grid = addfield(Grid, (; Phases, Temp))
@@ -30,10 +30,10 @@ using Test
 
     @test minimum(Temp) >= 0.0  # Minimum temperature
     @test maximum(Temp) <= 1350.0  # Maximum temperature
-    @test all(≥(0),    Temp) # Ensure no negative temperatures
+    @test all(≥(0), Temp) # Ensure no negative temperatures
     @test all(≤(1350), Temp) # Ensure no temperatures above max
 
     # Check if phases are correctly assigned in expected regions
     @test first(Phases) == 2  # Example: Verify a point's phase
-    @test last(Phases)  == 2  # Example: Verify another point's phase
+    @test last(Phases) == 2  # Example: Verify another point's phase
 end

@boriskaus boriskaus merged commit 74760eb into JuliaGeodynamics:main Jan 28, 2025
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants