@@ -11,7 +11,7 @@ import Base: show
1111# These are routines that help to create input geometries, such as slabs with a given angle
1212#
1313
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!,
1515 make_volc_topo,
1616 ConstantTemp, LinearTemp, HalfspaceCoolingTemp, SpreadingRateTemp, LithosphericTemp, LinearWeightedTemperature,
1717 McKenzie_subducting_slab,
@@ -37,6 +37,24 @@ function flatten_index_dimensions(Phase, ind_vec::Vector{CartesianIndex{3}})
3737 return ind2D
3838end
3939
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+
4058"""
4159 add_stripes!(Phase, Grid::AbstractGeneralGrid;
4260 stripAxes = (1,1,0),
@@ -792,7 +810,7 @@ function add_volcano!(
792810 end
793811 end
794812
795- ind_flat = flatten_index_dimensions (Temp , ind)
813+ ind_flat = flatten_index_dimensions (Phases , ind)
796814
797815 # @views Temp[ind .== false] .= 0.0
798816 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;
19291947
19301948 return nothing
19311949end
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