@@ -11,7 +11,7 @@ import Base: show
11
11
# These are routines that help to create input geometries, such as slabs with a given angle
12
12
#
13
13
14
- export add_box!, add_sphere!, add_ellipsoid!, add_cylinder!, add_layer!, add_polygon!, add_slab!, add_stripes!, add_volcano!,
14
+ export add_box!, add_sphere!, add_ellipsoid!, add_cylinder!, add_layer!, add_polygon!, add_slab!, add_stripes!, add_volcano!, add_fault!,
15
15
make_volc_topo,
16
16
ConstantTemp, LinearTemp, HalfspaceCoolingTemp, SpreadingRateTemp, LithosphericTemp, LinearWeightedTemperature,
17
17
McKenzie_subducting_slab,
@@ -37,6 +37,24 @@ function flatten_index_dimensions(Phase, ind_vec::Vector{CartesianIndex{3}})
37
37
return ind2D
38
38
end
39
39
40
+ """
41
+ ind2D = flatten_index_dimensions(Phase, ind_vec::Vector{CartesianIndex{3}})
42
+
43
+ This converts the indices to purely 2D indices if the array `phase` is 2D
44
+ """
45
+ function flatten_index_dimensions (Phase:: AbstractArray{T, N} , ind_vec:: Array{Bool, 3} ) where {T,N}
46
+ if N== 2
47
+ ind2D = Vector {CartesianIndex{2}} (undef,length (ind_vec))
48
+ for (num, ind) in enumerate (ind_vec)
49
+ ind2D[num] = CartesianIndex (ind[1 ], ind[3 ])
50
+ end
51
+ else
52
+ ind2D = ind_vec
53
+ end
54
+
55
+ return ind2D
56
+ end
57
+
40
58
"""
41
59
add_stripes!(Phase, Grid::AbstractGeneralGrid;
42
60
stripAxes = (1,1,0),
@@ -792,7 +810,7 @@ function add_volcano!(
792
810
end
793
811
end
794
812
795
- ind_flat = flatten_index_dimensions (Temp , ind)
813
+ ind_flat = flatten_index_dimensions (Phases , ind)
796
814
797
815
# @views Temp[ind .== false] .= 0.0
798
816
Temp[ind_flat] = compute_thermal_structure (Temp[ind_flat], Grid. x. val[ind], Grid. y. val[ind], depth[ind], Phases[ind_flat], T)
@@ -1929,3 +1947,103 @@ function add_slab!(Phase, Temp, Grid::AbstractGeneralGrid, trench::Trench;
1929
1947
1930
1948
return nothing
1931
1949
end
1950
+
1951
+ """
1952
+ add_fault!(Phase, Temp, Grid::AbstractGeneralGrid;
1953
+ Start=(20,100), End=(10,80),
1954
+ Fault_thickness=10.0,
1955
+ Depth_extent=nothing,
1956
+ DipAngle=0e0,
1957
+ phase=ConstantPhase(1),
1958
+ T=nothing,
1959
+ cell=false)
1960
+
1961
+ Adds a fault to the given 3D grid by modifying the `Phase` and `Temp` arrays.
1962
+ For a 2D grid, use `add_box` instead.
1963
+
1964
+ # Arguments
1965
+ - `Phase`: Phase array
1966
+ - `Temp`: Temp array
1967
+ - `Grid`: The grid on which the fault is to be added.
1968
+ - `Start`: Tuple representing the starting coordinates of the fault (X, Y).
1969
+ - `End`: Tuple representing the ending coordinates of the fault (X, Y).
1970
+ - `Fault_thickness`: Thickness of the fault.
1971
+ - `Depth_extent`: Depth extent of the fault. If `nothing`, the fault extends through the entire domain.
1972
+ - `DipAngle`: Dip angle of the fault.
1973
+ - `phase`: Phase to be assigned to the fault.
1974
+ - `T`: Temperature to be assigned to the fault. If `nothing`, the temperature is not modified.
1975
+
1976
+
1977
+ # Example
1978
+ ```julia
1979
+ add_fault!(Phase, Temp, Grid;
1980
+ Start=(20,100), End=(10,80),
1981
+ Fault_thickness=10.0,
1982
+ Depth_extent=(-25.0, 0.0),
1983
+ DipAngle=-10.0,
1984
+ phase=ConstantPhase(1)
1985
+ )
1986
+ ```
1987
+ """
1988
+ function add_fault! (
1989
+ Phase,
1990
+ Temp,
1991
+ Grid:: AbstractGeneralGrid ;
1992
+ Start= (20 ,100 ),
1993
+ End= (10 ,80 ),
1994
+ Fault_thickness= 10.0 ,
1995
+ Depth_extent= nothing ,
1996
+ DipAngle= 0e0 ,
1997
+ phase= ConstantPhase (1 ),
1998
+ T= nothing ,
1999
+ cell= false
2000
+ )
2001
+
2002
+ # Extract the coordinates
2003
+ X, Y, Z = coordinate_grids (Grid, cell= cell)
2004
+
2005
+ # Calculate the direction vector from Start to End
2006
+ direction = (End[1 ] - Start[1 ], End[2 ] - Start[2 ])
2007
+ length = sqrt (direction[1 ]^ 2 + direction[2 ]^ 2 )
2008
+ unit_direction = (direction[1 ], direction[2 ]) ./ length
2009
+
2010
+ # Calculate the fault region based on fault thickness and length
2011
+ fault_half_thickness = Fault_thickness / 2
2012
+
2013
+ # Create a mask for the fault region
2014
+ fault_mask = falses (size (X))
2015
+
2016
+ for k in 1 : size (Z, 3 ), j in 1 : size (Y, 2 ), i in 1 : size (X, 1 )
2017
+ # Rotate the point using the dip angle
2018
+ x_rot, y_rot, z_rot = Rot3D (X[i, j, k], Y[i, j, k], Z[i, j, k], 1.0 , 0.0 , cosd (DipAngle), sind (DipAngle))
2019
+
2020
+ # Calculate the projection of the rotated point onto the fault line
2021
+ projection_length = (x_rot - Start[1 ]) * unit_direction[1 ] + (y_rot - Start[2 ]) * unit_direction[2 ]
2022
+ if 0 ≤ projection_length ≤ length
2023
+ # Calculate the perpendicular distance to the fault line
2024
+ perpendicular_distance = abs ((x_rot - Start[1 ]) * unit_direction[2 ] - (y_rot - Start[2 ]) * unit_direction[1 ])
2025
+ if perpendicular_distance ≤ fault_half_thickness
2026
+ fault_mask[i, j, k] = true
2027
+ end
2028
+ end
2029
+ end
2030
+
2031
+ ind = findall (fault_mask)
2032
+
2033
+ # Apply depth extent if provided
2034
+ if ! isnothing (Depth_extent)
2035
+ ind = ind[Z[ind] .≥ Depth_extent[1 ] .&& Z[ind] .≤ Depth_extent[2 ]]
2036
+ end
2037
+
2038
+ ind_flat = flatten_index_dimensions (Phase, ind)
2039
+
2040
+ # Compute thermal structure accordingly
2041
+ if T != nothing
2042
+ Temp[ind_flat] = compute_thermal_structure (Temp[ind_flat], X[ind], Y[ind], Z[ind], Phase[ind_flat], T)
2043
+ end
2044
+
2045
+ # Set the phase
2046
+ Phase[ind_flat] = compute_phase (Phase[ind_flat], Temp[ind_flat], X[ind], Y[ind], Z[ind], phase)
2047
+
2048
+ return nothing
2049
+ end
0 commit comments