From 00c7734fcce91ede99b8c46a79997a137d7a30f8 Mon Sep 17 00:00:00 2001 From: Austin Blevins Date: Fri, 15 Sep 2023 16:30:27 -0400 Subject: [PATCH 01/42] fixed ejecta_emplace exception bug for quasimc branch --- src/ejecta/ejecta_emplace.f90 | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/ejecta/ejecta_emplace.f90 b/src/ejecta/ejecta_emplace.f90 index 737be2b3..8f97fd41 100644 --- a/src/ejecta/ejecta_emplace.f90 +++ b/src/ejecta/ejecta_emplace.f90 @@ -347,7 +347,6 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ ebh = cumulative_elchange(i,j) - crater_profile(user, crater, lrad) end if - if (user%doregotrack .and. ebh>1.0e-8_DP) then call regolith_streamtube(user,surf,crater,domain,ejb,ejtble,xp,yp,xpi,ypi,lrad,ebh,rm,vsq,volm) vmelt = vmelt + volm @@ -356,10 +355,12 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ end do end if - if (totmelt > vmelt) then - vmeltsheet = totmelt - vmelt - else !give the craters a melt sheet of 1m - vmeltsheet = 1.0_DP * user%pix * user%pix * nmeltsheet + if (user%doregotrack) then + if (totmelt > vmelt) then + vmeltsheet = totmelt - vmelt + else !give the craters a melt sheet of 1m + vmeltsheet = 1.0_DP * user%pix * user%pix * nmeltsheet + end if end if ! extra soften calculation From eaeafeb1504a94631ee38ca0dda5a0180a7c360e Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 19 Sep 2023 15:40:27 -0400 Subject: [PATCH 02/42] Removed some old unused seismic shaking calcs that were causing an FPE --- src/init/init_domain.f90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/init/init_domain.f90 b/src/init/init_domain.f90 index a1010f28..79317177 100644 --- a/src/init/init_domain.f90 +++ b/src/init/init_domain.f90 @@ -75,8 +75,8 @@ subroutine init_domain(user,crater,domain,prod,pdist,vdist,crtscl,nflux) end select ! Preliminary seismic property calculations - user%seisk = THIRD * user%tvel * user%tfrac - user%cohaccel = user%regcoh / user%trho_r + ! user%seisk = THIRD * user%tvel * user%tfrac + ! user%cohaccel = user%regcoh / user%trho_r ! Now we build an idealized production population domain%initialize = .true. From 327096b252ce00cce1c7706dba3b69ba8007c8f3 Mon Sep 17 00:00:00 2001 From: Austin Blevins Date: Thu, 19 Oct 2023 15:02:47 -0400 Subject: [PATCH 03/42] Made it so age information is only calculated when regotrack is turned on --- src/crater/crater_populate.f90 | 60 ++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/src/crater/crater_populate.f90 b/src/crater/crater_populate.f90 index 3c3ef7e7..a3d566cf 100644 --- a/src/crater/crater_populate.f90 +++ b/src/crater/crater_populate.f90 @@ -145,20 +145,22 @@ subroutine crater_populate(user,surf,crater,domain,prod,production_list,vdist,nt ! Reset age clock = 0.0_DP finterval = 1.0_DP / real(ntotcrat,kind=DP) - maxage = user%interval * user%numintervals - if (maxage < 0._DP ) then - write(*,*) "MAJOR ERROR: Negative age!" - stop - else if (maxage < 2330._DP) then - maxageGa = util_t_from_scale(maxage,1e-11_DP,4.5_DP) - else - maxageGa = 4.5_DP !util_t_from_scale only supports ages <4.5 Ga + if (user%doregotrack) then + maxage = user%interval * user%numintervals + if (maxage < 0._DP ) then + write(*,*) "MAJOR ERROR: Negative age!" + stop + else if (maxage < 2330._DP) then + maxageGa = util_t_from_scale(maxage,1e-11_DP,4.5_DP) + else + maxageGa = 4.5_DP !util_t_from_scale only supports ages <4.5 Ga + end if + age_resolution = maxageGa / real(MAXAGEBINS) + write(*,*) "Age resolution: ", age_resolution, " Ga." + do i = 1,MAXAGEBINS + domain%age_bin_times(i) = maxageGa-(i*age_resolution) + end do end if - age_resolution = maxageGa / real(MAXAGEBINS) - write(*,*) "Age resolution: ", age_resolution, " Ga." - do i = 1,MAXAGEBINS - domain%age_bin_times(i) = maxageGa-(i*age_resolution) - end do domain%age_counter = 1 oldGa = 0._DP @@ -175,25 +177,27 @@ subroutine crater_populate(user,surf,crater,domain,prod,production_list,vdist,nt timestamp_old = real(curyear + real(icrater,kind=DP) / real(ntotcrat,kind=DP) * user%interval,kind=DP) icrater = icrater + 1 crater%timestamp = real(curyear + real(icrater,kind=DP) / real(ntotcrat,kind=DP) * user%interval,kind=DP) - if (icrater .eq. 1) then - agemin = crater%timestamp * 0.9_DP - end if - if (crater%timestamp < 2330._DP) then - if (oldGa > 0._DP) then - if (user%numintervals .eq. 1) then - crater%timestampGa = util_t_from_scale(maxage-crater%timestamp,agemin,oldGa) + if (user%doregotrack) then + if (icrater .eq. 1) then + agemin = crater%timestamp * 0.9_DP + end if + if (crater%timestamp < 2330._DP) then + if (oldGa > 0._DP) then + if (user%numintervals .eq. 1) then + crater%timestampGa = util_t_from_scale(maxage-crater%timestamp,agemin,oldGa) + else + crater%timestampGa = util_t_from_scale(maxage-crater%timestamp,1e-10_DP,oldGa) + end if else - crater%timestampGa = util_t_from_scale(maxage-crater%timestamp,1e-10_DP,oldGa) + if (user%numintervals .eq. 1) then + crater%timestampGa = util_t_from_scale(maxage-crater%timestamp,agemin,maxageGa) + else + crater%timestampGa = util_t_from_scale(maxage-crater%timestamp,1e-10_DP,maxageGa) + end if end if else - if (user%numintervals .eq. 1) then - crater%timestampGa = util_t_from_scale(maxage-crater%timestamp,agemin,maxageGa) - else - crater%timestampGa = util_t_from_scale(maxage-crater%timestamp,1e-10_DP,maxageGa) - end if + crater%timestampGa = 4.5_DP end if - else - crater%timestampGa = 4.5_DP end if pbarpos = nint(real(icrater) / real(ntotcrat) * PBARRES) if (crater%timestampGa < domain%age_bin_times(domain%age_counter)) then From b2264c603c941fffb129af33e0bbc63a06b2df32 Mon Sep 17 00:00:00 2001 From: Austin Michael Blevins Date: Fri, 20 Oct 2023 14:35:51 -0400 Subject: [PATCH 04/42] Added bash scripts to compile using debug or production flags in cmake --- .gitignore | 3 ++- compile_debug.bash | 2 ++ compile_production.bash | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 compile_debug.bash create mode 100644 compile_production.bash diff --git a/.gitignore b/.gitignore index 733dc353..af49a6b0 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ !version.txt !src/**.f90 !ctem/**.py -!cmake/Modules/*.cmake \ No newline at end of file +!cmake/Modules/*.cmake +!*.bash diff --git a/compile_debug.bash b/compile_debug.bash new file mode 100644 index 00000000..c1102cd7 --- /dev/null +++ b/compile_debug.bash @@ -0,0 +1,2 @@ +cmake -B build -S . -DCMAKE_BUILD_TYPE=Debug +cmake --build build diff --git a/compile_production.bash b/compile_production.bash new file mode 100644 index 00000000..bc4e8a87 --- /dev/null +++ b/compile_production.bash @@ -0,0 +1,2 @@ +cmake -B build -S . +cmake --build build From 0c76f5dedc23f83b6e35c3a53309dba7e49e26da Mon Sep 17 00:00:00 2001 From: Austin Michael Blevins Date: Mon, 23 Oct 2023 10:14:29 -0400 Subject: [PATCH 05/42] Changed the names of the bash scripts for easier use with the tab key in the terminal --- compile_debug.bash => debug_compile.bash | 0 compile_production.bash => production_compile.bash | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename compile_debug.bash => debug_compile.bash (100%) rename compile_production.bash => production_compile.bash (100%) diff --git a/compile_debug.bash b/debug_compile.bash similarity index 100% rename from compile_debug.bash rename to debug_compile.bash diff --git a/compile_production.bash b/production_compile.bash similarity index 100% rename from compile_production.bash rename to production_compile.bash From 77e874045a183511e60af27b5027f75ea282e1e6 Mon Sep 17 00:00:00 2001 From: David A Minton Date: Mon, 23 Oct 2023 12:28:41 -0400 Subject: [PATCH 06/42] Removed redundant file --- examples/global-lunar-bombardment/ctemdriver.py | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 examples/global-lunar-bombardment/ctemdriver.py diff --git a/examples/global-lunar-bombardment/ctemdriver.py b/examples/global-lunar-bombardment/ctemdriver.py deleted file mode 100644 index 50392285..00000000 --- a/examples/global-lunar-bombardment/ctemdriver.py +++ /dev/null @@ -1,3 +0,0 @@ -import ctem -sim = ctem.Simulation() -sim.run() \ No newline at end of file From 8ac3810ab741a958a7493549f669d354ea477971 Mon Sep 17 00:00:00 2001 From: David A Minton Date: Mon, 23 Oct 2023 12:45:17 -0400 Subject: [PATCH 07/42] Fixed format statement to allow for more space for big numers --- src/crater/crater_populate.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crater/crater_populate.f90 b/src/crater/crater_populate.f90 index a3d566cf..8a4f5569 100644 --- a/src/crater/crater_populate.f90 +++ b/src/crater/crater_populate.f90 @@ -225,7 +225,7 @@ subroutine crater_populate(user,surf,crater,domain,prod,production_list,vdist,nt ! generate random crater call crater_generate(user,crater,domain,prod,production_list,vdist,surf) if (user%testflag) then - write(message,'("Dc=",F8.1," Dt=",F8.1)') crater%fcrat, crater%rad*2 + write(message,'("Dc=",F9.1," Dt=",F9.1)') crater%fcrat, crater%rad*2 call io_updatePbar(message) end if if (crater%fcrat > domain%biggest_crater) then ! End the run if the crater is too big From 0b171abb8119c3df188593ab0df5e3c59b02c13c Mon Sep 17 00:00:00 2001 From: Austin Blevins Date: Tue, 24 Oct 2023 12:58:08 -0400 Subject: [PATCH 08/42] Minor QoL changes, including notes on regolith_streamtube explaining certain variables --- debug_compile.bash | 1 + production_compile.bash | 1 + src/regolith/regolith_streamtube.f90 | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/debug_compile.bash b/debug_compile.bash index c1102cd7..05eb2280 100644 --- a/debug_compile.bash +++ b/debug_compile.bash @@ -1,2 +1,3 @@ +cmake -P distclean.cmake cmake -B build -S . -DCMAKE_BUILD_TYPE=Debug cmake --build build diff --git a/production_compile.bash b/production_compile.bash index bc4e8a87..8f07ea27 100644 --- a/production_compile.bash +++ b/production_compile.bash @@ -1,2 +1,3 @@ +cmake -P distclean.cmake cmake -B build -S . cmake --build build diff --git a/src/regolith/regolith_streamtube.f90 b/src/regolith/regolith_streamtube.f90 index 28c28d08..16389a23 100644 --- a/src/regolith/regolith_streamtube.f90 +++ b/src/regolith/regolith_streamtube.f90 @@ -53,7 +53,7 @@ ! Arguments : surf :: surface ! ! -! Notes : +! Notes : 'eradc' is the center of the ejection radius. 'eradi' is inner, 'erado' is outer. 'cnt' is counting number. 'cmax', 'ri', and 'rip1' concern streamtube geometry. ! !********************************************************************************************************************************** subroutine regolith_streamtube(user,surf,crater,domain,ejb,ejtble,xp,yp,xpi,ypi,lrad,ebh,rm,vsq,volm) From 924c89cea0ba185cac6779799758390ba4068a42 Mon Sep 17 00:00:00 2001 From: Austin Blevins Date: Thu, 26 Oct 2023 13:56:44 -0400 Subject: [PATCH 09/42] input file changes for easy popping --- examples/global-lunar-bombardment/ctem.in | 30 ++++----- examples/global-lunar-bombardment/temp.in | 76 ----------------------- 2 files changed, 15 insertions(+), 91 deletions(-) delete mode 100644 examples/global-lunar-bombardment/temp.in diff --git a/examples/global-lunar-bombardment/ctem.in b/examples/global-lunar-bombardment/ctem.in index 7b6750a7..97925a0e 100644 --- a/examples/global-lunar-bombardment/ctem.in +++ b/examples/global-lunar-bombardment/ctem.in @@ -2,21 +2,21 @@ ! Testing input. These are used to perform non-Monte Carlo tests. -testflag F ! Set to T to create a single crater with user-defined impactor properties -testimp 100000 ! Diameter of test impactor (m) +testflag T ! Set to T to create a single crater with user-defined impactor properties +testimp 15000.0 ! Diameter of test impactor (m) testvel 18.3e3 ! Velocity of test crater (m/s) -testang 45.0 ! Impact angle of test crater (deg) - Default 90.0 -testxoffset 0 ! x-axis offset of crater center from grid center (m) - Default 0.0 -testyoffset 0 ! y-axis offset of crater center from grid center (m) - Default 0.0 +testang 90.0 ! Impact angle of test crater (deg) - Default 90.0 +testxoffset 0.0 ! x-axis offset of crater center from grid center (m) - Default 0.0 +testyoffset 0.0 ! y-axis offset of crater center from grid center (m) - Default 0.0 tallyonly F ! Tally the craters without generating any craters testtally F quasimc F ! MC run constrained by non-MC 'real' craters given in a list -realcraterlist qmctest2.in ! list of 'real' craters for Quasi-MC runs +realcraterlist craterlist.in ! list of 'real' craters for Quasi-MC runs ! IDL driver in uts -interval 10.0 +interval 1.0 numintervals 1 ! Total number of intervals (total time = interval * numintervals) <--when runtype is 'single' restart F ! Restart a previous run impfile NPFextrap.dat ! Impactor SFD rate file (col 1: Dimp (m), col 2: ! impactors > D (m**(-2) y**(-1)) @@ -33,10 +33,10 @@ runtype single ! Run type: options are normal / ! statistical: surface is reset between intervals ! CTEM required inputs -seed 765 ! Random number generator seed -gridsize 500 ! Size of grid in pixels +seed 1111 ! Random number generator seed +gridsize 1000 ! Size of grid in pixels numlayers 10 ! Number of perched layers -pix 12.32e3 ! Pixel size (m) +pix 6.16e3 ! Pixel size (m) mat rock ! Material (rock or ice) ! Bedrock scaling parameters mu_b 0.55e0 ! Experimentally derived parameter for bedrock crater scaling law @@ -60,11 +60,11 @@ doseismic F ! Perform seismic shaking calcul ! Optional inputF These have internally set default values that work reasonable well. Comment them out with deplimit 9e99 ! Depth limit for craters (m) - Default is to ignore. -maxcrat 0.15 ! Fraction of gridsize that maximum crater can be - Default 1.0 (0.15 for full MC; 3.15e-2 for Quasi-MC) +maxcrat 3.15e-2 ! Fraction of gridsize that maximum crater can be - Default 1.0 <--0.15 for full MC; 3.15e-2 for Quasi-MC killatmaxcrater F ! Stop the run if a crater larger than the maximum is produced - Default F -basinimp 35.0e3 ! Size of impactor to switch to lunar basin scaling law - Default is to ignore +basinimp 35.0e6 ! Size of impactor to switch to lunar basin scaling law - Default is to ignore docollapse T ! Do slope collapse - Default T -dosoftening T ! Do ejecta softening - Default T +dosoftening F ! Do ejecta softening - Default T doangle T ! Vary the impact angle. Set to F to have only vertical impacts - Default T Kd1 0.0001 psi 2.000 @@ -74,5 +74,5 @@ doregotrack T dorays F superdomain F dorealistic F -domixing T -dotopodiffusion F \ No newline at end of file +dotopodiffusion F +domixing F \ No newline at end of file diff --git a/examples/global-lunar-bombardment/temp.in b/examples/global-lunar-bombardment/temp.in deleted file mode 100644 index 328c21ed..00000000 --- a/examples/global-lunar-bombardment/temp.in +++ /dev/null @@ -1,76 +0,0 @@ -! CTEM Input file - - -! Testing input. These are used to perform non-Monte Carlo tests. -testflag T! F ! Set to T to create a single crater with user-defined impactor properties -testimp 10 ! 15000.0 ! Diameter of test impactor (m) -testvel 18.3e3 ! Velocity of test crater (m/s) -testang 45.0 ! Impact angle of test crater (deg) - Default 90.0 -testxoffset 0.0 ! x-axis offset of crater center from grid center (m) - Default 0.0 -testyoffset 0.0 ! y-axis offset of crater center from grid center (m) - Default 0.0 -tallyonly F ! Tally the craters without generating any craters -testtally F -quasimc F! T ! MC run constrained by non-MC 'real' craters given in a list -realcraterlist qmctest.in ! list of 'real' craters for Quasi-MC runs - - - -! IDL driver in uts -interval 1 ! 0.1 -numintervals 1 ! 1 ! Total number of interval 1 !s (total time = interval 1 ! * numintervals 1 !) <--when runtype is 'single' -restart F ! Restart a previous run -impfile NPFextrap.dat ! Impactor SFD rate file (col 1: Dimp (m), col 2: ! impactors > D (m**(-2) y**(-1)) -popupconsole F ! Pop up console window every output interval 1 ! -saveshaded F ! Output shaded relief images -saverego T ! Output regolith map images -savepres F ! Output simplified console display images (presentation-compatible images) -savetruelist T ! Save the true cumulative crater distribution for each interval 1 ! (large file size) -sfdcompare LOLASethCraterCatalogv8gt20-binned.dat ! File name for the SFD comparison file used in the console display -shadedminh -85.0 ! Minimum height for shaded relief map (m) (Default - automatic) -shadedmaxh 85.0 ! Maximum height for shaded relief map (m) (Default - automatic) -runtype single ! Run type: options are normal / statistical - ! single: craters accumulate in successive interval 1 !s - ! statistical: surface is reset between interval 1 !s - -! CTEM required inputs -seed 76535 ! Random number generator seed -gridsize 2000 ! Size of grid in pixels -numlayers 10 ! Number of perched layers -pix 3.08e3 ! Pixel size (m) -mat rock ! Material (rock or ice) -! Bedrock scaling parameters -mu_b 0.55e0 ! Experimentally derived parameter for bedrock crater scaling law -kv_b 0.20e0 ! Experimentally derived parameter for bedrock crater scaling law -trho_b 2250.0e0 ! Target density (bedrock) (kg/m**3) -ybar_b 0.0e6 ! Bedrock strength (Pa) -! Regolith scaling parameters -mu_r 0.55e0 ! Experimentally derived parameter for regolith crater scaling law -kv_r 0.20e0 ! Experimentally derived parameter for regolith crater scaling law -trho_r 2250.0e0 ! Target density (regolith) (kg/m**3) -ybar_r 0.00e6 ! Regolith strength (Pa) -! Body parameters -gaccel 1.62e0 ! Gravitational acceleration at target (m/s**2) -trad 1737.35e3 ! Target radius (m) -prho 2500.0e0 ! Projectile density (kg/m**3) -sfdfile production.dat ! Impactor SFD file (col 1: Dimp (m), col 2: ! impactors > D -velfile lunar-MBA-impactor-velocities.dat ! Impactor velocity dist file - -! Seismic shaking input (required if seismic shaking is set to T, otherwise ignored) -doseismic F ! Perform seismic shaking calculations with each impact - Default F - -! Optional inputF These have internally set default values that work reasonable well. Comment them out with -deplimit 9e99 ! Depth limit for craters (m) - Default is to ignore. -maxcrat 3.15e-2 ! Fraction of gridsize that maximum crater can be - Default 1.0 -killatmaxcrater F ! Stop the run if a crater larger than the maximum is produced - Default F -basinimp 35.0e3 ! Size of impactor to switch to lunar basin scaling law - Default is to ignore -docollapse T ! Do slope collapse - Default T -dosoftening T ! Do ejecta softening - Default T -doangle T ! Vary the impact angle. Set to F to have only vertical impacts - Default T -Kd1 0.0001 -psi 2.000 -fe 4.00 -ejecta_truncation 4.0 -doregotrack T -dorays F -superdomain F -dorealistic F From 1a1f03c73df4faf759227e3f2a771b396eb1b245 Mon Sep 17 00:00:00 2001 From: Austin Blevins Date: Thu, 26 Oct 2023 15:11:44 -0400 Subject: [PATCH 10/42] fixed a bug with the melt index arrays --- src/crater/crater_subpixel_diffusion.f90 | 11 +- src/crater/crater_superdomain.f90 | 26 +- src/crater/module_crater.f90 | 60 +--- src/ejecta/ejecta_emplace.f90 | 270 +++++++++--------- src/ejecta/ejecta_ray_pattern.f90 | 105 ++++--- src/ejecta/module_ejecta.f90 | 9 +- src/regolith/module_regolith.f90 | 2 +- src/regolith/regolith_subpixel_streamtube.f90 | 2 +- 8 files changed, 244 insertions(+), 241 deletions(-) diff --git a/src/crater/crater_subpixel_diffusion.f90 b/src/crater/crater_subpixel_diffusion.f90 index 3da7b696..630d4401 100644 --- a/src/crater/crater_subpixel_diffusion.f90 +++ b/src/crater/crater_subpixel_diffusion.f90 @@ -45,7 +45,7 @@ subroutine crater_subpixel_diffusion(user,surf,nflux,domain,finterval,kdiffin) real(DP),dimension(3) :: rn real(DP) :: superlen,rayfrac,cutout,fe,fd type(cratertype) :: crater - real(DP) :: eji, diffi + real(DP),dimension(:,:),allocatable :: diffdistribution,ejdistribution integer(I4B),dimension(:,:),allocatable :: ejisray real(DP) :: xbar,ybar,dD,xp,yp,areafrac,krad,supersize,lrad integer(I8B),dimension(user%gridsize,user%gridsize) :: Ngrid @@ -174,6 +174,9 @@ subroutine crater_subpixel_diffusion(user,surf,nflux,domain,finterval,kdiffin) jmax = ypi - crater%ylpx + allocate(diffdistribution(imin:imax,jmin:jmax)) + allocate(ejdistribution(imin:imax,jmin:jmax)) + call ejecta_ray_pattern(user,surf,crater,inc,imin,imax,jmin,jmax,diffdistribution,ejdistribution) ! Loop over affected matrix area !!$OMP PARALLEL DO DEFAULT(SHARED) IF(inc > INCPAR) & !!$OMP FIRSTPRIVATE(jmin,jmax,imin,imax) & @@ -182,17 +185,17 @@ subroutine crater_subpixel_diffusion(user,surf,nflux,domain,finterval,kdiffin) do i = imin,imax xpi = crater%xlpx + i ypi = crater%ylpx + j - call ejecta_ray_pattern(user,crater,i,j,diffi,eji) - kdiff(xpi,ypi) = kdiff(xpi,ypi) + dKdN * diffi + kdiff(xpi,ypi) = kdiff(xpi,ypi) + dKdN * diffdistribution(i,j) !TEMP xp = xpi * user%pix yp = ypi * user%pix lrad = sqrt((xp - crater%xl)**2 + (yp - crater%yl)**2) - surf(xpi,ypi)%ejcov = surf(xpi,ypi)%ejcov + eji & + surf(xpi,ypi)%ejcov = surf(xpi,ypi)%ejcov + ejdistribution(i,j) & * 0.14_DP * crater%frad**(0.74_DP) * (lrad / crater%frad)**(-3) end do end do !!$OMP END PARALLEL DO + deallocate(diffdistribution,ejdistribution) end do end if diff --git a/src/crater/crater_superdomain.f90 b/src/crater/crater_superdomain.f90 index 997bd473..1d1f6092 100644 --- a/src/crater/crater_superdomain.f90 +++ b/src/crater/crater_superdomain.f90 @@ -42,8 +42,8 @@ subroutine crater_superdomain(user,surf,prod,nflux,domain,finterval) real(DP),dimension(2) :: rn real(DP) :: superlen,rayfrac type(cratertype) :: crater - real(DP) :: diffi, eji - logical :: ejisray + real(DP),dimension(:,:),allocatable :: ejdistribution, diffdistribution + integer(I4B),dimension(:,:),allocatable :: ejisray ! Melt or glassy ray test real(DP) :: xp, yp, lradsq, lrad, erad @@ -144,26 +144,40 @@ subroutine crater_superdomain(user,surf,prod,nflux,domain,finterval) lrad = minval(lradif) if (lrad > crater%ejdis) cycle + allocate(ejdistribution(xi:xf,yi:yf)) + allocate(diffdistribution(xi:xf,yi:yf)) + allocate(ejisray(xi:xf,yi:yf)) ! Now generate ray pattern + call ejecta_ray_pattern(user,surf,crater,inc,xi,xf,yi,yf,diffdistribution,ejdistribution) ! Now if doregotrack is on, do melt zone calculation if (user%doregotrack) call regolith_melt_zone_superdomain(user,crater,domain,rm,depthb) + do j = yi,yf + do i = xi,xf + ! Ejecta ray distribution + if (ejdistribution(i,j) > 0.0001_DP) then + ejisray(i,j) = 1 + else + ejisray(i,j) = 0 + end if + end do + end do + if (user%doregotrack) then do j = 1, user%gridsize do i = 1, user%gridsize xpi = i - crater%xlpx ypi = j - crater%ylpx if ((abs(xpi) > inc) .or. (abs(ypi) > inc)) cycle - call ejecta_ray_pattern(user,crater,i,j,diffi,eji) - ejisray = (eji > 0.0001_DP) - if (.not.ejisray) cycle - call regolith_superdomain(user,crater,domain,surf(i,j)%regolayer,eji,& + if (ejisray(xpi,ypi) == 0) cycle + call regolith_superdomain(user,crater,domain,surf(i,j)%regolayer,ejdistribution(xpi,ypi),& i,j,rm,depthb) end do end do end if + deallocate(ejdistribution,diffdistribution,ejisray) end do diff --git a/src/crater/module_crater.f90 b/src/crater/module_crater.f90 index 1c8e9253..c0dd5dfe 100644 --- a/src/crater/module_crater.f90 +++ b/src/crater/module_crater.f90 @@ -33,7 +33,7 @@ subroutine crater_populate(user,surf,crater,domain,prod,production_list,vdist,nt mass,fracdone,nflux,ntotcrat,curyear,rclist) use module_globals implicit none - type(usertype),intent(inout) :: user + type(usertype),intent(in) :: user type(surftype),dimension(:,:),intent(inout) :: surf type(cratertype),intent(inout) :: crater type(domaintype),intent(inout) :: domain @@ -338,62 +338,4 @@ subroutine crater_superdomain(user,surf,prod,nflux,domain,finterval) end subroutine crater_superdomain end interface - - - -! new subroutines added by jundu on 10/15/2022 - - -! Rim_crest: - - ! interface - - ! subroutine Calculate_am_wl_phase_from_diameter(psd_1D,amplitude,wavelength,phase) - ! use module_globals - ! implicit none - ! ! in and out - ! type(psdtype),intent(inout) :: psd_1D - ! real(DP),dimension(:), allocatable,intent(out) :: amplitude,wavelength,phase - ! end subroutine Calculate_am_wl_phase_from_diameter - - ! subroutine Calculate_breakpoint_slope_from_diameter(psd_1D) - ! use module_globals - ! implicit none - ! ! in and out - ! type(psdtype),intent(inout) :: psd_1D - ! end subroutine Calculate_breakpoint_slope_from_diameter - - ! subroutine Calculate_targetPSD_from_breakpoint_slope(psd_1D,wavelength,psd) - ! use module_globals - ! implicit none - ! !in and out - ! type(psdtype), intent(in) :: psd_1D - ! real(DP) ,dimension(:),allocatable,intent(out) :: wavelength,psd - ! end subroutine Calculate_targetPSD_from_breakpoint_slope - - ! subroutine Calculate_am_wl_phase_from_targetPSD(psd_1D,wavelength,psd,amplitude,phase) - ! use module_globals - ! implicit none - ! !in and out - ! type(psdtype), intent(in) :: psd_1D - ! real(DP) ,dimension(:),intent(in) :: wavelength,psd - ! real(DP) ,dimension(:),allocatable,intent(out) :: amplitude,phase - ! end subroutine Calculate_am_wl_phase_from_targetPSD - - - ! subroutine Create_rim(arc_length,psd_1D,amplitude,wavelength,phase,rim_parameter) - ! use module_globals - ! implicit none - ! ! in and out - ! real(DP),intent(in) :: arc_length - ! type(psdtype), intent(in) :: psd_1D - ! real(DP),dimension(:),intent(in) :: amplitude - ! real(DP),dimension(:),intent(in) :: wavelength - ! real(DP),dimension(:),intent(in) :: phase - ! real(DP),intent(out) :: rim_parameter - ! end subroutine Create_rim - - ! end interface - - end module diff --git a/src/ejecta/ejecta_emplace.f90 b/src/ejecta/ejecta_emplace.f90 index 8f97fd41..20706f1c 100644 --- a/src/ejecta/ejecta_emplace.f90 +++ b/src/ejecta/ejecta_emplace.f90 @@ -1,4 +1,4 @@ -!***** ejecta/ejecta_emplace +!****f* ejecta/ejecta_emplace ! Name ! ejecta_emplace -- Calculate ejecta mass during excavation stage. ! SYNOPSIS @@ -93,25 +93,28 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ integer(I4B),intent(in) :: ejtble type(ejbtype),dimension(:),intent(inout) :: ejb real(DP),intent(in) :: deltaMtot - real(DP),dimension(:,:),allocatable,intent(inout) :: cumulative_elchange + real(DP),dimension(:,:),allocatable,intent(out) :: cumulative_elchange integer(I4B),intent(in) :: nmeltsheet real(DP),intent(out) :: vmeltsheet ! Internal variables real(DP) :: lrad,lradsq integer(I4B),parameter :: MAXLOOP = 100 ! Maximum number of times to loop the ejecta angle correction calculation - integer(I4B) :: xpi,ypi,i,j,n,inc,incsq,iradsq,idistorted,jdistorted + integer(I4B) :: xpi,ypi,i,j,k,n,inc,incsq,iradsq,idistorted,jdistorted real(DP) :: xp,yp,fradsq,fradpxsq,radsq,ebh,ejdissq,ejbmass,fmasscons,areafrac,xbar,ybar,krad,kdiffmax - real(DP),dimension(:,:),allocatable :: kdiff,cel - integer(I4B),dimension(:,:,:),allocatable :: indarray - integer(I4B) :: maxhits,nin,nnot,dradsq + real(DP),dimension(:,:),allocatable :: big_cumulative_elchange,kdiff,big_kdiff,cel,big_cel + integer(I4B),dimension(:,:,:),allocatable :: indarray,big_indarray + real(DP),dimension(:,:),allocatable :: ejdistribution,diffdistribution + integer(I4B) :: bigi,bigj,maxhits,nin,nnot,dradsq character(len=MESSAGESIZE) :: message ! message for the progress bar real(DP) :: vmelt, totmelt, volm - real(DP) :: diffi,eji - logical :: bigej + + + ! Ray mixing model variables + real(DP) :: dsc ! Melt zone's radius - real(DP) :: rm, dm, melt + real(DP) :: rm, dm, melt, eradc ! Ejecta pattern distortion parameters real(DP) :: distance,erad,craterslope,landslope,baseline,lrange,frac,ejheight,ebh0,maxdistance @@ -119,6 +122,10 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ real(DP) :: vsq, ejtheta integer(I4B) :: ind,klo + ! Age + real(SP) :: age_mean + + ! Executable code if (user%doregotrack) call regolith_melt_zone(user,crater,crater%imp,crater%impvel,rm,dm,totmelt) @@ -152,39 +159,39 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ incsq = inc**2 - bigej = (inc >= user%gridsize / 2) - if (bigej) then - allocate(cumulative_elchange(0:user%gridsize+1,0:user%gridsize+1)) - allocate(cel(0:user%gridsize+1,0:user%gridsize+1)) - allocate(kdiff(0:user%gridsize+1,0:user%gridsize+1)) - allocate(indarray(2,0:user%gridsize+1,0:user%gridsize+1)) - cumulative_elchange(:,:) = 0.0_DP - cel(:,:) = 0.0_DP - kdiff(:,:) = 0.0_DP - + if (inc >= user%gridsize / 2) then if (user%testflag) then - write(*,*) 'Big ejecta: fcrat =',crater%fcrat, ' Ej/S =',(crater%ejdispx*user%pix)/domain%side, ' Ejrim =', crater%ejrim - else + write(*,*) 'Big ejecta: fcrat =',crater%fcrat, ' Ej/S =',(crater%ejdispx*user%pix)/domain%side, ' Ejrim =', crater%ejrim + else write(message,'("Ejb: Dc=",ES9.2," Ej/S=",F0.3)') crater%fcrat,(crater%ejdispx*user%pix)/domain%side call io_updatePbar(message) - end if - else - allocate(cumulative_elchange(-inc:inc,-inc:inc)) - allocate(cel(-inc:inc,-inc:inc)) - allocate(kdiff(-inc:inc,-inc:inc)) - allocate(indarray(2,-inc:inc,-inc:inc)) - end if + end if + endif + + allocate(cumulative_elchange(-inc:inc,-inc:inc)) + allocate(cel(-inc:inc,-inc:inc)) + allocate(kdiff(-inc:inc,-inc:inc)) + allocate(indarray(2,-inc:inc,-inc:inc)) + allocate(ejdistribution(-inc:inc,-inc:inc)) + allocate(diffdistribution(-inc:inc,-inc:inc)) cumulative_elchange = 0.0_DP kdiff = 0.0_DP indarray = inc - 1 ! initialize this array to point to a corner (this should have 0 elevation change since we're only doing work ! within a circle of radius irad + ! *************************** Continuous Ejecta Formula *****************************! + call ejecta_ray_pattern(user,surf,crater,inc,-inc,inc,-inc,inc,diffdistribution,ejdistribution) ejbmass = 0.0_DP nin = 0 nnot = 0 + !!$OMP PARALLEL DO DEFAULT(PRIVATE) IF(inc > INCPAR) & + !!$OMP SHARED(user,domain,crater,surf,ejb,ejtble) & + !!$OMP SHARED(inc,incsq) & + !!$OMP SHARED(cumulative_elchange,kdiff,kdiffmax,indarray,ejdistribution,diffdistribution) + !open(74, file='meltvserad.csv', status='replace') do j = -inc,inc do i = -inc,inc ! find distance from crater center @@ -199,10 +206,8 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ ! periodic boundary conditions call util_periodic(xpi,ypi,user%gridsize) - if (.not.bigej) then - indarray(1,i,j) = xpi - indarray(2,i,j) = ypi - end if + indarray(1,i,j) = xpi + indarray(2,i,j) = ypi lradsq = (crater%xl - xp)**2 + (crater%yl - yp)**2 lrad = sqrt(lradsq) @@ -246,68 +251,52 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ if (vsq < 0.0_DP) cycle if (distance /= distance) cycle - idistorted = int(i * distance / lrad) if (abs(idistorted) > inc) cycle jdistorted = int(j * distance / lrad) if (abs(jdistorted) > inc) cycle - + iradsq = idistorted**2 + jdistorted**2 if ((iradsq > incsq).or.(distance <= crater%ejrad)) cycle - call ejecta_ray_pattern(user,crater,idistorted,jdistorted,diffi,eji) ! we need to cut a hole out from the inside of the crater xbar = xpi * user%pix - crater%xl ybar = ypi * user%pix - crater%yl areafrac = (1.0_DP - util_area_intersection(crater%ejrad,xbar,ybar,user%pix)) - ebh = areafrac * eji * ebh - if (bigej) then - cumulative_elchange(xpi,ypi) = cumulative_elchange(xpi,ypi) + ebh + crater_profile(user, crater, lrad) - else - cumulative_elchange(i,j) = ebh + crater_profile(user, crater, lrad) - end if + ebh = areafrac * ejdistribution(idistorted,jdistorted) * ebh + cumulative_elchange(i,j) = ebh + crater_profile(user, crater, lrad) if (user%dosoftening) then ! Do extra diffusive degradation over ejecta region areafrac = (1.0_DP - util_area_intersection(crater%frad,xbar,ybar,user%pix)) areafrac = areafrac * util_area_intersection(crater%fe * crater%frad,xbar,ybar,user%pix) - if (bigej) then - kdiff(xpi,ypi) = kdiff(xpi,ypi) + areafrac * diffi * kdiffmax - else - kdiff(i,j) = areafrac * diffi * kdiffmax - end if - + kdiff(i,j) = areafrac * diffdistribution(idistorted,jdistorted) * kdiffmax end if end do end do + !close(74) + !!$OMP END PARALLEL DO + ! if(user%doregotrack .and. user%testflag) then + ! write(*,*) 'Ejected Melt: ', vmelt + ! write(*,*) 'Total Melt: ', totmelt + ! write(*,*) 'ejected / total melt:', vmelt/totmelt + ! end if ejbmass = sum(cumulative_elchange) ! Create buffer to prevent infinite hole bug - if (bigej) then - kdiff(0,:) = 0.0_DP - kdiff(user%gridsize+1,:) = 0.0_DP - kdiff(:,0) = 0.0_DP - kdiff(:,user%gridsize+1) = 0.0_DP - - cumulative_elchange(0,:) = 0.0_DP - cumulative_elchange(user%gridsize+1,:) = 0.0_DP - cumulative_elchange(:,0) = 0.0_DP - cumulative_elchange(:,user%gridsize+1) = 0.0_DP - else - kdiff(-inc,:) = 0.0_DP - kdiff(inc,:) = 0.0_DP - kdiff(:,-inc) = 0.0_DP - kdiff(:,inc) = 0.0_DP - - cumulative_elchange(-inc,:) = 0.0_DP - cumulative_elchange(inc,:) = 0.0_DP - cumulative_elchange(:,-inc) = 0.0_DP - cumulative_elchange(:,inc) = 0.0_DP - end if + kdiff(-inc,:) = 0.0_DP + kdiff(inc,:) = 0.0_DP + kdiff(:,-inc) = 0.0_DP + kdiff(:,inc) = 0.0_DP + + cumulative_elchange(-inc,:) = 0.0_DP + cumulative_elchange(inc,:) = 0.0_DP + cumulative_elchange(:,-inc) = 0.0_DP + cumulative_elchange(:,inc) = 0.0_DP ! Do mass conservation by adjusting ejecta thickness fmasscons = (-deltaMtot)/ ejbmass @@ -331,68 +320,40 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ ! periodic boundary conditions call util_periodic(xpi,ypi,user%gridsize) - - if (.not.bigej) then - indarray(1,i,j) = xpi - indarray(2,i,j) = ypi - end if + + indarray(1,i,j) = xpi + indarray(2,i,j) = ypi lradsq = (crater%xl - xp)**2 + (crater%yl - yp)**2 lrad = sqrt(lradsq) if (lrad < crater%ejrad) cycle - - if (bigej) then - ebh = cumulative_elchange(xpi,ypi) - crater_profile(user, crater, lrad) - else - ebh = cumulative_elchange(i,j) - crater_profile(user, crater, lrad) - end if - - if (user%doregotrack .and. ebh>1.0e-8_DP) then - call regolith_streamtube(user,surf,crater,domain,ejb,ejtble,xp,yp,xpi,ypi,lrad,ebh,rm,vsq,volm) - vmelt = vmelt + volm - end if + + + + ebh = cumulative_elchange(i,j) - crater_profile(user, crater, lrad) + + + if (user%doregotrack .and. ebh>1.0e-8_DP) then + call regolith_streamtube(user,surf,crater,domain,ejb,ejtble,xp,yp,xpi,ypi,lrad,ebh,rm,vsq,volm) + vmelt = vmelt + volm + !write(74,*) erad, surf(xpi,ypi)%regolayer%regodata%meltfrac + end if end do end do end if - if (user%doregotrack) then - if (totmelt > vmelt) then - vmeltsheet = totmelt - vmelt - else !give the craters a melt sheet of 1m - vmeltsheet = 1.0_DP * user%pix * user%pix * nmeltsheet - end if + if (totmelt > vmelt) then + vmeltsheet = totmelt - vmelt + else !give the craters a melt sheet of 1m + vmeltsheet = 1.0_DP * user%pix * user%pix * nmeltsheet end if - ! extra soften calculation - if (user%dosoftening) then - cel = 0.0_DP - - if (bigej) then - call util_diffusion_solver(user,surf,user%gridsize + 2,indarray,kdiff,cel,maxhits) - do ypi = 1,user%gridsize - do xpi = 1,user%gridsize - surf(xpi,ypi)%dem = surf(xpi,ypi)%dem + cel(xpi,ypi) - surf(xpi,ypi)%ejcov = max(surf(xpi,ypi)%ejcov + cel(xpi,ypi),0.0_DP) - indarray(1,xpi,ypi) = xpi - indarray(2,xpi,ypi) = ypi - end do - end do - indarray(1:2,0,:) = user%gridsize - indarray(1:2,user%gridsize+1,:) = 1 - indarray(1:2,:,0) = user%gridsize - indarray(1:2,:,user%gridsize+1) = 1 - - call ejecta_soften(user,surf,user%gridsize + 2,indarray,cumulative_elchange) - - ! Add the ejecta back to the DEM - do ypi = 1,user%gridsize - do xpi = 1,user%gridsize - surf(xpi,ypi)%dem = surf(xpi,ypi)%dem + cumulative_elchange(xpi,ypi) - surf(xpi,ypi)%ejcov = max(surf(xpi,ypi)%ejcov + cumulative_elchange(xpi,ypi), 0.0_DP) - end do - end do + ! Create box for soften calculation (will be no bigger than the grid itself) + if (2 * inc + 1 < user%gridsize) then - else + ! extra soften calculation + if (user%dosoftening) then + cel = 0.0_DP call util_diffusion_solver(user,surf,2 * inc + 1,indarray,kdiff,cel,maxhits) do j = -inc,inc do i = -inc,inc @@ -402,22 +363,75 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ surf(xpi,ypi)%ejcov = max(surf(xpi,ypi)%ejcov + cel(i,j),0.0_DP) end do end do + end if - call ejecta_soften(user,surf,2 * inc + 1,indarray,cumulative_elchange) + call ejecta_soften(user,surf,2 * inc + 1,indarray,cumulative_elchange) - ! Add the ejecta back to the DEM - do j = -inc,inc - do i = -inc,inc - xpi = indarray(1,i,j) - ypi = indarray(2,i,j) - surf(xpi,ypi)%dem = surf(xpi,ypi)%dem + cumulative_elchange(i,j) - surf(xpi,ypi)%ejcov = max(surf(xpi,ypi)%ejcov + cumulative_elchange(i,j), 0.0_DP) + ! Add the ejecta back to the DEM + do j = -inc,inc + do i = -inc,inc + xpi = indarray(1,i,j) + ypi = indarray(2,i,j) + surf(xpi,ypi)%dem = surf(xpi,ypi)%dem + cumulative_elchange(i,j) + surf(xpi,ypi)%ejcov = max(surf(xpi,ypi)%ejcov + cumulative_elchange(i,j), 0.0_DP) + end do + end do + + + else ! Ejecta wraps around the grid. + ! We will therefore send in the whole grid with the total ejecta thickness added to each pixel + allocate(big_cumulative_elchange(0:user%gridsize+1,0:user%gridsize+1)) + allocate(big_cel(0:user%gridsize+1,0:user%gridsize+1)) + allocate(big_indarray(2,0:user%gridsize+1,0:user%gridsize+1)) + allocate(big_kdiff(0:user%gridsize+1,0:user%gridsize+1)) + + do bigj = 0,user%gridsize + 1 + do bigi = 0,user%gridsize + 1 + xpi = bigi + ypi = bigj + call util_periodic(xpi,ypi,user%gridsize) + big_indarray(1,bigi,bigj) = xpi + big_indarray(2,bigi,bigj) = ypi + big_cumulative_elchange(bigi,bigj) = 0.0_DP + end do + end do + + big_kdiff = 0.0_DP + + do j = -inc,inc + do i = -inc,inc + xpi = indarray(1,i,j) + ypi = indarray(2,i,j) + big_cumulative_elchange(xpi,ypi) = big_cumulative_elchange(xpi,ypi) + cumulative_elchange(i,j) + big_kdiff(xpi,ypi) = big_kdiff(xpi,ypi) + kdiff(i,j) + end do + end do + + if (user%dosoftening) then + big_cel = 0.0_DP + call util_diffusion_solver(user,surf,user%gridsize + 2,big_indarray,big_kdiff,big_cel,maxhits) + + do j = 1,user%gridsize + do i = 1,user%gridsize + surf(i,j)%dem = surf(i,j)%dem + big_cel(i,j) + surf(i,j)%ejcov = max(surf(i,j)%ejcov + big_cel(i,j),0.0_DP) end do end do end if + + call ejecta_soften(user,surf,user%gridsize + 2,big_indarray,big_cumulative_elchange) + + do i = 1,user%gridsize + do j = 1,user%gridsize + surf(i,j)%dem = surf(i,j)%dem + big_cumulative_elchange(i,j) + surf(i,j)%ejcov = max(surf(i,j)%ejcov + big_cumulative_elchange(i,j),0.0_DP) + end do + end do + + deallocate(big_cumulative_elchange,big_indarray,big_kdiff,big_cel) end if - deallocate(indarray,kdiff,cel) + deallocate(indarray,diffdistribution,ejdistribution,kdiff,cel) return end subroutine ejecta_emplace diff --git a/src/ejecta/ejecta_ray_pattern.f90 b/src/ejecta/ejecta_ray_pattern.f90 index 663a216d..352cea4a 100644 --- a/src/ejecta/ejecta_ray_pattern.f90 +++ b/src/ejecta/ejecta_ray_pattern.f90 @@ -26,11 +26,12 @@ ! * domain -- Simulation domain variable container ! ! Output +! * ejdist -- logical array containing the pixels that contain ejecta ! !*** !********************************************************************************************************************************** -subroutine ejecta_ray_pattern(user,crater,i,j,diffi,eji) +subroutine ejecta_ray_pattern(user,surf,crater,inc,xi,xf,yi,yf,diffdistribution,ejdistribution) use module_globals use module_util use module_io @@ -41,22 +42,24 @@ subroutine ejecta_ray_pattern(user,crater,i,j,diffi,eji) ! Arguments type(usertype),intent(in) :: user + type(surftype),dimension(:,:),intent(in) :: surf type(cratertype),intent(inout) :: crater - integer(I4B),intent(in) :: i,j - real(DP),intent(out) :: diffi - real(DP),intent(out) :: eji + integer(I4B),intent(in) :: inc,xi,xf,yi,yf + real(DP),dimension(xi:xf,yi:yf),intent(out) :: diffdistribution + real(DP),dimension(xi:xf,yi:yf),intent(out) :: ejdistribution ! Internal variables - integer(I4B) :: nrays,k,n,nef,incsq,iradsq,xpi,ypi,ejpxsq + integer(I4B) :: nrays,i,j,k,n,nef,incsq,iradsq,xpi,ypi,ejpxsq real(DP) :: frac,mef,lrad,lradsq,xp,yp,binres,areafrac,xbar,ybar real(DP) :: rn real(DP) :: theta, lradp, maxdistance real(DP), parameter :: n1 = 4.0_DP real(DP) :: n2, mag + real(DP),dimension(xi:xf,yi:yf) :: isray real(DP),dimension(:),allocatable :: numinray,totnum real(DP),dimension(:),allocatable :: mefarray real(DP) :: ans - logical :: bigej + real(DP) :: C1,C2,p ! Fits to fe vs fd equation for the new ray pattern real(DP) :: rmin,rmax,r @@ -71,12 +74,11 @@ subroutine ejecta_ray_pattern(user,crater,i,j,diffi,eji) logical :: ej real(DP),dimension(Nraymax) :: thetari - eji = 0.0_DP - diffi = 0.0_DP + !TEMPORARY if (user%dorays) then - do k = 1,Nraymax - thetari(k) = 2 * pi * k / Nraymax + do i = 1,Nraymax + thetari(i) = 2 * pi * i / Nraymax end do call shuffle(thetari) ! randomize the ray pattern @@ -84,38 +86,65 @@ subroutine ejecta_ray_pattern(user,crater,i,j,diffi,eji) rmax = user%ejecta_truncation rmin = crater%continuous / crater%frad crater%fe = 10.0_DP ! Estimate the equivalent degradation radius - xpi = crater%xlpx + i - ypi = crater%ylpx + j - - ! Find distance from crater center to current pixel center in real space - xp = xpi * user%pix - yp = ypi * user%pix - - xbar = xp - crater%xl - ybar = yp - crater%yl - - areafrac = util_area_intersection(user%ejecta_truncation * crater%frad,xbar,ybar,user%pix) - r = sqrt(xbar**2 + ybar**2) / crater%frad - theta = mod(atan2(ybar,xbar) + pi + rn * 2 * pi,2 * pi) - diffi = areafrac * ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,.false.) - eji = areafrac * ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,.true.) + !ejdistribution = 0.0_DP + !diffdistribution = 0.0_DP + !!$OMP PARALLEL DO DEFAULT(PRIVATE) & + !!$OMP SHARED(user,crater) & + !!$OMP SHARED(xi,xf,yi,yf,rn,diffdistribution,ejdistribution,thetari,rmin) + do j = yi,yf + do i = xi,xf + xpi = crater%xlpx + i + ypi = crater%ylpx + j + + ! Find distance from crater center to current pixel center in real space + xp = xpi * user%pix + yp = ypi * user%pix + + xbar = xp - crater%xl + ybar = yp - crater%yl + + areafrac = util_area_intersection(user%ejecta_truncation * crater%frad,xbar,ybar,user%pix) + r = sqrt(xbar**2 + ybar**2) / crater%frad + theta = mod(atan2(ybar,xbar) + pi + rn * 2 * pi,2 * pi) + diffdistribution(i,j) = areafrac * ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,.false.) + ejdistribution(i,j) = areafrac * ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,.true.) + end do + end do + !!$OMP END PARALLEL DO + else + !Do simple circular region + incsq = inc**2 + ejdistribution = 0.0_DP + diffdistribution = 0.0_DP + !$OMP PARALLEL DO DEFAULT(PRIVATE) & + !$OMP SHARED(user,crater) & + !$OMP SHARED(inc,incsq,xi,xf,yi,yf,diffdistribution,ejdistribution) + do j = yi,yf + do i = xi,xf + iradsq = i*i + j*j + + if (iradsq < incsq) then + + xpi = crater%xlpx + i + ypi = crater%ylpx + j + + ! Find distance from crater center to current pixel center in real space + xp = xpi * user%pix + yp = ypi * user%pix + + xbar = xp - crater%xl + ybar = yp - crater%yl + areafrac = util_area_intersection(user%ejecta_truncation * crater%frad,xbar,ybar,user%pix) ! uniform circular + diffdistribution(i,j) = areafrac + ejdistribution(i,j) = areafrac + end if + end do + end do + !$OMP END PARALLEL DO - xpi = crater%xlpx + i - ypi = crater%ylpx + j - - ! Find distance from crater center to current pixel center in real space - xp = xpi * user%pix - yp = ypi * user%pix - - xbar = xp - crater%xl - ybar = yp - crater%yl - areafrac = util_area_intersection(user%ejecta_truncation * crater%frad,xbar,ybar,user%pix) ! uniform circular - diffi = areafrac - eji = areafrac end if - return contains diff --git a/src/ejecta/module_ejecta.f90 b/src/ejecta/module_ejecta.f90 index 9e75eb4d..06f8d9e9 100644 --- a/src/ejecta/module_ejecta.f90 +++ b/src/ejecta/module_ejecta.f90 @@ -43,14 +43,15 @@ end subroutine ejecta_emplace end interface interface - subroutine ejecta_ray_pattern(user,crater,i,j,diffi,eji) + subroutine ejecta_ray_pattern(user,surf,crater,inc,xi,xf,yi,yf,diffdistribution,ejdistribution) use module_globals implicit none type(usertype),intent(in) :: user + type(surftype),dimension(:,:),intent(in) :: surf type(cratertype),intent(inout) :: crater - integer(I4B),intent(in) :: i,j - real(DP),intent(out) :: diffi - real(DP),intent(out) :: eji + integer(I4B),intent(in) :: inc,xi,xf,yi,yf + real(DP),dimension(xi:xf,yi:yf),intent(out) :: diffdistribution + real(DP),dimension(xi:xf,yi:yf),intent(out) :: ejdistribution end subroutine ejecta_ray_pattern end interface diff --git a/src/regolith/module_regolith.f90 b/src/regolith/module_regolith.f90 index 0c77a42f..2ab24cd9 100644 --- a/src/regolith/module_regolith.f90 +++ b/src/regolith/module_regolith.f90 @@ -102,7 +102,7 @@ subroutine regolith_traverse_streamtube(user,surfi,deltar,ri,rip1,eradi,erado,ne type(surftype),intent(inout) :: surfi real(DP),intent(in) :: deltar,ri,rip1,eradi,erado type(regodatatype),intent(inout) :: newlayer - real(DP),intent(inout) :: meltinejecta,totvol + real(DP),intent(out) :: meltinejecta,totvol real(DP),intent(out) :: vmare,totseb real(SP),dimension(:),intent(inout) :: age_collector real(DP),intent(in) :: xmints diff --git a/src/regolith/regolith_subpixel_streamtube.f90 b/src/regolith/regolith_subpixel_streamtube.f90 index 694b23f5..acf2b08d 100644 --- a/src/regolith/regolith_subpixel_streamtube.f90 +++ b/src/regolith/regolith_subpixel_streamtube.f90 @@ -61,7 +61,7 @@ subroutine regolith_subpixel_streamtube(user,surfi,deltar,ri,rip1,eradi,newlayer type(surftype),intent(inout) :: surfi real(DP),intent(in) :: deltar,ri,rip1,eradi type(regodatatype),intent(inout) :: newlayer - real(DP),intent(inout) :: meltinejecta, totvol + real(DP),intent(out) :: meltinejecta, totvol real(DP),intent(out) :: vmare,totseb real(SP),dimension(:),intent(inout) :: age_collector real(DP),intent(in) :: xmints From c8356c2325578a1de3246a798f80376543c2f485 Mon Sep 17 00:00:00 2001 From: Austin Blevins Date: Fri, 27 Oct 2023 16:06:31 -0400 Subject: [PATCH 11/42] Update ray parameters --- src/globals/module_globals.f90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/globals/module_globals.f90 b/src/globals/module_globals.f90 index 3ce3f5cd..f0014af0 100644 --- a/src/globals/module_globals.f90 +++ b/src/globals/module_globals.f90 @@ -384,8 +384,8 @@ module module_globals real(DP),parameter :: DFAC = 0.556_DP ! impact distance exponent ! Crater ray parameters -real(DP),parameter :: rray = 16_DP -integer(I4B),parameter :: Nraymax = 16 +real(DP),parameter :: rray = 24_DP ! I think this is "L16" in Minton et al. (2019) +integer(I4B),parameter :: Nraymax = 16 ! "Nrays" in Minton et al. (2019) real(DP),parameter :: fpeak = 8000_DP ! narrow ray: rw0 propto 1/4 real(DP),parameter :: rayp = 2.0_DP integer(I4B),parameter :: rayq = 4 From 649fb611b53bbb7bc954d81c2da07c412e49806a Mon Sep 17 00:00:00 2001 From: Austin Blevins Date: Thu, 2 Nov 2023 16:34:17 -0400 Subject: [PATCH 12/42] Re-arranged array allocations in preparation for a more realistic ejecta ray calculation --- src/ejecta/ejecta_emplace.f90 | 16 ++++++++++------ src/ejecta/ejecta_ray_pattern_func.f90 | 11 +++++++++-- src/globals/module_globals.f90 | 6 +++--- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/ejecta/ejecta_emplace.f90 b/src/ejecta/ejecta_emplace.f90 index 20706f1c..44372d60 100644 --- a/src/ejecta/ejecta_emplace.f90 +++ b/src/ejecta/ejecta_emplace.f90 @@ -168,21 +168,25 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ end if endif + + allocate(ejdistribution(-inc:inc,-inc:inc)) + allocate(diffdistribution(-inc:inc,-inc:inc)) + !the other two temporary arrays get allocated here + + + ! *************************** Continuous Ejecta Formula *****************************! + call ejecta_ray_pattern(user,surf,crater,inc,-inc,inc,-inc,inc,diffdistribution,ejdistribution) + + allocate(cumulative_elchange(-inc:inc,-inc:inc)) allocate(cel(-inc:inc,-inc:inc)) allocate(kdiff(-inc:inc,-inc:inc)) allocate(indarray(2,-inc:inc,-inc:inc)) - allocate(ejdistribution(-inc:inc,-inc:inc)) - allocate(diffdistribution(-inc:inc,-inc:inc)) - cumulative_elchange = 0.0_DP kdiff = 0.0_DP indarray = inc - 1 ! initialize this array to point to a corner (this should have 0 elevation change since we're only doing work ! within a circle of radius irad - ! *************************** Continuous Ejecta Formula *****************************! - call ejecta_ray_pattern(user,surf,crater,inc,-inc,inc,-inc,inc,diffdistribution,ejdistribution) - ejbmass = 0.0_DP nin = 0 nnot = 0 diff --git a/src/ejecta/ejecta_ray_pattern_func.f90 b/src/ejecta/ejecta_ray_pattern_func.f90 index 8f83a704..fa4b712f 100644 --- a/src/ejecta/ejecta_ray_pattern_func.f90 +++ b/src/ejecta/ejecta_ray_pattern_func.f90 @@ -39,9 +39,11 @@ function ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,ej) result(ans) real(DP) :: thetar,rw,rw0,rw1 real(DP) :: f,rtrans,length,rpeak,minray,FF integer(I4B) :: n,i + real(DP) :: tmp - minray = rmin * 3 + minray = rmin * 3 !"L1" in Minton et al. (2019) + !minray = 11.0_DP if (r > rmax) then ans = 0._DP @@ -55,7 +57,12 @@ function ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,ej) result(ans) rw0 = rmin * pi / Nraymax / 2 rw1 = 2 * pi / Nraymax rw = rw0 * (1._DP - (1.0_DP - rw1 / rw0) * exp(1._DP - (r / rmin)**2)) ! equation 40 Minton et al. 2019 - n = max(min(floor((Nraymax**rayp - (Nraymax**rayp - 1) * log(r/minray) / log(rray/minray))**(1._DP/rayp)),Nraymax),1) ! Exponential decay of ray number with distance + tmp = (Nraymax**rayp - (Nraymax**rayp - 1) * log(r/minray) / log(rray/minray)) + if (tmp < 0.0_DP) then + n = Nraymax ! "Nrays" in Minton et al. (2019) + else + n = max(min(floor((Nraymax**rayp - (Nraymax**rayp - 1) * log(r/minray) / log(rray/minray))**(1._DP/rayp)),Nraymax),1) ! Exponential decay of ray number with distance + end if ans = 0._DP rtrans = r - 1.0_DP c = rw / r diff --git a/src/globals/module_globals.f90 b/src/globals/module_globals.f90 index f0014af0..3a325840 100644 --- a/src/globals/module_globals.f90 +++ b/src/globals/module_globals.f90 @@ -221,7 +221,7 @@ module module_globals ! Ejecta softening variables logical :: dosoftening ! Set T to use the extra crater softening model - real(DP) :: ejecta_truncation ! Set the number of crater diameters to truncate the ejecta + real(DP) :: ejecta_truncation ! Set the number of crater radii to truncate the ejecta logical :: dorays ! Set T to use ray model logical :: superdomain ! Set T to include the superdomain @@ -384,8 +384,8 @@ module module_globals real(DP),parameter :: DFAC = 0.556_DP ! impact distance exponent ! Crater ray parameters -real(DP),parameter :: rray = 24_DP ! I think this is "L16" in Minton et al. (2019) -integer(I4B),parameter :: Nraymax = 16 ! "Nrays" in Minton et al. (2019) +real(DP),parameter :: rray = 48_DP ! "L16" in Minton et al. (2019) +integer(I4B),parameter :: Nraymax = 14 ! "Nrays" in Minton et al. (2019) real(DP),parameter :: fpeak = 8000_DP ! narrow ray: rw0 propto 1/4 real(DP),parameter :: rayp = 2.0_DP integer(I4B),parameter :: rayq = 4 From 631e291fc9ec9abcd3844a8acbbeca8a41c1234d Mon Sep 17 00:00:00 2001 From: Austin Blevins Date: Fri, 3 Nov 2023 14:44:43 -0400 Subject: [PATCH 13/42] first pass at a more realistic ejecta ray model --- src/ejecta/ejecta_emplace.f90 | 38 ++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/src/ejecta/ejecta_emplace.f90 b/src/ejecta/ejecta_emplace.f90 index 44372d60..a7a92e98 100644 --- a/src/ejecta/ejecta_emplace.f90 +++ b/src/ejecta/ejecta_emplace.f90 @@ -104,10 +104,13 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ real(DP) :: xp,yp,fradsq,fradpxsq,radsq,ebh,ejdissq,ejbmass,fmasscons,areafrac,xbar,ybar,krad,kdiffmax real(DP),dimension(:,:),allocatable :: big_cumulative_elchange,kdiff,big_kdiff,cel,big_cel integer(I4B),dimension(:,:,:),allocatable :: indarray,big_indarray - real(DP),dimension(:,:),allocatable :: ejdistribution,diffdistribution + real(DP),dimension(:,:),allocatable :: ejdistribution,diffdistribution,maxdiff, maxej + real(DP),dimension(:,:,:),allocatable :: tempdiff,tempej integer(I4B) :: bigi,bigj,maxhits,nin,nnot,dradsq character(len=MESSAGESIZE) :: message ! message for the progress bar real(DP) :: vmelt, totmelt, volm + real(DP), dimension(:), allocatable :: freduction + integer(I4B) :: Npatt = 6 !Number of times to call ray pattern ! Ray mixing model variables @@ -171,12 +174,41 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ allocate(ejdistribution(-inc:inc,-inc:inc)) allocate(diffdistribution(-inc:inc,-inc:inc)) - !the other two temporary arrays get allocated here + allocate(tempdiff(1:Npatt,-inc:inc,-inc:inc)) + allocate(tempej(1:Npatt,-inc:inc,-inc:inc)) + allocate(freduction(Npatt)) + allocate(maxej(-inc:inc,-inc:inc)) + allocate(maxdiff(-inc:inc,-inc:inc)) + ! Set freduction parameters (Manually) <--for now this assumes Npatt=6 + freduction(1) = 0.8_DP + freduction(2) = 0.1_DP + freduction(3) = 0.04_DP + freduction(4) = 0.03_DP + freduction(5) = 0.02_DP + freduction(6) = 0.01_DP ! *************************** Continuous Ejecta Formula *****************************! - call ejecta_ray_pattern(user,surf,crater,inc,-inc,inc,-inc,inc,diffdistribution,ejdistribution) + do i=1,Npatt + call ejecta_ray_pattern(user,surf,crater,inc,-inc,inc,-inc,inc,diffdistribution,ejdistribution) + tempej(i,:,:) = ejdistribution(:,:) + tempdiff(i,:,:) = ejdistribution(:,:) + end do + + maxdiff(:,:) = maxval(tempdiff(:,:,:)) + maxej(:,:) = maxval(tempej(:,:,:)) + + ejdistribution(:,:) = 0.0_DP + diffdistribution(:,:) = 0.0_DP + do i=1,Npatt + ejdistribution(:,:) = ejdistribution(:,:) + (freduction(i) * tempej(i,:,:)) + diffdistribution(:,:) = diffdistribution(:,:) + (freduction(i) * tempdiff(i,:,:)) + end do + + ejdistribution(:,:) = ejdistribution(:,:) / maxej(:,:) + diffdistribution(:,:) = diffdistribution(:,:) / maxdiff(:,:) + deallocate(maxdiff,maxej,tempdiff,tempej,freduction) allocate(cumulative_elchange(-inc:inc,-inc:inc)) allocate(cel(-inc:inc,-inc:inc)) From b63de283892bba16ca3c8446eed76a9f2b3070da Mon Sep 17 00:00:00 2001 From: David Minton Date: Fri, 3 Nov 2023 14:53:37 -0400 Subject: [PATCH 14/42] Simplified ejecta ray layering model --- src/ejecta/ejecta_emplace.f90 | 47 +++++++++++------------------------ 1 file changed, 15 insertions(+), 32 deletions(-) diff --git a/src/ejecta/ejecta_emplace.f90 b/src/ejecta/ejecta_emplace.f90 index a7a92e98..6e380b90 100644 --- a/src/ejecta/ejecta_emplace.f90 +++ b/src/ejecta/ejecta_emplace.f90 @@ -105,12 +105,12 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ real(DP),dimension(:,:),allocatable :: big_cumulative_elchange,kdiff,big_kdiff,cel,big_cel integer(I4B),dimension(:,:,:),allocatable :: indarray,big_indarray real(DP),dimension(:,:),allocatable :: ejdistribution,diffdistribution,maxdiff, maxej - real(DP),dimension(:,:,:),allocatable :: tempdiff,tempej + real(DP),dimension(:,:),allocatable :: tempdiff,tempej integer(I4B) :: bigi,bigj,maxhits,nin,nnot,dradsq character(len=MESSAGESIZE) :: message ! message for the progress bar real(DP) :: vmelt, totmelt, volm - real(DP), dimension(:), allocatable :: freduction - integer(I4B) :: Npatt = 6 !Number of times to call ray pattern + real(DP) :: frayreduction = 0.5_DP ! Factor to apply to reduce the relative thickness of the ray for each subsequent pattern + integer(I4B), parameter :: Npatt = 10 ! Number of times to call ray pattern ! Ray mixing model variables @@ -174,41 +174,24 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ allocate(ejdistribution(-inc:inc,-inc:inc)) allocate(diffdistribution(-inc:inc,-inc:inc)) - allocate(tempdiff(1:Npatt,-inc:inc,-inc:inc)) - allocate(tempej(1:Npatt,-inc:inc,-inc:inc)) - allocate(freduction(Npatt)) - allocate(maxej(-inc:inc,-inc:inc)) - allocate(maxdiff(-inc:inc,-inc:inc)) - ! Set freduction parameters (Manually) <--for now this assumes Npatt=6 - freduction(1) = 0.8_DP - freduction(2) = 0.1_DP - freduction(3) = 0.04_DP - freduction(4) = 0.03_DP - freduction(5) = 0.02_DP - freduction(6) = 0.01_DP - - - ! *************************** Continuous Ejecta Formula *****************************! - do i=1,Npatt - call ejecta_ray_pattern(user,surf,crater,inc,-inc,inc,-inc,inc,diffdistribution,ejdistribution) - tempej(i,:,:) = ejdistribution(:,:) - tempdiff(i,:,:) = ejdistribution(:,:) - end do - - maxdiff(:,:) = maxval(tempdiff(:,:,:)) - maxej(:,:) = maxval(tempej(:,:,:)) + allocate(tempdiff(-inc:inc,-inc:inc)) + allocate(tempej(-inc:inc,-inc:inc)) ejdistribution(:,:) = 0.0_DP diffdistribution(:,:) = 0.0_DP + + ! *************************** Layered Ejecta Rays *****************************! do i=1,Npatt - ejdistribution(:,:) = ejdistribution(:,:) + (freduction(i) * tempej(i,:,:)) - diffdistribution(:,:) = diffdistribution(:,:) + (freduction(i) * tempdiff(i,:,:)) + call ejecta_ray_pattern(user,surf,crater,inc,-inc,inc,-inc,inc,tempdiff,tempej) + diffdistribution(:,:) = diffdistribution(:,:) + frayreduction**(i-1) * tempdiff(:,:) + ejdistribution(:,:) = ejdistribution(:,:) + frayreduction**(i-1) * tempej(:,:) end do + + diffdistribution(:,:) = diffdistribution(:,:) / maxval(ejdistribution) + ejdistribution(:,:) = ejdistribution(:,:) / maxval(diffdistribution) - ejdistribution(:,:) = ejdistribution(:,:) / maxej(:,:) - diffdistribution(:,:) = diffdistribution(:,:) / maxdiff(:,:) - - deallocate(maxdiff,maxej,tempdiff,tempej,freduction) + deallocate(tempdiff,tempej) + ! *****************************************************************************! allocate(cumulative_elchange(-inc:inc,-inc:inc)) allocate(cel(-inc:inc,-inc:inc)) From 0d45f8cdfedc77d2a4ea7e700757ab2a1ddd22c7 Mon Sep 17 00:00:00 2001 From: Austin Blevins Date: Mon, 6 Nov 2023 16:56:57 -0500 Subject: [PATCH 15/42] Tweaked layering parameters; still unrealistic, but better than before --- src/crater/crater_subpixel_diffusion.f90 | 10 +++++++++- src/crater/crater_superdomain.f90 | 10 +++++++++- src/ejecta/ejecta_emplace.f90 | 10 +++++++++- src/ejecta/ejecta_ray_pattern.f90 | 8 +++++--- src/ejecta/ejecta_ray_pattern_func.f90 | 8 +++++--- src/ejecta/module_ejecta.f90 | 9 +++++++-- src/globals/module_globals.f90 | 8 -------- 7 files changed, 44 insertions(+), 19 deletions(-) diff --git a/src/crater/crater_subpixel_diffusion.f90 b/src/crater/crater_subpixel_diffusion.f90 index 630d4401..05c9e05f 100644 --- a/src/crater/crater_subpixel_diffusion.f90 +++ b/src/crater/crater_subpixel_diffusion.f90 @@ -49,6 +49,14 @@ subroutine crater_subpixel_diffusion(user,surf,nflux,domain,finterval,kdiffin) integer(I4B),dimension(:,:),allocatable :: ejisray real(DP) :: xbar,ybar,dD,xp,yp,areafrac,krad,supersize,lrad integer(I8B),dimension(user%gridsize,user%gridsize) :: Ngrid + + ! Crater ray parameters + real(DP) :: rray = 48_DP ! "L16" in Minton et al. (2019) + integer(I4B) :: Nraymax = 14 + real(DP) :: fpeak = 8000_DP ! narrow ray: rw0 propto 1/4 + real(DP) :: rayp = 2.0_DP + integer(I4B) :: rayq = 4 + real(DP) :: rayfmult = (5)**(-4.0_DP / (1.2_DP)) ! Create box for soften calculation (will be no bigger than the grid itself) @@ -176,7 +184,7 @@ subroutine crater_subpixel_diffusion(user,surf,nflux,domain,finterval,kdiffin) allocate(diffdistribution(imin:imax,jmin:jmax)) allocate(ejdistribution(imin:imax,jmin:jmax)) - call ejecta_ray_pattern(user,surf,crater,inc,imin,imax,jmin,jmax,diffdistribution,ejdistribution) + call ejecta_ray_pattern(user,surf,crater,inc,xi,xf,yi,yf,rray,Nraymax,fpeak,rayp,rayq,rayfmult,diffdistribution,ejdistribution) ! Loop over affected matrix area !!$OMP PARALLEL DO DEFAULT(SHARED) IF(inc > INCPAR) & !!$OMP FIRSTPRIVATE(jmin,jmax,imin,imax) & diff --git a/src/crater/crater_superdomain.f90 b/src/crater/crater_superdomain.f90 index 1d1f6092..8cc47ff9 100644 --- a/src/crater/crater_superdomain.f90 +++ b/src/crater/crater_superdomain.f90 @@ -51,6 +51,14 @@ subroutine crater_superdomain(user,surf,prod,nflux,domain,finterval) real(DP) :: rm, depthb, maxgcrat, maxgcratkm real(SP) :: gglass, glrad + ! Crater ray parameters + real(DP) :: rray = 48_DP ! "L16" in Minton et al. (2019) + integer(I4B) :: Nraymax = 14 + real(DP) :: fpeak = 8000_DP ! narrow ray: rw0 propto 1/4 + real(DP) :: rayp = 2.0_DP + integer(I4B) :: rayq = 4 + real(DP) :: rayfmult = (5)**(-4.0_DP / (1.2_DP)) + ! Create box for soften calculation (will be no bigger than the grid itself) do j = 0,user%gridsize + 1 do i = 0,user%gridsize + 1 @@ -148,7 +156,7 @@ subroutine crater_superdomain(user,surf,prod,nflux,domain,finterval) allocate(diffdistribution(xi:xf,yi:yf)) allocate(ejisray(xi:xf,yi:yf)) ! Now generate ray pattern - call ejecta_ray_pattern(user,surf,crater,inc,xi,xf,yi,yf,diffdistribution,ejdistribution) + call ejecta_ray_pattern(user,surf,crater,inc,xi,xf,yi,yf,rray,Nraymax,fpeak,rayp,rayq,rayfmult,diffdistribution,ejdistribution) ! Now if doregotrack is on, do melt zone calculation if (user%doregotrack) call regolith_melt_zone_superdomain(user,crater,domain,rm,depthb) diff --git a/src/ejecta/ejecta_emplace.f90 b/src/ejecta/ejecta_emplace.f90 index 6e380b90..cc5f73d0 100644 --- a/src/ejecta/ejecta_emplace.f90 +++ b/src/ejecta/ejecta_emplace.f90 @@ -128,6 +128,14 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ ! Age real(SP) :: age_mean + ! Crater ray parameters + real(DP) :: rray = 48_DP ! "L16" in Minton et al. (2019) + integer(I4B) :: Nraymax = 12 + real(DP) :: fpeak = 8000_DP ! narrow ray: rw0 propto 1/4 + real(DP) :: rayp = 2.0_DP + integer(I4B) :: rayq = 4 + real(DP) :: rayfmult = (5)**(-4.0_DP / (1.2_DP)) + ! Executable code @@ -182,7 +190,7 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ ! *************************** Layered Ejecta Rays *****************************! do i=1,Npatt - call ejecta_ray_pattern(user,surf,crater,inc,-inc,inc,-inc,inc,tempdiff,tempej) + call ejecta_ray_pattern(user,surf,crater,inc,-inc,inc,-inc,inc,rray,Nraymax+i,fpeak,rayp,rayq,rayfmult,tempdiff,tempej) diffdistribution(:,:) = diffdistribution(:,:) + frayreduction**(i-1) * tempdiff(:,:) ejdistribution(:,:) = ejdistribution(:,:) + frayreduction**(i-1) * tempej(:,:) end do diff --git a/src/ejecta/ejecta_ray_pattern.f90 b/src/ejecta/ejecta_ray_pattern.f90 index 352cea4a..f9da323f 100644 --- a/src/ejecta/ejecta_ray_pattern.f90 +++ b/src/ejecta/ejecta_ray_pattern.f90 @@ -31,7 +31,7 @@ !*** !********************************************************************************************************************************** -subroutine ejecta_ray_pattern(user,surf,crater,inc,xi,xf,yi,yf,diffdistribution,ejdistribution) +subroutine ejecta_ray_pattern(user,surf,crater,inc,xi,xf,yi,yf,rray,Nraymax,fpeak,rayp,rayq,rayfmult,diffdistribution,ejdistribution) use module_globals use module_util use module_io @@ -45,6 +45,8 @@ subroutine ejecta_ray_pattern(user,surf,crater,inc,xi,xf,yi,yf,diffdistribution, type(surftype),dimension(:,:),intent(in) :: surf type(cratertype),intent(inout) :: crater integer(I4B),intent(in) :: inc,xi,xf,yi,yf + real(DP),intent(in) :: rray, fpeak, rayp, rayfmult + integer(I4B),intent(in) :: Nraymax, rayq real(DP),dimension(xi:xf,yi:yf),intent(out) :: diffdistribution real(DP),dimension(xi:xf,yi:yf),intent(out) :: ejdistribution @@ -106,8 +108,8 @@ subroutine ejecta_ray_pattern(user,surf,crater,inc,xi,xf,yi,yf,diffdistribution, areafrac = util_area_intersection(user%ejecta_truncation * crater%frad,xbar,ybar,user%pix) r = sqrt(xbar**2 + ybar**2) / crater%frad theta = mod(atan2(ybar,xbar) + pi + rn * 2 * pi,2 * pi) - diffdistribution(i,j) = areafrac * ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,.false.) - ejdistribution(i,j) = areafrac * ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,.true.) + diffdistribution(i,j) = areafrac * ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,rray,Nraymax,fpeak,rayp,rayq,rayfmult,.false.) + ejdistribution(i,j) = areafrac * ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,rray,Nraymax,fpeak,rayp,rayq,rayfmult,.true.) end do end do !!$OMP END PARALLEL DO diff --git a/src/ejecta/ejecta_ray_pattern_func.f90 b/src/ejecta/ejecta_ray_pattern_func.f90 index fa4b712f..61e173fa 100644 --- a/src/ejecta/ejecta_ray_pattern_func.f90 +++ b/src/ejecta/ejecta_ray_pattern_func.f90 @@ -27,13 +27,15 @@ !*** !********************************************************************************************************** -function ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,ej) result(ans) +function ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,rray,Nraymax,fpeak,rayp,rayq,rayfmult,ej) result(ans) use module_globals use module_ejecta, EXCEPT_THIS_ONE => ejecta_ray_pattern_func implicit none real(DP) :: ans real(DP),intent(in) :: r,rmin,rmax,theta real(DP),dimension(:),intent(in) :: thetari + real(DP),intent(in) :: rray, fpeak, rayp, rayfmult + integer(I4B),intent(in) :: Nraymax, rayq logical,intent(in) :: ej real(DP) :: a,c real(DP) :: thetar,rw,rw0,rw1 @@ -42,8 +44,8 @@ function ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,ej) result(ans) real(DP) :: tmp - minray = rmin * 3 !"L1" in Minton et al. (2019) - !minray = 11.0_DP + !minray = rmin * 3 !"L1" in Minton et al. (2019) + minray = rray / 2 if (r > rmax) then ans = 0._DP diff --git a/src/ejecta/module_ejecta.f90 b/src/ejecta/module_ejecta.f90 index 06f8d9e9..2c21a963 100644 --- a/src/ejecta/module_ejecta.f90 +++ b/src/ejecta/module_ejecta.f90 @@ -43,25 +43,30 @@ end subroutine ejecta_emplace end interface interface - subroutine ejecta_ray_pattern(user,surf,crater,inc,xi,xf,yi,yf,diffdistribution,ejdistribution) + subroutine ejecta_ray_pattern(user,surf,crater,inc,xi,xf,yi,yf,rray,Nraymax,fpeak,rayp,rayq,rayfmult,diffdistribution,ejdistribution) use module_globals implicit none type(usertype),intent(in) :: user type(surftype),dimension(:,:),intent(in) :: surf type(cratertype),intent(inout) :: crater integer(I4B),intent(in) :: inc,xi,xf,yi,yf + real(DP),intent(in) :: rray, fpeak, rayp, rayfmult + integer(I4B),intent(in) :: Nraymax, rayq real(DP),dimension(xi:xf,yi:yf),intent(out) :: diffdistribution real(DP),dimension(xi:xf,yi:yf),intent(out) :: ejdistribution + end subroutine ejecta_ray_pattern end interface interface - function ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,ej) result(ans) + function ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,rray,Nraymax,fpeak,rayp,rayq,rayfmult,ej) result(ans) use module_globals implicit none real(DP) :: ans real(DP),intent(in) :: r,rmin,rmax,theta real(DP),dimension(:),intent(in) :: thetari + real(DP),intent(in) :: rray, fpeak, rayp, rayfmult + integer(I4B),intent(in) :: Nraymax, rayq logical,intent(in) :: ej end function ejecta_ray_pattern_func end interface diff --git a/src/globals/module_globals.f90 b/src/globals/module_globals.f90 index 3a325840..157e1609 100644 --- a/src/globals/module_globals.f90 +++ b/src/globals/module_globals.f90 @@ -383,12 +383,4 @@ module module_globals real(DP),parameter :: GFAC = 0.487_DP ! gravitational acceleration exponent real(DP),parameter :: DFAC = 0.556_DP ! impact distance exponent -! Crater ray parameters -real(DP),parameter :: rray = 48_DP ! "L16" in Minton et al. (2019) -integer(I4B),parameter :: Nraymax = 14 ! "Nrays" in Minton et al. (2019) -real(DP),parameter :: fpeak = 8000_DP ! narrow ray: rw0 propto 1/4 -real(DP),parameter :: rayp = 2.0_DP -integer(I4B),parameter :: rayq = 4 -real(DP),parameter :: rayfmult = (5)**(-4.0_DP / (1.2_DP)) - end module module_globals From 145881aeaa0d8c2a441f01c3279dac0ef4cf6107 Mon Sep 17 00:00:00 2001 From: Austin Blevins Date: Fri, 10 Nov 2023 16:33:41 -0500 Subject: [PATCH 16/42] Attempt to add length relations based on fits to Jake's data; currently bugged --- src/crater/crater_subpixel_diffusion.f90 | 9 ++++++--- src/crater/crater_superdomain.f90 | 8 ++++++-- src/ejecta/ejecta_emplace.f90 | 10 ++++++++-- src/ejecta/ejecta_ray_pattern.f90 | 9 ++++++--- src/ejecta/ejecta_ray_pattern_func.f90 | 6 ++++-- src/ejecta/module_ejecta.f90 | 6 ++++-- 6 files changed, 34 insertions(+), 14 deletions(-) diff --git a/src/crater/crater_subpixel_diffusion.f90 b/src/crater/crater_subpixel_diffusion.f90 index 05c9e05f..cdba3408 100644 --- a/src/crater/crater_subpixel_diffusion.f90 +++ b/src/crater/crater_subpixel_diffusion.f90 @@ -51,13 +51,16 @@ subroutine crater_subpixel_diffusion(user,surf,nflux,domain,finterval,kdiffin) integer(I8B),dimension(user%gridsize,user%gridsize) :: Ngrid ! Crater ray parameters - real(DP) :: rray = 48_DP ! "L16" in Minton et al. (2019) - integer(I4B) :: Nraymax = 14 + real(DP) :: rray != 48_DP ! "L16" in Minton et al. (2019) + integer(I4B) :: Nraymax = 12 real(DP) :: fpeak = 8000_DP ! narrow ray: rw0 propto 1/4 real(DP) :: rayp = 2.0_DP integer(I4B) :: rayq = 4 real(DP) :: rayfmult = (5)**(-4.0_DP / (1.2_DP)) + real(DP) :: l1 + rray = 11.95*crater%frad**1.32 + l1 = 5.32*crater%frad**1.27 ! Create box for soften calculation (will be no bigger than the grid itself) do j = 0,user%gridsize + 1 @@ -184,7 +187,7 @@ subroutine crater_subpixel_diffusion(user,surf,nflux,domain,finterval,kdiffin) allocate(diffdistribution(imin:imax,jmin:jmax)) allocate(ejdistribution(imin:imax,jmin:jmax)) - call ejecta_ray_pattern(user,surf,crater,inc,xi,xf,yi,yf,rray,Nraymax,fpeak,rayp,rayq,rayfmult,diffdistribution,ejdistribution) + call ejecta_ray_pattern(user,surf,crater,inc,xi,xf,yi,yf,rray,Nraymax,fpeak,rayp,rayq,rayfmult,diffdistribution,ejdistribution,l1) ! Loop over affected matrix area !!$OMP PARALLEL DO DEFAULT(SHARED) IF(inc > INCPAR) & !!$OMP FIRSTPRIVATE(jmin,jmax,imin,imax) & diff --git a/src/crater/crater_superdomain.f90 b/src/crater/crater_superdomain.f90 index 8cc47ff9..65c94e09 100644 --- a/src/crater/crater_superdomain.f90 +++ b/src/crater/crater_superdomain.f90 @@ -52,12 +52,16 @@ subroutine crater_superdomain(user,surf,prod,nflux,domain,finterval) real(SP) :: gglass, glrad ! Crater ray parameters - real(DP) :: rray = 48_DP ! "L16" in Minton et al. (2019) + real(DP) :: rray != 48_DP ! "L16" in Minton et al. (2019) integer(I4B) :: Nraymax = 14 real(DP) :: fpeak = 8000_DP ! narrow ray: rw0 propto 1/4 real(DP) :: rayp = 2.0_DP integer(I4B) :: rayq = 4 real(DP) :: rayfmult = (5)**(-4.0_DP / (1.2_DP)) + real(DP) :: l1 + + rray = 11.95*crater%frad**1.32 + l1 = 5.32*crater%frad**1.27 ! Create box for soften calculation (will be no bigger than the grid itself) do j = 0,user%gridsize + 1 @@ -156,7 +160,7 @@ subroutine crater_superdomain(user,surf,prod,nflux,domain,finterval) allocate(diffdistribution(xi:xf,yi:yf)) allocate(ejisray(xi:xf,yi:yf)) ! Now generate ray pattern - call ejecta_ray_pattern(user,surf,crater,inc,xi,xf,yi,yf,rray,Nraymax,fpeak,rayp,rayq,rayfmult,diffdistribution,ejdistribution) + call ejecta_ray_pattern(user,surf,crater,inc,xi,xf,yi,yf,rray,Nraymax,fpeak,rayp,rayq,rayfmult,diffdistribution,ejdistribution,l1) ! Now if doregotrack is on, do melt zone calculation if (user%doregotrack) call regolith_melt_zone_superdomain(user,crater,domain,rm,depthb) diff --git a/src/ejecta/ejecta_emplace.f90 b/src/ejecta/ejecta_emplace.f90 index cc5f73d0..bbbea701 100644 --- a/src/ejecta/ejecta_emplace.f90 +++ b/src/ejecta/ejecta_emplace.f90 @@ -129,12 +129,18 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ real(SP) :: age_mean ! Crater ray parameters - real(DP) :: rray = 48_DP ! "L16" in Minton et al. (2019) + real(DP) :: rray != 48_DP ! "L16" in Minton et al. (2019) integer(I4B) :: Nraymax = 12 real(DP) :: fpeak = 8000_DP ! narrow ray: rw0 propto 1/4 real(DP) :: rayp = 2.0_DP integer(I4B) :: rayq = 4 real(DP) :: rayfmult = (5)**(-4.0_DP / (1.2_DP)) + real(DP) :: l1 + + + rray = 11.95*crater%frad**1.32 + l1 = 5.32*crater%frad**1.27 + write(*,*) "L16 = ", rray, "; L1 = ", l1 ! Executable code @@ -190,7 +196,7 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ ! *************************** Layered Ejecta Rays *****************************! do i=1,Npatt - call ejecta_ray_pattern(user,surf,crater,inc,-inc,inc,-inc,inc,rray,Nraymax+i,fpeak,rayp,rayq,rayfmult,tempdiff,tempej) + call ejecta_ray_pattern(user,surf,crater,inc,-inc,inc,-inc,inc,rray,Nraymax+i,fpeak,rayp,rayq,rayfmult,tempdiff,tempej,l1) diffdistribution(:,:) = diffdistribution(:,:) + frayreduction**(i-1) * tempdiff(:,:) ejdistribution(:,:) = ejdistribution(:,:) + frayreduction**(i-1) * tempej(:,:) end do diff --git a/src/ejecta/ejecta_ray_pattern.f90 b/src/ejecta/ejecta_ray_pattern.f90 index f9da323f..7a25bd50 100644 --- a/src/ejecta/ejecta_ray_pattern.f90 +++ b/src/ejecta/ejecta_ray_pattern.f90 @@ -31,7 +31,7 @@ !*** !********************************************************************************************************************************** -subroutine ejecta_ray_pattern(user,surf,crater,inc,xi,xf,yi,yf,rray,Nraymax,fpeak,rayp,rayq,rayfmult,diffdistribution,ejdistribution) +subroutine ejecta_ray_pattern(user,surf,crater,inc,xi,xf,yi,yf,rray,Nraymax,fpeak,rayp,rayq,rayfmult,diffdistribution,ejdistribution,l1) use module_globals use module_util use module_io @@ -49,6 +49,7 @@ subroutine ejecta_ray_pattern(user,surf,crater,inc,xi,xf,yi,yf,rray,Nraymax,fpea integer(I4B),intent(in) :: Nraymax, rayq real(DP),dimension(xi:xf,yi:yf),intent(out) :: diffdistribution real(DP),dimension(xi:xf,yi:yf),intent(out) :: ejdistribution + real(DP),intent(in) :: l1 ! Internal variables integer(I4B) :: nrays,i,j,k,n,nef,incsq,iradsq,xpi,ypi,ejpxsq @@ -87,6 +88,8 @@ subroutine ejecta_ray_pattern(user,surf,crater,inc,xi,xf,yi,yf,rray,Nraymax,fpea call random_number(rn) ! randomize the ray orientation rmax = user%ejecta_truncation rmin = crater%continuous / crater%frad + !rmax = rray / crater%frad + !rmin = l1 / crater%frad crater%fe = 10.0_DP ! Estimate the equivalent degradation radius !ejdistribution = 0.0_DP !diffdistribution = 0.0_DP @@ -108,8 +111,8 @@ subroutine ejecta_ray_pattern(user,surf,crater,inc,xi,xf,yi,yf,rray,Nraymax,fpea areafrac = util_area_intersection(user%ejecta_truncation * crater%frad,xbar,ybar,user%pix) r = sqrt(xbar**2 + ybar**2) / crater%frad theta = mod(atan2(ybar,xbar) + pi + rn * 2 * pi,2 * pi) - diffdistribution(i,j) = areafrac * ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,rray,Nraymax,fpeak,rayp,rayq,rayfmult,.false.) - ejdistribution(i,j) = areafrac * ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,rray,Nraymax,fpeak,rayp,rayq,rayfmult,.true.) + diffdistribution(i,j) = areafrac * ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,rray,Nraymax,fpeak,rayp,rayq,rayfmult,l1,.false.) + ejdistribution(i,j) = areafrac * ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,rray,Nraymax,fpeak,rayp,rayq,rayfmult,l1,.true.) end do end do !!$OMP END PARALLEL DO diff --git a/src/ejecta/ejecta_ray_pattern_func.f90 b/src/ejecta/ejecta_ray_pattern_func.f90 index 61e173fa..d5d81354 100644 --- a/src/ejecta/ejecta_ray_pattern_func.f90 +++ b/src/ejecta/ejecta_ray_pattern_func.f90 @@ -27,7 +27,7 @@ !*** !********************************************************************************************************** -function ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,rray,Nraymax,fpeak,rayp,rayq,rayfmult,ej) result(ans) +function ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,rray,Nraymax,fpeak,rayp,rayq,rayfmult,l1,ej) result(ans) use module_globals use module_ejecta, EXCEPT_THIS_ONE => ejecta_ray_pattern_func implicit none @@ -36,6 +36,7 @@ function ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,rray,Nraymax,fpeak,ra real(DP),dimension(:),intent(in) :: thetari real(DP),intent(in) :: rray, fpeak, rayp, rayfmult integer(I4B),intent(in) :: Nraymax, rayq + real(DP),intent(in) :: l1 logical,intent(in) :: ej real(DP) :: a,c real(DP) :: thetar,rw,rw0,rw1 @@ -45,7 +46,8 @@ function ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,rray,Nraymax,fpeak,ra !minray = rmin * 3 !"L1" in Minton et al. (2019) - minray = rray / 2 + !minray = rray / 2 + minray = l1 if (r > rmax) then ans = 0._DP diff --git a/src/ejecta/module_ejecta.f90 b/src/ejecta/module_ejecta.f90 index 2c21a963..e2d8747a 100644 --- a/src/ejecta/module_ejecta.f90 +++ b/src/ejecta/module_ejecta.f90 @@ -43,7 +43,7 @@ end subroutine ejecta_emplace end interface interface - subroutine ejecta_ray_pattern(user,surf,crater,inc,xi,xf,yi,yf,rray,Nraymax,fpeak,rayp,rayq,rayfmult,diffdistribution,ejdistribution) + subroutine ejecta_ray_pattern(user,surf,crater,inc,xi,xf,yi,yf,rray,Nraymax,fpeak,rayp,rayq,rayfmult,diffdistribution,ejdistribution,l1) use module_globals implicit none type(usertype),intent(in) :: user @@ -54,12 +54,13 @@ subroutine ejecta_ray_pattern(user,surf,crater,inc,xi,xf,yi,yf,rray,Nraymax,fpea integer(I4B),intent(in) :: Nraymax, rayq real(DP),dimension(xi:xf,yi:yf),intent(out) :: diffdistribution real(DP),dimension(xi:xf,yi:yf),intent(out) :: ejdistribution + real(DP),intent(in) :: l1 end subroutine ejecta_ray_pattern end interface interface - function ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,rray,Nraymax,fpeak,rayp,rayq,rayfmult,ej) result(ans) + function ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,rray,Nraymax,fpeak,rayp,rayq,rayfmult,l1,ej) result(ans) use module_globals implicit none real(DP) :: ans @@ -67,6 +68,7 @@ function ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,rray,Nraymax,fpeak,ra real(DP),dimension(:),intent(in) :: thetari real(DP),intent(in) :: rray, fpeak, rayp, rayfmult integer(I4B),intent(in) :: Nraymax, rayq + real(DP),intent(in) :: l1 logical,intent(in) :: ej end function ejecta_ray_pattern_func end interface From e6ec31eb9c928a7ce09ac6a35f6996cf0eaed533 Mon Sep 17 00:00:00 2001 From: Austin Blevins Date: Mon, 13 Nov 2023 13:13:24 -0500 Subject: [PATCH 17/42] Fixed a bug in the ray L1 and L16 formulas --- src/ejecta/ejecta_emplace.f90 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ejecta/ejecta_emplace.f90 b/src/ejecta/ejecta_emplace.f90 index bbbea701..3ed49557 100644 --- a/src/ejecta/ejecta_emplace.f90 +++ b/src/ejecta/ejecta_emplace.f90 @@ -112,6 +112,7 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ real(DP) :: frayreduction = 0.5_DP ! Factor to apply to reduce the relative thickness of the ray for each subsequent pattern integer(I4B), parameter :: Npatt = 10 ! Number of times to call ray pattern + ! Ray mixing model variables real(DP) :: dsc @@ -138,9 +139,9 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ real(DP) :: l1 - rray = 11.95*crater%frad**1.32 - l1 = 5.32*crater%frad**1.27 - write(*,*) "L16 = ", rray, "; L1 = ", l1 + rray = (11.95*(crater%frad/1000)**1.32)/(crater%frad/1000) + l1 = (5.32*(crater%frad/1000)**1.27)/(crater%frad/1000) + write(*,*) 'L16 = ', rray, 'L1 = ', l1 ! Executable code From b199af274797eb82f6b1d3bfadf129f0528470d5 Mon Sep 17 00:00:00 2001 From: David A Minton Date: Mon, 13 Nov 2023 13:23:53 -0500 Subject: [PATCH 18/42] Check to ensure that the value passed to exp doesn't cause an underflow exception --- src/ejecta/ejecta_ray_func.f90 | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/ejecta/ejecta_ray_func.f90 b/src/ejecta/ejecta_ray_func.f90 index 459fefde..25320bec 100644 --- a/src/ejecta/ejecta_ray_func.f90 +++ b/src/ejecta/ejecta_ray_func.f90 @@ -33,13 +33,18 @@ function ejecta_ray_func(theta,thetar,r,n,w) result(ans) real(DP) :: ans real(DP),intent(in) :: theta,thetar,r,w integer(I4B),intent(in) :: n - real(DP) :: thetap,thetapp,a,b,c,dtheta + real(DP) :: thetap,thetapp,a,b,c,dtheta,logval c = w / r b = thetar dtheta = min(2*pi - abs(theta - b),abs(theta - b)) - a = sqrt(2 * pi) / (n * c * erf(pi / (2 *sqrt(2._DP) * c))) !this is the intensity function - ans = a * exp(-dtheta**2 / (2 * c**2)) + logval = -dtheta**2 / (2 * c**2) + if (logval < LOGVSMALL) then + ans = 0.0_DP + else + a = sqrt(2 * pi) / (n * c * erf(pi / (2 *sqrt(2._DP) * c))) !this is the intensity function + ans = a * exp(logval) + end if -!return + return end function ejecta_ray_func \ No newline at end of file From 631ac45b81f4b27d3e882d067942e1412395b562 Mon Sep 17 00:00:00 2001 From: David A Minton Date: Mon, 13 Nov 2023 13:43:57 -0500 Subject: [PATCH 19/42] Added some floating point math checks to ensure that we don't get underflow errors --- src/ejecta/ejecta_ray_pattern_func.f90 | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/ejecta/ejecta_ray_pattern_func.f90 b/src/ejecta/ejecta_ray_pattern_func.f90 index d5d81354..7843a2e7 100644 --- a/src/ejecta/ejecta_ray_pattern_func.f90 +++ b/src/ejecta/ejecta_ray_pattern_func.f90 @@ -72,12 +72,12 @@ function ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,rray,Nraymax,fpeak,ra c = rw / r a = sqrt(2 * pi) / (n * c * erf(pi / (2 *sqrt(2._DP) * c))) !equation 39 Minton et al., 2019 do i = 1,Nraymax - length = minray * exp(log(rray/minray) * ((Nraymax - i + 1)**rayp - 1_DP) / ((Nraymax**rayp - 1))) - rpeak = (length - 1_DP) * 0.5_DP + length = minray * exp(log(rray/minray) * ((Nraymax - i + 1)**rayp - 1.0_DP) / ((Nraymax**rayp - 1))) + rpeak = (length - 1.0_DP) * 0.5_DP if (ej) then FF = 1.0_DP if (r > length) then - f = 0.0_DP + cycle ! Don't add any material beyond the length of the ray else f = a end if @@ -85,7 +85,8 @@ function ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,rray,Nraymax,fpeak,ra FF = rayfmult * (20 / rmax)**(0.5_DP) * 0.25_DP f = FF * fpeak * (rtrans / rpeak)**rayq * exp(1._DP / rayq * (1.0_DP - (rtrans / rpeak)**rayq)) !equation 42 Minton et al. 2019 end if - ans = ans + ejecta_ray_func(theta,thetari(i),r,n,rw) * f / a + tmp = ejecta_ray_func(theta,thetari(i),r,n,rw) + if (tmp > epsilon(ans) .and. (f/a > epsilon(ans))) ans = ans + tmp * f / a ! Ensure that we don't get an underflow end do end if From 550f34741de3ce54834911454785fbf7f1f4908d Mon Sep 17 00:00:00 2001 From: Austin Blevins Date: Mon, 13 Nov 2023 13:51:55 -0500 Subject: [PATCH 20/42] made write statement only display if testflag=T --- src/ejecta/ejecta_emplace.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ejecta/ejecta_emplace.f90 b/src/ejecta/ejecta_emplace.f90 index 3ed49557..105c3ab4 100644 --- a/src/ejecta/ejecta_emplace.f90 +++ b/src/ejecta/ejecta_emplace.f90 @@ -141,7 +141,6 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ rray = (11.95*(crater%frad/1000)**1.32)/(crater%frad/1000) l1 = (5.32*(crater%frad/1000)**1.27)/(crater%frad/1000) - write(*,*) 'L16 = ', rray, 'L1 = ', l1 ! Executable code @@ -180,6 +179,7 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ if (inc >= user%gridsize / 2) then if (user%testflag) then write(*,*) 'Big ejecta: fcrat =',crater%fcrat, ' Ej/S =',(crater%ejdispx*user%pix)/domain%side, ' Ejrim =', crater%ejrim + write(*,*) 'L16 = ', rray, 'L1 = ', l1 else write(message,'("Ejb: Dc=",ES9.2," Ej/S=",F0.3)') crater%fcrat,(crater%ejdispx*user%pix)/domain%side call io_updatePbar(message) From ada06b7c728f40ead9d62fcecb8f96af57d0763c Mon Sep 17 00:00:00 2001 From: Austin Blevins Date: Mon, 13 Nov 2023 16:49:11 -0500 Subject: [PATCH 21/42] changed the number of rays to better match observations --- src/ejecta/ejecta_emplace.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ejecta/ejecta_emplace.f90 b/src/ejecta/ejecta_emplace.f90 index 105c3ab4..ca748f8c 100644 --- a/src/ejecta/ejecta_emplace.f90 +++ b/src/ejecta/ejecta_emplace.f90 @@ -131,7 +131,7 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ ! Crater ray parameters real(DP) :: rray != 48_DP ! "L16" in Minton et al. (2019) - integer(I4B) :: Nraymax = 12 + integer(I4B) :: Nraymax = 5 real(DP) :: fpeak = 8000_DP ! narrow ray: rw0 propto 1/4 real(DP) :: rayp = 2.0_DP integer(I4B) :: rayq = 4 From e5431c4649489f640e001c475fd91889ee9b6865 Mon Sep 17 00:00:00 2001 From: Austin Blevins Date: Mon, 13 Nov 2023 17:32:27 -0500 Subject: [PATCH 22/42] Removed the dependency of ray length on ejecta_truncation value, but ignored for craters larger than ~Imbrium. (this may cause memory issues, need to test!) --- src/ejecta/ejecta_ray_pattern.f90 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ejecta/ejecta_ray_pattern.f90 b/src/ejecta/ejecta_ray_pattern.f90 index 7a25bd50..11868f6e 100644 --- a/src/ejecta/ejecta_ray_pattern.f90 +++ b/src/ejecta/ejecta_ray_pattern.f90 @@ -79,14 +79,14 @@ subroutine ejecta_ray_pattern(user,surf,crater,inc,xi,xf,yi,yf,rray,Nraymax,fpea !TEMPORARY - if (user%dorays) then + if (user%dorays .and. crater%fcrat<1500000._DP) then do i = 1,Nraymax thetari(i) = 2 * pi * i / Nraymax end do call shuffle(thetari) ! randomize the ray pattern call random_number(rn) ! randomize the ray orientation - rmax = user%ejecta_truncation + rmax = rray rmin = crater%continuous / crater%frad !rmax = rray / crater%frad !rmin = l1 / crater%frad @@ -108,7 +108,8 @@ subroutine ejecta_ray_pattern(user,surf,crater,inc,xi,xf,yi,yf,rray,Nraymax,fpea xbar = xp - crater%xl ybar = yp - crater%yl - areafrac = util_area_intersection(user%ejecta_truncation * crater%frad,xbar,ybar,user%pix) + !areafrac = util_area_intersection(user%ejecta_truncation * crater%frad,xbar,ybar,user%pix) + areafrac = util_area_intersection(rray * crater%frad,xbar,ybar,user%pix) r = sqrt(xbar**2 + ybar**2) / crater%frad theta = mod(atan2(ybar,xbar) + pi + rn * 2 * pi,2 * pi) diffdistribution(i,j) = areafrac * ejecta_ray_pattern_func(theta,r,rmin,rmax,thetari,rray,Nraymax,fpeak,rayp,rayq,rayfmult,l1,.false.) From 3fa34648ec0b0712feb1c090597d8639f9ebf887 Mon Sep 17 00:00:00 2001 From: Austin Blevins Date: Wed, 15 Nov 2023 12:02:36 -0500 Subject: [PATCH 23/42] Update executable directory to look in current directory first, then package directory --- ctem/ctem/driver.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ctem/ctem/driver.py b/ctem/ctem/driver.py index 0249c19d..541eb393 100644 --- a/ctem/ctem/driver.py +++ b/ctem/ctem/driver.py @@ -52,10 +52,10 @@ def __init__(self, param_file="ctem.in", isnew=True): } # Get the location of the CTEM executable - self.ctem_executable = Path(_pyfile).parent.parent.parent / "bin" / "CTEM" + self.ctem_executable = Path(currentdir) / "CTEM" if not self.ctem_executable.exists(): - print(f"CTEM driver not found at {self.ctem_executable}. Trying current directory.") - self.ctem_executable = Path(currentdir) / "CTEM" + print(f"CTEM driver not found at {self.ctem_executable}. Trying package directory..") + self.ctem_executable = Path(_pyfile).parent.parent.parent / "bin" / "CTEM" if not self.ctem_executable.exists(): warnings.warn(f"Cannot find the CTEM driver {str(self.ctem_executable)}", stacklevel=2) self.ctem_executable = None From a33cf1945b261953cd8399b1e695c522a59a9043 Mon Sep 17 00:00:00 2001 From: Austin Blevins Date: Fri, 17 Nov 2023 13:45:36 -0500 Subject: [PATCH 24/42] Changed parameters to be closer to Guo et al. (2018) ray generation --- src/ejecta/ejecta_emplace.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ejecta/ejecta_emplace.f90 b/src/ejecta/ejecta_emplace.f90 index ca748f8c..5e6de56c 100644 --- a/src/ejecta/ejecta_emplace.f90 +++ b/src/ejecta/ejecta_emplace.f90 @@ -110,7 +110,7 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ character(len=MESSAGESIZE) :: message ! message for the progress bar real(DP) :: vmelt, totmelt, volm real(DP) :: frayreduction = 0.5_DP ! Factor to apply to reduce the relative thickness of the ray for each subsequent pattern - integer(I4B), parameter :: Npatt = 10 ! Number of times to call ray pattern + integer(I4B), parameter :: Npatt = 8 ! Number of times to call ray pattern From 2ce51c9b663caeb3392e1911f6facf5fbcf5487c Mon Sep 17 00:00:00 2001 From: Austin Blevins Date: Tue, 28 Nov 2023 14:25:56 -0500 Subject: [PATCH 25/42] Quasi-MC mode is now compatible with statistical mode --- ctem/ctem/driver.py | 5 ++++- src/crater/crater_populate.f90 | 10 +++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/ctem/ctem/driver.py b/ctem/ctem/driver.py index 541eb393..2646d1db 100644 --- a/ctem/ctem/driver.py +++ b/ctem/ctem/driver.py @@ -169,7 +169,10 @@ def __init__(self, param_file="ctem.in", isnew=True): rclist[:,0] = np.exp(interp(np.log(rclist[:,0]))) #Convert age in Ga to "interval time" - rclist[:,5] = (self.user['interval'] * self.user['numintervals']) - craterproduction.Tscale(rclist[:,5], 'NPF_Moon') + if (self.user['runtype'].upper() == 'STATISTICAL'): + rclist[:,5] = (self.user['interval']) - craterproduction.Tscale(rclist[:,5], 'NPF_Moon') + else: + rclist[:,5] = (self.user['interval'] * self.user['numintervals']) - craterproduction.Tscale(rclist[:,5], 'NPF_Moon') rclist = rclist[rclist[:,5].argsort()] #Export to dat file diff --git a/src/crater/crater_populate.f90 b/src/crater/crater_populate.f90 index 1d342bc0..59c6e20e 100644 --- a/src/crater/crater_populate.f90 +++ b/src/crater/crater_populate.f90 @@ -146,7 +146,11 @@ subroutine crater_populate(user,surf,crater,domain,prod,production_list,vdist,nt clock = 0.0_DP finterval = 1.0_DP / real(ntotcrat,kind=DP) if (user%doregotrack) then - maxage = user%interval * user%numintervals + if (user%runtype .eq. 'STATISTICAL') then + maxage = user%interval + else + maxage = user%interval * user%numintervals + end if if (maxage < 0._DP ) then write(*,*) "MAJOR ERROR: Negative age!" stop @@ -183,13 +187,13 @@ subroutine crater_populate(user,surf,crater,domain,prod,production_list,vdist,nt end if if (crater%timestamp < 2330._DP) then if (oldGa > 0._DP) then - if (user%numintervals .eq. 1) then + if ((user%numintervals .eq. 1) .or. (user%runtype .eq. 'STATISTICAL')) then crater%timestampGa = util_t_from_scale(maxage-crater%timestamp,agemin,oldGa) else crater%timestampGa = util_t_from_scale(maxage-crater%timestamp,1e-10_DP,oldGa) end if else - if (user%numintervals .eq. 1) then + if ((user%numintervals .eq. 1) .or. (user%runtype .eq. 'STATISTICAL')) then crater%timestampGa = util_t_from_scale(maxage-crater%timestamp,agemin,maxageGa) else crater%timestampGa = util_t_from_scale(maxage-crater%timestamp,1e-10_DP,maxageGa) From f6582cbacf71e0eef26280e793443c40fac71994 Mon Sep 17 00:00:00 2001 From: David Minton Date: Sat, 10 Feb 2024 18:05:46 -0500 Subject: [PATCH 26/42] Restructured python files and fixed bugs to make the code more compatible with ifx --- ctem/NPF.py | 104 +++++++++ ctem/__init__.py | 1 + ctem/craterproduction.py | 216 +++++++++++++++++++ ctem/driver.py | 383 +++++++++++++++++++++++++++++++++ ctem/util.py | 443 +++++++++++++++++++++++++++++++++++++++ ctem/viewer3d.py | 124 +++++++++++ 6 files changed, 1271 insertions(+) create mode 100644 ctem/NPF.py create mode 100644 ctem/__init__.py create mode 100644 ctem/craterproduction.py create mode 100644 ctem/driver.py create mode 100644 ctem/util.py create mode 100644 ctem/viewer3d.py diff --git a/ctem/NPF.py b/ctem/NPF.py new file mode 100644 index 00000000..cb7ee363 --- /dev/null +++ b/ctem/NPF.py @@ -0,0 +1,104 @@ +import numpy as np +# The Neukum production function +# Ivanov, Neukum, and Hartmann (2001) SSR v. 96 pp. 55-86 +def N1lunar(T): + return 5.44e-14 * (np.exp(6.93*T) - 1) + 8.38e-4 * T + + +def Nlunar(D): + # Lunar crater SFD + aL00 = -3.0876 + aL01 = -3.557528 + aL02 = 0.781027 + aL03 = 1.021521 + aL04 = -0.156012 + aL05 = -0.444058 + aL06 = 0.019977 + aL07 = 0.086850 + aL08 = -0.005874 + aL09 = -0.006809 + aL10 = 8.25e-4 + aL11 = 5.54e-5 + + return np.where((D > 0.01) & (D < 1000.0), + 10**(aL00 + + aL01 * np.log10(D) ** 1 + + aL02 * np.log10(D) ** 2 + + aL03 * np.log10(D) ** 3 + + aL04 * np.log10(D) ** 4 + + aL05 * np.log10(D) ** 5 + + aL06 * np.log10(D) ** 6 + + aL07 * np.log10(D) ** 7 + + aL08 * np.log10(D) ** 8 + + aL09 * np.log10(D) ** 9 + + aL10 * np.log10(D) ** 10 + + aL11 * np.log10(D) ** 11),float('nan')) + +def Rproj(D): + #Projectile SFD + aP00 = 0.0 + aP01 = -1.375458 + aP02 = 1.272521e-1 + aP03 = -1.282166 + aP04 = -3.074558e-1 + aP05 = 4.149280e-1 + aP06 = 1.910668e-1 + aP07 = -4.260980e-2 + aP08 = -3.976305e-2 + aP09 = -3.180179e-3 + aP10 = 2.799369e-3 + aP11 = 6.892223e-4 + aP12 = 2.614385e-6 + aP13 = -1.416178e-5 + aP14 = -1.191124e-6 + + return np.where((D > 1e-4) & (D < 300), + 10**(aP00 + + aP01 * np.log10(D)**1 + + aP02 * np.log10(D)**2 + + aP03 * np.log10(D)**3 + + aP04 * np.log10(D)**4 + + aP05 * np.log10(D)**5 + + aP06 * np.log10(D)**6 + + aP07 * np.log10(D)**7 + + aP08 * np.log10(D)**8 + + aP09 * np.log10(D)**9 + + aP10 * np.log10(D)**10 + + aP11 * np.log10(D)**11 + + aP12 * np.log10(D)**12 + + aP13 * np.log10(D)**13 + + aP14 * np.log10(D)**14),float('nan')) + +def N1mars(T): + # Mars crater SFD + # Ivanov (2001) SSR v. 96 pp. 87-104 + return 2.68e-14 * (np.exp(6.93 * T) - 1) + 4.13e-4 * T + +def Nmars(D): + aM00 = -3.384 + aM01 = -3.197 + aM02 = 1.257 + aM03 = 0.7915 + aM04 = -0.4861 + aM05 = -0.3630 + aM06 = 0.1016 + aM07 = 6.756e-2 + aM08 = -1.181e-2 + aM09 = -4.753e-3 + aM10 = 6.233e-4 + aM11 = 5.805e-5 + + return np.where((D > 0.01) & (D < 1000.), + 10**(aM00 + + aM01 * np.log10(D)**1 + + aM02 * np.log10(D)**2 + + aM03 * np.log10(D)**3 + + aM04 * np.log10(D)**4 + + aM05 * np.log10(D)**5 + + aM06 * np.log10(D)**6 + + aM07 * np.log10(D)**7 + + aM08 * np.log10(D)**8 + + aM09 * np.log10(D)**9 + + aM10 * np.log10(D)**10 + + aM11 * np.log10(D)**11), + np.full_like(D, np.nan)) diff --git a/ctem/__init__.py b/ctem/__init__.py new file mode 100644 index 00000000..2e8ce2a0 --- /dev/null +++ b/ctem/__init__.py @@ -0,0 +1 @@ +from ctem.driver import * \ No newline at end of file diff --git a/ctem/craterproduction.py b/ctem/craterproduction.py new file mode 100644 index 00000000..4d81b687 --- /dev/null +++ b/ctem/craterproduction.py @@ -0,0 +1,216 @@ +import numpy as np +from scipy import optimize + +# The Neukum production function for the Moon and Mars +#Lunar PF from: Ivanov, Neukum, and Hartmann (2001) SSR v. 96 pp. 55-86 +#Mars PF from: Ivanov (2001) SSR v. 96 pp. 87-104 +sfd_coef = { + "NPF_Moon" : [-3.0876,-3.557528,+0.781027,+1.021521,-0.156012,-0.444058,+0.019977,+0.086850,-0.005874,-0.006809,+8.25e-4, +5.54e-5], + "NPF_Mars" : [-3.384, -3.197, +1.257, +0.7915, -0.4861, -0.3630, +0.1016, +6.756e-2,-1.181e-2,-4.753e-3,+6.233e-4,+5.805e-5] + } +sfd_range = { + "NPF_Moon" : [0.01,1000], + "NPF_Mars" : [0.015,362] +} +#Exponential time constant (Ga) +tau = 6.93 +Nexp = 5.44e-14 + +time_coef = { + "NPF_Moon" : Nexp, + "NPF_Mars" : Nexp * 10**(sfd_coef.get("NPF_Mars")[0]) / 10**(sfd_coef.get("NPF_Moon")[0]) +} + +def N1(T, pfmodel): + """ + Return the N(1) value as a function of time for a particular production function model + + Parameters + ---------- + T : numpy array + Time in units of Ga + pfmodel : string + The production function model to use + Currently options are 'NPF_Moon' or 'NPF_Mars' + + Returns + ------- + N1 : numpy array + The number of craters per square kilometer greater than 1 km in diameter + """ + T_valid_range = np.where((T <= 4.5) & (T >= 0.0), T, np.nan) + return time_coef.get(pfmodel) * (np.exp(tau * T_valid_range) - 1.0) + 10 ** (sfd_coef.get(pfmodel)[0]) * T_valid_range + +def CSFD(Dkm,planet): + """ + Return the cumulative size-frequency distribution for a particular production function model + + Parameters + ---------- + Dkm : numpy array + Diameters in units of km + pfmodel : string + The production function model to use + Currently options are 'NPF_Moon' or 'NPF_Mars' + + Returns + ------- + CSFD : numpy array + The number of craters per square kilometer greater than Dkm in diameter at T=1 Ga + """ + logCSFD = sum(co * np.log10(Dkm) ** i for i, co in enumerate(sfd_coef.get(planet))) + return 10**(logCSFD) + +def DSFD(Dkm,planet): + """ + Return the differential size-frequency distribution for a particular production function model + + Parameters + ---------- + Dkm : numpy array + Diameters in units of km + pfmodel : string + The production function model to use + Currently options are 'NPF_Moon' or 'NPF_Mars' + + Returns + ------- + DSFD : numpy array + The differential number of craters (dN/dD) per square kilometer greater than Dkm in diameter at T = 1 Ga + """ + dcoef = sfd_coef.get(planet)[1:] + logDSFD = sum(co * np.log10(Dkm) ** i for i, co in enumerate(dcoef)) + return 10**(logDSFD) * CSFD(Dkm,planet) / Dkm + +def Tscale(T,planet): + """ + Return the number density of craters at time T relative to time T = 1 Ga + + Parameters + ---------- + T : numpy array + Time in units of Ga + pfmodel : string + The production function model to use + Currently options are 'NPF_Moon' or 'NPF_Mars' + + Returns + ------- + Tscale : numpy array + N1(T) / CSFD(Dkm = 1.0) + """ + return N1(T,planet) / CSFD(1.0,planet) + +def pf_csfd(T,Dkm,planet): + """ + Return the cumulative size-frequency distribution for a particular production function model as a function of Time + + Parameters + ---------- + T : numpy array + Time in units of Ga + Dkm : numpy array + Diameters in units of km + pfmodel : string + The production function model to use + Currently options are 'NPF_Moon' or 'NPF_Mars' + + Returns + ------- + pf_csfd : numpy array + The cumulative number of craters per square kilometer greater than Dkm in diameter at time T T + """ + D_valid_range = np.where((Dkm >= sfd_range.get(planet)[0]) & (Dkm <= sfd_range.get(planet)[1]),Dkm,np.nan) + return CSFD(D_valid_range,planet) * Tscale(T,planet) + +def pf_dsfd(T,Dkm,planet): + """ + Return the differential size-frequency distribution for a particular production function model as a function of Time + + Parameters + ---------- + T : numpy array + Time in units of Ga + Dkm : numpy array + Diameters in units of km + pfmodel : string + The production function model to use + Currently options are 'NPF_Moon' or 'NPF_Mars' + + Returns + ------- + pf_dsfd : numpy array + The cumulative number of craters per square kilometer greater than Dkm in diameter at time T T + """ + D_valid_range = np.where((Dkm >= sfd_range.get(planet)[0]) & (Dkm <= sfd_range.get(planet)[1]), Dkm, np.nan) + return DSFD(D_valid_range, planet) * Tscale(T, planet) + +def T_from_scale(TS,planet): + """ + Return the time in Ga for the given number density of craters relative to that at 1 Ga. + This is the inverse of Tscale + + Parameters + ---------- + TS : numpy array + number density of craters relative to that at 1 Ga + pfmodel : string + The production function model to use + Currently options are 'NPF_Moon' or 'NPF_Mars' + + Returns + ------- + T_from_scale : numpy array + The time in Ga + """ + def func(S): + return Tscale(S,planet) - TS + return optimize.fsolve(func, np.full_like(TS,4.4),xtol=1e-10) + + +if __name__ == "__main__": + import matplotlib.pyplot as plt + import matplotlib.ticker as ticker + print("Tests go here") + print(f"T = 1 Ga, N(1) = {pf_csfd(1.0,1.00,'NPF_Moon')}") + print(f"T = 4.2 Ga, N(1) = {pf_csfd(4.2,1.00,'NPF_Moon')}") + print("Tscale test: Should return all 1s") + Ttest = np.logspace(-4,np.log10(4.4),num=100) + Tres = T_from_scale(Tscale(Ttest,'NPF_Mars'),'NPF_Mars') + print(Ttest / Tres) + #for i,t in enumerate(Ttest): + # print(t,Tscale(t,'Moon'),Tres[i]) + + CSFDfig = plt.figure(1, figsize=(8, 7)) + ax = {'NPF_Moon': CSFDfig.add_subplot(121), + 'NPF_Mars': CSFDfig.add_subplot(122)} + + tvals = [0.01,1.0,4.0] + x_min = 1e-3 + x_max = 1e3 + y_min = 1e-9 + y_max = 1e3 + Dvals = np.logspace(np.log10(x_min), np.log10(x_max)) + for key in ax: + ax[key].title.set_text(key) + ax[key].set_xscale('log') + ax[key].set_yscale('log') + ax[key].set_ylabel('$\mathregular{N_{>D} (km^{-2})}$') + ax[key].set_xlabel('Diameter (km)') + ax[key].set_xlim(x_min, x_max) + ax[key].set_ylim(y_min, y_max) + ax[key].yaxis.set_major_locator(ticker.LogLocator(base=10.0, numticks=20)) + ax[key].yaxis.set_minor_locator(ticker.LogLocator(base=10.0, subs=np.arange(2,10), numticks=100)) + ax[key].xaxis.set_major_locator(ticker.LogLocator(base=10.0, numticks=20)) + ax[key].xaxis.set_minor_locator(ticker.LogLocator(base=10.0, subs=np.arange(2,10), numticks=100)) + ax[key].grid(True,which="minor",ls="-",lw=0.5,zorder=5) + ax[key].grid(True,which="major",ls="-",lw=1,zorder=10) + for t in tvals: + prod = pf_csfd(t,Dvals,key) + ax[key].plot(Dvals, prod, '-', color='black', linewidth=1.0, zorder=50) + labeli = 15 + ax[key].text(Dvals[labeli],prod[labeli],f"{t:.2f} Ga", ha="left", va="top",rotation=-72) + + plt.tick_params(axis='y', which='minor') + plt.tight_layout() + plt.show() diff --git a/ctem/driver.py b/ctem/driver.py new file mode 100644 index 00000000..2646d1db --- /dev/null +++ b/ctem/driver.py @@ -0,0 +1,383 @@ +import numpy as np +import os +import subprocess +import shutil +from ctem import util +import sys +import pandas +from ctem import craterproduction +from scipy.interpolate import interp1d +from ctem import __file__ as _pyfile +from pathlib import Path +import warnings + +class Simulation: + """ + This is a class that defines the basic CTEM simulation object. It initializes a dictionary of user and reads + it in from a file (default name is ctem.in). It also creates the directory structure needed to store simulation + files if necessary. + """ + def __init__(self, param_file="ctem.in", isnew=True): + currentdir = os.getcwd() + self.user = { + 'restart': None, + 'runtype': None, + 'popupconsole': None, + 'saveshaded': None, + 'saverego': None, + 'savetruelist': None, + 'seedn': 1, + 'totalimpacts': 0, + 'ncount': 0, + 'curyear': 0.0, + 'fracdone': 1.0, + 'masstot': 0.0, + 'interval': 0.0, + 'numintervals': 0, + 'pix': -1.0, + 'gridsize': -1, + 'seed': 0, + 'maxcrat': 1.0, + 'shadedminhdefault': 1, + 'shadedmaxhdefault': 1, + 'shadedminh': 0.0, + 'shadedmaxh': 0.0, + 'workingdir': currentdir, + 'ctemfile': param_file, + 'impfile': None, + 'sfdcompare': None, + 'quasimc': None, + 'sfdfile' : None, + 'realcraterlist': None, + } + + # Get the location of the CTEM executable + self.ctem_executable = Path(currentdir) / "CTEM" + if not self.ctem_executable.exists(): + print(f"CTEM driver not found at {self.ctem_executable}. Trying package directory..") + self.ctem_executable = Path(_pyfile).parent.parent.parent / "bin" / "CTEM" + if not self.ctem_executable.exists(): + warnings.warn(f"Cannot find the CTEM driver {str(self.ctem_executable)}", stacklevel=2) + self.ctem_executable = None + + + self.user = util.read_user_input(self.user) + + # This is containsall files generated by the main Fortran CTEM program plus the ctem.dat file that + # communicates the state of the simulation from the Python driver to the Fortran program + self.output_filenames = { + 'dat': 'ctem.dat', + 'dem': 'surface_dem.dat', + 'diam': 'surface_diam.dat', + 'ejc': 'surface_ejc.dat', + 'pos': 'surface_pos.dat', + 'time': 'surface_time.dat', + 'stack': 'surface_stacknum.dat', + 'rego': 'surface_rego.dat', + 'melt': 'surface_melt.dat', + 'comp': 'surface_comp.dat', + 'age' : 'surface_age.dat', + 'ocum': 'ocumulative.dat', + 'odist': 'odistribution.dat', + 'pdist': 'pdistribution.dat', + 'tcum' : 'tcumulative.dat', + 'tdist' : 'tdistribution.dat', + 'impmass' : 'impactmass.dat', + 'fracdone' : 'fracdone.dat', + 'regodepth' : 'regolithdepth.dat', + 'ejmax' : 'ejecta_table_max.dat', + 'ejmin' : 'ejecta_table_min.dat', + 'testprof' : 'testprofile.dat', + 'craterscale' : 'craterscale.dat', + 'craterlist' : 'craterlist.dat', + 'sfdfile' : 'production.dat', + 'distfrac' : 'surface_distfrac.dat', + 'ejm' : 'surface_ejm.dat', + 'ejmf' : 'surface_ejmf.dat', + 'meltdist' : 'surface_meltdist.dat', + 'meltfrac' : 'surface_meltfrac.dat' + } + if self.user['sfdfile'] is not None: # Override the default sfdfile name if the user supplies an alternative + self.output_filenames['sfdfile'] = self.user['sfdfile'] + + for k, v in self.output_filenames.items(): + self.output_filenames[k] = os.path.join(currentdir, v) + + self.directories = ['dist', 'misc', 'surf'] + if self.user['saveshaded'].upper() == 'T': + self.directories.append('shaded') + if self.user['saverego'].upper() == 'T': + self.directories.append('rego') + + # Set up data arrays + self.seedarr = np.zeros(100, dtype=int) + self.seedarr[0] = self.user['seed'] + self.odist = np.zeros([1, 6]) + self.pdist = np.zeros([1, 6]) + self.tdist = np.zeros([1, 6]) + self.surface_dem = np.zeros([self.user['gridsize'], self.user['gridsize']], dtype=float) + self.surface_ejc = np.zeros([self.user['gridsize'], self.user['gridsize']], dtype=float) + self.ph1 = None + + if self.user['sfdcompare'] is not None: + # Read sfdcompare file + sfdfile = os.path.join(self.user['workingdir'], self.user['sfdcompare']) + self.ph1 = util.read_formatted_ascii(sfdfile, skip_lines=0) + + + # If this is a new simulation, run and post-process results. Otherwise, don't do anything more + if isnew: + # Starting new or old run? + if (self.user['restart'].upper() == 'F'): + print('Starting a new run') + + util.create_dir_structure(self.user, self.directories) + # Delete any old output files + for k, v in self.output_filenames.items(): + if os.path.isfile(v): + os.remove(v) + + # Scale the production function to the simulation domain + self.scale_production() + + # Setup Quasi-MC run + + if (self.user['quasimc'] == 'T'): + + #Read list of real craters + print("quasi-MC mode is ON") + print("Generating the crater scaling data in CTEM") + rclist = util.read_formatted_ascii(self.user['realcraterlist'], skip_lines = 0) + tempfile = os.path.join(currentdir, 'temp.in') + + # Generate craterlist.dat + shutil.copy2(self.user['ctemfile'], tempfile ) + + #Write a temporary input file to generate the necessary quasimc files + util.write_temp_input(self.user, tempfile) + util.write_datfile(self.user, self.output_filenames['dat'], self.seedarr) + self.compute_one_interval(ctemin=tempfile) + os.remove(tempfile) + + #Interpolate craterscale.dat to get impactor sizes from crater sizes given + df = pandas.read_csv(self.output_filenames['craterscale'], sep='\s+') + df['log(Dc)'] = np.log(df['Dcrat(m)']) + df['log(Di)'] = np.log(df['#Dimp(m)']) + xnew = df['log(Dc)'].values + ynew = df['log(Di)'].values + interp = interp1d(xnew, ynew, fill_value='extrapolate') + rclist[:,0] = np.exp(interp(np.log(rclist[:,0]))) + + #Convert age in Ga to "interval time" + if (self.user['runtype'].upper() == 'STATISTICAL'): + rclist[:,5] = (self.user['interval']) - craterproduction.Tscale(rclist[:,5], 'NPF_Moon') + else: + rclist[:,5] = (self.user['interval'] * self.user['numintervals']) - craterproduction.Tscale(rclist[:,5], 'NPF_Moon') + rclist = rclist[rclist[:,5].argsort()] + + #Export to dat file + util.write_realcraters(self.output_filenames['craterlist'], rclist) + + util.write_datfile(self.user, self.output_filenames['dat'], self.seedarr) + else: + print('Continuing a previous run') + self.read_output() + + return + + def scale_production(self): + """ + Scales the production function to the simulation domain and saves the scaled production function to a file that + will be read in by the main Fortran program. + """ + + # Read production function file + impfile = os.path.join(self.user['workingdir'], self.user['impfile']) + prodfunction = util.read_formatted_ascii(impfile, skip_lines=0) + + # Create impactor production population + area = (self.user['gridsize'] * self.user['pix']) ** 2 + self.production = np.copy(prodfunction) + self.production[:, 1] = self.production[:, 1] * area * self.user['interval'] + + # Write the scaled production function to file + util.write_production(self.output_filenames['sfdfile'], self.production) + + return + + def run(self): + """ + Runs a complete simulation over all intervals specified in the input user. This method loops over all + intervals and process outputs into images, and redirect output files to their apporpriate folders. + + This method replaces most of the functionality of the original ctem_driver.py + """ + + print('Beginning loops') + while (self.user['ncount'] <= self.user['numintervals']): + if (self.user['ncount'] > 0): + # Move ctem.dat + self.redirect_outputs(['dat'], 'misc') + + #Execute Fortran code + self.compute_one_interval(self.user['ctemfile']) + + # Read in output files + self.read_output() + + # Process the output files + self.process_output() + + # Update ncount + self.user['ncount'] = self.user['ncount'] + 1 + + if ((self.user['runtype'].upper() == 'STATISTICAL') or (self.user['ncount'] == 1)): # Reset the simulation + self.user['restart'] = 'F' + self.user['curyear'] = 0.0 + self.user['totalimpacts'] = 0 + self.user['masstot'] = 0.0 + + # Delete tdistribution file, if it exists so that we don't accumulate true craters in statistical mode + tdist_file = self.user['workingdir'] + 'tdistribution.dat' + if os.path.isfile(tdist_file): + os.remove(tdist_file) + + else: + self.user['restart'] = 'T' + + # Write ctem.dat file for next interval + util.write_datfile(self.user, self.output_filenames['dat'], self.seedarr) + + return + + def compute_one_interval(self, ctemin="ctem.in"): + """ + Executes the Fortran code to generate one interval of simulation output. + """ + # Create crater population and display CTEM progress on screen + print(self.user['ncount'], ' Calling FORTRAN routine') + try: + p = subprocess.Popen([os.path.join(self.user['workingdir'], self.ctem_executable), ctemin], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True, + shell=False) + for line in p.stdout: + if "%" in line: + print(line.replace('\n','\r'), end='') + else: + print(line,end='') + res = p.communicate() + if p.returncode != 0: + for line in res[1]: + print(line, end='') + raise Exception ("CTEM Failure") + except: + print("Error executing main CTEM program") + sys.exit() + + return + + def read_output(self): + """ + Reads in all of the files generated by the Fortran code after one interval and redirects them to appropriate + folders for storage after appending the interval number to the filename. + """ + # Read Fortran output + print(self.user['ncount'], ' Reading Fortran output') + + # Read surface dem(shaded relief) and ejecta data files + self.surface_dem = util.read_unformatted_binary(self.output_filenames['dem'], self.user['gridsize']) + self.surface_ejc = util.read_unformatted_binary(self.output_filenames['ejc'], self.user['gridsize']) + + # Read odistribution, tdistribution, and pdistribution files + self.odist = util.read_formatted_ascii(self.output_filenames['odist'], skip_lines=1) + self.tdist = util.read_formatted_ascii(self.output_filenames['tdist'], skip_lines=1) + self.pdist = util.read_formatted_ascii(self.output_filenames['pdist'], skip_lines=1) + + # Read impact mass from file + self.impact_mass = util.read_impact_mass(self.output_filenames['impmass']) + + # Read ctem.dat file + util.read_datfile(self.user, self.output_filenames['dat'], self.seedarr) + + + def process_output(self): + """ + Processes output to update masses, time, computes regolith depth, generates all plots, and redirects files + into intermediate storage. + """ + # Display results + print(self.user['ncount'], ' Generating surface images and plots') + + # Write surface dem, surface ejecta and shaded relief data + util.image_dem(self.user, self.surface_dem) + if (self.user['saverego'].upper() == 'T'): + util.image_regolith(self.user, self.surface_ejc) + if (self.user['saveshaded'].upper() == 'T'): + util.image_shaded_relief(self.user, self.surface_dem) + + if self.user['ncount'] > 0: # These aren't available yet from the initial conditions + + # Save copy of crater distribution files + # Update user: mass, curyear, regolith properties + self.user['masstot'] = self.user['masstot'] + self.impact_mass + + self.user['curyear'] = self.user['curyear'] + self.user['fracdone'] * self.user['interval'] + template = "%(fracdone)9.6f %(curyear)19.12E\n" + with open(self.output_filenames['fracdone'], 'w') as fp_frac: + fp_frac.write(template % self.user) + + reg_text = "%19.12E %19.12E %19.12E %19.12E\n" % (self.user['curyear'], + np.mean(self.surface_ejc), np.amax(self.surface_ejc), + np.amin(self.surface_ejc)) + with open(self.output_filenames['regodepth'], 'w') as fp_reg: + fp_reg.write(reg_text) + # Redirect output files to storage + self.redirect_outputs(['odist', 'ocum', 'pdist', 'tdist'], 'dist') + if (self.user['savetruelist'].upper() == 'T'): + self.redirect_outputs(['tcum'], 'dist') + self.redirect_outputs(['impmass'], 'misc') + if (self.user['saverego'].upper() == 'T') : + self.redirect_outputs(['stack','rego','age','melt','comp','ejm','meltdist'], 'rego') + + + + def redirect_outputs(self, filekeys, foldername): + """ + Copies a set of output files from the working directory into a subfolder. + Takes as input the dictionaries of user parameters and output file names, the dictionary keys to the file names + you wish to redirect, and the redirection destination folder name. The new name will be the key name + zero padded + interval number. + + Example: + calling redirect_outputs(['odist','tdist'], 'dist') when user['ncount'] is 1 + should do the following: + copy 'odistribution.dat' to 'dist/odist_000001.dat' + copy 'tdistribution.dat' to 'dist/tdist_000001.dat' + """ + + for k in filekeys: + forig = self.output_filenames[k] + fdest = os.path.join(self.user['workingdir'], foldername, f"{k}_{self.user['ncount']:06d}.dat") + shutil.copy2(forig, fdest) + + def cleanup(self): + """ + Deletes all files and folders generated by CTEM. + """ + # This is a list of files generated by the main Fortran program + print("Deleting all files generated by CTEM") + util.destroy_dir_structure(self.user, self.directories) + for key, filename in self.output_filenames.items(): + print(f"Deleting file {filename}") + try: + os.remove(filename) + except OSError as error: + print(error) + + return + +if __name__ == '__main__': + sim = Simulation() + sim.run() \ No newline at end of file diff --git a/ctem/util.py b/ctem/util.py new file mode 100644 index 00000000..00922421 --- /dev/null +++ b/ctem/util.py @@ -0,0 +1,443 @@ +import numpy as np +import os +import shutil +from matplotlib.colors import LightSource +import matplotlib.cm as cm +import matplotlib.pyplot as plt +import re +from tempfile import mkstemp +from scipy.io import FortranFile + +# Set pixel scaling common for image writing, at 1 pixel/ array element +dpi = 72.0 +class CTEMLightSource(LightSource): + """ + Override one function in LightSource to prevent the contrast from being rescaled. + """ + def shade_normals(self, normals, fraction=1.): + """ + Calculate the illumination intensity for the normal vectors of a + surface using the defined azimuth and elevation for the light source. + + Imagine an artificial sun placed at infinity in some azimuth and + elevation position illuminating our surface. The parts of the surface + that slope toward the sun should brighten while those sides facing away + should become darker. + + Changes by David Minton: The matplotlib version of this rescales the intensity + in a way that causes the brightness level of the images to change between + simulation outputs. This makes movies of the surface evolution appear to flicker. + + Parameters + ---------- + fraction : number, optional + Increases or decreases the contrast of the hillshade. Values + greater than one will cause intermediate values to move closer to + full illumination or shadow (and clipping any values that move + beyond 0 or 1). Note that this is not visually or mathematically + the same as vertical exaggeration. + + Returns + ------- + ndarray + A 2D array of illumination values between 0-1, where 0 is + completely in shadow and 1 is completely illuminated. + """ + + intensity = normals.dot(self.direction) + + # Apply contrast stretch + imin, imax = intensity.min(), intensity.max() + intensity *= fraction + + # Rescale to 0-1, keeping range before contrast stretch + # If constant slope, keep relative scaling (i.e. flat should be 0.5, + # fully occluded 0, etc.) + # if (imax - imin) > 1e-6: + # # Strictly speaking, this is incorrect. Negative values should be + # # clipped to 0 because they're fully occluded. However, rescaling + # # in this manner is consistent with the previous implementation and + # # visually appears better than a "hard" clip. + # intensity -= imin + # intensity /= (imax - imin) + intensity = np.clip(intensity, 0, 1) + + return intensity + + + +# These are directories that are created by CTEM in order to store intermediate results + +def create_dir_structure(user, directories): + """ + Create directories for various output files if they do not already exist + """ + + for dirname in directories: + dirpath = os.path.join(user['workingdir'], dirname) + if not os.path.isdir(dirpath): + print(f"Creating directory {dirpath}") + os.makedirs(dirpath) + + return + +def destroy_dir_structure(user, directories): + """ + Deletes directories generated by create_dir_structure + """ + for dirname in directories: + dirpath = os.path.join(user['workingdir'], dirname) + if os.path.isdir(dirpath): + print(f"Deleting directory {dirpath}") + shutil.rmtree(dirpath, ignore_errors=True) + + return + +def image_dem(user, DEM): + dpi = 300.0 # 72.0 + pix = user['pix'] + gridsize = user['gridsize'] + ve = 1.0 + azimuth = 300.0 # user['azimuth'] + solar_angle = 20.0 # user['solar_angle'] + + ls = CTEMLightSource(azdeg=azimuth, altdeg=solar_angle) + dem_img = ls.hillshade(np.flip(DEM,axis=0), vert_exag=ve, dx=pix, dy=pix, fraction=1) + + # Generate image to put into an array + height = gridsize / dpi + width = gridsize / dpi + fig = plt.figure(figsize=(width, height), dpi=dpi) + ax = plt.axes([0, 0, 1, 1]) + ax.imshow(dem_img, interpolation="nearest", cmap='gray', vmin=0.0, vmax=1.0) + plt.axis('off') + # Save image to file + filename = os.path.join(user['workingdir'],'surf',"surf%06d.png" % user['ncount']) + plt.savefig(filename, dpi=dpi, bbox_inches=0) + plt.close() + + return + + +def image_regolith(user, regolith): + # Create scaled regolith image + minref = user['pix'] * 1.0e-4 + maxreg = np.amax(regolith) + minreg = np.amin(regolith) + if (minreg < minref): minreg = minref + if (maxreg < minref): maxreg = (minref + 1.0e3) + regolith_scaled = np.copy(regolith) + np.place(regolith_scaled, regolith_scaled < minref, minref) + regolith_scaled = 254.0 * ( + (np.log(regolith_scaled) - np.log(minreg)) / (np.log(maxreg) - np.log(minreg))) + + # Save image to file + filename = os.path.join(user['workingdir'],'rego', "rego%06d.png" % user['ncount']) + height = user['gridsize'] / dpi + width = height + fig = plt.figure(figsize=(width, height), dpi=dpi) + fig.figimage(regolith_scaled, cmap=cm.nipy_spectral, origin='lower') + plt.savefig(filename) + plt.close() + + return + + +def image_shaded_relief(user, DEM): + dpi = 300.0 # 72.0 + pix = user['pix'] + gridsize = user['gridsize'] + ve = 1.0 + mode = 'overlay' + azimuth = 300.0 # user['azimuth'] + solar_angle = 20.0 # user['solar_angle'] + + ls = CTEMLightSource(azdeg=azimuth, altdeg=solar_angle) + cmap = cm.cividis + + # If min and max appear to be reversed, then fix them + if (user['shadedminh'] > user['shadedmaxh']): + temp = user['shadedminh'] + user['shadedminh'] = user['shadedmaxh'] + user['shadedmaxh'] = temp + else: + user['shadedminh'] = user['shadedminh'] + user['shadedmaxh'] = user['shadedmaxh'] + + # If no shadedmin/max user are read in from ctem.dat, determine the values from the data + if (user['shadedminhdefault'] == 1): + shadedminh = np.amin(DEM) + else: + shadedminh = user['shadedminh'] + if (user['shadedmaxhdefault'] == 1): + shadedmaxh = np.amax(DEM) + else: + shadedmaxh = user['shadedmaxh'] + + dem_img = ls.shade(np.flip(DEM,axis=0), cmap=cmap, blend_mode=mode, fraction=1.0, + vert_exag=ve, dx=pix, dy=pix, + vmin=shadedminh, vmax=shadedmaxh) + + # Generate image to put into an array + height = gridsize / dpi + width = gridsize / dpi + fig = plt.figure(figsize=(width, height), dpi=dpi) + ax = plt.axes([0, 0, 1, 1]) + ax.imshow(dem_img, interpolation="nearest", vmin=0.0, vmax=1.0) + plt.axis('off') + # Save image to file + filename = os.path.join(user['workingdir'],'shaded',"shaded%06d.png" % user['ncount']) + plt.savefig(filename, dpi=dpi, bbox_inches=0) + plt.close() + + return user + + +def read_datfile(user, datfile, seedarr): + # Read and parse ctem.dat file + + # Read ctem.dat file + print('Reading input file ' + datfile) + fp = open(datfile, 'r') + lines = fp.readlines() + fp.close() + + # Parse file lines and update parameter fields + fields = lines[0].split() + if len(fields) > 0: + user['totalimpacts'] = real2float(fields[0]) + user['ncount'] = int(fields[1]) + user['curyear'] = real2float(fields[2]) + user['restart'] = fields[3] + user['fracdone'] = real2float(fields[4]) + user['masstot'] = real2float(fields[5]) + + # Parse remainder of file to build seed array + nlines = len(lines) + index = 1 + while (index < nlines): + fields = lines[index].split() + seedarr[index - 1] = real2float(fields[0]) + index += 1 + + user['seedn'] = index - 1 + + return + + +def read_formatted_ascii(filename, skip_lines): + # Generalized ascii text reader + # For use with sfdcompare, production, odist, tdist, pdist data files + try: + data = np.genfromtxt(filename, skip_header=skip_lines) + except: + print(f"Error reading {filename}") + data = None + return data + + +def read_impact_mass(filename): + # Read impact mass file + + fp = open(filename, 'r') + line = fp.readlines() + fp.close() + + fields = line[0].split() + if (len(fields) > 0): + mass = real2float(fields[0]) + else: + mass = 0 + + return mass + + +# Write production function to file production.dat +# This file format does not exactly match that generated from IDL. Does it work? +def read_user_input(user): + # Read and parse ctem.in file + inputfile = user['ctemfile'] + + # Read ctem.in file + print('Reading input file ' + user['ctemfile']) + with open(inputfile, 'r') as fp: + lines = fp.readlines() + + # Process file text + for line in lines: + fields = line.split() + if len(fields) > 0: + if ('pix' == fields[0].lower()): user['pix'] = real2float(fields[1]) + if ('gridsize' == fields[0].lower()): user['gridsize'] = int(fields[1]) + if ('seed' == fields[0].lower()): user['seed'] = int(fields[1]) + if ('sfdfile' == fields[0].lower()): user['sfdfile'] = os.path.join(user['workingdir'],fields[1]) + if ('impfile' == fields[0].lower()): user['impfile'] = os.path.join(user['workingdir'],fields[1]) + if ('maxcrat' == fields[0].lower()): user['maxcrat'] = real2float(fields[1]) + if ('sfdcompare' == fields[0].lower()): user['sfdcompare'] = os.path.join(user['workingdir'], fields[1]) + if ('realcraterlist' == fields[0].lower()): user['realcraterlist'] = os.path.join(user['workingdir'], fields[1]) + if ('interval' == fields[0].lower()): user['interval'] = real2float(fields[1]) + if ('numintervals' == fields[0].lower()): user['numintervals'] = int(fields[1]) + if ('popupconsole' == fields[0].lower()): user['popupconsole'] = fields[1] + if ('saveshaded' == fields[0].lower()): user['saveshaded'] = fields[1] + if ('saverego' == fields[0].lower()): user['saverego'] = fields[1] + if ('savepres' == fields[0].lower()): user['savepres'] = fields[1] + if ('savetruelist' == fields[0].lower()): user['savetruelist'] = fields[1] + if ('runtype' == fields[0].lower()): user['runtype'] = fields[1] + if ('restart' == fields[0].lower()): user['restart'] = fields[1] + if ('quasimc' == fields[0].lower()): user['quasimc'] = fields[1] + if ('shadedminh' == fields[0].lower()): + user['shadedminh'] = real2float(fields[1]) + user['shadedminhdefault'] = 0 + if ('shadedmaxh' == fields[0].lower()): + user['shadedmaxh'] = real2float(fields[1]) + user['shadedmaxhdefault'] = 0 + + # Test values for further processing + if (user['interval'] <= 0.0): + print('Invalid value for or missing variable INTERVAL in ' + inputfile) + if (user['numintervals'] <= 0): + print('Invalid value for or missing variable NUMINTERVALS in ' + inputfile) + if (user['pix'] <= 0.0): + print('Invalid value for or missing variable PIX in ' + inputfile) + if (user['gridsize'] <= 0): + print('Invalid value for or missing variable GRIDSIZE in ' + inputfile) + if (user['seed'] == 0): + print('Invalid value for or missing variable SEED in ' + inputfile) + if (user['impfile'] is None): + print('Invalid value for or missing variable IMPFILE in ' + inputfile) + if (user['popupconsole'] is None): + print('Invalid value for or missing variable POPUPCONSOLE in ' + inputfile) + if (user['saveshaded'] is None): + print('Invalid value for or missing variable SAVESHADED in ' + inputfile) + if (user['saverego'] is None): + print('Invalid value for or missing variable SAVEREGO in ' + inputfile) + if (user['savepres'] is None): + print('Invalid value for or missing variable SAVEPRES in ' + inputfile) + if (user['savetruelist'] is None): + print('Invalid value for or missing variable SAVETRUELIST in ' + inputfile) + if (user['runtype'] is None): + print('Invalid value for or missing variable RUNTYPE in ' + inputfile) + if (user['restart'] is None): + print('Invalid value for or missing variable RESTART in ' + inputfile) + + return user + + +def read_unformatted_binary(filename, gridsize, kind='DP'): + # Read unformatted binary files created by Fortran + # For use with surface ejecta and surface dem data files + if kind == 'DP': + dt = np.dtype('f8') + elif kind == 'SP': + dt = np.dtype('f4') + elif kind == 'I4B': + dt = np.dtype(' count: + break + + fout.writelines(fin.readlines()) + + + fin.close() + fout.close() + + shutil.move(name, source) + + return + +def write_datfile(user, filename, seedarr): + # Write various user and random number seeds into ctem.dat file + fp = open(filename, 'w') + + template = "%(totalimpacts)17d %(ncount)12d %(curyear)19.12E %(restart)s %(fracdone)9.6f %(masstot)19.12E\n" + fp.write(template % user) + + # Write random number seeds to the file + for index in range(user['seedn']): + fp.write("%12d\n" % seedarr[index]) + + fp.close() + + return + + +def write_production(filename, production): + np.savetxt(filename, production, fmt='%1.8e', delimiter=' ') + + return + + +def write_realcraters(filename, realcraters): + """Writes file of real craters for use in quasi-MC runs""" + + np.savetxt(filename, realcraters, fmt='%1.8e', delimiter='\t') + + return + +def write_temp_input(user, filename): + """Makes changes to a temporary input file for use when generating craterlist.dat for quasimc runs""" + + sed('testflag', 'testflag T!', filename) + sed('testimp', f'testimp {user["pix"]*1e-3} !', filename) # Make a tiny test crater. We don't care about the crater itself, just that we run CTEM once to get all of the converted files + sed('quasimc', 'quasimc F!', filename) + sed('interval', 'interval 1 !', filename) + sed('numinterval 1 !s', 'numintervals 1 !', filename) + + return \ No newline at end of file diff --git a/ctem/viewer3d.py b/ctem/viewer3d.py new file mode 100644 index 00000000..8aacf84e --- /dev/null +++ b/ctem/viewer3d.py @@ -0,0 +1,124 @@ +import numpy as np +import open3d +import ctem + +class Polysurface(ctem.Simulation): + """A model of a self-gravitating small body""" + def __init__(self): + ctem.Simulation.__init__(self, isnew=False) # Initialize the data structures, but doesn't start a new run + self.read_output() + #used for Open3d module + self.mesh = open3d.geometry.TriangleMesh() + return + + def ctem2blockmesh(self): + # Build mesh grid + s = self.user['gridsize'] + pix = self.user['pix'] + ygrid, xgrid = np.mgrid[-s/2:s/2, -s/2:s/2] * pix + y0, x0 = ygrid - pix/2, xgrid - pix/2 + y1, x1 = ygrid - pix/2, xgrid + pix/2 + y2, x2 = ygrid + pix/2, xgrid + pix/2 + y3, x3 = ygrid + pix/2, xgrid - pix/2 + + xvals = np.append( + np.append( + np.append(x0.flatten(), + x1.flatten()), + x2.flatten()), + x3.flatten()) + yvals = np.append( + np.append( + np.append(y0.flatten(), + y1.flatten()), + y2.flatten()), + y3.flatten()) + zvals = np.append( + np.append( + np.append(self.surface_dem.flatten(), + self.surface_dem.flatten()), + self.surface_dem.flatten()), + self.surface_dem.flatten()) + verts = np.array((xvals, yvals, zvals)).T + nface_triangles = 10 + faces = np.full([nface_triangles*s**2, 3], -1, dtype=np.int64) + for j in range(s): + for i in range(s): + i0 = s*j + i + i1 = i0 + s**2 + i2 = i1 + s**2 + i3 = i2 + s**2 + + fidx = np.arange(nface_triangles*i0,nface_triangles*(i0+1)) + # Make the two top triangles + faces[fidx[0],:] = [i0, i1, i2] + faces[fidx[1],:] = [i0, i2, i3] + # Make the two west side triangles + if i > 0: + faces[fidx[2],:] = [i0, i3, i2-1] + faces[fidx[3],:] = [i0, i2-1, i1-1] + # Make the two south side triangles + if j > 0: + faces[fidx[4],:] = [i1, i0, i3-s ] + faces[fidx[5],:] = [i1, i3-s, i2-s] + # Make the two east side triangles + if i < (s - 1): + faces[fidx[6],:] = [i2, i1, i0+1] + faces[fidx[7],:] = [i2, i0+1, i3+1] + #Make the two north side triangles + if j < (s -1): + faces[fidx[8],:] = [i3, i2, i1+s] + faces[fidx[9],:] = [i3, i1+s, i0+s] + nz = faces[:,0] != -1 + f2 = faces[nz,:] + self.mesh.vertices = open3d.utility.Vector3dVector(verts) + self.mesh.triangles = open3d.utility.Vector3iVector(f2) + self.mesh.compute_vertex_normals() + self.mesh.compute_triangle_normals() + + return + + def ctem2trimesh(self): + # Build mesh grid + s = self.user['gridsize'] + pix = self.user['pix'] + ygrid, xgrid = np.mgrid[-s/2:s/2, -s/2:s/2] * pix + + xvals = xgrid.flatten() + yvals = ygrid.flatten() + zvals = self.surface_dem.flatten() + verts = np.array((xvals, yvals, zvals)).T + faces = np.full([2 * (s-1)**2, 3], -1, dtype=np.int64) + for j in range(s - 1): + for i in range(s - 1): + idx = (s - 1) * j + i + faces[idx, :] = [j * s + i, j * s + i + 1, (j + 1) * s + i + 1] + idx += (s - 1) ** 2 + faces[idx, :] = [(j + 1) * s + i + 1, (j + 1) * s + i, j * s + i ] + self.mesh.vertices = open3d.utility.Vector3dVector(verts) + self.mesh.triangles = open3d.utility.Vector3iVector(faces) + self.mesh.compute_vertex_normals() + self.mesh.compute_triangle_normals() + + return + + def visualize(self): + vis = open3d.visualization.Visualizer() + vis.create_window() + vis.add_geometry(self.mesh) + opt = vis.get_render_option() + opt.background_color = np.asarray([0, 0, 0]) + + self.mesh.paint_uniform_color([0.5, 0.5, 0.5]) + vis.run() + vis.destroy_window() + + +if __name__ == '__main__': + sim = Polysurface() + sim.surface_dem *= 10 + sim.ctem2trimesh() + sim.visualize() + + + From b8802390193d4ff018636e4726027bdfb8f6528f Mon Sep 17 00:00:00 2001 From: David Minton Date: Sat, 10 Feb 2024 18:07:21 -0500 Subject: [PATCH 27/42] Restructured python files and fixed bugs to make the code more compatible with ifx --- .gitignore | 1 + cmake/Modules/SetFortranFlags.cmake | 16 +- ctem/ctem/NPF.py | 104 ------ ctem/ctem/__init__.py | 1 - ctem/ctem/craterproduction.py | 216 ----------- ctem/ctem/driver.py | 383 -------------------- ctem/ctem/util.py | 443 ----------------------- ctem/ctem/viewer3d.py | 124 ------- ctem/setup.py | 6 - src/crater/crater_subpixel_diffusion.f90 | 8 +- src/ejecta/ejecta_emplace.f90 | 4 +- src/init/init_dist.f90 | 12 +- src/io/io_ejecta_table.f90 | 2 +- src/io/io_input.f90 | 2 +- src/io/io_read_craterlist.f90 | 6 +- src/io/io_read_prod.f90 | 2 +- src/io/io_read_vdist.f90 | 6 +- 17 files changed, 31 insertions(+), 1305 deletions(-) delete mode 100644 ctem/ctem/NPF.py delete mode 100644 ctem/ctem/__init__.py delete mode 100644 ctem/ctem/craterproduction.py delete mode 100644 ctem/ctem/driver.py delete mode 100644 ctem/ctem/util.py delete mode 100644 ctem/ctem/viewer3d.py delete mode 100644 ctem/setup.py diff --git a/.gitignore b/.gitignore index 6ce9617f..70c42081 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ !distclean.cmake !README.md !version.txt +!ctem/ !ctem/**.py !cmake/Modules/*.cmake !*.bash diff --git a/cmake/Modules/SetFortranFlags.cmake b/cmake/Modules/SetFortranFlags.cmake index edf73442..f42d8d75 100644 --- a/cmake/Modules/SetFortranFlags.cmake +++ b/cmake/Modules/SetFortranFlags.cmake @@ -533,10 +533,10 @@ IF (CMAKE_BUILD_TYPE STREQUAL "RELEASE" OR CMAKE_BUILD_TYPE STREQUAL "PROFILE") ) # Tells the compiler to link to certain libraries in the Intel oneAPI Math Kernel Library (oneMKL). - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" - Fortran "/Qmkl:cluster" # Intel Windows - "/Qmkl" # Intel Windows - ) + # SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" + # Fortran "/Qmkl:cluster" # Intel Windows + # "/Qmkl" # Intel Windows + # ) # Enables additional interprocedural optimizations for a single file compilation SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" @@ -574,10 +574,10 @@ IF (CMAKE_BUILD_TYPE STREQUAL "RELEASE" OR CMAKE_BUILD_TYPE STREQUAL "PROFILE") ) # Tells the compiler to link to certain libraries in the Intel oneAPI Math Kernel Library (oneMKL). - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" - Fortran "-qmkl=cluster" # Intel - "-qmkl" # Intel - ) + # SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" + # Fortran "-qmkl=cluster" # Intel + # "-qmkl" # Intel + # ) # Enables additional interprocedural optimizations for a single file compilation SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" diff --git a/ctem/ctem/NPF.py b/ctem/ctem/NPF.py deleted file mode 100644 index cb7ee363..00000000 --- a/ctem/ctem/NPF.py +++ /dev/null @@ -1,104 +0,0 @@ -import numpy as np -# The Neukum production function -# Ivanov, Neukum, and Hartmann (2001) SSR v. 96 pp. 55-86 -def N1lunar(T): - return 5.44e-14 * (np.exp(6.93*T) - 1) + 8.38e-4 * T - - -def Nlunar(D): - # Lunar crater SFD - aL00 = -3.0876 - aL01 = -3.557528 - aL02 = 0.781027 - aL03 = 1.021521 - aL04 = -0.156012 - aL05 = -0.444058 - aL06 = 0.019977 - aL07 = 0.086850 - aL08 = -0.005874 - aL09 = -0.006809 - aL10 = 8.25e-4 - aL11 = 5.54e-5 - - return np.where((D > 0.01) & (D < 1000.0), - 10**(aL00 - + aL01 * np.log10(D) ** 1 - + aL02 * np.log10(D) ** 2 - + aL03 * np.log10(D) ** 3 - + aL04 * np.log10(D) ** 4 - + aL05 * np.log10(D) ** 5 - + aL06 * np.log10(D) ** 6 - + aL07 * np.log10(D) ** 7 - + aL08 * np.log10(D) ** 8 - + aL09 * np.log10(D) ** 9 - + aL10 * np.log10(D) ** 10 - + aL11 * np.log10(D) ** 11),float('nan')) - -def Rproj(D): - #Projectile SFD - aP00 = 0.0 - aP01 = -1.375458 - aP02 = 1.272521e-1 - aP03 = -1.282166 - aP04 = -3.074558e-1 - aP05 = 4.149280e-1 - aP06 = 1.910668e-1 - aP07 = -4.260980e-2 - aP08 = -3.976305e-2 - aP09 = -3.180179e-3 - aP10 = 2.799369e-3 - aP11 = 6.892223e-4 - aP12 = 2.614385e-6 - aP13 = -1.416178e-5 - aP14 = -1.191124e-6 - - return np.where((D > 1e-4) & (D < 300), - 10**(aP00 - + aP01 * np.log10(D)**1 - + aP02 * np.log10(D)**2 - + aP03 * np.log10(D)**3 - + aP04 * np.log10(D)**4 - + aP05 * np.log10(D)**5 - + aP06 * np.log10(D)**6 - + aP07 * np.log10(D)**7 - + aP08 * np.log10(D)**8 - + aP09 * np.log10(D)**9 - + aP10 * np.log10(D)**10 - + aP11 * np.log10(D)**11 - + aP12 * np.log10(D)**12 - + aP13 * np.log10(D)**13 - + aP14 * np.log10(D)**14),float('nan')) - -def N1mars(T): - # Mars crater SFD - # Ivanov (2001) SSR v. 96 pp. 87-104 - return 2.68e-14 * (np.exp(6.93 * T) - 1) + 4.13e-4 * T - -def Nmars(D): - aM00 = -3.384 - aM01 = -3.197 - aM02 = 1.257 - aM03 = 0.7915 - aM04 = -0.4861 - aM05 = -0.3630 - aM06 = 0.1016 - aM07 = 6.756e-2 - aM08 = -1.181e-2 - aM09 = -4.753e-3 - aM10 = 6.233e-4 - aM11 = 5.805e-5 - - return np.where((D > 0.01) & (D < 1000.), - 10**(aM00 - + aM01 * np.log10(D)**1 - + aM02 * np.log10(D)**2 - + aM03 * np.log10(D)**3 - + aM04 * np.log10(D)**4 - + aM05 * np.log10(D)**5 - + aM06 * np.log10(D)**6 - + aM07 * np.log10(D)**7 - + aM08 * np.log10(D)**8 - + aM09 * np.log10(D)**9 - + aM10 * np.log10(D)**10 - + aM11 * np.log10(D)**11), - np.full_like(D, np.nan)) diff --git a/ctem/ctem/__init__.py b/ctem/ctem/__init__.py deleted file mode 100644 index 2e8ce2a0..00000000 --- a/ctem/ctem/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from ctem.driver import * \ No newline at end of file diff --git a/ctem/ctem/craterproduction.py b/ctem/ctem/craterproduction.py deleted file mode 100644 index 4d81b687..00000000 --- a/ctem/ctem/craterproduction.py +++ /dev/null @@ -1,216 +0,0 @@ -import numpy as np -from scipy import optimize - -# The Neukum production function for the Moon and Mars -#Lunar PF from: Ivanov, Neukum, and Hartmann (2001) SSR v. 96 pp. 55-86 -#Mars PF from: Ivanov (2001) SSR v. 96 pp. 87-104 -sfd_coef = { - "NPF_Moon" : [-3.0876,-3.557528,+0.781027,+1.021521,-0.156012,-0.444058,+0.019977,+0.086850,-0.005874,-0.006809,+8.25e-4, +5.54e-5], - "NPF_Mars" : [-3.384, -3.197, +1.257, +0.7915, -0.4861, -0.3630, +0.1016, +6.756e-2,-1.181e-2,-4.753e-3,+6.233e-4,+5.805e-5] - } -sfd_range = { - "NPF_Moon" : [0.01,1000], - "NPF_Mars" : [0.015,362] -} -#Exponential time constant (Ga) -tau = 6.93 -Nexp = 5.44e-14 - -time_coef = { - "NPF_Moon" : Nexp, - "NPF_Mars" : Nexp * 10**(sfd_coef.get("NPF_Mars")[0]) / 10**(sfd_coef.get("NPF_Moon")[0]) -} - -def N1(T, pfmodel): - """ - Return the N(1) value as a function of time for a particular production function model - - Parameters - ---------- - T : numpy array - Time in units of Ga - pfmodel : string - The production function model to use - Currently options are 'NPF_Moon' or 'NPF_Mars' - - Returns - ------- - N1 : numpy array - The number of craters per square kilometer greater than 1 km in diameter - """ - T_valid_range = np.where((T <= 4.5) & (T >= 0.0), T, np.nan) - return time_coef.get(pfmodel) * (np.exp(tau * T_valid_range) - 1.0) + 10 ** (sfd_coef.get(pfmodel)[0]) * T_valid_range - -def CSFD(Dkm,planet): - """ - Return the cumulative size-frequency distribution for a particular production function model - - Parameters - ---------- - Dkm : numpy array - Diameters in units of km - pfmodel : string - The production function model to use - Currently options are 'NPF_Moon' or 'NPF_Mars' - - Returns - ------- - CSFD : numpy array - The number of craters per square kilometer greater than Dkm in diameter at T=1 Ga - """ - logCSFD = sum(co * np.log10(Dkm) ** i for i, co in enumerate(sfd_coef.get(planet))) - return 10**(logCSFD) - -def DSFD(Dkm,planet): - """ - Return the differential size-frequency distribution for a particular production function model - - Parameters - ---------- - Dkm : numpy array - Diameters in units of km - pfmodel : string - The production function model to use - Currently options are 'NPF_Moon' or 'NPF_Mars' - - Returns - ------- - DSFD : numpy array - The differential number of craters (dN/dD) per square kilometer greater than Dkm in diameter at T = 1 Ga - """ - dcoef = sfd_coef.get(planet)[1:] - logDSFD = sum(co * np.log10(Dkm) ** i for i, co in enumerate(dcoef)) - return 10**(logDSFD) * CSFD(Dkm,planet) / Dkm - -def Tscale(T,planet): - """ - Return the number density of craters at time T relative to time T = 1 Ga - - Parameters - ---------- - T : numpy array - Time in units of Ga - pfmodel : string - The production function model to use - Currently options are 'NPF_Moon' or 'NPF_Mars' - - Returns - ------- - Tscale : numpy array - N1(T) / CSFD(Dkm = 1.0) - """ - return N1(T,planet) / CSFD(1.0,planet) - -def pf_csfd(T,Dkm,planet): - """ - Return the cumulative size-frequency distribution for a particular production function model as a function of Time - - Parameters - ---------- - T : numpy array - Time in units of Ga - Dkm : numpy array - Diameters in units of km - pfmodel : string - The production function model to use - Currently options are 'NPF_Moon' or 'NPF_Mars' - - Returns - ------- - pf_csfd : numpy array - The cumulative number of craters per square kilometer greater than Dkm in diameter at time T T - """ - D_valid_range = np.where((Dkm >= sfd_range.get(planet)[0]) & (Dkm <= sfd_range.get(planet)[1]),Dkm,np.nan) - return CSFD(D_valid_range,planet) * Tscale(T,planet) - -def pf_dsfd(T,Dkm,planet): - """ - Return the differential size-frequency distribution for a particular production function model as a function of Time - - Parameters - ---------- - T : numpy array - Time in units of Ga - Dkm : numpy array - Diameters in units of km - pfmodel : string - The production function model to use - Currently options are 'NPF_Moon' or 'NPF_Mars' - - Returns - ------- - pf_dsfd : numpy array - The cumulative number of craters per square kilometer greater than Dkm in diameter at time T T - """ - D_valid_range = np.where((Dkm >= sfd_range.get(planet)[0]) & (Dkm <= sfd_range.get(planet)[1]), Dkm, np.nan) - return DSFD(D_valid_range, planet) * Tscale(T, planet) - -def T_from_scale(TS,planet): - """ - Return the time in Ga for the given number density of craters relative to that at 1 Ga. - This is the inverse of Tscale - - Parameters - ---------- - TS : numpy array - number density of craters relative to that at 1 Ga - pfmodel : string - The production function model to use - Currently options are 'NPF_Moon' or 'NPF_Mars' - - Returns - ------- - T_from_scale : numpy array - The time in Ga - """ - def func(S): - return Tscale(S,planet) - TS - return optimize.fsolve(func, np.full_like(TS,4.4),xtol=1e-10) - - -if __name__ == "__main__": - import matplotlib.pyplot as plt - import matplotlib.ticker as ticker - print("Tests go here") - print(f"T = 1 Ga, N(1) = {pf_csfd(1.0,1.00,'NPF_Moon')}") - print(f"T = 4.2 Ga, N(1) = {pf_csfd(4.2,1.00,'NPF_Moon')}") - print("Tscale test: Should return all 1s") - Ttest = np.logspace(-4,np.log10(4.4),num=100) - Tres = T_from_scale(Tscale(Ttest,'NPF_Mars'),'NPF_Mars') - print(Ttest / Tres) - #for i,t in enumerate(Ttest): - # print(t,Tscale(t,'Moon'),Tres[i]) - - CSFDfig = plt.figure(1, figsize=(8, 7)) - ax = {'NPF_Moon': CSFDfig.add_subplot(121), - 'NPF_Mars': CSFDfig.add_subplot(122)} - - tvals = [0.01,1.0,4.0] - x_min = 1e-3 - x_max = 1e3 - y_min = 1e-9 - y_max = 1e3 - Dvals = np.logspace(np.log10(x_min), np.log10(x_max)) - for key in ax: - ax[key].title.set_text(key) - ax[key].set_xscale('log') - ax[key].set_yscale('log') - ax[key].set_ylabel('$\mathregular{N_{>D} (km^{-2})}$') - ax[key].set_xlabel('Diameter (km)') - ax[key].set_xlim(x_min, x_max) - ax[key].set_ylim(y_min, y_max) - ax[key].yaxis.set_major_locator(ticker.LogLocator(base=10.0, numticks=20)) - ax[key].yaxis.set_minor_locator(ticker.LogLocator(base=10.0, subs=np.arange(2,10), numticks=100)) - ax[key].xaxis.set_major_locator(ticker.LogLocator(base=10.0, numticks=20)) - ax[key].xaxis.set_minor_locator(ticker.LogLocator(base=10.0, subs=np.arange(2,10), numticks=100)) - ax[key].grid(True,which="minor",ls="-",lw=0.5,zorder=5) - ax[key].grid(True,which="major",ls="-",lw=1,zorder=10) - for t in tvals: - prod = pf_csfd(t,Dvals,key) - ax[key].plot(Dvals, prod, '-', color='black', linewidth=1.0, zorder=50) - labeli = 15 - ax[key].text(Dvals[labeli],prod[labeli],f"{t:.2f} Ga", ha="left", va="top",rotation=-72) - - plt.tick_params(axis='y', which='minor') - plt.tight_layout() - plt.show() diff --git a/ctem/ctem/driver.py b/ctem/ctem/driver.py deleted file mode 100644 index 2646d1db..00000000 --- a/ctem/ctem/driver.py +++ /dev/null @@ -1,383 +0,0 @@ -import numpy as np -import os -import subprocess -import shutil -from ctem import util -import sys -import pandas -from ctem import craterproduction -from scipy.interpolate import interp1d -from ctem import __file__ as _pyfile -from pathlib import Path -import warnings - -class Simulation: - """ - This is a class that defines the basic CTEM simulation object. It initializes a dictionary of user and reads - it in from a file (default name is ctem.in). It also creates the directory structure needed to store simulation - files if necessary. - """ - def __init__(self, param_file="ctem.in", isnew=True): - currentdir = os.getcwd() - self.user = { - 'restart': None, - 'runtype': None, - 'popupconsole': None, - 'saveshaded': None, - 'saverego': None, - 'savetruelist': None, - 'seedn': 1, - 'totalimpacts': 0, - 'ncount': 0, - 'curyear': 0.0, - 'fracdone': 1.0, - 'masstot': 0.0, - 'interval': 0.0, - 'numintervals': 0, - 'pix': -1.0, - 'gridsize': -1, - 'seed': 0, - 'maxcrat': 1.0, - 'shadedminhdefault': 1, - 'shadedmaxhdefault': 1, - 'shadedminh': 0.0, - 'shadedmaxh': 0.0, - 'workingdir': currentdir, - 'ctemfile': param_file, - 'impfile': None, - 'sfdcompare': None, - 'quasimc': None, - 'sfdfile' : None, - 'realcraterlist': None, - } - - # Get the location of the CTEM executable - self.ctem_executable = Path(currentdir) / "CTEM" - if not self.ctem_executable.exists(): - print(f"CTEM driver not found at {self.ctem_executable}. Trying package directory..") - self.ctem_executable = Path(_pyfile).parent.parent.parent / "bin" / "CTEM" - if not self.ctem_executable.exists(): - warnings.warn(f"Cannot find the CTEM driver {str(self.ctem_executable)}", stacklevel=2) - self.ctem_executable = None - - - self.user = util.read_user_input(self.user) - - # This is containsall files generated by the main Fortran CTEM program plus the ctem.dat file that - # communicates the state of the simulation from the Python driver to the Fortran program - self.output_filenames = { - 'dat': 'ctem.dat', - 'dem': 'surface_dem.dat', - 'diam': 'surface_diam.dat', - 'ejc': 'surface_ejc.dat', - 'pos': 'surface_pos.dat', - 'time': 'surface_time.dat', - 'stack': 'surface_stacknum.dat', - 'rego': 'surface_rego.dat', - 'melt': 'surface_melt.dat', - 'comp': 'surface_comp.dat', - 'age' : 'surface_age.dat', - 'ocum': 'ocumulative.dat', - 'odist': 'odistribution.dat', - 'pdist': 'pdistribution.dat', - 'tcum' : 'tcumulative.dat', - 'tdist' : 'tdistribution.dat', - 'impmass' : 'impactmass.dat', - 'fracdone' : 'fracdone.dat', - 'regodepth' : 'regolithdepth.dat', - 'ejmax' : 'ejecta_table_max.dat', - 'ejmin' : 'ejecta_table_min.dat', - 'testprof' : 'testprofile.dat', - 'craterscale' : 'craterscale.dat', - 'craterlist' : 'craterlist.dat', - 'sfdfile' : 'production.dat', - 'distfrac' : 'surface_distfrac.dat', - 'ejm' : 'surface_ejm.dat', - 'ejmf' : 'surface_ejmf.dat', - 'meltdist' : 'surface_meltdist.dat', - 'meltfrac' : 'surface_meltfrac.dat' - } - if self.user['sfdfile'] is not None: # Override the default sfdfile name if the user supplies an alternative - self.output_filenames['sfdfile'] = self.user['sfdfile'] - - for k, v in self.output_filenames.items(): - self.output_filenames[k] = os.path.join(currentdir, v) - - self.directories = ['dist', 'misc', 'surf'] - if self.user['saveshaded'].upper() == 'T': - self.directories.append('shaded') - if self.user['saverego'].upper() == 'T': - self.directories.append('rego') - - # Set up data arrays - self.seedarr = np.zeros(100, dtype=int) - self.seedarr[0] = self.user['seed'] - self.odist = np.zeros([1, 6]) - self.pdist = np.zeros([1, 6]) - self.tdist = np.zeros([1, 6]) - self.surface_dem = np.zeros([self.user['gridsize'], self.user['gridsize']], dtype=float) - self.surface_ejc = np.zeros([self.user['gridsize'], self.user['gridsize']], dtype=float) - self.ph1 = None - - if self.user['sfdcompare'] is not None: - # Read sfdcompare file - sfdfile = os.path.join(self.user['workingdir'], self.user['sfdcompare']) - self.ph1 = util.read_formatted_ascii(sfdfile, skip_lines=0) - - - # If this is a new simulation, run and post-process results. Otherwise, don't do anything more - if isnew: - # Starting new or old run? - if (self.user['restart'].upper() == 'F'): - print('Starting a new run') - - util.create_dir_structure(self.user, self.directories) - # Delete any old output files - for k, v in self.output_filenames.items(): - if os.path.isfile(v): - os.remove(v) - - # Scale the production function to the simulation domain - self.scale_production() - - # Setup Quasi-MC run - - if (self.user['quasimc'] == 'T'): - - #Read list of real craters - print("quasi-MC mode is ON") - print("Generating the crater scaling data in CTEM") - rclist = util.read_formatted_ascii(self.user['realcraterlist'], skip_lines = 0) - tempfile = os.path.join(currentdir, 'temp.in') - - # Generate craterlist.dat - shutil.copy2(self.user['ctemfile'], tempfile ) - - #Write a temporary input file to generate the necessary quasimc files - util.write_temp_input(self.user, tempfile) - util.write_datfile(self.user, self.output_filenames['dat'], self.seedarr) - self.compute_one_interval(ctemin=tempfile) - os.remove(tempfile) - - #Interpolate craterscale.dat to get impactor sizes from crater sizes given - df = pandas.read_csv(self.output_filenames['craterscale'], sep='\s+') - df['log(Dc)'] = np.log(df['Dcrat(m)']) - df['log(Di)'] = np.log(df['#Dimp(m)']) - xnew = df['log(Dc)'].values - ynew = df['log(Di)'].values - interp = interp1d(xnew, ynew, fill_value='extrapolate') - rclist[:,0] = np.exp(interp(np.log(rclist[:,0]))) - - #Convert age in Ga to "interval time" - if (self.user['runtype'].upper() == 'STATISTICAL'): - rclist[:,5] = (self.user['interval']) - craterproduction.Tscale(rclist[:,5], 'NPF_Moon') - else: - rclist[:,5] = (self.user['interval'] * self.user['numintervals']) - craterproduction.Tscale(rclist[:,5], 'NPF_Moon') - rclist = rclist[rclist[:,5].argsort()] - - #Export to dat file - util.write_realcraters(self.output_filenames['craterlist'], rclist) - - util.write_datfile(self.user, self.output_filenames['dat'], self.seedarr) - else: - print('Continuing a previous run') - self.read_output() - - return - - def scale_production(self): - """ - Scales the production function to the simulation domain and saves the scaled production function to a file that - will be read in by the main Fortran program. - """ - - # Read production function file - impfile = os.path.join(self.user['workingdir'], self.user['impfile']) - prodfunction = util.read_formatted_ascii(impfile, skip_lines=0) - - # Create impactor production population - area = (self.user['gridsize'] * self.user['pix']) ** 2 - self.production = np.copy(prodfunction) - self.production[:, 1] = self.production[:, 1] * area * self.user['interval'] - - # Write the scaled production function to file - util.write_production(self.output_filenames['sfdfile'], self.production) - - return - - def run(self): - """ - Runs a complete simulation over all intervals specified in the input user. This method loops over all - intervals and process outputs into images, and redirect output files to their apporpriate folders. - - This method replaces most of the functionality of the original ctem_driver.py - """ - - print('Beginning loops') - while (self.user['ncount'] <= self.user['numintervals']): - if (self.user['ncount'] > 0): - # Move ctem.dat - self.redirect_outputs(['dat'], 'misc') - - #Execute Fortran code - self.compute_one_interval(self.user['ctemfile']) - - # Read in output files - self.read_output() - - # Process the output files - self.process_output() - - # Update ncount - self.user['ncount'] = self.user['ncount'] + 1 - - if ((self.user['runtype'].upper() == 'STATISTICAL') or (self.user['ncount'] == 1)): # Reset the simulation - self.user['restart'] = 'F' - self.user['curyear'] = 0.0 - self.user['totalimpacts'] = 0 - self.user['masstot'] = 0.0 - - # Delete tdistribution file, if it exists so that we don't accumulate true craters in statistical mode - tdist_file = self.user['workingdir'] + 'tdistribution.dat' - if os.path.isfile(tdist_file): - os.remove(tdist_file) - - else: - self.user['restart'] = 'T' - - # Write ctem.dat file for next interval - util.write_datfile(self.user, self.output_filenames['dat'], self.seedarr) - - return - - def compute_one_interval(self, ctemin="ctem.in"): - """ - Executes the Fortran code to generate one interval of simulation output. - """ - # Create crater population and display CTEM progress on screen - print(self.user['ncount'], ' Calling FORTRAN routine') - try: - p = subprocess.Popen([os.path.join(self.user['workingdir'], self.ctem_executable), ctemin], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - universal_newlines=True, - shell=False) - for line in p.stdout: - if "%" in line: - print(line.replace('\n','\r'), end='') - else: - print(line,end='') - res = p.communicate() - if p.returncode != 0: - for line in res[1]: - print(line, end='') - raise Exception ("CTEM Failure") - except: - print("Error executing main CTEM program") - sys.exit() - - return - - def read_output(self): - """ - Reads in all of the files generated by the Fortran code after one interval and redirects them to appropriate - folders for storage after appending the interval number to the filename. - """ - # Read Fortran output - print(self.user['ncount'], ' Reading Fortran output') - - # Read surface dem(shaded relief) and ejecta data files - self.surface_dem = util.read_unformatted_binary(self.output_filenames['dem'], self.user['gridsize']) - self.surface_ejc = util.read_unformatted_binary(self.output_filenames['ejc'], self.user['gridsize']) - - # Read odistribution, tdistribution, and pdistribution files - self.odist = util.read_formatted_ascii(self.output_filenames['odist'], skip_lines=1) - self.tdist = util.read_formatted_ascii(self.output_filenames['tdist'], skip_lines=1) - self.pdist = util.read_formatted_ascii(self.output_filenames['pdist'], skip_lines=1) - - # Read impact mass from file - self.impact_mass = util.read_impact_mass(self.output_filenames['impmass']) - - # Read ctem.dat file - util.read_datfile(self.user, self.output_filenames['dat'], self.seedarr) - - - def process_output(self): - """ - Processes output to update masses, time, computes regolith depth, generates all plots, and redirects files - into intermediate storage. - """ - # Display results - print(self.user['ncount'], ' Generating surface images and plots') - - # Write surface dem, surface ejecta and shaded relief data - util.image_dem(self.user, self.surface_dem) - if (self.user['saverego'].upper() == 'T'): - util.image_regolith(self.user, self.surface_ejc) - if (self.user['saveshaded'].upper() == 'T'): - util.image_shaded_relief(self.user, self.surface_dem) - - if self.user['ncount'] > 0: # These aren't available yet from the initial conditions - - # Save copy of crater distribution files - # Update user: mass, curyear, regolith properties - self.user['masstot'] = self.user['masstot'] + self.impact_mass - - self.user['curyear'] = self.user['curyear'] + self.user['fracdone'] * self.user['interval'] - template = "%(fracdone)9.6f %(curyear)19.12E\n" - with open(self.output_filenames['fracdone'], 'w') as fp_frac: - fp_frac.write(template % self.user) - - reg_text = "%19.12E %19.12E %19.12E %19.12E\n" % (self.user['curyear'], - np.mean(self.surface_ejc), np.amax(self.surface_ejc), - np.amin(self.surface_ejc)) - with open(self.output_filenames['regodepth'], 'w') as fp_reg: - fp_reg.write(reg_text) - # Redirect output files to storage - self.redirect_outputs(['odist', 'ocum', 'pdist', 'tdist'], 'dist') - if (self.user['savetruelist'].upper() == 'T'): - self.redirect_outputs(['tcum'], 'dist') - self.redirect_outputs(['impmass'], 'misc') - if (self.user['saverego'].upper() == 'T') : - self.redirect_outputs(['stack','rego','age','melt','comp','ejm','meltdist'], 'rego') - - - - def redirect_outputs(self, filekeys, foldername): - """ - Copies a set of output files from the working directory into a subfolder. - Takes as input the dictionaries of user parameters and output file names, the dictionary keys to the file names - you wish to redirect, and the redirection destination folder name. The new name will be the key name + zero padded - interval number. - - Example: - calling redirect_outputs(['odist','tdist'], 'dist') when user['ncount'] is 1 - should do the following: - copy 'odistribution.dat' to 'dist/odist_000001.dat' - copy 'tdistribution.dat' to 'dist/tdist_000001.dat' - """ - - for k in filekeys: - forig = self.output_filenames[k] - fdest = os.path.join(self.user['workingdir'], foldername, f"{k}_{self.user['ncount']:06d}.dat") - shutil.copy2(forig, fdest) - - def cleanup(self): - """ - Deletes all files and folders generated by CTEM. - """ - # This is a list of files generated by the main Fortran program - print("Deleting all files generated by CTEM") - util.destroy_dir_structure(self.user, self.directories) - for key, filename in self.output_filenames.items(): - print(f"Deleting file {filename}") - try: - os.remove(filename) - except OSError as error: - print(error) - - return - -if __name__ == '__main__': - sim = Simulation() - sim.run() \ No newline at end of file diff --git a/ctem/ctem/util.py b/ctem/ctem/util.py deleted file mode 100644 index 00922421..00000000 --- a/ctem/ctem/util.py +++ /dev/null @@ -1,443 +0,0 @@ -import numpy as np -import os -import shutil -from matplotlib.colors import LightSource -import matplotlib.cm as cm -import matplotlib.pyplot as plt -import re -from tempfile import mkstemp -from scipy.io import FortranFile - -# Set pixel scaling common for image writing, at 1 pixel/ array element -dpi = 72.0 -class CTEMLightSource(LightSource): - """ - Override one function in LightSource to prevent the contrast from being rescaled. - """ - def shade_normals(self, normals, fraction=1.): - """ - Calculate the illumination intensity for the normal vectors of a - surface using the defined azimuth and elevation for the light source. - - Imagine an artificial sun placed at infinity in some azimuth and - elevation position illuminating our surface. The parts of the surface - that slope toward the sun should brighten while those sides facing away - should become darker. - - Changes by David Minton: The matplotlib version of this rescales the intensity - in a way that causes the brightness level of the images to change between - simulation outputs. This makes movies of the surface evolution appear to flicker. - - Parameters - ---------- - fraction : number, optional - Increases or decreases the contrast of the hillshade. Values - greater than one will cause intermediate values to move closer to - full illumination or shadow (and clipping any values that move - beyond 0 or 1). Note that this is not visually or mathematically - the same as vertical exaggeration. - - Returns - ------- - ndarray - A 2D array of illumination values between 0-1, where 0 is - completely in shadow and 1 is completely illuminated. - """ - - intensity = normals.dot(self.direction) - - # Apply contrast stretch - imin, imax = intensity.min(), intensity.max() - intensity *= fraction - - # Rescale to 0-1, keeping range before contrast stretch - # If constant slope, keep relative scaling (i.e. flat should be 0.5, - # fully occluded 0, etc.) - # if (imax - imin) > 1e-6: - # # Strictly speaking, this is incorrect. Negative values should be - # # clipped to 0 because they're fully occluded. However, rescaling - # # in this manner is consistent with the previous implementation and - # # visually appears better than a "hard" clip. - # intensity -= imin - # intensity /= (imax - imin) - intensity = np.clip(intensity, 0, 1) - - return intensity - - - -# These are directories that are created by CTEM in order to store intermediate results - -def create_dir_structure(user, directories): - """ - Create directories for various output files if they do not already exist - """ - - for dirname in directories: - dirpath = os.path.join(user['workingdir'], dirname) - if not os.path.isdir(dirpath): - print(f"Creating directory {dirpath}") - os.makedirs(dirpath) - - return - -def destroy_dir_structure(user, directories): - """ - Deletes directories generated by create_dir_structure - """ - for dirname in directories: - dirpath = os.path.join(user['workingdir'], dirname) - if os.path.isdir(dirpath): - print(f"Deleting directory {dirpath}") - shutil.rmtree(dirpath, ignore_errors=True) - - return - -def image_dem(user, DEM): - dpi = 300.0 # 72.0 - pix = user['pix'] - gridsize = user['gridsize'] - ve = 1.0 - azimuth = 300.0 # user['azimuth'] - solar_angle = 20.0 # user['solar_angle'] - - ls = CTEMLightSource(azdeg=azimuth, altdeg=solar_angle) - dem_img = ls.hillshade(np.flip(DEM,axis=0), vert_exag=ve, dx=pix, dy=pix, fraction=1) - - # Generate image to put into an array - height = gridsize / dpi - width = gridsize / dpi - fig = plt.figure(figsize=(width, height), dpi=dpi) - ax = plt.axes([0, 0, 1, 1]) - ax.imshow(dem_img, interpolation="nearest", cmap='gray', vmin=0.0, vmax=1.0) - plt.axis('off') - # Save image to file - filename = os.path.join(user['workingdir'],'surf',"surf%06d.png" % user['ncount']) - plt.savefig(filename, dpi=dpi, bbox_inches=0) - plt.close() - - return - - -def image_regolith(user, regolith): - # Create scaled regolith image - minref = user['pix'] * 1.0e-4 - maxreg = np.amax(regolith) - minreg = np.amin(regolith) - if (minreg < minref): minreg = minref - if (maxreg < minref): maxreg = (minref + 1.0e3) - regolith_scaled = np.copy(regolith) - np.place(regolith_scaled, regolith_scaled < minref, minref) - regolith_scaled = 254.0 * ( - (np.log(regolith_scaled) - np.log(minreg)) / (np.log(maxreg) - np.log(minreg))) - - # Save image to file - filename = os.path.join(user['workingdir'],'rego', "rego%06d.png" % user['ncount']) - height = user['gridsize'] / dpi - width = height - fig = plt.figure(figsize=(width, height), dpi=dpi) - fig.figimage(regolith_scaled, cmap=cm.nipy_spectral, origin='lower') - plt.savefig(filename) - plt.close() - - return - - -def image_shaded_relief(user, DEM): - dpi = 300.0 # 72.0 - pix = user['pix'] - gridsize = user['gridsize'] - ve = 1.0 - mode = 'overlay' - azimuth = 300.0 # user['azimuth'] - solar_angle = 20.0 # user['solar_angle'] - - ls = CTEMLightSource(azdeg=azimuth, altdeg=solar_angle) - cmap = cm.cividis - - # If min and max appear to be reversed, then fix them - if (user['shadedminh'] > user['shadedmaxh']): - temp = user['shadedminh'] - user['shadedminh'] = user['shadedmaxh'] - user['shadedmaxh'] = temp - else: - user['shadedminh'] = user['shadedminh'] - user['shadedmaxh'] = user['shadedmaxh'] - - # If no shadedmin/max user are read in from ctem.dat, determine the values from the data - if (user['shadedminhdefault'] == 1): - shadedminh = np.amin(DEM) - else: - shadedminh = user['shadedminh'] - if (user['shadedmaxhdefault'] == 1): - shadedmaxh = np.amax(DEM) - else: - shadedmaxh = user['shadedmaxh'] - - dem_img = ls.shade(np.flip(DEM,axis=0), cmap=cmap, blend_mode=mode, fraction=1.0, - vert_exag=ve, dx=pix, dy=pix, - vmin=shadedminh, vmax=shadedmaxh) - - # Generate image to put into an array - height = gridsize / dpi - width = gridsize / dpi - fig = plt.figure(figsize=(width, height), dpi=dpi) - ax = plt.axes([0, 0, 1, 1]) - ax.imshow(dem_img, interpolation="nearest", vmin=0.0, vmax=1.0) - plt.axis('off') - # Save image to file - filename = os.path.join(user['workingdir'],'shaded',"shaded%06d.png" % user['ncount']) - plt.savefig(filename, dpi=dpi, bbox_inches=0) - plt.close() - - return user - - -def read_datfile(user, datfile, seedarr): - # Read and parse ctem.dat file - - # Read ctem.dat file - print('Reading input file ' + datfile) - fp = open(datfile, 'r') - lines = fp.readlines() - fp.close() - - # Parse file lines and update parameter fields - fields = lines[0].split() - if len(fields) > 0: - user['totalimpacts'] = real2float(fields[0]) - user['ncount'] = int(fields[1]) - user['curyear'] = real2float(fields[2]) - user['restart'] = fields[3] - user['fracdone'] = real2float(fields[4]) - user['masstot'] = real2float(fields[5]) - - # Parse remainder of file to build seed array - nlines = len(lines) - index = 1 - while (index < nlines): - fields = lines[index].split() - seedarr[index - 1] = real2float(fields[0]) - index += 1 - - user['seedn'] = index - 1 - - return - - -def read_formatted_ascii(filename, skip_lines): - # Generalized ascii text reader - # For use with sfdcompare, production, odist, tdist, pdist data files - try: - data = np.genfromtxt(filename, skip_header=skip_lines) - except: - print(f"Error reading {filename}") - data = None - return data - - -def read_impact_mass(filename): - # Read impact mass file - - fp = open(filename, 'r') - line = fp.readlines() - fp.close() - - fields = line[0].split() - if (len(fields) > 0): - mass = real2float(fields[0]) - else: - mass = 0 - - return mass - - -# Write production function to file production.dat -# This file format does not exactly match that generated from IDL. Does it work? -def read_user_input(user): - # Read and parse ctem.in file - inputfile = user['ctemfile'] - - # Read ctem.in file - print('Reading input file ' + user['ctemfile']) - with open(inputfile, 'r') as fp: - lines = fp.readlines() - - # Process file text - for line in lines: - fields = line.split() - if len(fields) > 0: - if ('pix' == fields[0].lower()): user['pix'] = real2float(fields[1]) - if ('gridsize' == fields[0].lower()): user['gridsize'] = int(fields[1]) - if ('seed' == fields[0].lower()): user['seed'] = int(fields[1]) - if ('sfdfile' == fields[0].lower()): user['sfdfile'] = os.path.join(user['workingdir'],fields[1]) - if ('impfile' == fields[0].lower()): user['impfile'] = os.path.join(user['workingdir'],fields[1]) - if ('maxcrat' == fields[0].lower()): user['maxcrat'] = real2float(fields[1]) - if ('sfdcompare' == fields[0].lower()): user['sfdcompare'] = os.path.join(user['workingdir'], fields[1]) - if ('realcraterlist' == fields[0].lower()): user['realcraterlist'] = os.path.join(user['workingdir'], fields[1]) - if ('interval' == fields[0].lower()): user['interval'] = real2float(fields[1]) - if ('numintervals' == fields[0].lower()): user['numintervals'] = int(fields[1]) - if ('popupconsole' == fields[0].lower()): user['popupconsole'] = fields[1] - if ('saveshaded' == fields[0].lower()): user['saveshaded'] = fields[1] - if ('saverego' == fields[0].lower()): user['saverego'] = fields[1] - if ('savepres' == fields[0].lower()): user['savepres'] = fields[1] - if ('savetruelist' == fields[0].lower()): user['savetruelist'] = fields[1] - if ('runtype' == fields[0].lower()): user['runtype'] = fields[1] - if ('restart' == fields[0].lower()): user['restart'] = fields[1] - if ('quasimc' == fields[0].lower()): user['quasimc'] = fields[1] - if ('shadedminh' == fields[0].lower()): - user['shadedminh'] = real2float(fields[1]) - user['shadedminhdefault'] = 0 - if ('shadedmaxh' == fields[0].lower()): - user['shadedmaxh'] = real2float(fields[1]) - user['shadedmaxhdefault'] = 0 - - # Test values for further processing - if (user['interval'] <= 0.0): - print('Invalid value for or missing variable INTERVAL in ' + inputfile) - if (user['numintervals'] <= 0): - print('Invalid value for or missing variable NUMINTERVALS in ' + inputfile) - if (user['pix'] <= 0.0): - print('Invalid value for or missing variable PIX in ' + inputfile) - if (user['gridsize'] <= 0): - print('Invalid value for or missing variable GRIDSIZE in ' + inputfile) - if (user['seed'] == 0): - print('Invalid value for or missing variable SEED in ' + inputfile) - if (user['impfile'] is None): - print('Invalid value for or missing variable IMPFILE in ' + inputfile) - if (user['popupconsole'] is None): - print('Invalid value for or missing variable POPUPCONSOLE in ' + inputfile) - if (user['saveshaded'] is None): - print('Invalid value for or missing variable SAVESHADED in ' + inputfile) - if (user['saverego'] is None): - print('Invalid value for or missing variable SAVEREGO in ' + inputfile) - if (user['savepres'] is None): - print('Invalid value for or missing variable SAVEPRES in ' + inputfile) - if (user['savetruelist'] is None): - print('Invalid value for or missing variable SAVETRUELIST in ' + inputfile) - if (user['runtype'] is None): - print('Invalid value for or missing variable RUNTYPE in ' + inputfile) - if (user['restart'] is None): - print('Invalid value for or missing variable RESTART in ' + inputfile) - - return user - - -def read_unformatted_binary(filename, gridsize, kind='DP'): - # Read unformatted binary files created by Fortran - # For use with surface ejecta and surface dem data files - if kind == 'DP': - dt = np.dtype('f8') - elif kind == 'SP': - dt = np.dtype('f4') - elif kind == 'I4B': - dt = np.dtype(' count: - break - - fout.writelines(fin.readlines()) - - - fin.close() - fout.close() - - shutil.move(name, source) - - return - -def write_datfile(user, filename, seedarr): - # Write various user and random number seeds into ctem.dat file - fp = open(filename, 'w') - - template = "%(totalimpacts)17d %(ncount)12d %(curyear)19.12E %(restart)s %(fracdone)9.6f %(masstot)19.12E\n" - fp.write(template % user) - - # Write random number seeds to the file - for index in range(user['seedn']): - fp.write("%12d\n" % seedarr[index]) - - fp.close() - - return - - -def write_production(filename, production): - np.savetxt(filename, production, fmt='%1.8e', delimiter=' ') - - return - - -def write_realcraters(filename, realcraters): - """Writes file of real craters for use in quasi-MC runs""" - - np.savetxt(filename, realcraters, fmt='%1.8e', delimiter='\t') - - return - -def write_temp_input(user, filename): - """Makes changes to a temporary input file for use when generating craterlist.dat for quasimc runs""" - - sed('testflag', 'testflag T!', filename) - sed('testimp', f'testimp {user["pix"]*1e-3} !', filename) # Make a tiny test crater. We don't care about the crater itself, just that we run CTEM once to get all of the converted files - sed('quasimc', 'quasimc F!', filename) - sed('interval', 'interval 1 !', filename) - sed('numinterval 1 !s', 'numintervals 1 !', filename) - - return \ No newline at end of file diff --git a/ctem/ctem/viewer3d.py b/ctem/ctem/viewer3d.py deleted file mode 100644 index 8aacf84e..00000000 --- a/ctem/ctem/viewer3d.py +++ /dev/null @@ -1,124 +0,0 @@ -import numpy as np -import open3d -import ctem - -class Polysurface(ctem.Simulation): - """A model of a self-gravitating small body""" - def __init__(self): - ctem.Simulation.__init__(self, isnew=False) # Initialize the data structures, but doesn't start a new run - self.read_output() - #used for Open3d module - self.mesh = open3d.geometry.TriangleMesh() - return - - def ctem2blockmesh(self): - # Build mesh grid - s = self.user['gridsize'] - pix = self.user['pix'] - ygrid, xgrid = np.mgrid[-s/2:s/2, -s/2:s/2] * pix - y0, x0 = ygrid - pix/2, xgrid - pix/2 - y1, x1 = ygrid - pix/2, xgrid + pix/2 - y2, x2 = ygrid + pix/2, xgrid + pix/2 - y3, x3 = ygrid + pix/2, xgrid - pix/2 - - xvals = np.append( - np.append( - np.append(x0.flatten(), - x1.flatten()), - x2.flatten()), - x3.flatten()) - yvals = np.append( - np.append( - np.append(y0.flatten(), - y1.flatten()), - y2.flatten()), - y3.flatten()) - zvals = np.append( - np.append( - np.append(self.surface_dem.flatten(), - self.surface_dem.flatten()), - self.surface_dem.flatten()), - self.surface_dem.flatten()) - verts = np.array((xvals, yvals, zvals)).T - nface_triangles = 10 - faces = np.full([nface_triangles*s**2, 3], -1, dtype=np.int64) - for j in range(s): - for i in range(s): - i0 = s*j + i - i1 = i0 + s**2 - i2 = i1 + s**2 - i3 = i2 + s**2 - - fidx = np.arange(nface_triangles*i0,nface_triangles*(i0+1)) - # Make the two top triangles - faces[fidx[0],:] = [i0, i1, i2] - faces[fidx[1],:] = [i0, i2, i3] - # Make the two west side triangles - if i > 0: - faces[fidx[2],:] = [i0, i3, i2-1] - faces[fidx[3],:] = [i0, i2-1, i1-1] - # Make the two south side triangles - if j > 0: - faces[fidx[4],:] = [i1, i0, i3-s ] - faces[fidx[5],:] = [i1, i3-s, i2-s] - # Make the two east side triangles - if i < (s - 1): - faces[fidx[6],:] = [i2, i1, i0+1] - faces[fidx[7],:] = [i2, i0+1, i3+1] - #Make the two north side triangles - if j < (s -1): - faces[fidx[8],:] = [i3, i2, i1+s] - faces[fidx[9],:] = [i3, i1+s, i0+s] - nz = faces[:,0] != -1 - f2 = faces[nz,:] - self.mesh.vertices = open3d.utility.Vector3dVector(verts) - self.mesh.triangles = open3d.utility.Vector3iVector(f2) - self.mesh.compute_vertex_normals() - self.mesh.compute_triangle_normals() - - return - - def ctem2trimesh(self): - # Build mesh grid - s = self.user['gridsize'] - pix = self.user['pix'] - ygrid, xgrid = np.mgrid[-s/2:s/2, -s/2:s/2] * pix - - xvals = xgrid.flatten() - yvals = ygrid.flatten() - zvals = self.surface_dem.flatten() - verts = np.array((xvals, yvals, zvals)).T - faces = np.full([2 * (s-1)**2, 3], -1, dtype=np.int64) - for j in range(s - 1): - for i in range(s - 1): - idx = (s - 1) * j + i - faces[idx, :] = [j * s + i, j * s + i + 1, (j + 1) * s + i + 1] - idx += (s - 1) ** 2 - faces[idx, :] = [(j + 1) * s + i + 1, (j + 1) * s + i, j * s + i ] - self.mesh.vertices = open3d.utility.Vector3dVector(verts) - self.mesh.triangles = open3d.utility.Vector3iVector(faces) - self.mesh.compute_vertex_normals() - self.mesh.compute_triangle_normals() - - return - - def visualize(self): - vis = open3d.visualization.Visualizer() - vis.create_window() - vis.add_geometry(self.mesh) - opt = vis.get_render_option() - opt.background_color = np.asarray([0, 0, 0]) - - self.mesh.paint_uniform_color([0.5, 0.5, 0.5]) - vis.run() - vis.destroy_window() - - -if __name__ == '__main__': - sim = Polysurface() - sim.surface_dem *= 10 - sim.ctem2trimesh() - sim.visualize() - - - diff --git a/ctem/setup.py b/ctem/setup.py deleted file mode 100644 index f7003601..00000000 --- a/ctem/setup.py +++ /dev/null @@ -1,6 +0,0 @@ -from setuptools import setup, find_packages - -setup(name='ctem', - version='0.1', - author='David A. Minton', - packages=find_packages()) diff --git a/src/crater/crater_subpixel_diffusion.f90 b/src/crater/crater_subpixel_diffusion.f90 index cdba3408..63a69bfe 100644 --- a/src/crater/crater_subpixel_diffusion.f90 +++ b/src/crater/crater_subpixel_diffusion.f90 @@ -59,9 +59,6 @@ subroutine crater_subpixel_diffusion(user,surf,nflux,domain,finterval,kdiffin) real(DP) :: rayfmult = (5)**(-4.0_DP / (1.2_DP)) real(DP) :: l1 - rray = 11.95*crater%frad**1.32 - l1 = 5.32*crater%frad**1.27 - ! Create box for soften calculation (will be no bigger than the grid itself) do j = 0,user%gridsize + 1 do i = 0,user%gridsize + 1 @@ -187,7 +184,10 @@ subroutine crater_subpixel_diffusion(user,surf,nflux,domain,finterval,kdiffin) allocate(diffdistribution(imin:imax,jmin:jmax)) allocate(ejdistribution(imin:imax,jmin:jmax)) - call ejecta_ray_pattern(user,surf,crater,inc,xi,xf,yi,yf,rray,Nraymax,fpeak,rayp,rayq,rayfmult,diffdistribution,ejdistribution,l1) + rray = 11.95_DP*crater%frad**1.32 + l1 = 5.32_DP*crater%frad**1.27 + + call ejecta_ray_pattern(user,surf,crater,inc,imin,imax,jmin,jmax,rray,Nraymax,fpeak,rayp,rayq,rayfmult,diffdistribution,ejdistribution,l1) ! Loop over affected matrix area !!$OMP PARALLEL DO DEFAULT(SHARED) IF(inc > INCPAR) & !!$OMP FIRSTPRIVATE(jmin,jmax,imin,imax) & diff --git a/src/ejecta/ejecta_emplace.f90 b/src/ejecta/ejecta_emplace.f90 index 5e6de56c..9cc16e41 100644 --- a/src/ejecta/ejecta_emplace.f90 +++ b/src/ejecta/ejecta_emplace.f90 @@ -254,7 +254,9 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ klo = int((log(lrad) - log(crater%ejrad)) / domain%ejbres) do n = 1,MAXLOOP call ejecta_interpolate(crater,domain,distance,ejb,ejtble,ebh,vsq=vsq,theta=ejtheta,erad=erad,melt=melt) - if ((n > 1).and.((abs(ebh0 - ebh) / ebh0) < domain%small)) exit + if (n > 1) then + if ((abs(ebh0 - ebh) / ebh0) < domain%small) exit + endif ebh0 = ebh erad = exp(erad) diff --git a/src/init/init_dist.f90 b/src/init/init_dist.f90 index fc17a1bd..72e96af5 100644 --- a/src/init/init_dist.f90 +++ b/src/init/init_dist.f90 @@ -33,7 +33,7 @@ subroutine init_dist(user,domain) ! Executable code ! Get size of crater production function array - open(unit=LUN,file=user%sfdfile,status="old",iostat=ierr) + open(unit=LUN,file=trim(adjustl(user%sfdfile)),status="old",iostat=ierr) if (ierr /= 0) then write(*,*) "Unable to open file ", trim(user%sfdfile) stop @@ -47,12 +47,12 @@ subroutine init_dist(user,domain) end do if (domain%pnum == 0) then - write(*,*) "No valid entries in ",trim(user%sfdfile) + write(*,*) "No valid entries in ",trim(adjustl(user%sfdfile)) end if close(LUN) ! Get size of velocity distribution array - open(unit=LUN,file=user%velfile,status="old",iostat=ierr) + open(unit=LUN,file=trim(adjustl(user%velfile)),status="old",iostat=ierr) if (ierr /= 0) then write(*,*) "Unable to open file ",trim(user%velfile) stop @@ -65,15 +65,15 @@ subroutine init_dist(user,domain) domain%vnum = domain%vnum + 1 end do if (domain%vnum == 0) then - write(*,*) "No valid entries in ",trim(user%velfile) + write(*,*) "No valid entries in ",trim(adjustl(user%velfile)) end if close(LUN) ! Get size of real crater list array if (user%doquasimc) then - open(unit=LUN,file=rcfile,status="old",iostat=ierr) + open(unit=LUN,file=trim(adjustl(rcfile)),status="old",iostat=ierr) if (ierr /= 0) then - write(*,*) "Unable to open file ", trim(rcfile) + write(*,*) "Unable to open file ", trim(adjustl(rcfile)) stop end if diff --git a/src/io/io_ejecta_table.f90 b/src/io/io_ejecta_table.f90 index f5e1287a..342af640 100644 --- a/src/io/io_ejecta_table.f90 +++ b/src/io/io_ejecta_table.f90 @@ -35,7 +35,7 @@ subroutine io_ejecta_table(crater,domain,ejb,ejtble,filename) integer(I4B) :: k ! Executable code - open(LUN, FILE=filename, status='replace') + open(LUN, FILE=trim(adjustl(filename)), status='replace') write(LUN,'("# trad = ",ES12.5, " frad = ",ES12.5)') crater%rad,crater%frad write(LUN,'("# ejrim = ",ES12.5, " ejdis = ",ES12.5," imp = ",ES12.5)') crater%ejrim,crater%ejdis,crater%imp write(LUN,'(A63)') '# "r (m)" "h (m)" "v (m/s)" "ang (deg)" "erad (m)"' diff --git a/src/io/io_input.f90 b/src/io/io_input.f90 index b89b2612..4a528246 100644 --- a/src/io/io_input.f90 +++ b/src/io/io_input.f90 @@ -97,7 +97,7 @@ subroutine io_input(infile,user) user%dotopodiffusion = .true. write(user%sfdfile,*) trim(adjustl(SFDFILE)) - open(unit=LUN,file=infile,status="old",iostat=ierr) + open(unit=LUN,file=trim(adjustl(infile)),status="old",iostat=ierr) if (ierr /= 0) then write(*,*) "Unable to open file ",trim(infile) stop diff --git a/src/io/io_read_craterlist.f90 b/src/io/io_read_craterlist.f90 index ec17ff58..35b4e38d 100644 --- a/src/io/io_read_craterlist.f90 +++ b/src/io/io_read_craterlist.f90 @@ -35,16 +35,16 @@ subroutine io_read_craterlist(rclist, user, domain) ! Read the next crater from the craterlist - open(unit=LUN,file=rcfile,status='old',iostat=ierr) + open(unit=LUN,file=trim(adjustl(rcfile)),status='old',iostat=ierr) if (ierr /= 0) then - write(*,*) "Unable to open file ",trim(rcfile) + write(*,*) "Unable to open file ",trim(adjustl(rcfile)) stop end if do i=1,domain%rcnum read(LUN,*,iostat=ierr) rclist(1:6,i) if (ierr/=0) then - write(*,*) "Unable to read file ",trim(rcfile) + write(*,*) "Unable to read file ",trim(adjustl(rcfile)) stop end if end do diff --git a/src/io/io_read_prod.f90 b/src/io/io_read_prod.f90 index 2eb47516..8a845980 100644 --- a/src/io/io_read_prod.f90 +++ b/src/io/io_read_prod.f90 @@ -35,7 +35,7 @@ subroutine io_read_prod(prod,user,domain) ! Executable code ! Read in the size-frequency distribution file - open(unit=LUN,file=user%sfdfile,status='old',iostat=ierr) + open(unit=LUN,file=trim(adjustl(user%sfdfile)),status='old',iostat=ierr) if (ierr /= 0) then write(*,*) "Unable to open file ",trim(user%sfdfile) stop diff --git a/src/io/io_read_vdist.f90 b/src/io/io_read_vdist.f90 index a15dc8dd..84309feb 100644 --- a/src/io/io_read_vdist.f90 +++ b/src/io/io_read_vdist.f90 @@ -35,16 +35,16 @@ subroutine io_read_vdist(vdist,user,domain) ! Executable code ! Read in velocity distribution file - open(unit=LUN,file=user%velfile,status='old',iostat=ierr) + open(unit=LUN,file=trim(adjustl(user%velfile)),status='old',iostat=ierr) if (ierr /= 0) then - write(*,*) "Unable to open file ",trim(user%velfile) + write(*,*) "Unable to open file ",trim(adjustl(user%velfile)) stop end if do i=1,domain%vnum read(LUN,*,iostat=ierr) vdist(1:3,i) if (ierr/=0) then - write(*,*) "Unable to read file ",trim(user%velfile) + write(*,*) "Unable to read file ",trim(adjustl(user%velfile)) stop end if end do From dfbe54f3a3d9505f49d3cb5f68fda32f1e1c45c4 Mon Sep 17 00:00:00 2001 From: David Minton Date: Sun, 11 Feb 2024 10:52:50 -0500 Subject: [PATCH 28/42] Put the ejecta table values in logspace and fixed bugs due to trying to compute melt values when doregotrack was .false. --- src/crater/crater_populate.f90 | 2 -- src/ejecta/ejecta_emplace.f90 | 17 +++++++++++------ src/ejecta/ejecta_interpolate.f90 | 15 +++++++++++++-- src/ejecta/ejecta_table_define.f90 | 6 +++--- src/globals/module_globals.f90 | 2 +- src/io/io_ejecta_table.f90 | 2 +- src/regolith/regolith_melt_fraction.f90 | 6 ++++++ 7 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/crater/crater_populate.f90 b/src/crater/crater_populate.f90 index 59c6e20e..eb858938 100644 --- a/src/crater/crater_populate.f90 +++ b/src/crater/crater_populate.f90 @@ -315,10 +315,8 @@ subroutine crater_populate(user,surf,crater,domain,prod,production_list,vdist,nt if (crater%ejdis > domain%smallest_ejecta) then ! Estimated size is big enough, so proceed with precise calculation if (user%doregotrack) then call ejecta_table_define(user,crater,domain,ejb,ejtble,melt) - !call ejecta_interpolate(crater,domain,crater%frad,ejb(1:ejtble),ejtble,crater%ejrim) else call ejecta_table_define(user,crater,domain,ejb,ejtble) - !call ejecta_interpolate(crater,domain,crater%frad,ejb(1:ejtble),ejtble,crater%ejrim) end if call ejecta_emplace(user,surf,crater,domain,ejb(1:ejtble),ejtble,ejbmass,& ejecta_dem,nmeltsheet,vmeltsheet) diff --git a/src/ejecta/ejecta_emplace.f90 b/src/ejecta/ejecta_emplace.f90 index 9cc16e41..b6ec3381 100644 --- a/src/ejecta/ejecta_emplace.f90 +++ b/src/ejecta/ejecta_emplace.f90 @@ -253,13 +253,16 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ maxslp = -huge(maxslp) klo = int((log(lrad) - log(crater%ejrad)) / domain%ejbres) do n = 1,MAXLOOP - call ejecta_interpolate(crater,domain,distance,ejb,ejtble,ebh,vsq=vsq,theta=ejtheta,erad=erad,melt=melt) + if (user%doregotrack) then + call ejecta_interpolate(crater,domain,distance,ejb,ejtble,ebh,vsq=vsq,theta=ejtheta,erad=erad,melt=melt) + else + call ejecta_interpolate(crater,domain,distance,ejb,ejtble,ebh,vsq=vsq,theta=ejtheta,erad=erad) + end if if (n > 1) then if ((abs(ebh0 - ebh) / ebh0) < domain%small) exit endif ebh0 = ebh - erad = exp(erad) lrange = lrad - erad baseline = ((i * crater%xslp) + (j * crater%yslp)) * user%pix @@ -378,10 +381,12 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ end do end if - if (totmelt > vmelt) then - vmeltsheet = totmelt - vmelt - else !give the craters a melt sheet of 1m - vmeltsheet = 1.0_DP * user%pix * user%pix * nmeltsheet + if (user%doregotrack) then + if (totmelt > vmelt) then + vmeltsheet = totmelt - vmelt + else !give the craters a melt sheet of 1m + vmeltsheet = 1.0_DP * user%pix * user%pix * nmeltsheet + end if end if ! Create box for soften calculation (will be no bigger than the grid itself) diff --git a/src/ejecta/ejecta_interpolate.f90 b/src/ejecta/ejecta_interpolate.f90 index c71d50a0..3463c08e 100644 --- a/src/ejecta/ejecta_interpolate.f90 +++ b/src/ejecta/ejecta_interpolate.f90 @@ -70,8 +70,19 @@ subroutine ejecta_interpolate(crater,domain,lrad,ejb,ejtble,ebh,vsq,theta,erad,m if (present(erad)) erad = ejb(k)%erad - ((ejb(k)%erad - ejb(k+1)%erad) * frac) end if ebh = exp(ebh) - if (lrad > crater%ejdis) ebh = 0._DP - + if (lrad > crater%ejdis) then + ebh = 0._DP + if (present(vsq)) vsq = 0._DP + if (present(theta)) theta = 0._DP + if (present(melt)) melt = 0._DP + if (present(erad)) erad = 0._DP + else + if (present(vsq)) vsq = exp(vsq) + if (present(theta)) theta = exp(theta) + if (present(melt)) melt = exp(melt) + if (present(erad)) erad = exp(erad) + end if + return end subroutine ejecta_interpolate diff --git a/src/ejecta/ejecta_table_define.f90 b/src/ejecta/ejecta_table_define.f90 index cf259e2d..408d9c7e 100644 --- a/src/ejecta/ejecta_table_define.f90 +++ b/src/ejecta/ejecta_table_define.f90 @@ -80,12 +80,12 @@ subroutine ejecta_table_define(user,crater,domain,ejb,ejtble,melt) thick = max(crater_profile(user,crater,r),VSMALL) end if ejb(k)%thick = log(thick) - ejb(k)%vesq = vejsq - ejb(k)%angle = ejang + ejb(k)%vesq = log(vejsq) + ejb(k)%angle = log(ejang) ejb(k)%erad = log(erad) if (present(melt)) then call regolith_melt_fraction(dimp,depthb,erad,eradold,rmelt,melt) - ejb(k)%meltfrac = melt + ejb(k)%meltfrac = log(melt) end if if ((thick <= VSMALL) .or. (abs(eradold - erad) < VSMALL)) then ejtble = k diff --git a/src/globals/module_globals.f90 b/src/globals/module_globals.f90 index 157e1609..a1d38273 100644 --- a/src/globals/module_globals.f90 +++ b/src/globals/module_globals.f90 @@ -45,7 +45,7 @@ module module_globals integer(I4B), parameter :: UPPERCASE_OFFSET = iachar('A') - iachar('a') ! Miscellaneous constants: -real(DP),parameter :: VSMALL = tiny(1._DP) ! Very small number +real(DP),parameter :: VSMALL = 10*tiny(1._DP) ! Very small number real(DP),parameter :: LOGVSMALL = log(VSMALL) ! log of a very small number real(DP),parameter :: VBIG = huge(1._DP) ! Very big number real(DP),parameter :: SMALLFAC = 1e-5_DP ! Smallest unit of measurement proportional to pixel size diff --git a/src/io/io_ejecta_table.f90 b/src/io/io_ejecta_table.f90 index 342af640..f2f178a0 100644 --- a/src/io/io_ejecta_table.f90 +++ b/src/io/io_ejecta_table.f90 @@ -40,7 +40,7 @@ subroutine io_ejecta_table(crater,domain,ejb,ejtble,filename) write(LUN,'("# ejrim = ",ES12.5, " ejdis = ",ES12.5," imp = ",ES12.5)') crater%ejrim,crater%ejdis,crater%imp write(LUN,'(A63)') '# "r (m)" "h (m)" "v (m/s)" "ang (deg)" "erad (m)"' do k=1,ejtble - write(LUN,'(5(ES13.5E3,1X))') exp(ejb(k)%lrad),exp(ejb(k)%thick),sqrt(ejb(k)%vesq),ejb(k)%angle/DEG2RAD, & + write(LUN,'(5(ES13.5E3,1X))') exp(ejb(k)%lrad),exp(ejb(k)%thick),sqrt(exp(ejb(k)%vesq)),exp(ejb(k)%angle)/DEG2RAD, & exp(ejb(k)%erad) end do close(LUN) diff --git a/src/regolith/regolith_melt_fraction.f90 b/src/regolith/regolith_melt_fraction.f90 index 4886d9fc..01dac4ac 100755 --- a/src/regolith/regolith_melt_fraction.f90 +++ b/src/regolith/regolith_melt_fraction.f90 @@ -102,5 +102,11 @@ subroutine regolith_melt_fraction(dimp,depthb,erad1,erad2,rmelt,meltfrac) write(*,*) 'regolith_melt_fraction: this is a bug!' end if + if (meltfrac < epsilon(1.0_DP)) then + meltfrac = 0.0_DP + else if (meltfrac > 1.0_DP) then + meltfrac = 1.0_DP + end if + return end subroutine regolith_melt_fraction From db513e0885a5b9a0ec7cd5f04a2afbd82d5d527e Mon Sep 17 00:00:00 2001 From: David Minton Date: Sun, 11 Feb 2024 12:38:00 -0500 Subject: [PATCH 29/42] Changed do concurrent to regular do because of a complex data structure that is incompatible with optimized ifx --- src/init/init_regolith_stack.f90 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/init/init_regolith_stack.f90 b/src/init/init_regolith_stack.f90 index 7115a63c..3538909f 100644 --- a/src/init/init_regolith_stack.f90 +++ b/src/init/init_regolith_stack.f90 @@ -37,9 +37,10 @@ subroutine init_regolith_stack(user,surf,domain) !======================================= ! Initialize the grid space !======================================= - - do concurrent(xp=1:user%gridsize,yp=1:user%gridsize) - call util_init_array(user,surf(xp,yp)%regolayer,domain,initstat) + do yp=1,user%gridsize + do xp=1,user%gridsize + call util_init_array(user,surf(xp,yp)%regolayer,domain,initstat) + end do end do return From ab4551fe28947c2521859d1be785748ebdf07893 Mon Sep 17 00:00:00 2001 From: David Minton Date: Sun, 11 Feb 2024 12:42:02 -0500 Subject: [PATCH 30/42] Updated flags to be ifx compatible --- cmake/Modules/SetFortranFlags.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/Modules/SetFortranFlags.cmake b/cmake/Modules/SetFortranFlags.cmake index f42d8d75..585e7e3c 100644 --- a/cmake/Modules/SetFortranFlags.cmake +++ b/cmake/Modules/SetFortranFlags.cmake @@ -671,11 +671,11 @@ IF (CMAKE_BUILD_TYPE STREQUAL "PROFILE") # Enables the optimization reports to be generated IF (WINOPT) SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_PROFILE "${CMAKE_Fortran_FLAGS_RELEASE}" - Fortran "/O2 /Qopt-report:5 /traceback /Z7" # Intel Windows + Fortran "/O2 /Qopt-report:3 /traceback /Z7" # Intel Windows ) ELSE () SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_PROFILE "${CMAKE_Fortran_FLAGS_RELEASE}" - Fortran "-O2 -pg -qopt-report=5 -traceback -p -g3" # Intel + Fortran "-O2 -pg -qopt-report=3 -traceback -p -g3" # Intel ) ENDIF () ELSEIF (COMPILER_OPTIONS STREQUAL "GNU") From 56054d90c3920afcf8ebd3ab7135031ea6982869 Mon Sep 17 00:00:00 2001 From: David Minton Date: Sun, 11 Feb 2024 14:11:47 -0500 Subject: [PATCH 31/42] Fixed bugs that occur when ejecta thickness is near 0 --- src/ejecta/ejecta_emplace.f90 | 1 + src/ejecta/ejecta_interpolate.f90 | 38 +++++++++++++++++++++++++++---- src/util/util_sort_layer.f90 | 2 +- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/ejecta/ejecta_emplace.f90 b/src/ejecta/ejecta_emplace.f90 index b6ec3381..fda8c4b4 100644 --- a/src/ejecta/ejecta_emplace.f90 +++ b/src/ejecta/ejecta_emplace.f90 @@ -258,6 +258,7 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ else call ejecta_interpolate(crater,domain,distance,ejb,ejtble,ebh,vsq=vsq,theta=ejtheta,erad=erad) end if + if (ebh < VSMALL) exit if (n > 1) then if ((abs(ebh0 - ebh) / ebh0) < domain%small) exit endif diff --git a/src/ejecta/ejecta_interpolate.f90 b/src/ejecta/ejecta_interpolate.f90 index 3463c08e..1b181ee2 100644 --- a/src/ejecta/ejecta_interpolate.f90 +++ b/src/ejecta/ejecta_interpolate.f90 @@ -69,7 +69,11 @@ subroutine ejecta_interpolate(crater,domain,lrad,ejb,ejtble,ebh,vsq,theta,erad,m if (present(melt)) melt = ejb(k)%meltfrac - ((ejb(k)%meltfrac - ejb(k+1)%meltfrac) * frac) if (present(erad)) erad = ejb(k)%erad - ((ejb(k)%erad - ejb(k+1)%erad) * frac) end if - ebh = exp(ebh) + if (ebh < LOGVSMALL) then + ebh = 0.0_DP + else + ebh = exp(ebh) + end if if (lrad > crater%ejdis) then ebh = 0._DP if (present(vsq)) vsq = 0._DP @@ -77,10 +81,34 @@ subroutine ejecta_interpolate(crater,domain,lrad,ejb,ejtble,ebh,vsq,theta,erad,m if (present(melt)) melt = 0._DP if (present(erad)) erad = 0._DP else - if (present(vsq)) vsq = exp(vsq) - if (present(theta)) theta = exp(theta) - if (present(melt)) melt = exp(melt) - if (present(erad)) erad = exp(erad) + if (present(vsq)) then + if (vsq < LOGVSMALL) then + vsq = 0.0_DP + else + vsq = exp(vsq) + end if + end if + if (present(theta)) then + if (theta < LOGVSMALL) then + theta = 0.0_DP + else + theta = exp(theta) + end if + end if + if (present(melt)) then + if (melt < LOGVSMALL) then + melt = 0.0_DP + else + melt = exp(melt) + end if + end if + if (present(erad)) then + if (erad < LOGVSMALL) then + erad = 0.0_DP + else + erad = exp(erad) + end if + end if end if return diff --git a/src/util/util_sort_layer.f90 b/src/util/util_sort_layer.f90 index c3d055b1..65cd70d0 100644 --- a/src/util/util_sort_layer.f90 +++ b/src/util/util_sort_layer.f90 @@ -57,7 +57,7 @@ subroutine util_sort_layer(user,surf,crater) temptime = surf(mx,my)%timestamp(1:user%numlayers) ! Sort the layers by crater diameter - call util_mrgrnk(surf(mx,my)%diam(1:user%numlayers),ind) + call util_mrgrnk(tempdiam,ind) do k=1,user%numlayers surf(mx,my)%diam(k)=tempdiam(ind(k)) From b0e64a2452ac1a9a91fe201efdf6f512f1df6c51 Mon Sep 17 00:00:00 2001 From: David Minton Date: Sun, 11 Feb 2024 14:52:56 -0500 Subject: [PATCH 32/42] Fixed bugs arising from not converting the logspace values in the ejecta table to real space. --- src/ejecta/ejecta_emplace.f90 | 4 ++-- src/regolith/regolith_streamtube.f90 | 2 +- src/regolith/regolith_transport.f90 | 5 +++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/ejecta/ejecta_emplace.f90 b/src/ejecta/ejecta_emplace.f90 index fda8c4b4..476d6b82 100644 --- a/src/ejecta/ejecta_emplace.f90 +++ b/src/ejecta/ejecta_emplace.f90 @@ -282,10 +282,10 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ ! Find out where in the table this new velocity corresponds to ind = 1 - call util_search(ejb%vesq,ind,ejtble,vsq,klo) + call util_search(ejb%vesq,ind,ejtble,log(vsq),klo) klo = min(max(klo,1),ejtble-1) ! Interpolate on the table to find the flat plane equivalent landing distance for this velocity - frac = (vsq - ejb(klo)%vesq) / (ejb(klo+1)%vesq - ejb(klo)%vesq) + frac = (vsq - exp(ejb(klo)%vesq)) / (exp(ejb(klo+1)%vesq) - exp(ejb(klo)%vesq)) distance = exp(ejb(klo)%lrad) + frac * (exp(ejb(klo+1)%lrad) - exp(ejb(klo)%lrad)) end do diff --git a/src/regolith/regolith_streamtube.f90 b/src/regolith/regolith_streamtube.f90 index 16389a23..e6d04702 100644 --- a/src/regolith/regolith_streamtube.f90 +++ b/src/regolith/regolith_streamtube.f90 @@ -154,7 +154,7 @@ subroutine regolith_streamtube(user,surf,crater,domain,ejb,ejtble,xp,yp,xpi,ypi, end if if (eradc<=0.0_DP) then - write(*,*) k,ebh,crater%ejdis,lrad,exp(ejb(k-1)%lrad),exp(ejb(k)%lrad),eradc,ejb(k-1)%erad,ejb(k)%erad + write(*,*) k,ebh,crater%ejdis,lrad,exp(ejb(k-1)%lrad),exp(ejb(k)%lrad),eradc,exp(ejb(k-1)%erad),exp(ejb(k)%erad) stop end if diff --git a/src/regolith/regolith_transport.f90 b/src/regolith/regolith_transport.f90 index 01ca20a1..ca832102 100644 --- a/src/regolith/regolith_transport.f90 +++ b/src/regolith/regolith_transport.f90 @@ -63,6 +63,11 @@ subroutine regolith_transport(user,surfi,crater,domain,ejb,ejtble,lrad,ebh,newla frac = (loglrad - logtablerad) / logdelta melt = ejb(k)%meltfrac - ((ejb(k)%meltfrac - ejb(k+1)%meltfrac) * frac) end if + if (melt < LOGVSMALL) then + melt = 0.0_DP + else + melt = exp(melt) + end if newlayer%meltvolume = melt * newlayer%totvolume From c143ab0fd47281098c9dc26f45f297da6b0244de Mon Sep 17 00:00:00 2001 From: David A Minton Date: Tue, 20 Feb 2024 14:39:01 -0500 Subject: [PATCH 33/42] Updated the build process so that the CTEM executable gets installed into the environment's bin folder --- CMakeLists.txt | 43 ++++++++++++++++++++++-------------- ctem/driver.py | 12 ++++------ examples/quasimc-global/CTEM | 1 - src/CMakeLists.txt | 8 +++---- 4 files changed, 35 insertions(+), 29 deletions(-) delete mode 120000 examples/quasimc-global/CTEM diff --git a/CMakeLists.txt b/CMakeLists.txt index eb4fdb32..ea1ab76f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,11 +11,12 @@ ################################################## # Define the project and the depencies that it has ################################################## -CMAKE_MINIMUM_REQUIRED(VERSION 3.6.0...3.27.1) +CMAKE_MINIMUM_REQUIRED(VERSION 3.24.0...3.27.1) +SET(SKBUILD_PROJECT_NAME "ctem" CACHE STRING "Name of project set by scikit-build") # Get version stored in text file FILE(READ "version.txt" VERSION) -PROJECT(CTEM LANGUAGES C Fortran VERSION ${VERSION}) +PROJECT(${SKBUILD_PROJECT_NAME} LANGUAGES C Fortran VERSION ${VERSION}) IF (CMAKE_Fortran_COMPILER_ID MATCHES "^Intel") SET(COMPILER_OPTIONS "Intel" CACHE STRING "Compiler identified as Intel") @@ -39,30 +40,40 @@ ENDIF() # Ensure scikit-build modules FIND_PACKAGE(Python COMPONENTS Interpreter Development.Module REQUIRED) -# Add our local modules to the module path -FILE(TO_CMAKE_PATH "${CMAKE_SOURCE_DIR}/cmake/Modules" LOCAL_MODULE_PATH) -LIST(APPEND CMAKE_MODULE_PATH ${LOCAL_MODULE_PATH}) - # Define some directories that are important to the build SET(SRC "${CMAKE_SOURCE_DIR}/src") -SET(LIB "${CMAKE_SOURCE_DIR}/lib") -SET(BIN "${CMAKE_SOURCE_DIR}/bin") -SET(MOD "${CMAKE_SOURCE_DIR}/include") SET(PY "${CMAKE_SOURCE_DIR}/ctem") # Make sure paths are correct for Unix or Windows style FILE(TO_CMAKE_PATH ${SRC} SRC) -FILE(TO_CMAKE_PATH ${LIB} LIB) -FILE(TO_CMAKE_PATH ${BIN} BIN) -FILE(TO_CMAKE_PATH ${MOD} MOD) FILE(TO_CMAKE_PATH ${PY} PY) -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIB}) -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIB}) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BIN}) +INCLUDE(GNUInstallDirs) +IF (SKBUILD) + SET(INSTALL_BINDIR ${SKBUILD_SCRIPTS_DIR}) + SET(INSTALL_LIBDIR ${SKBUILD_DATA_DIR}/lib) + SET(INSTALL_INCLUDEDIR ${SKBUILD_HEADERS_DIR}) + SET(INSTALL_PYPROJ ${SKBUILD_PLATLIB_DIR}/${SKBUILD_PROJECT_NAME}) + IF (APPLE) + SET(CMAKE_INSTALL_RPATH "@loader_path;${CMAKE_BINARY_DIR}/bin") + ELSEIF (LINUX) + SET(CMAKE_INSTALL_RPATH "@ORIGIN;${CMAKE_BINARY_DIR}/bin") + ENDIF () +ELSE () + SET(INSTALL_PYPROJ ${PY}) + SET(INSTALL_BINDIR ${CMAKE_INSTALL_BINDIR}) + SET(INSTALL_LIBDIR ${CMAKE_INSTALL_LIBDIR}) + SET(INSTALL_INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR}) +ENDIF () + +SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) # Have the .mod files placed in the lib folder -SET(CMAKE_Fortran_MODULE_DIRECTORY ${MOD}) +SET(CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/mod) + +# Add our local modules to the module path +FILE(TO_CMAKE_PATH "${CMAKE_SOURCE_DIR}/cmake/Modules" LOCAL_MODULE_PATH) +LIST(APPEND CMAKE_MODULE_PATH ${LOCAL_MODULE_PATH}) # Set the name of the ctem library SET(CTEM_LIBRARY ctem) diff --git a/ctem/driver.py b/ctem/driver.py index 2646d1db..661d18c8 100644 --- a/ctem/driver.py +++ b/ctem/driver.py @@ -52,14 +52,10 @@ def __init__(self, param_file="ctem.in", isnew=True): } # Get the location of the CTEM executable - self.ctem_executable = Path(currentdir) / "CTEM" - if not self.ctem_executable.exists(): - print(f"CTEM driver not found at {self.ctem_executable}. Trying package directory..") - self.ctem_executable = Path(_pyfile).parent.parent.parent / "bin" / "CTEM" - if not self.ctem_executable.exists(): - warnings.warn(f"Cannot find the CTEM driver {str(self.ctem_executable)}", stacklevel=2) - self.ctem_executable = None - + self.ctem_executable = shutil.which("CTEM") + if not self.ctem_executable: + warnings.warn(f"Cannot find the CTEM driver {str(self.ctem_executable)}", stacklevel=2) + self.ctem_executable = None self.user = util.read_user_input(self.user) diff --git a/examples/quasimc-global/CTEM b/examples/quasimc-global/CTEM deleted file mode 120000 index 604970bd..00000000 --- a/examples/quasimc-global/CTEM +++ /dev/null @@ -1 +0,0 @@ -../../build/src/CTEM \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 99ff6ff0..bc1aebc7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -239,9 +239,9 @@ ELSE() SET(CMAKE_INSTALL_PREFIX /usr/local) ENDIF(WIN32) INSTALL(TARGETS ${CTEM_DRIVER} ${CTEM_LIBRARY} - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - INCLUDES DESTINATION include + RUNTIME DESTINATION ${INSTALL_BINDIR} + LIBRARY DESTINATION ${INSTALL_LIBDIR} + ARCHIVE DESTINATION ${INSTALL_LIBDIR} + INCLUDES DESTINATION ${INSTALL_INCLUDEDIR} ) From 766f27e85a8ae84bdb6d873b39be0c9121a8fa69 Mon Sep 17 00:00:00 2001 From: David A Minton Date: Tue, 20 Feb 2024 14:40:42 -0500 Subject: [PATCH 34/42] Incremented version --- pyproject.toml | 2 +- version.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ba12d7c1..d1d84406 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "ctem" -version = "2023.10.0" +version = "2024.2.0" authors=[ {name = 'David A. Minton', email='daminton@purdue.edu'}, {name = 'James E. Richardson'}, diff --git a/version.txt b/version.txt index 3bae6081..032892e0 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -2023.10.0 \ No newline at end of file +2024.2.0 \ No newline at end of file From 06a6da8798394cb83634d9f7fa56655e8e1d8227 Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 25 Apr 2024 11:03:13 -0400 Subject: [PATCH 35/42] Fixed interface mismatches --- src/crater/module_crater.f90 | 2 +- src/ejecta/ejecta_emplace.f90 | 2 +- src/regolith/module_regolith.f90 | 2 +- src/regolith/regolith_subpixel_streamtube.f90 | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/crater/module_crater.f90 b/src/crater/module_crater.f90 index c0dd5dfe..d5108399 100644 --- a/src/crater/module_crater.f90 +++ b/src/crater/module_crater.f90 @@ -33,7 +33,7 @@ subroutine crater_populate(user,surf,crater,domain,prod,production_list,vdist,nt mass,fracdone,nflux,ntotcrat,curyear,rclist) use module_globals implicit none - type(usertype),intent(in) :: user + type(usertype),intent(inout) :: user type(surftype),dimension(:,:),intent(inout) :: surf type(cratertype),intent(inout) :: crater type(domaintype),intent(inout) :: domain diff --git a/src/ejecta/ejecta_emplace.f90 b/src/ejecta/ejecta_emplace.f90 index 476d6b82..8a7568e0 100644 --- a/src/ejecta/ejecta_emplace.f90 +++ b/src/ejecta/ejecta_emplace.f90 @@ -93,7 +93,7 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ integer(I4B),intent(in) :: ejtble type(ejbtype),dimension(:),intent(inout) :: ejb real(DP),intent(in) :: deltaMtot - real(DP),dimension(:,:),allocatable,intent(out) :: cumulative_elchange + real(DP),dimension(:,:),allocatable,intent(inout) :: cumulative_elchange integer(I4B),intent(in) :: nmeltsheet real(DP),intent(out) :: vmeltsheet diff --git a/src/regolith/module_regolith.f90 b/src/regolith/module_regolith.f90 index 2ab24cd9..0c77a42f 100644 --- a/src/regolith/module_regolith.f90 +++ b/src/regolith/module_regolith.f90 @@ -102,7 +102,7 @@ subroutine regolith_traverse_streamtube(user,surfi,deltar,ri,rip1,eradi,erado,ne type(surftype),intent(inout) :: surfi real(DP),intent(in) :: deltar,ri,rip1,eradi,erado type(regodatatype),intent(inout) :: newlayer - real(DP),intent(out) :: meltinejecta,totvol + real(DP),intent(inout) :: meltinejecta,totvol real(DP),intent(out) :: vmare,totseb real(SP),dimension(:),intent(inout) :: age_collector real(DP),intent(in) :: xmints diff --git a/src/regolith/regolith_subpixel_streamtube.f90 b/src/regolith/regolith_subpixel_streamtube.f90 index acf2b08d..694b23f5 100644 --- a/src/regolith/regolith_subpixel_streamtube.f90 +++ b/src/regolith/regolith_subpixel_streamtube.f90 @@ -61,7 +61,7 @@ subroutine regolith_subpixel_streamtube(user,surfi,deltar,ri,rip1,eradi,newlayer type(surftype),intent(inout) :: surfi real(DP),intent(in) :: deltar,ri,rip1,eradi type(regodatatype),intent(inout) :: newlayer - real(DP),intent(out) :: meltinejecta, totvol + real(DP),intent(inout) :: meltinejecta, totvol real(DP),intent(out) :: vmare,totseb real(SP),dimension(:),intent(inout) :: age_collector real(DP),intent(in) :: xmints From da73d4703fbc8be0d6a26d0e549c6f3210745b18 Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 25 Apr 2024 11:29:42 -0400 Subject: [PATCH 36/42] Updated the ray generation input file --- .../ray-generation-test-environment/ctem.in | 15 +- .../testprofile.dat | 1000 ----------------- 2 files changed, 10 insertions(+), 1005 deletions(-) delete mode 100644 examples/ray-generation-test-environment/testprofile.dat diff --git a/examples/ray-generation-test-environment/ctem.in b/examples/ray-generation-test-environment/ctem.in index e9f20086..dfd33eb2 100644 --- a/examples/ray-generation-test-environment/ctem.in +++ b/examples/ray-generation-test-environment/ctem.in @@ -22,7 +22,7 @@ runtype single ! Run type: options are normal / seed 1108267 ! Random number generator seed gridsize 1000 ! Size of grid in pixels numlayers 10 ! Number of perched layers -pix 1.0e0 ! Pixel size (m) +pix 1.0e2 ! Pixel size (m) mat rock ! Material (rock or ice) ! Bedrock scaling parameters mu_b 0.41d0 ! Experimentally derived parameter for bedrock crater scaling law @@ -62,18 +62,23 @@ neff 5.0d-10 ! Impact energy seismic efficien ! Optional input. These have internally set default values that work reasonable well. Comment them out with countingmodel Fassett ! Crater counter model. Default is by Caleb Fassett. deplimit 10d3 ! Depth limit for craters (m) - Default is to ignore. -maxcrat 1.00d0 ! Fraction of gridsize that maximum crater can be - Default 1.0 +maxcrat 1.00d4 ! Fraction of gridsize that maximum crater can be - Default 1.0 killatmaxcrater F ! Stop the run if a crater larger than the maximum is produced - Default F basinimp 35.0d3 ! Size of impactor to switch to lunar basin scaling law - Default is to ignore docollapse T ! Do slope collapse - Default T dosoftening T ! Do ejecta softening - Default T doangle T ! Vary the impact angle. Set to F to have only vertical impacts - Default T -doregotrack F +doregotrack T +Kd1 0.00312669649143281 +psi 2.000 +fe 10.0 +dorays T +ejecta_truncation 100.0 ! Testing input. These are used to perform non-Monte Carlo tests. testflag T ! Set to T to create a single crater with user-defined impactor properties -testimp 1.0 ! Diameter of test impactor (m) -testvel 15.d3 ! Velocity of test crater (m/s) +testimp 1.e2 ! Diameter of test impactor (m) +testvel 15.e3 ! Velocity of test crater (m/s) testang 90.0 ! Impact angle of test crater (deg) - Default 90.0 testxoffset 0.0d0 ! x-axis offset of crater center from grid center (m) - Default 0.0 testyoffset 0.0d0 ! y-axis offset of crater center from grid center (m) - Default 0.0 diff --git a/examples/ray-generation-test-environment/testprofile.dat b/examples/ray-generation-test-environment/testprofile.dat deleted file mode 100644 index 09f1b660..00000000 --- a/examples/ray-generation-test-environment/testprofile.dat +++ /dev/null @@ -1,1000 +0,0 @@ - 1.0000000000000000 1.2525955388259645E-003 - 2.0000000000000000 1.2527493144024800E-003 - 3.0000000000000000 1.2530056375141877E-003 - 4.0000000000000000 1.2533645538970216E-003 - 5.0000000000000000 1.2538261276006199E-003 - 6.0000000000000000 1.2543904410076655E-003 - 7.0000000000000000 1.2550575948587633E-003 - 8.0000000000000000 1.2558277082828800E-003 - 9.0000000000000000 1.2567009188333385E-003 - 10.000000000000000 1.2576773825294040E-003 - 11.000000000000000 1.2587572739034647E-003 - 12.000000000000000 1.2599407860538437E-003 - 13.000000000000000 1.2612281307032500E-003 - 14.000000000000000 1.2626195382629108E-003 - 15.000000000000000 1.2641152579024033E-003 - 16.000000000000000 1.2657155576252257E-003 - 17.000000000000000 1.2674207243501341E-003 - 18.000000000000000 1.2692310639982928E-003 - 19.000000000000000 1.2711469015862706E-003 - 20.000000000000000 1.2731685813249238E-003 - 21.000000000000000 1.2752964667242241E-003 - 22.000000000000000 1.2775309407040661E-003 - 23.000000000000000 1.2798724057111101E-003 - 24.000000000000000 1.2823212838417191E-003 - 25.000000000000000 1.2848780169710419E-003 - 26.000000000000000 1.2875430668883000E-003 - 27.000000000000000 1.2903169154383515E-003 - 28.000000000000000 1.2932000646695841E-003 - 29.000000000000000 1.2961930369882163E-003 - 30.000000000000000 1.2992963753190782E-003 - 31.000000000000000 1.3025106432729382E-003 - 32.000000000000000 1.3058364253204667E-003 - 33.000000000000000 1.3092743269729082E-003 - 34.000000000000000 1.3128249749695513E-003 - 35.000000000000000 1.3164890174720873E-003 - 36.000000000000000 1.3202671242659397E-003 - 37.000000000000000 1.3241599869686746E-003 - 38.000000000000000 1.3281683192455729E-003 - 39.000000000000000 1.3322928570324861E-003 - 40.000000000000000 1.3365343587660638E-003 - 41.000000000000000 1.3408936056214739E-003 - 42.000000000000000 1.3453714017577245E-003 - 43.000000000000000 1.3499685745707120E-003 - 44.000000000000000 1.3546859749540999E-003 - 45.000000000000000 1.3595244775681770E-003 - 46.000000000000000 1.3644849811168085E-003 - 47.000000000000000 1.3695684086326135E-003 - 48.000000000000000 1.3747757077705212E-003 - 49.000000000000000 1.3801078511098319E-003 - 50.000000000000000 1.3855658364649425E-003 - 51.000000000000000 1.3911506872048797E-003 - 52.000000000000000 1.3968634525818040E-003 - 53.000000000000000 1.4027052080686439E-003 - 54.000000000000000 1.4086770557060206E-003 - 55.000000000000000 1.4147801244586476E-003 - 56.000000000000000 1.4210155705813678E-003 - 57.000000000000000 1.4273845779950217E-003 - 58.000000000000000 1.4338883586723259E-003 - 59.000000000000000 1.4405281530339581E-003 - 60.000000000000000 1.4473052303550491E-003 - 61.000000000000000 1.4542208891822866E-003 - 62.000000000000000 1.4612764577618328E-003 - 63.000000000000000 1.4684732944782823E-003 - 64.000000000000000 1.4758127883048875E-003 - 65.000000000000000 1.4832963592652608E-003 - 66.000000000000000 1.4909254589068135E-003 - 67.000000000000000 1.4987015707861599E-003 - 68.000000000000000 1.5066262109667365E-003 - 69.000000000000000 1.5147009285289086E-003 - 70.000000000000000 1.5229273060928051E-003 - 71.000000000000000 1.5313069603541743E-003 - 72.000000000000000 1.5398415426335313E-003 - 73.000000000000000 1.5485327394388858E-003 - 74.000000000000000 1.5573822730423456E-003 - 75.000000000000000 1.5663919020709037E-003 - 76.000000000000000 1.5755634221117198E-003 - 77.000000000000000 1.5848986663322198E-003 - 78.000000000000000 1.5943995061153374E-003 - 79.000000000000000 1.6040678517102553E-003 - 80.000000000000000 1.6139056528989722E-003 - 81.000000000000000 1.6239148996790818E-003 - 82.000000000000000 1.6340976229631109E-003 - 83.000000000000000 1.6444558952948157E-003 - 84.000000000000000 1.6549918315828139E-003 - 85.000000000000000 1.6657075898519639E-003 - 86.000000000000000 1.6766053720129090E-003 - 87.000000000000000 1.6876874246501943E-003 - 88.000000000000000 1.6989560398294184E-003 - 89.000000000000000 1.7104135559238519E-003 - 90.000000000000000 1.7220623584609926E-003 - 91.000000000000000 1.7339048809895405E-003 - 92.000000000000000 1.7459436059672681E-003 - 93.000000000000000 1.7581810656702973E-003 - 94.000000000000000 1.7706198431243151E-003 - 95.000000000000000 1.7832625730582283E-003 - 96.000000000000000 1.7961119428808376E-003 - 97.000000000000000 1.8091706936810869E-003 - 98.000000000000000 1.8224416212524442E-003 - 99.000000000000000 1.8359275771420555E-003 - 100.00000000000000 1.8496314697252390E-003 - 101.00000000000000 1.8635562653059900E-003 - 102.00000000000000 1.8777049892441181E-003 - 103.00000000000000 1.8920807271096969E-003 - 104.00000000000000 1.9066866258655249E-003 - 105.00000000000000 1.9215258950782826E-003 - 106.00000000000000 1.9366018081591314E-003 - 107.00000000000000 1.9519177036344986E-003 - 108.00000000000000 1.9674769864478194E-003 - 109.00000000000000 1.9832831292930296E-003 - 110.00000000000000 1.9993396739806271E-003 - 111.00000000000000 2.0156502328371496E-003 - 112.00000000000000 2.0322184901389144E-003 - 113.00000000000000 2.0490482035809407E-003 - 114.00000000000000 2.0661432057819409E-003 - 115.00000000000000 2.0835074058263544E-003 - 116.00000000000000 2.1011447908443766E-003 - 117.00000000000000 2.1190594276309835E-003 - 118.00000000000000 2.1372554643050061E-003 - 119.00000000000000 2.1557371320092872E-003 - 120.00000000000000 2.1745087466530297E-003 - 121.00000000000000 2.1935747106974638E-003 - 122.00000000000000 2.2129395149859928E-003 - 123.00000000000000 2.2326077406199878E-003 - 124.00000000000000 2.2525840608815201E-003 - 125.00000000000000 2.2728732432042223E-003 - 126.00000000000000 2.2934801511936545E-003 - 127.00000000000000 2.3144097466984742E-003 - 128.00000000000000 2.3356670919338234E-003 - 129.00000000000000 2.3572573516583463E-003 - 130.00000000000000 2.3791857954063218E-003 - 131.00000000000000 2.4014577997764183E-003 - 132.00000000000000 2.4240788507786464E-003 - 133.00000000000000 2.4470545462411133E-003 - 134.00000000000000 2.4703905982782432E-003 - 135.00000000000000 2.4940928358221821E-003 - 136.00000000000000 2.5181672072191520E-003 - 137.00000000000000 2.5426197828925666E-003 - 138.00000000000000 2.5674567580748066E-003 - 139.00000000000000 2.5926844556095809E-003 - 140.00000000000000 2.6183093288268604E-003 - 141.00000000000000 2.6443379644924738E-003 - 142.00000000000000 2.6707770858344676E-003 - 143.00000000000000 2.6976335556484383E-003 - 144.00000000000000 2.7249143794840724E-003 - 145.00000000000000 2.7526267089152795E-003 - 146.00000000000000 2.7807778448962765E-003 - 147.00000000000000 2.8093752412061343E-003 - 148.00000000000000 2.8384265079843445E-003 - 149.00000000000000 2.8679394153600731E-003 - 150.00000000000000 2.8979218971777942E-003 - 151.00000000000000 2.9283820548221678E-003 - 152.00000000000000 2.9593281611450524E-003 - 153.00000000000000 2.9907686644976583E-003 - 154.00000000000000 3.0227121928709582E-003 - 155.00000000000000 3.0551675581475608E-003 - 156.00000000000000 3.0881437604683331E-003 - 157.00000000000000 3.1216499927172472E-003 - 158.00000000000000 3.1556956451279272E-003 - 159.00000000000000 3.1902903100155676E-003 - 160.00000000000000 3.2254437866380244E-003 - 161.00000000000000 3.2611660861899218E-003 - 162.00000000000000 3.2974674369338304E-003 - 163.00000000000000 3.3343582894726923E-003 - 164.00000000000000 3.3718493221677566E-003 - 165.00000000000000 3.4099514467064965E-003 - 166.00000000000000 3.4486758138250920E-003 - 167.00000000000000 3.4880338191902345E-003 - 168.00000000000000 3.5280371094451681E-003 - 169.00000000000000 3.5686975884250227E-003 - 170.00000000000000 3.6100274235467147E-003 - 171.00000000000000 3.6520390523788592E-003 - 172.00000000000000 3.6947451893972437E-003 - 173.00000000000000 3.7381588329317848E-003 - 174.00000000000000 3.7822932723108639E-003 - 175.00000000000000 3.8271620952093398E-003 - 176.00000000000000 3.8727791952066653E-003 - 177.00000000000000 3.9191587795617197E-003 - 178.00000000000000 3.9663153772113192E-003 - 179.00000000000000 4.0142638469994902E-003 - 180.00000000000000 4.0630193861449105E-003 - 181.00000000000000 4.1125975389541799E-003 - 182.00000000000000 4.1730182948308721E-003 - 183.00000000000000 4.2243216838178509E-003 - 184.00000000000000 4.2764966192740906E-003 - 185.00000000000000 4.3295601267864465E-003 - 186.00000000000000 4.3835296265737102E-003 - 187.00000000000000 4.4384229438513287E-003 - 188.00000000000000 4.4942583195036415E-003 - 189.00000000000000 4.5510544210738031E-003 - 190.00000000000000 4.6088303540819170E-003 - 191.00000000000000 4.6676056736822073E-003 - 192.00000000000000 4.7274003966705615E-003 - 193.00000000000000 4.7882350138541037E-003 - 194.00000000000000 4.8501305027949596E-003 - 195.00000000000000 4.9131083409407516E-003 - 196.00000000000000 4.9771905191548999E-003 - 197.00000000000000 5.0423995556602109E-003 - 198.00000000000000 5.1087585104098209E-003 - 199.00000000000000 5.1762909999000378E-003 - 200.00000000000000 5.2450212124401652E-003 - 201.00000000000000 5.3149739238949898E-003 - 202.00000000000000 5.3861745139161931E-003 - 203.00000000000000 5.4586489826795757E-003 - 204.00000000000000 5.5324239681455627E-003 - 205.00000000000000 5.6075267638612796E-003 - 206.00000000000000 5.6839853373229464E-003 - 207.00000000000000 5.7618283489183318E-003 - 208.00000000000000 5.8410851714695454E-003 - 209.00000000000000 5.9217859103973891E-003 - 210.00000000000000 6.0039614245291544E-003 - 211.00000000000000 6.0876433475728145E-003 - 212.00000000000000 6.1728641102812435E-003 - 213.00000000000000 6.2596569633311689E-003 - 214.00000000000000 6.3480560009424600E-003 - 215.00000000000000 6.4380961852644313E-003 - 216.00000000000000 6.5298133715567929E-003 - 217.00000000000000 6.6232443341941475E-003 - 218.00000000000000 6.7184267935238486E-003 - 219.00000000000000 6.8153994436085368E-003 - 220.00000000000000 6.9142019808855985E-003 - 221.00000000000000 7.0148751337773766E-003 - 222.00000000000000 7.1174606932871524E-003 - 223.00000000000000 7.2220015446174245E-003 - 224.00000000000000 7.3285416998484692E-003 - 225.00000000000000 7.4371263317167639E-003 - 226.00000000000000 7.5478018085344111E-003 - 227.00000000000000 7.6606157302924541E-003 - 228.00000000000000 7.7756169659927770E-003 - 229.00000000000000 7.8928556922550196E-003 - 230.00000000000000 8.0123834332470646E-003 - 231.00000000000000 8.1342531019894544E-003 - 232.00000000000000 8.2585190430864604E-003 - 233.00000000000000 8.3852370769385079E-003 - 234.00000000000000 8.5144645454932541E-003 - 235.00000000000000 8.6462603595946833E-003 - 236.00000000000000 8.7806850479925959E-003 - 237.00000000000000 8.9178008080769821E-003 - 238.00000000000000 9.0576715584051136E-003 - 239.00000000000000 9.2003629930916733E-003 - 240.00000000000000 9.3459426381354450E-003 - 241.00000000000000 9.4944799097594658E-003 - 242.00000000000000 9.6460461748445157E-003 - 243.00000000000000 9.8007148135396769E-003 - 244.00000000000000 9.9585612841372653E-003 - 245.00000000000000 1.0119663190303147E-002 - 246.00000000000000 1.0284100350757738E-002 - 247.00000000000000 1.0451954871507015E-002 - 248.00000000000000 1.0623311220727558E-002 - 249.00000000000000 1.0798256306413921E-002 - 250.00000000000000 1.0976879556902018E-002 - 251.00000000000000 1.1159273004386849E-002 - 252.00000000000000 1.1345531371558734E-002 - 253.00000000000000 1.1535752161487469E-002 - 254.00000000000000 1.1730035750890079E-002 - 255.00000000000000 1.1928485486923908E-002 - 256.00000000000000 1.2131207787653352E-002 - 257.00000000000000 1.2338312246345502E-002 - 258.00000000000000 1.2549911739757138E-002 - 259.00000000000000 1.2766122540583029E-002 - 260.00000000000000 1.2987064434243741E-002 - 261.00000000000000 1.3212860840199205E-002 - 262.00000000000000 1.3443638937983457E-002 - 263.00000000000000 1.3679529798165002E-002 - 264.00000000000000 1.3920668518447202E-002 - 265.00000000000000 1.4167194365133235E-002 - 266.00000000000000 1.4419250920191131E-002 - 267.00000000000000 1.4676986234165679E-002 - 268.00000000000000 1.4940552985196020E-002 - 269.00000000000000 1.5210108644410412E-002 - 270.00000000000000 1.5485815647982959E-002 - 271.00000000000000 1.5767841576151079E-002 - 272.00000000000000 1.6056359339507314E-002 - 273.00000000000000 1.6351547372894584E-002 - 274.00000000000000 1.6653589837250633E-002 - 275.00000000000000 1.6962676829764385E-002 - 276.00000000000000 1.7279004602725481E-002 - 277.00000000000000 1.7602775791467590E-002 - 278.00000000000000 1.7934199651826136E-002 - 279.00000000000000 1.8273492307552812E-002 - 280.00000000000000 1.8620877008151869E-002 - 281.00000000000000 1.8976584397627255E-002 - 282.00000000000000 1.9340852794654442E-002 - 283.00000000000000 1.9713928484718531E-002 - 284.00000000000000 2.0096066024787265E-002 - 285.00000000000000 2.0487528561118414E-002 - 286.00000000000000 2.0888588160832215E-002 - 287.00000000000000 2.1299526157912838E-002 - 288.00000000000000 2.1720633514338408E-002 - 289.00000000000000 2.2152211197076520E-002 - 290.00000000000000 2.2594570571721605E-002 - 291.00000000000000 2.3048033813592564E-002 - 292.00000000000000 2.3512934337153655E-002 - 293.00000000000000 2.3989617244668075E-002 - 294.00000000000000 2.4478439795044493E-002 - 295.00000000000000 2.4979771893888478E-002 - 296.00000000000000 2.5493996605827855E-002 - 297.00000000000000 2.6021510690239679E-002 - 298.00000000000000 2.6562725161570114E-002 - 299.00000000000000 2.7118065875504745E-002 - 300.00000000000000 2.7687974142318595E-002 - 301.00000000000000 2.8272907368810076E-002 - 302.00000000000000 2.8873339730303021E-002 - 303.00000000000000 2.9489762874286656E-002 - 304.00000000000000 3.0122686657352959E-002 - 305.00000000000000 3.0772639917187820E-002 - 306.00000000000000 3.1440171281473826E-002 - 307.00000000000000 3.2125850015671850E-002 - 308.00000000000000 3.2830266911764008E-002 - 309.00000000000000 3.3554035220163626E-002 - 310.00000000000000 3.4297791627129350E-002 - 311.00000000000000 3.5062197280159559E-002 - 312.00000000000000 3.5847938863992790E-002 - 313.00000000000000 3.6655729729997970E-002 - 314.00000000000000 3.7486311081907003E-002 - 315.00000000000000 3.8340453221023932E-002 - 316.00000000000000 3.9218956854235126E-002 - 317.00000000000000 4.0122654468352767E-002 - 318.00000000000000 4.1052411774540720E-002 - 319.00000000000000 4.2009129226807745E-002 - 320.00000000000000 4.2993743618802205E-002 - 321.00000000000000 4.4007229763409865E-002 - 322.00000000000000 4.5050602259942674E-002 - 323.00000000000000 4.6124917354011044E-002 - 324.00000000000000 4.7231274895500608E-002 - 325.00000000000000 4.8370820400423085E-002 - 326.00000000000000 4.9544747222786539E-002 - 327.00000000000000 5.0754298843032057E-002 - 328.00000000000000 5.2000771280012958E-002 - 329.00000000000000 5.3285515633955075E-002 - 330.00000000000000 5.4609940768330839E-002 - 331.00000000000000 5.5975516139110490E-002 - 332.00000000000000 5.7383774780423016E-002 - 333.00000000000000 5.8836316456272353E-002 - 334.00000000000000 6.0334810988609065E-002 - 335.00000000000000 6.1881001772766543E-002 - 336.00000000000000 6.3476709492027106E-002 - 337.00000000000000 6.5123836043901817E-002 - 338.00000000000000 6.6824368691585215E-002 - 339.00000000000000 6.8580384454992482E-002 - 340.00000000000000 7.0394054756804908E-002 - 341.00000000000000 7.2267650340046452E-002 - 342.00000000000000 7.4203546474899101E-002 - 343.00000000000000 7.6204228473738117E-002 - 344.00000000000000 7.8272297534747376E-002 - 345.00000000000000 8.0410476935960026E-002 - 346.00000000000000 8.2621618603174990E-002 - 347.00000000000000 8.4908710076935068E-002 - 348.00000000000000 8.7274881905626517E-002 - 349.00000000000000 8.9723415493789913E-002 - 350.00000000000000 9.2257751436925217E-002 - 351.00000000000000 9.4881498376452864E-002 - 352.00000000000000 9.7598442411065217E-002 - 353.00000000000000 0.10041255710349541 - 354.00000000000000 0.10332801412475574 - 355.00000000000000 0.10634919458118347 - 356.00000000000000 0.10948070107319365 - 357.00000000000000 0.11272737053851653 - 358.00000000000000 0.11609428793690132 - 359.00000000000000 0.11956681095755470 - 360.00000000000000 0.12319058655672448 - 361.00000000000000 0.20215606231105379 - 362.00000000000000 0.20767836655079511 - 363.00000000000000 0.21339757104679685 - 364.00000000000000 0.21932309981141065 - 365.00000000000000 0.22547112302603478 - 366.00000000000000 0.23184378314292695 - 367.00000000000000 0.23845117169658930 - 368.00000000000000 0.24531076919203776 - 369.00000000000000 0.25243074132053034 - 370.00000000000000 0.25981965000064650 - 371.00000000000000 0.26749299089800815 - 372.00000000000000 0.27547045567711703 - 373.00000000000000 0.28375710030617890 - 374.00000000000000 0.29236763916203834 - 375.00000000000000 0.30132993283334525 - 376.00000000000000 0.31065146905631030 - 377.00000000000000 0.32034714134579778 - 378.00000000000000 0.33044261174769046 - 379.00000000000000 0.34096159348153232 - 380.00000000000000 0.35191439794373885 - 381.00000000000000 0.36332296755228577 - 382.00000000000000 0.37523253789844113 - 383.00000000000000 0.38764758539697330 - 384.00000000000000 0.40059394198574017 - 385.00000000000000 0.41411473244920344 - 386.00000000000000 0.42823772087934930 - 387.00000000000000 0.44298275905051820 - 388.00000000000000 0.45838796882698890 - 389.00000000000000 0.47451481465346507 - 390.00000000000000 0.49137327862230068 - 391.00000000000000 0.50900398863576979 - 392.00000000000000 0.52748101490987698 - 393.00000000000000 0.54683467109905082 - 394.00000000000000 0.56710244968828383 - 395.00000000000000 0.58835288386395801 - 396.00000000000000 0.61066753969252008 - 397.00000000000000 0.63406993565488778 - 398.00000000000000 0.65862489001281666 - 399.00000000000000 0.68446344414786442 - 400.00000000000000 0.71161260859447073 - 401.00000000000000 0.74014341279599116 - 402.00000000000000 0.77018232901078987 - 403.00000000000000 0.80183662937043043 - 404.00000000000000 0.83515728202995065 - 405.00000000000000 0.87025409194107461 - 406.00000000000000 0.90736005332093461 - 407.00000000000000 0.94648891155794024 - 408.00000000000000 0.98777520868187607 - 409.00000000000000 1.0314615474044391 - 410.00000000000000 1.0776831936316438 - 411.00000000000000 1.1265483490871420 - 412.00000000000000 1.1781379027335419 - 413.00000000000000 1.2322390642582450 - 414.00000000000000 1.2887605860153917 - 415.00000000000000 1.3478388596435678 - 416.00000000000000 1.4098492302337373 - 417.00000000000000 1.4748123692744954 - 418.00000000000000 1.5428240767018095 - 419.00000000000000 1.6141989538573758 - 420.00000000000000 1.6892819247025452 - 421.00000000000000 1.7680162980503829 - 422.00000000000000 1.8506228702063829 - 423.00000000000000 1.9378440080421810 - 424.00000000000000 2.0295018786282628 - 425.00000000000000 2.1258181935060092 - 426.00000000000000 2.2274413067773802 - 427.00000000000000 2.3347138818077733 - 428.00000000000000 2.4475928828467048 - 429.00000000000000 2.5664920279678136 - 430.00000000000000 2.6926181354813652 - 431.00000000000000 2.8254607617069070 - 432.00000000000000 2.9654303946603466 - 433.00000000000000 3.1137265704532910 - 434.00000000000000 3.2703892004237818 - 435.00000000000000 3.4354237516213146 - 436.00000000000000 3.6095859988127006 - 437.00000000000000 3.7939003021594333 - 438.00000000000000 3.9876027391801281 - 439.00000000000000 4.1910534762001381 - 440.00000000000000 4.4045901165285013 - 441.00000000000000 4.3237452455533312 - 442.00000000000000 3.7472280632877575 - 443.00000000000000 3.0641344129130803 - 444.00000000000000 2.3373994510541216 - 445.00000000000000 1.6235270526813124 - 446.00000000000000 0.92090939737629762 - 447.00000000000000 0.22150738307397194 - 448.00000000000000 -0.45377732487761319 - 449.00000000000000 -1.1161994693693704 - 450.00000000000000 -1.7657590504077436 - 451.00000000000000 -2.4024560679991263 - 452.00000000000000 -3.0262905221498708 - 453.00000000000000 -3.6372624128662738 - 454.00000000000000 -4.2353717401545845 - 455.00000000000000 -4.8206185040210014 - 456.00000000000000 -5.3930027044716811 - 457.00000000000000 -5.9525243415127242 - 458.00000000000000 -6.4991834151501902 - 459.00000000000000 -7.0329799253900882 - 460.00000000000000 -7.5539138722383834 - 461.00000000000000 -8.0619852557009928 - 462.00000000000000 -8.5571940757837890 - 463.00000000000000 -9.0395403324925923 - 464.00000000000000 -9.5090240258331917 - 465.00000000000000 -9.9656451558113179 - 466.00000000000000 -10.409403722432666 - 467.00000000000000 -10.840299725702879 - 468.00000000000000 -11.258333165627567 - 469.00000000000000 -11.663504042212283 - 470.00000000000000 -12.055812355462551 - 471.00000000000000 -12.435258105383843 - 472.00000000000000 -12.801841291981589 - 473.00000000000000 -13.155561915261183 - 474.00000000000000 -13.496419975227973 - 475.00000000000000 -13.824415471887267 - 476.00000000000000 -14.139548405244325 - 477.00000000000000 -14.441818775304380 - 478.00000000000000 -14.731226582072612 - 479.00000000000000 -15.007771825554169 - 480.00000000000000 -15.271454505754155 - 481.00000000000000 -15.522274622677635 - 482.00000000000000 -15.760232176329636 - 483.00000000000000 -15.985327166715141 - 484.00000000000000 -16.197559593839109 - 485.00000000000000 -16.396929457706445 - 486.00000000000000 -16.583436758322016 - 487.00000000000000 -16.757081495690663 - 488.00000000000000 -16.917863669817187 - 489.00000000000000 -17.065783280706341 - 490.00000000000000 -17.200840328362855 - 491.00000000000000 -17.323034812791413 - 492.00000000000000 -17.432366733996663 - 493.00000000000000 -17.528836091983223 - 494.00000000000000 -17.612442886755673 - 495.00000000000000 -17.683187118318560 - 496.00000000000000 -17.741068786676387 - 497.00000000000000 -17.786087891833624 - 498.00000000000000 -17.818244433794721 - 499.00000000000000 -17.837538412564072 - 500.00000000000000 -17.843969828146058 - 501.00000000000000 -17.837538680545002 - 502.00000000000000 -17.818244969765221 - 503.00000000000000 -17.786088695810978 - 504.00000000000000 -17.741069858686508 - 505.00000000000000 -17.683188458396021 - 506.00000000000000 -17.612444494943681 - 507.00000000000000 -17.528837968333633 - 508.00000000000000 -17.432368878569978 - 509.00000000000000 -17.323037225656801 - 510.00000000000000 -17.200843009598131 - 511.00000000000000 -17.065786230397993 - 512.00000000000000 -16.917866888060356 - 513.00000000000000 -16.757084982589177 - 514.00000000000000 -16.583440513988378 - 515.00000000000000 -16.396933482261844 - 516.00000000000000 -16.197563887413430 - 517.00000000000000 -15.985331729446967 - 518.00000000000000 -15.760237008366257 - 519.00000000000000 -15.522279724175064 - 520.00000000000000 -15.271459876877133 - 521.00000000000000 -15.007777466476169 - 522.00000000000000 -14.731232492975856 - 523.00000000000000 -14.441824956379850 - 524.00000000000000 -14.139554856691770 - 525.00000000000000 -13.824422193915218 - 526.00000000000000 -13.496426968053756 - 527.00000000000000 -13.155569179110930 - 528.00000000000000 -12.801848827090250 - 529.00000000000000 -12.435265911995202 - 530.00000000000000 -12.055820433829242 - 531.00000000000000 -11.663512392595802 - 532.00000000000000 -11.258341788298289 - 533.00000000000000 -10.840308620940073 - 534.00000000000000 -10.409412890524514 - 535.00000000000000 -9.9656545970549288 - 536.00000000000000 -9.5090337405346190 - 537.00000000000000 -9.0395503209668586 - 538.00000000000000 -8.5572043383548966 - 539.00000000000000 -8.0619957927019481 - 540.00000000000000 -7.5539246840112124 - 541.00000000000000 -7.0329910122858621 - 542.00000000000000 -6.4991947775290413 - 543.00000000000000 -5.9525359797438711 - 544.00000000000000 -5.3930146189334502 - 545.00000000000000 -4.8206306951008475 - 546.00000000000000 -4.2353842082491147 - 547.00000000000000 -3.6372751583812724 - 548.00000000000000 -3.0263035455003222 - 549.00000000000000 -2.4024693696092405 - 550.00000000000000 -1.7657726307109816 - 551.00000000000000 -1.1162133288084697 - 552.00000000000000 -0.45379146390461472 - 553.00000000000000 0.22149296399769688 - 554.00000000000000 0.92089469760988818 - 555.00000000000000 1.6235120718872194 - 556.00000000000000 2.3373841887665656 - 557.00000000000000 3.0641188686330736 - 558.00000000000000 3.7472122989084702 - 559.00000000000000 4.3237293854665744 - 560.00000000000000 4.4045747218253233 - 561.00000000000000 4.1910388896988220 - 562.00000000000000 3.9875889581923225 - 563.00000000000000 3.7938873221348377 - 564.00000000000000 3.6095738133337378 - 565.00000000000000 3.4354123523976066 - 566.00000000000000 3.2703785772863987 - 567.00000000000000 3.1137167113487938 - 568.00000000000000 2.9654212856446143 - 569.00000000000000 2.8254523869387467 - 570.00000000000000 2.6926104772159052 - 571.00000000000000 2.5664850665496783 - 572.00000000000000 2.4475865967029722 - 573.00000000000000 2.3347082474407097 - 574.00000000000000 2.2274362987569556 - 575.00000000000000 2.1258137844621876 - 576.00000000000000 2.0294980392430695 - 577.00000000000000 1.9378407070415469 - 578.00000000000000 1.8506200743517576 - 579.00000000000000 1.7680139721301240 - 580.00000000000000 1.6892800315230763 - 581.00000000000000 1.6141974542341133 - 582.00000000000000 1.5428229294498581 - 583.00000000000000 1.4748115311991106 - 584.00000000000000 1.4098486561205510 - 585.00000000000000 1.3478385022485782 - 586.00000000000000 1.2887603960547158 - 587.00000000000000 1.2322389903976294 - 588.00000000000000 1.1781378915776335 - 589.00000000000000 1.1265483490871420 - 590.00000000000000 1.0776831936316438 - 591.00000000000000 1.0314615474044393 - 592.00000000000000 0.98777520868187607 - 593.00000000000000 0.94648891155794013 - 594.00000000000000 0.90736005332093472 - 595.00000000000000 0.87025409194107450 - 596.00000000000000 0.83515728202995076 - 597.00000000000000 0.80183662937043032 - 598.00000000000000 0.77018232901078976 - 599.00000000000000 0.74014341279599116 - 600.00000000000000 0.71161260859447073 - 601.00000000000000 0.68446344414786442 - 602.00000000000000 0.65862489001281654 - 603.00000000000000 0.63406993565488778 - 604.00000000000000 0.61066753969252008 - 605.00000000000000 0.58835288386395801 - 606.00000000000000 0.56710244968828372 - 607.00000000000000 0.54683467109905082 - 608.00000000000000 0.52748101490987698 - 609.00000000000000 0.50900398863576968 - 610.00000000000000 0.49137327862230062 - 611.00000000000000 0.47451481465346507 - 612.00000000000000 0.45838796882698890 - 613.00000000000000 0.44298275905051826 - 614.00000000000000 0.42823772087934930 - 615.00000000000000 0.41411473244920344 - 616.00000000000000 0.40059394198574022 - 617.00000000000000 0.38764758539697330 - 618.00000000000000 0.37523253789844113 - 619.00000000000000 0.36332296755228582 - 620.00000000000000 0.35191439794373891 - 621.00000000000000 0.34096159348153232 - 622.00000000000000 0.33044261174769046 - 623.00000000000000 0.32034714134579784 - 624.00000000000000 0.31065146905631036 - 625.00000000000000 0.30132993283334530 - 626.00000000000000 0.29236763916203834 - 627.00000000000000 0.28375710030617884 - 628.00000000000000 0.27547045567711698 - 629.00000000000000 0.26749299089800815 - 630.00000000000000 0.25981965000064655 - 631.00000000000000 0.25243074132053034 - 632.00000000000000 0.24531076919203776 - 633.00000000000000 0.23845117169658933 - 634.00000000000000 0.23184378314292695 - 635.00000000000000 0.22547112302603478 - 636.00000000000000 0.21932309981141065 - 637.00000000000000 0.21339757104679688 - 638.00000000000000 0.20767836655079513 - 639.00000000000000 0.20215606231105382 - 640.00000000000000 0.19682582761625819 - 641.00000000000000 0.19167982330775035 - 642.00000000000000 0.18672696654771398 - 643.00000000000000 0.18192054139684583 - 644.00000000000000 0.17727890418311293 - 645.00000000000000 0.17278991703524316 - 646.00000000000000 0.16844748741350876 - 647.00000000000000 0.16424900989967869 - 648.00000000000000 0.16018736546821363 - 649.00000000000000 0.15625542794898403 - 650.00000000000000 0.15244910084499205 - 651.00000000000000 0.14876591644195133 - 652.00000000000000 0.14519782951023819 - 653.00000000000000 0.14174046701721671 - 654.00000000000000 0.13839255824457214 - 655.00000000000000 0.13514781451803515 - 656.00000000000000 0.13200165216490886 - 657.00000000000000 0.12895160852273427 - 658.00000000000000 0.12599492383504082 - 659.00000000000000 0.12312622039848933 - 660.00000000000000 0.12034230949484220 - 661.00000000000000 0.11764271949271111 - 662.00000000000000 0.11502197461611340 - 663.00000000000000 0.11247713539610175 - 664.00000000000000 0.11000677535126910 - 665.00000000000000 0.10760812700883783 - 666.00000000000000 0.10527757823651729 - 667.00000000000000 0.10301298705578783 - 668.00000000000000 0.10081370407939616 - 669.00000000000000 9.8675646695142380E-002 - 670.00000000000000 9.6596733867987283E-002 - 671.00000000000000 9.4576199022144605E-002 - 672.00000000000000 9.2611410021550877E-002 - 673.00000000000000 9.0699938520709733E-002 - 674.00000000000000 8.8840429484792899E-002 - 675.00000000000000 8.7031917266284592E-002 - 676.00000000000000 8.5271563056124128E-002 - 677.00000000000000 8.3557798664696439E-002 - 678.00000000000000 8.1890277424310459E-002 - 679.00000000000000 8.0266567842262979E-002 - 680.00000000000000 7.8685043792767945E-002 - 681.00000000000000 7.7144874253372214E-002 - 682.00000000000000 7.5644950036665298E-002 - 683.00000000000000 7.4183291895265444E-002 - 684.00000000000000 7.2758704195004742E-002 - 685.00000000000000 7.1371105514012864E-002 - 686.00000000000000 7.0018287782061567E-002 - 687.00000000000000 6.8699173155846380E-002 - 688.00000000000000 6.7413280674158596E-002 - 689.00000000000000 6.6159459959854769E-002 - 690.00000000000000 6.4936331692535265E-002 - 691.00000000000000 6.3743100248271650E-002 - 692.00000000000000 6.2579471415829382E-002 - 693.00000000000000 6.1443838156918514E-002 - 694.00000000000000 6.0335373868345567E-002 - 695.00000000000000 5.9253831366600347E-002 - 696.00000000000000 5.8198078528077887E-002 - 697.00000000000000 5.7167158217017247E-002 - 698.00000000000000 5.6160558893561835E-002 - 699.00000000000000 5.5177845798565002E-002 - 700.00000000000000 5.4217863533364788E-002 - 701.00000000000000 5.3279965979651928E-002 - 702.00000000000000 5.2364061336419972E-002 - 703.00000000000000 5.1469068883887095E-002 - 704.00000000000000 5.0594330570570840E-002 - 705.00000000000000 4.9739532188371835E-002 - 706.00000000000000 4.8904164548527411E-002 - 707.00000000000000 4.8087397979924298E-002 - 708.00000000000000 4.7288739231721132E-002 - 709.00000000000000 4.6508149579767247E-002 - 710.00000000000000 4.5744665849155201E-002 - 711.00000000000000 4.4997826565984569E-002 - 712.00000000000000 4.4267454594403767E-002 - 713.00000000000000 4.3553008838545411E-002 - 714.00000000000000 4.2853896091344032E-002 - 715.00000000000000 4.2169786340945391E-002 - 716.00000000000000 4.1500529857782770E-002 - 717.00000000000000 4.0845416044326281E-002 - 718.00000000000000 4.0204076575993876E-002 - 719.00000000000000 3.9576429233948190E-002 - 720.00000000000000 3.8961928056838478E-002 - 721.00000000000000 3.8360152418914592E-002 - 722.00000000000000 3.7770889438067598E-002 - 723.00000000000000 3.7193920290172600E-002 - 724.00000000000000 3.6628721584536783E-002 - 725.00000000000000 3.6074997087473720E-002 - 726.00000000000000 3.5532729838403804E-002 - 727.00000000000000 3.5001385848684771E-002 - 728.00000000000000 3.4480670966863129E-002 - 729.00000000000000 3.3970456374860895E-002 - 730.00000000000000 3.3470482814120253E-002 - 731.00000000000000 3.2980366390782077E-002 - 732.00000000000000 3.2499885615723638E-002 - 733.00000000000000 3.2029012398702816E-002 - 734.00000000000000 3.1567290256334243E-002 - 735.00000000000000 3.1114499504827434E-002 - 736.00000000000000 3.0670571534666773E-002 - 737.00000000000000 3.0235226193148244E-002 - 738.00000000000000 2.9808183988412906E-002 - 739.00000000000000 2.9389296068666325E-002 - 740.00000000000000 2.8978478688023938E-002 - 741.00000000000000 2.8575388204418833E-002 - 742.00000000000000 2.8179844963048331E-002 - 743.00000000000000 2.7791823266279037E-002 - 744.00000000000000 2.7411035296325978E-002 - 745.00000000000000 2.7037279964544809E-002 - 746.00000000000000 2.6670462006151918E-002 - 747.00000000000000 2.6310461102025968E-002 - 748.00000000000000 2.5957019581810542E-002 - 749.00000000000000 2.5609989616343247E-002 - 750.00000000000000 2.5269375829575676E-002 - 751.00000000000000 2.4934891582875485E-002 - 752.00000000000000 2.4606394807498121E-002 - 753.00000000000000 2.4283829718863833E-002 - 754.00000000000000 2.3967053046550134E-002 - 755.00000000000000 2.3655872860561922E-002 - 756.00000000000000 2.3350182231881594E-002 - 757.00000000000000 2.3049960648894439E-002 - 758.00000000000000 2.2754974710119519E-002 - 759.00000000000000 2.2465111410781242E-002 - 760.00000000000000 2.2180343954422831E-002 - 761.00000000000000 2.1900515822827798E-002 - 762.00000000000000 2.1625485501298048E-002 - 763.00000000000000 2.1355181376686905E-002 - 764.00000000000000 2.1089552989145281E-002 - 765.00000000000000 2.0828421932410007E-002 - 766.00000000000000 2.0571693948829572E-002 - 767.00000000000000 2.0319363398577487E-002 - 768.00000000000000 2.0071267394891165E-002 - 769.00000000000000 1.9827303166308288E-002 - 770.00000000000000 1.9587425750335268E-002 - 771.00000000000000 1.9351564164693955E-002 - 772.00000000000000 1.9119582845056663E-002 - 773.00000000000000 1.8891403180723781E-002 - 774.00000000000000 1.8667033597476981E-002 - 775.00000000000000 1.8446310906346790E-002 - 776.00000000000000 1.8229161735692140E-002 - 777.00000000000000 1.8015561186808252E-002 - 778.00000000000000 1.7805424714368349E-002 - 779.00000000000000 1.7598650211370175E-002 - 780.00000000000000 1.7395183022348493E-002 - 781.00000000000000 1.7195007972322103E-002 - 782.00000000000000 1.6997998197970241E-002 - 783.00000000000000 1.6804091769382998E-002 - 784.00000000000000 1.6613278828341193E-002 - 785.00000000000000 1.6425466396661478E-002 - 786.00000000000000 1.6240578543692329E-002 - 787.00000000000000 1.6058579067756845E-002 - 788.00000000000000 1.5879435742429140E-002 - 789.00000000000000 1.5703050465128657E-002 - 790.00000000000000 1.5529370730227140E-002 - 791.00000000000000 1.5358397879165835E-002 - 792.00000000000000 1.5190034269608002E-002 - 793.00000000000000 1.5024224474121998E-002 - 794.00000000000000 1.4860946483311042E-002 - 795.00000000000000 1.4700155988965073E-002 - 796.00000000000000 1.4541777709063007E-002 - 797.00000000000000 1.4385769352419501E-002 - 798.00000000000000 1.4232133279758852E-002 - 799.00000000000000 1.4080777175136588E-002 - 800.00000000000000 1.3931659264211801E-002 - 801.00000000000000 1.3784768419054131E-002 - 802.00000000000000 1.3640052020327663E-002 - 803.00000000000000 1.3497452922874676E-002 - 804.00000000000000 1.3356941903011775E-002 - 805.00000000000000 1.3218507588744160E-002 - 806.00000000000000 1.3082077478306328E-002 - 807.00000000000000 1.2947615802451686E-002 - 808.00000000000000 1.2815119736236631E-002 - 809.00000000000000 1.2684531206552191E-002 - 810.00000000000000 1.2555807498173440E-002 - 811.00000000000000 1.2428929623850334E-002 - 812.00000000000000 1.2303876041117205E-002 - 813.00000000000000 1.2180590192056199E-002 - 814.00000000000000 1.2059041335108758E-002 - 815.00000000000000 1.1939232936385482E-002 - 816.00000000000000 1.1821103628580416E-002 - 817.00000000000000 1.1704622182492984E-002 - 818.00000000000000 1.1589777611929437E-002 - 819.00000000000000 1.1466568696423448E-002 - 820.00000000000000 1.1354927962697966E-002 - 821.00000000000000 1.1244827629165965E-002 - 822.00000000000000 1.1136267419006149E-002 - 823.00000000000000 1.1029192759102888E-002 - 824.00000000000000 1.0923578740838847E-002 - 825.00000000000000 1.0819420610610727E-002 - 826.00000000000000 1.0716684160802958E-002 - 827.00000000000000 1.0615336047055288E-002 - 828.00000000000000 1.0515360090319071E-002 - 829.00000000000000 1.0416747671761928E-002 - 830.00000000000000 1.0319455596454462E-002 - 831.00000000000000 1.0223462279344854E-002 - 832.00000000000000 1.0128767796266234E-002 - 833.00000000000000 1.0035334342908380E-002 - 834.00000000000000 9.9431369401379172E-003 - 835.00000000000000 9.8521653803766446E-003 - 836.00000000000000 9.7624047371550511E-003 - 837.00000000000000 9.6738210986040789E-003 - 838.00000000000000 9.5863957017491268E-003 - 839.00000000000000 9.5001323383326463E-003 - 840.00000000000000 9.4149908942391496E-003 - 841.00000000000000 9.3309531418945338E-003 - 842.00000000000000 9.2480136075845411E-003 - 843.00000000000000 9.1661526665213454E-003 - 844.00000000000000 9.0853439879362823E-003 - 845.00000000000000 9.0055738683715945E-003 - 846.00000000000000 8.9268409680820643E-003 - 847.00000000000000 8.8491118180304817E-003 - 848.00000000000000 8.7723709823741593E-003 - 849.00000000000000 8.6966167262425478E-003 - 850.00000000000000 8.6218259994250666E-003 - 851.00000000000000 8.5479786659088206E-003 - 852.00000000000000 8.4750655406575694E-003 - 853.00000000000000 8.4030800293105300E-003 - 854.00000000000000 8.3319954891620095E-003 - 855.00000000000000 8.2617984107957974E-003 - 856.00000000000000 8.1924899971071666E-003 - 857.00000000000000 8.1240447784226479E-003 - 858.00000000000000 8.0564476814267566E-003 - 859.00000000000000 2.6443379644924738E-003 - 860.00000000000000 2.6183093288268604E-003 - 861.00000000000000 2.5926844556095809E-003 - 862.00000000000000 2.5674567580748066E-003 - 863.00000000000000 2.5426197828925666E-003 - 864.00000000000000 2.5181672072191520E-003 - 865.00000000000000 2.4940928358221817E-003 - 866.00000000000000 2.4703905982782432E-003 - 867.00000000000000 2.4470545462411133E-003 - 868.00000000000000 2.4240788507786464E-003 - 869.00000000000000 2.4014577997764183E-003 - 870.00000000000000 2.3791857954063222E-003 - 871.00000000000000 2.3572573516583463E-003 - 872.00000000000000 2.3356670919338234E-003 - 873.00000000000000 2.3144097466984742E-003 - 874.00000000000000 2.2934801511936545E-003 - 875.00000000000000 2.2728732432042219E-003 - 876.00000000000000 2.2525840608815196E-003 - 877.00000000000000 2.2326077406199878E-003 - 878.00000000000000 2.2129395149859928E-003 - 879.00000000000000 2.1935747106974642E-003 - 880.00000000000000 2.1745087466530297E-003 - 881.00000000000000 2.1557371320092872E-003 - 882.00000000000000 2.1372554643050061E-003 - 883.00000000000000 2.1190594276309835E-003 - 884.00000000000000 2.1011447908443766E-003 - 885.00000000000000 2.0835074058263544E-003 - 886.00000000000000 2.0661432057819409E-003 - 887.00000000000000 2.0490482035809407E-003 - 888.00000000000000 2.0322184901389148E-003 - 889.00000000000000 2.0156502328371492E-003 - 890.00000000000000 1.9993396739806271E-003 - 891.00000000000000 1.9832831292930296E-003 - 892.00000000000000 1.9674769864478198E-003 - 893.00000000000000 1.9519177036344986E-003 - 894.00000000000000 1.9366018081591314E-003 - 895.00000000000000 1.9215258950782824E-003 - 896.00000000000000 1.9066866258655247E-003 - 897.00000000000000 1.8920807271096969E-003 - 898.00000000000000 1.8777049892441181E-003 - 899.00000000000000 1.8635562653059900E-003 - 900.00000000000000 1.8496314697252390E-003 - 901.00000000000000 1.8359275771420555E-003 - 902.00000000000000 1.8224416212524442E-003 - 903.00000000000000 1.8091706936810869E-003 - 904.00000000000000 1.7961119428808378E-003 - 905.00000000000000 1.7832625730582283E-003 - 906.00000000000000 1.7706198431243151E-003 - 907.00000000000000 1.7581810656702973E-003 - 908.00000000000000 1.7459436059672679E-003 - 909.00000000000000 1.7339048809895405E-003 - 910.00000000000000 1.7220623584609926E-003 - 911.00000000000000 1.7104135559238519E-003 - 912.00000000000000 1.6989560398294184E-003 - 913.00000000000000 1.6876874246501943E-003 - 914.00000000000000 1.6766053720129090E-003 - 915.00000000000000 1.6657075898519639E-003 - 916.00000000000000 1.6549918315828139E-003 - 917.00000000000000 1.6444558952948157E-003 - 918.00000000000000 1.6340976229631112E-003 - 919.00000000000000 1.6239148996790818E-003 - 920.00000000000000 1.6139056528989722E-003 - 921.00000000000000 1.6040678517102553E-003 - 922.00000000000000 1.5943995061153376E-003 - 923.00000000000000 1.5848986663322198E-003 - 924.00000000000000 1.5755634221117198E-003 - 925.00000000000000 1.5663919020709040E-003 - 926.00000000000000 1.5573822730423456E-003 - 927.00000000000000 1.5485327394388858E-003 - 928.00000000000000 1.5398415426335313E-003 - 929.00000000000000 1.5313069603541743E-003 - 930.00000000000000 1.5229273060928053E-003 - 931.00000000000000 1.5147009285289086E-003 - 932.00000000000000 1.5066262109667365E-003 - 933.00000000000000 1.4987015707861599E-003 - 934.00000000000000 1.4909254589068135E-003 - 935.00000000000000 1.4832963592652608E-003 - 936.00000000000000 1.4758127883048875E-003 - 937.00000000000000 1.4684732944782826E-003 - 938.00000000000000 1.4612764577618328E-003 - 939.00000000000000 1.4542208891822866E-003 - 940.00000000000000 1.4473052303550491E-003 - 941.00000000000000 1.4405281530339581E-003 - 942.00000000000000 1.4338883586723259E-003 - 943.00000000000000 1.4273845779950217E-003 - 944.00000000000000 1.4210155705813678E-003 - 945.00000000000000 1.4147801244586476E-003 - 946.00000000000000 1.4086770557060206E-003 - 947.00000000000000 1.4027052080686437E-003 - 948.00000000000000 1.3968634525818040E-003 - 949.00000000000000 1.3911506872048797E-003 - 950.00000000000000 1.3855658364649425E-003 - 951.00000000000000 1.3801078511098319E-003 - 952.00000000000000 1.3747757077705212E-003 - 953.00000000000000 1.3695684086326135E-003 - 954.00000000000000 1.3644849811168085E-003 - 955.00000000000000 1.3595244775681770E-003 - 956.00000000000000 1.3546859749540999E-003 - 957.00000000000000 1.3499685745707120E-003 - 958.00000000000000 1.3453714017577245E-003 - 959.00000000000000 1.3408936056214739E-003 - 960.00000000000000 1.3365343587660638E-003 - 961.00000000000000 1.3322928570324861E-003 - 962.00000000000000 1.3281683192455727E-003 - 963.00000000000000 1.3241599869686746E-003 - 964.00000000000000 1.3202671242659397E-003 - 965.00000000000000 1.3164890174720873E-003 - 966.00000000000000 1.3128249749695513E-003 - 967.00000000000000 1.3092743269729082E-003 - 968.00000000000000 1.3058364253204665E-003 - 969.00000000000000 1.3025106432729382E-003 - 970.00000000000000 1.2992963753190782E-003 - 971.00000000000000 1.2961930369882163E-003 - 972.00000000000000 1.2932000646695839E-003 - 973.00000000000000 1.2903169154383515E-003 - 974.00000000000000 1.2875430668882997E-003 - 975.00000000000000 1.2848780169710419E-003 - 976.00000000000000 1.2823212838417191E-003 - 977.00000000000000 1.2798724057111101E-003 - 978.00000000000000 1.2775309407040661E-003 - 979.00000000000000 1.2752964667242241E-003 - 980.00000000000000 1.2731685813249238E-003 - 981.00000000000000 1.2711469015862706E-003 - 982.00000000000000 1.2692310639982930E-003 - 983.00000000000000 1.2674207243501341E-003 - 984.00000000000000 1.2657155576252257E-003 - 985.00000000000000 1.2641152579024033E-003 - 986.00000000000000 1.2626195382629108E-003 - 987.00000000000000 1.2612281307032500E-003 - 988.00000000000000 1.2599407860538437E-003 - 989.00000000000000 1.2587572739034647E-003 - 990.00000000000000 1.2576773825294040E-003 - 991.00000000000000 1.2567009188333385E-003 - 992.00000000000000 1.2558277082828800E-003 - 993.00000000000000 1.2550575948587633E-003 - 994.00000000000000 1.2543904410076655E-003 - 995.00000000000000 1.2538261276006199E-003 - 996.00000000000000 1.2533645538970216E-003 - 997.00000000000000 1.2530056375141877E-003 - 998.00000000000000 1.2527493144024800E-003 - 999.00000000000000 1.2525955388259645E-003 - 1000.0000000000000 1.2525442833486017E-003 From 51270403eb0ea4e02d8260d206d09587516e133b Mon Sep 17 00:00:00 2001 From: David A Minton Date: Thu, 25 Apr 2024 11:46:53 -0400 Subject: [PATCH 37/42] Updated the ray test input file --- examples/ray-generation-test-environment/ctem.in | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/ray-generation-test-environment/ctem.in b/examples/ray-generation-test-environment/ctem.in index dfd33eb2..758debd4 100644 --- a/examples/ray-generation-test-environment/ctem.in +++ b/examples/ray-generation-test-environment/ctem.in @@ -22,7 +22,7 @@ runtype single ! Run type: options are normal / seed 1108267 ! Random number generator seed gridsize 1000 ! Size of grid in pixels numlayers 10 ! Number of perched layers -pix 1.0e2 ! Pixel size (m) +pix 6.16e3 ! Pixel size (m) mat rock ! Material (rock or ice) ! Bedrock scaling parameters mu_b 0.41d0 ! Experimentally derived parameter for bedrock crater scaling law @@ -73,12 +73,12 @@ Kd1 0.00312669649143281 psi 2.000 fe 10.0 dorays T -ejecta_truncation 100.0 +ejecta_truncation 10.0 ! Testing input. These are used to perform non-Monte Carlo tests. testflag T ! Set to T to create a single crater with user-defined impactor properties -testimp 1.e2 ! Diameter of test impactor (m) -testvel 15.e3 ! Velocity of test crater (m/s) +testimp 15e3 ! Diameter of test impactor (m) +testvel 18.3e3 ! Velocity of test crater (m/s) testang 90.0 ! Impact angle of test crater (deg) - Default 90.0 testxoffset 0.0d0 ! x-axis offset of crater center from grid center (m) - Default 0.0 testyoffset 0.0d0 ! y-axis offset of crater center from grid center (m) - Default 0.0 From 156518f5776578b92176b738bbda76535f9f69a9 Mon Sep 17 00:00:00 2001 From: David A Minton Date: Thu, 25 Apr 2024 12:02:16 -0400 Subject: [PATCH 38/42] Added explicit DP type to calcualtion. --- src/ejecta/ejecta_emplace.f90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ejecta/ejecta_emplace.f90 b/src/ejecta/ejecta_emplace.f90 index 8a7568e0..c5724985 100644 --- a/src/ejecta/ejecta_emplace.f90 +++ b/src/ejecta/ejecta_emplace.f90 @@ -130,7 +130,7 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ real(SP) :: age_mean ! Crater ray parameters - real(DP) :: rray != 48_DP ! "L16" in Minton et al. (2019) + real(DP) :: rray != 48.0_DP ! "L16" in Minton et al. (2019) integer(I4B) :: Nraymax = 5 real(DP) :: fpeak = 8000_DP ! narrow ray: rw0 propto 1/4 real(DP) :: rayp = 2.0_DP @@ -139,8 +139,8 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ real(DP) :: l1 - rray = (11.95*(crater%frad/1000)**1.32)/(crater%frad/1000) - l1 = (5.32*(crater%frad/1000)**1.27)/(crater%frad/1000) + rray = (11.95_DP*(crater%frad/1000)**1.32)/(crater%frad/1000) + l1 = (5.32_DP*(crater%frad/1000)**1.27)/(crater%frad/1000) ! Executable code From 0bdaa68a6fc970968c325df62a8817b73fb0c93c Mon Sep 17 00:00:00 2001 From: David A Minton Date: Thu, 25 Apr 2024 12:23:22 -0400 Subject: [PATCH 39/42] Updated ray model so that the longest ray is set to the truncation radius --- examples/ray-generation-test-environment/ctem.in | 2 +- src/ejecta/ejecta_emplace.f90 | 5 ++--- src/ejecta/ejecta_ray_pattern.f90 | 1 - 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/examples/ray-generation-test-environment/ctem.in b/examples/ray-generation-test-environment/ctem.in index 758debd4..48d1a8f5 100644 --- a/examples/ray-generation-test-environment/ctem.in +++ b/examples/ray-generation-test-environment/ctem.in @@ -73,7 +73,7 @@ Kd1 0.00312669649143281 psi 2.000 fe 10.0 dorays T -ejecta_truncation 10.0 +ejecta_truncation 50.0 ! Testing input. These are used to perform non-Monte Carlo tests. testflag T ! Set to T to create a single crater with user-defined impactor properties diff --git a/src/ejecta/ejecta_emplace.f90 b/src/ejecta/ejecta_emplace.f90 index c5724985..5186f6cd 100644 --- a/src/ejecta/ejecta_emplace.f90 +++ b/src/ejecta/ejecta_emplace.f90 @@ -139,9 +139,8 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ real(DP) :: l1 - rray = (11.95_DP*(crater%frad/1000)**1.32)/(crater%frad/1000) l1 = (5.32_DP*(crater%frad/1000)**1.27)/(crater%frad/1000) - + rray = user%ejecta_truncation ! Executable code @@ -179,7 +178,7 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,cumulativ if (inc >= user%gridsize / 2) then if (user%testflag) then write(*,*) 'Big ejecta: fcrat =',crater%fcrat, ' Ej/S =',(crater%ejdispx*user%pix)/domain%side, ' Ejrim =', crater%ejrim - write(*,*) 'L16 = ', rray, 'L1 = ', l1 + write(*,*) 'Rray = ', rray, 'L1 = ', l1 else write(message,'("Ejb: Dc=",ES9.2," Ej/S=",F0.3)') crater%fcrat,(crater%ejdispx*user%pix)/domain%side call io_updatePbar(message) diff --git a/src/ejecta/ejecta_ray_pattern.f90 b/src/ejecta/ejecta_ray_pattern.f90 index 11868f6e..41f26bbe 100644 --- a/src/ejecta/ejecta_ray_pattern.f90 +++ b/src/ejecta/ejecta_ray_pattern.f90 @@ -108,7 +108,6 @@ subroutine ejecta_ray_pattern(user,surf,crater,inc,xi,xf,yi,yf,rray,Nraymax,fpea xbar = xp - crater%xl ybar = yp - crater%yl - !areafrac = util_area_intersection(user%ejecta_truncation * crater%frad,xbar,ybar,user%pix) areafrac = util_area_intersection(rray * crater%frad,xbar,ybar,user%pix) r = sqrt(xbar**2 + ybar**2) / crater%frad theta = mod(atan2(ybar,xbar) + pi + rn * 2 * pi,2 * pi) From 2a51b1adb560f6f900c477228b118d1112c8ed9e Mon Sep 17 00:00:00 2001 From: David A Minton Date: Thu, 25 Apr 2024 14:10:35 -0400 Subject: [PATCH 40/42] Updated the regolith image generator to use a the magma color map instead of spectral. Also updated the ray generation initial conditions to make a higher resolution example. --- ctem/util.py | 2 +- examples/ray-generation-test-environment/ctem.in | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ctem/util.py b/ctem/util.py index 00922421..0597c9a4 100644 --- a/ctem/util.py +++ b/ctem/util.py @@ -136,7 +136,7 @@ def image_regolith(user, regolith): height = user['gridsize'] / dpi width = height fig = plt.figure(figsize=(width, height), dpi=dpi) - fig.figimage(regolith_scaled, cmap=cm.nipy_spectral, origin='lower') + fig.figimage(regolith_scaled, cmap=cm.magma, origin='lower') plt.savefig(filename) plt.close() diff --git a/examples/ray-generation-test-environment/ctem.in b/examples/ray-generation-test-environment/ctem.in index 48d1a8f5..c297424a 100644 --- a/examples/ray-generation-test-environment/ctem.in +++ b/examples/ray-generation-test-environment/ctem.in @@ -20,9 +20,9 @@ runtype single ! Run type: options are normal / ! CTEM required inputs seed 1108267 ! Random number generator seed -gridsize 1000 ! Size of grid in pixels +gridsize 2000 ! Size of grid in pixels numlayers 10 ! Number of perched layers -pix 6.16e3 ! Pixel size (m) +pix 10.0 ! Pixel size (m) mat rock ! Material (rock or ice) ! Bedrock scaling parameters mu_b 0.41d0 ! Experimentally derived parameter for bedrock crater scaling law @@ -73,11 +73,11 @@ Kd1 0.00312669649143281 psi 2.000 fe 10.0 dorays T -ejecta_truncation 50.0 +ejecta_truncation 60.0 ! Testing input. These are used to perform non-Monte Carlo tests. testflag T ! Set to T to create a single crater with user-defined impactor properties -testimp 15e3 ! Diameter of test impactor (m) +testimp 15.0 ! Diameter of test impactor (m) testvel 18.3e3 ! Velocity of test crater (m/s) testang 90.0 ! Impact angle of test crater (deg) - Default 90.0 testxoffset 0.0d0 ! x-axis offset of crater center from grid center (m) - Default 0.0 From 32ca9b5ede32137b629d0dd7669e0f2ce20bbf30 Mon Sep 17 00:00:00 2001 From: David A Minton Date: Mon, 10 Jun 2024 15:49:14 -0400 Subject: [PATCH 41/42] Removed coarray fortran stuff from the cmake script, as it is a leftover from the Swiftest project --- CMakeLists.txt | 1 - cmake/Modules/SetParallelizationLibrary.cmake | 15 +++------------ 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ea1ab76f..f6cd01ba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,6 @@ ELSE () ENDIF () # Set some options the user may choose -OPTION(USE_COARRAY "Use Coarray Fortran for parallelization of test particles" OFF) OPTION(USE_OPENMP "Use OpenMP for parallelization" ON) OPTION(USE_SIMD "Use SIMD vectorization" ON) OPTION(BUILD_SHARED_LIBS "Build using shared libraries" ON) diff --git a/cmake/Modules/SetParallelizationLibrary.cmake b/cmake/Modules/SetParallelizationLibrary.cmake index 505a77d6..71a382a9 100644 --- a/cmake/Modules/SetParallelizationLibrary.cmake +++ b/cmake/Modules/SetParallelizationLibrary.cmake @@ -17,20 +17,11 @@ IF (USE_OPENMP) ENDIF (NOT OpenMP_Fortran_FLAGS) ENDIF (USE_OPENMP) -IF (USE_COARRAY) - IF (NOT Coarray_Fortran_FLAGS) - FIND_PACKAGE (Coarray_Fortran) - IF (NOT Coarray_Fortran_FLAGS) - MESSAGE (FATAL_ERROR "Fortran compiler does not support Coarrays") - ENDIF (NOT Coarray_Fortran_FLAGS) - ENDIF (NOT Coarray_Fortran_FLAGS) -ENDIF (USE_COARRAY) -IF (NOT USE_OPENMP AND NOT USE_COARRAY) - # Turn off both OpenMP and CAF +IF (NOT USE_OPENMP) + # Turn off OpenMP SET (OMP_NUM_PROCS 0 CACHE STRING "Number of processors OpenMP may use" FORCE) UNSET (OpenMP_Fortran_FLAGS CACHE) - UNSET (Coarray_Fortran_FLAGS CACHE) UNSET (GOMP_Fortran_LINK_FLAGS CACHE) -ENDIF (NOT USE_OPENMP AND NOT USE_COARRAY) +ENDIF () From e846d0b592a98a795e9065f9f58f67a7a3f6e41b Mon Sep 17 00:00:00 2001 From: David Minton Date: Mon, 10 Jun 2024 15:50:23 -0400 Subject: [PATCH 42/42] Added util import to ctem project import --- ctem/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ctem/__init__.py b/ctem/__init__.py index 2e8ce2a0..81f6944a 100644 --- a/ctem/__init__.py +++ b/ctem/__init__.py @@ -1 +1,2 @@ -from ctem.driver import * \ No newline at end of file +from ctem.driver import * +from ctem import util \ No newline at end of file