diff --git a/build/Makefile_setups b/build/Makefile_setups index 28352dda4..1c4b919a5 100644 --- a/build/Makefile_setups +++ b/build/Makefile_setups @@ -81,7 +81,7 @@ endif ifeq ($(SETUP), solarsystem) # orbits of minor planets ISOTHERMAL=yes - SETUPFILE=utils_mpc.f90 setup_solarsystem.f90 + SETUPFILE=utils_ephemeris.f90 utils_mpc.f90 setup_solarsystem.f90 KNOWN_SETUP=yes DUST=yes endif diff --git a/scripts/bots.sh b/scripts/bots.sh index 131288648..46fe18b8f 100755 --- a/scripts/bots.sh +++ b/scripts/bots.sh @@ -207,7 +207,7 @@ for edittype in $bots_to_run; do 'shout' ) sed -e 's/SQRT(/sqrt(/g' \ -e 's/NINT(/nint(/g' \ - -e 's/STOP/stop/g' \ + -e 's/ STOP/ stop/g' \ -e 's/ATAN/atan/g' \ -e 's/ACOS(/acos(/g' \ -e 's/ASIN(/asin(/g' \ diff --git a/src/main/extern_binary.f90 b/src/main/extern_binary.f90 index 5c53956be..fc5835313 100644 --- a/src/main/extern_binary.f90 +++ b/src/main/extern_binary.f90 @@ -29,7 +29,8 @@ module extern_binary !--code input parameters: these are the default values ! and can be changed in the input file ! - real, public :: binarymassr = 0.5 + real, public :: mass1 = 1.0 + real, public :: mass2 = 0.001 real, public :: accradius1 = 0.5 real, public :: accradius2 = 0.5 real, public :: accretedmass1 = 0. @@ -38,7 +39,7 @@ module extern_binary real, public :: eps_soft2 = 0.0 logical, public :: ramp = .false. logical, public :: surface_force = .false. - real, private :: binarymassri + real, private :: mass2_temp public :: binary_force, binary_posvel, binary_accreted, update_binary public :: write_options_externbinary, read_options_externbinary @@ -61,15 +62,13 @@ module extern_binary !---------------------------------------------- subroutine update_binary(ti) use physcon, only:pi - real, intent(in) :: ti - real :: cost,sint - real :: omega + real, intent(in) :: ti + real :: omega,mtot,a,x,y if (ramp .and. ti < 10.*pi) then - binarymassri = binarymassr*(sin(ti/20.)**2) - !print*,' Mplanet = ',binarymassri + mass2_temp = mass2*(sin(ti/20.)**2) else - binarymassri = binarymassr + mass2_temp = mass2 endif if (surface_force) then @@ -78,12 +77,17 @@ subroutine update_binary(ti) omega = 1. endif - cost = cos(omega*ti) - sint = sin(omega*ti) - x1 = (1.-binarymassri)*cost - y1 = (1.-binarymassri)*sint - x2 = -binarymassri*cost - y2 = -binarymassri*sint + a = 1. ! semi-major axis + x = a*cos(omega*ti) + y = a*sin(omega*ti) + + !--positions of primary and secondary (exact) + mtot = mass1 + mass2_temp + x1 = -mass2_temp/mtot*x + y1 = -mass2_temp/mtot*y + + x2 = mass1/mtot*x + y2 = mass1/mtot*y end subroutine update_binary @@ -96,8 +100,8 @@ end subroutine update_binary subroutine binary_force(xi,yi,zi,ti,fxi,fyi,fzi,phi) real, intent(in) :: xi,yi,zi,ti real, intent(out) :: fxi,fyi,fzi,phi - real :: dx1,dy1,dz1,rr1,f1,r1 - real :: dx2,dy2,dz2,rr2,f2 + real :: dx1,dy1,dz1,rr1,f1 + real :: dx2,dy2,dz2,rr2,f2,r2 real :: dr1,dr2,phi1,phi2 !--compute gravitational force on gas particle i @@ -117,19 +121,19 @@ subroutine binary_force(xi,yi,zi,ti,fxi,fyi,fzi,phi) dr2 = 1./sqrt(rr2 + eps_soft2**2) if (surface_force) then - r1 = sqrt(rr1) - if (r1 < 2.*eps_soft1) then + r2 = sqrt(rr2) + if (r2 < 2.*eps_soft2) then !--add surface force to keep particles outside of r_planet - f1 = binarymassri/(rr1*r1)*(1.-((2.*eps_soft1-r1)/eps_soft1)**4) + f2 = mass2_temp/(rr2*r2)*(1.-((2.*eps_soft2-r2)/eps_soft2)**4) else !--1/r potential - f1 = binarymassri/(rr1*r1) + f2 = mass2_temp/(rr2*r2) endif else !--normal softened potential - f1 = binarymassri*dr1*dr1*dr1 + f2 = mass2_temp*dr2*dr2*dr2 endif - f2 = (1.-binarymassri)*dr2*dr2*dr2 + f1 = mass1*dr1*dr1*dr1 fxi = -dx1*f1 - dx2*f2 fyi = -dy1*f1 - dy2*f2 @@ -137,8 +141,8 @@ subroutine binary_force(xi,yi,zi,ti,fxi,fyi,fzi,phi) ! Note: phi1 is the Newtonian potential and does not include then surface force above; ! however, this is not critical since phi is only used for timestep control - phi1 = -binarymassri*dr1 - phi2 = -(1.-binarymassri)*dr2 + phi1 = -mass1*dr1 + phi2 = -mass2_temp*dr2 phi = phi1 + phi2 end subroutine binary_force @@ -153,25 +157,36 @@ subroutine binary_posvel(ti,posmh,vels) real, intent(in) :: ti real, intent(out) :: posmh(10) real, intent(out) :: vels(6) + real :: mtot,omega,vx,vy !--positions of primary and secondary (exact) posmh(1) = x1 posmh(2) = y1 posmh(3) = 0. - posmh(4) = binarymassri*1./(1.-binarymassri) + posmh(4) = mass1 posmh(5) = accradius1 posmh(6) = x2 posmh(7) = y2 posmh(8) = 0. - posmh(9) = 1. + posmh(9) = mass2_temp posmh(10) = accradius2 - vels(1) = -(1.-binarymassri)*sin(ti) - vels(2) = (1.-binarymassri)*cos(ti) + if (surface_force) then + omega = 0. ! fixed position + else + omega = 1. + endif + + vx = -omega*x2 + vy = omega*y2 + + mtot = mass1 + mass2_temp + vels(1) = -mass2_temp/mtot*vx + vels(2) = -mass2_temp/mtot*vy vels(3) = 0. - vels(4) = binarymassri*sin(ti) - vels(5) = -binarymassri*cos(ti) + vels(4) = mass1/mtot*vx + vels(5) = mass1/mtot*vy vels(6) = 0. end subroutine binary_posvel @@ -219,7 +234,7 @@ subroutine write_options_externbinary(iunit) use infile_utils, only:write_inopt integer, intent(in) :: iunit - call write_inopt(binarymassr,'binarymassr','m1/(m1+m2) of central binary system (if iexternalforce=binary)',iunit) + call write_inopt(mass2,'mass2','m2 of central binary system (if iexternalforce=binary)',iunit) call write_inopt(accradius1,'accradius1','accretion radius of primary',iunit) call write_inopt(accradius2,'accradius2','accretion radius of secondary (if iexternalforce=binary)',iunit) call write_inopt(eps_soft1,'eps_soft1','Plummer softening of primary',iunit) @@ -244,12 +259,12 @@ subroutine read_options_externbinary(name,valstring,imatch,igotall,ierr) imatch = .true. igotall = .false. select case(trim(name)) - case('binarymassr') - read(valstring,*,iostat=ierr) binarymassr + case('mass2') + read(valstring,*,iostat=ierr) mass2 ngot = ngot + 1 - if (binarymassr < epsilon(binarymassr)) & - call fatal(where,'invalid setting for binary mass ratio (<0)') - if (binarymassr > 1.e10) call error(where,'binary mass ratio is huge!!!') + if (mass2 < epsilon(mass2)) & + call fatal(where,'invalid setting for m2 (<0)') + if (mass2/mass1 > 1.e10) call error(where,'binary mass ratio is huge!!!') case('accradius1') ! cannot be compulsory, because also handled in parent routine read(valstring,*,iostat=ierr) accradius1 if (accradius1 < 0.) call fatal(where,'negative accretion radius') diff --git a/src/main/extern_binary_gw.f90 b/src/main/extern_binary_gw.f90 index 9cf0647de..764a31b6f 100644 --- a/src/main/extern_binary_gw.f90 +++ b/src/main/extern_binary_gw.f90 @@ -26,11 +26,11 @@ module extern_binary !--code input parameters: these are the default values ! and can be changed in the input file ! - real, public, parameter :: massp = 1. - real, public :: massr = 0.001 + real, public :: mass1 = 1.0 + real, public :: mass2 = 0.001 real, public :: a0 = 30. real, public :: accradius1 = 2.0 - real, public :: accradius2 = 2. ! accradius1 x mass ratio + real, public :: accradius2 = 0.002 ! accradius1 x mass ratio real, public :: direction = 1. real, public :: accretedmass1 = 0. real, public :: accretedmass2 = 0. @@ -40,7 +40,6 @@ module extern_binary public :: write_headeropts_externbinary, read_headeropts_externbinary private - !real, private, save :: tset = -1. real, private :: xyzbin(3,2) contains @@ -75,7 +74,6 @@ subroutine compute_binary_pos(ti) xyzbin(1,2) = posmh(6) xyzbin(2,2) = posmh(7) xyzbin(3,2) = posmh(8) - !tset = ti end subroutine compute_binary_pos @@ -92,9 +90,9 @@ subroutine binary_force(xi,yi,zi,ti,fxi,fyi,fzi,phi) real :: dx1,dy1,dz1,dx2,dy2,dz2 real :: rr1,rr2,f1,f2,dr1,dr2,phi1,phi2 - if (abs(massr) < tiny(massr)) then - x1=0. - y1=0. + if (abs(mass2) < tiny(mass2)) then + x1 = 0. + y1 = 0. dx1 = xi - x1 dy1 = yi - y1 @@ -103,8 +101,8 @@ subroutine binary_force(xi,yi,zi,ti,fxi,fyi,fzi,phi) rr1 = dx1*dx1 + dy1*dy1 + dz1*dz1 dr1 = 1./sqrt(rr1) - f1 = massp*dr1*dr1*dr1 - phi1 = massp*dr1 + f1 = mass1*dr1*dr1*dr1 + phi1 = mass1*dr1 fxi = -dx1*f1 fyi = -dy1*f1 @@ -128,20 +126,18 @@ subroutine binary_force(xi,yi,zi,ti,fxi,fyi,fzi,phi) dr1 = 1./sqrt(rr1) dr2 = 1./sqrt(rr2) - f1 = massp*dr1*dr1*dr1 - f2 = massp*massr*dr2*dr2*dr2 + f1 = mass1*dr1*dr1*dr1 + f2 = mass2*dr2*dr2*dr2 fxi = -dx1*f1 - dx2*f2 fyi = -dy1*f1 - dy2*f2 fzi = -dz1*f1 - dz2*f2 - phi1 = massp*dr1 - phi2 = massp*massr*dr2 + phi1 = mass1*dr1 + phi2 = mass2*dr2 phi = phi1 + phi2 endif - !write (*,*) ti,0.,0.,0.,0.,x2,y2,0.,0.,0.,0.,a,theta - return end subroutine binary_force !---------------------------------------------- @@ -154,14 +150,14 @@ subroutine binary_posvel(ti,posmh,vels) real, intent(in) :: ti real, intent(out) :: posmh(10) real, intent(out) :: vels(6) - real :: theta,a,mu,mtot,tau,x,y,omega,dadt,vx,vy + real :: theta,a,mu,mtot,tau,x,y,omega,dadt,vx,vy,term - if (abs(massr) < tiny(massr)) then + if (abs(mass2) < tiny(mass2)) then ! m2 = 0 posmh(1:3) = 0. - posmh(4) = massp + posmh(4) = mass1 posmh(5) = accradius1 posmh(6:8) = 0. - posmh(9) = massp*massr + posmh(9) = mass2 posmh(10) = accradius2 vels(1) = 0. @@ -173,8 +169,8 @@ subroutine binary_posvel(ti,posmh,vels) else - mtot=massp+massp*massr; - mu=(massp**2)*massr/mtot; + mtot = mass1 + mass2 + mu = mass1*mass2/mtot !--time of coalescence tau=5./256.*a0**4/(mu * mtot**2) @@ -182,46 +178,46 @@ subroutine binary_posvel(ti,posmh,vels) a=a0*((1.-ti/tau)**.25) !--relative angular position - theta=direction*(-1./32.)*1./(mu*mtot**(2./3.))*(5./256.*1./(mu*mtot**(2./3.))*1./(tau-ti))**(-5./8.) + term = 1./(mu*mtot**(2./3.)) + theta=direction*(-1./32.)*term*(5./256.*term*1./(tau-ti))**(-5./8.) !--relative position x=a*cos(theta) y=a*sin(theta) !--positions of primary and secondary (exact) - posmh(1) = -massp*massr/mtot*x - posmh(2) = -massp*massr/mtot*y + posmh(1) = -mass2/mtot*x + posmh(2) = -mass2/mtot*y posmh(3) = 0. - posmh(4) = massp + posmh(4) = mass1 posmh(5) = accradius1 - posmh(6) = massp/mtot*x - posmh(7) = massp/mtot*y + posmh(6) = mass1/mtot*x + posmh(7) = mass1/mtot*y posmh(8) = 0. - posmh(9) = massp*massr + posmh(9) = mass2 posmh(10) = accradius2 !-- rate of shrinking dadt = -64./5. * mu*mtot**2/a**3 !-- rate of rotating - omega = direction*(5./256. * 1./(mu*mtot**(2./3.)) *1./(tau-ti))**(3./8.) + omega = direction*(5./256.*term*1./(tau-ti))**(3./8.) !--relative velocity vx = 1./a*dadt*x - omega*y vy = 1./a*dadt*y + omega*x !--absolute velocity - vels(1) = -massp*massr/mtot*vx - vels(2) = -massp*massr/mtot*vy + vels(1) = -mass2/mtot*vx + vels(2) = -mass2/mtot*vy vels(3) = 0. - vels(4) = massp/mtot*vx - vels(5) = massp/mtot*vy + vels(4) = mass1/mtot*vx + vels(5) = mass1/mtot*vy vels(6) = 0. endif - return end subroutine binary_posvel !---------------------------------------------- @@ -236,7 +232,7 @@ logical function binary_accreted(xi,yi,zi,mi,ti) real :: dx1,dy1,dz1,dx2,dy2,dz2 real :: rr1,rr2 - if (abs(massr) < tiny(massr)) then + if (abs(mass2) < tiny(mass2)) then ! if m2=0 x1=0. y1=0. @@ -245,7 +241,7 @@ logical function binary_accreted(xi,yi,zi,mi,ti) dz1 = zi rr1 = dx1*dx1 + dy1*dy1 + dz1*dz1 - rr2 = 1.e10 + rr2 = huge(rr2) else !if (abs(ti-tset) > epsilon(0.)) call compute_binary_pos(ti) dx1 = xi - xyzbin(1,1) @@ -356,17 +352,21 @@ subroutine read_headeropts_externbinary(hdr,ierr) use io, only:error type(dump_h), intent(in) :: hdr integer, intent(out) :: ierr - real :: time,mtot,mu,tau,m1,m2,x1,y1,z1,x2,y2,z2 + real :: time,mtot,mu,tau,m1,m2,x1,y1,z1,x2,y2,z2,massr integer :: ierrs(7) ierr = 0 call extract('time',time,hdr,ierrs(1)) call extract('m1',m1,hdr,ierrs(2)) - if (abs(m1 - massp) > epsilon(massp)) then + if (abs(m1 - mass1) > epsilon(mass1)) then call error('read_headeropts_externbinary','m1 in dump header not equal to mass of primary',var='m1',val=m1) ierr = 2 endif call extract('m2',m2,hdr,ierrs(3)) + if (abs(m2 - mass2) > epsilon(mass2)) then + call error('read_headeropts_externbinary','m2 in dump header not equal to mass of secondary',var='m2',val=m2) + ierr = 2 + endif call extract('a0',a0,hdr,ierrs(4)) call extract('direction',direction,hdr,ierrs(5)) call extract('accretedmass1',accretedmass1,hdr,ierrs(6)) @@ -395,9 +395,9 @@ subroutine read_headeropts_externbinary(hdr,ierr) print*,' Accreted mass on prim : ',accretedmass1 print*,' Accreted mass on sec. : ',accretedmass2 - mtot=massp+massp*massr; - mu=massp**2 * massr/mtot; - tau=5./256.*a0**4/(mu * mtot**2) + mtot = mass1 + mass2 + mu = mass1*mass2/mtot + tau = 5./256.*a0**4/(mu * mtot**2) print*,' Time of coalescence : ',tau print*,' Remaining time : ',tau - time print "(2x,a,2pf6.2,'%')",'Fraction complete : ',time/tau diff --git a/src/main/externalforces.F90 b/src/main/externalforces.F90 index 940278203..04e023bfa 100644 --- a/src/main/externalforces.F90 +++ b/src/main/externalforces.F90 @@ -23,7 +23,7 @@ module externalforces ! extern_lensethirring, extern_prdrag, extern_spiral, extern_staticsine, ! infile_utils, io, lumin_nsdisc, part, units ! - use extern_binary, only:accradius1 + use extern_binary, only:accradius1,mass1 use extern_corotate, only:omega_corotate ! so public from this module implicit none @@ -37,7 +37,6 @@ module externalforces public :: update_externalforce public :: write_headeropts_extern,read_headeropts_extern - real, public :: mass1 = 1.0 real, public :: eps_soft = 0.d0 real, private :: eps2_soft = 0.d0 real, public :: Rdisc = 5. @@ -45,6 +44,8 @@ module externalforces real, public :: accradius1_hard = 0. logical, public :: extract_iextern_from_hdr = .false. + public :: mass1 + ! ! enumerated list of external forces ! diff --git a/src/main/utils_datafiles.f90 b/src/main/utils_datafiles.f90 index b138d0b16..94cb3c3f6 100644 --- a/src/main/utils_datafiles.f90 +++ b/src/main/utils_datafiles.f90 @@ -18,7 +18,7 @@ module datautils ! :Dependencies: None ! implicit none - public :: find_datafile + public :: find_datafile,download_datafile private diff --git a/src/main/utils_filenames.f90 b/src/main/utils_filenames.f90 index f0acb635c..c2a6308eb 100644 --- a/src/main/utils_filenames.f90 +++ b/src/main/utils_filenames.f90 @@ -21,7 +21,7 @@ module fileutils implicit none public :: getnextfilename,numfromfile,basename,get_ncolumns,skip_header,get_column_labels,split public :: strip_extension,is_digit,files_are_sequential - public :: ucase,lcase,make_tags_unique,get_nlines,string_delete + public :: ucase,lcase,make_tags_unique,get_nlines,string_delete,string_replace,nospaces private @@ -465,6 +465,31 @@ pure subroutine string_delete(string,skey) enddo end subroutine string_delete +!--------------------------------------------------------------------------- +! +! subroutine to replace a matching section of a string with another +! string, possibly of differing length +! +!--------------------------------------------------------------------------- +subroutine string_replace(string,skey,sreplacewith) + character(len=*), intent(inout) :: string + character(len=*), intent(in) :: skey,sreplacewith + character(len=len(string)) :: remstring + integer :: ipos,imax,lensub,i + + ipos = index(trim(string),skey) + lensub = len(skey) + imax = len(string) + i = 0 + do while (ipos > 0 .and. i <= imax) + i = i + 1 ! only allow as many replacements as characters + remstring = string(ipos+lensub:len_trim(string)) + string = string(1:ipos-1)//sreplacewith//remstring + ipos = index(trim(string),skey) + enddo + +end subroutine string_replace + !--------------------------------------------------------------------------- ! ! Split a string into substrings based on a delimiter diff --git a/src/setup/set_star.f90 b/src/setup/set_star.f90 index 83cb9aea8..7a617d3c3 100644 --- a/src/setup/set_star.f90 +++ b/src/setup/set_star.f90 @@ -374,7 +374,7 @@ subroutine write_dist(item_in,dist_in,udist) write(*,'(1x,2(a,es12.5),a)') item_in, dist_in*udist,' cm = ',dist_in,' km' else write(*,'(1x,2(a,es12.5),a)') item_in, dist_in*udist,' cm = ',dist_in*udist/solarr,' R_sun' - endif + endif end subroutine write_dist !----------------------------------------------------------------------- diff --git a/src/setup/setup_chinchen.f90 b/src/setup/setup_chinchen.f90 index dc5c503cd..687284395 100644 --- a/src/setup/setup_chinchen.f90 +++ b/src/setup/setup_chinchen.f90 @@ -34,7 +34,7 @@ subroutine setpart(id,npart,npartoftype,xyzh,massoftype,vxyzu,polyk,gamma,hfact, use physcon, only:solarm,au,pi use options, only:iexternalforce use externalforces, only:iext_binary - use extern_binary, only:binarymassr + use extern_binary, only:mass2 use io, only:master use timestep, only:dtmax integer, intent(in) :: id @@ -46,10 +46,7 @@ subroutine setpart(id,npart,npartoftype,xyzh,massoftype,vxyzu,polyk,gamma,hfact, real, intent(inout) :: time character(len=20), intent(in) :: fileprefix real, intent(out) :: vxyzu(:,:) - character(len=120) :: filename - integer :: ierr - logical :: iexist - real :: m1 + real :: m1 ! !--units ! @@ -82,7 +79,7 @@ subroutine setpart(id,npart,npartoftype,xyzh,massoftype,vxyzu,polyk,gamma,hfact, vxyz_ptmass(1,1) = 0.489765446 iexternalforce = iext_binary - binarymassr = 0.5 + mass2 = m1 dtmax = 0.1*(9.*pi) end subroutine setpart diff --git a/src/setup/setup_disc.f90 b/src/setup/setup_disc.f90 index 574d37219..44a88049b 100644 --- a/src/setup/setup_disc.f90 +++ b/src/setup/setup_disc.f90 @@ -99,7 +99,7 @@ module setup use externalforces, only:iext_star,iext_binary,iext_lensethirring,& iext_einsteinprec,iext_corot_binary,iext_corotate,& update_externalforce - use extern_binary, only:binarymassr,accradius1,accradius2,ramp,surface_force,eps_soft1 + use extern_binary, only:mass2,accradius1,accradius2,ramp,surface_force,eps_soft1 use fileutils, only:make_tags_unique use growth, only:ifrag,isnow,rsnow,Tsnow,vfragSI,vfraginSI,vfragoutSI,gsizemincgs use io, only:master,warning,error,fatal @@ -779,16 +779,16 @@ subroutine setup_central_objects(fileprefix) mcentral = m1 case (2) print "(/,a)",' Central binary represented by external force with accretion boundary' - print "(a,g10.3,a)",' Primary mass: ', m2, trim(mass_unit) - print "(a,g10.3)", ' Binary mass ratio: ', m1/m2 + print "(a,g10.3,a)",' Primary mass: ', m1, trim(mass_unit) + print "(a,g10.3)", ' Binary mass ratio: ', m2/m1 print "(a,g10.3,a)",' Accretion Radius 1: ', accr1, trim(dist_unit) print "(a,g10.3,a)",' Accretion Radius 2: ', accr2, trim(dist_unit) mass1 = m1 - binarymassr = m2/(m1+m2) + mass2 = m2 accradius1 = accr1 accradius2 = accr2 if (iexternalforce == iext_corot_binary) then - mcentral = m2 + mcentral = m1 else mcentral = m1 + m2 endif @@ -1507,7 +1507,7 @@ subroutine set_planet_atm(id,xyzh,vxyzu,npartoftype,maxvxyzu,itype,a0,R_in, & if (ramp) then xyz_orig(:) = (/a0,0.,0./) else - a_orbit = a0 - binarymassr + a_orbit = a0 - mass2/Mstar xyz_orig(:) = (/a_orbit,0.,0./) endif diff --git a/src/setup/setup_gwdisc.f90 b/src/setup/setup_gwdisc.f90 index 8c464bc0d..ced4b97ab 100644 --- a/src/setup/setup_gwdisc.f90 +++ b/src/setup/setup_gwdisc.f90 @@ -23,7 +23,7 @@ module setup ! - alphaSS : *desired alpha_SS* ! - discm : *disc mass* ! - inc : *inclination (tilt) in degrees* -! - massr : *mass ratio* +! - mass2 : *mass of secondary* ! - np : *number of particles* ! - p_indexinput : *surface density profile* ! - q_indexinput : *temperature profile* @@ -31,7 +31,7 @@ module setup ! :Dependencies: extern_binary, externalforces, infile_utils, io, options, ! physcon, prompting, setdisc, units ! - use extern_binary, only:accradius1,accradius2,massr,a0 !,binary_posvel + use extern_binary, only:accradius1,accradius2,mass1,mass2,a0 !,binary_posvel implicit none public :: setpart @@ -153,7 +153,6 @@ subroutine setpart(id,npart,npartoftype,xyzh,massoftype,vxyzu,polyk,gamma,hfact, ! vxyzu(3,i) = vxyzu(3,i) + vbinary(3) ! enddo - return end subroutine setpart subroutine setup_interactive() @@ -166,9 +165,9 @@ subroutine setup_interactive() ! print "(a,f6.3,a,1pe8.2,a)",' Schwarzschild radius is ',2.0*udist/au,' AU for ',umass/solarm,' M_sun black hole' call prompt('Enter total number of gas particles ',np,0) - call prompt('Enter mass ratio of binary',massr,0.,1.) + call prompt('Enter mass of secondary',mass2,0.,1.) - accradius2 = massr*accradius1 + accradius2 = mass2/mass1*accradius1 call prompt('Enter initial binary separation',a0,0.) call prompt('Enter accretion radius of the PRIMARY black hole ',accradius1,accradius1,a0) @@ -199,7 +198,7 @@ subroutine write_setupfile(filename) call write_inopt(np,'np','number of particles',iunit) write(iunit,"(/,a)") '# options for binary' - call write_inopt(massr,'massr','mass ratio',iunit) + call write_inopt(mass2,'mass2','mass of secondary',iunit) call write_inopt(a0,'a0','initial binary separation',iunit) call write_inopt(accradius1,'accradius1','primary accretion radius',iunit) call write_inopt(accradius2,'accradius2','secondary accretion radius',iunit) @@ -231,7 +230,7 @@ subroutine read_setupfile(filename,ierr) call open_db_from_file(db,filename,iunit,ierr) nerr = 0 call read_inopt(np,'np',db,min=1,errcount=nerr) - call read_inopt(massr,'massr',db,min=0.,errcount=nerr) + call read_inopt(mass2,'mass2',db,min=0.,errcount=nerr) call read_inopt(a0,'a0',db,min=0.,errcount=nerr) call read_inopt(accradius1,'accradius1',db,min=0.,errcount=nerr) call read_inopt(accradius2,'accradius2',db,min=0.,errcount=nerr) diff --git a/src/setup/setup_planetdisc.f90 b/src/setup/setup_planetdisc.f90 index 6f58bc2c6..609f73adc 100644 --- a/src/setup/setup_planetdisc.f90 +++ b/src/setup/setup_planetdisc.f90 @@ -56,7 +56,7 @@ subroutine setpart(id,npart,npartoftype,xyzh,massoftype,vxyzu,polyk,gamma,hfact, use timestep, only:dtmax,tmax use prompting, only:prompt use extern_binary, only:accradius1,accradius2 !,binary_posvel - use extern_binary, only:binarymassr,eps_soft1,eps_soft2,ramp + use extern_binary, only:mass2,eps_soft1,eps_soft2,ramp use externalforces, only:iext_binary integer, intent(in) :: id @@ -90,7 +90,7 @@ subroutine setpart(id,npart,npartoftype,xyzh,massoftype,vxyzu,polyk,gamma,hfact, hfact = 1.2 time = 0. a0 = 1. - binarymassr = 1.e-3 + mass2 = 1.e-3 HoverR = 0.05 accradius1 = 0.0 accradius2 = 0.3 @@ -119,13 +119,13 @@ subroutine setpart(id,npart,npartoftype,xyzh,massoftype,vxyzu,polyk,gamma,hfact, !--set default options ! call prompt('Enter total number of gas particles ',np,0,size(xyzh(1,:))) - call prompt('Enter mplanet/mtot',binarymassr,0.,1.) + call prompt('Enter mplanet',mass2,0.,1.) - call prompt('Enter accretion radius of the PRIMARY (planet)',accradius1,accradius1,1.) - call prompt('Enter accretion radius of the SECONDARY (star)',accradius2,accradius2,1.) + call prompt('Enter accretion radius of the PRIMARY (star)',accradius1,accradius1,1.) + call prompt('Enter accretion radius of the SECONDARY (planet)',accradius2,accradius2,1.) - call prompt('Enter softening radius of the PRIMARY (planet)',eps_soft1,0.,1.) - call prompt('Enter softening radius of the SECONDARY (star)',eps_soft2,0.,1.) + call prompt('Enter softening radius of the PRIMARY (star)',eps_soft1,0.,1.) + call prompt('Enter softening radius of the SECONDARY (planet)',eps_soft2,0.,1.) call prompt('Enter inner disc edge R_in ',R_in,accradius1) call prompt('Enter outer disc edge R_out ',R_out,R_in) @@ -197,7 +197,7 @@ end subroutine setpart subroutine write_setupfile(filename) use infile_utils, only:write_inopt use extern_binary, only:accradius1,accradius2,binary_posvel - use extern_binary, only:binarymassr + use extern_binary, only:mass2 implicit none character(len=*), intent(in) :: filename integer, parameter :: iunit = 20 @@ -212,7 +212,7 @@ subroutine write_setupfile(filename) write(iunit,"(/,a)") '# options for binary' - call write_inopt(binarymassr,'mplanet','m1/(m1+m2)',iunit) + call write_inopt(mass2,'mplanet','m2',iunit) call write_inopt(accradius1,'accradius1','primary accretion radius',iunit) call write_inopt(accradius2,'accradius2','secondary accretion radius',iunit) call write_inopt(norbits, 'norbits', 'number of orbits', iunit) @@ -234,7 +234,7 @@ end subroutine write_setupfile subroutine read_setupfile(filename,ierr) use infile_utils, only:open_db_from_file,inopts,read_inopt,close_db use extern_binary, only:accradius1,accradius2,binary_posvel - use extern_binary, only:binarymassr + use extern_binary, only:mass2 implicit none character(len=*), intent(in) :: filename integer, intent(out) :: ierr @@ -248,7 +248,7 @@ subroutine read_setupfile(filename,ierr) nerr = 0 call read_inopt(np,'np',db,errcount=nerr) - call read_inopt(binarymassr,'mplanet',db,errcount=nerr) + call read_inopt(mass2,'mplanet',db,errcount=nerr) call read_inopt(accradius1,'accradius1',db,errcount=nerr) call read_inopt(accradius2,'accradius2',db,errcount=nerr) call read_inopt(R_in,'R_in',db,errcount=nerr) @@ -266,5 +266,4 @@ subroutine read_setupfile(filename,ierr) end subroutine read_setupfile - end module setup diff --git a/src/setup/setup_solarsystem.f90 b/src/setup/setup_solarsystem.f90 index 72015427a..333519a44 100644 --- a/src/setup/setup_solarsystem.f90 +++ b/src/setup/setup_solarsystem.f90 @@ -10,14 +10,14 @@ module setup ! ! :References: https://minorplanetcenter.net/data ! -! :Owner: Not Committed Yet +! :Owner: Daniel Price ! ! :Runtime parameters: ! - dumpsperorbit : *number of dumps per orbit* ! - norbits : *number of orbits* ! -! :Dependencies: infile_utils, io, mpc, part, physcon, setbinary, timestep, -! units +! :Dependencies: centreofmass, datautils, ephemeris, infile_utils, io, mpc, +! part, physcon, setbinary, timestep, units ! implicit none public :: setpart @@ -35,15 +35,16 @@ module setup !+ !---------------------------------------------------------------- subroutine setpart(id,npart,npartoftype,xyzh,massoftype,vxyzu,polyk,gamma,hfact,time,fileprefix) - use part, only:nptmass,xyzmh_ptmass,vxyz_ptmass,idust,ndustlarge,set_particle_type,& - grainsize,graindens,ndusttypes - use setbinary, only:set_binary - use units, only:set_units,umass,udist,unit_density - use physcon, only:solarm,au,pi,km - use io, only:master,fatal - use timestep, only:tmax,dtmax - use mpc, only:read_mpc,mpc_entry - use datautils, only:find_datafile + use part, only:nptmass,xyzmh_ptmass,vxyz_ptmass,idust,set_particle_type,& + grainsize,graindens,ndustlarge,ndusttypes + use setbinary, only:set_binary + use units, only:set_units,umass,udist,unit_density + use physcon, only:solarm,au,pi,km + use io, only:master,fatal + use timestep, only:tmax,dtmax + use mpc, only:read_mpc,mpc_entry + use datautils, only:find_datafile + use centreofmass, only:reset_centreofmass integer, intent(in) :: id integer, intent(inout) :: npart integer, intent(out) :: npartoftype(:) @@ -97,16 +98,14 @@ subroutine setpart(id,npart,npartoftype,xyzh,massoftype,vxyzu,polyk,gamma,hfact, vxyzu(:,:) = 0. nptmass = 0 - semia = 5.2 ! Jupiter + semia = 1. ! Earth mtot = solarm/umass hpart = 100.*au/udist period = 2.*pi*sqrt(semia**3/mtot) tmax = norbits*period dtmax = period/dumpsperorbit -! -! read the orbital data from the data file -! + filename = find_datafile('Distant.txt',url='https://www.minorplanetcenter.net/iau/MPCORB/') call read_mpc(filename,nbodies,dat=dat) print "(a,i0,a)",' read orbital data for ',nbodies,' minor planets' @@ -116,7 +115,7 @@ subroutine setpart(id,npart,npartoftype,xyzh,massoftype,vxyzu,polyk,gamma,hfact, ! for each solar system object get the xyz positions from the orbital parameters ! !print*,i,'aeiOwM=',dat(i)%a,dat(i)%ecc,dat(i)%inc,dat(i)%O,dat(i)%w,dat(i)%M - call set_binary(mtot,epsilon(0.),dat(i)%a,dat(i)%ecc,1.,1.e-15,& + call set_binary(mtot,epsilon(0.),dat(i)%a,dat(i)%ecc,0.02,1.e-15,& xyzmh_ptmass,vxyz_ptmass,nptmass,ierr,incl=dat(i)%inc,& arg_peri=dat(i)%w,posang_ascnode=dat(i)%O,& mean_anomaly=dat(i)%M,verbose=.false.) @@ -144,12 +143,75 @@ subroutine setpart(id,npart,npartoftype,xyzh,massoftype,vxyzu,polyk,gamma,hfact, grainsize(1:ndustlarge) = km/udist ! assume km-sized bodies graindens(1:ndustlarge) = 2./unit_density ! 2 g/cm^3 + ! + ! add the planets + ! + call set_solarsystem_planets(nptmass,xyzmh_ptmass,vxyz_ptmass) + + call reset_centreofmass(npart,xyzh,vxyzu,nptmass,xyzmh_ptmass,vxyz_ptmass) hfact = 1.2 if (ierr /= 0) call fatal('setup','ERROR during setup') end subroutine setpart +!---------------------------------------------------------------- +!+ +! setup the solar system planets by querying their ephemeris +! from the JPL server +!+ +!---------------------------------------------------------------- +subroutine set_solarsystem_planets(nptmass,xyzmh_ptmass,vxyz_ptmass) + use ephemeris, only:get_ephemeris,nelem + use units, only:umass,udist + use physcon, only:gg,km,solarm,earthm,au + use setbinary, only:set_binary + integer, intent(inout) :: nptmass + real, intent(inout) :: xyzmh_ptmass(:,:),vxyz_ptmass(:,:) + integer, parameter :: nplanets = 9 + character(len=*), parameter :: planet_name(nplanets) = & + (/'mercury', & + 'venus ', & + 'earth ', & + 'mars ', & + 'jupiter', & + 'saturn ', & + 'uranus ', & + 'neptune', & + 'pluto '/) ! for nostalgia's sake + real :: elems(nelem),xyz_tmp(size(xyzmh_ptmass(:,1)),2),vxyz_tmp(3,2),gm_cgs + real :: msun,mplanet,a,e,inc,O,w,f + integer :: i,ierr,ntmp + + msun = solarm/umass + do i=1,nplanets + elems = get_ephemeris(planet_name(i),ierr) + if (ierr /= 0) then + print "(a)",' ERROR: could not read ephemeris data for '//planet_name(i) + cycle ! skip if error reading ephemeris file + endif + gm_cgs = elems(1)*km**3 + mplanet = (gm_cgs/gg)/umass + a = elems(2)*km/udist + e = elems(3) + inc = elems(4) + O = elems(5) + w = elems(6) + f = elems(7) + print*,' mplanet/mearth = ',mplanet*umass/earthm,' a = ',a*udist/au,' au' + ntmp = 0 + call set_binary(msun,mplanet,a,e,0.01,0.01,& + xyz_tmp,vxyz_tmp,ntmp,ierr,incl=inc,& + arg_peri=w,posang_ascnode=O,f=f,verbose=.false.) + nptmass = nptmass + 1 + xyzmh_ptmass(:,nptmass) = xyz_tmp(:,2) + vxyz_ptmass(:,nptmass) = vxyz_tmp(:,2) + enddo + + print*,' nptmass = ',nptmass + +end subroutine set_solarsystem_planets + !---------------------------------------------------------------- !+ ! write setup parameters to file diff --git a/src/utils/moddump_rad_to_LTE.f90 b/src/utils/moddump_rad_to_LTE.f90 index 865ddf1f9..c3c309830 100644 --- a/src/utils/moddump_rad_to_LTE.f90 +++ b/src/utils/moddump_rad_to_LTE.f90 @@ -5,30 +5,21 @@ ! http://phantomsph.bitbucket.io/ ! !--------------------------------------------------------------------------! module moddump - ! - ! Convert a radiative dump into a non-radiative dump, assuming LTE (i.e., ieos=12) - ! INSTRUCTIONS: 1) Set gmw (mean molecular weight) in the code below to the - ! same value assumed in the radiative dump - ! 1) Make this moddump with a radiative setup (e.g. SETUP=radstar), - ! otherwise the rad array is not read. - ! 2) Run this moddump - ! 3) Write/modify the infile to remove radiation-related options, - ! make sure ieos=12 and mu is correct - ! 4) Recompile Phantom with the desired non-radiative setup (e.g. - ! SETUP=star). - ! - ! :References: None - ! - ! :Owner: Mike Lau - ! - ! :Runtime parameters: None - ! - ! :Dependencies: - ! +! +! moddump +! +! :References: None +! +! :Owner: Mike Lau +! +! :Runtime parameters: None +! +! :Dependencies: dim, eos, io, part +! implicit none - - contains - + +contains + subroutine modify_dump(npart,npartoftype,massoftype,xyzh,vxyzu) use dim, only:do_radiation use io, only:fatal @@ -39,7 +30,7 @@ subroutine modify_dump(npart,npartoftype,massoftype,xyzh,vxyzu) real, intent(inout) :: massoftype(:) real, intent(inout) :: xyzh(:,:),vxyzu(:,:) integer :: i - + if (.not. do_radiation) call fatal("moddump_rad_to_LTE","Not compiled with radiation") do i=1,npart if (isnan(rad(iradxi,i))) call fatal("moddump_rad_to_LTE","rad array contains NaNs") @@ -51,7 +42,6 @@ subroutine modify_dump(npart,npartoftype,massoftype,xyzh,vxyzu) print*,'mu has been changed to',gmw ! mu should not change from what was assumed with radiation end subroutine modify_dump - + end module moddump - - \ No newline at end of file + diff --git a/src/utils/utils_ephemeris.f90 b/src/utils/utils_ephemeris.f90 new file mode 100644 index 000000000..66664e39c --- /dev/null +++ b/src/utils/utils_ephemeris.f90 @@ -0,0 +1,215 @@ +!--------------------------------------------------------------------------! +! The Phantom Smoothed Particle Hydrodynamics code, by Daniel Price et al. ! +! Copyright (c) 2007-2023 The Authors (see AUTHORS) ! +! See LICENCE file for usage and distribution conditions ! +! http://phantomsph.bitbucket.io/ ! +!--------------------------------------------------------------------------! +module ephemeris +! +! Download and read data files from the JPL horizons ephemeris service +! +! :References: +! https://ssd-api.jpl.nasa.gov/doc/horizons.html +! +! :Owner: Daniel Price +! +! :Runtime parameters: None +! +! :Dependencies: datautils, fileutils +! + implicit none + integer, parameter :: nelem = 7 + + public :: get_ephemeris,nelem + + private + +contains + +!----------------------------------------------------------------------- +!+ +! read data files from the JPL Horizons ephemeris server +!+ +!----------------------------------------------------------------------- +function get_ephemeris(object,ierr) result(elems) + use datautils, only:download_datafile + character(len=*), intent(in) :: object ! name of the solar system object + integer, intent(out) :: ierr + real :: elems(nelem) + character(len=512) :: url + character(len=30) :: localfile,filepath + logical :: iexist + integer :: ierr2 + + ierr = 0 + localfile = trim(object)//'.txt' + inquire(file=localfile,exist=iexist) + if (.not.iexist) then + call construct_horizons_api_url(trim(object),url,ierr) + if (ierr /= 0) then + print*,' ERROR: could not query horizons database for object='//trim(object) + return + endif + call download_datafile(url=url,dir=localfile,filename='',filepath=filepath,ierr=ierr) + else + filepath = localfile + endif + + call read_ephemeris_file(filepath,elems,ierr2) + if (ierr2 /= 0) ierr = ierr2 + +end function get_ephemeris + +!----------------------------------------------------------------------- +!+ +! construct API call to the JPL Horizons ephemeris server +!+ +!----------------------------------------------------------------------- +subroutine construct_horizons_api_url(object,url,ierr) + character(len=*), intent(in) :: object ! name of the solar system object + character(len=*), intent(out) :: url ! url for query + integer, intent(out) :: ierr + character(len=3) :: cmd + character(len=10) :: start_epoch,end_epoch + integer(kind=8) :: values(8),year,month,day + + ierr = 0 + select case(trim(adjustl(object))) + case('pluto') + cmd = '999' ! pluto barycentre + case('neptune') + cmd = '899' ! neptune barycentre + case('uranus') + cmd = '799' ! uranus barycentre + case('saturn') + cmd = '699' ! saturn barycentre + case('jupiter') + cmd = '599' ! jupiter barycentre + case('mars') + cmd = '499' ! mars barycentre + case('earth') + cmd = '399' ! earth-moon barycentre + case('venus') + cmd = '299' ! venus barycentre + case('mercury') + cmd = '199' ! mercury barycentre + case default + ierr = 1 + end select + + !if (present(epoch)) then +! start_epoch = epoch + !else + call date_and_time(values=values) + year = values(1); month = values(2); day = values(3) + write(start_epoch,"(i4.4,'-',i2.2,'-',i2.2)") year,month,day + write(end_epoch,"(i4.4,'-',i2.2,'-',i2.2)") year,month,day+1 + !endif + + url = "'https://ssd.jpl.nasa.gov/api/horizons.api?format=text&COMMAND='"//trim(cmd)// & + "'&OBJ_DATA='YES'&MAKE_EPHEM='YES'&EPHEM_TYPE='ELEMENTS'&CENTER='500@10'&START_TIME='"& + //trim(start_epoch)//"'&STOP_TIME='"//trim(end_epoch)// & + "'&STEP_SIZE='1DAYS'&REF_SYSTEM='ICRF'&REF_PLANE='ECLIPTIC''" + +end subroutine construct_horizons_api_url + +!----------------------------------------------------------------------- +!+ +! read required information from the ephemeris data file +!+ +!----------------------------------------------------------------------- +subroutine read_ephemeris_file(file,elems,ierr) + character(len=*), intent(in) :: file + real, intent(out) :: elems(nelem) + integer, intent(out) :: ierr + integer :: iu,j + character(len=80) :: line + character(len=*), parameter :: tag(nelem) = & + (/'GM km^3/s^2',& + 'A ',& + 'EC ',& + 'IN ',& + 'OM ',& + 'W ',& + 'TA '/) + logical :: got_elem(nelem) + + ! give default parameters + got_elem(:) = .false. + elems(:) = 0. + + open(newunit=iu,file=file,status='old',iostat=ierr) + if (ierr /= 0) then + print "(a)",' ERROR opening '//trim(file) + return + endif + print "(/,a)",' > reading ephemeris from '//trim(file) + do while(ierr == 0) + read(iu,"(a)",iostat=ierr) line + do j=1,nelem + if (.not.got_elem(j)) then + call read_value(line,tag(j),elems(j),got_elem(j)) + endif + enddo + enddo + ierr = 0 + print "(a,/)" + do j=1,nelem + if (.not.got_elem(j)) then + print*,' ERROR: could not find '//trim(tag(j))//' in '//trim(file) + ierr = ierr + 1 + endif + enddo + close(iu) + +end subroutine read_ephemeris_file + +!----------------------------------------------------------------------- +!+ +! utility routine to read a var = blah string from the ephemeris file +!+ +!----------------------------------------------------------------------- +subroutine read_value(line,tag,val,got_val) + use fileutils, only:string_delete,string_replace + character(len=*), intent(in) :: line, tag + real, intent(out) :: val + logical, intent(inout) :: got_val + character(len=len(line)) :: string + integer :: ieq,j,ierr + + val = 0. + if (.not.got_val) then + ! make a copy of the line string + string = line + + call string_delete(string,'(planet)') ! pluto has GM(planet) km^3/s^2 + + ! delete double spaces + call string_replace(string,' ',' ') + call string_delete(string,'(') + call string_delete(string,')') + call string_delete(string,',') + + ! add space at start of string if necessary + if (string(1:1) /= ' ') string = ' '//trim(string) + + ! search for ' TAG = value' in the line, including spaces + ! to avoid confusion of A = val with TA= val + j = max(index(string,' '//trim(tag)//' ='),index(string,' '//trim(tag)//'=')) + + ! if we get a match read the value from what is after the equals sign + if (j > 0) then + string = string(j:) ! start + ieq = index(string,'=') + read(string(ieq+1:),*,iostat=ierr) val + if (ierr == 0) then + ! mark this quantity as having already been read + write(*,"(1x,a,g0)",advance='no') trim(tag)//' = ',val + got_val = .true. + endif + endif + endif + +end subroutine read_value + +end module ephemeris diff --git a/src/utils/utils_mpc.f90 b/src/utils/utils_mpc.f90 index 9a14e5f30..269a5c296 100644 --- a/src/utils/utils_mpc.f90 +++ b/src/utils/utils_mpc.f90 @@ -28,7 +28,7 @@ module mpc ! :References: ! https://minorplanetcenter.net/Extended_Files/Extended_MPCORB_Data_Format_Manual.pdf ! -! :Owner: Not Committed Yet +! :Owner: Daniel Price ! ! :Runtime parameters: None !