From 79c3f1a7abe1e515d3c4527c9bed0885b9ac1068 Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 10 Feb 2022 16:58:07 -0500 Subject: [PATCH 01/32] Improved parameters so that the rim is no longer expanded so much when realistic is turned on --- src/crater/crater_realistic_topography.f90 | 25 +++++++++++++--------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/crater/crater_realistic_topography.f90 b/src/crater/crater_realistic_topography.f90 index ed1b29c4..115601ff 100644 --- a/src/crater/crater_realistic_topography.f90 +++ b/src/crater/crater_realistic_topography.f90 @@ -314,10 +314,10 @@ subroutine complex_wall_texture(user,surf,crater,domain,deltaMtot) integer(I4B), parameter :: num_octaves = 10 ! Number of Perlin noise octaves integer(I4B), parameter :: offset = 4000 ! Scales the random xy-offset so that each crater's random noise is unique real(DP), parameter :: xy_noise_fac = 3.0_DP ! Spatial "size" of noise features at the first octave - real(DP), parameter :: noise_height = 7.0e-3_DP ! Spatial "size" of noise features at the first octave + real(DP), parameter :: noise_height = 3.0e-3_DP ! Spatial "size" of noise features at the first octave real(DP), parameter :: freq = 2.0_DP ! Spatial size scale factor multiplier at each octave level real(DP), parameter :: pers = 1.20_DP ! The relative size scaling at each octave level - real(DP), parameter :: outer_wall_size = 2.1_DP + real(DP), parameter :: outer_wall_size = 1.2_DP !Executable code call random_number(rn) @@ -344,7 +344,7 @@ subroutine complex_wall_texture(user,surf,crater,domain,deltaMtot) areafrac = 1.0 - util_area_intersection(0.3_DP * crater%floordiam,xbar,ybar,user%pix) areafrac = areafrac * util_area_intersection(outer_wall_size * crater%frad,xbar,ybar,user%pix) areafrac = areafrac * min((r / flr)**12,1.0_DP) ! Smooth out interface between wall and floor - areafrac = areafrac * max(min(2._DP - r,1.0_DP),0.0_DP) ! Smooth out region outside of the rim + areafrac = areafrac * max(min(outer_wall_size- r,1.0_DP),0.0_DP) ! Smooth out region outside of the rim ! Add some roughness to the walls noise = 0.0_DP @@ -356,7 +356,6 @@ subroutine complex_wall_texture(user,surf,crater,domain,deltaMtot) end do newdem = newdem + noise * areafrac if (r < flr) newdem = max(newdem,crater%melev - crater%floordepth) - if (r > 1.1_DP) newdem = max(newdem,newdem + areafrac * crater%ejrim * r**(-3)) elchange = newdem - surf(xpi,ypi)%dem deltaMtot = deltaMtot + elchange @@ -405,6 +404,7 @@ subroutine complex_terrace(user,surf,crater,deltaMtot) real(DP) :: router ! The radius of the terrace outer edge real(DP) :: rinner ! The radius of the terrace outer edge real(DP) :: upshift,dfloor + real(DP) :: h_scallop_profile ! Profile of the scallop wall integer(I4B) :: num_oct_tfloor real(DP) :: noise_height_tfloor real(DP) :: freq_tfloor @@ -424,7 +424,9 @@ subroutine complex_terrace(user,surf,crater,deltaMtot) nscallops = 16 scallop_p = 0.6_DP scallop_width = 0.20_DP - rimfloor = crater%melev + h_scallop_profile = 2.0_DP + rimfloor = crater%melev + 0.5_DP * crater%rimheight + upshift = 0.0_DP num_oct_tfloor = 4 noise_height_tfloor = crater%floordepth / nterraces @@ -441,13 +443,12 @@ subroutine complex_terrace(user,surf,crater,deltaMtot) !^^^^^^^^^^^^^^^ rad = 2.0_DP * crater%frad - upshift = 0._DP inc = max(min(nint(rad / user%pix),PBCLIM*user%gridsize),1) + 1 crater%maxinc = max(crater%maxinc,inc) flr = crater%floordiam / crater%fcrat - do terrace = 1, nterraces + do terrace = 1, nterraces router = flr + (1._DP - flr) * (terrace / real(nterraces,kind=DP))**(terracefac) ! The radius of the outer edge of the terrace rinner = flr + (1._DP - flr) * ((terrace - 1) / real(nterraces,kind=DP))**(terracefac) ! The radius of the inner edge of the terrace @@ -484,7 +485,11 @@ subroutine complex_terrace(user,surf,crater,deltaMtot) isterrace = 1.0_DP - noise < hprof - tprof = crater_profile(user,crater,rinner) * (r/rinner)**2 + tnoise ! This is the floor profile that replaces the old one at each terrace + if (r < 1.0_DP) then + tprof = crater_profile(user,crater,rinner) * (r/rinner)**h_scallop_profile + tnoise ! This is the floor profile that replaces the old one at each terrace + else + tprof = (crater_profile(user,crater,rinner) + crater%ejrim * (rinner)**(-EJPROFILE)) + tnoise ! This is the floor profile that replaces the old one at each terrace + end if if (isterrace) then newdem = min(tprof,newdem) @@ -517,7 +522,7 @@ subroutine complex_terrace(user,surf,crater,deltaMtot) r = sqrt(xbar**2 + ybar**2) / crater%frad ! Make scalloped rim - znoise = scallop_width**(1._DP / (2 * scallop_p)) + znoise = (scallop_width)**(1._DP / (2 * scallop_p)) xynoise = (nscallops / PI) / crater%fcrat dnoise = util_perlin_noise(xynoise * xbar + offset * rn(1), & xynoise * ybar + offset * rn(2)) * znoise @@ -563,7 +568,7 @@ subroutine complex_terrace(user,surf,crater,deltaMtot) r = sqrt(xbar**2 + ybar**2) / crater%frad if (r > flr) then - newdem = newdem + upshift * max(min(3.0_DP - 2 * r,1.0_DP),0.0_DP) + newdem = newdem + upshift * max(min(3.0_DP - 2 * r**2,1.0_DP),0.0_DP) elchange = newdem - surf(xpi,ypi)%dem deltaMtot = deltaMtot + elchange surf(xpi,ypi)%dem = newdem From 64ea812f24002e57c114067f648a71ed53f3f072 Mon Sep 17 00:00:00 2001 From: David Minton Date: Fri, 11 Feb 2022 13:03:35 -0500 Subject: [PATCH 02/32] Made sure to compute crater%ejrim before calling crater_profile for the first time --- src/crater/crater_dimensions.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crater/crater_dimensions.f90 b/src/crater/crater_dimensions.f90 index 9a45e04f..fc6de8c9 100644 --- a/src/crater/crater_dimensions.f90 +++ b/src/crater/crater_dimensions.f90 @@ -68,8 +68,8 @@ subroutine crater_dimensions(user,crater,domain) ! Calculate the radius where the inner wall meets the original pre-existing surface ! This is used to demark the location where excavation transitions to deposition - crater%ejrad = max(crater_profile_find_r_inner_wall(user,crater) * crater%frad, crater%rad) crater%ejrim = 0.14_DP * (crater%fcrat * 1e-3 * 0.5_DP)**(0.74_DP) * 1e3_DP ! McGetchin et al. (1973) Thickness of ejecta at rim + crater%ejrad = max(crater_profile_find_r_inner_wall(user,crater) * crater%frad, crater%rad) !find rim for counting purposes crater%frim = RIMFAC * crater%frad From b13345c5ec25a4bbf66d4b07990996704ab3bf05 Mon Sep 17 00:00:00 2001 From: David Minton Date: Wed, 16 Feb 2022 10:59:01 -0500 Subject: [PATCH 03/32] Restructured python folder with the aim of making it a package --- examples/morphology_test_cases/.DS_Store | Bin 10244 -> 0 bytes python/.idea/.gitignore | 3 + python/{ => ctem/ctem}/NPF.py | 0 python/ctem/ctem/__init__.py | 3 + python/{ => ctem/ctem}/ctem_draw_surf.py | 0 python/{ => ctem/ctem}/ctem_driver.py | 458 +++++++++---------- python/{ => ctem/ctem}/ctem_io_readers.py | 286 ++++++------ python/{ => ctem/ctem}/ctem_io_writers.py | 526 +++++++++++----------- python/ctem/ctem/ctem_viewer_3d.py | 1 + python/{ => ctem/ctem}/dist_reader.py | 0 python/{ => ctem}/readme.txt | 44 +- python/ctem/setup.py | 6 + 12 files changed, 670 insertions(+), 657 deletions(-) delete mode 100644 examples/morphology_test_cases/.DS_Store create mode 100644 python/.idea/.gitignore rename python/{ => ctem/ctem}/NPF.py (100%) create mode 100644 python/ctem/ctem/__init__.py rename python/{ => ctem/ctem}/ctem_draw_surf.py (100%) rename python/{ => ctem/ctem}/ctem_driver.py (97%) rename python/{ => ctem/ctem}/ctem_io_readers.py (97%) rename python/{ => ctem/ctem}/ctem_io_writers.py (97%) create mode 100644 python/ctem/ctem/ctem_viewer_3d.py rename python/{ => ctem/ctem}/dist_reader.py (100%) rename python/{ => ctem}/readme.txt (96%) create mode 100644 python/ctem/setup.py diff --git a/examples/morphology_test_cases/.DS_Store b/examples/morphology_test_cases/.DS_Store deleted file mode 100644 index 3a3743e9d35528ba4bc9041c04e4f259ecc0fba7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10244 zcmeHMTWl298UFvlz>GcMvEu-{c)bgbu>%X(#$cP`WPObRCw8%oFCo}_ncz{!GtSQL znqY`rdV6R{+dNc>(}zYhO;dVTE{*!oG`*$dAyMKgAyTT+mq@*+>V>2aRonlZGrQQk zMrtKX^~0<*^UwLu`OnPx=ljk#=PUqVM>^2}5CQ<14rVo#PAmLaJv$11lIvlWNbvwB z=x{bR>&(Q=g4UkH%Yc^wF9Ti%ybO35SPK~-&1OHjL|E_aWx&gTmw{Xc*!&QpgV~5{ z=Y{1{2c7s5fNT-D`H!w?9l&Eku8p{MURWMVeTvlsx}oSUF;Ik4eTX$D8*%Ntup%5# zgaf*FMt6mR{O%MN;>`gg!g^;f16~FSGr(xG5#nIOG|VhrzuPgY`BiMjG@Mj@{W~bF zD_Xx{qbwK8#hZ#B7@V?a2UF2h+UbZU?`NffXlg3vUJu!}nY)h0P8#~`gjUgMTdAmF z=}8`JBy?(WYQ(S-_H2ipwh|8SXHZngvLY)J+P1m5LoH3=(1F(03*pdQYh!&l)O6s` zg$s(jwWgu%=;ZXn=jP5|c;rbjGIVDLD9sz`Lg6q?C({`-*)Z4b%MSCs>@bz$5_OY* zX!zvFs5+sQXJ`cdGbzKioRfOeAv>X!IyCB|aoZY5>a2bwZky?8%bC#1;!!i6Hlr!M z-82V{b2|A-op{nV%>mmnST|#%DgA7U)fH5YjyrZT)yX>>HK>2lN=rNX37tAMGI|$v z?P#ccXYH8(j8kr{ zl<}aUCzUb`D??UvT3;;J%1XES{Ql8&%y=kmq#o9)Wm)u9?B{dX!_R336@WTK0(x=+y@W#|+1qD5$fdO+3^%CH%Y>85ZU zQd?y0xH6Iv$ra8D^@yyD#_j28dT2-Z?)JCK+H3M@cH_RNlj@(*ExI=wLT8oVKgRs+ ziG-eTN8s=EACtAW0&ge1(tC3pg!hUei$cnN+1Z@@e7 zK70Uwg}=dv@DcnI*W+f?unfy_J62*91~H5W@enp+C-&jJ*pCA^jHht|qZq?8ID-$N zgDE_RpTbY$XYq6R1$+XZ#09*J-@ckz4pV|)$Y!nbh|-^btJZ}B?*5pUp!_>rVY z<AsbSuTxdhv@oQId94!F42}BxYz=ei z+GfU{+bV9~vNgmg)qEt9!=8X@7M)8`&w;+|)pMY8V&#LBIJUhqpazGD3HsT5Ze}^F zZDh=p7g_5aJJq1Jp12~4yK1Spfp{W{d&0q>CJ{YFvA!XwYU_x63Xd%b2UYj7rBzk6 zA|j!vX$w#h+(LT?b;2kmuQs@^!rO2SuEU=Q-2cWRRB#*az*^i(P`(@6u?xGghv58i z9K<0G=}7`~91}Q=Hi0@xus)BE;5>d3FXHF%QM`m-CTK6&uK zm+*)9GQNth6U49M@AClMw;aIuhe7~n29uU)TW6?-!F~fcU}P0h>}PX5ypaX>yGw*Z zDcM}2ELX${t5GpoJoU9_zW(g1Kjl%7)6Ozc&YgcoSIZJ|Q#qx_3lpN0 z_=xGpY5L4ptp80ja|*e#9>`y#%Ml~j@sE$Hi!=a0C8@8&Sq$Ea8;jiPg9tTd);BhDV6_ z$M87m*nLF%Q}_Vs*d#tkgrDJrpCb+X45^sVFh=w%MDQ1g;;-OO@G8E6?+RSz)G43b z@2!B=tTv6Ugw{ZJ&pqw`7qnhe+1uixQ&nBJw{fZDJowQ zi})pcob=|ad7$eR;M1P&I5Z-;$^_g zz^Z2ei@FB8I;h+1ia-Aj5;;P2Owz%Atlhk@JcLfH3G?&qcq*`cMZQHsK6fvK*GJrT u^TP6QisRvAc{o`X&f1IJ{8j%mAb({-duiVKf0Z}4y!AiZ;9j%q|Nj8$k6q>f diff --git a/python/.idea/.gitignore b/python/.idea/.gitignore new file mode 100644 index 00000000..26d33521 --- /dev/null +++ b/python/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/python/NPF.py b/python/ctem/ctem/NPF.py similarity index 100% rename from python/NPF.py rename to python/ctem/ctem/NPF.py diff --git a/python/ctem/ctem/__init__.py b/python/ctem/ctem/__init__.py new file mode 100644 index 00000000..67da11db --- /dev/null +++ b/python/ctem/ctem/__init__.py @@ -0,0 +1,3 @@ +from ctem.ctem_io_readers import * +from ctem.ctem_io_writers import * +from ctem.ctem_driver import * diff --git a/python/ctem_draw_surf.py b/python/ctem/ctem/ctem_draw_surf.py similarity index 100% rename from python/ctem_draw_surf.py rename to python/ctem/ctem/ctem_draw_surf.py diff --git a/python/ctem_driver.py b/python/ctem/ctem/ctem_driver.py similarity index 97% rename from python/ctem_driver.py rename to python/ctem/ctem/ctem_driver.py index 712a6157..29057053 100644 --- a/python/ctem_driver.py +++ b/python/ctem/ctem/ctem_driver.py @@ -1,229 +1,229 @@ -#!/usr/local/bin/python -# -#Cratered Terrain Evolution Model driver -# -#Original IDL design: Jim Richardson, Arecibo Observatory -#Revised IDL design: David Minton, Purdue University -#Re-engineered design and Python implementation: Matthew Route, Purdue University -#August 2016 - -#Import general purpose modules -import numpy -import os -import subprocess -import shutil - -#Import CTEM modules -import ctem_io_readers -import ctem_io_writers - -#Create and initialize data dictionaries for parameters and options from CTEM.in -notset = '-NOTSET-' -currentdir = os.getcwd() + os.sep - -parameters={'restart': notset, - 'runtype': notset, - 'popupconsole': notset, - 'saveshaded': notset, - 'saverego': notset, - 'savepres': notset, - 'savetruelist': notset, - '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': 'ctem.in', - 'datfile': 'ctem.dat', - 'impfile': notset, - 'sfdcompare': notset, - 'sfdfile': notset} - -#Read ctem.in to initialize parameter values based on user input -ctem_io_readers.read_ctemin(parameters,notset) - -#Read sfdcompare file -sfdfile = parameters['workingdir'] + parameters['sfdcompare'] -ph1 = ctem_io_readers.read_formatted_ascii(sfdfile, skip_lines = 0) - -#Set up data arrays -seedarr = numpy.zeros(100, dtype = numpy.int) -seedarr[0] = parameters['seed'] -odist = numpy.zeros([1, 6]) -pdist = numpy.zeros([1, 6]) -tdist = numpy.zeros([1, 6]) -surface_dem = numpy.zeros([parameters['gridsize'], parameters['gridsize']], dtype = numpy.float) -regolith = numpy.zeros([parameters['gridsize'], parameters['gridsize']], dtype =numpy.float) - -#Read production function file -impfile = parameters['workingdir'] + parameters['impfile'] -prodfunction = ctem_io_readers.read_formatted_ascii(impfile, skip_lines = 0) - -#Create impactor production population -area = (parameters['gridsize'] * parameters['pix'])**2 -production = numpy.copy(prodfunction) -production[:,1] = production[:,1] * area * parameters['interval'] - -#Write corrected production function to file -ctem_io_writers.write_production(parameters, production) - -#Starting new or old run? -if (parameters['restart'].upper() == 'F'): - print('Starting a new run') - - if (parameters['runtype'].upper() == 'STATISTICAL'): - parameters['ncount'] = 1 - - #Write ctem.dat file - ctem_io_writers.write_ctemdat(parameters, seedarr) - - else: - parameters['ncount'] = 0 - - #Delete tdistribution file, if it exists - tdist_file = parameters['workingdir'] + 'tdistribution.dat' - if os.path.isfile(tdist_file): - os.remove(tdist_file) - -else: - print('Continuing a previous run') - - #Read surface dem(shaded relief) and ejecta data files - dem_file = parameters['workingdir'] + 'surface_dem.dat' - surface_dem = ctem_io_readers.read_unformatted_binary(dem_file, parameters['gridsize']) - ejecta_file = parameters['workingdir'] + 'surface_ejc.dat' - regolith = ctem_io_readers.read_unformatted_binary(ejecta_file, parameters['gridsize']) - - #Read odistribution, tdistribution, and pdistribution files - ofile = parameters['workingdir'] + 'odistribution.dat' - odist = ctem_io_readers.read_formatted_ascii(ofile, skip_lines = 1) - tfile = parameters['workingdir'] + 'tdistribution.dat' - tdist = ctem_io_readers.read_formatted_ascii(tfile, skip_lines = 1) - pfile = parameters['workingdir'] + 'pdistribution.dat' - pdist = ctem_io_readers.read_formatted_ascii(pfile, skip_lines = 1) - - #Read impact mass from file - massfile = parameters['workingdir'] + 'impactmass.dat' - impact_mass = ctem_io_readers.read_impact_mass(massfile) - - #Read ctem.dat file - ctem_io_readers.read_ctemdat(parameters, seedarr) - -#Open fracdonefile and regodepthfile for writing -filename = parameters['workingdir'] + 'fracdone.dat' -fp_frac = open(filename,'w') -filename = parameters['workingdir'] + 'regolithdepth.dat' -fp_reg = open(filename,'w') - -#Begin CTEM processing loops -print('Beginning loops') - -ctem_io_writers.create_dir_structure(parameters) - -while (parameters['ncount'] <= parameters['numintervals']): - - #Create crater population - if (parameters['ncount'] > 0): - - #Move ctem.dat - forig = parameters['workingdir'] + 'ctem.dat' - fdest = parameters['workingdir'] + 'misc' + os.sep + "ctem%06d.dat" % parameters['ncount'] - shutil.copy2(forig, fdest) - - #Create crater population and display CTEM progress on screen - print(parameters['ncount'], ' Calling FORTRAN routine') - with subprocess.Popen([parameters['workingdir']+'CTEM'], - stdout=subprocess.PIPE, - universal_newlines=True) as p: - for line in p.stdout: - print(line, end='') - - - #Optional: do not pipe CTEM progress to the screen - #subprocess.check_output([parameters['workingdir']+'CTEM']) - - #Read Fortran output - print(parameters['ncount'], ' Reading Fortran output') - - #Read surface dem(shaded relief) and ejecta data files - dem_file = parameters['workingdir'] + 'surface_dem.dat' - surface_dem = ctem_io_readers.read_unformatted_binary(dem_file, parameters['gridsize']) - ejecta_file = parameters['workingdir'] + 'surface_ejc.dat' - regolith = ctem_io_readers.read_unformatted_binary(ejecta_file, parameters['gridsize']) - - #Read odistribution, tdistribution, and pdistribution files - ofile = parameters['workingdir'] + 'odistribution.dat' - odist = ctem_io_readers.read_formatted_ascii(ofile, skip_lines = 1) - tfile = parameters['workingdir'] + 'tdistribution.dat' - tdist = ctem_io_readers.read_formatted_ascii(tfile, skip_lines = 1) - pfile = parameters['workingdir'] + 'pdistribution.dat' - pdist = ctem_io_readers.read_formatted_ascii(pfile, skip_lines = 1) - - #Read impact mass from file - massfile = parameters['workingdir'] + 'impactmass.dat' - impact_mass = ctem_io_readers.read_impact_mass(massfile) - - #Read ctem.dat file - ctem_io_readers.read_ctemdat(parameters, seedarr) - - #Update parameters: mass, curyear, regolith properties - parameters['masstot'] = parameters['masstot'] + impact_mass - - parameters['curyear'] = parameters['curyear'] + parameters['fracdone'] * parameters['interval'] - template = "%(fracdone)9.6f %(curyear)19.12E\n" - fp_frac.write(template % parameters) - - reg_text = "%19.12E %19.12E %19.12E %19.12E\n" % (parameters['curyear'], - numpy.mean(regolith), numpy.amax(regolith), numpy.amin(regolith)) - fp_reg.write(reg_text) - - #Save copy of crater distribution files - ctem_io_writers.copy_dists(parameters) - - #Display results - print(parameters['ncount'], ' Displaying results') - - #Write surface dem, surface ejecta, shaded relief, and rplot data - ctem_io_writers.image_dem(parameters, surface_dem) - if (parameters['saverego'].upper() == 'T'): - ctem_io_writers.image_regolith(parameters, regolith) - if (parameters['saveshaded'].upper() == 'T'): - ctem_io_writers.image_shaded_relief(parameters, surface_dem) - if (parameters['savepres'].upper() == 'T'): - ctem_io_writers.create_rplot(parameters,odist,pdist,tdist,ph1) - - #Update ncount - parameters['ncount'] = parameters['ncount'] + 1 - - if ((parameters['runtype'].upper() == 'STATISTICAL') or (parameters['ncount'] == 1)): - parameters['restart'] = 'F' - parameters['curyear'] = 0.0 - parameters['totalimpacts'] = 0 - parameters['masstot'] = 0.0 - - #Delete tdistribution file, if it exists - tdist_file = parameters['workingdir'] + 'tdistribution.dat' - if os.path.isfile(tdist_file): - os.remove(tdist_file) - - else: - parameters['restart'] = 'T' - - #Write ctem.dat file - ctem_io_writers.write_ctemdat(parameters, seedarr) - -#Close updateable fracdonefile and regodepthfile files -fp_frac.close() -fp_reg.close() +#!/usr/local/bin/python +# +#Cratered Terrain Evolution Model driver +# +#Original IDL design: Jim Richardson, Arecibo Observatory +#Revised IDL design: David Minton, Purdue University +#Re-engineered design and Python implementation: Matthew Route, Purdue University +#August 2016 + +#Import general purpose modules +import numpy +import os +import subprocess +import shutil + +#Import CTEM modules +import ctem_io_readers +import ctem_io_writers + +#Create and initialize data dictionaries for parameters and options from CTEM.in +notset = '-NOTSET-' +currentdir = os.getcwd() + os.sep + +parameters={'restart': notset, + 'runtype': notset, + 'popupconsole': notset, + 'saveshaded': notset, + 'saverego': notset, + 'savepres': notset, + 'savetruelist': notset, + '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': 'ctem.in', + 'datfile': 'ctem.dat', + 'impfile': notset, + 'sfdcompare': notset, + 'sfdfile': notset} + +#Read ctem.in to initialize parameter values based on user input +ctem_io_readers.read_ctemin(parameters,notset) + +#Read sfdcompare file +sfdfile = parameters['workingdir'] + parameters['sfdcompare'] +ph1 = ctem_io_readers.read_formatted_ascii(sfdfile, skip_lines = 0) + +#Set up data arrays +seedarr = numpy.zeros(100, dtype = numpy.int) +seedarr[0] = parameters['seed'] +odist = numpy.zeros([1, 6]) +pdist = numpy.zeros([1, 6]) +tdist = numpy.zeros([1, 6]) +surface_dem = numpy.zeros([parameters['gridsize'], parameters['gridsize']], dtype = numpy.float) +regolith = numpy.zeros([parameters['gridsize'], parameters['gridsize']], dtype =numpy.float) + +#Read production function file +impfile = parameters['workingdir'] + parameters['impfile'] +prodfunction = ctem_io_readers.read_formatted_ascii(impfile, skip_lines = 0) + +#Create impactor production population +area = (parameters['gridsize'] * parameters['pix'])**2 +production = numpy.copy(prodfunction) +production[:,1] = production[:,1] * area * parameters['interval'] + +#Write corrected production function to file +ctem_io_writers.write_production(parameters, production) + +#Starting new or old run? +if (parameters['restart'].upper() == 'F'): + print('Starting a new run') + + if (parameters['runtype'].upper() == 'STATISTICAL'): + parameters['ncount'] = 1 + + #Write ctem.dat file + ctem_io_writers.write_ctemdat(parameters, seedarr) + + else: + parameters['ncount'] = 0 + + #Delete tdistribution file, if it exists + tdist_file = parameters['workingdir'] + 'tdistribution.dat' + if os.path.isfile(tdist_file): + os.remove(tdist_file) + +else: + print('Continuing a previous run') + + #Read surface dem(shaded relief) and ejecta data files + dem_file = parameters['workingdir'] + 'surface_dem.dat' + surface_dem = ctem_io_readers.read_unformatted_binary(dem_file, parameters['gridsize']) + ejecta_file = parameters['workingdir'] + 'surface_ejc.dat' + regolith = ctem_io_readers.read_unformatted_binary(ejecta_file, parameters['gridsize']) + + #Read odistribution, tdistribution, and pdistribution files + ofile = parameters['workingdir'] + 'odistribution.dat' + odist = ctem_io_readers.read_formatted_ascii(ofile, skip_lines = 1) + tfile = parameters['workingdir'] + 'tdistribution.dat' + tdist = ctem_io_readers.read_formatted_ascii(tfile, skip_lines = 1) + pfile = parameters['workingdir'] + 'pdistribution.dat' + pdist = ctem_io_readers.read_formatted_ascii(pfile, skip_lines = 1) + + #Read impact mass from file + massfile = parameters['workingdir'] + 'impactmass.dat' + impact_mass = ctem_io_readers.read_impact_mass(massfile) + + #Read ctem.dat file + ctem_io_readers.read_ctemdat(parameters, seedarr) + +#Open fracdonefile and regodepthfile for writing +filename = parameters['workingdir'] + 'fracdone.dat' +fp_frac = open(filename,'w') +filename = parameters['workingdir'] + 'regolithdepth.dat' +fp_reg = open(filename,'w') + +#Begin CTEM processing loops +print('Beginning loops') + +ctem_io_writers.create_dir_structure(parameters) + +while (parameters['ncount'] <= parameters['numintervals']): + + #Create crater population + if (parameters['ncount'] > 0): + + #Move ctem.dat + forig = parameters['workingdir'] + 'ctem.dat' + fdest = parameters['workingdir'] + 'misc' + os.sep + "ctem%06d.dat" % parameters['ncount'] + shutil.copy2(forig, fdest) + + #Create crater population and display CTEM progress on screen + print(parameters['ncount'], ' Calling FORTRAN routine') + with subprocess.Popen([parameters['workingdir']+'CTEM'], + stdout=subprocess.PIPE, + universal_newlines=True) as p: + for line in p.stdout: + print(line, end='') + + + #Optional: do not pipe CTEM progress to the screen + #subprocess.check_output([parameters['workingdir']+'CTEM']) + + #Read Fortran output + print(parameters['ncount'], ' Reading Fortran output') + + #Read surface dem(shaded relief) and ejecta data files + dem_file = parameters['workingdir'] + 'surface_dem.dat' + surface_dem = ctem_io_readers.read_unformatted_binary(dem_file, parameters['gridsize']) + ejecta_file = parameters['workingdir'] + 'surface_ejc.dat' + regolith = ctem_io_readers.read_unformatted_binary(ejecta_file, parameters['gridsize']) + + #Read odistribution, tdistribution, and pdistribution files + ofile = parameters['workingdir'] + 'odistribution.dat' + odist = ctem_io_readers.read_formatted_ascii(ofile, skip_lines = 1) + tfile = parameters['workingdir'] + 'tdistribution.dat' + tdist = ctem_io_readers.read_formatted_ascii(tfile, skip_lines = 1) + pfile = parameters['workingdir'] + 'pdistribution.dat' + pdist = ctem_io_readers.read_formatted_ascii(pfile, skip_lines = 1) + + #Read impact mass from file + massfile = parameters['workingdir'] + 'impactmass.dat' + impact_mass = ctem_io_readers.read_impact_mass(massfile) + + #Read ctem.dat file + ctem_io_readers.read_ctemdat(parameters, seedarr) + + #Update parameters: mass, curyear, regolith properties + parameters['masstot'] = parameters['masstot'] + impact_mass + + parameters['curyear'] = parameters['curyear'] + parameters['fracdone'] * parameters['interval'] + template = "%(fracdone)9.6f %(curyear)19.12E\n" + fp_frac.write(template % parameters) + + reg_text = "%19.12E %19.12E %19.12E %19.12E\n" % (parameters['curyear'], + numpy.mean(regolith), numpy.amax(regolith), numpy.amin(regolith)) + fp_reg.write(reg_text) + + #Save copy of crater distribution files + ctem_io_writers.copy_dists(parameters) + + #Display results + print(parameters['ncount'], ' Displaying results') + + #Write surface dem, surface ejecta, shaded relief, and rplot data + ctem_io_writers.image_dem(parameters, surface_dem) + if (parameters['saverego'].upper() == 'T'): + ctem_io_writers.image_regolith(parameters, regolith) + if (parameters['saveshaded'].upper() == 'T'): + ctem_io_writers.image_shaded_relief(parameters, surface_dem) + if (parameters['savepres'].upper() == 'T'): + ctem_io_writers.create_rplot(parameters,odist,pdist,tdist,ph1) + + #Update ncount + parameters['ncount'] = parameters['ncount'] + 1 + + if ((parameters['runtype'].upper() == 'STATISTICAL') or (parameters['ncount'] == 1)): + parameters['restart'] = 'F' + parameters['curyear'] = 0.0 + parameters['totalimpacts'] = 0 + parameters['masstot'] = 0.0 + + #Delete tdistribution file, if it exists + tdist_file = parameters['workingdir'] + 'tdistribution.dat' + if os.path.isfile(tdist_file): + os.remove(tdist_file) + + else: + parameters['restart'] = 'T' + + #Write ctem.dat file + ctem_io_writers.write_ctemdat(parameters, seedarr) + +#Close updateable fracdonefile and regodepthfile files +fp_frac.close() +fp_reg.close() diff --git a/python/ctem_io_readers.py b/python/ctem/ctem/ctem_io_readers.py similarity index 97% rename from python/ctem_io_readers.py rename to python/ctem/ctem/ctem_io_readers.py index a58ba9ab..84cf7e06 100644 --- a/python/ctem_io_readers.py +++ b/python/ctem/ctem/ctem_io_readers.py @@ -1,144 +1,144 @@ -#!/usr/local/bin/python -# -#Cratered Terrain Evolution Model file reading utilities -# -#Original IDL design: Jim Richardson, Arecibo Observatory -#Revised IDL design: David Minton, Purdue University -#Re-engineered design and Python implementation: Matthew Route, Purdue University -#August 2016 -# -#Known issues for operation with CTEM -#1) ctem.in has 1.0d0 value for maxcrat which is not readable by Python - -import numpy - -def read_ctemin(parameters,notset): - #Read and parse ctem.in file - inputfile = parameters['workingdir'] + parameters['ctemfile'] - - #Read ctem.in file - print('Reading input file '+ parameters['ctemfile']) - fp = open(inputfile,'r') - lines = fp.readlines() - fp.close() - - #Process file text - for line in lines: - fields = line.split() - if len(fields) > 0: - if ('pix' == fields[0].lower()): parameters['pix']=float(fields[1]) - if ('gridsize' == fields[0].lower()): parameters['gridsize']=int(fields[1]) - if ('seed' == fields[0].lower()): parameters['seed']=int(fields[1]) - if ('sfdfile' == fields[0].lower()): parameters['sfdfile']=fields[1] - if ('impfile' == fields[0].lower()): parameters['impfile']=fields[1] - if ('maxcrat' == fields[0].lower()): parameters['maxcrat']=float(fields[1]) - if ('sfdcompare' == fields[0].lower()): parameters['sfdcompare']=fields[1] - if ('interval' == fields[0].lower()): parameters['interval']=float(fields[1]) - if ('numintervals' == fields[0].lower()): parameters['numintervals']=int(fields[1]) - if ('popupconsole' == fields[0].lower()): parameters['popupconsole']=fields[1] - if ('saveshaded' == fields[0].lower()): parameters['saveshaded']=fields[1] - if ('saverego' == fields[0].lower()): parameters['saverego']=fields[1] - if ('savepres' == fields[0].lower()): parameters['savepres']=fields[1] - if ('savetruelist' == fields[0].lower()): parameters['savetruelist']=fields[1] - if ('runtype' == fields[0].lower()): parameters['runtype']=fields[1] - if ('restart' == fields[0].lower()): parameters['restart']=fields[1] - if ('shadedminh' == fields[0].lower()): - parameters['shadedminh'] = float(fields[1]) - parameters['shadedminhdefault'] = 0 - if ('shadedmaxh' == fields[0].lower()): - parameters['shadedmaxh'] = float(fields[1]) - parameters['shadedmaxhdefault'] = 0 - - #Test values for further processing - if (parameters['interval'] <= 0.0): - print('Invalid value for or missing variable INTERVAL in '+ inputfile) - if (parameters['numintervals'] <= 0): - print('Invalid value for or missing variable NUMINTERVALS in '+ inputfile) - if (parameters['pix'] <= 0.0): - print('Invalid value for or missing variable PIX in '+ inputfile) - if (parameters['gridsize'] <= 0): - print('Invalid value for or missing variable GRIDSIZE in '+ inputfile) - if (parameters['seed'] == 0): - print('Invalid value for or missing variable SEED in '+ inputfile) - if (parameters['sfdfile'] == notset): - print('Invalid value for or missing variable SFDFILE in '+ inputfile) - if (parameters['impfile'] == notset): - print('Invalid value for or missing variable IMPFILE in '+ inputfile) - if (parameters['popupconsole'] == notset): - print('Invalid value for or missing variable POPUPCONSOLE in '+ inputfile) - if (parameters['saveshaded'] == notset): - print('Invalid value for or missing variable SAVESHADED in '+ inputfile) - if (parameters['saverego'] == notset): - print('Invalid value for or missing variable SAVEREGO in '+ inputfile) - if (parameters['savepres'] == notset): - print('Invalid value for or missing variable SAVEPRES in '+ inputfile) - if (parameters['savetruelist'] == notset): - print('Invalid value for or missing variable SAVETRUELIST in '+ inputfile) - if (parameters['runtype'] == notset): - print('Invalid value for or missing variable RUNTYPE in '+ inputfile) - if (parameters['restart'] == notset): - print('Invalid value for or missing variable RESTART in '+ inputfile) - - return - -def read_formatted_ascii(filename, skip_lines): - #Generalized ascii text reader - #For use with sfdcompare, production, odist, tdist, pdist data files - data = numpy.genfromtxt(filename, skip_header = skip_lines) - return data - -def read_unformatted_binary(filename, gridsize): - #Read unformatted binary files created by Fortran - #For use with surface ejecta and surface dem data files - dt = numpy.float - data = numpy.fromfile(filename, dtype = dt) - data.shape = (gridsize,gridsize) - - return data - -def read_ctemdat(parameters, seedarr): - #Read and parse ctem.dat file - datfile = parameters['workingdir'] + 'ctem.dat' - - #Read ctem.dat file - print('Reading input file '+ parameters['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: - parameters['totalimpacts'] = float(fields[0]) - parameters['ncount'] = int(fields[1]) - parameters['curyear'] = float(fields[2]) - parameters['restart'] = fields[3] - parameters['fracdone'] = float(fields[4]) - parameters['masstot'] = float(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] = float(fields[0]) - index += 1 - - parameters['seedn'] = index - 1 - - return - -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 = float(fields[0]) - else: - mass = 0 - +#!/usr/local/bin/python +# +#Cratered Terrain Evolution Model file reading utilities +# +#Original IDL design: Jim Richardson, Arecibo Observatory +#Revised IDL design: David Minton, Purdue University +#Re-engineered design and Python implementation: Matthew Route, Purdue University +#August 2016 +# +#Known issues for operation with CTEM +#1) ctem.in has 1.0d0 value for maxcrat which is not readable by Python + +import numpy + +def read_ctemin(parameters,notset): + #Read and parse ctem.in file + inputfile = parameters['workingdir'] + parameters['ctemfile'] + + #Read ctem.in file + print('Reading input file '+ parameters['ctemfile']) + fp = open(inputfile,'r') + lines = fp.readlines() + fp.close() + + #Process file text + for line in lines: + fields = line.split() + if len(fields) > 0: + if ('pix' == fields[0].lower()): parameters['pix']=float(fields[1]) + if ('gridsize' == fields[0].lower()): parameters['gridsize']=int(fields[1]) + if ('seed' == fields[0].lower()): parameters['seed']=int(fields[1]) + if ('sfdfile' == fields[0].lower()): parameters['sfdfile']=fields[1] + if ('impfile' == fields[0].lower()): parameters['impfile']=fields[1] + if ('maxcrat' == fields[0].lower()): parameters['maxcrat']=float(fields[1]) + if ('sfdcompare' == fields[0].lower()): parameters['sfdcompare']=fields[1] + if ('interval' == fields[0].lower()): parameters['interval']=float(fields[1]) + if ('numintervals' == fields[0].lower()): parameters['numintervals']=int(fields[1]) + if ('popupconsole' == fields[0].lower()): parameters['popupconsole']=fields[1] + if ('saveshaded' == fields[0].lower()): parameters['saveshaded']=fields[1] + if ('saverego' == fields[0].lower()): parameters['saverego']=fields[1] + if ('savepres' == fields[0].lower()): parameters['savepres']=fields[1] + if ('savetruelist' == fields[0].lower()): parameters['savetruelist']=fields[1] + if ('runtype' == fields[0].lower()): parameters['runtype']=fields[1] + if ('restart' == fields[0].lower()): parameters['restart']=fields[1] + if ('shadedminh' == fields[0].lower()): + parameters['shadedminh'] = float(fields[1]) + parameters['shadedminhdefault'] = 0 + if ('shadedmaxh' == fields[0].lower()): + parameters['shadedmaxh'] = float(fields[1]) + parameters['shadedmaxhdefault'] = 0 + + #Test values for further processing + if (parameters['interval'] <= 0.0): + print('Invalid value for or missing variable INTERVAL in '+ inputfile) + if (parameters['numintervals'] <= 0): + print('Invalid value for or missing variable NUMINTERVALS in '+ inputfile) + if (parameters['pix'] <= 0.0): + print('Invalid value for or missing variable PIX in '+ inputfile) + if (parameters['gridsize'] <= 0): + print('Invalid value for or missing variable GRIDSIZE in '+ inputfile) + if (parameters['seed'] == 0): + print('Invalid value for or missing variable SEED in '+ inputfile) + if (parameters['sfdfile'] == notset): + print('Invalid value for or missing variable SFDFILE in '+ inputfile) + if (parameters['impfile'] == notset): + print('Invalid value for or missing variable IMPFILE in '+ inputfile) + if (parameters['popupconsole'] == notset): + print('Invalid value for or missing variable POPUPCONSOLE in '+ inputfile) + if (parameters['saveshaded'] == notset): + print('Invalid value for or missing variable SAVESHADED in '+ inputfile) + if (parameters['saverego'] == notset): + print('Invalid value for or missing variable SAVEREGO in '+ inputfile) + if (parameters['savepres'] == notset): + print('Invalid value for or missing variable SAVEPRES in '+ inputfile) + if (parameters['savetruelist'] == notset): + print('Invalid value for or missing variable SAVETRUELIST in '+ inputfile) + if (parameters['runtype'] == notset): + print('Invalid value for or missing variable RUNTYPE in '+ inputfile) + if (parameters['restart'] == notset): + print('Invalid value for or missing variable RESTART in '+ inputfile) + + return + +def read_formatted_ascii(filename, skip_lines): + #Generalized ascii text reader + #For use with sfdcompare, production, odist, tdist, pdist data files + data = numpy.genfromtxt(filename, skip_header = skip_lines) + return data + +def read_unformatted_binary(filename, gridsize): + #Read unformatted binary files created by Fortran + #For use with surface ejecta and surface dem data files + dt = numpy.float + data = numpy.fromfile(filename, dtype = dt) + data.shape = (gridsize,gridsize) + + return data + +def read_ctemdat(parameters, seedarr): + #Read and parse ctem.dat file + datfile = parameters['workingdir'] + 'ctem.dat' + + #Read ctem.dat file + print('Reading input file '+ parameters['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: + parameters['totalimpacts'] = float(fields[0]) + parameters['ncount'] = int(fields[1]) + parameters['curyear'] = float(fields[2]) + parameters['restart'] = fields[3] + parameters['fracdone'] = float(fields[4]) + parameters['masstot'] = float(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] = float(fields[0]) + index += 1 + + parameters['seedn'] = index - 1 + + return + +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 = float(fields[0]) + else: + mass = 0 + return mass \ No newline at end of file diff --git a/python/ctem_io_writers.py b/python/ctem/ctem/ctem_io_writers.py similarity index 97% rename from python/ctem_io_writers.py rename to python/ctem/ctem/ctem_io_writers.py index 7d7934e8..7bf21ce4 100644 --- a/python/ctem_io_writers.py +++ b/python/ctem/ctem/ctem_io_writers.py @@ -1,264 +1,264 @@ -#!/usr/local/bin/python -# -#Cratered Terrain Evolution Model file and graphical writing utilities -# -#Original IDL design: Jim Richardson, Arecibo Observatory -#Revised IDL design: David Minton, Purdue University -#Re-engineered design and Python implementation: Matthew Route, Purdue University -#August 2016 -# - -import matplotlib -from matplotlib import pyplot -import numpy -import os -import shutil -import scipy -from scipy import signal -from matplotlib.colors import LightSource -import matplotlib.cm as cm - -#Set pixel scaling common for image writing, at 1 pixel/ array element -dpi = 72.0 - -#Write production function to file production.dat -#This file format does not exactly match that generated from IDL. Does it work? -def write_production(parameters, production): - filename = parameters['workingdir'] + parameters['sfdfile'] - numpy.savetxt(filename, production, fmt='%1.8e', delimiter=' ') - - return - -def create_dir_structure(parameters): - #Create directories for various output files if they do not already exist - directories=['dist','misc','rego','rplot','surf','shaded'] - - for directory in directories: - dir_test = parameters['workingdir'] + directory - if not os.path.isdir(dir_test): - os.makedirs(dir_test) - - return - -def write_ctemdat(parameters, seedarr): - #Write various parameters and random number seeds into ctem.dat file - filename = parameters['workingdir'] + parameters['datfile'] - fp = open(filename,'w') - - template = "%(totalimpacts)17d %(ncount)12d %(curyear)19.12E %(restart)s %(fracdone)9.6f %(masstot)19.12E\n" - fp.write(template % parameters) - - #Write random number seeds to the file - for index in range(parameters['seedn']): - fp.write("%12d\n" % seedarr[index]) - - fp.close() - - return - -def copy_dists(parameters): - #Save copies of distribution files - - orig_list = ['odistribution', 'ocumulative', 'pdistribution', 'tdistribution'] - dest_list = ['odist', 'ocum', 'pdist', 'tdist'] - - for index in range(len(orig_list)): - forig = parameters['workingdir'] + orig_list[index] + '.dat' - fdest = parameters['workingdir'] + 'dist' + os.sep + dest_list[index] + "_%06d.dat" % parameters['ncount'] - shutil.copy2(forig, fdest) - - forig = parameters['workingdir'] + 'impactmass.dat' - fdest = parameters['workingdir'] + 'misc' + os.sep + "mass_%06d.dat" % parameters['ncount'] - shutil.copy2(forig, fdest) - - if (parameters['savetruelist'].upper() == 'T'): - forig = parameters['workingdir'] + 'tcumulative.dat' - fdest = parameters['workingdir'] + 'dist' + os.sep + "tcum_%06d.dat" % parameters['ncount'] - shutil.copy2(forig, fdest) - - return - -#Possible references -#http://nbviewer.jupyter.org/github/ThomasLecocq/geophysique.be/blob/master/2014-02-25%20Shaded%20Relief%20Map%20in%20Python.ipynb - -def image_dem(parameters, DEM): - dpi = 300.0 # 72.0 - pix = parameters['pix'] - gridsize = parameters['gridsize'] - ve = 1.0 - azimuth = 300.0 #parameters['azimuth'] - solar_angle = 20.0 #parameters['solar_angle'] - - ls = LightSource(azdeg=azimuth, altdeg=solar_angle) - dem_img = ls.hillshade(DEM, vert_exag=ve, dx=pix, dy=pix) - - # Generate image to put into an array - height = gridsize / dpi - width = gridsize / dpi - fig = matplotlib.pyplot.figure(figsize=(width, height), dpi=dpi) - ax = matplotlib.pyplot.axes([0, 0, 1, 1]) - ax.imshow(dem_img, interpolation="nearest", cmap='gray',vmin=0.0,vmax=1.0) - matplotlib.pyplot.axis('off') - # Save image to file - filename = parameters['workingdir'] + 'surf' + os.sep + "surf%06d.png" % parameters['ncount'] - matplotlib.pyplot.savefig(filename,dpi=dpi,bbox_inches=0) - - return - -def image_shaded_relief(parameters, DEM): - dpi = 300.0 #72.0 - pix = parameters['pix'] - gridsize = parameters['gridsize'] - ve = 1.0 - mode = 'overlay' - azimuth = 300.0 #parameters['azimuth'] - solar_angle = 20.0 #parameters['solar_angle'] - - ls = LightSource(azdeg=azimuth, altdeg=solar_angle) - cmap = cm.cividis - - # If min and max appear to be reversed, then fix them - if (parameters['shadedminh'] > parameters['shadedmaxh']): - temp = parameters['shadedminh'] - parameters['shadedminh'] = parameters['shadedmaxh'] - parameters['shadedmaxh'] = temp - else: - parameters['shadedminh'] = parameters['shadedminh'] - parameters['shadedmaxh'] = parameters['shadedmaxh'] - - # If no shadedmin/max parameters are read in from ctem.dat, determine the values from the data - if (parameters['shadedminhdefault'] == 1): - shadedminh = numpy.amin(DEM) - else: - shadedminh = parameters['shadedminh'] - if (parameters['shadedmaxhdefault'] == 1): - shadedmaxh = numpy.amax(DEM) - else: - shadedmaxh = parameters['shadedmaxh'] - - dem_img = ls.shade(DEM, 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 = matplotlib.pyplot.figure(figsize=(width, height), dpi=dpi) - ax = matplotlib.pyplot.axes([0, 0, 1, 1]) - ax.imshow(dem_img,interpolation="nearest",vmin=0.0,vmax=1.0) - matplotlib.pyplot.axis('off') - # Save image to file - filename = parameters['workingdir'] + 'shaded' + os.sep + "shaded%06d.png" % parameters['ncount'] - matplotlib.pyplot.savefig(filename,dpi=dpi,bbox_inches=0) - return - - -def image_regolith(parameters, regolith): - # Create scaled regolith image - minref = parameters['pix'] * 1.0e-4 - maxreg = numpy.amax(regolith) - minreg = numpy.amin(regolith) - if (minreg < minref): minreg = minref - if (maxreg < minref): maxreg = (minref + 1.0e3) - regolith_scaled = numpy.copy(regolith) - numpy.place(regolith_scaled, regolith_scaled < minref, minref) - regolith_scaled = 254.0 * ( - (numpy.log(regolith_scaled) - numpy.log(minreg)) / (numpy.log(maxreg) - numpy.log(minreg))) - - # Save image to file - filename = parameters['workingdir'] + 'rego' + os.sep + "rego%06d.png" % parameters['ncount'] - height = parameters['gridsize'] / dpi - width = height - fig = matplotlib.pyplot.figure(figsize=(width, height), dpi=dpi) - fig.figimage(regolith_scaled, cmap=matplotlib.cm.nipy_spectral, origin='lower') - matplotlib.pyplot.savefig(filename) - - return - -def create_rplot(parameters,odist,pdist,tdist,ph1): - #Parameters: empirical saturation limit and dfrac - satlimit = 3.12636 - dfrac = 2**(1./4) * 1.0e-3 - - #Calculate geometric saturation - minx = (parameters['pix'] / 3.0) * 1.0e-3 - maxx = 3 * parameters['pix'] * parameters['gridsize'] * 1.0e-3 - geomem = numpy.array([[minx, satlimit / 20.0], [maxx, satlimit / 20.0]]) - geomep = numpy.array([[minx, satlimit / 10.0], [maxx, satlimit / 10.0]]) - - #Create distribution arrays without zeros for plotting on log scale - idx = numpy.nonzero(odist[:,5]) - odistnz = odist[idx] - odistnz = odistnz[:,[2,5]] - - idx = numpy.nonzero(pdist[:,5]) - pdistnz = pdist[idx] - pdistnz = pdistnz[:,[2,5]] - - idx = numpy.nonzero(tdist[:,5]) - tdistnz = tdist[idx] - tdistnz = tdistnz[:,[2,5]] - - #Correct pdist - pdistnz[:,1] = pdistnz[:,1] * parameters['curyear'] / parameters['interval'] - - #Create sdist bin factors, which contain one crater per bin - area = (parameters['gridsize'] * parameters['pix'] * 1.0e-3)**2. - plo = 1 - sq2 = 2**(1./2) - while (sq2**plo > minx): - plo = plo - 1 - phi = plo + 1 - while (sq2**phi < maxx): - phi = phi + 1 - n = phi - plo + 1 - sdist = numpy.zeros([n , 2]) - p = plo - for index in range(n): - sdist[index, 0] = sq2**p - sdist[index, 1] = sq2**(2.0*p + 1.5) / (area * (sq2 - 1)) - p = p + 1 - - #Create time label - tlabel = "%5.4e" % parameters['curyear'] - tlabel = tlabel.split('e') - texp = str(int(tlabel[1])) - timelabel = 'Time = '+ r'${}$ x 10$^{}$'.format(tlabel[0], texp) + ' yrs' - - #Save image to file - filename = parameters['workingdir'] + 'rplot' + os.sep + "rplot%06d.png" % parameters['ncount'] - height = parameters['gridsize'] / dpi - width = height - fig = matplotlib.pyplot.figure(figsize = (width, height), dpi = dpi) - - #Alter background color to be black, and change axis colors accordingly - matplotlib.pyplot.style.use('dark_background') - matplotlib.pyplot.rcParams['axes.prop_cycle'] - - #Plot data - matplotlib.pyplot.plot(odistnz[:,0]*1.0e-3, odistnz[:,1], linewidth=3.0, color = 'blue') - matplotlib.pyplot.plot(pdistnz[:,0]*1.0e-3, pdistnz[:,1], linewidth=2.0, linestyle='dashdot', color = 'white') - matplotlib.pyplot.plot(tdistnz[:,0]*1.0e-3, tdistnz[:,1], linewidth=2.0, color = 'red') - - matplotlib.pyplot.plot(geomem[:,0], geomem[:,1], linewidth=2.0, linestyle =':', color = 'yellow') - matplotlib.pyplot.plot(geomep[:,0], geomep[:,1], linewidth=2.0, linestyle =':', color = 'yellow') - matplotlib.pyplot.plot(sdist[:,0], sdist[:,1], linewidth=2.0, linestyle =':', color = 'yellow') - - matplotlib.pyplot.plot(ph1[:,0] * dfrac, ph1[:,1], 'wo') - - #Create plot labels - matplotlib.pyplot.title('Crater Distribution R-Plot',fontsize=22) - matplotlib.pyplot.xlim([minx, maxx]) - matplotlib.pyplot.xscale('log') - matplotlib.pyplot.xlabel('Crater Diameter (km)',fontsize=18) - matplotlib.pyplot.ylim([5.0e-4, 5.0]) - matplotlib.pyplot.yscale('log') - matplotlib.pyplot.ylabel('R Value', fontsize=18) - matplotlib.pyplot.text(1.0e-2, 1.0, timelabel, fontsize=18) - - matplotlib.pyplot.tick_params(axis='both', which='major', labelsize=14) - matplotlib.pyplot.tick_params(axis='both', which='minor', labelsize=12) - - matplotlib.pyplot.savefig(filename) - +#!/usr/local/bin/python +# +#Cratered Terrain Evolution Model file and graphical writing utilities +# +#Original IDL design: Jim Richardson, Arecibo Observatory +#Revised IDL design: David Minton, Purdue University +#Re-engineered design and Python implementation: Matthew Route, Purdue University +#August 2016 +# + +import matplotlib +from matplotlib import pyplot +import numpy +import os +import shutil +import scipy +from scipy import signal +from matplotlib.colors import LightSource +import matplotlib.cm as cm + +#Set pixel scaling common for image writing, at 1 pixel/ array element +dpi = 72.0 + +#Write production function to file production.dat +#This file format does not exactly match that generated from IDL. Does it work? +def write_production(parameters, production): + filename = parameters['workingdir'] + parameters['sfdfile'] + numpy.savetxt(filename, production, fmt='%1.8e', delimiter=' ') + + return + +def create_dir_structure(parameters): + #Create directories for various output files if they do not already exist + directories=['dist','misc','rego','rplot','surf','shaded'] + + for directory in directories: + dir_test = parameters['workingdir'] + directory + if not os.path.isdir(dir_test): + os.makedirs(dir_test) + + return + +def write_ctemdat(parameters, seedarr): + #Write various parameters and random number seeds into ctem.dat file + filename = parameters['workingdir'] + parameters['datfile'] + fp = open(filename,'w') + + template = "%(totalimpacts)17d %(ncount)12d %(curyear)19.12E %(restart)s %(fracdone)9.6f %(masstot)19.12E\n" + fp.write(template % parameters) + + #Write random number seeds to the file + for index in range(parameters['seedn']): + fp.write("%12d\n" % seedarr[index]) + + fp.close() + + return + +def copy_dists(parameters): + #Save copies of distribution files + + orig_list = ['odistribution', 'ocumulative', 'pdistribution', 'tdistribution'] + dest_list = ['odist', 'ocum', 'pdist', 'tdist'] + + for index in range(len(orig_list)): + forig = parameters['workingdir'] + orig_list[index] + '.dat' + fdest = parameters['workingdir'] + 'dist' + os.sep + dest_list[index] + "_%06d.dat" % parameters['ncount'] + shutil.copy2(forig, fdest) + + forig = parameters['workingdir'] + 'impactmass.dat' + fdest = parameters['workingdir'] + 'misc' + os.sep + "mass_%06d.dat" % parameters['ncount'] + shutil.copy2(forig, fdest) + + if (parameters['savetruelist'].upper() == 'T'): + forig = parameters['workingdir'] + 'tcumulative.dat' + fdest = parameters['workingdir'] + 'dist' + os.sep + "tcum_%06d.dat" % parameters['ncount'] + shutil.copy2(forig, fdest) + + return + +#Possible references +#http://nbviewer.jupyter.org/github/ThomasLecocq/geophysique.be/blob/master/2014-02-25%20Shaded%20Relief%20Map%20in%20Python.ipynb + +def image_dem(parameters, DEM): + dpi = 300.0 # 72.0 + pix = parameters['pix'] + gridsize = parameters['gridsize'] + ve = 1.0 + azimuth = 300.0 #parameters['azimuth'] + solar_angle = 20.0 #parameters['solar_angle'] + + ls = LightSource(azdeg=azimuth, altdeg=solar_angle) + dem_img = ls.hillshade(DEM, vert_exag=ve, dx=pix, dy=pix) + + # Generate image to put into an array + height = gridsize / dpi + width = gridsize / dpi + fig = matplotlib.pyplot.figure(figsize=(width, height), dpi=dpi) + ax = matplotlib.pyplot.axes([0, 0, 1, 1]) + ax.imshow(dem_img, interpolation="nearest", cmap='gray',vmin=0.0,vmax=1.0) + matplotlib.pyplot.axis('off') + # Save image to file + filename = parameters['workingdir'] + 'surf' + os.sep + "surf%06d.png" % parameters['ncount'] + matplotlib.pyplot.savefig(filename,dpi=dpi,bbox_inches=0) + + return + +def image_shaded_relief(parameters, DEM): + dpi = 300.0 #72.0 + pix = parameters['pix'] + gridsize = parameters['gridsize'] + ve = 1.0 + mode = 'overlay' + azimuth = 300.0 #parameters['azimuth'] + solar_angle = 20.0 #parameters['solar_angle'] + + ls = LightSource(azdeg=azimuth, altdeg=solar_angle) + cmap = cm.cividis + + # If min and max appear to be reversed, then fix them + if (parameters['shadedminh'] > parameters['shadedmaxh']): + temp = parameters['shadedminh'] + parameters['shadedminh'] = parameters['shadedmaxh'] + parameters['shadedmaxh'] = temp + else: + parameters['shadedminh'] = parameters['shadedminh'] + parameters['shadedmaxh'] = parameters['shadedmaxh'] + + # If no shadedmin/max parameters are read in from ctem.dat, determine the values from the data + if (parameters['shadedminhdefault'] == 1): + shadedminh = numpy.amin(DEM) + else: + shadedminh = parameters['shadedminh'] + if (parameters['shadedmaxhdefault'] == 1): + shadedmaxh = numpy.amax(DEM) + else: + shadedmaxh = parameters['shadedmaxh'] + + dem_img = ls.shade(DEM, 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 = matplotlib.pyplot.figure(figsize=(width, height), dpi=dpi) + ax = matplotlib.pyplot.axes([0, 0, 1, 1]) + ax.imshow(dem_img,interpolation="nearest",vmin=0.0,vmax=1.0) + matplotlib.pyplot.axis('off') + # Save image to file + filename = parameters['workingdir'] + 'shaded' + os.sep + "shaded%06d.png" % parameters['ncount'] + matplotlib.pyplot.savefig(filename,dpi=dpi,bbox_inches=0) + return + + +def image_regolith(parameters, regolith): + # Create scaled regolith image + minref = parameters['pix'] * 1.0e-4 + maxreg = numpy.amax(regolith) + minreg = numpy.amin(regolith) + if (minreg < minref): minreg = minref + if (maxreg < minref): maxreg = (minref + 1.0e3) + regolith_scaled = numpy.copy(regolith) + numpy.place(regolith_scaled, regolith_scaled < minref, minref) + regolith_scaled = 254.0 * ( + (numpy.log(regolith_scaled) - numpy.log(minreg)) / (numpy.log(maxreg) - numpy.log(minreg))) + + # Save image to file + filename = parameters['workingdir'] + 'rego' + os.sep + "rego%06d.png" % parameters['ncount'] + height = parameters['gridsize'] / dpi + width = height + fig = matplotlib.pyplot.figure(figsize=(width, height), dpi=dpi) + fig.figimage(regolith_scaled, cmap=matplotlib.cm.nipy_spectral, origin='lower') + matplotlib.pyplot.savefig(filename) + + return + +def create_rplot(parameters,odist,pdist,tdist,ph1): + #Parameters: empirical saturation limit and dfrac + satlimit = 3.12636 + dfrac = 2**(1./4) * 1.0e-3 + + #Calculate geometric saturation + minx = (parameters['pix'] / 3.0) * 1.0e-3 + maxx = 3 * parameters['pix'] * parameters['gridsize'] * 1.0e-3 + geomem = numpy.array([[minx, satlimit / 20.0], [maxx, satlimit / 20.0]]) + geomep = numpy.array([[minx, satlimit / 10.0], [maxx, satlimit / 10.0]]) + + #Create distribution arrays without zeros for plotting on log scale + idx = numpy.nonzero(odist[:,5]) + odistnz = odist[idx] + odistnz = odistnz[:,[2,5]] + + idx = numpy.nonzero(pdist[:,5]) + pdistnz = pdist[idx] + pdistnz = pdistnz[:,[2,5]] + + idx = numpy.nonzero(tdist[:,5]) + tdistnz = tdist[idx] + tdistnz = tdistnz[:,[2,5]] + + #Correct pdist + pdistnz[:,1] = pdistnz[:,1] * parameters['curyear'] / parameters['interval'] + + #Create sdist bin factors, which contain one crater per bin + area = (parameters['gridsize'] * parameters['pix'] * 1.0e-3)**2. + plo = 1 + sq2 = 2**(1./2) + while (sq2**plo > minx): + plo = plo - 1 + phi = plo + 1 + while (sq2**phi < maxx): + phi = phi + 1 + n = phi - plo + 1 + sdist = numpy.zeros([n , 2]) + p = plo + for index in range(n): + sdist[index, 0] = sq2**p + sdist[index, 1] = sq2**(2.0*p + 1.5) / (area * (sq2 - 1)) + p = p + 1 + + #Create time label + tlabel = "%5.4e" % parameters['curyear'] + tlabel = tlabel.split('e') + texp = str(int(tlabel[1])) + timelabel = 'Time = '+ r'${}$ x 10$^{}$'.format(tlabel[0], texp) + ' yrs' + + #Save image to file + filename = parameters['workingdir'] + 'rplot' + os.sep + "rplot%06d.png" % parameters['ncount'] + height = parameters['gridsize'] / dpi + width = height + fig = matplotlib.pyplot.figure(figsize = (width, height), dpi = dpi) + + #Alter background color to be black, and change axis colors accordingly + matplotlib.pyplot.style.use('dark_background') + matplotlib.pyplot.rcParams['axes.prop_cycle'] + + #Plot data + matplotlib.pyplot.plot(odistnz[:,0]*1.0e-3, odistnz[:,1], linewidth=3.0, color = 'blue') + matplotlib.pyplot.plot(pdistnz[:,0]*1.0e-3, pdistnz[:,1], linewidth=2.0, linestyle='dashdot', color = 'white') + matplotlib.pyplot.plot(tdistnz[:,0]*1.0e-3, tdistnz[:,1], linewidth=2.0, color = 'red') + + matplotlib.pyplot.plot(geomem[:,0], geomem[:,1], linewidth=2.0, linestyle =':', color = 'yellow') + matplotlib.pyplot.plot(geomep[:,0], geomep[:,1], linewidth=2.0, linestyle =':', color = 'yellow') + matplotlib.pyplot.plot(sdist[:,0], sdist[:,1], linewidth=2.0, linestyle =':', color = 'yellow') + + matplotlib.pyplot.plot(ph1[:,0] * dfrac, ph1[:,1], 'wo') + + #Create plot labels + matplotlib.pyplot.title('Crater Distribution R-Plot',fontsize=22) + matplotlib.pyplot.xlim([minx, maxx]) + matplotlib.pyplot.xscale('log') + matplotlib.pyplot.xlabel('Crater Diameter (km)',fontsize=18) + matplotlib.pyplot.ylim([5.0e-4, 5.0]) + matplotlib.pyplot.yscale('log') + matplotlib.pyplot.ylabel('R Value', fontsize=18) + matplotlib.pyplot.text(1.0e-2, 1.0, timelabel, fontsize=18) + + matplotlib.pyplot.tick_params(axis='both', which='major', labelsize=14) + matplotlib.pyplot.tick_params(axis='both', which='minor', labelsize=12) + + matplotlib.pyplot.savefig(filename) + return \ No newline at end of file diff --git a/python/ctem/ctem/ctem_viewer_3d.py b/python/ctem/ctem/ctem_viewer_3d.py new file mode 100644 index 00000000..2f03bb5a --- /dev/null +++ b/python/ctem/ctem/ctem_viewer_3d.py @@ -0,0 +1 @@ +import open3d as o3d \ No newline at end of file diff --git a/python/dist_reader.py b/python/ctem/ctem/dist_reader.py similarity index 100% rename from python/dist_reader.py rename to python/ctem/ctem/dist_reader.py diff --git a/python/readme.txt b/python/ctem/readme.txt similarity index 96% rename from python/readme.txt rename to python/ctem/readme.txt index e89c42cd..4a127168 100644 --- a/python/readme.txt +++ b/python/ctem/readme.txt @@ -1,22 +1,22 @@ -1) Install a distribution of Python 2.x to your machine. This source code - has been tested on Anaconda Python 4.1.1. - -2) Insure required modules are installed: - numpy - os - scipy - shutil - subprocess - -3) Place the .py files in this directory into the directory you wish - to execute from, with the required initialization files. For this, - the IDL directory may be copied, and ctem.in replaced by the one found - in this directory. - -4) Inside Anaconda Python, the program can be run through the Spyder2 GUI. - Outside of Anaconda, the progam can be begun by configuring the ctem.in - file, then typing - - python < ctem_driver.py - - at the command line. +1) Install a distribution of Python 2.x to your machine. This source code + has been tested on Anaconda Python 4.1.1. + +2) Insure required modules are installed: + numpy + os + scipy + shutil + subprocess + +3) Place the .py files in this directory into the directory you wish + to execute from, with the required initialization files. For this, + the IDL directory may be copied, and ctem.in replaced by the one found + in this directory. + +4) Inside Anaconda Python, the program can be run through the Spyder2 GUI. + Outside of Anaconda, the progam can be begun by configuring the ctem.in + file, then typing + + python < ctem_driver.py + + at the command line. diff --git a/python/ctem/setup.py b/python/ctem/setup.py new file mode 100644 index 00000000..f7003601 --- /dev/null +++ b/python/ctem/setup.py @@ -0,0 +1,6 @@ +from setuptools import setup, find_packages + +setup(name='ctem', + version='0.1', + author='David A. Minton', + packages=find_packages()) From 3e4c1a58a1c49ce87f75864c3cb5d42cf4b8876d Mon Sep 17 00:00:00 2001 From: David A Minton Date: Thu, 17 Feb 2022 10:39:38 -0500 Subject: [PATCH 04/32] Changed order of when ejrim is called to ensure that it is set before computing the ejecta radius --- src/crater/crater_dimensions.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crater/crater_dimensions.f90 b/src/crater/crater_dimensions.f90 index 9a45e04f..fc6de8c9 100644 --- a/src/crater/crater_dimensions.f90 +++ b/src/crater/crater_dimensions.f90 @@ -68,8 +68,8 @@ subroutine crater_dimensions(user,crater,domain) ! Calculate the radius where the inner wall meets the original pre-existing surface ! This is used to demark the location where excavation transitions to deposition - crater%ejrad = max(crater_profile_find_r_inner_wall(user,crater) * crater%frad, crater%rad) crater%ejrim = 0.14_DP * (crater%fcrat * 1e-3 * 0.5_DP)**(0.74_DP) * 1e3_DP ! McGetchin et al. (1973) Thickness of ejecta at rim + crater%ejrad = max(crater_profile_find_r_inner_wall(user,crater) * crater%frad, crater%rad) !find rim for counting purposes crater%frim = RIMFAC * crater%frad From 9512de6df6a4315a46fa9ab91fa8fe234df200c9 Mon Sep 17 00:00:00 2001 From: David Minton Date: Fri, 18 Feb 2022 10:40:37 -0500 Subject: [PATCH 05/32] Tweaked order of vertices when generating faces --- python/ctem/ctem/ctem_viewer_3d.py | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/python/ctem/ctem/ctem_viewer_3d.py b/python/ctem/ctem/ctem_viewer_3d.py index be967d10..4d545b69 100644 --- a/python/ctem/ctem/ctem_viewer_3d.py +++ b/python/ctem/ctem/ctem_viewer_3d.py @@ -68,25 +68,39 @@ def ctem2mesh(self, surface_file): 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, (j+1)*s+i ] - faces[idx, :] = [j * s + i, j * s + i + 1, (j + 1) * s + i] + faces[idx, :] = [j * s + i, j * s + i + 1, (j + 1) * s + i + 1] idx += (s - 1) ** 2 - faces[idx, :] = [j * s + i + 1, (j + 1) * s + i + 1, (j + 1) * s + i] + 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() + return + def visualize(self): + vis = open3d.visualization.Visualizer() + vis.create_window() + vis.add_geometry(self.mesh) + + + # zmax = np.amax(surf.dem) + # zmin = np.amin(surf.dem) + # cnorm = (surf.dem.flatten() - zmin) / (zmax - zmin) + # cval = plt.cm.terrain(cnorm)[:, :3] + + self.mesh.paint_uniform_color([0.5, 0.5, 0.5]) + vis.run() + vis.destroy_window() + + if __name__ == '__main__': import matplotlib.pyplot as plt surf = polysurface() surf.ctem2mesh(surface_file="surface_dem.dat") + surf.visualize() + + - zmax = np.amax(surf.dem) - zmin = np.amin(surf.dem) - cnorm = (surf.dem.flatten() - zmin) / (zmax - zmin) - cval = plt.cm.terrain(cnorm)[:,:3] - surf.mesh.vertex_colors = open3d.utility.Vector3dVector(cval) - open3d.visualization.draw_geometries([surf.mesh]) From 2fa61db9c477ad43c47f9ae1a11ea36143191aa0 Mon Sep 17 00:00:00 2001 From: David A Minton Date: Fri, 18 Feb 2022 10:41:26 -0500 Subject: [PATCH 06/32] Added setup script so that the ctem Python packaage may be installed --- python/ctem/setup.py | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 python/ctem/setup.py diff --git a/python/ctem/setup.py b/python/ctem/setup.py new file mode 100644 index 00000000..f7003601 --- /dev/null +++ b/python/ctem/setup.py @@ -0,0 +1,6 @@ +from setuptools import setup, find_packages + +setup(name='ctem', + version='0.1', + author='David A. Minton', + packages=find_packages()) From 528a1182098c69594da6478990ba190dd438cfa6 Mon Sep 17 00:00:00 2001 From: David Minton Date: Fri, 18 Feb 2022 12:47:33 -0500 Subject: [PATCH 07/32] Added real2float function to convert Fortran double precision real ASCII that uses d or D for exponent to float with E --- .gitignore | 2 ++ python/ctem/ctem/ctem_io_readers.py | 41 +++++++++++++++++++++-------- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 1650087f..f7ab64c6 100644 --- a/.gitignore +++ b/.gitignore @@ -69,3 +69,5 @@ examples/global-lunar-bombardment/scale.ipynb *.code-workspace *.png + +python/ctem/ctem.egg-info/ diff --git a/python/ctem/ctem/ctem_io_readers.py b/python/ctem/ctem/ctem_io_readers.py index 84cf7e06..0935fac9 100644 --- a/python/ctem/ctem/ctem_io_readers.py +++ b/python/ctem/ctem/ctem_io_readers.py @@ -12,6 +12,25 @@ import numpy + +def real2float(realstr): + """ + Converts a Fortran-generated ASCII string of a real value into a numpy float type. Handles cases where double precision + numbers in exponential notation use 'd' or 'D' instead of 'e' or 'E' + + Parameters + ---------- + realstr : string + Fortran-generated ASCII string of a real value. + + Returns + ------- + : float + The converted floating point value of the input string + """ + return float(realstr.replace('d', 'E').replace('D', 'E')) + + def read_ctemin(parameters,notset): #Read and parse ctem.in file inputfile = parameters['workingdir'] + parameters['ctemfile'] @@ -26,14 +45,14 @@ def read_ctemin(parameters,notset): for line in lines: fields = line.split() if len(fields) > 0: - if ('pix' == fields[0].lower()): parameters['pix']=float(fields[1]) + if ('pix' == fields[0].lower()): parameters['pix']=real2float(fields[1]) if ('gridsize' == fields[0].lower()): parameters['gridsize']=int(fields[1]) if ('seed' == fields[0].lower()): parameters['seed']=int(fields[1]) if ('sfdfile' == fields[0].lower()): parameters['sfdfile']=fields[1] if ('impfile' == fields[0].lower()): parameters['impfile']=fields[1] - if ('maxcrat' == fields[0].lower()): parameters['maxcrat']=float(fields[1]) + if ('maxcrat' == fields[0].lower()): parameters['maxcrat']=real2float(fields[1]) if ('sfdcompare' == fields[0].lower()): parameters['sfdcompare']=fields[1] - if ('interval' == fields[0].lower()): parameters['interval']=float(fields[1]) + if ('interval' == fields[0].lower()): parameters['interval']=real2float(fields[1]) if ('numintervals' == fields[0].lower()): parameters['numintervals']=int(fields[1]) if ('popupconsole' == fields[0].lower()): parameters['popupconsole']=fields[1] if ('saveshaded' == fields[0].lower()): parameters['saveshaded']=fields[1] @@ -43,10 +62,10 @@ def read_ctemin(parameters,notset): if ('runtype' == fields[0].lower()): parameters['runtype']=fields[1] if ('restart' == fields[0].lower()): parameters['restart']=fields[1] if ('shadedminh' == fields[0].lower()): - parameters['shadedminh'] = float(fields[1]) + parameters['shadedminh'] = real2float(fields[1]) parameters['shadedminhdefault'] = 0 if ('shadedmaxh' == fields[0].lower()): - parameters['shadedmaxh'] = float(fields[1]) + parameters['shadedmaxh'] = real2float(fields[1]) parameters['shadedmaxhdefault'] = 0 #Test values for further processing @@ -109,19 +128,19 @@ def read_ctemdat(parameters, seedarr): #Parse file lines and update parameter fields fields = lines[0].split() if len(fields) > 0: - parameters['totalimpacts'] = float(fields[0]) + parameters['totalimpacts'] = real2float(fields[0]) parameters['ncount'] = int(fields[1]) - parameters['curyear'] = float(fields[2]) + parameters['curyear'] = real2float(fields[2]) parameters['restart'] = fields[3] - parameters['fracdone'] = float(fields[4]) - parameters['masstot'] = float(fields[5]) + parameters['fracdone'] = real2float(fields[4]) + parameters['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] = float(fields[0]) + seedarr[index - 1] = real2float(fields[0]) index += 1 parameters['seedn'] = index - 1 @@ -137,7 +156,7 @@ def read_impact_mass(filename): fields = line[0].split() if (len(fields) > 0): - mass = float(fields[0]) + mass = real2float(fields[0]) else: mass = 0 From b273acba928270961c125284674f2280eb4a2527 Mon Sep 17 00:00:00 2001 From: David Minton Date: Sat, 19 Feb 2022 14:23:06 -0500 Subject: [PATCH 08/32] Updated the viewer to plot elevation points as square pixels as it is characterized internally --- python/ctem/ctem/ctem_viewer_3d.py | 78 ++++++++++++++++++++------ python/ctem/tests/viewer3d/polytest.py | 13 +++-- 2 files changed, 69 insertions(+), 22 deletions(-) diff --git a/python/ctem/ctem/ctem_viewer_3d.py b/python/ctem/ctem/ctem_viewer_3d.py index 4d545b69..093ae1e3 100644 --- a/python/ctem/ctem/ctem_viewer_3d.py +++ b/python/ctem/ctem/ctem_viewer_3d.py @@ -1,7 +1,7 @@ import numpy as np import os import open3d -import ctem_io_readers +from ctem import ctem_io_readers import os @@ -57,31 +57,76 @@ def ctem2mesh(self, surface_file): # Build mesh grid s = parameters['gridsize'] pix = parameters['pix'] - ygrid, xgrid = np.mgrid[-s / 2:s / 2, -s / 2:s / 2] * 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 = xgrid.flatten() - yvals = ygrid.flatten() - zvals = self.dem.flatten() + 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.dem.flatten(), + self.dem.flatten()), + self.dem.flatten()), + self.dem.flatten()) verts = np.array((xvals, yvals, zvals)).T - faces = np.empty([2 * (s - 1) ** 2, 3], 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, (j+1)*s+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 ] + 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[0],:] = [i0, i3, i3-1] + faces[fidx[1],:] = [i0, i3-1, i0-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(faces) + self.mesh.triangles = open3d.utility.Vector3iVector(f2) 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]) # zmax = np.amax(surf.dem) # zmin = np.amin(surf.dem) @@ -99,6 +144,7 @@ def visualize(self): surf = polysurface() surf.ctem2mesh(surface_file="surface_dem.dat") surf.visualize() + #open3d.visualization.draw_geometries_with_editing([surf.mesh]) diff --git a/python/ctem/tests/viewer3d/polytest.py b/python/ctem/tests/viewer3d/polytest.py index 13cee521..c528374c 100644 --- a/python/ctem/tests/viewer3d/polytest.py +++ b/python/ctem/tests/viewer3d/polytest.py @@ -1,8 +1,9 @@ import numpy as np from ctem import ctem_viewer_3d - -surf = ctem_viewer_3d.surf() -surf.io_read_ply("216kleopatra-mesh.ply") -v = np.asarray(surf.mesh) -t = np.asarray(surf.mesh) -surf.render() \ No newline at end of file +import open3d +surf = ctem_viewer_3d.polysurface() +#surf.io_read_ply("216kleopatra-mesh.ply") +surf.mesh = open3d.geometry.TriangleMesh.create_box() +v = np.asarray(surf.mesh.vertices) +t = np.asarray(surf.mesh.triangles) +surf.visualize() \ No newline at end of file From 1b9e858a830f81ec6486d4de14393af583b21b14 Mon Sep 17 00:00:00 2001 From: David Minton Date: Sat, 19 Feb 2022 14:34:36 -0500 Subject: [PATCH 09/32] Fixed bad indices --- python/ctem/ctem/ctem_viewer_3d.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ctem/ctem/ctem_viewer_3d.py b/python/ctem/ctem/ctem_viewer_3d.py index 093ae1e3..45612354 100644 --- a/python/ctem/ctem/ctem_viewer_3d.py +++ b/python/ctem/ctem/ctem_viewer_3d.py @@ -98,8 +98,8 @@ def ctem2mesh(self, surface_file): faces[fidx[1],:] = [i0, i2, i3] # Make the two west side triangles if i > 0: - faces[fidx[0],:] = [i0, i3, i3-1] - faces[fidx[1],:] = [i0, i3-1, i0-1] + 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 ] From 93f168dfc23b01c9c02a1b97cf808a535697f466 Mon Sep 17 00:00:00 2001 From: David Minton Date: Sat, 19 Feb 2022 15:09:17 -0500 Subject: [PATCH 10/32] Added two different mesh styles (block vs triangle) and separated input file reading out into its own method --- python/ctem/ctem/ctem_viewer_3d.py | 50 +++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/python/ctem/ctem/ctem_viewer_3d.py b/python/ctem/ctem/ctem_viewer_3d.py index 45612354..b4517054 100644 --- a/python/ctem/ctem/ctem_viewer_3d.py +++ b/python/ctem/ctem/ctem_viewer_3d.py @@ -13,13 +13,12 @@ def __init__(self): self.mesh = open3d.geometry.TriangleMesh() return - def ctem2mesh(self, surface_file): - + def readctem(self, surface_file): # Create and initialize data dictionaries for parameters and options from CTEM.in notset = '-NOTSET-' currentdir = os.getcwd() + os.sep - parameters = {'restart': notset, + self.parameters = {'restart': notset, 'runtype': notset, 'popupconsole': notset, 'saveshaded': notset, @@ -48,22 +47,24 @@ def ctem2mesh(self, surface_file): 'impfile': notset, 'sfdcompare': notset, 'sfdfile': notset} - + # Read ctem.in to initialize parameter values based on user input - ctem_io_readers.read_ctemin(parameters, notset) + ctem_io_readers.read_ctemin(self.parameters, notset) # Read surface dem(shaded relief) and ejecta data files - dem_file = parameters['workingdir'] + surface_file - self.dem = ctem_io_readers.read_unformatted_binary(dem_file, parameters['gridsize']) + dem_file = self.parameters['workingdir'] + surface_file + self.dem = ctem_io_readers.read_unformatted_binary(dem_file, self.parameters['gridsize']) + return + + def ctem2blockmesh(self): # Build mesh grid - s = parameters['gridsize'] - pix = parameters['pix'] + s = self.parameters['gridsize'] + pix = self.parameters['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(), @@ -121,6 +122,31 @@ def ctem2mesh(self, surface_file): return + def ctem2trimesh(self): + # Build mesh grid + s = self.parameters['gridsize'] + pix = self.parameters['pix'] + ygrid, xgrid = np.mgrid[-s/2:s/2, -s/2:s/2] * pix + + xvals = xgrid.flatten() + yvals = ygrid.flatten() + zvals = self.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, (j+1)*s+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() @@ -142,9 +168,9 @@ def visualize(self): import matplotlib.pyplot as plt surf = polysurface() - surf.ctem2mesh(surface_file="surface_dem.dat") + surf.readctem(surface_file="surface_dem.dat") + surf.ctem2trimesh() surf.visualize() - #open3d.visualization.draw_geometries_with_editing([surf.mesh]) From ead9d0cad7c6f1be351275580073aa6fbd49e509 Mon Sep 17 00:00:00 2001 From: David Minton Date: Mon, 21 Feb 2022 11:03:11 -0500 Subject: [PATCH 11/32] Began process of restructuring the Python frontend with a basic class definition for a CTEM simulation --- python/ctem/ctem/__init__.py | 1 + python/ctem/ctem/frontend.py | 46 ++++++++++++++++ python/ctem/ctem/io.py | 87 ++++++++++++++++++++++++++++++ python/ctem/tests/testio/ctem.in | 70 ++++++++++++++++++++++++ python/ctem/tests/testio/testio.py | 7 +++ 5 files changed, 211 insertions(+) create mode 100644 python/ctem/ctem/frontend.py create mode 100644 python/ctem/ctem/io.py create mode 100755 python/ctem/tests/testio/ctem.in create mode 100644 python/ctem/tests/testio/testio.py diff --git a/python/ctem/ctem/__init__.py b/python/ctem/ctem/__init__.py index 4774c6af..b9aa95ac 100644 --- a/python/ctem/ctem/__init__.py +++ b/python/ctem/ctem/__init__.py @@ -1,3 +1,4 @@ # from ctem.ctem_io_readers import * # from ctem.ctem_io_writers import * # from ctem.ctem_driver import * +from ctem.frontend import * \ No newline at end of file diff --git a/python/ctem/ctem/frontend.py b/python/ctem/ctem/frontend.py new file mode 100644 index 00000000..6340d5ec --- /dev/null +++ b/python/ctem/ctem/frontend.py @@ -0,0 +1,46 @@ +import numpy +import os +import subprocess +import shutil +from ctem import io + +class Simulation: + """ + This is a class that defines the basic CTEM simulation object + """ + def __init__(self, param_file="ctem.in"): + currentdir = os.getcwd() + self.parameters = { + 'restart': None, + 'runtype': None, + 'popupconsole': None, + 'saveshaded': None, + 'saverego': None, + 'savepres': 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, + 'datfile': 'ctem.dat', + 'impfile': None, + 'sfdcompare': None, + 'sfdfile': None + } + self.parameters = io.read_param(self.parameters) + + return \ No newline at end of file diff --git a/python/ctem/ctem/io.py b/python/ctem/ctem/io.py new file mode 100644 index 00000000..664d8bb8 --- /dev/null +++ b/python/ctem/ctem/io.py @@ -0,0 +1,87 @@ +import numpy +import os + +def real2float(realstr): + """ + Converts a Fortran-generated ASCII string of a real value into a numpy float type. Handles cases where double precision + numbers in exponential notation use 'd' or 'D' instead of 'e' or 'E' + + Parameters + ---------- + realstr : string + Fortran-generated ASCII string of a real value. + + Returns + ------- + : float + The converted floating point value of the input string + """ + return float(realstr.replace('d', 'E').replace('D', 'E')) + +def read_param(parameters): + # Read and parse ctem.in file + inputfile = os.path.join(parameters['workingdir'], parameters['ctemfile']) + + # Read ctem.in file + print('Reading input file ' + parameters['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()): parameters['pix'] = real2float(fields[1]) + if ('gridsize' == fields[0].lower()): parameters['gridsize'] = int(fields[1]) + if ('seed' == fields[0].lower()): parameters['seed'] = int(fields[1]) + if ('sfdfile' == fields[0].lower()): parameters['sfdfile'] = fields[1] + if ('impfile' == fields[0].lower()): parameters['impfile'] = fields[1] + if ('maxcrat' == fields[0].lower()): parameters['maxcrat'] = real2float(fields[1]) + if ('sfdcompare' == fields[0].lower()): parameters['sfdcompare'] = fields[1] + if ('interval' == fields[0].lower()): parameters['interval'] = real2float(fields[1]) + if ('numintervals' == fields[0].lower()): parameters['numintervals'] = int(fields[1]) + if ('popupconsole' == fields[0].lower()): parameters['popupconsole'] = fields[1] + if ('saveshaded' == fields[0].lower()): parameters['saveshaded'] = fields[1] + if ('saverego' == fields[0].lower()): parameters['saverego'] = fields[1] + if ('savepres' == fields[0].lower()): parameters['savepres'] = fields[1] + if ('savetruelist' == fields[0].lower()): parameters['savetruelist'] = fields[1] + if ('runtype' == fields[0].lower()): parameters['runtype'] = fields[1] + if ('restart' == fields[0].lower()): parameters['restart'] = fields[1] + if ('shadedminh' == fields[0].lower()): + parameters['shadedminh'] = real2float(fields[1]) + parameters['shadedminhdefault'] = 0 + if ('shadedmaxh' == fields[0].lower()): + parameters['shadedmaxh'] = real2float(fields[1]) + parameters['shadedmaxhdefault'] = 0 + + # Test values for further processing + if (parameters['interval'] <= 0.0): + print('Invalid value for or missing variable INTERVAL in ' + inputfile) + if (parameters['numintervals'] <= 0): + print('Invalid value for or missing variable NUMINTERVALS in ' + inputfile) + if (parameters['pix'] <= 0.0): + print('Invalid value for or missing variable PIX in ' + inputfile) + if (parameters['gridsize'] <= 0): + print('Invalid value for or missing variable GRIDSIZE in ' + inputfile) + if (parameters['seed'] == 0): + print('Invalid value for or missing variable SEED in ' + inputfile) + if (parameters['sfdfile'] is None): + print('Invalid value for or missing variable SFDFILE in ' + inputfile) + if (parameters['impfile'] is None): + print('Invalid value for or missing variable IMPFILE in ' + inputfile) + if (parameters['popupconsole'] is None): + print('Invalid value for or missing variable POPUPCONSOLE in ' + inputfile) + if (parameters['saveshaded'] is None): + print('Invalid value for or missing variable SAVESHADED in ' + inputfile) + if (parameters['saverego'] is None): + print('Invalid value for or missing variable SAVEREGO in ' + inputfile) + if (parameters['savepres'] is None): + print('Invalid value for or missing variable SAVEPRES in ' + inputfile) + if (parameters['savetruelist'] is None): + print('Invalid value for or missing variable SAVETRUELIST in ' + inputfile) + if (parameters['runtype'] is None): + print('Invalid value for or missing variable RUNTYPE in ' + inputfile) + if (parameters['restart'] is None): + print('Invalid value for or missing variable RESTART in ' + inputfile) + + return parameters diff --git a/python/ctem/tests/testio/ctem.in b/python/ctem/tests/testio/ctem.in new file mode 100755 index 00000000..e57310dc --- /dev/null +++ b/python/ctem/tests/testio/ctem.in @@ -0,0 +1,70 @@ +! CTEM Input file + + +! 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 5.934e3 ! 93km crater ! Diameter of test impactor (m) +testvel 15.0e3 ! Velocity of test crater (m/s) +testang 90.0 ! Impact angle of test crater (deg) - Default 90.0 +testxoffset 0.0e0 ! x-axis offset of crater center from grid center (m) - Default 0.0 +testyoffset 0.0e0 ! y-axis offset of crater center from grid center (m) - Default 0.0 +tallyonly F ! Tally the craters without generating any craters +testtally F + +! IDL driver in uts +interval 1.0 +numintervals 1 ! Total number of intervals +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 +saveshaded T ! Output shaded relief images +saverego F ! 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 (large file size) +runtype statistical ! single: craters accumulate in successive intervals + ! statistical: surface is reset between intervals +sfdcompare FassettCounts.txt + +! CTEM required inputs +seed 23790 ! Random number generator seed +gridsize 1000 ! Size of grid in pixels +numlayers 10 ! Number of perched layers +pix 0.3468773099817e3 ! Pixel size (m) - Copernicus DEM compariso +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 1.00e0 ! 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 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 +fe 2.00 +ejecta_truncation 2.0 +dorays F +superdomain F + +dorealistic T + diff --git a/python/ctem/tests/testio/testio.py b/python/ctem/tests/testio/testio.py new file mode 100644 index 00000000..ae329313 --- /dev/null +++ b/python/ctem/tests/testio/testio.py @@ -0,0 +1,7 @@ +import ctem + +d = dir(ctem) + +sim = ctem.Simulation() +for k, v in sim.parameters.items(): + print(k, v) \ No newline at end of file From aa12ad186eb82229d0f1cff44ddccceb705066c5 Mon Sep 17 00:00:00 2001 From: David Minton Date: Mon, 21 Feb 2022 11:33:10 -0500 Subject: [PATCH 12/32] Updated frontend with new io routines --- python/ctem/ctem/frontend.py | 83 ++++++++- python/ctem/ctem/io.py | 327 ++++++++++++++++++++++++++++++++++- 2 files changed, 406 insertions(+), 4 deletions(-) diff --git a/python/ctem/ctem/frontend.py b/python/ctem/ctem/frontend.py index 6340d5ec..69327c37 100644 --- a/python/ctem/ctem/frontend.py +++ b/python/ctem/ctem/frontend.py @@ -1,4 +1,4 @@ -import numpy +import numpy as np import os import subprocess import shutil @@ -43,4 +43,83 @@ def __init__(self, param_file="ctem.in"): } self.parameters = io.read_param(self.parameters) - return \ No newline at end of file + # Set up data arrays + self.seedarr = np.zeros(100, dtype=int) + self.seedarr[0] = self.parameters['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.parameters['gridsize'], self.parameters['gridsize']], dtype=np.float) + self.regolith = np.zeros([self.parameters['gridsize'], self.parameters['gridsize']], dtype=np.float) + + if self.parameters['sfdcompare'] is not None: + # Read sfdcompare file + sfdfile = os.path.join(self.parameters['workingdir'], self.parameters['sfdcompare']) + self.ph1 = io.read_formatted_ascii(sfdfile, skip_lines=0) + + # Read production function file + impfile = os.path.join(self.parameters['workingdir'], parameters['impfile']) + prodfunction = io.read_formatted_ascii(impfile, skip_lines=0) + + # Create impactor production population + area = (self.parameters['gridsize'] * self.parameters['pix']) ** 2 + self.production = np.copy(prodfunction) + self.production[:, 1] = self.production[:, 1] * area * self.parameters['interval'] + + # Write corrected production function to file + io.write_production(self.parameters, self.production) + + # Starting new or old run? + if (self.parameters['restart'].upper() == 'F'): + print('Starting a new run') + + if (self.parameters['runtype'].upper() == 'STATISTICAL'): + self.parameters['ncount'] = 1 + + # Write ctem.dat file + io.write_ctemdat(self.parameters, self.seedarr) + + else: + self.parameters['ncount'] = 0 + + # Delete tdistribution file, if it exists + tdist_file = os.path.join(self.parameters['workingdir'], 'tdistribution.dat') + if os.path.isfile(tdist_file): + os.remove(tdist_file) + else: + print('Continuing a previous run') + + # Read surface dem(shaded relief) and ejecta data files + dem_file = os.path.join(self.parameters['workingdir'], 'surface_dem.dat') + self.surface_dem = io.read_unformatted_binary(dem_file, self.parameters['gridsize']) + ejecta_file = os.path.join(self.parameters['workingdir'], 'surface_ejc.dat') + self.regolith = io.read_unformatted_binary(ejecta_file, self.parameters['gridsize']) + + # Read odistribution, tdistribution, and pdistribution files + ofile = os.path.join(self.parameters['workingdir'],'odistribution.dat') + odist = io.read_formatted_ascii(ofile, skip_lines=1) + tfile = os.path.join(self.parameters['workingdir'], 'tdistribution.dat') + tdist = io.read_formatted_ascii(tfile, skip_lines=1) + pfile = os.path.join(self.parameters['workingdir'], 'pdistribution.dat') + pdist = io.read_formatted_ascii(pfile, skip_lines=1) + + # Read impact mass from file + massfile = os.path.join(self.parameters['workingdir'], 'impactmass.dat') + impact_mass = io.read_impact_mass(massfile) + + # Read ctem.dat file + io.read_ctemdat(self.parameters, self.seedarr) + + # Open fracdonefile and regodepthfile for writing + # filename = os.path.join(self.parameters['workingdir'], 'fracdone.dat') + # fp_frac = open(filename, 'w') + # filename = os.path.join(self.parameters['workingdir'], 'regolithdepth.dat') + # fp_reg = open(filename, 'w') + + io.create_dir_structure(self.parameters) + + + return + + + def \ No newline at end of file diff --git a/python/ctem/ctem/io.py b/python/ctem/ctem/io.py index 664d8bb8..3786d87c 100644 --- a/python/ctem/ctem/io.py +++ b/python/ctem/ctem/io.py @@ -1,9 +1,17 @@ -import numpy +import numpy as np import os +import matplotlib.pyplot as plt +import shutil +from matplotlib.colors import LightSource +import matplotlib.cm as cm + + +#Set pixel scaling common for image writing, at 1 pixel/ array element +dpi = 72.0 def real2float(realstr): """ - Converts a Fortran-generated ASCII string of a real value into a numpy float type. Handles cases where double precision + Converts a Fortran-generated ASCII string of a real value into a np float type. Handles cases where double precision numbers in exponential notation use 'd' or 'D' instead of 'e' or 'E' Parameters @@ -85,3 +93,318 @@ def read_param(parameters): print('Invalid value for or missing variable RESTART in ' + inputfile) return parameters + + +def read_formatted_ascii(filename, skip_lines): + # Generalized ascii text reader + # For use with sfdcompare, production, odist, tdist, pdist data files + data = np.genfromtxt(filename, skip_header=skip_lines) + return data + + +def read_unformatted_binary(filename, gridsize): + # Read unformatted binary files created by Fortran + # For use with surface ejecta and surface dem data files + dt = np.float + data = np.fromfile(filename, dtype=dt) + data.shape = (gridsize, gridsize) + + return data + + +def read_ctemdat(parameters, seedarr): + # Read and parse ctem.dat file + datfile = parameters['workingdir'] + 'ctem.dat' + + # Read ctem.dat file + print('Reading input file ' + parameters['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: + parameters['totalimpacts'] = real2float(fields[0]) + parameters['ncount'] = int(fields[1]) + parameters['curyear'] = real2float(fields[2]) + parameters['restart'] = fields[3] + parameters['fracdone'] = real2float(fields[4]) + parameters['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 + + parameters['seedn'] = index - 1 + + return + + +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 write_production(parameters, production): + filename = parameters['workingdir'] + parameters['sfdfile'] + np.savetxt(filename, production, fmt='%1.8e', delimiter=' ') + + return + + +def create_dir_structure(parameters): + # Create directories for various output files if they do not already exist + directories = ['dist', 'misc', 'rego', 'rplot', 'surf', 'shaded'] + + for directory in directories: + dir_test = parameters['workingdir'] + directory + if not os.path.isdir(dir_test): + os.makedirs(dir_test) + + return + + +def write_ctemdat(parameters, seedarr): + # Write various parameters and random number seeds into ctem.dat file + filename = parameters['workingdir'] + parameters['datfile'] + fp = open(filename, 'w') + + template = "%(totalimpacts)17d %(ncount)12d %(curyear)19.12E %(restart)s %(fracdone)9.6f %(masstot)19.12E\n" + fp.write(template % parameters) + + # Write random number seeds to the file + for index in range(parameters['seedn']): + fp.write("%12d\n" % seedarr[index]) + + fp.close() + + return + + +def copy_dists(parameters): + # Save copies of distribution files + + orig_list = ['odistribution', 'ocumulative', 'pdistribution', 'tdistribution'] + dest_list = ['odist', 'ocum', 'pdist', 'tdist'] + + for index in range(len(orig_list)): + forig = parameters['workingdir'] + orig_list[index] + '.dat' + fdest = parameters['workingdir'] + 'dist' + os.sep + dest_list[index] + "_%06d.dat" % parameters['ncount'] + shutil.copy2(forig, fdest) + + forig = parameters['workingdir'] + 'impactmass.dat' + fdest = parameters['workingdir'] + 'misc' + os.sep + "mass_%06d.dat" % parameters['ncount'] + shutil.copy2(forig, fdest) + + if (parameters['savetruelist'].upper() == 'T'): + forig = parameters['workingdir'] + 'tcumulative.dat' + fdest = parameters['workingdir'] + 'dist' + os.sep + "tcum_%06d.dat" % parameters['ncount'] + shutil.copy2(forig, fdest) + + return + + +# Possible references +# http://nbviewer.jupyter.org/github/ThomasLecocq/geophysique.be/blob/master/2014-02-25%20Shaded%20Relief%20Map%20in%20Python.ipynb + +def image_dem(parameters, DEM): + dpi = 300.0 # 72.0 + pix = parameters['pix'] + gridsize = parameters['gridsize'] + ve = 1.0 + azimuth = 300.0 # parameters['azimuth'] + solar_angle = 20.0 # parameters['solar_angle'] + + ls = LightSource(azdeg=azimuth, altdeg=solar_angle) + dem_img = ls.hillshade(DEM, vert_exag=ve, dx=pix, dy=pix) + + # 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 = parameters['workingdir'] + 'surf' + os.sep + "surf%06d.png" % parameters['ncount'] + plt.savefig(filename, dpi=dpi, bbox_inches=0) + + return + + +def image_shaded_relief(parameters, DEM): + dpi = 300.0 # 72.0 + pix = parameters['pix'] + gridsize = parameters['gridsize'] + ve = 1.0 + mode = 'overlay' + azimuth = 300.0 # parameters['azimuth'] + solar_angle = 20.0 # parameters['solar_angle'] + + ls = LightSource(azdeg=azimuth, altdeg=solar_angle) + cmap = cm.cividis + + # If min and max appear to be reversed, then fix them + if (parameters['shadedminh'] > parameters['shadedmaxh']): + temp = parameters['shadedminh'] + parameters['shadedminh'] = parameters['shadedmaxh'] + parameters['shadedmaxh'] = temp + else: + parameters['shadedminh'] = parameters['shadedminh'] + parameters['shadedmaxh'] = parameters['shadedmaxh'] + + # If no shadedmin/max parameters are read in from ctem.dat, determine the values from the data + if (parameters['shadedminhdefault'] == 1): + shadedminh = np.amin(DEM) + else: + shadedminh = parameters['shadedminh'] + if (parameters['shadedmaxhdefault'] == 1): + shadedmaxh = np.amax(DEM) + else: + shadedmaxh = parameters['shadedmaxh'] + + dem_img = ls.shade(DEM, 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 = parameters['workingdir'] + 'shaded' + os.sep + "shaded%06d.png" % parameters['ncount'] + plt.savefig(filename, dpi=dpi, bbox_inches=0) + return parameters + + +def image_regolith(parameters, regolith): + # Create scaled regolith image + minref = parameters['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 = parameters['workingdir'] + 'rego' + os.sep + "rego%06d.png" % parameters['ncount'] + height = parameters['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) + + return + + +def create_rplot(parameters, odist, pdist, tdist, ph1): + # Parameters: empirical saturation limit and dfrac + satlimit = 3.12636 + dfrac = 2 ** (1. / 4) * 1.0e-3 + + # Calculate geometric saturation + minx = (parameters['pix'] / 3.0) * 1.0e-3 + maxx = 3 * parameters['pix'] * parameters['gridsize'] * 1.0e-3 + geomem = np.array([[minx, satlimit / 20.0], [maxx, satlimit / 20.0]]) + geomep = np.array([[minx, satlimit / 10.0], [maxx, satlimit / 10.0]]) + + # Create distribution arrays without zeros for plotting on log scale + idx = np.nonzero(odist[:, 5]) + odistnz = odist[idx] + odistnz = odistnz[:, [2, 5]] + + idx = np.nonzero(pdist[:, 5]) + pdistnz = pdist[idx] + pdistnz = pdistnz[:, [2, 5]] + + idx = np.nonzero(tdist[:, 5]) + tdistnz = tdist[idx] + tdistnz = tdistnz[:, [2, 5]] + + # Correct pdist + pdistnz[:, 1] = pdistnz[:, 1] * parameters['curyear'] / parameters['interval'] + + # Create sdist bin factors, which contain one crater per bin + area = (parameters['gridsize'] * parameters['pix'] * 1.0e-3) ** 2. + plo = 1 + sq2 = 2 ** (1. / 2) + while (sq2 ** plo > minx): + plo = plo - 1 + phi = plo + 1 + while (sq2 ** phi < maxx): + phi = phi + 1 + n = phi - plo + 1 + sdist = np.zeros([n, 2]) + p = plo + for index in range(n): + sdist[index, 0] = sq2 ** p + sdist[index, 1] = sq2 ** (2.0 * p + 1.5) / (area * (sq2 - 1)) + p = p + 1 + + # Create time label + tlabel = "%5.4e" % parameters['curyear'] + tlabel = tlabel.split('e') + texp = str(int(tlabel[1])) + timelabel = 'Time = ' + r'${}$ x 10$^{}$'.format(tlabel[0], texp) + ' yrs' + + # Save image to file + filename = parameters['workingdir'] + 'rplot' + os.sep + "rplot%06d.png" % parameters['ncount'] + height = parameters['gridsize'] / dpi + width = height + fig = plt.figure(figsize=(width, height), dpi=dpi) + + # Alter background color to be black, and change axis colors accordingly + plt.style.use('dark_background') + plt.rcParams['axes.prop_cycle'] + + # Plot data + plt.plot(odistnz[:, 0] * 1.0e-3, odistnz[:, 1], linewidth=3.0, color='blue') + plt.plot(pdistnz[:, 0] * 1.0e-3, pdistnz[:, 1], linewidth=2.0, linestyle='dashdot', color='white') + plt.plot(tdistnz[:, 0] * 1.0e-3, tdistnz[:, 1], linewidth=2.0, color='red') + + plt.plot(geomem[:, 0], geomem[:, 1], linewidth=2.0, linestyle=':', color='yellow') + plt.plot(geomep[:, 0], geomep[:, 1], linewidth=2.0, linestyle=':', color='yellow') + plt.plot(sdist[:, 0], sdist[:, 1], linewidth=2.0, linestyle=':', color='yellow') + + plt.plot(ph1[:, 0] * dfrac, ph1[:, 1], 'wo') + + # Create plot labels + plt.title('Crater Distribution R-Plot', fontsize=22) + plt.xlim([minx, maxx]) + plt.xscale('log') + plt.xlabel('Crater Diameter (km)', fontsize=18) + plt.ylim([5.0e-4, 5.0]) + plt.yscale('log') + plt.ylabel('R Value', fontsize=18) + plt.text(1.0e-2, 1.0, timelabel, fontsize=18) + + plt.tick_params(axis='both', which='major', labelsize=14) + plt.tick_params(axis='both', which='minor', labelsize=12) + + plt.savefig(filename) + + return From 58ee60823a62e6f78b2c7f53f372efd94ba2a99c Mon Sep 17 00:00:00 2001 From: David Minton Date: Mon, 21 Feb 2022 11:41:38 -0500 Subject: [PATCH 13/32] Fixed bug --- python/ctem/ctem/frontend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ctem/ctem/frontend.py b/python/ctem/ctem/frontend.py index 69327c37..f7ee95ea 100644 --- a/python/ctem/ctem/frontend.py +++ b/python/ctem/ctem/frontend.py @@ -122,4 +122,4 @@ def __init__(self, param_file="ctem.in"): return - def \ No newline at end of file + # def \ No newline at end of file From d67a569b336fca329e8a10dab1c1786210b21c4b Mon Sep 17 00:00:00 2001 From: David A Minton Date: Mon, 21 Feb 2022 18:02:36 -0500 Subject: [PATCH 14/32] Temporarily disable FPE halting modes in diffusion solver to prevent underflow --- src/util/util_diffusion_solver.f90 | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/util/util_diffusion_solver.f90 b/src/util/util_diffusion_solver.f90 index b9c23f45..7189dbd7 100644 --- a/src/util/util_diffusion_solver.f90 +++ b/src/util/util_diffusion_solver.f90 @@ -22,6 +22,7 @@ subroutine util_diffusion_solver(user,surf,N,indarray,kdiff,cumulative_elchange,maxhits) use module_globals use module_util, EXCEPT_THIS_ONE => util_diffusion_solver + use, intrinsic :: ieee_exceptions implicit none ! Arguments @@ -40,7 +41,12 @@ subroutine util_diffusion_solver(user,surf,N,indarray,kdiff,cumulative_elchange, integer(I4B) :: mi,mip1,mim1,mj,mjp1,mjm1,nloops real(DP),dimension(N,N) :: elchange integer(I4B),dimension(6,N,N) :: indarray_extended + logical, dimension(size(IEEE_ALL)) :: fpe_halting_modes, fpe_quiet_modes + logical, dimension(size(IEEE_USUAL)) :: fpe_flag + call ieee_get_halting_mode(IEEE_ALL,fpe_halting_modes) ! Save the current halting modes so we can turn them off temporarily + fpe_quiet_modes(:) = .false. + call ieee_set_halting_mode(IEEE_ALL,fpe_quiet_modes) cumulative_elchange = 0.0_DP kdiffmax = maxval(kdiff) @@ -122,6 +128,8 @@ subroutine util_diffusion_solver(user,surf,N,indarray,kdiff,cumulative_elchange, cumulative_elchange = cumulative_elchange + elchange end do + call ieee_set_halting_mode(IEEE_ALL,fpe_halting_modes) ! Restore the original FPE halting modes + return end subroutine util_diffusion_solver From a462529ad2e2ee223f636aac0640114e8df6cb24 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 22 Feb 2022 08:44:06 -0500 Subject: [PATCH 15/32] Installed a nifty tool in Pycharm called Code Blocks Sorter that let me sort the methods in alphabetical order. --- python/ctem/ctem/io.py | 632 +++++++++++++++++++++-------------------- 1 file changed, 317 insertions(+), 315 deletions(-) diff --git a/python/ctem/ctem/io.py b/python/ctem/ctem/io.py index 3786d87c..d4842f8c 100644 --- a/python/ctem/ctem/io.py +++ b/python/ctem/ctem/io.py @@ -1,40 +1,289 @@ -import numpy as np -import os -import matplotlib.pyplot as plt -import shutil -from matplotlib.colors import LightSource -import matplotlib.cm as cm +def copy_dists(parameters): + # Save copies of distribution files + + orig_list = ['odistribution', 'ocumulative', 'pdistribution', 'tdistribution'] + dest_list = ['odist', 'ocum', 'pdist', 'tdist'] + + for index in range(len(orig_list)): + forig = parameters['workingdir'] + orig_list[index] + '.dat' + fdest = parameters['workingdir'] + 'dist' + os.sep + dest_list[index] + "_%06d.dat" % parameters['ncount'] + shutil.copy2(forig, fdest) + + forig = parameters['workingdir'] + 'impactmass.dat' + fdest = parameters['workingdir'] + 'misc' + os.sep + "mass_%06d.dat" % parameters['ncount'] + shutil.copy2(forig, fdest) + + if (parameters['savetruelist'].upper() == 'T'): + forig = parameters['workingdir'] + 'tcumulative.dat' + fdest = parameters['workingdir'] + 'dist' + os.sep + "tcum_%06d.dat" % parameters['ncount'] + shutil.copy2(forig, fdest) + + return -#Set pixel scaling common for image writing, at 1 pixel/ array element -dpi = 72.0 +def create_dir_structure(parameters): + # Create directories for various output files if they do not already exist + directories = ['dist', 'misc', 'rego', 'rplot', 'surf', 'shaded'] + + for directory in directories: + dir_test = parameters['workingdir'] + directory + if not os.path.isdir(dir_test): + os.makedirs(dir_test) + + return -def real2float(realstr): - """ - Converts a Fortran-generated ASCII string of a real value into a np float type. Handles cases where double precision - numbers in exponential notation use 'd' or 'D' instead of 'e' or 'E' - Parameters - ---------- - realstr : string - Fortran-generated ASCII string of a real value. +def create_rplot(parameters, odist, pdist, tdist, ph1): + # Parameters: empirical saturation limit and dfrac + satlimit = 3.12636 + dfrac = 2 ** (1. / 4) * 1.0e-3 + + # Calculate geometric saturation + minx = (parameters['pix'] / 3.0) * 1.0e-3 + maxx = 3 * parameters['pix'] * parameters['gridsize'] * 1.0e-3 + geomem = np.array([[minx, satlimit / 20.0], [maxx, satlimit / 20.0]]) + geomep = np.array([[minx, satlimit / 10.0], [maxx, satlimit / 10.0]]) + + # Create distribution arrays without zeros for plotting on log scale + idx = np.nonzero(odist[:, 5]) + odistnz = odist[idx] + odistnz = odistnz[:, [2, 5]] + + idx = np.nonzero(pdist[:, 5]) + pdistnz = pdist[idx] + pdistnz = pdistnz[:, [2, 5]] + + idx = np.nonzero(tdist[:, 5]) + tdistnz = tdist[idx] + tdistnz = tdistnz[:, [2, 5]] + + # Correct pdist + pdistnz[:, 1] = pdistnz[:, 1] * parameters['curyear'] / parameters['interval'] + + # Create sdist bin factors, which contain one crater per bin + area = (parameters['gridsize'] * parameters['pix'] * 1.0e-3) ** 2. + plo = 1 + sq2 = 2 ** (1. / 2) + while (sq2 ** plo > minx): + plo = plo - 1 + phi = plo + 1 + while (sq2 ** phi < maxx): + phi = phi + 1 + n = phi - plo + 1 + sdist = np.zeros([n, 2]) + p = plo + for index in range(n): + sdist[index, 0] = sq2 ** p + sdist[index, 1] = sq2 ** (2.0 * p + 1.5) / (area * (sq2 - 1)) + p = p + 1 + + # Create time label + tlabel = "%5.4e" % parameters['curyear'] + tlabel = tlabel.split('e') + texp = str(int(tlabel[1])) + timelabel = 'Time = ' + r'${}$ x 10$^{}$'.format(tlabel[0], texp) + ' yrs' + + # Save image to file + filename = parameters['workingdir'] + 'rplot' + os.sep + "rplot%06d.png" % parameters['ncount'] + height = parameters['gridsize'] / dpi + width = height + fig = plt.figure(figsize=(width, height), dpi=dpi) + + # Alter background color to be black, and change axis colors accordingly + plt.style.use('dark_background') + plt.rcParams['axes.prop_cycle'] + + # Plot data + plt.plot(odistnz[:, 0] * 1.0e-3, odistnz[:, 1], linewidth=3.0, color='blue') + plt.plot(pdistnz[:, 0] * 1.0e-3, pdistnz[:, 1], linewidth=2.0, linestyle='dashdot', color='white') + plt.plot(tdistnz[:, 0] * 1.0e-3, tdistnz[:, 1], linewidth=2.0, color='red') + + plt.plot(geomem[:, 0], geomem[:, 1], linewidth=2.0, linestyle=':', color='yellow') + plt.plot(geomep[:, 0], geomep[:, 1], linewidth=2.0, linestyle=':', color='yellow') + plt.plot(sdist[:, 0], sdist[:, 1], linewidth=2.0, linestyle=':', color='yellow') + + plt.plot(ph1[:, 0] * dfrac, ph1[:, 1], 'wo') + + # Create plot labels + plt.title('Crater Distribution R-Plot', fontsize=22) + plt.xlim([minx, maxx]) + plt.xscale('log') + plt.xlabel('Crater Diameter (km)', fontsize=18) + plt.ylim([5.0e-4, 5.0]) + plt.yscale('log') + plt.ylabel('R Value', fontsize=18) + plt.text(1.0e-2, 1.0, timelabel, fontsize=18) + + plt.tick_params(axis='both', which='major', labelsize=14) + plt.tick_params(axis='both', which='minor', labelsize=12) + + plt.savefig(filename) + + return + +def image_dem(parameters, DEM): + dpi = 300.0 # 72.0 + pix = parameters['pix'] + gridsize = parameters['gridsize'] + ve = 1.0 + azimuth = 300.0 # parameters['azimuth'] + solar_angle = 20.0 # parameters['solar_angle'] + + ls = LightSource(azdeg=azimuth, altdeg=solar_angle) + dem_img = ls.hillshade(DEM, vert_exag=ve, dx=pix, dy=pix) + + # 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 = parameters['workingdir'] + 'surf' + os.sep + "surf%06d.png" % parameters['ncount'] + plt.savefig(filename, dpi=dpi, bbox_inches=0) + + return + + +def image_regolith(parameters, regolith): + # Create scaled regolith image + minref = parameters['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 = parameters['workingdir'] + 'rego' + os.sep + "rego%06d.png" % parameters['ncount'] + height = parameters['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) + + return - Returns - ------- - : float - The converted floating point value of the input string - """ - return float(realstr.replace('d', 'E').replace('D', 'E')) +def image_shaded_relief(parameters, DEM): + dpi = 300.0 # 72.0 + pix = parameters['pix'] + gridsize = parameters['gridsize'] + ve = 1.0 + mode = 'overlay' + azimuth = 300.0 # parameters['azimuth'] + solar_angle = 20.0 # parameters['solar_angle'] + + ls = LightSource(azdeg=azimuth, altdeg=solar_angle) + cmap = cm.cividis + + # If min and max appear to be reversed, then fix them + if (parameters['shadedminh'] > parameters['shadedmaxh']): + temp = parameters['shadedminh'] + parameters['shadedminh'] = parameters['shadedmaxh'] + parameters['shadedmaxh'] = temp + else: + parameters['shadedminh'] = parameters['shadedminh'] + parameters['shadedmaxh'] = parameters['shadedmaxh'] + + # If no shadedmin/max parameters are read in from ctem.dat, determine the values from the data + if (parameters['shadedminhdefault'] == 1): + shadedminh = np.amin(DEM) + else: + shadedminh = parameters['shadedminh'] + if (parameters['shadedmaxhdefault'] == 1): + shadedmaxh = np.amax(DEM) + else: + shadedmaxh = parameters['shadedmaxh'] + + dem_img = ls.shade(DEM, 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 = parameters['workingdir'] + 'shaded' + os.sep + "shaded%06d.png" % parameters['ncount'] + plt.savefig(filename, dpi=dpi, bbox_inches=0) + return parameters + + +def read_ctemdat(parameters, seedarr): + # Read and parse ctem.dat file + datfile = parameters['workingdir'] + 'ctem.dat' + + # Read ctem.dat file + print('Reading input file ' + parameters['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: + parameters['totalimpacts'] = real2float(fields[0]) + parameters['ncount'] = int(fields[1]) + parameters['curyear'] = real2float(fields[2]) + parameters['restart'] = fields[3] + parameters['fracdone'] = real2float(fields[4]) + parameters['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 + + parameters['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 + data = np.genfromtxt(filename, skip_header=skip_lines) + 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_param(parameters): # Read and parse ctem.in file inputfile = os.path.join(parameters['workingdir'], parameters['ctemfile']) - + # Read ctem.in file print('Reading input file ' + parameters['ctemfile']) with open(inputfile, 'r') as fp: lines = fp.readlines() - + # Process file text for line in lines: fields = line.split() @@ -61,7 +310,7 @@ def read_param(parameters): if ('shadedmaxh' == fields[0].lower()): parameters['shadedmaxh'] = real2float(fields[1]) parameters['shadedmaxhdefault'] = 0 - + # Test values for further processing if (parameters['interval'] <= 0.0): print('Invalid value for or missing variable INTERVAL in ' + inputfile) @@ -85,101 +334,42 @@ def read_param(parameters): print('Invalid value for or missing variable SAVEREGO in ' + inputfile) if (parameters['savepres'] is None): print('Invalid value for or missing variable SAVEPRES in ' + inputfile) - if (parameters['savetruelist'] is None): - print('Invalid value for or missing variable SAVETRUELIST in ' + inputfile) - if (parameters['runtype'] is None): - print('Invalid value for or missing variable RUNTYPE in ' + inputfile) - if (parameters['restart'] is None): - print('Invalid value for or missing variable RESTART in ' + inputfile) - - return parameters - - -def read_formatted_ascii(filename, skip_lines): - # Generalized ascii text reader - # For use with sfdcompare, production, odist, tdist, pdist data files - data = np.genfromtxt(filename, skip_header=skip_lines) - return data - - -def read_unformatted_binary(filename, gridsize): - # Read unformatted binary files created by Fortran - # For use with surface ejecta and surface dem data files - dt = np.float - data = np.fromfile(filename, dtype=dt) - data.shape = (gridsize, gridsize) - - return data - - -def read_ctemdat(parameters, seedarr): - # Read and parse ctem.dat file - datfile = parameters['workingdir'] + 'ctem.dat' - - # Read ctem.dat file - print('Reading input file ' + parameters['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: - parameters['totalimpacts'] = real2float(fields[0]) - parameters['ncount'] = int(fields[1]) - parameters['curyear'] = real2float(fields[2]) - parameters['restart'] = fields[3] - parameters['fracdone'] = real2float(fields[4]) - parameters['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 - - parameters['seedn'] = index - 1 - - return - - -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 + if (parameters['savetruelist'] is None): + print('Invalid value for or missing variable SAVETRUELIST in ' + inputfile) + if (parameters['runtype'] is None): + print('Invalid value for or missing variable RUNTYPE in ' + inputfile) + if (parameters['restart'] is None): + print('Invalid value for or missing variable RESTART in ' + inputfile) - return mass + return parameters -# Write production function to file production.dat -# This file format does not exactly match that generated from IDL. Does it work? -def write_production(parameters, production): - filename = parameters['workingdir'] + parameters['sfdfile'] - np.savetxt(filename, production, fmt='%1.8e', delimiter=' ') +def read_unformatted_binary(filename, gridsize): + # Read unformatted binary files created by Fortran + # For use with surface ejecta and surface dem data files + dt = np.float + data = np.fromfile(filename, dtype=dt) + data.shape = (gridsize, gridsize) - return + return data -def create_dir_structure(parameters): - # Create directories for various output files if they do not already exist - directories = ['dist', 'misc', 'rego', 'rplot', 'surf', 'shaded'] - - for directory in directories: - dir_test = parameters['workingdir'] + directory - if not os.path.isdir(dir_test): - os.makedirs(dir_test) - - return +def real2float(realstr): + """ + Converts a Fortran-generated ASCII string of a real value into a np float type. Handles cases where double precision + numbers in exponential notation use 'd' or 'D' instead of 'e' or 'E' + + Parameters + ---------- + realstr : string + Fortran-generated ASCII string of a real value. + + Returns + ------- + : float + The converted floating point value of the input string + """ + return float(realstr.replace('d', 'E').replace('D', 'E')) def write_ctemdat(parameters, seedarr): @@ -189,7 +379,7 @@ def write_ctemdat(parameters, seedarr): template = "%(totalimpacts)17d %(ncount)12d %(curyear)19.12E %(restart)s %(fracdone)9.6f %(masstot)19.12E\n" fp.write(template % parameters) - + # Write random number seeds to the file for index in range(parameters['seedn']): fp.write("%12d\n" % seedarr[index]) @@ -199,212 +389,24 @@ def write_ctemdat(parameters, seedarr): return -def copy_dists(parameters): - # Save copies of distribution files - - orig_list = ['odistribution', 'ocumulative', 'pdistribution', 'tdistribution'] - dest_list = ['odist', 'ocum', 'pdist', 'tdist'] - - for index in range(len(orig_list)): - forig = parameters['workingdir'] + orig_list[index] + '.dat' - fdest = parameters['workingdir'] + 'dist' + os.sep + dest_list[index] + "_%06d.dat" % parameters['ncount'] - shutil.copy2(forig, fdest) - - forig = parameters['workingdir'] + 'impactmass.dat' - fdest = parameters['workingdir'] + 'misc' + os.sep + "mass_%06d.dat" % parameters['ncount'] - shutil.copy2(forig, fdest) - - if (parameters['savetruelist'].upper() == 'T'): - forig = parameters['workingdir'] + 'tcumulative.dat' - fdest = parameters['workingdir'] + 'dist' + os.sep + "tcum_%06d.dat" % parameters['ncount'] - shutil.copy2(forig, fdest) - - return - - # Possible references -# http://nbviewer.jupyter.org/github/ThomasLecocq/geophysique.be/blob/master/2014-02-25%20Shaded%20Relief%20Map%20in%20Python.ipynb - -def image_dem(parameters, DEM): - dpi = 300.0 # 72.0 - pix = parameters['pix'] - gridsize = parameters['gridsize'] - ve = 1.0 - azimuth = 300.0 # parameters['azimuth'] - solar_angle = 20.0 # parameters['solar_angle'] - - ls = LightSource(azdeg=azimuth, altdeg=solar_angle) - dem_img = ls.hillshade(DEM, vert_exag=ve, dx=pix, dy=pix) - - # 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 = parameters['workingdir'] + 'surf' + os.sep + "surf%06d.png" % parameters['ncount'] - plt.savefig(filename, dpi=dpi, bbox_inches=0) - - return - - -def image_shaded_relief(parameters, DEM): - dpi = 300.0 # 72.0 - pix = parameters['pix'] - gridsize = parameters['gridsize'] - ve = 1.0 - mode = 'overlay' - azimuth = 300.0 # parameters['azimuth'] - solar_angle = 20.0 # parameters['solar_angle'] - - ls = LightSource(azdeg=azimuth, altdeg=solar_angle) - cmap = cm.cividis - - # If min and max appear to be reversed, then fix them - if (parameters['shadedminh'] > parameters['shadedmaxh']): - temp = parameters['shadedminh'] - parameters['shadedminh'] = parameters['shadedmaxh'] - parameters['shadedmaxh'] = temp - else: - parameters['shadedminh'] = parameters['shadedminh'] - parameters['shadedmaxh'] = parameters['shadedmaxh'] - - # If no shadedmin/max parameters are read in from ctem.dat, determine the values from the data - if (parameters['shadedminhdefault'] == 1): - shadedminh = np.amin(DEM) - else: - shadedminh = parameters['shadedminh'] - if (parameters['shadedmaxhdefault'] == 1): - shadedmaxh = np.amax(DEM) - else: - shadedmaxh = parameters['shadedmaxh'] - - dem_img = ls.shade(DEM, 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 = parameters['workingdir'] + 'shaded' + os.sep + "shaded%06d.png" % parameters['ncount'] - plt.savefig(filename, dpi=dpi, bbox_inches=0) - return parameters +# http://nbviewer.jupyter.org/github/ThomasLecocq/geophysique.be/blob/master/2014-02-25%20Shaded%20Relief%20Map%20in%20Python.ipynb - -def image_regolith(parameters, regolith): - # Create scaled regolith image - minref = parameters['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 = parameters['workingdir'] + 'rego' + os.sep + "rego%06d.png" % parameters['ncount'] - height = parameters['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) +def write_production(parameters, production): + filename = parameters['workingdir'] + parameters['sfdfile'] + np.savetxt(filename, production, fmt='%1.8e', delimiter=' ') return -def create_rplot(parameters, odist, pdist, tdist, ph1): - # Parameters: empirical saturation limit and dfrac - satlimit = 3.12636 - dfrac = 2 ** (1. / 4) * 1.0e-3 - - # Calculate geometric saturation - minx = (parameters['pix'] / 3.0) * 1.0e-3 - maxx = 3 * parameters['pix'] * parameters['gridsize'] * 1.0e-3 - geomem = np.array([[minx, satlimit / 20.0], [maxx, satlimit / 20.0]]) - geomep = np.array([[minx, satlimit / 10.0], [maxx, satlimit / 10.0]]) - - # Create distribution arrays without zeros for plotting on log scale - idx = np.nonzero(odist[:, 5]) - odistnz = odist[idx] - odistnz = odistnz[:, [2, 5]] - - idx = np.nonzero(pdist[:, 5]) - pdistnz = pdist[idx] - pdistnz = pdistnz[:, [2, 5]] - - idx = np.nonzero(tdist[:, 5]) - tdistnz = tdist[idx] - tdistnz = tdistnz[:, [2, 5]] - - # Correct pdist - pdistnz[:, 1] = pdistnz[:, 1] * parameters['curyear'] / parameters['interval'] - - # Create sdist bin factors, which contain one crater per bin - area = (parameters['gridsize'] * parameters['pix'] * 1.0e-3) ** 2. - plo = 1 - sq2 = 2 ** (1. / 2) - while (sq2 ** plo > minx): - plo = plo - 1 - phi = plo + 1 - while (sq2 ** phi < maxx): - phi = phi + 1 - n = phi - plo + 1 - sdist = np.zeros([n, 2]) - p = plo - for index in range(n): - sdist[index, 0] = sq2 ** p - sdist[index, 1] = sq2 ** (2.0 * p + 1.5) / (area * (sq2 - 1)) - p = p + 1 - - # Create time label - tlabel = "%5.4e" % parameters['curyear'] - tlabel = tlabel.split('e') - texp = str(int(tlabel[1])) - timelabel = 'Time = ' + r'${}$ x 10$^{}$'.format(tlabel[0], texp) + ' yrs' - - # Save image to file - filename = parameters['workingdir'] + 'rplot' + os.sep + "rplot%06d.png" % parameters['ncount'] - height = parameters['gridsize'] / dpi - width = height - fig = plt.figure(figsize=(width, height), dpi=dpi) +dpi = 72.0 - # Alter background color to be black, and change axis colors accordingly - plt.style.use('dark_background') - plt.rcParams['axes.prop_cycle'] - # Plot data - plt.plot(odistnz[:, 0] * 1.0e-3, odistnz[:, 1], linewidth=3.0, color='blue') - plt.plot(pdistnz[:, 0] * 1.0e-3, pdistnz[:, 1], linewidth=2.0, linestyle='dashdot', color='white') - plt.plot(tdistnz[:, 0] * 1.0e-3, tdistnz[:, 1], linewidth=2.0, color='red') - - plt.plot(geomem[:, 0], geomem[:, 1], linewidth=2.0, linestyle=':', color='yellow') - plt.plot(geomep[:, 0], geomep[:, 1], linewidth=2.0, linestyle=':', color='yellow') - plt.plot(sdist[:, 0], sdist[:, 1], linewidth=2.0, linestyle=':', color='yellow') - - plt.plot(ph1[:, 0] * dfrac, ph1[:, 1], 'wo') +from matplotlib.colors import LightSource +import matplotlib.cm as cm - # Create plot labels - plt.title('Crater Distribution R-Plot', fontsize=22) - plt.xlim([minx, maxx]) - plt.xscale('log') - plt.xlabel('Crater Diameter (km)', fontsize=18) - plt.ylim([5.0e-4, 5.0]) - plt.yscale('log') - plt.ylabel('R Value', fontsize=18) - plt.text(1.0e-2, 1.0, timelabel, fontsize=18) - - plt.tick_params(axis='both', which='major', labelsize=14) - plt.tick_params(axis='both', which='minor', labelsize=12) - - plt.savefig(filename) - - return +# Set pixel scaling common for image writing, at 1 pixel/ array element +import matplotlib.pyplot as plt +import numpy as np +import os +import shutil From 56bc4c40995b046c79ec7a6e60304d674c7fc20d Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 22 Feb 2022 09:52:12 -0500 Subject: [PATCH 16/32] Fixed position of import statements --- python/ctem/ctem/io.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/python/ctem/ctem/io.py b/python/ctem/ctem/io.py index d4842f8c..60ae499e 100644 --- a/python/ctem/ctem/io.py +++ b/python/ctem/ctem/io.py @@ -1,3 +1,13 @@ +import numpy as np +import os +import shutil +from matplotlib.colors import LightSource +import matplotlib.cm as cm +import matplotlib.pyplot as plt + +# Set pixel scaling common for image writing, at 1 pixel/ array element +dpi = 72.0 + def copy_dists(parameters): # Save copies of distribution files @@ -398,15 +408,3 @@ def write_production(parameters, production): return - -dpi = 72.0 - - -from matplotlib.colors import LightSource -import matplotlib.cm as cm - -# Set pixel scaling common for image writing, at 1 pixel/ array element -import matplotlib.pyplot as plt -import numpy as np -import os -import shutil From cee986627317452a41fe8bb383a00effce5e5457 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 22 Feb 2022 11:54:27 -0500 Subject: [PATCH 17/32] Restructured the driver to be object oriented and streamlined --- python/ctem/ctem/__init__.py | 2 +- python/ctem/ctem/ctem_draw_surf.py | 69 ----- python/ctem/ctem/ctem_driver.py | 229 --------------- python/ctem/ctem/ctem_io_readers.py | 163 ----------- python/ctem/ctem/ctem_io_writers.py | 264 ------------------ python/ctem/ctem/dist_reader.py | 29 -- python/ctem/ctem/driver.py | 263 +++++++++++++++++ python/ctem/ctem/frontend.py | 125 --------- python/ctem/ctem/io.py | 205 +++++++------- .../ctem/{ctem_viewer_3d.py => viewer3d.py} | 2 +- python/ctem/tests/testio/testio.py | 2 +- 11 files changed, 367 insertions(+), 986 deletions(-) delete mode 100644 python/ctem/ctem/ctem_draw_surf.py delete mode 100644 python/ctem/ctem/ctem_driver.py delete mode 100644 python/ctem/ctem/ctem_io_readers.py delete mode 100644 python/ctem/ctem/ctem_io_writers.py delete mode 100644 python/ctem/ctem/dist_reader.py create mode 100644 python/ctem/ctem/driver.py delete mode 100644 python/ctem/ctem/frontend.py rename python/ctem/ctem/{ctem_viewer_3d.py => viewer3d.py} (98%) diff --git a/python/ctem/ctem/__init__.py b/python/ctem/ctem/__init__.py index b9aa95ac..165a1bb0 100644 --- a/python/ctem/ctem/__init__.py +++ b/python/ctem/ctem/__init__.py @@ -1,4 +1,4 @@ # from ctem.ctem_io_readers import * # from ctem.ctem_io_writers import * # from ctem.ctem_driver import * -from ctem.frontend import * \ No newline at end of file +from ctem.driver import * \ No newline at end of file diff --git a/python/ctem/ctem/ctem_draw_surf.py b/python/ctem/ctem/ctem_draw_surf.py deleted file mode 100644 index 74bf81e1..00000000 --- a/python/ctem/ctem/ctem_draw_surf.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/local/bin/python -# -#Cratered Terrain Evolution Model driver -# -#Original IDL design: Jim Richardson, Arecibo Observatory -#Revised IDL design: David Minton, Purdue University -#Re-engineered design and Python implementation: Matthew Route, Purdue University -#August 2016 - -#Import general purpose modules -import numpy -import os -import subprocess -import shutil - -#Import CTEM modules -import ctem_io_readers -import ctem_io_writers - -#Create and initialize data dictionaries for parameters and options from CTEM.in -notset = '-NOTSET-' -currentdir = os.getcwd() + os.sep - -parameters={'restart': notset, - 'runtype': notset, - 'popupconsole': notset, - 'saveshaded': notset, - 'saverego': notset, - 'savepres': notset, - 'savetruelist': notset, - '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': 'ctem.in', - 'datfile': 'ctem.dat', - 'impfile': notset, - 'sfdcompare': notset, - 'sfdfile': notset} - -#Read ctem.in to initialize parameter values based on user input -ctem_io_readers.read_ctemin(parameters,notset) -ctem_io_writers.create_dir_structure(parameters) - -dem_file = parameters['workingdir'] + 'surface_dem.dat' -surface_dem = ctem_io_readers.read_unformatted_binary(dem_file, parameters['gridsize']) - -#Set up data arrays -seedarr = numpy.zeros(100, dtype = numpy.int) -seedarr[0] = parameters['seed'] - -#Read ctem.dat file -ctem_io_readers.read_ctemdat(parameters, seedarr) - -#Write surface dem -ctem_io_writers.image_dem(parameters, surface_dem) \ No newline at end of file diff --git a/python/ctem/ctem/ctem_driver.py b/python/ctem/ctem/ctem_driver.py deleted file mode 100644 index 29057053..00000000 --- a/python/ctem/ctem/ctem_driver.py +++ /dev/null @@ -1,229 +0,0 @@ -#!/usr/local/bin/python -# -#Cratered Terrain Evolution Model driver -# -#Original IDL design: Jim Richardson, Arecibo Observatory -#Revised IDL design: David Minton, Purdue University -#Re-engineered design and Python implementation: Matthew Route, Purdue University -#August 2016 - -#Import general purpose modules -import numpy -import os -import subprocess -import shutil - -#Import CTEM modules -import ctem_io_readers -import ctem_io_writers - -#Create and initialize data dictionaries for parameters and options from CTEM.in -notset = '-NOTSET-' -currentdir = os.getcwd() + os.sep - -parameters={'restart': notset, - 'runtype': notset, - 'popupconsole': notset, - 'saveshaded': notset, - 'saverego': notset, - 'savepres': notset, - 'savetruelist': notset, - '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': 'ctem.in', - 'datfile': 'ctem.dat', - 'impfile': notset, - 'sfdcompare': notset, - 'sfdfile': notset} - -#Read ctem.in to initialize parameter values based on user input -ctem_io_readers.read_ctemin(parameters,notset) - -#Read sfdcompare file -sfdfile = parameters['workingdir'] + parameters['sfdcompare'] -ph1 = ctem_io_readers.read_formatted_ascii(sfdfile, skip_lines = 0) - -#Set up data arrays -seedarr = numpy.zeros(100, dtype = numpy.int) -seedarr[0] = parameters['seed'] -odist = numpy.zeros([1, 6]) -pdist = numpy.zeros([1, 6]) -tdist = numpy.zeros([1, 6]) -surface_dem = numpy.zeros([parameters['gridsize'], parameters['gridsize']], dtype = numpy.float) -regolith = numpy.zeros([parameters['gridsize'], parameters['gridsize']], dtype =numpy.float) - -#Read production function file -impfile = parameters['workingdir'] + parameters['impfile'] -prodfunction = ctem_io_readers.read_formatted_ascii(impfile, skip_lines = 0) - -#Create impactor production population -area = (parameters['gridsize'] * parameters['pix'])**2 -production = numpy.copy(prodfunction) -production[:,1] = production[:,1] * area * parameters['interval'] - -#Write corrected production function to file -ctem_io_writers.write_production(parameters, production) - -#Starting new or old run? -if (parameters['restart'].upper() == 'F'): - print('Starting a new run') - - if (parameters['runtype'].upper() == 'STATISTICAL'): - parameters['ncount'] = 1 - - #Write ctem.dat file - ctem_io_writers.write_ctemdat(parameters, seedarr) - - else: - parameters['ncount'] = 0 - - #Delete tdistribution file, if it exists - tdist_file = parameters['workingdir'] + 'tdistribution.dat' - if os.path.isfile(tdist_file): - os.remove(tdist_file) - -else: - print('Continuing a previous run') - - #Read surface dem(shaded relief) and ejecta data files - dem_file = parameters['workingdir'] + 'surface_dem.dat' - surface_dem = ctem_io_readers.read_unformatted_binary(dem_file, parameters['gridsize']) - ejecta_file = parameters['workingdir'] + 'surface_ejc.dat' - regolith = ctem_io_readers.read_unformatted_binary(ejecta_file, parameters['gridsize']) - - #Read odistribution, tdistribution, and pdistribution files - ofile = parameters['workingdir'] + 'odistribution.dat' - odist = ctem_io_readers.read_formatted_ascii(ofile, skip_lines = 1) - tfile = parameters['workingdir'] + 'tdistribution.dat' - tdist = ctem_io_readers.read_formatted_ascii(tfile, skip_lines = 1) - pfile = parameters['workingdir'] + 'pdistribution.dat' - pdist = ctem_io_readers.read_formatted_ascii(pfile, skip_lines = 1) - - #Read impact mass from file - massfile = parameters['workingdir'] + 'impactmass.dat' - impact_mass = ctem_io_readers.read_impact_mass(massfile) - - #Read ctem.dat file - ctem_io_readers.read_ctemdat(parameters, seedarr) - -#Open fracdonefile and regodepthfile for writing -filename = parameters['workingdir'] + 'fracdone.dat' -fp_frac = open(filename,'w') -filename = parameters['workingdir'] + 'regolithdepth.dat' -fp_reg = open(filename,'w') - -#Begin CTEM processing loops -print('Beginning loops') - -ctem_io_writers.create_dir_structure(parameters) - -while (parameters['ncount'] <= parameters['numintervals']): - - #Create crater population - if (parameters['ncount'] > 0): - - #Move ctem.dat - forig = parameters['workingdir'] + 'ctem.dat' - fdest = parameters['workingdir'] + 'misc' + os.sep + "ctem%06d.dat" % parameters['ncount'] - shutil.copy2(forig, fdest) - - #Create crater population and display CTEM progress on screen - print(parameters['ncount'], ' Calling FORTRAN routine') - with subprocess.Popen([parameters['workingdir']+'CTEM'], - stdout=subprocess.PIPE, - universal_newlines=True) as p: - for line in p.stdout: - print(line, end='') - - - #Optional: do not pipe CTEM progress to the screen - #subprocess.check_output([parameters['workingdir']+'CTEM']) - - #Read Fortran output - print(parameters['ncount'], ' Reading Fortran output') - - #Read surface dem(shaded relief) and ejecta data files - dem_file = parameters['workingdir'] + 'surface_dem.dat' - surface_dem = ctem_io_readers.read_unformatted_binary(dem_file, parameters['gridsize']) - ejecta_file = parameters['workingdir'] + 'surface_ejc.dat' - regolith = ctem_io_readers.read_unformatted_binary(ejecta_file, parameters['gridsize']) - - #Read odistribution, tdistribution, and pdistribution files - ofile = parameters['workingdir'] + 'odistribution.dat' - odist = ctem_io_readers.read_formatted_ascii(ofile, skip_lines = 1) - tfile = parameters['workingdir'] + 'tdistribution.dat' - tdist = ctem_io_readers.read_formatted_ascii(tfile, skip_lines = 1) - pfile = parameters['workingdir'] + 'pdistribution.dat' - pdist = ctem_io_readers.read_formatted_ascii(pfile, skip_lines = 1) - - #Read impact mass from file - massfile = parameters['workingdir'] + 'impactmass.dat' - impact_mass = ctem_io_readers.read_impact_mass(massfile) - - #Read ctem.dat file - ctem_io_readers.read_ctemdat(parameters, seedarr) - - #Update parameters: mass, curyear, regolith properties - parameters['masstot'] = parameters['masstot'] + impact_mass - - parameters['curyear'] = parameters['curyear'] + parameters['fracdone'] * parameters['interval'] - template = "%(fracdone)9.6f %(curyear)19.12E\n" - fp_frac.write(template % parameters) - - reg_text = "%19.12E %19.12E %19.12E %19.12E\n" % (parameters['curyear'], - numpy.mean(regolith), numpy.amax(regolith), numpy.amin(regolith)) - fp_reg.write(reg_text) - - #Save copy of crater distribution files - ctem_io_writers.copy_dists(parameters) - - #Display results - print(parameters['ncount'], ' Displaying results') - - #Write surface dem, surface ejecta, shaded relief, and rplot data - ctem_io_writers.image_dem(parameters, surface_dem) - if (parameters['saverego'].upper() == 'T'): - ctem_io_writers.image_regolith(parameters, regolith) - if (parameters['saveshaded'].upper() == 'T'): - ctem_io_writers.image_shaded_relief(parameters, surface_dem) - if (parameters['savepres'].upper() == 'T'): - ctem_io_writers.create_rplot(parameters,odist,pdist,tdist,ph1) - - #Update ncount - parameters['ncount'] = parameters['ncount'] + 1 - - if ((parameters['runtype'].upper() == 'STATISTICAL') or (parameters['ncount'] == 1)): - parameters['restart'] = 'F' - parameters['curyear'] = 0.0 - parameters['totalimpacts'] = 0 - parameters['masstot'] = 0.0 - - #Delete tdistribution file, if it exists - tdist_file = parameters['workingdir'] + 'tdistribution.dat' - if os.path.isfile(tdist_file): - os.remove(tdist_file) - - else: - parameters['restart'] = 'T' - - #Write ctem.dat file - ctem_io_writers.write_ctemdat(parameters, seedarr) - -#Close updateable fracdonefile and regodepthfile files -fp_frac.close() -fp_reg.close() diff --git a/python/ctem/ctem/ctem_io_readers.py b/python/ctem/ctem/ctem_io_readers.py deleted file mode 100644 index 0935fac9..00000000 --- a/python/ctem/ctem/ctem_io_readers.py +++ /dev/null @@ -1,163 +0,0 @@ -#!/usr/local/bin/python -# -#Cratered Terrain Evolution Model file reading utilities -# -#Original IDL design: Jim Richardson, Arecibo Observatory -#Revised IDL design: David Minton, Purdue University -#Re-engineered design and Python implementation: Matthew Route, Purdue University -#August 2016 -# -#Known issues for operation with CTEM -#1) ctem.in has 1.0d0 value for maxcrat which is not readable by Python - -import numpy - - -def real2float(realstr): - """ - Converts a Fortran-generated ASCII string of a real value into a numpy float type. Handles cases where double precision - numbers in exponential notation use 'd' or 'D' instead of 'e' or 'E' - - Parameters - ---------- - realstr : string - Fortran-generated ASCII string of a real value. - - Returns - ------- - : float - The converted floating point value of the input string - """ - return float(realstr.replace('d', 'E').replace('D', 'E')) - - -def read_ctemin(parameters,notset): - #Read and parse ctem.in file - inputfile = parameters['workingdir'] + parameters['ctemfile'] - - #Read ctem.in file - print('Reading input file '+ parameters['ctemfile']) - fp = open(inputfile,'r') - lines = fp.readlines() - fp.close() - - #Process file text - for line in lines: - fields = line.split() - if len(fields) > 0: - if ('pix' == fields[0].lower()): parameters['pix']=real2float(fields[1]) - if ('gridsize' == fields[0].lower()): parameters['gridsize']=int(fields[1]) - if ('seed' == fields[0].lower()): parameters['seed']=int(fields[1]) - if ('sfdfile' == fields[0].lower()): parameters['sfdfile']=fields[1] - if ('impfile' == fields[0].lower()): parameters['impfile']=fields[1] - if ('maxcrat' == fields[0].lower()): parameters['maxcrat']=real2float(fields[1]) - if ('sfdcompare' == fields[0].lower()): parameters['sfdcompare']=fields[1] - if ('interval' == fields[0].lower()): parameters['interval']=real2float(fields[1]) - if ('numintervals' == fields[0].lower()): parameters['numintervals']=int(fields[1]) - if ('popupconsole' == fields[0].lower()): parameters['popupconsole']=fields[1] - if ('saveshaded' == fields[0].lower()): parameters['saveshaded']=fields[1] - if ('saverego' == fields[0].lower()): parameters['saverego']=fields[1] - if ('savepres' == fields[0].lower()): parameters['savepres']=fields[1] - if ('savetruelist' == fields[0].lower()): parameters['savetruelist']=fields[1] - if ('runtype' == fields[0].lower()): parameters['runtype']=fields[1] - if ('restart' == fields[0].lower()): parameters['restart']=fields[1] - if ('shadedminh' == fields[0].lower()): - parameters['shadedminh'] = real2float(fields[1]) - parameters['shadedminhdefault'] = 0 - if ('shadedmaxh' == fields[0].lower()): - parameters['shadedmaxh'] = real2float(fields[1]) - parameters['shadedmaxhdefault'] = 0 - - #Test values for further processing - if (parameters['interval'] <= 0.0): - print('Invalid value for or missing variable INTERVAL in '+ inputfile) - if (parameters['numintervals'] <= 0): - print('Invalid value for or missing variable NUMINTERVALS in '+ inputfile) - if (parameters['pix'] <= 0.0): - print('Invalid value for or missing variable PIX in '+ inputfile) - if (parameters['gridsize'] <= 0): - print('Invalid value for or missing variable GRIDSIZE in '+ inputfile) - if (parameters['seed'] == 0): - print('Invalid value for or missing variable SEED in '+ inputfile) - if (parameters['sfdfile'] == notset): - print('Invalid value for or missing variable SFDFILE in '+ inputfile) - if (parameters['impfile'] == notset): - print('Invalid value for or missing variable IMPFILE in '+ inputfile) - if (parameters['popupconsole'] == notset): - print('Invalid value for or missing variable POPUPCONSOLE in '+ inputfile) - if (parameters['saveshaded'] == notset): - print('Invalid value for or missing variable SAVESHADED in '+ inputfile) - if (parameters['saverego'] == notset): - print('Invalid value for or missing variable SAVEREGO in '+ inputfile) - if (parameters['savepres'] == notset): - print('Invalid value for or missing variable SAVEPRES in '+ inputfile) - if (parameters['savetruelist'] == notset): - print('Invalid value for or missing variable SAVETRUELIST in '+ inputfile) - if (parameters['runtype'] == notset): - print('Invalid value for or missing variable RUNTYPE in '+ inputfile) - if (parameters['restart'] == notset): - print('Invalid value for or missing variable RESTART in '+ inputfile) - - return - -def read_formatted_ascii(filename, skip_lines): - #Generalized ascii text reader - #For use with sfdcompare, production, odist, tdist, pdist data files - data = numpy.genfromtxt(filename, skip_header = skip_lines) - return data - -def read_unformatted_binary(filename, gridsize): - #Read unformatted binary files created by Fortran - #For use with surface ejecta and surface dem data files - dt = numpy.float - data = numpy.fromfile(filename, dtype = dt) - data.shape = (gridsize,gridsize) - - return data - -def read_ctemdat(parameters, seedarr): - #Read and parse ctem.dat file - datfile = parameters['workingdir'] + 'ctem.dat' - - #Read ctem.dat file - print('Reading input file '+ parameters['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: - parameters['totalimpacts'] = real2float(fields[0]) - parameters['ncount'] = int(fields[1]) - parameters['curyear'] = real2float(fields[2]) - parameters['restart'] = fields[3] - parameters['fracdone'] = real2float(fields[4]) - parameters['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 - - parameters['seedn'] = index - 1 - - return - -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 \ No newline at end of file diff --git a/python/ctem/ctem/ctem_io_writers.py b/python/ctem/ctem/ctem_io_writers.py deleted file mode 100644 index 7bf21ce4..00000000 --- a/python/ctem/ctem/ctem_io_writers.py +++ /dev/null @@ -1,264 +0,0 @@ -#!/usr/local/bin/python -# -#Cratered Terrain Evolution Model file and graphical writing utilities -# -#Original IDL design: Jim Richardson, Arecibo Observatory -#Revised IDL design: David Minton, Purdue University -#Re-engineered design and Python implementation: Matthew Route, Purdue University -#August 2016 -# - -import matplotlib -from matplotlib import pyplot -import numpy -import os -import shutil -import scipy -from scipy import signal -from matplotlib.colors import LightSource -import matplotlib.cm as cm - -#Set pixel scaling common for image writing, at 1 pixel/ array element -dpi = 72.0 - -#Write production function to file production.dat -#This file format does not exactly match that generated from IDL. Does it work? -def write_production(parameters, production): - filename = parameters['workingdir'] + parameters['sfdfile'] - numpy.savetxt(filename, production, fmt='%1.8e', delimiter=' ') - - return - -def create_dir_structure(parameters): - #Create directories for various output files if they do not already exist - directories=['dist','misc','rego','rplot','surf','shaded'] - - for directory in directories: - dir_test = parameters['workingdir'] + directory - if not os.path.isdir(dir_test): - os.makedirs(dir_test) - - return - -def write_ctemdat(parameters, seedarr): - #Write various parameters and random number seeds into ctem.dat file - filename = parameters['workingdir'] + parameters['datfile'] - fp = open(filename,'w') - - template = "%(totalimpacts)17d %(ncount)12d %(curyear)19.12E %(restart)s %(fracdone)9.6f %(masstot)19.12E\n" - fp.write(template % parameters) - - #Write random number seeds to the file - for index in range(parameters['seedn']): - fp.write("%12d\n" % seedarr[index]) - - fp.close() - - return - -def copy_dists(parameters): - #Save copies of distribution files - - orig_list = ['odistribution', 'ocumulative', 'pdistribution', 'tdistribution'] - dest_list = ['odist', 'ocum', 'pdist', 'tdist'] - - for index in range(len(orig_list)): - forig = parameters['workingdir'] + orig_list[index] + '.dat' - fdest = parameters['workingdir'] + 'dist' + os.sep + dest_list[index] + "_%06d.dat" % parameters['ncount'] - shutil.copy2(forig, fdest) - - forig = parameters['workingdir'] + 'impactmass.dat' - fdest = parameters['workingdir'] + 'misc' + os.sep + "mass_%06d.dat" % parameters['ncount'] - shutil.copy2(forig, fdest) - - if (parameters['savetruelist'].upper() == 'T'): - forig = parameters['workingdir'] + 'tcumulative.dat' - fdest = parameters['workingdir'] + 'dist' + os.sep + "tcum_%06d.dat" % parameters['ncount'] - shutil.copy2(forig, fdest) - - return - -#Possible references -#http://nbviewer.jupyter.org/github/ThomasLecocq/geophysique.be/blob/master/2014-02-25%20Shaded%20Relief%20Map%20in%20Python.ipynb - -def image_dem(parameters, DEM): - dpi = 300.0 # 72.0 - pix = parameters['pix'] - gridsize = parameters['gridsize'] - ve = 1.0 - azimuth = 300.0 #parameters['azimuth'] - solar_angle = 20.0 #parameters['solar_angle'] - - ls = LightSource(azdeg=azimuth, altdeg=solar_angle) - dem_img = ls.hillshade(DEM, vert_exag=ve, dx=pix, dy=pix) - - # Generate image to put into an array - height = gridsize / dpi - width = gridsize / dpi - fig = matplotlib.pyplot.figure(figsize=(width, height), dpi=dpi) - ax = matplotlib.pyplot.axes([0, 0, 1, 1]) - ax.imshow(dem_img, interpolation="nearest", cmap='gray',vmin=0.0,vmax=1.0) - matplotlib.pyplot.axis('off') - # Save image to file - filename = parameters['workingdir'] + 'surf' + os.sep + "surf%06d.png" % parameters['ncount'] - matplotlib.pyplot.savefig(filename,dpi=dpi,bbox_inches=0) - - return - -def image_shaded_relief(parameters, DEM): - dpi = 300.0 #72.0 - pix = parameters['pix'] - gridsize = parameters['gridsize'] - ve = 1.0 - mode = 'overlay' - azimuth = 300.0 #parameters['azimuth'] - solar_angle = 20.0 #parameters['solar_angle'] - - ls = LightSource(azdeg=azimuth, altdeg=solar_angle) - cmap = cm.cividis - - # If min and max appear to be reversed, then fix them - if (parameters['shadedminh'] > parameters['shadedmaxh']): - temp = parameters['shadedminh'] - parameters['shadedminh'] = parameters['shadedmaxh'] - parameters['shadedmaxh'] = temp - else: - parameters['shadedminh'] = parameters['shadedminh'] - parameters['shadedmaxh'] = parameters['shadedmaxh'] - - # If no shadedmin/max parameters are read in from ctem.dat, determine the values from the data - if (parameters['shadedminhdefault'] == 1): - shadedminh = numpy.amin(DEM) - else: - shadedminh = parameters['shadedminh'] - if (parameters['shadedmaxhdefault'] == 1): - shadedmaxh = numpy.amax(DEM) - else: - shadedmaxh = parameters['shadedmaxh'] - - dem_img = ls.shade(DEM, 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 = matplotlib.pyplot.figure(figsize=(width, height), dpi=dpi) - ax = matplotlib.pyplot.axes([0, 0, 1, 1]) - ax.imshow(dem_img,interpolation="nearest",vmin=0.0,vmax=1.0) - matplotlib.pyplot.axis('off') - # Save image to file - filename = parameters['workingdir'] + 'shaded' + os.sep + "shaded%06d.png" % parameters['ncount'] - matplotlib.pyplot.savefig(filename,dpi=dpi,bbox_inches=0) - return - - -def image_regolith(parameters, regolith): - # Create scaled regolith image - minref = parameters['pix'] * 1.0e-4 - maxreg = numpy.amax(regolith) - minreg = numpy.amin(regolith) - if (minreg < minref): minreg = minref - if (maxreg < minref): maxreg = (minref + 1.0e3) - regolith_scaled = numpy.copy(regolith) - numpy.place(regolith_scaled, regolith_scaled < minref, minref) - regolith_scaled = 254.0 * ( - (numpy.log(regolith_scaled) - numpy.log(minreg)) / (numpy.log(maxreg) - numpy.log(minreg))) - - # Save image to file - filename = parameters['workingdir'] + 'rego' + os.sep + "rego%06d.png" % parameters['ncount'] - height = parameters['gridsize'] / dpi - width = height - fig = matplotlib.pyplot.figure(figsize=(width, height), dpi=dpi) - fig.figimage(regolith_scaled, cmap=matplotlib.cm.nipy_spectral, origin='lower') - matplotlib.pyplot.savefig(filename) - - return - -def create_rplot(parameters,odist,pdist,tdist,ph1): - #Parameters: empirical saturation limit and dfrac - satlimit = 3.12636 - dfrac = 2**(1./4) * 1.0e-3 - - #Calculate geometric saturation - minx = (parameters['pix'] / 3.0) * 1.0e-3 - maxx = 3 * parameters['pix'] * parameters['gridsize'] * 1.0e-3 - geomem = numpy.array([[minx, satlimit / 20.0], [maxx, satlimit / 20.0]]) - geomep = numpy.array([[minx, satlimit / 10.0], [maxx, satlimit / 10.0]]) - - #Create distribution arrays without zeros for plotting on log scale - idx = numpy.nonzero(odist[:,5]) - odistnz = odist[idx] - odistnz = odistnz[:,[2,5]] - - idx = numpy.nonzero(pdist[:,5]) - pdistnz = pdist[idx] - pdistnz = pdistnz[:,[2,5]] - - idx = numpy.nonzero(tdist[:,5]) - tdistnz = tdist[idx] - tdistnz = tdistnz[:,[2,5]] - - #Correct pdist - pdistnz[:,1] = pdistnz[:,1] * parameters['curyear'] / parameters['interval'] - - #Create sdist bin factors, which contain one crater per bin - area = (parameters['gridsize'] * parameters['pix'] * 1.0e-3)**2. - plo = 1 - sq2 = 2**(1./2) - while (sq2**plo > minx): - plo = plo - 1 - phi = plo + 1 - while (sq2**phi < maxx): - phi = phi + 1 - n = phi - plo + 1 - sdist = numpy.zeros([n , 2]) - p = plo - for index in range(n): - sdist[index, 0] = sq2**p - sdist[index, 1] = sq2**(2.0*p + 1.5) / (area * (sq2 - 1)) - p = p + 1 - - #Create time label - tlabel = "%5.4e" % parameters['curyear'] - tlabel = tlabel.split('e') - texp = str(int(tlabel[1])) - timelabel = 'Time = '+ r'${}$ x 10$^{}$'.format(tlabel[0], texp) + ' yrs' - - #Save image to file - filename = parameters['workingdir'] + 'rplot' + os.sep + "rplot%06d.png" % parameters['ncount'] - height = parameters['gridsize'] / dpi - width = height - fig = matplotlib.pyplot.figure(figsize = (width, height), dpi = dpi) - - #Alter background color to be black, and change axis colors accordingly - matplotlib.pyplot.style.use('dark_background') - matplotlib.pyplot.rcParams['axes.prop_cycle'] - - #Plot data - matplotlib.pyplot.plot(odistnz[:,0]*1.0e-3, odistnz[:,1], linewidth=3.0, color = 'blue') - matplotlib.pyplot.plot(pdistnz[:,0]*1.0e-3, pdistnz[:,1], linewidth=2.0, linestyle='dashdot', color = 'white') - matplotlib.pyplot.plot(tdistnz[:,0]*1.0e-3, tdistnz[:,1], linewidth=2.0, color = 'red') - - matplotlib.pyplot.plot(geomem[:,0], geomem[:,1], linewidth=2.0, linestyle =':', color = 'yellow') - matplotlib.pyplot.plot(geomep[:,0], geomep[:,1], linewidth=2.0, linestyle =':', color = 'yellow') - matplotlib.pyplot.plot(sdist[:,0], sdist[:,1], linewidth=2.0, linestyle =':', color = 'yellow') - - matplotlib.pyplot.plot(ph1[:,0] * dfrac, ph1[:,1], 'wo') - - #Create plot labels - matplotlib.pyplot.title('Crater Distribution R-Plot',fontsize=22) - matplotlib.pyplot.xlim([minx, maxx]) - matplotlib.pyplot.xscale('log') - matplotlib.pyplot.xlabel('Crater Diameter (km)',fontsize=18) - matplotlib.pyplot.ylim([5.0e-4, 5.0]) - matplotlib.pyplot.yscale('log') - matplotlib.pyplot.ylabel('R Value', fontsize=18) - matplotlib.pyplot.text(1.0e-2, 1.0, timelabel, fontsize=18) - - matplotlib.pyplot.tick_params(axis='both', which='major', labelsize=14) - matplotlib.pyplot.tick_params(axis='both', which='minor', labelsize=12) - - matplotlib.pyplot.savefig(filename) - - return \ No newline at end of file diff --git a/python/ctem/ctem/dist_reader.py b/python/ctem/ctem/dist_reader.py deleted file mode 100644 index 31793793..00000000 --- a/python/ctem/ctem/dist_reader.py +++ /dev/null @@ -1,29 +0,0 @@ -import numpy as np -import pandas as pd - -gridsize = 2000 -pix = 3.08e3 -side = (gridsize * pix) -area = side**2 -iside = [-side, 0.0, side] -basin_crater_cutoff = 300000.0 #diameter in meters - -craters = pd.read_csv('NPF-global-Kd0.0001/dist/ocum_000100.dat',delim_whitespace=True) - -basins = craters.loc[craters['#Dcrat(m)'] >= basin_crater_cutoff] - -for bind, b in basins.iterrows(): - print(f"Basin{bind:02}: ",b['#Dcrat(m)'],b['time(y)']) - overlaps = open(f"NPF-global-Kd0.0001/basin_overlap/overlap{bind:02}.dat", 'w') - print(f"#BASIN NUMBER {bind}: Diameter = {b['#Dcrat(m)']}, Time {b['time(y)']}", file=overlaps) - for cind, c in craters.iterrows(): - if c['time(y)'] > b['time(y)']: - for i in iside: - for j in iside: - disx = b['xpos(m)'] - c['xpos(m)'] + i - disy = b['ypos(m)'] - c['ypos(m)'] + j - distance = np.sqrt(disx ** 2 + disy ** 2) - if distance < 0.5 * (b['#Dcrat(m)'] + c['#Dcrat(m)']): - print(c['#Dcrat(m)'],c['xpos(m)'],c['ypos(m)'],c['time(y)'], file=overlaps) - - diff --git a/python/ctem/ctem/driver.py b/python/ctem/ctem/driver.py new file mode 100644 index 00000000..764759cc --- /dev/null +++ b/python/ctem/ctem/driver.py @@ -0,0 +1,263 @@ +import numpy as np +import os +import subprocess +import shutil +from ctem import io + +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"): + currentdir = os.getcwd() + self.user = { + 'restart': None, + 'runtype': None, + 'popupconsole': None, + 'saveshaded': None, + 'saverego': None, + 'savepres': 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': os.path.join(currentdir, param_file), + 'impfile': None, + 'sfdcompare': None, + 'sfdfile': None + } + self.user = io.read_user_input(self.user) + + 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', + 'ocum': 'ocumulative.dat', + 'odist': 'odistribution.dat', + 'pdist': 'pdistribution.dat', + 'tcum' : 'tcumulative.dat', + 'tdist' : 'tdistribution.dat', + 'impmass' : 'impactmass.dat', + 'fracdone' : 'fracdone.dat', + 'regodepth' : 'regolithdepth.dat', + } + + for k, v in self.output_filenames.items(): + self.output_filenames[k] = os.path.join(currentdir, v) + + # 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.regolith = np.zeros([self.user['gridsize'], self.user['gridsize']], dtype=float) + + if self.user['sfdcompare'] is not None: + # Read sfdcompare file + sfdfile = os.path.join(self.user['workingdir'], self.user['sfdcompare']) + self.ph1 = io.read_formatted_ascii(sfdfile, skip_lines=0) + + # Scale the production function to the simulation domain + self.scale_production() + + # Starting new or old run? + if (self.user['restart'].upper() == 'F'): + print('Starting a new run') + + io.create_dir_structure(self.user) + + if (self.user['runtype'].upper() == 'STATISTICAL'): + self.user['ncount'] = 1 + + # Write ctem.dat file + io.write_datfile(self.user, self.seedarr) + else: + self.user['ncount'] = 0 + + # Delete any old output files + for k, v in self.output_filenames.items(): + if os.path.isfile(v): + os.remove(v) + else: + print('Continuing a previous run') + self.process_interval(isnew=False) + + + 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 = io.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 + io.write_production(self.user, 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() + + # Process output files + self.process_interval() + + # Display results + print(self.user['ncount'], ' Displaying results') + + # Write surface dem, surface ejecta, shaded relief, and rplot data + io.image_dem(self.user, self.surface_dem) + if (self.user['saverego'].upper() == 'T'): + io.image_regolith(self.user, self.surface_ejc) + if (self.user['saveshaded'].upper() == 'T'): + io.image_shaded_relief(self.user, self.surface_dem) + if (self.user['savepres'].upper() == 'T'): + io.create_rplot(self.user, self.odist, self.pdist, self.tdist, self.ph1) + + # Update ncount + self.user['ncount'] = self.user['ncount'] + 1 + + if ((self.user['runtype'].upper() == 'STATISTICAL') or (self.user['ncount'] == 1)): + self.user['restart'] = 'F' + self.user['curyear'] = 0.0 + self.user['totalimpacts'] = 0 + self.user['masstot'] = 0.0 + + # Delete tdistribution file, if it exists + 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 + io.write_datfile(self.user, self.output_filenames['dat'],self.seedarr) + + return + + def compute_one_interval(self): + """ + 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') + with subprocess.Popen([os.path.join(self.user['workingdir'], 'CTEM')], + stdout=subprocess.PIPE, + universal_newlines=True) as p: + for line in p.stdout: + print(line, end='') + + return + + def process_interval(self, isnew=True): + """ + 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 = io.read_unformatted_binary(self.output_filenames['dem'], self.user['gridsize']) + self.surface_ejc = io.read_unformatted_binary(self.output_filenames['ejc'], self.user['gridsize']) + + # Read odistribution, tdistribution, and pdistribution files + self.odist = io.read_formatted_ascii(self.output_filenames['odist'], skip_lines=1) + self.tdist = io.read_formatted_ascii(self.output_filenames['tdist'], skip_lines=1) + self.pdist = io.read_formatted_ascii(self.output_filenames['pdist'], skip_lines=1) + + # Read impact mass from file + impact_mass = io.read_impact_mass(self.output_filenames['massfile']) + + # Read ctem.dat file + io.read_ctemdat(self.user, self.seedarr) + + # Save copy of crater distribution files + if isnew: + + # Update user: mass, curyear, regolith properties + self.user['masstot'] = self.user['masstot'] + 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']) 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']) as fp_reg: + fp_reg.write(reg_text) + + self.redirect_outputs(['odist', 'ocum', 'pdist', 'tdist'], 'dist') + if (self.user['savetruelist'].upper() == 'T'): + self.redirect_outputs(['tcum'], 'dist') + self.redirect_outputs(['impmass'], 'misc') + return + + 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] + fdist = os.path.join(self.user['workingdir'], foldername, f"{k}_{self.user['ncount']:06d}.dat") + +if __name__ == '__main__': + sim = Simulation() + sim.run() \ No newline at end of file diff --git a/python/ctem/ctem/frontend.py b/python/ctem/ctem/frontend.py deleted file mode 100644 index f7ee95ea..00000000 --- a/python/ctem/ctem/frontend.py +++ /dev/null @@ -1,125 +0,0 @@ -import numpy as np -import os -import subprocess -import shutil -from ctem import io - -class Simulation: - """ - This is a class that defines the basic CTEM simulation object - """ - def __init__(self, param_file="ctem.in"): - currentdir = os.getcwd() - self.parameters = { - 'restart': None, - 'runtype': None, - 'popupconsole': None, - 'saveshaded': None, - 'saverego': None, - 'savepres': 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, - 'datfile': 'ctem.dat', - 'impfile': None, - 'sfdcompare': None, - 'sfdfile': None - } - self.parameters = io.read_param(self.parameters) - - # Set up data arrays - self.seedarr = np.zeros(100, dtype=int) - self.seedarr[0] = self.parameters['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.parameters['gridsize'], self.parameters['gridsize']], dtype=np.float) - self.regolith = np.zeros([self.parameters['gridsize'], self.parameters['gridsize']], dtype=np.float) - - if self.parameters['sfdcompare'] is not None: - # Read sfdcompare file - sfdfile = os.path.join(self.parameters['workingdir'], self.parameters['sfdcompare']) - self.ph1 = io.read_formatted_ascii(sfdfile, skip_lines=0) - - # Read production function file - impfile = os.path.join(self.parameters['workingdir'], parameters['impfile']) - prodfunction = io.read_formatted_ascii(impfile, skip_lines=0) - - # Create impactor production population - area = (self.parameters['gridsize'] * self.parameters['pix']) ** 2 - self.production = np.copy(prodfunction) - self.production[:, 1] = self.production[:, 1] * area * self.parameters['interval'] - - # Write corrected production function to file - io.write_production(self.parameters, self.production) - - # Starting new or old run? - if (self.parameters['restart'].upper() == 'F'): - print('Starting a new run') - - if (self.parameters['runtype'].upper() == 'STATISTICAL'): - self.parameters['ncount'] = 1 - - # Write ctem.dat file - io.write_ctemdat(self.parameters, self.seedarr) - - else: - self.parameters['ncount'] = 0 - - # Delete tdistribution file, if it exists - tdist_file = os.path.join(self.parameters['workingdir'], 'tdistribution.dat') - if os.path.isfile(tdist_file): - os.remove(tdist_file) - else: - print('Continuing a previous run') - - # Read surface dem(shaded relief) and ejecta data files - dem_file = os.path.join(self.parameters['workingdir'], 'surface_dem.dat') - self.surface_dem = io.read_unformatted_binary(dem_file, self.parameters['gridsize']) - ejecta_file = os.path.join(self.parameters['workingdir'], 'surface_ejc.dat') - self.regolith = io.read_unformatted_binary(ejecta_file, self.parameters['gridsize']) - - # Read odistribution, tdistribution, and pdistribution files - ofile = os.path.join(self.parameters['workingdir'],'odistribution.dat') - odist = io.read_formatted_ascii(ofile, skip_lines=1) - tfile = os.path.join(self.parameters['workingdir'], 'tdistribution.dat') - tdist = io.read_formatted_ascii(tfile, skip_lines=1) - pfile = os.path.join(self.parameters['workingdir'], 'pdistribution.dat') - pdist = io.read_formatted_ascii(pfile, skip_lines=1) - - # Read impact mass from file - massfile = os.path.join(self.parameters['workingdir'], 'impactmass.dat') - impact_mass = io.read_impact_mass(massfile) - - # Read ctem.dat file - io.read_ctemdat(self.parameters, self.seedarr) - - # Open fracdonefile and regodepthfile for writing - # filename = os.path.join(self.parameters['workingdir'], 'fracdone.dat') - # fp_frac = open(filename, 'w') - # filename = os.path.join(self.parameters['workingdir'], 'regolithdepth.dat') - # fp_reg = open(filename, 'w') - - io.create_dir_structure(self.parameters) - - - return - - - # def \ No newline at end of file diff --git a/python/ctem/ctem/io.py b/python/ctem/ctem/io.py index 60ae499e..0b587234 100644 --- a/python/ctem/ctem/io.py +++ b/python/ctem/ctem/io.py @@ -8,49 +8,50 @@ # Set pixel scaling common for image writing, at 1 pixel/ array element dpi = 72.0 -def copy_dists(parameters): +def copy_dists(user, output_filenames, distlist): # Save copies of distribution files orig_list = ['odistribution', 'ocumulative', 'pdistribution', 'tdistribution'] dest_list = ['odist', 'ocum', 'pdist', 'tdist'] for index in range(len(orig_list)): - forig = parameters['workingdir'] + orig_list[index] + '.dat' - fdest = parameters['workingdir'] + 'dist' + os.sep + dest_list[index] + "_%06d.dat" % parameters['ncount'] + forig = user['workingdir'] + orig_list[index] + '.dat' + fdest = user['workingdir'] + 'dist' + os.sep + dest_list[index] + "_%06d.dat" % user['ncount'] shutil.copy2(forig, fdest) - forig = parameters['workingdir'] + 'impactmass.dat' - fdest = parameters['workingdir'] + 'misc' + os.sep + "mass_%06d.dat" % parameters['ncount'] + forig = user['workingdir'] + 'impactmass.dat' + fdest = user['workingdir'] + 'misc' + os.sep + "mass_%06d.dat" % user['ncount'] shutil.copy2(forig, fdest) - if (parameters['savetruelist'].upper() == 'T'): - forig = parameters['workingdir'] + 'tcumulative.dat' - fdest = parameters['workingdir'] + 'dist' + os.sep + "tcum_%06d.dat" % parameters['ncount'] + if (user['savetruelist'].upper() == 'T'): + forig = user['workingdir'] + 'tcumulative.dat' + fdest = user['workingdir'] + 'dist' + os.sep + "tcum_%06d.dat" % user['ncount'] shutil.copy2(forig, fdest) return -def create_dir_structure(parameters): + +def create_dir_structure(user): # Create directories for various output files if they do not already exist directories = ['dist', 'misc', 'rego', 'rplot', 'surf', 'shaded'] for directory in directories: - dir_test = parameters['workingdir'] + directory + dir_test = user['workingdir'] + directory if not os.path.isdir(dir_test): os.makedirs(dir_test) return -def create_rplot(parameters, odist, pdist, tdist, ph1): +def create_rplot(user, odist, pdist, tdist, ph1): # Parameters: empirical saturation limit and dfrac satlimit = 3.12636 dfrac = 2 ** (1. / 4) * 1.0e-3 # Calculate geometric saturation - minx = (parameters['pix'] / 3.0) * 1.0e-3 - maxx = 3 * parameters['pix'] * parameters['gridsize'] * 1.0e-3 + minx = (user['pix'] / 3.0) * 1.0e-3 + maxx = 3 * user['pix'] * user['gridsize'] * 1.0e-3 geomem = np.array([[minx, satlimit / 20.0], [maxx, satlimit / 20.0]]) geomep = np.array([[minx, satlimit / 10.0], [maxx, satlimit / 10.0]]) @@ -68,10 +69,10 @@ def create_rplot(parameters, odist, pdist, tdist, ph1): tdistnz = tdistnz[:, [2, 5]] # Correct pdist - pdistnz[:, 1] = pdistnz[:, 1] * parameters['curyear'] / parameters['interval'] + pdistnz[:, 1] = pdistnz[:, 1] * user['curyear'] / user['interval'] # Create sdist bin factors, which contain one crater per bin - area = (parameters['gridsize'] * parameters['pix'] * 1.0e-3) ** 2. + area = (user['gridsize'] * user['pix'] * 1.0e-3) ** 2. plo = 1 sq2 = 2 ** (1. / 2) while (sq2 ** plo > minx): @@ -88,14 +89,14 @@ def create_rplot(parameters, odist, pdist, tdist, ph1): p = p + 1 # Create time label - tlabel = "%5.4e" % parameters['curyear'] + tlabel = "%5.4e" % user['curyear'] tlabel = tlabel.split('e') texp = str(int(tlabel[1])) timelabel = 'Time = ' + r'${}$ x 10$^{}$'.format(tlabel[0], texp) + ' yrs' # Save image to file - filename = parameters['workingdir'] + 'rplot' + os.sep + "rplot%06d.png" % parameters['ncount'] - height = parameters['gridsize'] / dpi + filename = user['workingdir'] + 'rplot' + os.sep + "rplot%06d.png" % user['ncount'] + height = user['gridsize'] / dpi width = height fig = plt.figure(figsize=(width, height), dpi=dpi) @@ -131,13 +132,13 @@ def create_rplot(parameters, odist, pdist, tdist, ph1): return -def image_dem(parameters, DEM): +def image_dem(user, DEM): dpi = 300.0 # 72.0 - pix = parameters['pix'] - gridsize = parameters['gridsize'] + pix = user['pix'] + gridsize = user['gridsize'] ve = 1.0 - azimuth = 300.0 # parameters['azimuth'] - solar_angle = 20.0 # parameters['solar_angle'] + azimuth = 300.0 # user['azimuth'] + solar_angle = 20.0 # user['solar_angle'] ls = LightSource(azdeg=azimuth, altdeg=solar_angle) dem_img = ls.hillshade(DEM, vert_exag=ve, dx=pix, dy=pix) @@ -150,15 +151,15 @@ def image_dem(parameters, DEM): ax.imshow(dem_img, interpolation="nearest", cmap='gray', vmin=0.0, vmax=1.0) plt.axis('off') # Save image to file - filename = parameters['workingdir'] + 'surf' + os.sep + "surf%06d.png" % parameters['ncount'] + filename = user['workingdir'] + 'surf' + os.sep + "surf%06d.png" % user['ncount'] plt.savefig(filename, dpi=dpi, bbox_inches=0) return -def image_regolith(parameters, regolith): +def image_regolith(user, regolith): # Create scaled regolith image - minref = parameters['pix'] * 1.0e-4 + minref = user['pix'] * 1.0e-4 maxreg = np.amax(regolith) minreg = np.amin(regolith) if (minreg < minref): minreg = minref @@ -169,8 +170,8 @@ def image_regolith(parameters, regolith): (np.log(regolith_scaled) - np.log(minreg)) / (np.log(maxreg) - np.log(minreg))) # Save image to file - filename = parameters['workingdir'] + 'rego' + os.sep + "rego%06d.png" % parameters['ncount'] - height = parameters['gridsize'] / dpi + filename = user['workingdir'] + 'rego' + os.sep + "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') @@ -179,36 +180,36 @@ def image_regolith(parameters, regolith): return -def image_shaded_relief(parameters, DEM): +def image_shaded_relief(user, DEM): dpi = 300.0 # 72.0 - pix = parameters['pix'] - gridsize = parameters['gridsize'] + pix = user['pix'] + gridsize = user['gridsize'] ve = 1.0 mode = 'overlay' - azimuth = 300.0 # parameters['azimuth'] - solar_angle = 20.0 # parameters['solar_angle'] + azimuth = 300.0 # user['azimuth'] + solar_angle = 20.0 # user['solar_angle'] ls = LightSource(azdeg=azimuth, altdeg=solar_angle) cmap = cm.cividis # If min and max appear to be reversed, then fix them - if (parameters['shadedminh'] > parameters['shadedmaxh']): - temp = parameters['shadedminh'] - parameters['shadedminh'] = parameters['shadedmaxh'] - parameters['shadedmaxh'] = temp + if (user['shadedminh'] > user['shadedmaxh']): + temp = user['shadedminh'] + user['shadedminh'] = user['shadedmaxh'] + user['shadedmaxh'] = temp else: - parameters['shadedminh'] = parameters['shadedminh'] - parameters['shadedmaxh'] = parameters['shadedmaxh'] + user['shadedminh'] = user['shadedminh'] + user['shadedmaxh'] = user['shadedmaxh'] - # If no shadedmin/max parameters are read in from ctem.dat, determine the values from the data - if (parameters['shadedminhdefault'] == 1): + # 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 = parameters['shadedminh'] - if (parameters['shadedmaxhdefault'] == 1): + shadedminh = user['shadedminh'] + if (user['shadedmaxhdefault'] == 1): shadedmaxh = np.amax(DEM) else: - shadedmaxh = parameters['shadedmaxh'] + shadedmaxh = user['shadedmaxh'] dem_img = ls.shade(DEM, cmap=cmap, blend_mode=mode, fraction=1.0, vert_exag=ve, dx=pix, dy=pix, @@ -222,17 +223,17 @@ def image_shaded_relief(parameters, DEM): ax.imshow(dem_img, interpolation="nearest", vmin=0.0, vmax=1.0) plt.axis('off') # Save image to file - filename = parameters['workingdir'] + 'shaded' + os.sep + "shaded%06d.png" % parameters['ncount'] + filename = user['workingdir'] + 'shaded' + os.sep + "shaded%06d.png" % user['ncount'] plt.savefig(filename, dpi=dpi, bbox_inches=0) - return parameters + return user -def read_ctemdat(parameters, seedarr): +def read_datfile(user, seedarr): # Read and parse ctem.dat file - datfile = parameters['workingdir'] + 'ctem.dat' + datfile = user['workingdir'] + 'ctem.dat' # Read ctem.dat file - print('Reading input file ' + parameters['datfile']) + print('Reading input file ' + user['datfile']) fp = open(datfile, 'r') lines = fp.readlines() fp.close() @@ -240,12 +241,12 @@ def read_ctemdat(parameters, seedarr): # Parse file lines and update parameter fields fields = lines[0].split() if len(fields) > 0: - parameters['totalimpacts'] = real2float(fields[0]) - parameters['ncount'] = int(fields[1]) - parameters['curyear'] = real2float(fields[2]) - parameters['restart'] = fields[3] - parameters['fracdone'] = real2float(fields[4]) - parameters['masstot'] = real2float(fields[5]) + 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) @@ -255,7 +256,7 @@ def read_ctemdat(parameters, seedarr): seedarr[index - 1] = real2float(fields[0]) index += 1 - parameters['seedn'] = index - 1 + user['seedn'] = index - 1 return @@ -285,12 +286,12 @@ def read_impact_mass(filename): # Write production function to file production.dat # This file format does not exactly match that generated from IDL. Does it work? -def read_param(parameters): +def read_user_input(user): # Read and parse ctem.in file - inputfile = os.path.join(parameters['workingdir'], parameters['ctemfile']) + inputfile = user['ctemfile'] # Read ctem.in file - print('Reading input file ' + parameters['ctemfile']) + print('Reading input file ' + user['ctemfile']) with open(inputfile, 'r') as fp: lines = fp.readlines() @@ -298,60 +299,60 @@ def read_param(parameters): for line in lines: fields = line.split() if len(fields) > 0: - if ('pix' == fields[0].lower()): parameters['pix'] = real2float(fields[1]) - if ('gridsize' == fields[0].lower()): parameters['gridsize'] = int(fields[1]) - if ('seed' == fields[0].lower()): parameters['seed'] = int(fields[1]) - if ('sfdfile' == fields[0].lower()): parameters['sfdfile'] = fields[1] - if ('impfile' == fields[0].lower()): parameters['impfile'] = fields[1] - if ('maxcrat' == fields[0].lower()): parameters['maxcrat'] = real2float(fields[1]) - if ('sfdcompare' == fields[0].lower()): parameters['sfdcompare'] = fields[1] - if ('interval' == fields[0].lower()): parameters['interval'] = real2float(fields[1]) - if ('numintervals' == fields[0].lower()): parameters['numintervals'] = int(fields[1]) - if ('popupconsole' == fields[0].lower()): parameters['popupconsole'] = fields[1] - if ('saveshaded' == fields[0].lower()): parameters['saveshaded'] = fields[1] - if ('saverego' == fields[0].lower()): parameters['saverego'] = fields[1] - if ('savepres' == fields[0].lower()): parameters['savepres'] = fields[1] - if ('savetruelist' == fields[0].lower()): parameters['savetruelist'] = fields[1] - if ('runtype' == fields[0].lower()): parameters['runtype'] = fields[1] - if ('restart' == fields[0].lower()): parameters['restart'] = fields[1] + 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 ('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 ('shadedminh' == fields[0].lower()): - parameters['shadedminh'] = real2float(fields[1]) - parameters['shadedminhdefault'] = 0 + user['shadedminh'] = real2float(fields[1]) + user['shadedminhdefault'] = 0 if ('shadedmaxh' == fields[0].lower()): - parameters['shadedmaxh'] = real2float(fields[1]) - parameters['shadedmaxhdefault'] = 0 + user['shadedmaxh'] = real2float(fields[1]) + user['shadedmaxhdefault'] = 0 # Test values for further processing - if (parameters['interval'] <= 0.0): + if (user['interval'] <= 0.0): print('Invalid value for or missing variable INTERVAL in ' + inputfile) - if (parameters['numintervals'] <= 0): + if (user['numintervals'] <= 0): print('Invalid value for or missing variable NUMINTERVALS in ' + inputfile) - if (parameters['pix'] <= 0.0): + if (user['pix'] <= 0.0): print('Invalid value for or missing variable PIX in ' + inputfile) - if (parameters['gridsize'] <= 0): + if (user['gridsize'] <= 0): print('Invalid value for or missing variable GRIDSIZE in ' + inputfile) - if (parameters['seed'] == 0): + if (user['seed'] == 0): print('Invalid value for or missing variable SEED in ' + inputfile) - if (parameters['sfdfile'] is None): + if (user['sfdfile'] is None): print('Invalid value for or missing variable SFDFILE in ' + inputfile) - if (parameters['impfile'] is None): + if (user['impfile'] is None): print('Invalid value for or missing variable IMPFILE in ' + inputfile) - if (parameters['popupconsole'] is None): + if (user['popupconsole'] is None): print('Invalid value for or missing variable POPUPCONSOLE in ' + inputfile) - if (parameters['saveshaded'] is None): + if (user['saveshaded'] is None): print('Invalid value for or missing variable SAVESHADED in ' + inputfile) - if (parameters['saverego'] is None): + if (user['saverego'] is None): print('Invalid value for or missing variable SAVEREGO in ' + inputfile) - if (parameters['savepres'] is None): + if (user['savepres'] is None): print('Invalid value for or missing variable SAVEPRES in ' + inputfile) - if (parameters['savetruelist'] is None): + if (user['savetruelist'] is None): print('Invalid value for or missing variable SAVETRUELIST in ' + inputfile) - if (parameters['runtype'] is None): + if (user['runtype'] is None): print('Invalid value for or missing variable RUNTYPE in ' + inputfile) - if (parameters['restart'] is None): + if (user['restart'] is None): print('Invalid value for or missing variable RESTART in ' + inputfile) - return parameters + return user def read_unformatted_binary(filename, gridsize): @@ -382,16 +383,15 @@ def real2float(realstr): return float(realstr.replace('d', 'E').replace('D', 'E')) -def write_ctemdat(parameters, seedarr): - # Write various parameters and random number seeds into ctem.dat file - filename = parameters['workingdir'] + parameters['datfile'] +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 % parameters) + fp.write(template % user) # Write random number seeds to the file - for index in range(parameters['seedn']): + for index in range(user['seedn']): fp.write("%12d\n" % seedarr[index]) fp.close() @@ -399,11 +399,8 @@ def write_ctemdat(parameters, seedarr): return -# Possible references -# http://nbviewer.jupyter.org/github/ThomasLecocq/geophysique.be/blob/master/2014-02-25%20Shaded%20Relief%20Map%20in%20Python.ipynb - -def write_production(parameters, production): - filename = parameters['workingdir'] + parameters['sfdfile'] +def write_production(user, production): + filename = user['sfdfile'] np.savetxt(filename, production, fmt='%1.8e', delimiter=' ') return diff --git a/python/ctem/ctem/ctem_viewer_3d.py b/python/ctem/ctem/viewer3d.py similarity index 98% rename from python/ctem/ctem/ctem_viewer_3d.py rename to python/ctem/ctem/viewer3d.py index b4517054..684aed85 100644 --- a/python/ctem/ctem/ctem_viewer_3d.py +++ b/python/ctem/ctem/viewer3d.py @@ -14,7 +14,7 @@ def __init__(self): return def readctem(self, surface_file): - # Create and initialize data dictionaries for parameters and options from CTEM.in + # Create and initialize data dictionaries for user and options from CTEM.in notset = '-NOTSET-' currentdir = os.getcwd() + os.sep diff --git a/python/ctem/tests/testio/testio.py b/python/ctem/tests/testio/testio.py index ae329313..1212193e 100644 --- a/python/ctem/tests/testio/testio.py +++ b/python/ctem/tests/testio/testio.py @@ -3,5 +3,5 @@ d = dir(ctem) sim = ctem.Simulation() -for k, v in sim.parameters.items(): +for k, v in sim.user.items(): print(k, v) \ No newline at end of file From c5c6c74d33753dda1629628cc4f5564898ac047d Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 22 Feb 2022 12:01:21 -0500 Subject: [PATCH 18/32] Fixed a bunch of typos --- examples/global-lunar-bombardment/ctem.in | 4 ++-- python/ctem/ctem/driver.py | 6 +++--- python/ctem/ctem/io.py | 5 ++--- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/examples/global-lunar-bombardment/ctem.in b/examples/global-lunar-bombardment/ctem.in index 470aaee4..ca50a7fa 100755 --- a/examples/global-lunar-bombardment/ctem.in +++ b/examples/global-lunar-bombardment/ctem.in @@ -34,9 +34,9 @@ runtype single ! Run type: options are normal / ! CTEM required inputs seed 76535 ! Random number generator seed -gridsize 2000 ! Size of grid in pixels +gridsize 200 ! Size of grid in pixels numlayers 10 ! Number of perched layers -pix 3.08e3 ! Pixel size (m) +pix 3.08e4 ! Pixel size (m) mat rock ! Material (rock or ice) ! Bedrock scaling parameters mu_b 0.55e0 ! Experimentally derived parameter for bedrock crater scaling law diff --git a/python/ctem/ctem/driver.py b/python/ctem/ctem/driver.py index 764759cc..061e8098 100644 --- a/python/ctem/ctem/driver.py +++ b/python/ctem/ctem/driver.py @@ -91,7 +91,7 @@ def __init__(self, param_file="ctem.in"): self.user['ncount'] = 1 # Write ctem.dat file - io.write_datfile(self.user, self.seedarr) + io.write_datfile(self.user, self.output_filenames['dat'], self.seedarr) else: self.user['ncount'] = 0 @@ -212,10 +212,10 @@ def process_interval(self, isnew=True): self.pdist = io.read_formatted_ascii(self.output_filenames['pdist'], skip_lines=1) # Read impact mass from file - impact_mass = io.read_impact_mass(self.output_filenames['massfile']) + impact_mass = io.read_impact_mass(self.output_filenames['impmass']) # Read ctem.dat file - io.read_ctemdat(self.user, self.seedarr) + io.read_datfile(self.user, self.output_filenames['dat'], self.seedarr) # Save copy of crater distribution files if isnew: diff --git a/python/ctem/ctem/io.py b/python/ctem/ctem/io.py index 0b587234..92f5dc7a 100644 --- a/python/ctem/ctem/io.py +++ b/python/ctem/ctem/io.py @@ -228,12 +228,11 @@ def image_shaded_relief(user, DEM): return user -def read_datfile(user, seedarr): +def read_datfile(user, datfile, seedarr): # Read and parse ctem.dat file - datfile = user['workingdir'] + 'ctem.dat' # Read ctem.dat file - print('Reading input file ' + user['datfile']) + print('Reading input file ' + datfile) fp = open(datfile, 'r') lines = fp.readlines() fp.close() From 7557f79ea1e98a276cac46a4dc32705826ee97a1 Mon Sep 17 00:00:00 2001 From: David Minton Date: Tue, 22 Feb 2022 12:44:51 -0500 Subject: [PATCH 19/32] Fixed more typos. --- python/ctem/ctem/driver.py | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/python/ctem/ctem/driver.py b/python/ctem/ctem/driver.py index 061e8098..c09cf20a 100644 --- a/python/ctem/ctem/driver.py +++ b/python/ctem/ctem/driver.py @@ -218,22 +218,21 @@ def process_interval(self, isnew=True): io.read_datfile(self.user, self.output_filenames['dat'], self.seedarr) # Save copy of crater distribution files + # Update user: mass, curyear, regolith properties + self.user['masstot'] = self.user['masstot'] + 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) + if isnew: - - # Update user: mass, curyear, regolith properties - self.user['masstot'] = self.user['masstot'] + 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']) 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']) as fp_reg: - fp_reg.write(reg_text) - self.redirect_outputs(['odist', 'ocum', 'pdist', 'tdist'], 'dist') if (self.user['savetruelist'].upper() == 'T'): self.redirect_outputs(['tcum'], 'dist') From ffb03159b02854c497bfcb61c7b83a4fe655c91a Mon Sep 17 00:00:00 2001 From: David Minton Date: Wed, 23 Feb 2022 12:58:58 -0500 Subject: [PATCH 20/32] Fixed some problems related to directory structure generation and accidentally deleting ctem.dat after generating it --- python/ctem/ctem/driver.py | 19 +++++++++---------- python/ctem/ctem/io.py | 2 +- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/python/ctem/ctem/driver.py b/python/ctem/ctem/driver.py index c09cf20a..9bda0aa8 100644 --- a/python/ctem/ctem/driver.py +++ b/python/ctem/ctem/driver.py @@ -10,7 +10,7 @@ class Simulation: 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"): + def __init__(self, param_file="ctem.in", isnew=True): currentdir = os.getcwd() self.user = { 'restart': None, @@ -78,14 +78,19 @@ def __init__(self, param_file="ctem.in"): sfdfile = os.path.join(self.user['workingdir'], self.user['sfdcompare']) self.ph1 = io.read_formatted_ascii(sfdfile, skip_lines=0) - # Scale the production function to the simulation domain - self.scale_production() # Starting new or old run? - if (self.user['restart'].upper() == 'F'): + if (self.user['restart'].upper() == 'F' and isnew): print('Starting a new run') io.create_dir_structure(self.user) + # 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() if (self.user['runtype'].upper() == 'STATISTICAL'): self.user['ncount'] = 1 @@ -94,16 +99,10 @@ def __init__(self, param_file="ctem.in"): io.write_datfile(self.user, self.output_filenames['dat'], self.seedarr) else: self.user['ncount'] = 0 - - # Delete any old output files - for k, v in self.output_filenames.items(): - if os.path.isfile(v): - os.remove(v) else: print('Continuing a previous run') self.process_interval(isnew=False) - return def scale_production(self): diff --git a/python/ctem/ctem/io.py b/python/ctem/ctem/io.py index 92f5dc7a..4088c7ea 100644 --- a/python/ctem/ctem/io.py +++ b/python/ctem/ctem/io.py @@ -37,7 +37,7 @@ def create_dir_structure(user): directories = ['dist', 'misc', 'rego', 'rplot', 'surf', 'shaded'] for directory in directories: - dir_test = user['workingdir'] + directory + dir_test = os.path.join(user['workingdir'], directory) if not os.path.isdir(dir_test): os.makedirs(dir_test) From a3d78a9bb6becda9fba45ce255174362aae83140 Mon Sep 17 00:00:00 2001 From: David Minton Date: Wed, 23 Feb 2022 12:59:19 -0500 Subject: [PATCH 21/32] Restructured the 3d viewer so that it uses a derived class of the main Simulation class --- python/ctem/ctem/viewer3d.py | 75 ++++++++---------------------------- 1 file changed, 15 insertions(+), 60 deletions(-) diff --git a/python/ctem/ctem/viewer3d.py b/python/ctem/ctem/viewer3d.py index 684aed85..7c68d995 100644 --- a/python/ctem/ctem/viewer3d.py +++ b/python/ctem/ctem/viewer3d.py @@ -1,64 +1,22 @@ import numpy as np import os import open3d -from ctem import ctem_io_readers +import ctem import os - -class polysurface: +class Polysurface(ctem.Simulation): """A model of a self-gravitating small body""" def __init__(self): - self.polyfile = "" + ctem.Simulation.__init__(self, isnew=False) # Initialize the data structures, but doesn't start a new run #used for Open3d module self.mesh = open3d.geometry.TriangleMesh() - return - - def readctem(self, surface_file): - # Create and initialize data dictionaries for user and options from CTEM.in - notset = '-NOTSET-' - currentdir = os.getcwd() + os.sep - - self.parameters = {'restart': notset, - 'runtype': notset, - 'popupconsole': notset, - 'saveshaded': notset, - 'saverego': notset, - 'savepres': notset, - 'savetruelist': notset, - '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': 'ctem.in', - 'datfile': 'ctem.dat', - 'impfile': notset, - 'sfdcompare': notset, - 'sfdfile': notset} - - # Read ctem.in to initialize parameter values based on user input - ctem_io_readers.read_ctemin(self.parameters, notset) - # Read surface dem(shaded relief) and ejecta data files - dem_file = self.parameters['workingdir'] + surface_file - self.dem = ctem_io_readers.read_unformatted_binary(dem_file, self.parameters['gridsize']) + self.process_interval(isnew=False) return def ctem2blockmesh(self): # Build mesh grid - s = self.parameters['gridsize'] - pix = self.parameters['pix'] + 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 @@ -124,13 +82,13 @@ def ctem2blockmesh(self): def ctem2trimesh(self): # Build mesh grid - s = self.parameters['gridsize'] - pix = self.parameters['pix'] + 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.dem.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): @@ -154,9 +112,9 @@ def visualize(self): opt = vis.get_render_option() opt.background_color = np.asarray([0, 0, 0]) - # zmax = np.amax(surf.dem) - # zmin = np.amin(surf.dem) - # cnorm = (surf.dem.flatten() - zmin) / (zmax - zmin) + # zmax = np.amax(self.surface_dem) + # zmin = np.amin(self.surface_dem) + # cnorm = (self.surface_dem.flatten() - zmin) / (zmax - zmin) # cval = plt.cm.terrain(cnorm)[:, :3] self.mesh.paint_uniform_color([0.5, 0.5, 0.5]) @@ -167,12 +125,9 @@ def visualize(self): if __name__ == '__main__': import matplotlib.pyplot as plt - surf = polysurface() - surf.readctem(surface_file="surface_dem.dat") - surf.ctem2trimesh() - surf.visualize() - - + sim = Polysurface() + sim.ctem2trimesh() + sim.visualize() From 769ed1709c52ee534ff2bdf42bcd1f2996270cda Mon Sep 17 00:00:00 2001 From: David Minton Date: Wed, 23 Feb 2022 13:04:24 -0500 Subject: [PATCH 22/32] Fixed directory structure naming using os.path.join instead of appending separation characters manually --- python/ctem/ctem/io.py | 32 ++++---------------------------- 1 file changed, 4 insertions(+), 28 deletions(-) diff --git a/python/ctem/ctem/io.py b/python/ctem/ctem/io.py index 4088c7ea..d0d383e5 100644 --- a/python/ctem/ctem/io.py +++ b/python/ctem/ctem/io.py @@ -8,30 +8,6 @@ # Set pixel scaling common for image writing, at 1 pixel/ array element dpi = 72.0 -def copy_dists(user, output_filenames, distlist): - # Save copies of distribution files - - orig_list = ['odistribution', 'ocumulative', 'pdistribution', 'tdistribution'] - dest_list = ['odist', 'ocum', 'pdist', 'tdist'] - - for index in range(len(orig_list)): - forig = user['workingdir'] + orig_list[index] + '.dat' - fdest = user['workingdir'] + 'dist' + os.sep + dest_list[index] + "_%06d.dat" % user['ncount'] - shutil.copy2(forig, fdest) - - forig = user['workingdir'] + 'impactmass.dat' - fdest = user['workingdir'] + 'misc' + os.sep + "mass_%06d.dat" % user['ncount'] - shutil.copy2(forig, fdest) - - if (user['savetruelist'].upper() == 'T'): - forig = user['workingdir'] + 'tcumulative.dat' - fdest = user['workingdir'] + 'dist' + os.sep + "tcum_%06d.dat" % user['ncount'] - shutil.copy2(forig, fdest) - - return - - - def create_dir_structure(user): # Create directories for various output files if they do not already exist directories = ['dist', 'misc', 'rego', 'rplot', 'surf', 'shaded'] @@ -95,7 +71,7 @@ def create_rplot(user, odist, pdist, tdist, ph1): timelabel = 'Time = ' + r'${}$ x 10$^{}$'.format(tlabel[0], texp) + ' yrs' # Save image to file - filename = user['workingdir'] + 'rplot' + os.sep + "rplot%06d.png" % user['ncount'] + filename = os.path.join(user['workingdir'],'rplot',"rplot%06d.png" % user['ncount']) height = user['gridsize'] / dpi width = height fig = plt.figure(figsize=(width, height), dpi=dpi) @@ -151,7 +127,7 @@ def image_dem(user, DEM): ax.imshow(dem_img, interpolation="nearest", cmap='gray', vmin=0.0, vmax=1.0) plt.axis('off') # Save image to file - filename = user['workingdir'] + 'surf' + os.sep + "surf%06d.png" % user['ncount'] + filename = os.path.join(user['workingdir'],'surf',"surf%06d.png" % user['ncount']) plt.savefig(filename, dpi=dpi, bbox_inches=0) return @@ -170,7 +146,7 @@ def image_regolith(user, regolith): (np.log(regolith_scaled) - np.log(minreg)) / (np.log(maxreg) - np.log(minreg))) # Save image to file - filename = user['workingdir'] + 'rego' + os.sep + "rego%06d.png" % user['ncount'] + 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) @@ -223,7 +199,7 @@ def image_shaded_relief(user, DEM): ax.imshow(dem_img, interpolation="nearest", vmin=0.0, vmax=1.0) plt.axis('off') # Save image to file - filename = user['workingdir'] + 'shaded' + os.sep + "shaded%06d.png" % user['ncount'] + filename = os.path.join(user['workingdir'],'shaded',"shaded%06d.png" % user['ncount']) plt.savefig(filename, dpi=dpi, bbox_inches=0) return user From e7c62084faa16338bdda91190e4a281111a446d1 Mon Sep 17 00:00:00 2001 From: Jun Du Date: Wed, 23 Feb 2022 14:40:52 -0500 Subject: [PATCH 23/32] fix ejecta thickness issue --- 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 04dee3f2..8da930b2 100644 --- a/src/ejecta/ejecta_emplace.f90 +++ b/src/ejecta/ejecta_emplace.f90 @@ -296,7 +296,7 @@ subroutine ejecta_emplace(user,surf,crater,domain,ejb,ejtble,deltaMtot,age,age_r fmasscons = (-deltaMtot)/ ejbmass cumulative_elchange = cumulative_elchange * fmasscons crater%ejrim = crater%ejrim * fmasscons - ejb(:)%thick = ejb(:)%thick * fmasscons + ejb(:)%thick = ejb(:)%thick + log(fmasscons) maxhits = 1 ! Create box for soften calculation (will be no bigger than the grid itself) if (2 * inc + 1 < user%gridsize) then From bc52cba3630f374213ecdd062ac29892d6ab254b Mon Sep 17 00:00:00 2001 From: David Minton Date: Wed, 23 Feb 2022 15:05:05 -0500 Subject: [PATCH 24/32] Finished redirect method to copy files to subfolders and append interval numbers to them --- python/ctem/ctem/driver.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/ctem/ctem/driver.py b/python/ctem/ctem/driver.py index 9bda0aa8..7dd8dfef 100644 --- a/python/ctem/ctem/driver.py +++ b/python/ctem/ctem/driver.py @@ -254,7 +254,8 @@ def redirect_outputs(self, filekeys, foldername): for k in filekeys: forig = self.output_filenames[k] - fdist = os.path.join(self.user['workingdir'], foldername, f"{k}_{self.user['ncount']:06d}.dat") + fdest = os.path.join(self.user['workingdir'], foldername, f"{k}_{self.user['ncount']:06d}.dat") + shutil.copy2(forig, fdest) if __name__ == '__main__': sim = Simulation() From ed8cac8b07f5f3f1b6b91a5df2cdc58338b076c0 Mon Sep 17 00:00:00 2001 From: David Minton Date: Wed, 23 Feb 2022 15:07:59 -0500 Subject: [PATCH 25/32] Streamlined 3d viewer by removing extraneous code --- python/ctem/ctem/viewer3d.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/python/ctem/ctem/viewer3d.py b/python/ctem/ctem/viewer3d.py index 7c68d995..e3d66cb7 100644 --- a/python/ctem/ctem/viewer3d.py +++ b/python/ctem/ctem/viewer3d.py @@ -1,8 +1,6 @@ import numpy as np -import os import open3d import ctem -import os class Polysurface(ctem.Simulation): """A model of a self-gravitating small body""" @@ -10,7 +8,6 @@ def __init__(self): ctem.Simulation.__init__(self, isnew=False) # Initialize the data structures, but doesn't start a new run #used for Open3d module self.mesh = open3d.geometry.TriangleMesh() - self.process_interval(isnew=False) return def ctem2blockmesh(self): @@ -94,7 +91,6 @@ def ctem2trimesh(self): 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, (j+1)*s+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 ] @@ -112,19 +108,12 @@ def visualize(self): opt = vis.get_render_option() opt.background_color = np.asarray([0, 0, 0]) - # zmax = np.amax(self.surface_dem) - # zmin = np.amin(self.surface_dem) - # cnorm = (self.surface_dem.flatten() - zmin) / (zmax - zmin) - # cval = plt.cm.terrain(cnorm)[:, :3] - self.mesh.paint_uniform_color([0.5, 0.5, 0.5]) vis.run() vis.destroy_window() if __name__ == '__main__': - import matplotlib.pyplot as plt - sim = Polysurface() sim.ctem2trimesh() sim.visualize() From c66e232f082df30b964b79748108f570a74f21c6 Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 24 Feb 2022 08:51:15 -0500 Subject: [PATCH 26/32] Fixed some bugs in the Python code and generated a new test environment to test separating pre and post-processing tasks --- python/ctem/ctem/driver.py | 67 +- python/ctem/ctem/{io.py => util.py} | 0 python/ctem/tests/run_and_reprocess/CTEM | 1 + .../tests/run_and_reprocess/NPFextrap.dat | 1418 +++++++++++++++++ python/ctem/tests/run_and_reprocess/ctem.in | 72 + .../tests/run_and_reprocess/ctem_driver.py | 3 + .../lunar-MBA-impactor-velocities.dat | 64 + 7 files changed, 1590 insertions(+), 35 deletions(-) rename python/ctem/ctem/{io.py => util.py} (100%) create mode 120000 python/ctem/tests/run_and_reprocess/CTEM create mode 100755 python/ctem/tests/run_and_reprocess/NPFextrap.dat create mode 100755 python/ctem/tests/run_and_reprocess/ctem.in create mode 100644 python/ctem/tests/run_and_reprocess/ctem_driver.py create mode 100755 python/ctem/tests/run_and_reprocess/lunar-MBA-impactor-velocities.dat diff --git a/python/ctem/ctem/driver.py b/python/ctem/ctem/driver.py index 7dd8dfef..e81571e0 100644 --- a/python/ctem/ctem/driver.py +++ b/python/ctem/ctem/driver.py @@ -2,7 +2,7 @@ import os import subprocess import shutil -from ctem import io +from ctem import util class Simulation: """ @@ -42,7 +42,7 @@ def __init__(self, param_file="ctem.in", isnew=True): 'sfdcompare': None, 'sfdfile': None } - self.user = io.read_user_input(self.user) + self.user = util.read_user_input(self.user) self.output_filenames = { 'dat': 'ctem.dat', @@ -71,19 +71,19 @@ def __init__(self, param_file="ctem.in", isnew=True): 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.regolith = np.zeros([self.user['gridsize'], self.user['gridsize']], dtype=float) + self.surface_ejc = np.zeros([self.user['gridsize'], self.user['gridsize']], dtype=float) if self.user['sfdcompare'] is not None: # Read sfdcompare file sfdfile = os.path.join(self.user['workingdir'], self.user['sfdcompare']) - self.ph1 = io.read_formatted_ascii(sfdfile, skip_lines=0) + self.ph1 = util.read_formatted_ascii(sfdfile, skip_lines=0) # Starting new or old run? if (self.user['restart'].upper() == 'F' and isnew): print('Starting a new run') - io.create_dir_structure(self.user) + util.create_dir_structure(self.user) # Delete any old output files for k, v in self.output_filenames.items(): if os.path.isfile(v): @@ -92,13 +92,7 @@ def __init__(self, param_file="ctem.in", isnew=True): # Scale the production function to the simulation domain self.scale_production() - if (self.user['runtype'].upper() == 'STATISTICAL'): - self.user['ncount'] = 1 - - # Write ctem.dat file - io.write_datfile(self.user, self.output_filenames['dat'], self.seedarr) - else: - self.user['ncount'] = 0 + util.write_datfile(self.user, self.output_filenames['dat'], self.seedarr) else: print('Continuing a previous run') self.process_interval(isnew=False) @@ -113,7 +107,7 @@ def scale_production(self): # Read production function file impfile = os.path.join(self.user['workingdir'], self.user['impfile']) - prodfunction = io.read_formatted_ascii(impfile, skip_lines=0) + prodfunction = util.read_formatted_ascii(impfile, skip_lines=0) # Create impactor production population area = (self.user['gridsize'] * self.user['pix']) ** 2 @@ -121,7 +115,7 @@ def scale_production(self): self.production[:, 1] = self.production[:, 1] * area * self.user['interval'] # Write the scaled production function to file - io.write_production(self.user, self.production) + util.write_production(self.user, self.production) return @@ -145,17 +139,23 @@ def run(self): # Process output files self.process_interval() + # 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') + # Display results print(self.user['ncount'], ' Displaying results') # Write surface dem, surface ejecta, shaded relief, and rplot data - io.image_dem(self.user, self.surface_dem) + util.image_dem(self.user, self.surface_dem) if (self.user['saverego'].upper() == 'T'): - io.image_regolith(self.user, self.surface_ejc) + util.image_regolith(self.user, self.surface_ejc) if (self.user['saveshaded'].upper() == 'T'): - io.image_shaded_relief(self.user, self.surface_dem) + util.image_shaded_relief(self.user, self.surface_dem) if (self.user['savepres'].upper() == 'T'): - io.create_rplot(self.user, self.odist, self.pdist, self.tdist, self.ph1) + util.create_rplot(self.user, self.odist, self.pdist, self.tdist, self.ph1) # Update ncount self.user['ncount'] = self.user['ncount'] + 1 @@ -166,7 +166,7 @@ def run(self): self.user['totalimpacts'] = 0 self.user['masstot'] = 0.0 - # Delete tdistribution file, if it exists + # 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) @@ -175,7 +175,7 @@ def run(self): self.user['restart'] = 'T' # Write ctem.dat file - io.write_datfile(self.user, self.output_filenames['dat'],self.seedarr) + util.write_datfile(self.user, self.output_filenames['dat'], self.seedarr) return @@ -188,8 +188,11 @@ def compute_one_interval(self): with subprocess.Popen([os.path.join(self.user['workingdir'], 'CTEM')], stdout=subprocess.PIPE, universal_newlines=True) as p: - for line in p.stdout: - print(line, end='') + try: + for line in p.stdout: + print(line, end='') + except: + print("Error executing main CTEM program") return @@ -202,19 +205,19 @@ def process_interval(self, isnew=True): print(self.user['ncount'], ' Reading Fortran output') # Read surface dem(shaded relief) and ejecta data files - self.surface_dem = io.read_unformatted_binary(self.output_filenames['dem'], self.user['gridsize']) - self.surface_ejc = io.read_unformatted_binary(self.output_filenames['ejc'], self.user['gridsize']) + 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 = io.read_formatted_ascii(self.output_filenames['odist'], skip_lines=1) - self.tdist = io.read_formatted_ascii(self.output_filenames['tdist'], skip_lines=1) - self.pdist = io.read_formatted_ascii(self.output_filenames['pdist'], skip_lines=1) + 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 - impact_mass = io.read_impact_mass(self.output_filenames['impmass']) + impact_mass = util.read_impact_mass(self.output_filenames['impmass']) # Read ctem.dat file - io.read_datfile(self.user, self.output_filenames['dat'], self.seedarr) + util.read_datfile(self.user, self.output_filenames['dat'], self.seedarr) # Save copy of crater distribution files # Update user: mass, curyear, regolith properties @@ -231,12 +234,6 @@ def process_interval(self, isnew=True): with open(self.output_filenames['regodepth'], 'w') as fp_reg: fp_reg.write(reg_text) - if isnew: - self.redirect_outputs(['odist', 'ocum', 'pdist', 'tdist'], 'dist') - if (self.user['savetruelist'].upper() == 'T'): - self.redirect_outputs(['tcum'], 'dist') - self.redirect_outputs(['impmass'], 'misc') - return def redirect_outputs(self, filekeys, foldername): """ diff --git a/python/ctem/ctem/io.py b/python/ctem/ctem/util.py similarity index 100% rename from python/ctem/ctem/io.py rename to python/ctem/ctem/util.py diff --git a/python/ctem/tests/run_and_reprocess/CTEM b/python/ctem/tests/run_and_reprocess/CTEM new file mode 120000 index 00000000..5bb33aa9 --- /dev/null +++ b/python/ctem/tests/run_and_reprocess/CTEM @@ -0,0 +1 @@ +../../../../build/src/CTEM \ No newline at end of file diff --git a/python/ctem/tests/run_and_reprocess/NPFextrap.dat b/python/ctem/tests/run_and_reprocess/NPFextrap.dat new file mode 100755 index 00000000..e98391df --- /dev/null +++ b/python/ctem/tests/run_and_reprocess/NPFextrap.dat @@ -0,0 +1,1418 @@ + 1.0000000000000001E-009 16373498665196056. + 1.0200000000000000E-009 15624829133353072. + 1.0404000000000000E-009 14910392118418680. + 1.0612080000000001E-009 14228622356426014. + 1.0824322000000000E-009 13578024968994198. + 1.1040808000000000E-009 12957178207974354. + 1.1261623999999999E-009 12364718530314516. + 1.1486857000000000E-009 11799347079002376. + 1.1716594000000001E-009 11259828517385738. + 1.1950926000000001E-009 10744978582763124. + 1.2189943999999999E-009 10253671176415016. + 1.2433742999999999E-009 9784827283731524.0 + 1.2682417999999999E-009 9337421008741684.0 + 1.2936066000000000E-009 8910472977441879.0 + 1.3194787999999999E-009 8503045296702585.0 + 1.3458682999999999E-009 8114249148673952.0 + 1.3727857000000000E-009 7743228961776817.0 + 1.4002413999999999E-009 7389174104114597.0 + 1.4282461999999999E-009 7051308368799519.0 + 1.4568112000000000E-009 6728890208258190.0 + 1.4859474000000000E-009 6421215521897574.0 + 1.5156663000000001E-009 6127609310508435.0 + 1.5459797000000000E-009 5847426967224776.0 + 1.5768993000000000E-009 5580056424177601.0 + 1.6084372000000000E-009 5324911980228383.0 + 1.6406059999999999E-009 5081432797667148.0 + 1.6734181000000000E-009 4849087118238152.0 + 1.7068865000000000E-009 4627364941332780.0 + 1.7410241999999999E-009 4415781316339177.5 + 1.7758447000000000E-009 4213871971251545.0 + 1.8113615999999999E-009 4021194880969782.5 + 1.8475888000000001E-009 3837328037757316.5 + 1.8845406000000000E-009 3661868141016992.5 + 1.9222313999999999E-009 3494431216318050.5 + 1.9606759999999999E-009 3334650316747248.5 + 1.9998896000000001E-009 3182174901302566.0 + 2.0398873000000000E-009 3036671967025619.5 + 2.0806850999999999E-009 2897821576611301.5 + 2.1222988000000000E-009 2765320229959727.0 + 2.1647448000000000E-009 2638877361348099.5 + 2.2080397000000001E-009 2518216084527946.0 + 2.2522004999999999E-009 2403071976513234.5 + 2.2972445000000000E-009 2293192809795639.5 + 2.3431893999999999E-009 2188337764271766.2 + 2.3900531000000002E-009 2088277363840784.0 + 2.4378541999999999E-009 1992791917069052.2 + 2.4866113000000000E-009 1901672535858309.2 + 2.5363434999999998E-009 1814719612820091.0 + 2.5870704000000000E-009 1731742474774254.8 + 2.6388118000000001E-009 1652559481637765.0 + 2.6915880000000000E-009 1576997126693668.5 + 2.7454198000000002E-009 1504889718623458.0 + 2.8003281999999998E-009 1436079430510044.2 + 2.8563347000000001E-009 1370415533754651.0 + 2.9134614000000000E-009 1307754004857728.0 + 2.9717306999999998E-009 1247957575911645.5 + 3.0311653000000001E-009 1190895391529202.2 + 3.0917886000000001E-009 1136442337305807.5 + 3.1536243999999999E-009 1084479092213053.0 + 3.2166969000000001E-009 1034891852503704.1 + 3.2810308000000000E-009 987571998980541.62 + 3.3466513999999998E-009 942415804458058.00 + 3.4135843999999999E-009 899324359631564.38 + 3.4818560999999998E-009 858203223971718.88 + 3.5514931999999999E-009 818962349229012.12 + 3.6225231000000002E-009 781515712287184.12 + 3.6949736000000000E-009 745781303219183.00 + 3.7688729999999998E-009 711680881369590.50 + 3.8442505000000000E-009 679139634252424.62 + 3.9211355000000002E-009 648086339057709.00 + 3.9995582000000000E-009 618452938978139.88 + 4.0795494000000003E-009 590174494421968.88 + 4.1611404000000001E-009 563189075227060.88 + 4.2443631999999998E-009 537437556193661.94 + 4.3292503999999998E-009 512863527269277.06 + 4.4158355000000001E-009 489413090719507.75 + 4.5041521999999999E-009 467034939488460.38 + 4.5942352000000002E-009 445680024973336.06 + 4.6861198999999999E-009 425301543369721.69 + 4.7798422999999998E-009 405854855741145.12 + 4.8754392000000000E-009 387297347872637.31 + 4.9729479000000000E-009 369588397022663.94 + 5.0724068999999997E-009 352689156962741.94 + 5.1738549999999998E-009 336562638379934.25 + 5.2773320999999999E-009 321173490452837.50 + 5.3828788000000004E-009 306487995360364.31 + 5.4905363999999996E-009 292473991498358.12 + 5.6003471000000003E-009 279100776849566.19 + 5.7123539999999996E-009 266339046656329.31 + 5.8266011000000001E-009 254160833114840.06 + 5.9431331000000001E-009 242539466105880.25 + 6.0619958000000003E-009 231449474398208.41 + 6.1832356999999997E-009 220866571431898.88 + 6.3069004000000003E-009 210767565834604.31 + 6.4330384000000003E-009 201130331399540.56 + 6.5616992000000004E-009 191933751602170.12 + 6.6929332000000002E-009 183157681685953.81 + 6.8267918000000003E-009 174782897833489.59 + 6.9633277000000003E-009 166791039009238.41 + 7.1025941999999997E-009 159164610185338.97 + 7.2446461000000002E-009 151886892107514.00 + 7.3895389999999998E-009 144941945641289.97 + 7.5373297999999992E-009 138314551278590.05 + 7.6880764000000003E-009 131990191714344.11 + 7.8418378999999996E-009 125955011347589.45 + 7.9986746999999999E-009 120195783849702.44 + 8.1586482000000008E-009 114699895257102.41 + 8.3218211999999993E-009 109455302339307.47 + 8.4882576000000007E-009 104450517459128.98 + 8.6580226999999995E-009 99674574428007.266 + 8.8311832000000003E-009 95117006273188.609 + 9.0078069000000000E-009 90767830811786.562 + 9.1879630000000007E-009 86617520797173.422 + 9.3717223000000003E-009 82656979820887.656 + 9.5591567000000001E-009 78877534206942.641 + 9.7503398000000004E-009 75270901460268.844 + 9.9453466000000004E-009 71829179396882.812 + 1.0144254000000000E-008 68544820836225.852 + 1.0347139000000000E-008 65410646497629.273 + 1.0554081000000001E-008 62419790325370.305 + 1.0765163000000000E-008 59565673586258.523 + 1.0980465999999999E-008 56842067973770.125 + 1.1200076000000000E-008 54242986818745.445 + 1.1424077000000000E-008 51762760619395.273 + 1.1652559000000000E-008 49395931268191.195 + 1.1885609999999999E-008 47137330228209.656 + 1.2123322000000000E-008 44982002588342.570 + 1.2365788000000000E-008 42925228016763.523 + 1.2613104000000000E-008 40962492917581.109 + 1.2865366000000001E-008 39089505256454.422 + 1.3122674000000000E-008 37302153815962.242 + 1.3385127000000000E-008 35596535659580.703 + 1.3652830000000000E-008 33968900264402.430 + 1.3925886000000000E-008 32415693637990.871 + 1.4204404000000001E-008 30933501818846.531 + 1.4488492000000000E-008 29519084260541.852 + 1.4778261999999999E-008 28169339086295.105 + 1.5073827000000001E-008 26881312027552.051 + 1.5375304000000001E-008 25652176494844.832 + 1.5682810000000001E-008 24479244642274.449 + 1.5996465999999999E-008 23359944870186.188 + 1.6316394999999999E-008 22291824829480.715 + 1.6642723000000000E-008 21272542674614.992 + 1.6975578000000000E-008 20299865430624.629 + 1.7315088999999998E-008 19371666343646.961 + 1.7661391000000001E-008 18485906643103.184 + 1.8014619000000000E-008 17640647961544.605 + 1.8374910999999999E-008 16834039524188.734 + 1.8742409000000001E-008 16064312451471.598 + 1.9117258000000001E-008 15329778741146.434 + 1.9499602999999998E-008 14628833032189.432 + 1.9889595000000001E-008 13959937509623.682 + 2.0287386999999999E-008 13321626625147.031 + 2.0693133999999998E-008 12712503396493.473 + 2.1106997000000001E-008 12131230494230.133 + 2.1529137000000001E-008 11576536345526.742 + 2.1959720000000000E-008 11047205059657.873 + 2.2398914000000000E-008 10542077919747.137 + 2.2846892999999998E-008 10060046255544.195 + 2.3303830000000000E-008 9600056819862.7637 + 2.3769907000000001E-008 9161098955437.1289 + 2.4245305000000001E-008 8742212689765.9873 + 2.4730211000000002E-008 8342479736439.3154 + 2.5224815000000000E-008 7961024444539.4209 + 2.5729311999999999E-008 7597010341008.1240 + 2.6243898000000001E-008 7249641233953.4287 + 2.6768776000000001E-008 6918155213847.5566 + 2.7304150999999999E-008 6601826537550.0312 + 2.7850234000000000E-008 6299961535648.2812 + 2.8407239000000001E-008 6011898979667.3711 + 2.8975384000000000E-008 5737007988465.2129 + 2.9554892000000001E-008 5474686204565.7217 + 3.0145988999999997E-008 5224359429035.2139 + 3.0748909000000000E-008 4985478284117.9785 + 3.1363887000000002E-008 4757520001567.6973 + 3.1991165000000001E-008 4539984838571.4219 + 3.2630987999999999E-008 4332396536883.7876 + 3.3283608000000003E-008 4134299935039.2305 + 3.3949279999999998E-008 3945261310425.0435 + 3.4628266000000003E-008 3764866228554.6958 + 3.5320830999999998E-008 3592719796758.2207 + 3.6027248000000002E-008 3428444506578.7588 + 3.6747793000000003E-008 3271680693359.0024 + 3.7482749000000002E-008 3122084803976.6665 + 3.8232403999999998E-008 2979329130228.1948 + 3.8997051999999998E-008 2843100901531.3130 + 3.9776993000000001E-008 2713101629103.0752 + 4.0572533000000002E-008 2589046476685.4932 + 4.1383983000000000E-008 2470663794671.9092 + 4.2211663000000003E-008 2357693959398.8506 + 4.3055895999999998E-008 2249889687218.9824 + 4.3917014000000000E-008 2147014667034.8123 + 4.4795355000000002E-008 2048843483433.1084 + 4.5691261999999999E-008 1955161213496.6575 + 4.6605086999999997E-008 1865762527880.5625 + 4.7537189000000001E-008 1780451503931.3225 + 4.8487932000000002E-008 1699041369129.2983 + 4.9457691000000003E-008 1621353576798.9429 + 5.0446845000000002E-008 1547218032532.4575 + 5.1455781999999998E-008 1476472302781.3630 + 5.2484897000000000E-008 1408961431360.2058 + 5.3534595000000003E-008 1344537414557.3447 + 5.4605287000000000E-008 1283059149759.8259 + 5.5697393000000002E-008 1224391937812.7815 + 5.6811340999999998E-008 1168407259997.1379 + 5.7947567999999998E-008 1114982450296.6106 + 5.9106518999999997E-008 1064000485116.6843 + 6.0288649000000002E-008 1015349642963.6342 + 6.1494422000000003E-008 968923318991.95959 + 6.2724311000000003E-008 924619795267.01807 + 6.3978796999999998E-008 882342053288.68738 + 6.5258373000000004E-008 841997429632.64258 + 6.6563539999999999E-008 803497557403.88025 + 6.7894811000000003E-008 766758052921.46326 + 6.9252707000000001E-008 731698453641.91223 + 7.0637761999999997E-008 698241910301.06592 + 7.2050516999999996E-008 666315174928.58032 + 7.3491526999999999E-008 635848274355.08435 + 7.4961357999999994E-008 606774440832.36877 + 7.6460585000000002E-008 579030004685.42468 + 7.7989797000000004E-008 552554160097.28235 + 7.9549593000000000E-008 527288913637.53717 + 8.1140583999999998E-008 503178920665.76013 + 8.2763396000000005E-008 480171327337.28839 + 8.4418663999999995E-008 458215747372.30853 + 8.6107037000000007E-008 437264079007.88422 + 8.7829177999999996E-008 417270408258.57721 + 8.9585762000000003E-008 398190935823.03259 + 9.1377476999999995E-008 379983869073.30249 + 9.3205025999999995E-008 362609313384.73578 + 9.5069127000000000E-008 346029190991.65741 + 9.6970508999999994E-008 330207194295.50470 + 9.8909920000000005E-008 315108639531.97485 + 1.0088812000000000E-007 300700453028.72919 + 1.0290588000000000E-007 286951100304.25635 + 1.0496400000000000E-007 273830398824.25473 + 1.0706327999999999E-007 261309649245.87091 + 1.0920454000000000E-007 249361434541.21716 + 1.1138863000000000E-007 237959519387.66306 + 1.1361640999999999E-007 227078911767.07831 + 1.1588874000000000E-007 216695841161.21136 + 1.1820651000000000E-007 206787558744.98465 + 1.2057063999999999E-007 197332308194.68011 + 1.2298205000000001E-007 188309403334.54932 + 1.2544169000000001E-007 179699059251.88254 + 1.2795052999999999E-007 171482395554.55167 + 1.3050953999999999E-007 163641455843.85178 + 1.3311972999999999E-007 156159039406.35278 + 1.3578212000000000E-007 149018762172.14835 + 1.3849777000000001E-007 142204939962.86777 + 1.4126772000000001E-007 135702706863.71530 + 1.4409307999999999E-007 129497760760.52310 + 1.4697494000000000E-007 123576547597.46860 + 1.4991444000000001E-007 117926073347.71808 + 1.5291272000000000E-007 112533981565.08438 + 1.5597097999999999E-007 107388415907.11580 + 1.5909040000000000E-007 102478137005.01477 + 1.6227221000000001E-007 97792375760.095139 + 1.6551764999999999E-007 93320876904.490311 + 1.6882800000000001E-007 89053833104.851059 + 1.7220455999999999E-007 84981893879.282379 + 1.7564866000000000E-007 81096132302.188889 + 1.7916163000000001E-007 77388057987.848480 + 1.8274486000000001E-007 73849532612.797913 + 1.8639976000000000E-007 70472799448.051804 + 1.9012775000000001E-007 67250472464.319939 + 1.9393031000000000E-007 64175476409.695488 + 1.9780891000000001E-007 61241091364.895897 + 2.0176508999999999E-007 58440873753.760574 + 2.0580038999999999E-007 55768696985.791275 + 2.0991640000000001E-007 53218701612.847710 + 2.1411473000000001E-007 50785303621.508827 + 2.1839703000000000E-007 48463169749.026505 + 2.2276496999999999E-007 46247217340.361671 + 2.2722026999999999E-007 44132587611.583885 + 2.3176467000000001E-007 42114650797.673409 + 2.3639996000000001E-007 40188982118.849129 + 2.4112796000000000E-007 38351361952.392334 + 2.4595051999999998E-007 36597766012.277328 + 2.5086953000000001E-007 34924352727.238846 + 2.5588691999999999E-007 33327455429.419361 + 2.6100465999999998E-007 31803574765.990089 + 2.6622476000000002E-007 30349371365.674057 + 2.7154925000000000E-007 28961663787.900448 + 2.7698024000000001E-007 27637405910.687466 + 2.8251984000000002E-007 26373701261.103699 + 2.8817023999999999E-007 25167777115.559059 + 2.9393364000000001E-007 24016994798.944111 + 2.9981231000000000E-007 22918830970.512638 + 3.0580855999999997E-007 21870878952.293278 + 3.1192473000000001E-007 20870844815.995773 + 3.1816323000000000E-007 19916535721.223831 + 3.2452648999999998E-007 19005863338.361744 + 3.3101702000000000E-007 18136830303.799107 + 3.3763736000000000E-007 17307533417.960754 + 3.4439011000000000E-007 16516155325.650702 + 3.5127791000000000E-007 15760963127.140764 + 3.5830347000000001E-007 15040301278.532799 + 3.6546953999999998E-007 14352591433.729498 + 3.7277893000000002E-007 13696326881.594456 + 3.8023451000000001E-007 13070069494.442820 + 3.8783920000000002E-007 12472447522.296986 + 3.9559598000000000E-007 11902151766.819441 + 4.0350790000000000E-007 11357932171.402477 + 4.1157805999999999E-007 10838596629.491890 + 4.1980962000000000E-007 10343007623.858597 + 4.2820580999999999E-007 9870079223.4984512 + 4.3676993000000002E-007 9418774898.5524960 + 4.4550533000000002E-007 8988106351.1573124 + 4.5441543000000001E-007 8577130255.7068071 + 4.6350374000000000E-007 8184945470.8186483 + 4.7277382000000000E-007 7810692982.6348801 + 4.8222928999999996E-007 7453553427.5187416 + 4.9187388000000002E-007 7112743511.5251446 + 5.0171136000000002E-007 6787517014.6966610 + 5.1174559000000000E-007 6477161319.7870684 + 5.2198050000000003E-007 6180996608.3631239 + 5.3242010999999997E-007 5898373820.7871580 + 5.4306851000000005E-007 5628673863.8338795 + 5.5392987999999997E-007 5371305744.9803934 + 5.6500848000000005E-007 5125705590.5661449 + 5.7630865000000003E-007 4891335416.2200336 + 5.8783482000000000E-007 4667681758.0877953 + 5.9959151999999999E-007 4454254425.1566029 + 6.1158334999999995E-007 4250586013.4730248 + 6.2381500999999999E-007 4056230333.2004013 + 6.3629130999999998E-007 3870761357.1443782 + 6.4901713999999997E-007 3693772799.1979837 + 6.6199748000000004E-007 3524877033.9801593 + 6.7523743000000005E-007 3363703899.4316201 + 6.8874217999999998E-007 3209900309.0552664 + 7.0251701999999996E-007 3063129358.6413770 + 7.1656736000000002E-007 2923069399.7206674 + 7.3089871000000005E-007 2789413577.9710178 + 7.4551668999999998E-007 2661869074.3602333 + 7.6042702000000003E-007 2540156554.5936022 + 7.7563555999999996E-007 2424009247.9907260 + 7.9114827000000001E-007 2313172720.8053265 + 8.0697124000000003E-007 2207404096.8074675 + 8.2311066000000003E-007 2106471745.4751511 + 8.3957287999999996E-007 2010154405.2482915 + 8.5636432999999996E-007 1918241202.4974861 + 8.7349161999999997E-007 1830530625.4059026 + 8.9096145000000005E-007 1746830595.6282666 + 9.0878067999999999E-007 1666957689.9548492 + 9.2695629000000003E-007 1590736949.3339379 + 9.4549542000000000E-007 1518001331.1405859 + 9.6440533000000010E-007 1448591520.6681437 + 9.8369343999999992E-007 1382355431.5699728 + 1.0033673000000000E-006 1319147990.7537870 + 1.0234346999999999E-006 1258830492.3210196 + 1.0439033000000000E-006 1201271392.3003054 + 1.0647814000000000E-006 1146343809.2271917 + 1.0860770000000001E-006 1093927913.9954834 + 1.1077986000000000E-006 1043908507.3660606 + 1.1299546000000000E-006 996176286.85680950 + 1.1525536000000000E-006 950626834.44310856 + 1.1756046999999999E-006 907159876.11715174 + 1.1991168000000000E-006 865680462.29182279 + 1.2230990999999999E-006 826097740.43104613 + 1.2475611000000001E-006 788324832.95741260 + 1.2725124000000000E-006 752278989.66656435 + 1.2979626000000000E-006 717881495.07573700 + 1.3239218000000000E-006 685056808.51713252 + 1.3504003000000001E-006 653732876.48902380 + 1.3774083000000000E-006 623841294.32597458 + 1.4049565000000001E-006 595316448.27911973 + 1.4330556000000000E-006 568095947.99357510 + 1.4617166999999999E-006 542120072.91482520 + 1.4909509999999999E-006 517331948.33869046 + 1.5207701000000001E-006 493677158.38076752 + 1.5511855000000000E-006 471104033.88979679 + 1.5822092000000000E-006 449563058.84410787 + 1.6138532999999999E-006 429007079.48189741 + 1.6461304000000000E-006 409390938.55344498 + 1.6790529999999999E-006 390671759.68748778 + 1.7126340999999999E-006 372808480.38837469 + 1.7468867999999999E-006 355762001.91272759 + 1.7818245000000000E-006 339494989.49936914 + 1.8174609999999999E-006 323971757.16301894 + 1.8538102000000001E-006 309158328.49890012 + 1.8908864000000000E-006 295022229.57686782 + 1.9287040999999999E-006 281532504.44340748 + 1.9672781999999999E-006 268659574.38621789 + 2.0066237999999999E-006 256375247.11991504 + 2.0467562999999999E-006 244652618.30817631 + 2.0876914000000001E-006 233466014.11792561 + 2.1294452000000000E-006 222790911.53514940 + 2.1720341000000002E-006 212603916.32905811 + 2.2154747999999999E-006 202882711.27109835 + 2.2597843000000002E-006 193606006.22004980 + 2.3049799999999998E-006 184753471.74274507 + 2.3510795999999999E-006 176305717.35163444 + 2.3981012000000001E-006 168244230.71487257 + 2.4460632000000001E-006 160551356.33877766 + 2.4949844999999999E-006 153210225.59394935 + 2.5448841999999998E-006 146204768.03206238 + 2.5957817999999998E-006 139519643.32072857 + 2.6476974999999999E-006 133140174.11938395 + 2.7006514000000001E-006 127052415.91807871 + 2.7546645000000000E-006 121243004.17869684 + 2.8097577000000001E-006 115699240.95055012 + 2.8659529000000000E-006 110408950.41497400 + 2.9232720000000001E-006 105360556.20958902 + 2.9817373999999999E-006 100543003.90697807 + 3.0413720999999998E-006 95945732.025454387 + 3.1021996000000000E-006 91558660.330692887 + 3.1642435999999999E-006 87372188.689579099 + 3.2275284000000001E-006 83377146.149690047 + 3.2920789999999998E-006 79564768.593441397 + 3.3579205999999998E-006 75926710.726433173 + 3.4250790000000001E-006 72455002.798176125 + 3.4935805999999998E-006 69142035.336683005 + 3.5634522000000001E-006 65980553.011830956 + 3.6347211999999999E-006 62963629.066042639 + 3.7074157000000001E-006 60084647.650260292 + 3.7815640000000002E-006 57337309.543459058 + 3.8571953000000004E-006 54715590.843328290 + 3.9343391999999996E-006 52213749.695231773 + 4.0130259999999998E-006 49826303.246465102 + 4.0932865000000000E-006 47548022.537930578 + 4.1751521999999997E-006 45373915.228200622 + 4.2586551999999997E-006 43299218.106943920 + 4.3438283000000004E-006 41319384.440037131 + 4.4307049000000002E-006 39430076.813855864 + 4.5193190000000004E-006 37627157.449836500 + 4.6097054000000002E-006 35906675.288457364 + 4.7018995000000001E-006 34264861.766135469 + 4.7959375000000002E-006 32698118.995765790 + 4.8918562000000001E-006 31203015.622155707 + 4.9896933999999996E-006 29776273.231380627 + 5.0894872000000003E-006 28414769.846710719 + 5.1912770000000002E-006 27115518.892308448 + 5.2951024999999997E-006 25875676.652969956 + 5.4010046000000002E-006 24692524.538084690 + 5.5090247000000003E-006 23563471.884270709 + 5.6192051999999997E-006 22486044.588703938 + 5.7315893000000000E-006 21457882.176173091 + 5.8462210000000000E-006 20476732.620486479 + 5.9631455000000000E-006 19540444.275454685 + 6.0824084000000004E-006 18646967.909491993 + 6.2040564999999998E-006 17794345.664688975 + 6.3281377000000004E-006 16980708.214339003 + 6.4547004000000000E-006 16204274.669385515 + 6.5837944000000004E-006 15463342.858892167 + 6.7154702999999997E-006 14756289.655807687 + 6.8497796999999997E-006 14081566.176669700 + 6.9867753000000004E-006 13437694.013588579 + 7.1265107999999997E-006 12823262.615790203 + 7.2690409999999998E-006 12236925.805970181 + 7.4144218999999999E-006 11677398.573602589 + 7.5627103000000001E-006 11143455.857292952 + 7.7139645000000006E-006 10633927.275331518 + 7.8682438000000008E-006 10147696.566777911 + 8.0256086999999997E-006 9683698.4616727829 + 8.1861208000000003E-006 9240916.6891116519 + 8.3498433000000000E-006 8818380.4708922599 + 8.5168401000000005E-006 8415164.8609299120 + 8.6871768999999992E-006 8030385.9205410350 + 8.8609204999999996E-006 7663200.6619232958 + 9.0381389000000008E-006 7312804.9003621889 + 9.2189016999999998E-006 6978430.7400451154 + 9.4032797000000007E-006 6659345.7570849862 + 9.5913453000000004E-006 6354850.6992041664 + 9.7831721999999997E-006 6064278.5343819205 + 9.9788356000000005E-006 5786992.6790467855 + 1.0178412000000000E-005 5522385.9118151022 + 1.0381981000000000E-005 5269876.8367677992 + 1.0589620000000001E-005 5028915.2126645660 + 1.0801413000000000E-005 4798970.1050369870 + 1.1017440999999999E-005 4579540.0007866398 + 1.1237790000000000E-005 4370142.8006480681 + 1.1462545000000001E-005 4170321.0297175515 + 1.1691795999999999E-005 3979635.2350405804 + 1.1925632000000001E-005 3797668.4666920146 + 1.2164145000000001E-005 3624021.8394446643 + 1.2407428000000001E-005 3458315.2988679176 + 1.2655576000000001E-005 3300186.0139632057 + 1.2908687999999999E-005 3149286.4837214323 + 1.3166862000000000E-005 3005286.9024010641 + 1.3430199000000000E-005 2867871.8753652950 + 1.3698803000000000E-005 2736739.9479724532 + 1.3972779000000000E-005 2611603.9931547828 + 1.4252235000000000E-005 2492189.6136763925 + 1.4537279000000000E-005 2378235.8379557426 + 1.4828024999999999E-005 2269492.1153841284 + 1.5124585000000000E-005 2165720.9628725541 + 1.5427077000000000E-005 2066694.4265082360 + 1.5735619000000001E-005 1972195.7853850159 + 1.6050330999999999E-005 1882018.2856032588 + 1.6371338000000001E-005 1795963.9004598274 + 1.6698764000000002E-005 1713844.5889679128 + 1.7032740000000000E-005 1635479.7917542397 + 1.7373393999999999E-005 1560698.5167169769 + 1.7720862000000001E-005 1489336.3818411003 + 1.8075280000000002E-005 1421237.1255185530 + 1.8436784999999998E-005 1356251.9170877561 + 1.8805520999999999E-005 1294237.9695006604 + 1.9181631000000001E-005 1235059.6895512016 + 1.9565263999999999E-005 1178587.1870778245 + 1.9956569000000000E-005 1124696.9509151909 + 2.0355700999999998E-005 1073270.7029168624 + 2.0762815000000002E-005 1024195.9722807186 + 2.1178071000000000E-005 977365.18812400894 + 2.1601632000000001E-005 932675.72676108195 + 2.2033665000000000E-005 890029.58990739926 + 2.2474338000000000E-005 849333.48640435957 + 2.2923825000000001E-005 810498.14363984112 + 2.3382301000000001E-005 773438.58549524425 + 2.3849946999999999E-005 738073.51840637717 + 2.4326946000000002E-005 704325.49457770202 + 2.4813485000000001E-005 672120.58025205252 + 2.5309755000000000E-005 641388.20567062881 + 2.5815950000000001E-005 612061.07615932985 + 2.6332269000000000E-005 584074.90852185700 + 2.6858914999999999E-005 557368.36302855529 + 2.7396093000000001E-005 531883.00439070247 + 2.7944015000000000E-005 507562.93042676145 + 2.8502895000000001E-005 484354.89703530917 + 2.9072952999999999E-005 462208.02280674933 + 2.9654412000000001E-005 441073.80851015908 + 3.0247500000000001E-005 420905.95073286624 + 3.0852450000000000E-005 401660.24962004879 + 3.1469498999999998E-005 383294.54800707957 + 3.2098889000000002E-005 365768.60782600328 + 3.2740867000000000E-005 349044.02689875313 + 3.3395683999999999E-005 333084.18215294968 + 3.4063597999999998E-005 317854.07772982976 + 3.4744869999999998E-005 303320.36798482563 + 3.5439767000000002E-005 289451.21293872269 + 3.6148563000000000E-005 276216.19802248740 + 3.6871534000000001E-005 263586.36344363284 + 3.7608965000000003E-005 251534.01187652227 + 3.8361144000000001E-005 240032.75721127572 + 3.9128366999999999E-005 229057.38518446503 + 3.9910933999999997E-005 218583.86228548523 + 4.0709152999999998E-005 208589.22738368998 + 4.1523336000000001E-005 199051.59639622536 + 4.2353803000000003E-005 189950.06489815947 + 4.3200878999999998E-005 181264.69964266196 + 4.4064896000000001E-005 172976.47288255283 + 4.4946193999999997E-005 165067.21481268876 + 4.5845118000000002E-005 157519.60309820992 + 4.6762019999999999E-005 150317.10563231463 + 4.7697261000000002E-005 143443.93153248174 + 4.8651206000000002E-005 136885.03540384132 + 4.9624230000000000E-005 130626.04059658188 + 5.0616715000000000E-005 124653.23192424838 + 5.1629048999999997E-005 118953.53071920716 + 5.2661629999999999E-005 113514.44359218581 + 5.3714863000000002E-005 108324.05402841966 + 5.4789159999999998E-005 103370.99534595871 + 5.5884943000000002E-005 98644.412311095992 + 5.7002641999999997E-005 94133.948388619712 + 5.8142695000000001E-005 89829.723005431762 + 5.9305548999999997E-005 85722.306283478480 + 6.0491659999999999E-005 81802.699285230250 + 6.1701493000000006E-005 78062.314897604520 + 6.2935523000000004E-005 74492.956605586558 + 6.4194233000000006E-005 71086.806926364516 + 6.5478118000000002E-005 67836.399595407667 + 6.6787680000000003E-005 64734.617071938694 + 6.8123433999999999E-005 61774.660225477834 + 6.9485902000000004E-005 58950.048055397834 + 7.0875620000000004E-005 56254.588485216016 + 7.2293133000000004E-005 53682.376245656778 + 7.3738995999999996E-005 51227.777540072333 + 7.5213775000000006E-005 48885.416028320309 + 7.6718051000000006E-005 46650.155622935745 + 7.8252412000000003E-005 44517.102057208998 + 7.9817460000000003E-005 42481.581505754570 + 8.1413808999999994E-005 40539.133986816698 + 8.3042086000000004E-005 38685.502709762957 + 8.4702926999999999E-005 36916.629383039734 + 8.6396985999999995E-005 35228.635663673311 + 8.8124925999999998E-005 33617.824751977991 + 8.9887424000000002E-005 32080.668007057582 + 9.1685173000000000E-005 30613.796087803417 + 9.3518876000000004E-005 29213.996858227081 + 9.5389254000000006E-005 27878.202032182500 + 9.7297038999999994E-005 26603.486100990729 + 9.9242979000000001E-005 25387.056296952607 + 1.0122784000000000E-004 24226.245826690531 + 1.0325239999999999E-004 23118.511907098316 + 1.0531744000000000E-004 22061.434187145624 + 1.0742379000000001E-004 21052.686268415113 + 1.0957227000000001E-004 20090.061547655005 + 1.1176371000000000E-004 19171.456341886540 + 1.1399899000000000E-004 18294.849481054789 + 1.1627897000000000E-004 17458.327132412986 + 1.1860455000000000E-004 16660.054195544297 + 1.2097664000000001E-004 15898.282375265315 + 1.2339617000000001E-004 15171.342669353615 + 1.2586408999999999E-004 14477.642006433896 + 1.2838138000000000E-004 13815.657428149610 + 1.3094900000000000E-004 13183.945637516810 + 1.3356798000000000E-004 12581.116723967780 + 1.3623933999999999E-004 12005.851759216137 + 1.3896412999999999E-004 11456.889939716984 + 1.4174340999999999E-004 10933.030204674744 + 1.4457827999999999E-004 10433.122897617906 + 1.4746985000000000E-004 9956.0731913299514 + 1.5041923999999999E-004 9500.8380764484391 + 1.5342763000000001E-004 9066.4165742123387 + 1.5649618000000001E-004 8651.8598306724380 + 1.5962610000000001E-004 8256.2585744065291 + 1.6281862999999999E-004 7878.7446204035850 + 1.6607500000000001E-004 7518.4934844581639 + 1.6939650000000000E-004 7174.7143625408125 + 1.7278443000000001E-004 6846.6543581034957 + 1.7624011999999999E-004 6533.5946006210788 + 1.7976491999999999E-004 6234.8496538734908 + 1.8336021999999999E-004 5949.7643415035282 + 1.8702742000000001E-004 5677.7148422901691 + 1.9076797000000000E-004 5418.1042386559257 + 1.9458333000000000E-004 5170.3642617921560 + 1.9847500000000001E-004 4933.9519018229212 + 2.0244450000000001E-004 4708.3495711127734 + 2.0649338999999999E-004 4493.0627871997895 + 2.1062326000000000E-004 4287.6197713872743 + 2.1483571999999999E-004 4091.5708682275231 + 2.1913242999999999E-004 3904.4861478461448 + 2.2351508000000001E-004 3725.9555373309636 + 2.2798539000000001E-004 3555.5878891576617 + 2.3254509000000001E-004 3393.0107901952560 + 2.3719599000000000E-004 3237.8672318796284 + 2.4193991000000001E-004 3089.8174656635324 + 2.4677871000000000E-004 2948.5371523035915 + 2.5171428999999998E-004 2813.7167033104624 + 2.5674857000000000E-004 2685.0611445267027 + 2.6188353999999998E-004 2562.2881823134712 + 2.6712121999999998E-004 2445.1287164017031 + 2.7246364000000001E-004 2333.3265931216993 + 2.7791291000000000E-004 2226.6365271332370 + 2.8347117000000001E-004 2124.8247222291452 + 2.8914058999999999E-004 2027.6682967325241 + 2.9492340999999998E-004 1934.9541131481556 + 3.0082186999999999E-004 1846.4794830622891 + 3.0683830999999999E-004 1762.0501537185794 + 3.1297508000000001E-004 1681.4812979950680 + 3.1923458000000001E-004 1604.5964775505568 + 3.2561926999999998E-004 1531.2271735244158 + 3.3213166000000001E-004 1461.2125763080928 + 3.3877429000000000E-004 1394.3994383564398 + 3.4554977999999998E-004 1330.6412261985129 + 3.5246076999999998E-004 1269.7984105041310 + 3.5950998999999999E-004 1211.7375158246011 + 3.6670019000000002E-004 1156.3314598176823 + 3.7403418999999998E-004 1103.4588443940845 + 3.8151487000000000E-004 1053.0037993354442 + 3.8914517000000000E-004 1004.8557439839823 + 3.9692807000000000E-004 958.90926817138632 + 4.0486663999999997E-004 915.06360504680390 + 4.1296397000000000E-004 873.22282170206813 + 4.2122325000000001E-004 833.29516897294911 + 4.2964771000000000E-004 795.19321177104700 + 4.3824066999999998E-004 758.83340065720188 + 4.4700548000000003E-004 724.13615948878828 + 4.5594559000000000E-004 691.02541664890100 + 4.6506450000000001E-004 659.42865250192358 + 4.7436579000000002E-004 629.27662754348455 + 4.8385311000000001E-004 600.50327555720492 + 4.9353017000000002E-004 573.04558821081014 + 5.0340077000000005E-004 546.84339171685224 + 5.1346878999999998E-004 521.83925698704104 + 5.2373815999999995E-004 497.97844708202007 + 5.3421293000000003E-004 475.20863272687154 + 5.4489719000000002E-004 453.47996756245192 + 5.5579513000000001E-004 432.74484388859719 + 5.6691103000000001E-004 412.95782013318836 + 5.7824924999999995E-004 394.07554406959622 + 5.8981424000000005E-004 376.05664154394248 + 6.0161052000000002E-004 358.86165810382306 + 6.1364272999999997E-004 342.45289987060636 + 6.2591559000000003E-004 326.79441621993942 + 6.3843389999999997E-004 311.85191713956726 + 6.5120257999999999E-004 297.59265167353175 + 6.6422663000000005E-004 283.98538732020444 + 6.7751116000000001E-004 271.00030875774297 + 6.9106139000000004E-004 258.60895752742181 + 7.0488261000000005E-004 246.78420673106629 + 7.1898027000000004E-004 235.50012387696981 + 7.3335987000000004E-004 224.73200967541163 + 7.4802707000000000E-004 214.45625610250985 + 7.6298760999999997E-004 204.65035857094162 + 7.7824736000000000E-004 195.29283091255718 + 7.9381231000000003E-004 186.36316835613906 + 8.0968855000000000E-004 177.84181467609744 + 8.2588232999999999E-004 169.71008776841461 + 8.4239997000000000E-004 161.95018711420093 + 8.5924796999999997E-004 154.54510055106095 + 8.7643292999999998E-004 147.47860765768473 + 8.9396159000000000E-004 140.73522612058639 + 9.1184082000000000E-004 134.30018326835051 + 9.3007764000000001E-004 128.15937752913058 + 9.4867919000000002E-004 122.29935890304898 + 9.6765277000000001E-004 116.70728674919727 + 9.8700582999999994E-004 111.37090681021482 + 1.0067459000000000E-003 106.27854285962243 + 1.0268809000000001E-003 101.41899378289264 + 1.0474185000000000E-003 96.781668078947419 + 1.0683668999999999E-003 92.356371572505694 + 1.0897342000000000E-003 88.133432785485070 + 1.1115289000000000E-003 84.103575515231697 + 1.1337595000000000E-003 80.257980503515171 + 1.1564346000000000E-003 76.588241049170264 + 1.1795632999999999E-003 73.086283225151718 + 1.2031546000000001E-003 69.744447078952007 + 1.2272177000000001E-003 66.555418245317071 + 1.2517620000000000E-003 63.512213566317371 + 1.2767973000000000E-003 60.608144595986715 + 1.3023332000000000E-003 57.836874196360156 + 1.3283799000000001E-003 55.192310302517157 + 1.3549475000000000E-003 52.668671038432279 + 1.3820464000000000E-003 50.260428320124269 + 1.4096874000000001E-003 47.962291133764388 + 1.4378811000000000E-003 45.769244451627792 + 1.4666386999999999E-003 43.676471602128551 + 1.4959715000000000E-003 41.679386419660766 + 1.5258909000000001E-003 39.773620458543157 + 1.5564088000000001E-003 37.954988056748043 + 1.5875368999999999E-003 36.219520481762594 + 1.6192877000000001E-003 34.563399012652916 + 1.6516733999999999E-003 32.983008494777621 + 1.6847069000000001E-003 31.474876533747612 + 1.7184010000000000E-003 30.035706087859037 + 1.7527691000000000E-003 28.662336284402915 + 1.7878244000000001E-003 27.351769142616142 + 1.8235809000000001E-003 26.101123618430815 + 1.8600526000000000E-003 24.907661005447931 + 1.8972536000000000E-003 23.768772972227683 + 1.9351987000000000E-003 22.681957673830212 + 1.9739025999999998E-003 21.644839122059562 + 2.0133807000000002E-003 20.655139183383611 + 2.0536483000000000E-003 19.710694230172933 + 2.0947213000000000E-003 18.809432481785571 + 2.1366156999999999E-003 17.949381685655915 + 2.1793479999999998E-003 17.128655999701149 + 2.2229350000000001E-003 16.345456604863337 + 2.2673937000000002E-003 15.598069281538553 + 2.3127415999999999E-003 14.884855451231967 + 2.3589964000000001E-003 14.204253795047784 + 2.4061763000000000E-003 13.554772205764143 + 2.4542997999999999E-003 12.934987768514379 + 2.5033858000000002E-003 12.343542275133615 + 2.5534536000000000E-003 11.779139443544361 + 2.6045225999999999E-003 11.240545281847178 + 2.6566131000000000E-003 10.726576859973671 + 2.7097453000000001E-003 10.236110382515051 + 2.7639402000000000E-003 9.7680697210320773 + 2.8192191000000000E-003 9.3214291697803997 + 2.8756034000000001E-003 8.8952123706270250 + 2.9331155000000002E-003 8.4884832896086770 + 2.9917778000000000E-003 8.1003519626672364 + 3.0516134000000000E-003 7.7299674072682985 + 3.1126456000000000E-003 7.3765191332292943 + 3.1748985000000000E-003 7.0392317758868712 + 3.2383964999999999E-003 6.7173664937951703 + 3.3031644000000001E-003 6.4102186154783594 + 3.3692277000000001E-003 6.1171147219338406 + 3.4366123000000000E-003 5.8374127147768213 + 3.5053444999999998E-003 5.5705002911118102 + 3.5754514000000000E-003 5.3157920881015999 + 3.6469605000000000E-003 5.0727300810660143 + 3.7198996999999998E-003 4.8407822225644503 + 3.7942977000000001E-003 4.6194400088394785 + 3.8701835999999999E-003 4.4082187127596653 + 3.9475873000000003E-003 4.2066551825077063 + 4.0265390000000000E-003 4.0143082164439088 + 4.1070697999999999E-003 3.8307560609345042 + 4.1892112000000000E-003 3.6555967659571129 + 4.2729954000000001E-003 3.4884465912339926 + 4.3584553000000003E-003 3.3289392381115874 + 4.4456243999999997E-003 3.1767252691340784 + 4.5345369000000003E-003 3.0314711740842135 + 4.6252276999999998E-003 2.8928586727996413 + 4.7177321999999997E-003 2.7605843212152279 + 4.8120869000000000E-003 2.6343579964901789 + 4.9083286000000002E-003 2.5139034221241814 + 5.0064951999999998E-003 2.3989564912028905 + 5.1066250999999997E-003 2.2892654836967314 + 5.2087575999999998E-003 2.1845900369193556 + 5.3129327000000000E-003 2.0847008657056882 + 5.4191914000000004E-003 1.9893789857592377 + 5.5275751999999999E-003 1.8984157110153121 + 5.6381267000000001E-003 1.8116116637319581 + 5.7508893000000000E-003 1.7287766355627836 + 5.8659070000000001E-003 1.6497292989845691 + 5.9832252000000001E-003 1.5742962656613595 + 6.1028897000000000E-003 1.5023124071719436 + 6.2249475000000004E-003 1.4336199668291105 + 6.3494464000000000E-003 1.3680684806020620 + 6.4764354000000001E-003 1.3055142415118048 + 6.6059641000000002E-003 1.2458202994772352 + 6.7380833999999999E-003 1.1888558204819208 + 6.8728449999999998E-003 1.1344960459591205 + 7.0103018999999999E-003 1.0826218165777304 + 7.1505079999999999E-003 1.0331194879160142 + 7.2935181000000002E-003 0.98588066702327803 + 7.4393884999999996E-003 0.94080178566405215 + 7.5881762000000004E-003 0.89778414327704192 + 7.7399397999999998E-003 0.85673342012589626 + 7.8947385999999994E-003 0.81755973839638596 + 8.0526333000000005E-003 0.78017726996665782 + 8.2136859999999996E-003 0.74450407132540453 + 8.3779596999999997E-003 0.71046202200441488 + 8.5455189000000001E-003 0.67797652229419658 + 8.7164293000000000E-003 0.64697640195123329 + 8.8907579000000007E-003 0.61739374723079110 + 9.0685729999999999E-003 0.58916375490534367 + 9.2499444999999993E-003 0.56222454926777399 + 9.4349433999999996E-003 0.53651712898530080 + 9.6236423000000005E-003 0.51198516418139162 + 9.8161150999999999E-003 0.48857491980491274 + 1.0012437000000001E-002 0.46623513528188409 + 1.0212686000000000E-002 0.44491675455937113 + 1.0416940000000000E-002 0.42457314521480627 + 1.0625279000000000E-002 0.40515974557793161 + 1.0837784000000000E-002 0.38663408029013380 + 1.1054540000000000E-002 0.36895541702612150 + 1.1275631000000000E-002 0.35208511174224882 + 1.1501143000000000E-002 0.33598624979032610 + 1.1731165999999999E-002 0.32062344789591679 + 1.1965790000000000E-002 0.30596306990135075 + 1.2205105000000001E-002 0.29197311621767125 + 1.2449207000000000E-002 0.27862280582629312 + 1.2698192000000001E-002 0.26588288341533961 + 1.2952155000000000E-002 0.25372556865646928 + 1.3211199000000000E-002 0.24212406279904539 + 1.3475422000000001E-002 0.23105310831302997 + 1.3744931000000000E-002 0.22048830640289663 + 1.4019830000000000E-002 0.21040658219779360 + 1.4300225999999999E-002 0.20078587286253557 + 1.4586231000000000E-002 0.19160503053986452 + 1.4877955000000000E-002 0.18284401027857561 + 1.5175513999999999E-002 0.17448356772390042 + 1.5479025000000000E-002 0.16650538092873565 + 1.5788605000000001E-002 0.15889202269364919 + 1.6104377000000000E-002 0.15162677156871154 + 1.6426465000000001E-002 0.14469370836805959 + 1.6754993999999999E-002 0.13807767123810727 + 1.7090094000000000E-002 0.13176414085294239 + 1.7431895999999999E-002 0.12573929343627163 + 1.7780534000000001E-002 0.11998992974505628 + 1.8136144000000000E-002 0.11450346406709788 + 1.8498866999999999E-002 0.10926785229966474 + 1.8868844999999999E-002 0.10427162915670114 + 1.9246222000000000E-002 9.9503863062363321E-002 + 1.9631145999999999E-002 9.4954106797128096E-002 + 2.0023769000000000E-002 9.0612379827296058E-002 + 2.0424244000000001E-002 8.6469180684827104E-002 + 2.0832729000000001E-002 8.2515422188434634E-002 + 2.1249384000000000E-002 7.8742444651995577E-002 + 2.1674371000000001E-002 7.5141993754831299E-002 + 2.2107859000000001E-002 7.1706161547957906E-002 + 2.2550015999999999E-002 6.8427436675349312E-002 + 2.3001015999999999E-002 6.5298630616325334E-002 + 2.3461037000000001E-002 6.2312881138150637E-002 + 2.3930257000000000E-002 5.9463662087143557E-002 + 2.4408862999999999E-002 5.6744712988084874E-002 + 2.4897039999999999E-002 5.4150092456364991E-002 + 2.5394981000000000E-002 5.1674107272516742E-002 + 2.5902880000000000E-002 4.9311338945007187E-002 + 2.6420938000000001E-002 4.7056602473489244E-002 + 2.6949357000000000E-002 4.4904963371035084E-002 + 2.7488344000000001E-002 4.2851708281143361E-002 + 2.8038111000000001E-002 4.0892336262560322E-002 + 2.8598873000000000E-002 3.9022556611212483E-002 + 2.9170850000000002E-002 3.7238272318929865E-002 + 2.9754267000000001E-002 3.5535572092807909E-002 + 3.0349352999999999E-002 3.3910725184354645E-002 + 3.0956339999999999E-002 3.2360175432256826E-002 + 3.1575467000000003E-002 3.0880523131259750E-002 + 3.2206975999999998E-002 2.9468528344714199E-002 + 3.2851115000000000E-002 2.8121096586458158E-002 + 3.3508138000000000E-002 2.6835273054267930E-002 + 3.4178300000000002E-002 2.5608245788794195E-002 + 3.4861865999999998E-002 2.4437322349806948E-002 + 3.5559104000000001E-002 2.3319937707785655E-002 + 3.6270285999999999E-002 2.2253646054815338E-002 + 3.6995691999999997E-002 2.1236109527015865E-002 + 3.7735604999999998E-002 2.0265100761680453E-002 + 3.8490318000000003E-002 1.9338488721918529E-002 + 3.9260124000000000E-002 1.8454246994097888E-002 + 4.0045325999999999E-002 1.7610436848660517E-002 + 4.0846233000000003E-002 1.6805208509125601E-002 + 4.1663157999999999E-002 1.6036798964303569E-002 + 4.2496421000000000E-002 1.5303524984133326E-002 + 4.3346348999999999E-002 1.4603779765287841E-002 + 4.4213276000000003E-002 1.3936029675589538E-002 + 4.5097541999999997E-002 1.3298811783992724E-002 + 4.5999492000000003E-002 1.2690731225357922E-002 + 4.6919481999999998E-002 1.2110454181294502E-002 + 4.7857872000000003E-002 1.1556709889269892E-002 + 4.8815029000000003E-002 1.1028285701586156E-002 + 4.9791330000000002E-002 1.0524022984196546E-002 + 5.0787156999999999E-002 1.0042817434779193E-002 + 5.1802899999999999E-002 9.5836150019858683E-003 + 5.2838957999999998E-002 9.1454092949484790E-003 + 5.3895736999999999E-002 8.7272403727407643E-003 + 5.4973651999999998E-002 8.3281918480295827E-003 + 5.6073125000000001E-002 7.9473897114159184E-003 + 5.7194586999999998E-002 7.5839996939896194E-003 + 5.8338478999999999E-002 7.2372252589365579E-003 + 5.9505247999999997E-002 6.9063071362134047E-003 + 6.0695353000000000E-002 6.5905198996111438E-003 + 6.1909260000000001E-002 6.2891718912211131E-003 + 6.3147445999999996E-002 6.0016026666124779E-003 + 6.4410394999999995E-002 5.7271825549078349E-003 + 6.5698601999999995E-002 5.4653103507859195E-003 + 6.7012575000000005E-002 5.2154117605065871E-003 + 6.8352826000000005E-002 4.9769399134100556E-003 + 6.9719882999999996E-002 4.7493719014593400E-003 + 7.1114280000000002E-002 4.5322094926857652E-003 + 7.2536565999999997E-002 4.3249765639462086E-003 + 7.3987296999999994E-002 4.1272193494821408E-003 + 7.5467042999999998E-002 3.9385044288789148E-003 + 7.6976383999999995E-002 3.7584183891924239E-003 + 7.8515911999999993E-002 3.6022923901546607E-003 + 8.0086229999999994E-002 3.4312226207997448E-003 + 8.1687953999999993E-002 3.2692767414769096E-003 + 8.3321714000000005E-002 3.1158494908371383E-003 + 8.4988147999999999E-002 2.9703864529170964E-003 + 8.6687911000000006E-002 2.8323783456352821E-003 + 8.8421668999999994E-002 2.7013572414019589E-003 + 9.0190101999999994E-002 2.5768924155658555E-003 + 9.1993904000000001E-002 2.4585868899378942E-003 + 9.3833782000000004E-002 2.3460743772041044E-003 + 9.5710457999999998E-002 2.2390163545490840E-003 + 9.7624666999999998E-002 2.1370996669088666E-003 + 9.9577160999999997E-002 2.0400340514368045E-003 + 0.10156870000000000 1.9475505385187220E-003 + 0.10360008000000000 1.8593983413995490E-003 + 0.10567208000000000 1.7753455727625407E-003 + 0.10778552000000000 1.6951751804403542E-003 + 0.10994123000000000 1.6186849907224247E-003 + 0.11214006000000000 1.5456860881903436E-003 + 0.11438286000000000 1.4760023440242560E-003 + 0.11667051000000001 1.4094684066654184E-003 + 0.11900392000000000 1.3459289274486048E-003 + 0.12138400000000001 1.2852385829002393E-003 + 0.12381167999999999 1.2272607135139098E-003 + 0.12628792000000000 1.1718664511931147E-003 + 0.12881368000000001 1.1189347945696182E-003 + 0.13138995000000001 1.0683513525400652E-003 + 0.13401774999999999 1.0200079120643857E-003 + 0.13669809999999999 9.7380253343640731E-004 + 0.13943206000000000 9.2963839340060115E-004 + 0.14222071000000000 8.8742379783392558E-004 + 0.14506511999999999 8.4707223594697630E-004 + 0.14796641999999999 8.0850102094817287E-004 + 0.15092575000000000 7.7163177140573275E-004 + 0.15394426999999999 7.3638997871478169E-004 + 0.15702315000000000 7.0270486034572138E-004 + 0.16016361000000001 6.7050869799272644E-004 + 0.16336688999999999 6.3973700224614330E-004 + 0.16663422000000000 6.1032857068573038E-004 + 0.16996691000000000 5.8222448460980715E-004 + 0.17336625000000000 5.5536886846663117E-004 + 0.17683357000000000 5.2970819578543012E-004 + 0.18037023999999999 5.0519119375514745E-004 + 0.18397764999999999 4.8176887581484088E-004 + 0.18765720000000000 4.5939447056862884E-004 + 0.19141035000000001 4.3802300797355341E-004 + 0.19523855000000001 4.1761164308140933E-004 + 0.19914332000000001 3.9811911209959409E-004 + 0.20312619000000001 3.7950598739073713E-004 + 0.20718871000000000 3.6173452482926675E-004 + 0.21133249000000001 3.4476841875036155E-004 + 0.21555914000000001 3.2857299517820217E-004 + 0.21987032000000001 3.1311493426204698E-004 + 0.22426773000000000 2.9836226483885103E-004 + 0.22875308000000000 2.8428440631552798E-004 + 0.23332813999999999 2.7085194914668525E-004 + 0.23799471000000000 2.5803670987304441E-004 + 0.24275459999999999 2.4581172768853592E-004 + 0.24760968999999999 2.3415105893045062E-004 + 0.25256189000000001 2.2302984856593586E-004 + 0.25761311999999997 2.1242432380356169E-004 + 0.26276538999999999 2.0231158459034257E-004 + 0.26802069000000001 1.9266979537351951E-004 + 0.27338110999999998 1.8347791410466458E-004 + 0.27884872999999999 1.7471586345250523E-004 + 0.28442570000000000 1.6636435462571839E-004 + 0.29011421999999998 1.5840489812491947E-004 + 0.29591650000000003 1.5081982721019420E-004 + 0.30183483000000000 1.4359217184703056E-004 + 0.30787153000000000 1.3670570105455112E-004 + 0.31402896000000002 1.3014487962213775E-004 + 0.32030954000000000 1.2389482107831142E-004 + 0.32671572999999998 1.1794128528848531E-004 + 0.33325004000000003 1.1227064347966266E-004 + 0.33991505000000000 1.0686983986372273E-004 + 0.34671334999999998 1.0172641843476733E-004 + 0.35364761000000000 9.6828443111989703E-005 + 0.36072057000000002 9.2164490407483672E-005 + 0.36793498000000002 8.7723668450142203E-005 + 0.37529368000000002 8.3495543838788171E-005 + 0.38279954999999999 7.9470155823599205E-005 + 0.39045553999999999 7.5637980636287269E-005 + 0.39826465000000000 7.1989925113976138E-005 + 0.40622994000000001 6.8517304163223913E-005 + 0.41435453999999999 6.5211820616685806E-005 + 0.42264162999999999 6.2065558015812156E-005 + 0.43109447000000001 5.9070953554498873E-005 + 0.43971635999999997 5.6220798193003670E-005 + 0.44851067999999999 5.3508207777286272E-005 + 0.45748090000000002 5.0926608275832156E-005 + 0.46663051999999999 4.8469740289257595E-005 + 0.47596313000000001 4.6131628274601184E-005 + 0.48548238999999999 4.3906574661578607E-005 + 0.49519204000000000 4.1789145907399948E-005 + 0.50509588000000005 3.9774165616429312E-005 + 0.51519778999999999 3.7856698982543942E-005 + 0.52550174999999999 3.6032039261292469E-005 + 0.53601178000000005 3.4295708608746228E-005 + 0.54673201999999999 3.2643434299722012E-005 + 0.55766665999999998 3.1071151297384975E-005 + 0.56881999000000005 2.9574985244511821E-005 + 0.58019639000000001 2.8151245921697637E-005 + 0.59180032000000005 2.6796420350683046E-005 + 0.60363633000000005 2.5507163561611956E-005 + 0.61570906000000003 2.4280291103886423E-005 + 0.62802323999999998 2.3112771794102293E-005 + 0.64058369999999998 2.2001719866302217E-005 + 0.65339537000000003 2.0944388517727065E-005 + 0.66646327999999999 1.9938163654314873E-005 + 0.67979255000000005 1.8980558530682307E-005 + 0.69338840000000002 1.8069207033326317E-005 + 0.70725616999999996 1.7201856875192841E-005 + 0.72140128999999997 1.6376366311965109E-005 + 0.73582932000000001 1.5590696617540340E-005 + 0.75054589999999999 1.4842910078118326E-005 + 0.76555682000000003 1.4131161615913417E-005 + 0.78086796000000003 1.3453697522968135E-005 + 0.79648532000000005 1.2808849637618633E-005 + 0.81241501999999999 1.2195031346478809E-005 + 0.82866331999999998 1.1610733050584085E-005 + 0.84523658999999995 1.1054519666761100E-005 + 0.86214131999999999 1.0525026639626276E-005 + 0.87938415000000003 1.0020955679207626E-005 + 0.89697183000000003 9.5410728277409563E-006 + 0.91491127000000005 9.0842039817177521E-006 + 0.93320948999999997 8.6492333594888504E-006 + 0.95187368000000006 8.2350992297271437E-006 + 0.97091116000000000 7.8407923076613850E-006 + 0.99032938000000004 7.4653531495942172E-006 + 1.0101359999999999 7.1078682725896258E-006 + 1.0303386999999999 6.7674713418441464E-006 + 1.0509455000000001 6.4433353988246167E-006 + 1.0719643999999999 6.1346769090525625E-006 + 1.0934037000000001 5.8407486592846609E-006 + 1.1152717000000001 5.5608422672354001E-006 + 1.1375772000000000 5.2942799273487192E-006 + 1.1603287000000000 5.0404226807096867E-006 + 1.1835353000000000 4.7986579513811851E-006 + 1.2072060000000000 4.5684061438820748E-006 + 1.2313501000000000 4.3491147343732399E-006 + 1.2559771000000000 4.1402581002204751E-006 + 1.2810967000000000 3.9413362423637700E-006 + 1.3067186000000000 3.7518749861046138E-006 + 1.3328530000000001 3.5714209910923866E-006 + 1.3595100000000000 3.3995450844682388E-006 + 1.3867001999999999 3.2358370349092847E-006 + 1.4144342000000001 3.0799078641003735E-006 + 1.4427228999999999 2.9313869466316141E-006 + 1.4715773999999999 2.7899217281040942E-006 + 1.5010089000000000 2.6551772670741961E-006 + 1.5310291000000000 2.5268335737272809E-006 + 1.5616497000000000 2.4045871515327654E-006 + 1.5928827000000001 2.2881488476716760E-006 + 1.6247403000000000 2.1772435682696184E-006 + 1.6572351000000001 2.0716089373280299E-006 + 1.6903798000000001 1.9709957016289277E-006 + 1.7241873999999999 1.8751664189881942E-006 + 1.7586712000000000 1.7838949276976497E-006 + 1.7938445999999999 1.6969663077896142E-006 + 1.8297215000000000 1.6141753381465933E-006 + 1.8663159000000000 1.5353270155298157E-006 + 1.9036422000000000 1.4602353699085672E-006 + 1.9417150999999999 1.3887232860848904E-006 + 1.9805493999999999 1.3206224198964781E-006 + 2.0201604000000000 1.2557720535892756E-006 + 2.0605636000000001 1.1940192700385869E-006 + 2.1017747999999998 1.1352183991058157E-006 + 2.1438103000000002 1.0792304109036189E-006 + 2.1866865000000000 1.0259231517799499E-006 + 2.2304203000000000 9.7517048822484287E-007 + 2.2750287000000000 9.2685249717953427E-007 + 2.3205293000000000 8.8085461291098330E-007 + 2.3669397999999999 8.3706790542262777E-007 + 2.4142785999999998 7.9538823828433185E-007 + 2.4625642000000001 7.5571660682439918E-007 + 2.5118155000000000 7.1795860941770322E-007 + 2.5620517999999999 6.8202424150909173E-007 + 2.6132928000000000 6.4782769436210918E-007 + 2.6655587000000001 6.1528710290604083E-007 + 2.7188699000000001 5.8432454887356018E-007 + 2.7732473000000000 5.5486568620602606E-007 + 2.8287122000000000 5.2683963973580946E-007 + 2.8852864999999999 5.0017875135318330E-007 + 2.9429921999999999 4.7481866724102401E-007 + 3.0018520000000000 4.5069790456179084E-007 + 3.0618891000000001 4.2775782591244413E-007 + 3.1231268999999999 4.0594261569374603E-007 + 3.1855894000000000 3.8519899551149661E-007 + 3.2493012000000001 3.6547612161941246E-007 + 3.3142871999999999 3.4672556871512286E-007 + 3.3805730000000001 3.2890109871329619E-007 + 3.4481844000000001 3.1195869906256110E-007 + 3.5171481000000000 2.9585630064883208E-007 + 3.5874910999999998 2.8055384280017341E-007 + 3.6592408999999999 2.6601312763698079E-007 + 3.7324256999999998 2.5219769748557175E-007 + 3.8070742000000002 2.3907279902916152E-007 + 3.8832157000000000 2.2660528735736687E-007 + 3.9608800000000000 2.1476356942386979E-007 + 4.0400976000000002 2.0351750336750129E-007 + 4.1208996000000004 1.9283835048748273E-007 + 4.2033176000000001 1.8269872398046387E-007 + 4.2873839000000000 1.7307250173592538E-007 + 4.3731315999999998 1.6393476215019414E-007 + 4.4605942000000001 1.5526177371854186E-007 + 4.5498060999999996 1.4703088939026808E-007 + 4.6408022000000004 1.3922053790020964E-007 + 4.7336182999999998 1.3181014009141134E-007 + 4.8282905999999999 1.2478010539459352E-007 + 4.9248564000000004 1.1811173409699362E-007 + 5.0233536000000001 1.1178721674602573E-007 + 5.1238206000000002 1.0578959705457706E-007 + 5.2262971000000000 1.0010268658297935E-007 + 5.3308229999999996 9.4711094396125430E-008 + 5.4374395000000000 8.9600131083774358E-008 + 5.5461881999999996 8.4755823750441427E-008 + 5.6571119999999997 8.0164842292397229E-008 + 5.7702543000000004 7.5814506383632725E-008 + 5.8856593000000004 7.1692741682779182E-008 + 6.0033725000000002 6.7788036235637084E-008 + 6.1234400000000004 6.4089440353119546E-008 + 6.2459087999999996 6.0586530074846717E-008 + 6.3708270000000002 5.7269378335183679E-008 + 6.4982435000000001 5.4128541134981083E-008 + 6.6282084000000001 5.1155025714124698E-008 + 6.7607724999999999 4.8340282090247607E-008 + 6.8959880000000000 4.5676167704911064E-008 + 7.0339077000000003 4.3154945523871724E-008 + 7.1745859000000003 4.0769248354273071E-008 + 7.3180775999999996 3.8512076588258226E-008 + 7.4644392000000002 3.6376769680766525E-008 + 7.6137278999999998 3.4356999919806144E-008 + 7.7660024999999999 3.2446746131144812E-008 + 7.9213225999999999 3.0640290415178342E-008 + 8.0797489999999996 2.8932198610979322E-008 + 8.2413439999999998 2.7317304418008096E-008 + 8.4061708999999993 2.5790702366409486E-008 + 8.5742943000000000 2.4347732512357049E-008 + 8.7457802000000004 2.2983968354187342E-008 + 8.9206958000000007 2.1695207650757864E-008 + 9.0991096999999996 2.0477460325152658E-008 + 9.2810918999999998 1.9326938642103459E-008 + 9.4667136999999997 1.8240048294225797E-008 + 9.6560480000000002 1.7213377517830794E-008 + 9.8491689999999998 1.6243690201759347E-008 + 10.046151999999999 1.5327918151381987E-008 + 10.247075000000001 1.4463145917317794E-008 + 10.452017000000000 1.3646611659062357E-008 + 10.661057000000000 1.2875702506103728E-008 + 10.874278000000000 1.2147932399161688E-008 + 11.091764000000000 1.1460947819594073E-008 + 11.313599000000000 1.0812523391078608E-008 + 11.539871000000000 1.0200543647741965E-008 + 11.770669000000000 9.6230069745514478E-009 + 12.006081999999999 9.0780215504960070E-009 + 12.246204000000001 8.5637883250348497E-009 + 12.491128000000000 8.0786101429296585E-009 + 12.740950000000000 7.6208777192613472E-009 + 12.995768999999999 7.1890659978458325E-009 + 13.255685000000000 6.7817335244042287E-009 + 13.520797999999999 6.3975191008729669E-009 + 13.791214000000000 6.0351290961527149E-009 + 14.067038999999999 5.6933429562030971E-009 + 14.348379000000000 5.3710085726379308E-009 + 14.635346999999999 5.0670309067781817E-009 + 14.928053999999999 4.7803792527400868E-009 + 15.226615000000001 4.5100773028767143E-009 + 15.531147000000001 4.2552025150862812E-009 + 15.841770000000000 4.0148825020956005E-009 + 16.158605999999999 3.7882932784825927E-009 + 16.481777999999998 3.5746572710012221E-009 + 16.811413000000002 3.3732388284173237E-009 + 17.147642000000001 3.1833423468052765E-009 + 17.490594000000002 3.0043134261610007E-009 + 17.840406000000002 2.8355312663834403E-009 + 18.197213999999999 2.6764116173916283E-009 + 18.561159000000000 2.5264018946429973E-009 + 18.932382000000000 2.3849816339745919E-009 + 19.311029000000001 2.2516587310468632E-009 + 19.697250000000000 2.1259684941715491E-009 + 20.091194999999999 2.0074734302020766E-009 + 20.493019000000000 1.8957601407478390E-009 + 20.902878999999999 1.7904389478461058E-009 + 21.320937000000001 1.6911418271536741E-009 + 21.747356000000000 1.5975222152554887E-009 + 22.182303000000001 1.5092530890933402E-009 + 22.625948999999999 1.4260259491803929E-009 + 23.078468000000001 1.3475500091468277E-009 + 23.540037000000002 1.2735511943460025E-009 + 24.010838000000000 1.2037709103530324E-009 + 24.491054999999999 1.1379656506647364E-009 + 24.980875999999999 1.0759058410810340E-009 + 25.480492999999999 1.0173750803668472E-009 + 25.990103000000001 9.6216931142876283E-010 + 26.509905000000000 9.1009645923066965E-010 + 27.040102999999998 8.6097542861611026E-010 + 27.580905000000001 8.1463560222372053E-010 + 28.695174000000002 7.2966589031651737E-010 + 29.854458999999999 6.5401004871203844E-010 + 31.060579000000001 5.8662332610716834E-010 + 32.315427000000000 5.2657882156795515E-010 + 33.620970000000000 4.7305443767792211E-010 + 34.979256999999997 4.2532090882291807E-010 + 36.392418999999997 3.8273151116352206E-010 + 37.862673000000001 3.4471272458553628E-010 + 39.392325000000000 3.1075597040908430E-010 + 40.983775000000001 2.8041022558860062E-010 + 42.639519000000000 2.5327553160832373E-010 + 44.362155999999999 2.2899714203019620E-010 + 46.154387000000000 2.0726045398140483E-010 + 48.019024000000002 1.8778636715433720E-010 + 49.958993000000000 1.7032726118887742E-010 + 51.977336000000001 1.5466342475235416E-010 + 54.077219999999997 1.4059983475734602E-010 + 56.261940000000003 1.2796335776133195E-010 + 58.534922000000002 1.1660026189343760E-010 + 60.899732999999998 1.0637397901384812E-010 + 63.360081999999998 9.7163170260146996E-011 + 65.919830000000005 8.8859973981599563E-011 + 68.582991000000007 8.1368489040764416E-011 + 71.353744000000006 7.4603397767326091E-011 + 74.236435000000000 6.8488777741613896E-011 + 77.235586999999995 6.2957029531914039E-011 + 80.355905000000007 5.7947940028684915E-011 + 83.602283000000000 5.3407848706021217E-011 + 86.979815000000002 4.9288905282129231E-011 + 90.493799999999993 4.5548421668259681E-011 + 94.149749000000000 4.2148294372322209E-011 + 97.953399000000005 3.9054487437455199E-011 + 101.91072000000000 3.6236582365917923E-011 + 106.02791000000001 3.3667385383971742E-011 + 110.31144000000000 3.1322548711452861E-011 + 114.76802000000001 2.9180283178750872E-011 + 119.40465000000000 2.7221055805406316E-011 + 124.22859000000000 2.5427361505696765E-011 + 129.24743000000001 2.3783480138677208E-011 + 134.46903000000000 2.2275308356690163E-011 + 139.90156999999999 2.0890170792799357E-011 + 145.55359999999999 1.9616659415287865E-011 + 151.43396000000001 1.8444519687436268E-011 + 157.55189999999999 1.7364504962686349E-011 + 163.91699000000000 1.6368289658158696E-011 + 170.53924000000001 1.5448354644830361E-011 + 177.42902000000001 1.4597917400578771E-011 + 184.59716000000000 1.3810844104722072E-011 + 192.05488000000000 1.3081592553335565E-011 + 199.81389999999999 1.2405141601367561E-011 + 207.88638000000000 1.1776945459797219E-011 + 216.28498999999999 1.1192880863357955E-011 + 225.02289999999999 1.0649206747803399E-011 + 234.11383000000001 1.0142524046928303E-011 + 243.57203000000001 9.6697440056861121E-012 + 253.41234000000000 9.2280553832457931E-012 + 263.65019999999998 8.8148980034579494E-012 + 274.30166000000003 8.4279387996075459E-012 + 285.38344999999998 8.0650482906622494E-012 + 296.91293999999999 7.7242833523534219E-012 + 308.90823000000000 7.4038675178755780E-012 + 321.38812000000001 7.1021769571817967E-012 + 334.37220000000002 6.8177247317838258E-012 + 347.88083999999998 6.5491492274878016E-012 + 361.93522000000002 6.2952026998320719E-012 + 376.55739999999997 6.0547403892198138E-012 + 391.77032000000003 5.8267120333720584E-012 + 407.59784000000002 5.6101534932722536E-012 + 424.06479999999999 5.4041790417962714E-012 + 441.19702000000001 5.2079752198784723E-012 + 459.02136999999999 5.0207944374417017E-012 + 477.56583999999998 4.8419493641553783E-012 + 496.85950000000003 4.6708089196574999E-012 + 516.93262000000004 4.5067931301187465E-012 + 537.81669999999997 4.3350103125034375E-012 + 559.54449000000000 4.1650647877128398E-012 + 582.15008999999998 4.0022199906156007E-012 + 605.66895999999997 3.8458988079149174E-012 + 630.13797999999997 3.6955799275282834E-012 + 655.59555999999998 3.5507932426035585E-012 + 682.08162000000004 3.4111164729844574E-012 + 709.63770999999997 3.2761712877846989E-012 + 738.30708000000004 3.1456200991730542E-012 + 768.13468000000000 3.0191634079698438E-012 + 799.16732000000002 2.8965366444739648E-012 + 831.45367999999996 2.7775078844133395E-012 + 865.04440999999997 2.6618753227528650E-012 + 899.99221000000000 2.5494649743098607E-012 + 936.35189000000003 2.4401285420523291E-012 + 974.18051000000003 2.3337411277745463E-012 + 1013.5374000000000 2.2301993826574698E-012 + 1054.4843000000001 2.1294193560535412E-012 + 1097.0854999999999 2.0313344485513330E-012 + 1141.4077000000000 1.9358940287028195E-012 + 1187.5206000000001 1.8430604707869154E-012 + 1235.4964000000000 1.7528086174307183E-012 + 1285.4105000000000 1.6651227768555657E-012 + 1337.3411000000001 1.5799959523867731E-012 + 1391.3697000000000 1.4974274427972068E-012 + 1447.5809999999999 1.4174215901675241E-012 + 1506.0633000000000 1.3399858263733937E-012 + 1566.9082000000001 1.2651297928721501E-012 + 1630.2112999999999 1.1928632217994020E-012 + 1696.0717999999999 1.1231953394488761E-012 + 1764.5931000000000 1.0561331741664425E-012 + 1835.8827000000001 9.9168081231061112E-013 + 1910.0524000000000 9.2983842984609447E-013 + 1987.2184999999999 8.7060148211505633E-013 + 2067.5021000000002 8.1395998190553921E-013 + 2151.0291999999999 7.5989808799183736E-013 + 2237.9308000000001 7.0839380412722407E-013 + 2328.3431999999998 6.5941868776680804E-013 + 2422.4083000000001 6.1293772542875806E-013 + 2520.2734999999998 5.6890953121051755E-013 + 2622.0925999999999 5.2728619490771499E-013 + 2728.0250999999998 4.8801396173734828E-013 + 2838.2374000000000 4.5103319374642640E-013 + 2952.9020999999998 4.1627916085350289E-013 + 3072.1994000000000 3.8368217589230718E-013 + 3196.3162000000002 3.5316851866203663E-013 + 3325.4474000000000 3.2466075111523831E-013 + 3459.7955000000002 2.9807852989126127E-013 + 3599.5711999999999 2.7333916905142226E-013 + 3744.9938999999999 2.5035825868342118E-013 + 3896.2917000000002 2.2905035715304517E-013 + 4053.7017999999998 2.0932958189071832E-013 + 4217.4714000000004 1.9111012692213490E-013 + 4387.8572000000004 1.7430691477087417E-013 + 4565.1266999999998 1.5883599405911280E-013 + 4749.5577999999996 1.4461507414226649E-013 + 4941.4399000000003 1.3156386553664597E-013 + 5141.0740999999998 1.1960445593892954E-013 + 5348.7735000000002 1.0866161529690159E-013 + 5564.8639999999996 9.8663021395578856E-014 + 5789.6845000000003 8.9539469901704571E-014 + 6023.5877000000000 8.1225006195797373E-014 + 6266.9405999999999 7.3657029160501952E-014 + 6520.1251000000002 6.6776348749453348E-014 + 6783.5380999999998 6.0527216966835591E-014 + 7057.5929999999998 5.4857289114847534E-014 + 7342.7197999999999 4.9717594313488356E-014 + 7639.3657000000003 4.5062463630043374E-014 + 7947.9961000000003 4.0849431214398112E-014 + 8269.0951000000005 3.7039126944504290E-014 + 8603.1664999999994 3.3595147770735904E-014 + 8950.7345000000005 3.0483923118074751E-014 + 9312.3441000000003 2.7674573888566115E-014 + 9688.5627999999997 2.5138756108691086E-014 + 10079.981000000000 2.2850514290316272E-014 + 10487.212000000000 2.0786133585866365E-014 + 10910.895000000000 1.8923977856640371E-014 + 11351.696000000000 1.7244346290321227E-014 + 11810.304000000000 1.5729347235479436E-014 + 12287.440000000001 1.4362730528210602E-014 + 12783.852999999999 1.3129776245284544E-014 + 13300.321000000000 1.2017167368127060E-014 + 13837.654000000000 1.1012866596426995E-014 + 14396.695000000000 1.0106006572840395E-014 + 14978.321000000000 9.2867867341240056E-015 + 15583.445000000000 8.5463758174280703E-015 + 16213.017000000000 7.8768230343847488E-015 + 16868.022000000001 7.2709782203031616E-015 + 17549.491000000002 6.7224065125122176E-015 + 18258.490000000002 6.2253299982360160E-015 + 18996.133000000002 5.7745540290743498E-015 + 19763.577000000001 5.3654142688988730E-015 + 20562.025000000001 4.9937221940735513E-015 + 21392.731000000000 4.6557154134006144E-015 + 22256.996999999999 4.3480161615777856E-015 + 23156.180000000000 4.0675896048309341E-015 + 24091.689999999999 3.8117096112415683E-015 + 25064.993999999999 3.5779257644432805E-015 + 26077.619999999999 3.3640340249452290E-015 + 27131.155999999999 3.1680514581870478E-015 + 28227.254000000001 2.9881923819981091E-015 + 29367.634999999998 2.8228470667151590E-015 + 30554.088000000000 2.6705636121978543E-015 + 31788.473000000002 2.5300310463776182E-015 + 33072.726999999999 2.4000640310196475E-015 + 34408.864999999998 2.2795898796367450E-015 + 35798.983999999997 2.3913811981261564E-015 + 37245.262999999999 2.2452778320345745E-015 + 38749.970999999998 2.1116445392284188E-015 + 40315.470000000001 1.9889073395881336E-015 + 41944.214999999997 1.8756682859287949E-015 + 43638.760999999999 1.7706845196908967E-015 + 45401.767000000000 1.6728509691286447E-015 + 47235.999000000003 1.5811860493936842E-015 + 49144.332999999999 1.4948199595382982E-015 + 51129.764000000003 1.4129850420333424E-015 + 53195.406999999999 1.3350085506505829E-015 + 55344.500999999997 1.2603069468879770E-015 + 57580.419000000002 1.1883813989582614E-015 + 59906.667999999998 1.1188146994378623E-015 + 62326.896999999997 1.0512686000772998E-015 + 64844.904000000002 9.8548153797691524E-016 + 67464.638000000006 9.2126644028569005E-016 + 70190.209000000003 8.5850787903785407E-016 + 73025.894000000000 7.9715854536744735E-016 + 75976.139999999999 7.3723465610053916E-016 + 79045.576000000001 6.7880979188701792E-016 + 82239.017000000007 6.2200738173102105E-016 + 85561.472999999998 1.0000000000000001E-030 diff --git a/python/ctem/tests/run_and_reprocess/ctem.in b/python/ctem/tests/run_and_reprocess/ctem.in new file mode 100755 index 00000000..f81032f8 --- /dev/null +++ b/python/ctem/tests/run_and_reprocess/ctem.in @@ -0,0 +1,72 @@ +! CTEM Input file + + +! 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 25.425 ! 1km crater ! Diameter of test impactor (m) +testvel 15.0e3 ! Velocity of test crater (m/s) +testang 90.0 ! Impact angle of test crater (deg) - Default 90.0 +testxoffset 0.0e0 ! x-axis offset of crater center from grid center (m) - Default 0.0 +testyoffset 0.0e0 ! y-axis offset of crater center from grid center (m) - Default 0.0 +tallyonly F ! Tally the craters without generating any craters +testtally F + + + +! IDL driver in uts +interval 1.0 +numintervals 1 ! Total number of intervals +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 +saveshaded T ! 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 (large file size) +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 intervals + ! statistical: surface is reset between intervals + +! CTEM required inputs +seed 33790 ! Random number generator seed +gridsize 1000 ! Size of grid in pixels +numlayers 10 ! Number of perched layers +pix 4.0 ! 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 1.00e0 ! 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 F ! Do ejecta softening - Default T +doangle T ! Vary the impact angle. Set to F to have only vertical impacts - Default T +Kd1 0.0000 +psi 2.000 +fe 10.0 +ejecta_truncation 4.0 +dorays T +superdomain F + diff --git a/python/ctem/tests/run_and_reprocess/ctem_driver.py b/python/ctem/tests/run_and_reprocess/ctem_driver.py new file mode 100644 index 00000000..50392285 --- /dev/null +++ b/python/ctem/tests/run_and_reprocess/ctem_driver.py @@ -0,0 +1,3 @@ +import ctem +sim = ctem.Simulation() +sim.run() \ No newline at end of file diff --git a/python/ctem/tests/run_and_reprocess/lunar-MBA-impactor-velocities.dat b/python/ctem/tests/run_and_reprocess/lunar-MBA-impactor-velocities.dat new file mode 100755 index 00000000..b56ce090 --- /dev/null +++ b/python/ctem/tests/run_and_reprocess/lunar-MBA-impactor-velocities.dat @@ -0,0 +1,64 @@ +6000 41.000000 0.002861 +7000 200.000000 0.016817 +8000 541.000000 0.054567 +9000 793.000000 0.109902 +10000 822.000000 0.167260 +11000 974.000000 0.235224 +12000 978.000000 0.303468 +13000 973.000000 0.371363 +14000 901.000000 0.434233 +15000 1034.000000 0.506385 +16000 1036.000000 0.578676 +17000 934.000000 0.643849 +18000 784.000000 0.698556 +19000 644.000000 0.743493 +20000 467.000000 0.776080 +21000 356.000000 0.800921 +22000 285.000000 0.820808 +23000 239.000000 0.837485 +24000 232.000000 0.853674 +25000 319.000000 0.875933 +26000 368.000000 0.901612 +27000 240.000000 0.918359 +28000 162.000000 0.929663 +29000 132.000000 0.938874 +30000 84.000000 0.944735 +31000 82.000000 0.950457 +32000 83.000000 0.956249 +33000 79.000000 0.961761 +34000 81.000000 0.967413 +35000 50.000000 0.970902 +36000 63.000000 0.975298 +37000 66.000000 0.979904 +38000 43.000000 0.982904 +39000 41.000000 0.985765 +40000 44.000000 0.988835 +41000 28.000000 0.990789 +42000 37.000000 0.993371 +43000 19.000000 0.994697 +44000 20.000000 0.996092 +45000 19.000000 0.997418 +46000 5.000000 0.997767 +47000 10.000000 0.998465 +48000 5.000000 0.998814 +49000 3.000000 0.999023 +50000 2.000000 0.999163 +51000 1.000000 0.999232 +52000 0.000000 0.999232 +53000 1.000000 0.999302 +54000 0.000000 0.999302 +55000 1.000000 0.999372 +56000 1.000000 0.999442 +57000 1.000000 0.999512 +58000 0.000000 0.999512 +59000 0.000000 0.999512 +60000 1.000000 0.999581 +61000 0.000000 0.999581 +62000 1.000000 0.999651 +63000 1.000000 0.999721 +64000 0.000000 0.999721 +65000 1.000000 0.999791 +66000 2.000000 0.999930 +67000 0.000000 0.999930 +68000 0.000000 0.999930 +69000 1.000000 1.000000 From 923163215ccf77c99a54bf12ccc4e0d3a58092ee Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 24 Feb 2022 10:08:38 -0500 Subject: [PATCH 27/32] Improved robustness of the Python driver. Separated pre and post-processing steps more thoroughly so that dedicated scripts can be written to do those tasks independently --- python/ctem/ctem/driver.py | 149 +++++++++++------- python/ctem/ctem/util.py | 36 ++++- python/ctem/ctem/viewer3d.py | 1 + .../tests/run_and_reprocess/ctem_cleanup.py | 6 + .../ctem_compute_one_interval.py | 7 + .../tests/run_and_reprocess/ctem_driver.py | 4 + .../run_and_reprocess/ctem_postprocess.py | 10 ++ .../run_and_reprocess/ctem_preprocess.py | 5 + 8 files changed, 156 insertions(+), 62 deletions(-) create mode 100644 python/ctem/tests/run_and_reprocess/ctem_cleanup.py create mode 100644 python/ctem/tests/run_and_reprocess/ctem_compute_one_interval.py create mode 100644 python/ctem/tests/run_and_reprocess/ctem_postprocess.py create mode 100644 python/ctem/tests/run_and_reprocess/ctem_preprocess.py diff --git a/python/ctem/ctem/driver.py b/python/ctem/ctem/driver.py index e81571e0..32c7f4be 100644 --- a/python/ctem/ctem/driver.py +++ b/python/ctem/ctem/driver.py @@ -43,7 +43,9 @@ def __init__(self, param_file="ctem.in", isnew=True): 'sfdfile': 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', @@ -59,8 +61,12 @@ def __init__(self, param_file="ctem.in", isnew=True): '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' } - + for k, v in self.output_filenames.items(): self.output_filenames[k] = os.path.join(currentdir, v) @@ -79,23 +85,25 @@ def __init__(self, param_file="ctem.in", isnew=True): self.ph1 = util.read_formatted_ascii(sfdfile, skip_lines=0) - # Starting new or old run? - if (self.user['restart'].upper() == 'F' and isnew): - print('Starting a new run') + # 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) - # Delete any old output files - for k, v in self.output_filenames.items(): - if os.path.isfile(v): - os.remove(v) + util.create_dir_structure(self.user) + # 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() - - util.write_datfile(self.user, self.output_filenames['dat'], self.seedarr) - else: - print('Continuing a previous run') - self.process_interval(isnew=False) + # Scale the production function to the simulation domain + self.scale_production() + + util.write_datfile(self.user, self.output_filenames['dat'], self.seedarr) + else: + print('Continuing a previous run') + self.read_output() return @@ -136,31 +144,16 @@ def run(self): #Execute Fortran code self.compute_one_interval() - # Process output files - self.process_interval() - - # 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') + # Read in output files + self.read_output() - # Display results - print(self.user['ncount'], ' Displaying results') - - # Write surface dem, surface ejecta, shaded relief, and rplot 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['savepres'].upper() == 'T'): - util.create_rplot(self.user, self.odist, self.pdist, self.tdist, self.ph1) + # Process the o utput files + self.process_output() # Update ncount self.user['ncount'] = self.user['ncount'] + 1 - if ((self.user['runtype'].upper() == 'STATISTICAL') or (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 @@ -174,7 +167,7 @@ def run(self): else: self.user['restart'] = 'T' - # Write ctem.dat file + # Write ctem.dat file for next interval util.write_datfile(self.user, self.output_filenames['dat'], self.seedarr) return @@ -196,7 +189,7 @@ def compute_one_interval(self): return - def process_interval(self, isnew=True): + 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. @@ -214,25 +207,50 @@ def process_interval(self, isnew=True): self.pdist = util.read_formatted_ascii(self.output_filenames['pdist'], skip_lines=1) # Read impact mass from file - impact_mass = util.read_impact_mass(self.output_filenames['impmass']) + 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') - # Save copy of crater distribution files - # Update user: mass, curyear, regolith properties - self.user['masstot'] = self.user['masstot'] + 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) + # Write surface dem, surface ejecta, shaded relief, and rplot 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 + if (self.user['savepres'].upper() == 'T'): + util.create_rplot(self.user, self.odist, self.pdist, self.tdist, self.ph1) + + # 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') + def redirect_outputs(self, filekeys, foldername): @@ -253,6 +271,29 @@ def redirect_outputs(self, filekeys, foldername): 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) + for key, filename in self.output_filenames.items(): + print(f"Deleting file {filename}") + try: + os.remove(filename) + except OSError as error: + print(error) + # Delete scaled production file + prodfile = self.user['sfdfile'] + print(f"Deleting file {prodfile}") + try: + os.remove(prodfile) + except OSError as error: + print(error) + + return if __name__ == '__main__': sim = Simulation() diff --git a/python/ctem/ctem/util.py b/python/ctem/ctem/util.py index d0d383e5..7d363f2f 100644 --- a/python/ctem/ctem/util.py +++ b/python/ctem/ctem/util.py @@ -8,17 +8,33 @@ # Set pixel scaling common for image writing, at 1 pixel/ array element dpi = 72.0 +# These are directories that are created by CTEM in order to store intermediate results +directories = ['dist', 'misc', 'rego', 'rplot', 'surf', 'shaded'] + def create_dir_structure(user): - # Create directories for various output files if they do not already exist - directories = ['dist', 'misc', 'rego', 'rplot', 'surf', 'shaded'] - - for directory in directories: - dir_test = os.path.join(user['workingdir'], directory) - if not os.path.isdir(dir_test): - os.makedirs(dir_test) + """ + 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): + """ + 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 create_rplot(user, odist, pdist, tdist, ph1): # Parameters: empirical saturation limit and dfrac @@ -239,7 +255,11 @@ def read_datfile(user, datfile, seedarr): def read_formatted_ascii(filename, skip_lines): # Generalized ascii text reader # For use with sfdcompare, production, odist, tdist, pdist data files - data = np.genfromtxt(filename, skip_header=skip_lines) + try: + data = np.genfromtxt(filename, skip_header=skip_lines) + except: + print(f"Error reading {filename}") + data = None return data diff --git a/python/ctem/ctem/viewer3d.py b/python/ctem/ctem/viewer3d.py index e3d66cb7..b7c3267d 100644 --- a/python/ctem/ctem/viewer3d.py +++ b/python/ctem/ctem/viewer3d.py @@ -6,6 +6,7 @@ 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(isnew=False) #used for Open3d module self.mesh = open3d.geometry.TriangleMesh() return diff --git a/python/ctem/tests/run_and_reprocess/ctem_cleanup.py b/python/ctem/tests/run_and_reprocess/ctem_cleanup.py new file mode 100644 index 00000000..d9de5e24 --- /dev/null +++ b/python/ctem/tests/run_and_reprocess/ctem_cleanup.py @@ -0,0 +1,6 @@ +""" +Deletes all output generated by a previous simulation +""" +import ctem +sim = ctem.Simulation(isnew=False) +sim.cleanup() \ No newline at end of file diff --git a/python/ctem/tests/run_and_reprocess/ctem_compute_one_interval.py b/python/ctem/tests/run_and_reprocess/ctem_compute_one_interval.py new file mode 100644 index 00000000..fe9ecb39 --- /dev/null +++ b/python/ctem/tests/run_and_reprocess/ctem_compute_one_interval.py @@ -0,0 +1,7 @@ +""" +This is an example of a standalone script. Files must be generated by a preprocessing script (this is an atypical useage +and is only here for testing purposes). +""" +import ctem +sim = ctem.Simulation(isnew=False) +sim.compute_one_interval() \ No newline at end of file diff --git a/python/ctem/tests/run_and_reprocess/ctem_driver.py b/python/ctem/tests/run_and_reprocess/ctem_driver.py index 50392285..04b5970d 100644 --- a/python/ctem/tests/run_and_reprocess/ctem_driver.py +++ b/python/ctem/tests/run_and_reprocess/ctem_driver.py @@ -1,3 +1,7 @@ +""" +This is an example of a standard "driver" script. This will read in the input files, pre-process them for the main +Fortran code and post-process them. +""" import ctem sim = ctem.Simulation() sim.run() \ No newline at end of file diff --git a/python/ctem/tests/run_and_reprocess/ctem_postprocess.py b/python/ctem/tests/run_and_reprocess/ctem_postprocess.py new file mode 100644 index 00000000..5d56dac5 --- /dev/null +++ b/python/ctem/tests/run_and_reprocess/ctem_postprocess.py @@ -0,0 +1,10 @@ +""" +This is an example of a post-processing script. This will read in the input and output files and process them like as in +a typical CTEM simulation + +""" +import ctem +sim = ctem.Simulation(isnew=False) +sim.read_output() +sim.user['ncount'] += 1 +sim.process_output() \ No newline at end of file diff --git a/python/ctem/tests/run_and_reprocess/ctem_preprocess.py b/python/ctem/tests/run_and_reprocess/ctem_preprocess.py new file mode 100644 index 00000000..4f982486 --- /dev/null +++ b/python/ctem/tests/run_and_reprocess/ctem_preprocess.py @@ -0,0 +1,5 @@ +""" +This is an example of a pre-processing script. This will read in the input files, but won't execute a simulation. +""" +import ctem +sim = ctem.Simulation() \ No newline at end of file From 2b9e3a6665306fe9dbcfe497ca55994f0bd994b1 Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 24 Feb 2022 10:10:50 -0500 Subject: [PATCH 28/32] Added a helpful comment --- python/ctem/tests/run_and_reprocess/ctem_postprocess.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ctem/tests/run_and_reprocess/ctem_postprocess.py b/python/ctem/tests/run_and_reprocess/ctem_postprocess.py index 5d56dac5..641b1dfb 100644 --- a/python/ctem/tests/run_and_reprocess/ctem_postprocess.py +++ b/python/ctem/tests/run_and_reprocess/ctem_postprocess.py @@ -6,5 +6,5 @@ import ctem sim = ctem.Simulation(isnew=False) sim.read_output() -sim.user['ncount'] += 1 +sim.user['ncount'] += 1 # Increment the output count in the situation in which the simulation was run outside of the driver script sim.process_output() \ No newline at end of file From 4698626c5fb2ec9d84f56c85a25fa5149d47f0f0 Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 24 Feb 2022 10:58:57 -0500 Subject: [PATCH 29/32] Improved exception handling for the main Fortran code. Python driver should now halt if there was an error encountered in the Fortran code --- python/ctem/ctem/driver.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/python/ctem/ctem/driver.py b/python/ctem/ctem/driver.py index 32c7f4be..401a29b1 100644 --- a/python/ctem/ctem/driver.py +++ b/python/ctem/ctem/driver.py @@ -3,6 +3,7 @@ import subprocess import shutil from ctem import util +import sys class Simulation: """ @@ -178,14 +179,21 @@ def compute_one_interval(self): """ # Create crater population and display CTEM progress on screen print(self.user['ncount'], ' Calling FORTRAN routine') - with subprocess.Popen([os.path.join(self.user['workingdir'], 'CTEM')], + try: + p = subprocess.Popen([os.path.join(self.user['workingdir'], 'CTEM')], stdout=subprocess.PIPE, - universal_newlines=True) as p: - try: - for line in p.stdout: + stderr=subprocess.PIPE, + universal_newlines=True) + for line in p.stdout: + print(line, end='') + res = p.communicate() + if p.returncode != 0: + for line in res[1]: print(line, end='') - except: - print("Error executing main CTEM program") + raise Exception ("CTEM Failure") + except: + print("Error executing main CTEM program") + sys.exit() return From 0295dbb3af6aa64dd617d106c8930d22d4f86de0 Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 24 Feb 2022 11:00:27 -0500 Subject: [PATCH 30/32] Changed invalid surface error to a true exception so that the driver can handle it --- src/crater/crater_populate.f90 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/crater/crater_populate.f90 b/src/crater/crater_populate.f90 index 3db1fa06..e60b68ce 100644 --- a/src/crater/crater_populate.f90 +++ b/src/crater/crater_populate.f90 @@ -345,9 +345,8 @@ subroutine crater_populate(user,surf,crater,domain,prod,production_list,vdist,nt hmax = maxval(surf(:,:)%dem) hmin = minval(surf(:,:)%dem) if (any(surf(:,:)%dem /= surf(:,:)%dem)) then - write(*,*) 'Invalid surface elevation detected. Halting.' write(*,*) crater%imp, crater%impvel, crater%xl, crater%yl, crater%sinimpang - exit + error stop "Invalid surface elevation detected. Halting." end if end do ! end crater production loop From fefd820240ae506c8f54be30d7ca58d52384da38 Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 24 Feb 2022 16:58:52 -0500 Subject: [PATCH 31/32] Updated scripts and removed cruft --- python/ctem/ctem/__init__.py | 3 --- python/ctem/ctem/viewer3d.py | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/python/ctem/ctem/__init__.py b/python/ctem/ctem/__init__.py index 165a1bb0..2e8ce2a0 100644 --- a/python/ctem/ctem/__init__.py +++ b/python/ctem/ctem/__init__.py @@ -1,4 +1 @@ -# from ctem.ctem_io_readers import * -# from ctem.ctem_io_writers import * -# from ctem.ctem_driver import * from ctem.driver import * \ No newline at end of file diff --git a/python/ctem/ctem/viewer3d.py b/python/ctem/ctem/viewer3d.py index b7c3267d..a8ae9f64 100644 --- a/python/ctem/ctem/viewer3d.py +++ b/python/ctem/ctem/viewer3d.py @@ -6,7 +6,7 @@ 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(isnew=False) + self.read_output() #used for Open3d module self.mesh = open3d.geometry.TriangleMesh() return From 5c931f110aed09f20faa2ed1e1a3970940053fb1 Mon Sep 17 00:00:00 2001 From: David Minton Date: Thu, 24 Feb 2022 19:16:25 -0500 Subject: [PATCH 32/32] Updated viewer and added a new test case --- .gitignore | 1 + .../morphology_test_cases/complex/ctem.in | 1 - .../morphology_test_cases/transition/CTEM | 1 + .../transition/NPFextrap.dat | 1418 +++++++++++++++++ .../morphology_test_cases/transition/ctem.in | 76 + .../lunar-MBA-impactor-velocities.dat | 64 + python/.idea/.gitignore | 3 - python/ctem/.idea/.gitignore | 3 - python/ctem/ctem/viewer3d.py | 9 +- 9 files changed, 1565 insertions(+), 11 deletions(-) create mode 120000 examples/morphology_test_cases/transition/CTEM create mode 100755 examples/morphology_test_cases/transition/NPFextrap.dat create mode 100755 examples/morphology_test_cases/transition/ctem.in create mode 100755 examples/morphology_test_cases/transition/lunar-MBA-impactor-velocities.dat delete mode 100644 python/.idea/.gitignore delete mode 100644 python/ctem/.idea/.gitignore diff --git a/.gitignore b/.gitignore index f7ab64c6..2453fb1c 100644 --- a/.gitignore +++ b/.gitignore @@ -71,3 +71,4 @@ examples/global-lunar-bombardment/scale.ipynb *.png python/ctem/ctem.egg-info/ +.idea/* diff --git a/examples/morphology_test_cases/complex/ctem.in b/examples/morphology_test_cases/complex/ctem.in index 7bcb9aa0..9f1919d3 100755 --- a/examples/morphology_test_cases/complex/ctem.in +++ b/examples/morphology_test_cases/complex/ctem.in @@ -25,7 +25,6 @@ saveshaded T ! Output shaded relief images saverego F ! 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 (large file size) -sfdcompare LOLASethCraterCatalogv8gt20-binned.dat ! File name for the SFD comparison file used in the console display shadedminh -5000.0 ! Minimum height for shaded relief map (m) (Default - automatic) shadedmaxh 5000.0 ! Maximum height for shaded relief map (m) (Default - automatic) runtype single ! Run type: options are normal / statistical diff --git a/examples/morphology_test_cases/transition/CTEM b/examples/morphology_test_cases/transition/CTEM new file mode 120000 index 00000000..9173fccf --- /dev/null +++ b/examples/morphology_test_cases/transition/CTEM @@ -0,0 +1 @@ +../../../build/src/CTEM \ No newline at end of file diff --git a/examples/morphology_test_cases/transition/NPFextrap.dat b/examples/morphology_test_cases/transition/NPFextrap.dat new file mode 100755 index 00000000..e98391df --- /dev/null +++ b/examples/morphology_test_cases/transition/NPFextrap.dat @@ -0,0 +1,1418 @@ + 1.0000000000000001E-009 16373498665196056. + 1.0200000000000000E-009 15624829133353072. + 1.0404000000000000E-009 14910392118418680. + 1.0612080000000001E-009 14228622356426014. + 1.0824322000000000E-009 13578024968994198. + 1.1040808000000000E-009 12957178207974354. + 1.1261623999999999E-009 12364718530314516. + 1.1486857000000000E-009 11799347079002376. + 1.1716594000000001E-009 11259828517385738. + 1.1950926000000001E-009 10744978582763124. + 1.2189943999999999E-009 10253671176415016. + 1.2433742999999999E-009 9784827283731524.0 + 1.2682417999999999E-009 9337421008741684.0 + 1.2936066000000000E-009 8910472977441879.0 + 1.3194787999999999E-009 8503045296702585.0 + 1.3458682999999999E-009 8114249148673952.0 + 1.3727857000000000E-009 7743228961776817.0 + 1.4002413999999999E-009 7389174104114597.0 + 1.4282461999999999E-009 7051308368799519.0 + 1.4568112000000000E-009 6728890208258190.0 + 1.4859474000000000E-009 6421215521897574.0 + 1.5156663000000001E-009 6127609310508435.0 + 1.5459797000000000E-009 5847426967224776.0 + 1.5768993000000000E-009 5580056424177601.0 + 1.6084372000000000E-009 5324911980228383.0 + 1.6406059999999999E-009 5081432797667148.0 + 1.6734181000000000E-009 4849087118238152.0 + 1.7068865000000000E-009 4627364941332780.0 + 1.7410241999999999E-009 4415781316339177.5 + 1.7758447000000000E-009 4213871971251545.0 + 1.8113615999999999E-009 4021194880969782.5 + 1.8475888000000001E-009 3837328037757316.5 + 1.8845406000000000E-009 3661868141016992.5 + 1.9222313999999999E-009 3494431216318050.5 + 1.9606759999999999E-009 3334650316747248.5 + 1.9998896000000001E-009 3182174901302566.0 + 2.0398873000000000E-009 3036671967025619.5 + 2.0806850999999999E-009 2897821576611301.5 + 2.1222988000000000E-009 2765320229959727.0 + 2.1647448000000000E-009 2638877361348099.5 + 2.2080397000000001E-009 2518216084527946.0 + 2.2522004999999999E-009 2403071976513234.5 + 2.2972445000000000E-009 2293192809795639.5 + 2.3431893999999999E-009 2188337764271766.2 + 2.3900531000000002E-009 2088277363840784.0 + 2.4378541999999999E-009 1992791917069052.2 + 2.4866113000000000E-009 1901672535858309.2 + 2.5363434999999998E-009 1814719612820091.0 + 2.5870704000000000E-009 1731742474774254.8 + 2.6388118000000001E-009 1652559481637765.0 + 2.6915880000000000E-009 1576997126693668.5 + 2.7454198000000002E-009 1504889718623458.0 + 2.8003281999999998E-009 1436079430510044.2 + 2.8563347000000001E-009 1370415533754651.0 + 2.9134614000000000E-009 1307754004857728.0 + 2.9717306999999998E-009 1247957575911645.5 + 3.0311653000000001E-009 1190895391529202.2 + 3.0917886000000001E-009 1136442337305807.5 + 3.1536243999999999E-009 1084479092213053.0 + 3.2166969000000001E-009 1034891852503704.1 + 3.2810308000000000E-009 987571998980541.62 + 3.3466513999999998E-009 942415804458058.00 + 3.4135843999999999E-009 899324359631564.38 + 3.4818560999999998E-009 858203223971718.88 + 3.5514931999999999E-009 818962349229012.12 + 3.6225231000000002E-009 781515712287184.12 + 3.6949736000000000E-009 745781303219183.00 + 3.7688729999999998E-009 711680881369590.50 + 3.8442505000000000E-009 679139634252424.62 + 3.9211355000000002E-009 648086339057709.00 + 3.9995582000000000E-009 618452938978139.88 + 4.0795494000000003E-009 590174494421968.88 + 4.1611404000000001E-009 563189075227060.88 + 4.2443631999999998E-009 537437556193661.94 + 4.3292503999999998E-009 512863527269277.06 + 4.4158355000000001E-009 489413090719507.75 + 4.5041521999999999E-009 467034939488460.38 + 4.5942352000000002E-009 445680024973336.06 + 4.6861198999999999E-009 425301543369721.69 + 4.7798422999999998E-009 405854855741145.12 + 4.8754392000000000E-009 387297347872637.31 + 4.9729479000000000E-009 369588397022663.94 + 5.0724068999999997E-009 352689156962741.94 + 5.1738549999999998E-009 336562638379934.25 + 5.2773320999999999E-009 321173490452837.50 + 5.3828788000000004E-009 306487995360364.31 + 5.4905363999999996E-009 292473991498358.12 + 5.6003471000000003E-009 279100776849566.19 + 5.7123539999999996E-009 266339046656329.31 + 5.8266011000000001E-009 254160833114840.06 + 5.9431331000000001E-009 242539466105880.25 + 6.0619958000000003E-009 231449474398208.41 + 6.1832356999999997E-009 220866571431898.88 + 6.3069004000000003E-009 210767565834604.31 + 6.4330384000000003E-009 201130331399540.56 + 6.5616992000000004E-009 191933751602170.12 + 6.6929332000000002E-009 183157681685953.81 + 6.8267918000000003E-009 174782897833489.59 + 6.9633277000000003E-009 166791039009238.41 + 7.1025941999999997E-009 159164610185338.97 + 7.2446461000000002E-009 151886892107514.00 + 7.3895389999999998E-009 144941945641289.97 + 7.5373297999999992E-009 138314551278590.05 + 7.6880764000000003E-009 131990191714344.11 + 7.8418378999999996E-009 125955011347589.45 + 7.9986746999999999E-009 120195783849702.44 + 8.1586482000000008E-009 114699895257102.41 + 8.3218211999999993E-009 109455302339307.47 + 8.4882576000000007E-009 104450517459128.98 + 8.6580226999999995E-009 99674574428007.266 + 8.8311832000000003E-009 95117006273188.609 + 9.0078069000000000E-009 90767830811786.562 + 9.1879630000000007E-009 86617520797173.422 + 9.3717223000000003E-009 82656979820887.656 + 9.5591567000000001E-009 78877534206942.641 + 9.7503398000000004E-009 75270901460268.844 + 9.9453466000000004E-009 71829179396882.812 + 1.0144254000000000E-008 68544820836225.852 + 1.0347139000000000E-008 65410646497629.273 + 1.0554081000000001E-008 62419790325370.305 + 1.0765163000000000E-008 59565673586258.523 + 1.0980465999999999E-008 56842067973770.125 + 1.1200076000000000E-008 54242986818745.445 + 1.1424077000000000E-008 51762760619395.273 + 1.1652559000000000E-008 49395931268191.195 + 1.1885609999999999E-008 47137330228209.656 + 1.2123322000000000E-008 44982002588342.570 + 1.2365788000000000E-008 42925228016763.523 + 1.2613104000000000E-008 40962492917581.109 + 1.2865366000000001E-008 39089505256454.422 + 1.3122674000000000E-008 37302153815962.242 + 1.3385127000000000E-008 35596535659580.703 + 1.3652830000000000E-008 33968900264402.430 + 1.3925886000000000E-008 32415693637990.871 + 1.4204404000000001E-008 30933501818846.531 + 1.4488492000000000E-008 29519084260541.852 + 1.4778261999999999E-008 28169339086295.105 + 1.5073827000000001E-008 26881312027552.051 + 1.5375304000000001E-008 25652176494844.832 + 1.5682810000000001E-008 24479244642274.449 + 1.5996465999999999E-008 23359944870186.188 + 1.6316394999999999E-008 22291824829480.715 + 1.6642723000000000E-008 21272542674614.992 + 1.6975578000000000E-008 20299865430624.629 + 1.7315088999999998E-008 19371666343646.961 + 1.7661391000000001E-008 18485906643103.184 + 1.8014619000000000E-008 17640647961544.605 + 1.8374910999999999E-008 16834039524188.734 + 1.8742409000000001E-008 16064312451471.598 + 1.9117258000000001E-008 15329778741146.434 + 1.9499602999999998E-008 14628833032189.432 + 1.9889595000000001E-008 13959937509623.682 + 2.0287386999999999E-008 13321626625147.031 + 2.0693133999999998E-008 12712503396493.473 + 2.1106997000000001E-008 12131230494230.133 + 2.1529137000000001E-008 11576536345526.742 + 2.1959720000000000E-008 11047205059657.873 + 2.2398914000000000E-008 10542077919747.137 + 2.2846892999999998E-008 10060046255544.195 + 2.3303830000000000E-008 9600056819862.7637 + 2.3769907000000001E-008 9161098955437.1289 + 2.4245305000000001E-008 8742212689765.9873 + 2.4730211000000002E-008 8342479736439.3154 + 2.5224815000000000E-008 7961024444539.4209 + 2.5729311999999999E-008 7597010341008.1240 + 2.6243898000000001E-008 7249641233953.4287 + 2.6768776000000001E-008 6918155213847.5566 + 2.7304150999999999E-008 6601826537550.0312 + 2.7850234000000000E-008 6299961535648.2812 + 2.8407239000000001E-008 6011898979667.3711 + 2.8975384000000000E-008 5737007988465.2129 + 2.9554892000000001E-008 5474686204565.7217 + 3.0145988999999997E-008 5224359429035.2139 + 3.0748909000000000E-008 4985478284117.9785 + 3.1363887000000002E-008 4757520001567.6973 + 3.1991165000000001E-008 4539984838571.4219 + 3.2630987999999999E-008 4332396536883.7876 + 3.3283608000000003E-008 4134299935039.2305 + 3.3949279999999998E-008 3945261310425.0435 + 3.4628266000000003E-008 3764866228554.6958 + 3.5320830999999998E-008 3592719796758.2207 + 3.6027248000000002E-008 3428444506578.7588 + 3.6747793000000003E-008 3271680693359.0024 + 3.7482749000000002E-008 3122084803976.6665 + 3.8232403999999998E-008 2979329130228.1948 + 3.8997051999999998E-008 2843100901531.3130 + 3.9776993000000001E-008 2713101629103.0752 + 4.0572533000000002E-008 2589046476685.4932 + 4.1383983000000000E-008 2470663794671.9092 + 4.2211663000000003E-008 2357693959398.8506 + 4.3055895999999998E-008 2249889687218.9824 + 4.3917014000000000E-008 2147014667034.8123 + 4.4795355000000002E-008 2048843483433.1084 + 4.5691261999999999E-008 1955161213496.6575 + 4.6605086999999997E-008 1865762527880.5625 + 4.7537189000000001E-008 1780451503931.3225 + 4.8487932000000002E-008 1699041369129.2983 + 4.9457691000000003E-008 1621353576798.9429 + 5.0446845000000002E-008 1547218032532.4575 + 5.1455781999999998E-008 1476472302781.3630 + 5.2484897000000000E-008 1408961431360.2058 + 5.3534595000000003E-008 1344537414557.3447 + 5.4605287000000000E-008 1283059149759.8259 + 5.5697393000000002E-008 1224391937812.7815 + 5.6811340999999998E-008 1168407259997.1379 + 5.7947567999999998E-008 1114982450296.6106 + 5.9106518999999997E-008 1064000485116.6843 + 6.0288649000000002E-008 1015349642963.6342 + 6.1494422000000003E-008 968923318991.95959 + 6.2724311000000003E-008 924619795267.01807 + 6.3978796999999998E-008 882342053288.68738 + 6.5258373000000004E-008 841997429632.64258 + 6.6563539999999999E-008 803497557403.88025 + 6.7894811000000003E-008 766758052921.46326 + 6.9252707000000001E-008 731698453641.91223 + 7.0637761999999997E-008 698241910301.06592 + 7.2050516999999996E-008 666315174928.58032 + 7.3491526999999999E-008 635848274355.08435 + 7.4961357999999994E-008 606774440832.36877 + 7.6460585000000002E-008 579030004685.42468 + 7.7989797000000004E-008 552554160097.28235 + 7.9549593000000000E-008 527288913637.53717 + 8.1140583999999998E-008 503178920665.76013 + 8.2763396000000005E-008 480171327337.28839 + 8.4418663999999995E-008 458215747372.30853 + 8.6107037000000007E-008 437264079007.88422 + 8.7829177999999996E-008 417270408258.57721 + 8.9585762000000003E-008 398190935823.03259 + 9.1377476999999995E-008 379983869073.30249 + 9.3205025999999995E-008 362609313384.73578 + 9.5069127000000000E-008 346029190991.65741 + 9.6970508999999994E-008 330207194295.50470 + 9.8909920000000005E-008 315108639531.97485 + 1.0088812000000000E-007 300700453028.72919 + 1.0290588000000000E-007 286951100304.25635 + 1.0496400000000000E-007 273830398824.25473 + 1.0706327999999999E-007 261309649245.87091 + 1.0920454000000000E-007 249361434541.21716 + 1.1138863000000000E-007 237959519387.66306 + 1.1361640999999999E-007 227078911767.07831 + 1.1588874000000000E-007 216695841161.21136 + 1.1820651000000000E-007 206787558744.98465 + 1.2057063999999999E-007 197332308194.68011 + 1.2298205000000001E-007 188309403334.54932 + 1.2544169000000001E-007 179699059251.88254 + 1.2795052999999999E-007 171482395554.55167 + 1.3050953999999999E-007 163641455843.85178 + 1.3311972999999999E-007 156159039406.35278 + 1.3578212000000000E-007 149018762172.14835 + 1.3849777000000001E-007 142204939962.86777 + 1.4126772000000001E-007 135702706863.71530 + 1.4409307999999999E-007 129497760760.52310 + 1.4697494000000000E-007 123576547597.46860 + 1.4991444000000001E-007 117926073347.71808 + 1.5291272000000000E-007 112533981565.08438 + 1.5597097999999999E-007 107388415907.11580 + 1.5909040000000000E-007 102478137005.01477 + 1.6227221000000001E-007 97792375760.095139 + 1.6551764999999999E-007 93320876904.490311 + 1.6882800000000001E-007 89053833104.851059 + 1.7220455999999999E-007 84981893879.282379 + 1.7564866000000000E-007 81096132302.188889 + 1.7916163000000001E-007 77388057987.848480 + 1.8274486000000001E-007 73849532612.797913 + 1.8639976000000000E-007 70472799448.051804 + 1.9012775000000001E-007 67250472464.319939 + 1.9393031000000000E-007 64175476409.695488 + 1.9780891000000001E-007 61241091364.895897 + 2.0176508999999999E-007 58440873753.760574 + 2.0580038999999999E-007 55768696985.791275 + 2.0991640000000001E-007 53218701612.847710 + 2.1411473000000001E-007 50785303621.508827 + 2.1839703000000000E-007 48463169749.026505 + 2.2276496999999999E-007 46247217340.361671 + 2.2722026999999999E-007 44132587611.583885 + 2.3176467000000001E-007 42114650797.673409 + 2.3639996000000001E-007 40188982118.849129 + 2.4112796000000000E-007 38351361952.392334 + 2.4595051999999998E-007 36597766012.277328 + 2.5086953000000001E-007 34924352727.238846 + 2.5588691999999999E-007 33327455429.419361 + 2.6100465999999998E-007 31803574765.990089 + 2.6622476000000002E-007 30349371365.674057 + 2.7154925000000000E-007 28961663787.900448 + 2.7698024000000001E-007 27637405910.687466 + 2.8251984000000002E-007 26373701261.103699 + 2.8817023999999999E-007 25167777115.559059 + 2.9393364000000001E-007 24016994798.944111 + 2.9981231000000000E-007 22918830970.512638 + 3.0580855999999997E-007 21870878952.293278 + 3.1192473000000001E-007 20870844815.995773 + 3.1816323000000000E-007 19916535721.223831 + 3.2452648999999998E-007 19005863338.361744 + 3.3101702000000000E-007 18136830303.799107 + 3.3763736000000000E-007 17307533417.960754 + 3.4439011000000000E-007 16516155325.650702 + 3.5127791000000000E-007 15760963127.140764 + 3.5830347000000001E-007 15040301278.532799 + 3.6546953999999998E-007 14352591433.729498 + 3.7277893000000002E-007 13696326881.594456 + 3.8023451000000001E-007 13070069494.442820 + 3.8783920000000002E-007 12472447522.296986 + 3.9559598000000000E-007 11902151766.819441 + 4.0350790000000000E-007 11357932171.402477 + 4.1157805999999999E-007 10838596629.491890 + 4.1980962000000000E-007 10343007623.858597 + 4.2820580999999999E-007 9870079223.4984512 + 4.3676993000000002E-007 9418774898.5524960 + 4.4550533000000002E-007 8988106351.1573124 + 4.5441543000000001E-007 8577130255.7068071 + 4.6350374000000000E-007 8184945470.8186483 + 4.7277382000000000E-007 7810692982.6348801 + 4.8222928999999996E-007 7453553427.5187416 + 4.9187388000000002E-007 7112743511.5251446 + 5.0171136000000002E-007 6787517014.6966610 + 5.1174559000000000E-007 6477161319.7870684 + 5.2198050000000003E-007 6180996608.3631239 + 5.3242010999999997E-007 5898373820.7871580 + 5.4306851000000005E-007 5628673863.8338795 + 5.5392987999999997E-007 5371305744.9803934 + 5.6500848000000005E-007 5125705590.5661449 + 5.7630865000000003E-007 4891335416.2200336 + 5.8783482000000000E-007 4667681758.0877953 + 5.9959151999999999E-007 4454254425.1566029 + 6.1158334999999995E-007 4250586013.4730248 + 6.2381500999999999E-007 4056230333.2004013 + 6.3629130999999998E-007 3870761357.1443782 + 6.4901713999999997E-007 3693772799.1979837 + 6.6199748000000004E-007 3524877033.9801593 + 6.7523743000000005E-007 3363703899.4316201 + 6.8874217999999998E-007 3209900309.0552664 + 7.0251701999999996E-007 3063129358.6413770 + 7.1656736000000002E-007 2923069399.7206674 + 7.3089871000000005E-007 2789413577.9710178 + 7.4551668999999998E-007 2661869074.3602333 + 7.6042702000000003E-007 2540156554.5936022 + 7.7563555999999996E-007 2424009247.9907260 + 7.9114827000000001E-007 2313172720.8053265 + 8.0697124000000003E-007 2207404096.8074675 + 8.2311066000000003E-007 2106471745.4751511 + 8.3957287999999996E-007 2010154405.2482915 + 8.5636432999999996E-007 1918241202.4974861 + 8.7349161999999997E-007 1830530625.4059026 + 8.9096145000000005E-007 1746830595.6282666 + 9.0878067999999999E-007 1666957689.9548492 + 9.2695629000000003E-007 1590736949.3339379 + 9.4549542000000000E-007 1518001331.1405859 + 9.6440533000000010E-007 1448591520.6681437 + 9.8369343999999992E-007 1382355431.5699728 + 1.0033673000000000E-006 1319147990.7537870 + 1.0234346999999999E-006 1258830492.3210196 + 1.0439033000000000E-006 1201271392.3003054 + 1.0647814000000000E-006 1146343809.2271917 + 1.0860770000000001E-006 1093927913.9954834 + 1.1077986000000000E-006 1043908507.3660606 + 1.1299546000000000E-006 996176286.85680950 + 1.1525536000000000E-006 950626834.44310856 + 1.1756046999999999E-006 907159876.11715174 + 1.1991168000000000E-006 865680462.29182279 + 1.2230990999999999E-006 826097740.43104613 + 1.2475611000000001E-006 788324832.95741260 + 1.2725124000000000E-006 752278989.66656435 + 1.2979626000000000E-006 717881495.07573700 + 1.3239218000000000E-006 685056808.51713252 + 1.3504003000000001E-006 653732876.48902380 + 1.3774083000000000E-006 623841294.32597458 + 1.4049565000000001E-006 595316448.27911973 + 1.4330556000000000E-006 568095947.99357510 + 1.4617166999999999E-006 542120072.91482520 + 1.4909509999999999E-006 517331948.33869046 + 1.5207701000000001E-006 493677158.38076752 + 1.5511855000000000E-006 471104033.88979679 + 1.5822092000000000E-006 449563058.84410787 + 1.6138532999999999E-006 429007079.48189741 + 1.6461304000000000E-006 409390938.55344498 + 1.6790529999999999E-006 390671759.68748778 + 1.7126340999999999E-006 372808480.38837469 + 1.7468867999999999E-006 355762001.91272759 + 1.7818245000000000E-006 339494989.49936914 + 1.8174609999999999E-006 323971757.16301894 + 1.8538102000000001E-006 309158328.49890012 + 1.8908864000000000E-006 295022229.57686782 + 1.9287040999999999E-006 281532504.44340748 + 1.9672781999999999E-006 268659574.38621789 + 2.0066237999999999E-006 256375247.11991504 + 2.0467562999999999E-006 244652618.30817631 + 2.0876914000000001E-006 233466014.11792561 + 2.1294452000000000E-006 222790911.53514940 + 2.1720341000000002E-006 212603916.32905811 + 2.2154747999999999E-006 202882711.27109835 + 2.2597843000000002E-006 193606006.22004980 + 2.3049799999999998E-006 184753471.74274507 + 2.3510795999999999E-006 176305717.35163444 + 2.3981012000000001E-006 168244230.71487257 + 2.4460632000000001E-006 160551356.33877766 + 2.4949844999999999E-006 153210225.59394935 + 2.5448841999999998E-006 146204768.03206238 + 2.5957817999999998E-006 139519643.32072857 + 2.6476974999999999E-006 133140174.11938395 + 2.7006514000000001E-006 127052415.91807871 + 2.7546645000000000E-006 121243004.17869684 + 2.8097577000000001E-006 115699240.95055012 + 2.8659529000000000E-006 110408950.41497400 + 2.9232720000000001E-006 105360556.20958902 + 2.9817373999999999E-006 100543003.90697807 + 3.0413720999999998E-006 95945732.025454387 + 3.1021996000000000E-006 91558660.330692887 + 3.1642435999999999E-006 87372188.689579099 + 3.2275284000000001E-006 83377146.149690047 + 3.2920789999999998E-006 79564768.593441397 + 3.3579205999999998E-006 75926710.726433173 + 3.4250790000000001E-006 72455002.798176125 + 3.4935805999999998E-006 69142035.336683005 + 3.5634522000000001E-006 65980553.011830956 + 3.6347211999999999E-006 62963629.066042639 + 3.7074157000000001E-006 60084647.650260292 + 3.7815640000000002E-006 57337309.543459058 + 3.8571953000000004E-006 54715590.843328290 + 3.9343391999999996E-006 52213749.695231773 + 4.0130259999999998E-006 49826303.246465102 + 4.0932865000000000E-006 47548022.537930578 + 4.1751521999999997E-006 45373915.228200622 + 4.2586551999999997E-006 43299218.106943920 + 4.3438283000000004E-006 41319384.440037131 + 4.4307049000000002E-006 39430076.813855864 + 4.5193190000000004E-006 37627157.449836500 + 4.6097054000000002E-006 35906675.288457364 + 4.7018995000000001E-006 34264861.766135469 + 4.7959375000000002E-006 32698118.995765790 + 4.8918562000000001E-006 31203015.622155707 + 4.9896933999999996E-006 29776273.231380627 + 5.0894872000000003E-006 28414769.846710719 + 5.1912770000000002E-006 27115518.892308448 + 5.2951024999999997E-006 25875676.652969956 + 5.4010046000000002E-006 24692524.538084690 + 5.5090247000000003E-006 23563471.884270709 + 5.6192051999999997E-006 22486044.588703938 + 5.7315893000000000E-006 21457882.176173091 + 5.8462210000000000E-006 20476732.620486479 + 5.9631455000000000E-006 19540444.275454685 + 6.0824084000000004E-006 18646967.909491993 + 6.2040564999999998E-006 17794345.664688975 + 6.3281377000000004E-006 16980708.214339003 + 6.4547004000000000E-006 16204274.669385515 + 6.5837944000000004E-006 15463342.858892167 + 6.7154702999999997E-006 14756289.655807687 + 6.8497796999999997E-006 14081566.176669700 + 6.9867753000000004E-006 13437694.013588579 + 7.1265107999999997E-006 12823262.615790203 + 7.2690409999999998E-006 12236925.805970181 + 7.4144218999999999E-006 11677398.573602589 + 7.5627103000000001E-006 11143455.857292952 + 7.7139645000000006E-006 10633927.275331518 + 7.8682438000000008E-006 10147696.566777911 + 8.0256086999999997E-006 9683698.4616727829 + 8.1861208000000003E-006 9240916.6891116519 + 8.3498433000000000E-006 8818380.4708922599 + 8.5168401000000005E-006 8415164.8609299120 + 8.6871768999999992E-006 8030385.9205410350 + 8.8609204999999996E-006 7663200.6619232958 + 9.0381389000000008E-006 7312804.9003621889 + 9.2189016999999998E-006 6978430.7400451154 + 9.4032797000000007E-006 6659345.7570849862 + 9.5913453000000004E-006 6354850.6992041664 + 9.7831721999999997E-006 6064278.5343819205 + 9.9788356000000005E-006 5786992.6790467855 + 1.0178412000000000E-005 5522385.9118151022 + 1.0381981000000000E-005 5269876.8367677992 + 1.0589620000000001E-005 5028915.2126645660 + 1.0801413000000000E-005 4798970.1050369870 + 1.1017440999999999E-005 4579540.0007866398 + 1.1237790000000000E-005 4370142.8006480681 + 1.1462545000000001E-005 4170321.0297175515 + 1.1691795999999999E-005 3979635.2350405804 + 1.1925632000000001E-005 3797668.4666920146 + 1.2164145000000001E-005 3624021.8394446643 + 1.2407428000000001E-005 3458315.2988679176 + 1.2655576000000001E-005 3300186.0139632057 + 1.2908687999999999E-005 3149286.4837214323 + 1.3166862000000000E-005 3005286.9024010641 + 1.3430199000000000E-005 2867871.8753652950 + 1.3698803000000000E-005 2736739.9479724532 + 1.3972779000000000E-005 2611603.9931547828 + 1.4252235000000000E-005 2492189.6136763925 + 1.4537279000000000E-005 2378235.8379557426 + 1.4828024999999999E-005 2269492.1153841284 + 1.5124585000000000E-005 2165720.9628725541 + 1.5427077000000000E-005 2066694.4265082360 + 1.5735619000000001E-005 1972195.7853850159 + 1.6050330999999999E-005 1882018.2856032588 + 1.6371338000000001E-005 1795963.9004598274 + 1.6698764000000002E-005 1713844.5889679128 + 1.7032740000000000E-005 1635479.7917542397 + 1.7373393999999999E-005 1560698.5167169769 + 1.7720862000000001E-005 1489336.3818411003 + 1.8075280000000002E-005 1421237.1255185530 + 1.8436784999999998E-005 1356251.9170877561 + 1.8805520999999999E-005 1294237.9695006604 + 1.9181631000000001E-005 1235059.6895512016 + 1.9565263999999999E-005 1178587.1870778245 + 1.9956569000000000E-005 1124696.9509151909 + 2.0355700999999998E-005 1073270.7029168624 + 2.0762815000000002E-005 1024195.9722807186 + 2.1178071000000000E-005 977365.18812400894 + 2.1601632000000001E-005 932675.72676108195 + 2.2033665000000000E-005 890029.58990739926 + 2.2474338000000000E-005 849333.48640435957 + 2.2923825000000001E-005 810498.14363984112 + 2.3382301000000001E-005 773438.58549524425 + 2.3849946999999999E-005 738073.51840637717 + 2.4326946000000002E-005 704325.49457770202 + 2.4813485000000001E-005 672120.58025205252 + 2.5309755000000000E-005 641388.20567062881 + 2.5815950000000001E-005 612061.07615932985 + 2.6332269000000000E-005 584074.90852185700 + 2.6858914999999999E-005 557368.36302855529 + 2.7396093000000001E-005 531883.00439070247 + 2.7944015000000000E-005 507562.93042676145 + 2.8502895000000001E-005 484354.89703530917 + 2.9072952999999999E-005 462208.02280674933 + 2.9654412000000001E-005 441073.80851015908 + 3.0247500000000001E-005 420905.95073286624 + 3.0852450000000000E-005 401660.24962004879 + 3.1469498999999998E-005 383294.54800707957 + 3.2098889000000002E-005 365768.60782600328 + 3.2740867000000000E-005 349044.02689875313 + 3.3395683999999999E-005 333084.18215294968 + 3.4063597999999998E-005 317854.07772982976 + 3.4744869999999998E-005 303320.36798482563 + 3.5439767000000002E-005 289451.21293872269 + 3.6148563000000000E-005 276216.19802248740 + 3.6871534000000001E-005 263586.36344363284 + 3.7608965000000003E-005 251534.01187652227 + 3.8361144000000001E-005 240032.75721127572 + 3.9128366999999999E-005 229057.38518446503 + 3.9910933999999997E-005 218583.86228548523 + 4.0709152999999998E-005 208589.22738368998 + 4.1523336000000001E-005 199051.59639622536 + 4.2353803000000003E-005 189950.06489815947 + 4.3200878999999998E-005 181264.69964266196 + 4.4064896000000001E-005 172976.47288255283 + 4.4946193999999997E-005 165067.21481268876 + 4.5845118000000002E-005 157519.60309820992 + 4.6762019999999999E-005 150317.10563231463 + 4.7697261000000002E-005 143443.93153248174 + 4.8651206000000002E-005 136885.03540384132 + 4.9624230000000000E-005 130626.04059658188 + 5.0616715000000000E-005 124653.23192424838 + 5.1629048999999997E-005 118953.53071920716 + 5.2661629999999999E-005 113514.44359218581 + 5.3714863000000002E-005 108324.05402841966 + 5.4789159999999998E-005 103370.99534595871 + 5.5884943000000002E-005 98644.412311095992 + 5.7002641999999997E-005 94133.948388619712 + 5.8142695000000001E-005 89829.723005431762 + 5.9305548999999997E-005 85722.306283478480 + 6.0491659999999999E-005 81802.699285230250 + 6.1701493000000006E-005 78062.314897604520 + 6.2935523000000004E-005 74492.956605586558 + 6.4194233000000006E-005 71086.806926364516 + 6.5478118000000002E-005 67836.399595407667 + 6.6787680000000003E-005 64734.617071938694 + 6.8123433999999999E-005 61774.660225477834 + 6.9485902000000004E-005 58950.048055397834 + 7.0875620000000004E-005 56254.588485216016 + 7.2293133000000004E-005 53682.376245656778 + 7.3738995999999996E-005 51227.777540072333 + 7.5213775000000006E-005 48885.416028320309 + 7.6718051000000006E-005 46650.155622935745 + 7.8252412000000003E-005 44517.102057208998 + 7.9817460000000003E-005 42481.581505754570 + 8.1413808999999994E-005 40539.133986816698 + 8.3042086000000004E-005 38685.502709762957 + 8.4702926999999999E-005 36916.629383039734 + 8.6396985999999995E-005 35228.635663673311 + 8.8124925999999998E-005 33617.824751977991 + 8.9887424000000002E-005 32080.668007057582 + 9.1685173000000000E-005 30613.796087803417 + 9.3518876000000004E-005 29213.996858227081 + 9.5389254000000006E-005 27878.202032182500 + 9.7297038999999994E-005 26603.486100990729 + 9.9242979000000001E-005 25387.056296952607 + 1.0122784000000000E-004 24226.245826690531 + 1.0325239999999999E-004 23118.511907098316 + 1.0531744000000000E-004 22061.434187145624 + 1.0742379000000001E-004 21052.686268415113 + 1.0957227000000001E-004 20090.061547655005 + 1.1176371000000000E-004 19171.456341886540 + 1.1399899000000000E-004 18294.849481054789 + 1.1627897000000000E-004 17458.327132412986 + 1.1860455000000000E-004 16660.054195544297 + 1.2097664000000001E-004 15898.282375265315 + 1.2339617000000001E-004 15171.342669353615 + 1.2586408999999999E-004 14477.642006433896 + 1.2838138000000000E-004 13815.657428149610 + 1.3094900000000000E-004 13183.945637516810 + 1.3356798000000000E-004 12581.116723967780 + 1.3623933999999999E-004 12005.851759216137 + 1.3896412999999999E-004 11456.889939716984 + 1.4174340999999999E-004 10933.030204674744 + 1.4457827999999999E-004 10433.122897617906 + 1.4746985000000000E-004 9956.0731913299514 + 1.5041923999999999E-004 9500.8380764484391 + 1.5342763000000001E-004 9066.4165742123387 + 1.5649618000000001E-004 8651.8598306724380 + 1.5962610000000001E-004 8256.2585744065291 + 1.6281862999999999E-004 7878.7446204035850 + 1.6607500000000001E-004 7518.4934844581639 + 1.6939650000000000E-004 7174.7143625408125 + 1.7278443000000001E-004 6846.6543581034957 + 1.7624011999999999E-004 6533.5946006210788 + 1.7976491999999999E-004 6234.8496538734908 + 1.8336021999999999E-004 5949.7643415035282 + 1.8702742000000001E-004 5677.7148422901691 + 1.9076797000000000E-004 5418.1042386559257 + 1.9458333000000000E-004 5170.3642617921560 + 1.9847500000000001E-004 4933.9519018229212 + 2.0244450000000001E-004 4708.3495711127734 + 2.0649338999999999E-004 4493.0627871997895 + 2.1062326000000000E-004 4287.6197713872743 + 2.1483571999999999E-004 4091.5708682275231 + 2.1913242999999999E-004 3904.4861478461448 + 2.2351508000000001E-004 3725.9555373309636 + 2.2798539000000001E-004 3555.5878891576617 + 2.3254509000000001E-004 3393.0107901952560 + 2.3719599000000000E-004 3237.8672318796284 + 2.4193991000000001E-004 3089.8174656635324 + 2.4677871000000000E-004 2948.5371523035915 + 2.5171428999999998E-004 2813.7167033104624 + 2.5674857000000000E-004 2685.0611445267027 + 2.6188353999999998E-004 2562.2881823134712 + 2.6712121999999998E-004 2445.1287164017031 + 2.7246364000000001E-004 2333.3265931216993 + 2.7791291000000000E-004 2226.6365271332370 + 2.8347117000000001E-004 2124.8247222291452 + 2.8914058999999999E-004 2027.6682967325241 + 2.9492340999999998E-004 1934.9541131481556 + 3.0082186999999999E-004 1846.4794830622891 + 3.0683830999999999E-004 1762.0501537185794 + 3.1297508000000001E-004 1681.4812979950680 + 3.1923458000000001E-004 1604.5964775505568 + 3.2561926999999998E-004 1531.2271735244158 + 3.3213166000000001E-004 1461.2125763080928 + 3.3877429000000000E-004 1394.3994383564398 + 3.4554977999999998E-004 1330.6412261985129 + 3.5246076999999998E-004 1269.7984105041310 + 3.5950998999999999E-004 1211.7375158246011 + 3.6670019000000002E-004 1156.3314598176823 + 3.7403418999999998E-004 1103.4588443940845 + 3.8151487000000000E-004 1053.0037993354442 + 3.8914517000000000E-004 1004.8557439839823 + 3.9692807000000000E-004 958.90926817138632 + 4.0486663999999997E-004 915.06360504680390 + 4.1296397000000000E-004 873.22282170206813 + 4.2122325000000001E-004 833.29516897294911 + 4.2964771000000000E-004 795.19321177104700 + 4.3824066999999998E-004 758.83340065720188 + 4.4700548000000003E-004 724.13615948878828 + 4.5594559000000000E-004 691.02541664890100 + 4.6506450000000001E-004 659.42865250192358 + 4.7436579000000002E-004 629.27662754348455 + 4.8385311000000001E-004 600.50327555720492 + 4.9353017000000002E-004 573.04558821081014 + 5.0340077000000005E-004 546.84339171685224 + 5.1346878999999998E-004 521.83925698704104 + 5.2373815999999995E-004 497.97844708202007 + 5.3421293000000003E-004 475.20863272687154 + 5.4489719000000002E-004 453.47996756245192 + 5.5579513000000001E-004 432.74484388859719 + 5.6691103000000001E-004 412.95782013318836 + 5.7824924999999995E-004 394.07554406959622 + 5.8981424000000005E-004 376.05664154394248 + 6.0161052000000002E-004 358.86165810382306 + 6.1364272999999997E-004 342.45289987060636 + 6.2591559000000003E-004 326.79441621993942 + 6.3843389999999997E-004 311.85191713956726 + 6.5120257999999999E-004 297.59265167353175 + 6.6422663000000005E-004 283.98538732020444 + 6.7751116000000001E-004 271.00030875774297 + 6.9106139000000004E-004 258.60895752742181 + 7.0488261000000005E-004 246.78420673106629 + 7.1898027000000004E-004 235.50012387696981 + 7.3335987000000004E-004 224.73200967541163 + 7.4802707000000000E-004 214.45625610250985 + 7.6298760999999997E-004 204.65035857094162 + 7.7824736000000000E-004 195.29283091255718 + 7.9381231000000003E-004 186.36316835613906 + 8.0968855000000000E-004 177.84181467609744 + 8.2588232999999999E-004 169.71008776841461 + 8.4239997000000000E-004 161.95018711420093 + 8.5924796999999997E-004 154.54510055106095 + 8.7643292999999998E-004 147.47860765768473 + 8.9396159000000000E-004 140.73522612058639 + 9.1184082000000000E-004 134.30018326835051 + 9.3007764000000001E-004 128.15937752913058 + 9.4867919000000002E-004 122.29935890304898 + 9.6765277000000001E-004 116.70728674919727 + 9.8700582999999994E-004 111.37090681021482 + 1.0067459000000000E-003 106.27854285962243 + 1.0268809000000001E-003 101.41899378289264 + 1.0474185000000000E-003 96.781668078947419 + 1.0683668999999999E-003 92.356371572505694 + 1.0897342000000000E-003 88.133432785485070 + 1.1115289000000000E-003 84.103575515231697 + 1.1337595000000000E-003 80.257980503515171 + 1.1564346000000000E-003 76.588241049170264 + 1.1795632999999999E-003 73.086283225151718 + 1.2031546000000001E-003 69.744447078952007 + 1.2272177000000001E-003 66.555418245317071 + 1.2517620000000000E-003 63.512213566317371 + 1.2767973000000000E-003 60.608144595986715 + 1.3023332000000000E-003 57.836874196360156 + 1.3283799000000001E-003 55.192310302517157 + 1.3549475000000000E-003 52.668671038432279 + 1.3820464000000000E-003 50.260428320124269 + 1.4096874000000001E-003 47.962291133764388 + 1.4378811000000000E-003 45.769244451627792 + 1.4666386999999999E-003 43.676471602128551 + 1.4959715000000000E-003 41.679386419660766 + 1.5258909000000001E-003 39.773620458543157 + 1.5564088000000001E-003 37.954988056748043 + 1.5875368999999999E-003 36.219520481762594 + 1.6192877000000001E-003 34.563399012652916 + 1.6516733999999999E-003 32.983008494777621 + 1.6847069000000001E-003 31.474876533747612 + 1.7184010000000000E-003 30.035706087859037 + 1.7527691000000000E-003 28.662336284402915 + 1.7878244000000001E-003 27.351769142616142 + 1.8235809000000001E-003 26.101123618430815 + 1.8600526000000000E-003 24.907661005447931 + 1.8972536000000000E-003 23.768772972227683 + 1.9351987000000000E-003 22.681957673830212 + 1.9739025999999998E-003 21.644839122059562 + 2.0133807000000002E-003 20.655139183383611 + 2.0536483000000000E-003 19.710694230172933 + 2.0947213000000000E-003 18.809432481785571 + 2.1366156999999999E-003 17.949381685655915 + 2.1793479999999998E-003 17.128655999701149 + 2.2229350000000001E-003 16.345456604863337 + 2.2673937000000002E-003 15.598069281538553 + 2.3127415999999999E-003 14.884855451231967 + 2.3589964000000001E-003 14.204253795047784 + 2.4061763000000000E-003 13.554772205764143 + 2.4542997999999999E-003 12.934987768514379 + 2.5033858000000002E-003 12.343542275133615 + 2.5534536000000000E-003 11.779139443544361 + 2.6045225999999999E-003 11.240545281847178 + 2.6566131000000000E-003 10.726576859973671 + 2.7097453000000001E-003 10.236110382515051 + 2.7639402000000000E-003 9.7680697210320773 + 2.8192191000000000E-003 9.3214291697803997 + 2.8756034000000001E-003 8.8952123706270250 + 2.9331155000000002E-003 8.4884832896086770 + 2.9917778000000000E-003 8.1003519626672364 + 3.0516134000000000E-003 7.7299674072682985 + 3.1126456000000000E-003 7.3765191332292943 + 3.1748985000000000E-003 7.0392317758868712 + 3.2383964999999999E-003 6.7173664937951703 + 3.3031644000000001E-003 6.4102186154783594 + 3.3692277000000001E-003 6.1171147219338406 + 3.4366123000000000E-003 5.8374127147768213 + 3.5053444999999998E-003 5.5705002911118102 + 3.5754514000000000E-003 5.3157920881015999 + 3.6469605000000000E-003 5.0727300810660143 + 3.7198996999999998E-003 4.8407822225644503 + 3.7942977000000001E-003 4.6194400088394785 + 3.8701835999999999E-003 4.4082187127596653 + 3.9475873000000003E-003 4.2066551825077063 + 4.0265390000000000E-003 4.0143082164439088 + 4.1070697999999999E-003 3.8307560609345042 + 4.1892112000000000E-003 3.6555967659571129 + 4.2729954000000001E-003 3.4884465912339926 + 4.3584553000000003E-003 3.3289392381115874 + 4.4456243999999997E-003 3.1767252691340784 + 4.5345369000000003E-003 3.0314711740842135 + 4.6252276999999998E-003 2.8928586727996413 + 4.7177321999999997E-003 2.7605843212152279 + 4.8120869000000000E-003 2.6343579964901789 + 4.9083286000000002E-003 2.5139034221241814 + 5.0064951999999998E-003 2.3989564912028905 + 5.1066250999999997E-003 2.2892654836967314 + 5.2087575999999998E-003 2.1845900369193556 + 5.3129327000000000E-003 2.0847008657056882 + 5.4191914000000004E-003 1.9893789857592377 + 5.5275751999999999E-003 1.8984157110153121 + 5.6381267000000001E-003 1.8116116637319581 + 5.7508893000000000E-003 1.7287766355627836 + 5.8659070000000001E-003 1.6497292989845691 + 5.9832252000000001E-003 1.5742962656613595 + 6.1028897000000000E-003 1.5023124071719436 + 6.2249475000000004E-003 1.4336199668291105 + 6.3494464000000000E-003 1.3680684806020620 + 6.4764354000000001E-003 1.3055142415118048 + 6.6059641000000002E-003 1.2458202994772352 + 6.7380833999999999E-003 1.1888558204819208 + 6.8728449999999998E-003 1.1344960459591205 + 7.0103018999999999E-003 1.0826218165777304 + 7.1505079999999999E-003 1.0331194879160142 + 7.2935181000000002E-003 0.98588066702327803 + 7.4393884999999996E-003 0.94080178566405215 + 7.5881762000000004E-003 0.89778414327704192 + 7.7399397999999998E-003 0.85673342012589626 + 7.8947385999999994E-003 0.81755973839638596 + 8.0526333000000005E-003 0.78017726996665782 + 8.2136859999999996E-003 0.74450407132540453 + 8.3779596999999997E-003 0.71046202200441488 + 8.5455189000000001E-003 0.67797652229419658 + 8.7164293000000000E-003 0.64697640195123329 + 8.8907579000000007E-003 0.61739374723079110 + 9.0685729999999999E-003 0.58916375490534367 + 9.2499444999999993E-003 0.56222454926777399 + 9.4349433999999996E-003 0.53651712898530080 + 9.6236423000000005E-003 0.51198516418139162 + 9.8161150999999999E-003 0.48857491980491274 + 1.0012437000000001E-002 0.46623513528188409 + 1.0212686000000000E-002 0.44491675455937113 + 1.0416940000000000E-002 0.42457314521480627 + 1.0625279000000000E-002 0.40515974557793161 + 1.0837784000000000E-002 0.38663408029013380 + 1.1054540000000000E-002 0.36895541702612150 + 1.1275631000000000E-002 0.35208511174224882 + 1.1501143000000000E-002 0.33598624979032610 + 1.1731165999999999E-002 0.32062344789591679 + 1.1965790000000000E-002 0.30596306990135075 + 1.2205105000000001E-002 0.29197311621767125 + 1.2449207000000000E-002 0.27862280582629312 + 1.2698192000000001E-002 0.26588288341533961 + 1.2952155000000000E-002 0.25372556865646928 + 1.3211199000000000E-002 0.24212406279904539 + 1.3475422000000001E-002 0.23105310831302997 + 1.3744931000000000E-002 0.22048830640289663 + 1.4019830000000000E-002 0.21040658219779360 + 1.4300225999999999E-002 0.20078587286253557 + 1.4586231000000000E-002 0.19160503053986452 + 1.4877955000000000E-002 0.18284401027857561 + 1.5175513999999999E-002 0.17448356772390042 + 1.5479025000000000E-002 0.16650538092873565 + 1.5788605000000001E-002 0.15889202269364919 + 1.6104377000000000E-002 0.15162677156871154 + 1.6426465000000001E-002 0.14469370836805959 + 1.6754993999999999E-002 0.13807767123810727 + 1.7090094000000000E-002 0.13176414085294239 + 1.7431895999999999E-002 0.12573929343627163 + 1.7780534000000001E-002 0.11998992974505628 + 1.8136144000000000E-002 0.11450346406709788 + 1.8498866999999999E-002 0.10926785229966474 + 1.8868844999999999E-002 0.10427162915670114 + 1.9246222000000000E-002 9.9503863062363321E-002 + 1.9631145999999999E-002 9.4954106797128096E-002 + 2.0023769000000000E-002 9.0612379827296058E-002 + 2.0424244000000001E-002 8.6469180684827104E-002 + 2.0832729000000001E-002 8.2515422188434634E-002 + 2.1249384000000000E-002 7.8742444651995577E-002 + 2.1674371000000001E-002 7.5141993754831299E-002 + 2.2107859000000001E-002 7.1706161547957906E-002 + 2.2550015999999999E-002 6.8427436675349312E-002 + 2.3001015999999999E-002 6.5298630616325334E-002 + 2.3461037000000001E-002 6.2312881138150637E-002 + 2.3930257000000000E-002 5.9463662087143557E-002 + 2.4408862999999999E-002 5.6744712988084874E-002 + 2.4897039999999999E-002 5.4150092456364991E-002 + 2.5394981000000000E-002 5.1674107272516742E-002 + 2.5902880000000000E-002 4.9311338945007187E-002 + 2.6420938000000001E-002 4.7056602473489244E-002 + 2.6949357000000000E-002 4.4904963371035084E-002 + 2.7488344000000001E-002 4.2851708281143361E-002 + 2.8038111000000001E-002 4.0892336262560322E-002 + 2.8598873000000000E-002 3.9022556611212483E-002 + 2.9170850000000002E-002 3.7238272318929865E-002 + 2.9754267000000001E-002 3.5535572092807909E-002 + 3.0349352999999999E-002 3.3910725184354645E-002 + 3.0956339999999999E-002 3.2360175432256826E-002 + 3.1575467000000003E-002 3.0880523131259750E-002 + 3.2206975999999998E-002 2.9468528344714199E-002 + 3.2851115000000000E-002 2.8121096586458158E-002 + 3.3508138000000000E-002 2.6835273054267930E-002 + 3.4178300000000002E-002 2.5608245788794195E-002 + 3.4861865999999998E-002 2.4437322349806948E-002 + 3.5559104000000001E-002 2.3319937707785655E-002 + 3.6270285999999999E-002 2.2253646054815338E-002 + 3.6995691999999997E-002 2.1236109527015865E-002 + 3.7735604999999998E-002 2.0265100761680453E-002 + 3.8490318000000003E-002 1.9338488721918529E-002 + 3.9260124000000000E-002 1.8454246994097888E-002 + 4.0045325999999999E-002 1.7610436848660517E-002 + 4.0846233000000003E-002 1.6805208509125601E-002 + 4.1663157999999999E-002 1.6036798964303569E-002 + 4.2496421000000000E-002 1.5303524984133326E-002 + 4.3346348999999999E-002 1.4603779765287841E-002 + 4.4213276000000003E-002 1.3936029675589538E-002 + 4.5097541999999997E-002 1.3298811783992724E-002 + 4.5999492000000003E-002 1.2690731225357922E-002 + 4.6919481999999998E-002 1.2110454181294502E-002 + 4.7857872000000003E-002 1.1556709889269892E-002 + 4.8815029000000003E-002 1.1028285701586156E-002 + 4.9791330000000002E-002 1.0524022984196546E-002 + 5.0787156999999999E-002 1.0042817434779193E-002 + 5.1802899999999999E-002 9.5836150019858683E-003 + 5.2838957999999998E-002 9.1454092949484790E-003 + 5.3895736999999999E-002 8.7272403727407643E-003 + 5.4973651999999998E-002 8.3281918480295827E-003 + 5.6073125000000001E-002 7.9473897114159184E-003 + 5.7194586999999998E-002 7.5839996939896194E-003 + 5.8338478999999999E-002 7.2372252589365579E-003 + 5.9505247999999997E-002 6.9063071362134047E-003 + 6.0695353000000000E-002 6.5905198996111438E-003 + 6.1909260000000001E-002 6.2891718912211131E-003 + 6.3147445999999996E-002 6.0016026666124779E-003 + 6.4410394999999995E-002 5.7271825549078349E-003 + 6.5698601999999995E-002 5.4653103507859195E-003 + 6.7012575000000005E-002 5.2154117605065871E-003 + 6.8352826000000005E-002 4.9769399134100556E-003 + 6.9719882999999996E-002 4.7493719014593400E-003 + 7.1114280000000002E-002 4.5322094926857652E-003 + 7.2536565999999997E-002 4.3249765639462086E-003 + 7.3987296999999994E-002 4.1272193494821408E-003 + 7.5467042999999998E-002 3.9385044288789148E-003 + 7.6976383999999995E-002 3.7584183891924239E-003 + 7.8515911999999993E-002 3.6022923901546607E-003 + 8.0086229999999994E-002 3.4312226207997448E-003 + 8.1687953999999993E-002 3.2692767414769096E-003 + 8.3321714000000005E-002 3.1158494908371383E-003 + 8.4988147999999999E-002 2.9703864529170964E-003 + 8.6687911000000006E-002 2.8323783456352821E-003 + 8.8421668999999994E-002 2.7013572414019589E-003 + 9.0190101999999994E-002 2.5768924155658555E-003 + 9.1993904000000001E-002 2.4585868899378942E-003 + 9.3833782000000004E-002 2.3460743772041044E-003 + 9.5710457999999998E-002 2.2390163545490840E-003 + 9.7624666999999998E-002 2.1370996669088666E-003 + 9.9577160999999997E-002 2.0400340514368045E-003 + 0.10156870000000000 1.9475505385187220E-003 + 0.10360008000000000 1.8593983413995490E-003 + 0.10567208000000000 1.7753455727625407E-003 + 0.10778552000000000 1.6951751804403542E-003 + 0.10994123000000000 1.6186849907224247E-003 + 0.11214006000000000 1.5456860881903436E-003 + 0.11438286000000000 1.4760023440242560E-003 + 0.11667051000000001 1.4094684066654184E-003 + 0.11900392000000000 1.3459289274486048E-003 + 0.12138400000000001 1.2852385829002393E-003 + 0.12381167999999999 1.2272607135139098E-003 + 0.12628792000000000 1.1718664511931147E-003 + 0.12881368000000001 1.1189347945696182E-003 + 0.13138995000000001 1.0683513525400652E-003 + 0.13401774999999999 1.0200079120643857E-003 + 0.13669809999999999 9.7380253343640731E-004 + 0.13943206000000000 9.2963839340060115E-004 + 0.14222071000000000 8.8742379783392558E-004 + 0.14506511999999999 8.4707223594697630E-004 + 0.14796641999999999 8.0850102094817287E-004 + 0.15092575000000000 7.7163177140573275E-004 + 0.15394426999999999 7.3638997871478169E-004 + 0.15702315000000000 7.0270486034572138E-004 + 0.16016361000000001 6.7050869799272644E-004 + 0.16336688999999999 6.3973700224614330E-004 + 0.16663422000000000 6.1032857068573038E-004 + 0.16996691000000000 5.8222448460980715E-004 + 0.17336625000000000 5.5536886846663117E-004 + 0.17683357000000000 5.2970819578543012E-004 + 0.18037023999999999 5.0519119375514745E-004 + 0.18397764999999999 4.8176887581484088E-004 + 0.18765720000000000 4.5939447056862884E-004 + 0.19141035000000001 4.3802300797355341E-004 + 0.19523855000000001 4.1761164308140933E-004 + 0.19914332000000001 3.9811911209959409E-004 + 0.20312619000000001 3.7950598739073713E-004 + 0.20718871000000000 3.6173452482926675E-004 + 0.21133249000000001 3.4476841875036155E-004 + 0.21555914000000001 3.2857299517820217E-004 + 0.21987032000000001 3.1311493426204698E-004 + 0.22426773000000000 2.9836226483885103E-004 + 0.22875308000000000 2.8428440631552798E-004 + 0.23332813999999999 2.7085194914668525E-004 + 0.23799471000000000 2.5803670987304441E-004 + 0.24275459999999999 2.4581172768853592E-004 + 0.24760968999999999 2.3415105893045062E-004 + 0.25256189000000001 2.2302984856593586E-004 + 0.25761311999999997 2.1242432380356169E-004 + 0.26276538999999999 2.0231158459034257E-004 + 0.26802069000000001 1.9266979537351951E-004 + 0.27338110999999998 1.8347791410466458E-004 + 0.27884872999999999 1.7471586345250523E-004 + 0.28442570000000000 1.6636435462571839E-004 + 0.29011421999999998 1.5840489812491947E-004 + 0.29591650000000003 1.5081982721019420E-004 + 0.30183483000000000 1.4359217184703056E-004 + 0.30787153000000000 1.3670570105455112E-004 + 0.31402896000000002 1.3014487962213775E-004 + 0.32030954000000000 1.2389482107831142E-004 + 0.32671572999999998 1.1794128528848531E-004 + 0.33325004000000003 1.1227064347966266E-004 + 0.33991505000000000 1.0686983986372273E-004 + 0.34671334999999998 1.0172641843476733E-004 + 0.35364761000000000 9.6828443111989703E-005 + 0.36072057000000002 9.2164490407483672E-005 + 0.36793498000000002 8.7723668450142203E-005 + 0.37529368000000002 8.3495543838788171E-005 + 0.38279954999999999 7.9470155823599205E-005 + 0.39045553999999999 7.5637980636287269E-005 + 0.39826465000000000 7.1989925113976138E-005 + 0.40622994000000001 6.8517304163223913E-005 + 0.41435453999999999 6.5211820616685806E-005 + 0.42264162999999999 6.2065558015812156E-005 + 0.43109447000000001 5.9070953554498873E-005 + 0.43971635999999997 5.6220798193003670E-005 + 0.44851067999999999 5.3508207777286272E-005 + 0.45748090000000002 5.0926608275832156E-005 + 0.46663051999999999 4.8469740289257595E-005 + 0.47596313000000001 4.6131628274601184E-005 + 0.48548238999999999 4.3906574661578607E-005 + 0.49519204000000000 4.1789145907399948E-005 + 0.50509588000000005 3.9774165616429312E-005 + 0.51519778999999999 3.7856698982543942E-005 + 0.52550174999999999 3.6032039261292469E-005 + 0.53601178000000005 3.4295708608746228E-005 + 0.54673201999999999 3.2643434299722012E-005 + 0.55766665999999998 3.1071151297384975E-005 + 0.56881999000000005 2.9574985244511821E-005 + 0.58019639000000001 2.8151245921697637E-005 + 0.59180032000000005 2.6796420350683046E-005 + 0.60363633000000005 2.5507163561611956E-005 + 0.61570906000000003 2.4280291103886423E-005 + 0.62802323999999998 2.3112771794102293E-005 + 0.64058369999999998 2.2001719866302217E-005 + 0.65339537000000003 2.0944388517727065E-005 + 0.66646327999999999 1.9938163654314873E-005 + 0.67979255000000005 1.8980558530682307E-005 + 0.69338840000000002 1.8069207033326317E-005 + 0.70725616999999996 1.7201856875192841E-005 + 0.72140128999999997 1.6376366311965109E-005 + 0.73582932000000001 1.5590696617540340E-005 + 0.75054589999999999 1.4842910078118326E-005 + 0.76555682000000003 1.4131161615913417E-005 + 0.78086796000000003 1.3453697522968135E-005 + 0.79648532000000005 1.2808849637618633E-005 + 0.81241501999999999 1.2195031346478809E-005 + 0.82866331999999998 1.1610733050584085E-005 + 0.84523658999999995 1.1054519666761100E-005 + 0.86214131999999999 1.0525026639626276E-005 + 0.87938415000000003 1.0020955679207626E-005 + 0.89697183000000003 9.5410728277409563E-006 + 0.91491127000000005 9.0842039817177521E-006 + 0.93320948999999997 8.6492333594888504E-006 + 0.95187368000000006 8.2350992297271437E-006 + 0.97091116000000000 7.8407923076613850E-006 + 0.99032938000000004 7.4653531495942172E-006 + 1.0101359999999999 7.1078682725896258E-006 + 1.0303386999999999 6.7674713418441464E-006 + 1.0509455000000001 6.4433353988246167E-006 + 1.0719643999999999 6.1346769090525625E-006 + 1.0934037000000001 5.8407486592846609E-006 + 1.1152717000000001 5.5608422672354001E-006 + 1.1375772000000000 5.2942799273487192E-006 + 1.1603287000000000 5.0404226807096867E-006 + 1.1835353000000000 4.7986579513811851E-006 + 1.2072060000000000 4.5684061438820748E-006 + 1.2313501000000000 4.3491147343732399E-006 + 1.2559771000000000 4.1402581002204751E-006 + 1.2810967000000000 3.9413362423637700E-006 + 1.3067186000000000 3.7518749861046138E-006 + 1.3328530000000001 3.5714209910923866E-006 + 1.3595100000000000 3.3995450844682388E-006 + 1.3867001999999999 3.2358370349092847E-006 + 1.4144342000000001 3.0799078641003735E-006 + 1.4427228999999999 2.9313869466316141E-006 + 1.4715773999999999 2.7899217281040942E-006 + 1.5010089000000000 2.6551772670741961E-006 + 1.5310291000000000 2.5268335737272809E-006 + 1.5616497000000000 2.4045871515327654E-006 + 1.5928827000000001 2.2881488476716760E-006 + 1.6247403000000000 2.1772435682696184E-006 + 1.6572351000000001 2.0716089373280299E-006 + 1.6903798000000001 1.9709957016289277E-006 + 1.7241873999999999 1.8751664189881942E-006 + 1.7586712000000000 1.7838949276976497E-006 + 1.7938445999999999 1.6969663077896142E-006 + 1.8297215000000000 1.6141753381465933E-006 + 1.8663159000000000 1.5353270155298157E-006 + 1.9036422000000000 1.4602353699085672E-006 + 1.9417150999999999 1.3887232860848904E-006 + 1.9805493999999999 1.3206224198964781E-006 + 2.0201604000000000 1.2557720535892756E-006 + 2.0605636000000001 1.1940192700385869E-006 + 2.1017747999999998 1.1352183991058157E-006 + 2.1438103000000002 1.0792304109036189E-006 + 2.1866865000000000 1.0259231517799499E-006 + 2.2304203000000000 9.7517048822484287E-007 + 2.2750287000000000 9.2685249717953427E-007 + 2.3205293000000000 8.8085461291098330E-007 + 2.3669397999999999 8.3706790542262777E-007 + 2.4142785999999998 7.9538823828433185E-007 + 2.4625642000000001 7.5571660682439918E-007 + 2.5118155000000000 7.1795860941770322E-007 + 2.5620517999999999 6.8202424150909173E-007 + 2.6132928000000000 6.4782769436210918E-007 + 2.6655587000000001 6.1528710290604083E-007 + 2.7188699000000001 5.8432454887356018E-007 + 2.7732473000000000 5.5486568620602606E-007 + 2.8287122000000000 5.2683963973580946E-007 + 2.8852864999999999 5.0017875135318330E-007 + 2.9429921999999999 4.7481866724102401E-007 + 3.0018520000000000 4.5069790456179084E-007 + 3.0618891000000001 4.2775782591244413E-007 + 3.1231268999999999 4.0594261569374603E-007 + 3.1855894000000000 3.8519899551149661E-007 + 3.2493012000000001 3.6547612161941246E-007 + 3.3142871999999999 3.4672556871512286E-007 + 3.3805730000000001 3.2890109871329619E-007 + 3.4481844000000001 3.1195869906256110E-007 + 3.5171481000000000 2.9585630064883208E-007 + 3.5874910999999998 2.8055384280017341E-007 + 3.6592408999999999 2.6601312763698079E-007 + 3.7324256999999998 2.5219769748557175E-007 + 3.8070742000000002 2.3907279902916152E-007 + 3.8832157000000000 2.2660528735736687E-007 + 3.9608800000000000 2.1476356942386979E-007 + 4.0400976000000002 2.0351750336750129E-007 + 4.1208996000000004 1.9283835048748273E-007 + 4.2033176000000001 1.8269872398046387E-007 + 4.2873839000000000 1.7307250173592538E-007 + 4.3731315999999998 1.6393476215019414E-007 + 4.4605942000000001 1.5526177371854186E-007 + 4.5498060999999996 1.4703088939026808E-007 + 4.6408022000000004 1.3922053790020964E-007 + 4.7336182999999998 1.3181014009141134E-007 + 4.8282905999999999 1.2478010539459352E-007 + 4.9248564000000004 1.1811173409699362E-007 + 5.0233536000000001 1.1178721674602573E-007 + 5.1238206000000002 1.0578959705457706E-007 + 5.2262971000000000 1.0010268658297935E-007 + 5.3308229999999996 9.4711094396125430E-008 + 5.4374395000000000 8.9600131083774358E-008 + 5.5461881999999996 8.4755823750441427E-008 + 5.6571119999999997 8.0164842292397229E-008 + 5.7702543000000004 7.5814506383632725E-008 + 5.8856593000000004 7.1692741682779182E-008 + 6.0033725000000002 6.7788036235637084E-008 + 6.1234400000000004 6.4089440353119546E-008 + 6.2459087999999996 6.0586530074846717E-008 + 6.3708270000000002 5.7269378335183679E-008 + 6.4982435000000001 5.4128541134981083E-008 + 6.6282084000000001 5.1155025714124698E-008 + 6.7607724999999999 4.8340282090247607E-008 + 6.8959880000000000 4.5676167704911064E-008 + 7.0339077000000003 4.3154945523871724E-008 + 7.1745859000000003 4.0769248354273071E-008 + 7.3180775999999996 3.8512076588258226E-008 + 7.4644392000000002 3.6376769680766525E-008 + 7.6137278999999998 3.4356999919806144E-008 + 7.7660024999999999 3.2446746131144812E-008 + 7.9213225999999999 3.0640290415178342E-008 + 8.0797489999999996 2.8932198610979322E-008 + 8.2413439999999998 2.7317304418008096E-008 + 8.4061708999999993 2.5790702366409486E-008 + 8.5742943000000000 2.4347732512357049E-008 + 8.7457802000000004 2.2983968354187342E-008 + 8.9206958000000007 2.1695207650757864E-008 + 9.0991096999999996 2.0477460325152658E-008 + 9.2810918999999998 1.9326938642103459E-008 + 9.4667136999999997 1.8240048294225797E-008 + 9.6560480000000002 1.7213377517830794E-008 + 9.8491689999999998 1.6243690201759347E-008 + 10.046151999999999 1.5327918151381987E-008 + 10.247075000000001 1.4463145917317794E-008 + 10.452017000000000 1.3646611659062357E-008 + 10.661057000000000 1.2875702506103728E-008 + 10.874278000000000 1.2147932399161688E-008 + 11.091764000000000 1.1460947819594073E-008 + 11.313599000000000 1.0812523391078608E-008 + 11.539871000000000 1.0200543647741965E-008 + 11.770669000000000 9.6230069745514478E-009 + 12.006081999999999 9.0780215504960070E-009 + 12.246204000000001 8.5637883250348497E-009 + 12.491128000000000 8.0786101429296585E-009 + 12.740950000000000 7.6208777192613472E-009 + 12.995768999999999 7.1890659978458325E-009 + 13.255685000000000 6.7817335244042287E-009 + 13.520797999999999 6.3975191008729669E-009 + 13.791214000000000 6.0351290961527149E-009 + 14.067038999999999 5.6933429562030971E-009 + 14.348379000000000 5.3710085726379308E-009 + 14.635346999999999 5.0670309067781817E-009 + 14.928053999999999 4.7803792527400868E-009 + 15.226615000000001 4.5100773028767143E-009 + 15.531147000000001 4.2552025150862812E-009 + 15.841770000000000 4.0148825020956005E-009 + 16.158605999999999 3.7882932784825927E-009 + 16.481777999999998 3.5746572710012221E-009 + 16.811413000000002 3.3732388284173237E-009 + 17.147642000000001 3.1833423468052765E-009 + 17.490594000000002 3.0043134261610007E-009 + 17.840406000000002 2.8355312663834403E-009 + 18.197213999999999 2.6764116173916283E-009 + 18.561159000000000 2.5264018946429973E-009 + 18.932382000000000 2.3849816339745919E-009 + 19.311029000000001 2.2516587310468632E-009 + 19.697250000000000 2.1259684941715491E-009 + 20.091194999999999 2.0074734302020766E-009 + 20.493019000000000 1.8957601407478390E-009 + 20.902878999999999 1.7904389478461058E-009 + 21.320937000000001 1.6911418271536741E-009 + 21.747356000000000 1.5975222152554887E-009 + 22.182303000000001 1.5092530890933402E-009 + 22.625948999999999 1.4260259491803929E-009 + 23.078468000000001 1.3475500091468277E-009 + 23.540037000000002 1.2735511943460025E-009 + 24.010838000000000 1.2037709103530324E-009 + 24.491054999999999 1.1379656506647364E-009 + 24.980875999999999 1.0759058410810340E-009 + 25.480492999999999 1.0173750803668472E-009 + 25.990103000000001 9.6216931142876283E-010 + 26.509905000000000 9.1009645923066965E-010 + 27.040102999999998 8.6097542861611026E-010 + 27.580905000000001 8.1463560222372053E-010 + 28.695174000000002 7.2966589031651737E-010 + 29.854458999999999 6.5401004871203844E-010 + 31.060579000000001 5.8662332610716834E-010 + 32.315427000000000 5.2657882156795515E-010 + 33.620970000000000 4.7305443767792211E-010 + 34.979256999999997 4.2532090882291807E-010 + 36.392418999999997 3.8273151116352206E-010 + 37.862673000000001 3.4471272458553628E-010 + 39.392325000000000 3.1075597040908430E-010 + 40.983775000000001 2.8041022558860062E-010 + 42.639519000000000 2.5327553160832373E-010 + 44.362155999999999 2.2899714203019620E-010 + 46.154387000000000 2.0726045398140483E-010 + 48.019024000000002 1.8778636715433720E-010 + 49.958993000000000 1.7032726118887742E-010 + 51.977336000000001 1.5466342475235416E-010 + 54.077219999999997 1.4059983475734602E-010 + 56.261940000000003 1.2796335776133195E-010 + 58.534922000000002 1.1660026189343760E-010 + 60.899732999999998 1.0637397901384812E-010 + 63.360081999999998 9.7163170260146996E-011 + 65.919830000000005 8.8859973981599563E-011 + 68.582991000000007 8.1368489040764416E-011 + 71.353744000000006 7.4603397767326091E-011 + 74.236435000000000 6.8488777741613896E-011 + 77.235586999999995 6.2957029531914039E-011 + 80.355905000000007 5.7947940028684915E-011 + 83.602283000000000 5.3407848706021217E-011 + 86.979815000000002 4.9288905282129231E-011 + 90.493799999999993 4.5548421668259681E-011 + 94.149749000000000 4.2148294372322209E-011 + 97.953399000000005 3.9054487437455199E-011 + 101.91072000000000 3.6236582365917923E-011 + 106.02791000000001 3.3667385383971742E-011 + 110.31144000000000 3.1322548711452861E-011 + 114.76802000000001 2.9180283178750872E-011 + 119.40465000000000 2.7221055805406316E-011 + 124.22859000000000 2.5427361505696765E-011 + 129.24743000000001 2.3783480138677208E-011 + 134.46903000000000 2.2275308356690163E-011 + 139.90156999999999 2.0890170792799357E-011 + 145.55359999999999 1.9616659415287865E-011 + 151.43396000000001 1.8444519687436268E-011 + 157.55189999999999 1.7364504962686349E-011 + 163.91699000000000 1.6368289658158696E-011 + 170.53924000000001 1.5448354644830361E-011 + 177.42902000000001 1.4597917400578771E-011 + 184.59716000000000 1.3810844104722072E-011 + 192.05488000000000 1.3081592553335565E-011 + 199.81389999999999 1.2405141601367561E-011 + 207.88638000000000 1.1776945459797219E-011 + 216.28498999999999 1.1192880863357955E-011 + 225.02289999999999 1.0649206747803399E-011 + 234.11383000000001 1.0142524046928303E-011 + 243.57203000000001 9.6697440056861121E-012 + 253.41234000000000 9.2280553832457931E-012 + 263.65019999999998 8.8148980034579494E-012 + 274.30166000000003 8.4279387996075459E-012 + 285.38344999999998 8.0650482906622494E-012 + 296.91293999999999 7.7242833523534219E-012 + 308.90823000000000 7.4038675178755780E-012 + 321.38812000000001 7.1021769571817967E-012 + 334.37220000000002 6.8177247317838258E-012 + 347.88083999999998 6.5491492274878016E-012 + 361.93522000000002 6.2952026998320719E-012 + 376.55739999999997 6.0547403892198138E-012 + 391.77032000000003 5.8267120333720584E-012 + 407.59784000000002 5.6101534932722536E-012 + 424.06479999999999 5.4041790417962714E-012 + 441.19702000000001 5.2079752198784723E-012 + 459.02136999999999 5.0207944374417017E-012 + 477.56583999999998 4.8419493641553783E-012 + 496.85950000000003 4.6708089196574999E-012 + 516.93262000000004 4.5067931301187465E-012 + 537.81669999999997 4.3350103125034375E-012 + 559.54449000000000 4.1650647877128398E-012 + 582.15008999999998 4.0022199906156007E-012 + 605.66895999999997 3.8458988079149174E-012 + 630.13797999999997 3.6955799275282834E-012 + 655.59555999999998 3.5507932426035585E-012 + 682.08162000000004 3.4111164729844574E-012 + 709.63770999999997 3.2761712877846989E-012 + 738.30708000000004 3.1456200991730542E-012 + 768.13468000000000 3.0191634079698438E-012 + 799.16732000000002 2.8965366444739648E-012 + 831.45367999999996 2.7775078844133395E-012 + 865.04440999999997 2.6618753227528650E-012 + 899.99221000000000 2.5494649743098607E-012 + 936.35189000000003 2.4401285420523291E-012 + 974.18051000000003 2.3337411277745463E-012 + 1013.5374000000000 2.2301993826574698E-012 + 1054.4843000000001 2.1294193560535412E-012 + 1097.0854999999999 2.0313344485513330E-012 + 1141.4077000000000 1.9358940287028195E-012 + 1187.5206000000001 1.8430604707869154E-012 + 1235.4964000000000 1.7528086174307183E-012 + 1285.4105000000000 1.6651227768555657E-012 + 1337.3411000000001 1.5799959523867731E-012 + 1391.3697000000000 1.4974274427972068E-012 + 1447.5809999999999 1.4174215901675241E-012 + 1506.0633000000000 1.3399858263733937E-012 + 1566.9082000000001 1.2651297928721501E-012 + 1630.2112999999999 1.1928632217994020E-012 + 1696.0717999999999 1.1231953394488761E-012 + 1764.5931000000000 1.0561331741664425E-012 + 1835.8827000000001 9.9168081231061112E-013 + 1910.0524000000000 9.2983842984609447E-013 + 1987.2184999999999 8.7060148211505633E-013 + 2067.5021000000002 8.1395998190553921E-013 + 2151.0291999999999 7.5989808799183736E-013 + 2237.9308000000001 7.0839380412722407E-013 + 2328.3431999999998 6.5941868776680804E-013 + 2422.4083000000001 6.1293772542875806E-013 + 2520.2734999999998 5.6890953121051755E-013 + 2622.0925999999999 5.2728619490771499E-013 + 2728.0250999999998 4.8801396173734828E-013 + 2838.2374000000000 4.5103319374642640E-013 + 2952.9020999999998 4.1627916085350289E-013 + 3072.1994000000000 3.8368217589230718E-013 + 3196.3162000000002 3.5316851866203663E-013 + 3325.4474000000000 3.2466075111523831E-013 + 3459.7955000000002 2.9807852989126127E-013 + 3599.5711999999999 2.7333916905142226E-013 + 3744.9938999999999 2.5035825868342118E-013 + 3896.2917000000002 2.2905035715304517E-013 + 4053.7017999999998 2.0932958189071832E-013 + 4217.4714000000004 1.9111012692213490E-013 + 4387.8572000000004 1.7430691477087417E-013 + 4565.1266999999998 1.5883599405911280E-013 + 4749.5577999999996 1.4461507414226649E-013 + 4941.4399000000003 1.3156386553664597E-013 + 5141.0740999999998 1.1960445593892954E-013 + 5348.7735000000002 1.0866161529690159E-013 + 5564.8639999999996 9.8663021395578856E-014 + 5789.6845000000003 8.9539469901704571E-014 + 6023.5877000000000 8.1225006195797373E-014 + 6266.9405999999999 7.3657029160501952E-014 + 6520.1251000000002 6.6776348749453348E-014 + 6783.5380999999998 6.0527216966835591E-014 + 7057.5929999999998 5.4857289114847534E-014 + 7342.7197999999999 4.9717594313488356E-014 + 7639.3657000000003 4.5062463630043374E-014 + 7947.9961000000003 4.0849431214398112E-014 + 8269.0951000000005 3.7039126944504290E-014 + 8603.1664999999994 3.3595147770735904E-014 + 8950.7345000000005 3.0483923118074751E-014 + 9312.3441000000003 2.7674573888566115E-014 + 9688.5627999999997 2.5138756108691086E-014 + 10079.981000000000 2.2850514290316272E-014 + 10487.212000000000 2.0786133585866365E-014 + 10910.895000000000 1.8923977856640371E-014 + 11351.696000000000 1.7244346290321227E-014 + 11810.304000000000 1.5729347235479436E-014 + 12287.440000000001 1.4362730528210602E-014 + 12783.852999999999 1.3129776245284544E-014 + 13300.321000000000 1.2017167368127060E-014 + 13837.654000000000 1.1012866596426995E-014 + 14396.695000000000 1.0106006572840395E-014 + 14978.321000000000 9.2867867341240056E-015 + 15583.445000000000 8.5463758174280703E-015 + 16213.017000000000 7.8768230343847488E-015 + 16868.022000000001 7.2709782203031616E-015 + 17549.491000000002 6.7224065125122176E-015 + 18258.490000000002 6.2253299982360160E-015 + 18996.133000000002 5.7745540290743498E-015 + 19763.577000000001 5.3654142688988730E-015 + 20562.025000000001 4.9937221940735513E-015 + 21392.731000000000 4.6557154134006144E-015 + 22256.996999999999 4.3480161615777856E-015 + 23156.180000000000 4.0675896048309341E-015 + 24091.689999999999 3.8117096112415683E-015 + 25064.993999999999 3.5779257644432805E-015 + 26077.619999999999 3.3640340249452290E-015 + 27131.155999999999 3.1680514581870478E-015 + 28227.254000000001 2.9881923819981091E-015 + 29367.634999999998 2.8228470667151590E-015 + 30554.088000000000 2.6705636121978543E-015 + 31788.473000000002 2.5300310463776182E-015 + 33072.726999999999 2.4000640310196475E-015 + 34408.864999999998 2.2795898796367450E-015 + 35798.983999999997 2.3913811981261564E-015 + 37245.262999999999 2.2452778320345745E-015 + 38749.970999999998 2.1116445392284188E-015 + 40315.470000000001 1.9889073395881336E-015 + 41944.214999999997 1.8756682859287949E-015 + 43638.760999999999 1.7706845196908967E-015 + 45401.767000000000 1.6728509691286447E-015 + 47235.999000000003 1.5811860493936842E-015 + 49144.332999999999 1.4948199595382982E-015 + 51129.764000000003 1.4129850420333424E-015 + 53195.406999999999 1.3350085506505829E-015 + 55344.500999999997 1.2603069468879770E-015 + 57580.419000000002 1.1883813989582614E-015 + 59906.667999999998 1.1188146994378623E-015 + 62326.896999999997 1.0512686000772998E-015 + 64844.904000000002 9.8548153797691524E-016 + 67464.638000000006 9.2126644028569005E-016 + 70190.209000000003 8.5850787903785407E-016 + 73025.894000000000 7.9715854536744735E-016 + 75976.139999999999 7.3723465610053916E-016 + 79045.576000000001 6.7880979188701792E-016 + 82239.017000000007 6.2200738173102105E-016 + 85561.472999999998 1.0000000000000001E-030 diff --git a/examples/morphology_test_cases/transition/ctem.in b/examples/morphology_test_cases/transition/ctem.in new file mode 100755 index 00000000..7e58515a --- /dev/null +++ b/examples/morphology_test_cases/transition/ctem.in @@ -0,0 +1,76 @@ +! CTEM Input file + + +! 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 975.0 r ! Diameter of test impactor (m) +testvel 15.0e3 ! Velocity of test crater (m/s) +testang 90.0 ! Impact angle of test crater (deg) - Default 90.0 +testxoffset 0.0e0 ! x-axis offset of crater center from grid center (m) - Default 0.0 +testyoffset 0.0e0 ! 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 craterlist.in ! list of 'real' craters for Quasi-MC runs + + + +! IDL driver in uts +interval 1.0 +numintervals 1 ! Total number of intervals +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 +saveshaded T ! Output shaded relief images +saverego F ! 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 (large file size) +shadedminh -5000.0 ! Minimum height for shaded relief map (m) (Default - automatic) +shadedmaxh 5000.0 ! Maximum height for shaded relief map (m) (Default - automatic) +runtype single ! Run type: options are normal / statistical + ! single: craters accumulate in successive intervals + ! statistical: surface is reset between intervals + +! CTEM required inputs +seed 23790 ! Random number generator seed +gridsize 1000 ! Size of grid in pixels +numlayers 10 ! Number of perched layers +pix 1.0e2 ! 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 1.00e-98 ! 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 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 +fe 4.00 +ejecta_truncation 4.0 +dorays F +superdomain F +doregotrack F +dorealistic T + diff --git a/examples/morphology_test_cases/transition/lunar-MBA-impactor-velocities.dat b/examples/morphology_test_cases/transition/lunar-MBA-impactor-velocities.dat new file mode 100755 index 00000000..b56ce090 --- /dev/null +++ b/examples/morphology_test_cases/transition/lunar-MBA-impactor-velocities.dat @@ -0,0 +1,64 @@ +6000 41.000000 0.002861 +7000 200.000000 0.016817 +8000 541.000000 0.054567 +9000 793.000000 0.109902 +10000 822.000000 0.167260 +11000 974.000000 0.235224 +12000 978.000000 0.303468 +13000 973.000000 0.371363 +14000 901.000000 0.434233 +15000 1034.000000 0.506385 +16000 1036.000000 0.578676 +17000 934.000000 0.643849 +18000 784.000000 0.698556 +19000 644.000000 0.743493 +20000 467.000000 0.776080 +21000 356.000000 0.800921 +22000 285.000000 0.820808 +23000 239.000000 0.837485 +24000 232.000000 0.853674 +25000 319.000000 0.875933 +26000 368.000000 0.901612 +27000 240.000000 0.918359 +28000 162.000000 0.929663 +29000 132.000000 0.938874 +30000 84.000000 0.944735 +31000 82.000000 0.950457 +32000 83.000000 0.956249 +33000 79.000000 0.961761 +34000 81.000000 0.967413 +35000 50.000000 0.970902 +36000 63.000000 0.975298 +37000 66.000000 0.979904 +38000 43.000000 0.982904 +39000 41.000000 0.985765 +40000 44.000000 0.988835 +41000 28.000000 0.990789 +42000 37.000000 0.993371 +43000 19.000000 0.994697 +44000 20.000000 0.996092 +45000 19.000000 0.997418 +46000 5.000000 0.997767 +47000 10.000000 0.998465 +48000 5.000000 0.998814 +49000 3.000000 0.999023 +50000 2.000000 0.999163 +51000 1.000000 0.999232 +52000 0.000000 0.999232 +53000 1.000000 0.999302 +54000 0.000000 0.999302 +55000 1.000000 0.999372 +56000 1.000000 0.999442 +57000 1.000000 0.999512 +58000 0.000000 0.999512 +59000 0.000000 0.999512 +60000 1.000000 0.999581 +61000 0.000000 0.999581 +62000 1.000000 0.999651 +63000 1.000000 0.999721 +64000 0.000000 0.999721 +65000 1.000000 0.999791 +66000 2.000000 0.999930 +67000 0.000000 0.999930 +68000 0.000000 0.999930 +69000 1.000000 1.000000 diff --git a/python/.idea/.gitignore b/python/.idea/.gitignore deleted file mode 100644 index 26d33521..00000000 --- a/python/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/python/ctem/.idea/.gitignore b/python/ctem/.idea/.gitignore deleted file mode 100644 index 26d33521..00000000 --- a/python/ctem/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/python/ctem/ctem/viewer3d.py b/python/ctem/ctem/viewer3d.py index a8ae9f64..8aacf84e 100644 --- a/python/ctem/ctem/viewer3d.py +++ b/python/ctem/ctem/viewer3d.py @@ -35,10 +35,10 @@ def ctem2blockmesh(self): y3.flatten()) zvals = np.append( np.append( - np.append(self.dem.flatten(), - self.dem.flatten()), - self.dem.flatten()), - self.dem.flatten()) + 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) @@ -116,6 +116,7 @@ def visualize(self): if __name__ == '__main__': sim = Polysurface() + sim.surface_dem *= 10 sim.ctem2trimesh() sim.visualize()