Compare commits

...

44 Commits

Author SHA1 Message Date
Daniele Micheletti
56b8700af3 refl/gray/after_onestep: fixed test for search of ray that completed 1st pass in plasma 2019-03-14 10:53:34 +00:00
Daniele Micheletti
49303ac2e3 refl/gray/after_onestep: fixed test for 2nd pass, fixed exin2,eyin2 evaluation, added test for powrfl<0 2019-03-14 10:47:39 +00:00
4c508f0943 fixed rhot print in central ray output (fort.4) 2017-02-10 10:41:24 +00:00
88705d8231 warmdisp bug fixed in trunk propagated to branches/refl 2016-06-09 08:32:14 +00:00
0aa1bb3537 removed obsolete branches; added templates for input files in trunk/input and branches/refl/input 2016-01-26 10:32:29 +00:00
Daniele Micheletti
8e621d0dac addedd missing term in dbgr computation (fwork) in refl branch 2016-01-26 09:21:06 +00:00
Daniele Micheletti
c0c966af96 added branch for multiple passes (from nocommon rev142); fixed initial condition for second pass, new dispersion module for low density 2016-01-26 09:14:47 +00:00
Daniele Micheletti
e1ba175efb added test in pol_limit for anpl=0 to avoid 0/0 expressions 2015-10-14 10:26:05 +00:00
af5fb208b2 inclusion of updated routines for analytical equilibrium/profiles; further cleaning of equidata 2015-10-12 17:09:28 +00:00
Daniela Farina
79c080b14d bugs fixed in eccdeff, density and zeffan 2015-10-12 11:29:53 +00:00
61c97e3357 corrected bug in equinum_fpol: vacuum value was returned for psin=0 2015-10-02 15:09:10 +00:00
dcd3badba9 partial upgrade of equidata and auxiliary routines 2015-10-02 14:10:38 +00:00
2856725b49 partial changes uploaded by mistake in the previous revision. gray, interp_eqprof and reflections were in an inconsistent state 2015-09-18 10:24:24 +00:00
c06fbf3d4f cleaned arguments list in diel_tens_fr 2015-09-17 15:46:21 +00:00
b9b6d3e8f4 split profdata routine and moved in coreprof module 2015-07-16 16:48:27 +00:00
Daniele Micheletti
667f6fd111 subroutine wall_refl moved in reflections module, rlim,zlim,nlim moved from interp_eqprof to reflections module 2015-07-16 14:47:56 +00:00
dcc199b336 added missing file 2015-07-16 14:14:10 +00:00
c6c1395cff updated bfield routine, replacing btor/bpol; btotal passed explicitly to cniteq; equian partially modified (psinv passed as argument) 2015-07-16 10:36:03 +00:00
321d870431 started reorganization of interp_eqprof (equilibrium) and coreprofiles modules 2015-07-13 14:50:41 +00:00
Daniela Farina
900a51a08c modified density smoothing at the boundary 2015-07-10 15:29:44 +00:00
87de4c9cc2 all subroutines for CD computation grouped in eccd module 2015-06-24 17:10:45 +00:00
Daniela Farina
e92ff7cee1 pec subroutine(s) updated 2015-06-19 13:07:49 +00:00
771cdb3822 changes in rhotor interpolation merged from trunk into nocommon 2015-06-19 10:22:49 +00:00
464af38310 further cleaning of eccd routines 2015-06-19 09:11:33 +00:00
2333f83914 some cleaning in eccd routines 2015-06-17 09:50:00 +00:00
Daniele Micheletti
cc9a10a525 added module beamdata in nocommon branch 2015-06-16 09:34:35 +00:00
9a64cc5e59 changed a few dynamic allocations into automatic 2015-06-15 16:25:00 +00:00
e31949e5ae Corrected mistype in surf_anal 2015-06-15 15:36:18 +00:00
20e68d468f Hlambda function now evaluated from 1D spline in fjncl integration (mom. cons. CD model). Cleaned unused variables. 2015-06-15 15:35:15 +00:00
Daniele Micheletti
f755232b01 updated declarative section in gray.f in nocommon branch 2015-06-12 14:53:29 +00:00
5f8f6c454d spline modules added, grayl removed 2015-06-12 12:08:45 +00:00
139f42fee2 grayl split in several f90 modules. only spline routines missing. 2015-06-12 10:25:18 +00:00
1e1406ff2a calcei module replaced with eierf, calerf removed from grayl. 2015-06-11 16:48:56 +00:00
f8c7aaf924 explicit declaration in modules use 2015-06-11 16:40:33 +00:00
Daniele Micheletti
88d0bffa22 added modules not previously uploaded in nocommon and gray-jintrac branches 2015-06-10 13:22:01 +00:00
Daniele Micheletti
31ecfb6be4 updated declarative section in module dispersion in nocommon branch 2015-06-10 07:35:02 +00:00
Daniele Micheletti
79af5f0b4b added modules graydata_flags, graydata_par, graydata_anequil, interp_eqprof, magsurf_data in nocommon branch 2015-06-08 14:06:03 +00:00
97c9eff345 dispersion module added in nocommon branch 2015-05-25 15:30:00 +00:00
20ce211eef removed duplicated declaration in ic_rt 2015-05-22 13:17:32 +00:00
bd8b185ddc changes in trunk / new-refl / new-equinum up to rev 101 merged into branch nocommon 2015-05-21 16:00:41 +00:00
2a05888c60 grayvg branch integrated in gaussfit. other branches synced 2015-05-21 10:52:04 +00:00
e31f05e9a8 moved all the definitions of arithmetical, physical and type kind constants in const_and_precisions. Changed argument from tekev to mu in spitzer function subroutines. 2015-05-15 16:02:27 +00:00
045c581865 other variables moved from common to argument list in eccd. fixed print of nharm in print_output, added missin /ierr/ common in ecrh_cd 2015-05-13 16:27:52 +00:00
3b24d5d58d created branch for code restructuring (progressive removal of common statements, dynamic allocation, etc). curr_int subroutine (and dependencies) partially updated. 2015-05-13 13:19:29 +00:00
27 changed files with 20087 additions and 16986 deletions

View File

@ -2,40 +2,63 @@
EXE=gray
# Objects list
OBJ=gray.o grayl.o reflections.o green_func_p.o \
const_and_precisions.o itm_constants.o itm_types.o
MAINOBJ=gray.o
OTHOBJ=conical.o const_and_precisions.o coreprofiles.o dierckx.o dispersion.o \
eccd.o eierf.o graydata_anequil.o graydata_flags.o graydata_par.o \
equilibrium.o magsurf_data.o math.o minpack.o numint.o quadpack.o \
reflections.o simplespline.o utils.o beamdata.o
# Alternative search paths
vpath %.f90 src
vpath %.f src
# Fortran compiler name and flags
FC=gfortran
FFLAGS=-Wall -fcheck=all
FFLAGS=-Wall -g -fcheck=all
DIRECTIVES = -DREVISION="'$(shell svnversion src)'"
all: $(EXE)
# Build executable from object files
$(EXE): $(OBJ)
$(EXE): $(MAINOBJ) $(OTHOBJ)
$(FC) $(FFLAGS) -o $@ $^
# Dependencies on modules
gray.o: green_func_p.o reflections.o
green_func_p.o: const_and_precisions.o
const_and_precisions.o: itm_types.o itm_constants.o
itm_constants.o: itm_types.o
gray.o: const_and_precisions.o coreprofiles.o dierckx.o dispersion.o eccd.o \
graydata_anequil.o graydata_flags.o graydata_par.o \
equilibrium.o magsurf_data.o math.o numint.o quadpack.o \
reflections.o simplespline.o utils.o beamdata.o
conical.o: const_and_precisions.o
coreprofiles.o: const_and_precisions.o dierckx.o graydata_anequil.o \
graydata_flags.o simplespline.o utils.o
dierckx.o: const_and_precisions.o
dispersion.o: const_and_precisions.o eierf.o math.o quadpack.o
eccd.o: const_and_precisions.o conical.o magsurf_data.o dierckx.o numint.o
eierf.o: const_and_precisions.o
graydata_anequil.o: const_and_precisions.o
graydata_flags.o: const_and_precisions.o
graydata_par.o: const_and_precisions.o
equilibrium.o: const_and_precisions.o dierckx.o minpack.o simplespline.o utils.o
magsurf_data.o: const_and_precisions.o
math.o: const_and_precisions.o
minpack.o: const_and_precisions.o
numint.o: const_and_precisions.o
quadpack.o: const_and_precisions.o
reflections.o: const_and_precisions.o utils.o
simplespline.o: const_and_precisions.o
utils.o: const_and_precisions.o
beamdata.o: const_and_precisions.o
# General object compilation command
%.o: %.f90
$(FC) $(FFLAGS) -c $<
gray.o:gray.f green_func_p.o
$(FC) -cpp $(DIRECTIVES) $(FFLAGS) -c $<
%.o: %.f
$(FC) $(FFLAGS) -c $<
grayl.o:grayl.f
$(FC) $(FFLAGS) -c $^
gray.o:gray.f
$(FC) -cpp $(DIRECTIVES) $(FFLAGS) -c $<
.PHONY: clean install
# Remove output files

28
input/gray.data Normal file
View File

@ -0,0 +1,28 @@
40. 0. : alfac, betac poloidal and toroidal launching angles
82.7 : f (GHz)
1 : P0 (MW) injected power
1 1 1 : nray ktx,rhomx
123. 0. 50. : x00 y00 z00 (cm) mirror position (y00=0 !)
2.1 2.1 162 162 0 : w0xt w0yt pw0xt pw0yt awr (cm) [pw0>0 towards plasma]
0 : ibeam=0 uses data above, >0 read from file beam data (1,2,3)
mpusm : filename.txt for beam data max(character*16)
2 0 : iequil= 0 vacuum, 1 analytical equilibrium, 2 EQDSK;indXpoint
0 : iprof= 0/1 analytical/numerical dens & temp profiles
1 2 -10 : iwarm= 0-3 ECRH&CD computation, ilarm order of larmor expans
0 : ieccd 0/1 NO/YES ECCD calculation
1 251 : ipec=0/1 profiles in dpsi/drhop; nnd=no. intervals +1 (=< 501)
.01 50000 100 5 1 : dst (cm), nsteps < = 8000, istprj,istpl,ist (0,1,2 integration in s,ct,Sr)
0 -2 0.624 : igrad (0 rtr - 1 gauss beam), ipass=1/2 passes in plasma, R_wall(m)
2 0 0 0 : IOX = 1 : O-MODE IOX = 2 : X-MODE, psi_pol_ant chi_pol_ant
TCV : filename EQDSK : filename.eqdsk max(character 16)
0 0.001 0 1 : ipsinorm =0/1 [psi normalized (1) or not (0) in EQDSK], sspl spline coeff psi
1 1 1 1 : factb, iscal=0/1/2 nustar=const/ngreenw=const/no_scal, factT factn scal.
filename : filename profiles : filename.prf max(character*16)
1.015 : psi plasma boundary
-1 -1 2 : signum B_phi I_phi +1=counterclockwise , -1=clockwise from above, icocos (0 old case, 11 iter)
9.99999999999999999992 8 8 : dens190 aln1,aln2 (10^19 m-3)
4.99999999999999999424 0 8 8 : te0,dte0,alt1,alt2 (keV)
2 : Zeff
620 0 180 : rr0 zr0 a (cm)
5.3 : b0 (T)
1 3 2 : q0,qa alq

80
src/beamdata.f90 Normal file
View File

@ -0,0 +1,80 @@
module beamdata
use const_and_precisions, only : wp_
implicit none
integer, parameter :: jmx=31,kmx=36,nmx=100000
integer, save :: nrayr,nrayth,nstep
real(wp_), dimension(:,:,:), allocatable, save :: psjki,ppabs,ccci,tauv,alphav
real(wp_), dimension(:,:,:), allocatable, save :: pdjki,currj,didst
integer, dimension(:,:), allocatable, save :: iiv,iop,iow,ihcd,istore
real(wp_), dimension(:,:), allocatable, save :: tau1v
real(wp_), dimension(:), allocatable, save :: q
real(wp_), dimension(:,:,:), allocatable, save :: yyrfl !(:,:,6)
real(wp_), dimension(:,:,:), allocatable, save :: ywrk,ypwrk !(6,:,:)
real(wp_), dimension(:,:,:), allocatable, save :: xc,xco,du1,du1o !(3,:,:)
real(wp_), dimension(:,:,:), allocatable, save :: gri,dgrad2v !(3,:,:)
real(wp_), dimension(:,:,:,:), allocatable, save :: ggri !(3,3,:,:)
real(wp_), dimension(:,:), allocatable, save :: grad2
real(wp_), dimension(:), allocatable, save :: dffiu,ddffiu
complex(wp_), dimension(:,:,:), allocatable, save :: ext,eyt
contains
subroutine alloc_beam(ierr)
implicit none
integer, intent(out) :: ierr
call dealloc_beam
allocate(psjki(nrayr,nrayth,nstep), ppabs(nrayr,nrayth,nstep), &
pdjki(nrayr,nrayth,nstep), ccci(nrayr,nrayth,nstep), &
currj(nrayr,nrayth,nstep), didst(nrayr,nrayth,nstep), &
tauv(nrayr,nrayth,nstep), alphav(nrayr,nrayth,nstep), &
iiv(nrayr,nrayth), iop(nrayr,nrayth), &
iow(nrayr,nrayth), tau1v(nrayr,nrayth), &
ihcd(nrayr,nrayth), istore(nrayr,nrayth), &
q(nrayr), yyrfl(nrayr,nrayth,6), &
ywrk(6,nrayr,nrayth), ypwrk(6,nrayr,nrayth), &
xc(3,nrayr,nrayth), xco(3,nrayr,nrayth), &
du1(3,nrayr,nrayth), du1o(3,nrayr,nrayth), &
gri(3,nrayr,nrayth), dgrad2v(3,nrayr,nrayth), &
ggri(3,3,nrayr,nrayth), grad2(nrayr,nrayth), &
dffiu(nrayr), ddffiu(nrayr), &
ext(nrayr,nrayth,0:4), eyt(nrayr,nrayth,0:4), &
stat=ierr)
if (ierr/=0) call dealloc_beam
end subroutine alloc_beam
subroutine dealloc_beam
implicit none
if (allocated(psjki)) deallocate(psjki)
if (allocated(ppabs)) deallocate(ppabs)
if (allocated(pdjki)) deallocate(pdjki)
if (allocated(ccci)) deallocate(ccci)
if (allocated(currj)) deallocate(currj)
if (allocated(didst)) deallocate(didst)
if (allocated(tauv)) deallocate(tauv)
if (allocated(alphav)) deallocate(alphav)
if (allocated(iiv)) deallocate(iiv)
if (allocated(iop)) deallocate(iop)
if (allocated(iow)) deallocate(iow)
if (allocated(ihcd)) deallocate(ihcd)
if (allocated(istore)) deallocate(istore)
if (allocated(tau1v)) deallocate(tau1v)
if (allocated(q)) deallocate(q)
if (allocated(yyrfl)) deallocate(yyrfl)
if (allocated(ywrk)) deallocate(ywrk)
if (allocated(ypwrk)) deallocate(ypwrk)
if (allocated(xc)) deallocate(xc)
if (allocated(xco)) deallocate(xco)
if (allocated(du1)) deallocate(du1)
if (allocated(du1o)) deallocate(du1o)
if (allocated(gri)) deallocate(gri)
if (allocated(dgrad2v)) deallocate(dgrad2v)
if (allocated(ggri)) deallocate(ggri)
if (allocated(grad2)) deallocate(grad2)
if (allocated(dffiu)) deallocate(dffiu)
if (allocated(ddffiu)) deallocate(ddffiu)
if (allocated(ext)) deallocate(ext)
if (allocated(eyt)) deallocate(eyt)
end subroutine dealloc_beam
end module beamdata

853
src/conical.f90 Normal file
View File

@ -0,0 +1,853 @@
module conical
use const_and_precisions, only : wp_
implicit none
contains
function fconic(x,tau,m)
!
! this function subprogram computes the conical functions of the
! first kind P sub(-1/2 + i*tau) (x) for m = 0 and m = 1.
! Ref. in Kolbig, Comp. Phys. Commun. 23 (1981) 51
!
implicit none
real(wp_), intent(in) :: x, tau
integer, intent(in) :: m
real(wp_) :: fconic
real(wp_) :: t(7),h(9),v(11)
real(wp_) :: aa,a0,a1,a2,a3,a4,a5,a6,b0,b1,fm,fn,fn1,r1,r2,s,s0,s1
real(wp_) :: x1,y,y2,y3,z
integer :: jp,j,n
real(wp_), parameter :: rpi=1.7724538509055_wp_,pi2=0.63661977236758_wp_
real(wp_), parameter :: eps=1.0e-14_wp_
integer, parameter :: nout=2,nmax=200
!
complex(wp_) a,b,c,ti,r,rr,q,u,u0,u1,u2,uu
complex(wp_) v0,v1,v2,vv,w(19)
!
logical lm0,lm1,lta
fconic=0.0_wp_
lm0=m == 0
lm1=m == 1
if(.not.(lm0 .or. lm1)) then
write(nout,"(1x,'fconic ... illegal value for m = ',i4)") m
return
end if
fm=m
fconic=1.0_wp_-fm
if(x == 1.0_wp_) return
!
fconic=0.0_wp_
if(tau == 0.0_wp_ .and. abs(x-1.0_wp_) > 0.01_wp_) then
if(x > 1.0_wp_) then
y=sqrt((x-1.0_wp_)/(x+1.0_wp_))
z=ellick(y)
s=sqrt(0.5_wp_*(x+1.0_wp_))
if(lm0) fconic=pi2*z/s
if(lm1) fconic=pi2*s*(ellice(y)-z)/sqrt(x**2-1.0_wp_)
return
else
y=sqrt(0.5_wp_*(1.0_wp_-x))
z=ellick(y)
if(lm0) fconic=pi2*z
if(lm1) fconic=pi2*(ellice(y)-0.5_wp_*(1.0_wp_+x)*z)/ &
sqrt(1.0_wp_-x**2)
return
end if
else
ti=cmplx(0._wp_,tau,wp_)
!
if((-1._wp_ < x .and. x <= 0.0_wp_).or. &
(0.0_wp_ < x .and. x <= 0.1_wp_ .and.tau<= 17.0_wp_).or. &
(0.1_wp_ < x .and. x <= 0.2_wp_ .and.tau<= 5.0_wp_)) then
lta=tau <= 10.0_wp_
x1=x**2
a=0.5_wp_*(0.5_wp_-fm-ti)
b=0.5_wp_*(0.5_wp_-fm+ti)
c=0.5_wp_
jp=30
else if((0.1_wp_ < x .and. x <= 0.2_wp_ .and.tau<= 17.0_wp_) &
.or.(0.2_wp_ < x .and. x <= 1.5_wp_ .and.tau<= 20.0_wp_)) &
then
lta=x > 1.0_wp_ .or. x <= 1.0_wp_ .and. tau <= 5.0_wp_
x1=(1.0_wp_-x)/2._wp_
a=0.5_wp_+fm-ti
b=0.5_wp_+fm+ti
c=fm+1.0_wp_
jp=32
else if(1.5_wp_ < x .and. tau <= max(20.0_wp_,x)) then
lta=.true.
x1=1.0_wp_/x**2
u=exp((-0.5_wp_+ti)*log(2.0_wp_*x)+clogam(1.0_wp_+ti) &
-clogam(1.5_wp_-fm+ti))
a=0.5_wp_*(0.5_wp_-fm-ti)
b=0.5_wp_*(1.5_wp_-fm-ti)
c=1.0_wp_-ti
jp=33
else
if(x > 1.0_wp_) then
s=sqrt(x**2-1.0_wp_)
t(1)=log(x+s)
h(1)=tau*t(1)
b0=besj0l(h(1))
b1=besj1l(h(1))
z=1.0_wp_
else
s=sqrt(1.0_wp_-x**2)
t(1)=acos(x)
h(1)=tau*t(1)
b0=besi0(h(1))
b1=besi1(h(1))
z=-1.0_wp_
end if
h(1)=t(1)*x/s
v(1)=tau
do j = 2,7
t(j)=t(j-1)*t(1)
h(j)=h(j-1)*h(1)
end do
do j = 2,11
v(j)=v(j-1)*v(1)
end do
!
if(lm1) then
aa=-1.0_wp_
a0=3.0_wp_*(1.0_wp_-h(1))/(8.0_wp_*t(1))
a1=(-15.0_wp_*h(2)+6.0_wp_*h(1)+9.0_wp_+z*8.0_wp_*t(2))/ &
(128.0_wp_*t(2))
a2=3.0_wp_*(-35.0_wp_*h(3)-15.0_wp_*h(2)+15.0_wp_*h(1)+35.0_wp_ &
+z*t(2)*(32.0_wp_*h(1)+8.0_wp_))/(1024.0_wp_*t(3))
a3=(-4725.0_wp_*h(4)-6300.0_wp_*h(3)-3150.0_wp_*h(2)+3780.0_wp_*h(1) &
+10395.0_wp_-1216.0_wp_*t(4)+z*t(2)*(6000.0_wp_*h(2) &
+5760.0_wp_*h(1)+1680.0_wp_)) /(32768.0_wp_*t(4))
a4=7.0_wp_*(-10395.0_wp_*h(5)-23625.0_wp_*h(4)-28350.0_wp_*h(3) &
-14850.0_wp_*h(2)+19305.0_wp_*h(1)+57915.0_wp_ &
-t(4)*(6336.0_wp_*h(1)+6080.0_wp_)+z*t(2)*(16800.0_wp_*h(3) &
+30000.0_wp_*h(2)+25920.0_wp_*h(1)+7920.0_wp_))/ &
(262144.0_wp_*t(5))
a5=(-2837835.0_wp_*h(6)-9168390.0_wp_*h(5)-16372125.0_wp_*h(4) &
-18918900*h(3) -10135125.0_wp_*h(2)+13783770.0_wp_*h(1) &
+43648605.0_wp_-t(4)*(3044160.0_wp_*h(2)+5588352.0_wp_*h(1) &
+4213440.0_wp_)+z*t(2)*(5556600.0_wp_*h(4)+14817600.0_wp_*h(3) &
+20790000.0_wp_*h(2)+17297280.0_wp_*h(1)+5405400.0_wp_ &
+323072.0_wp_*t(4)))/ (4194304.0_wp_*t(6))
a6=0.0_wp_
else
aa=0.0_wp_
a0=1.0_wp_
a1=(h(1)-1.0_wp_)/(8.0_wp_*t(1))
a2=(9.0_wp_*h(2)+6.0_wp_*h(1)-15.0_wp_-z*8.0_wp_*t(2))/ &
(128.0_wp_*t(2))
a3=5.0_wp_*(15.0_wp_*h(3)+27.0_wp_*h(2)+21.0_wp_*h(1)-63.0_wp_ &
-z*t(2)*(16.0_wp_*h(1)+24.0_wp_))/(1024.0_wp_*t(3))
a4=7.0_wp_*(525.0_wp_*h(4)+1500.0_wp_*h(3)+2430.0_wp_*h(2) &
+1980.0_wp_*h(1)-6435.0_wp_+192.0_wp_*t(4)-z*t(2)* &
(720.0_wp_*h(2)+1600.0_wp_*h(1)+2160.0_wp_))/(32768.0_wp_*t(4))
a5=21.0_wp_*(2835.0_wp_*h(5)+11025.0_wp_*h(4)+24750.0_wp_*h(3) &
+38610.0_wp_*h(2)+32175.0_wp_*h(1)-109395.0_wp_+t(4) &
*(1984.0_wp_*h(1)+4032.0_wp_)-z*t(2) &
*(4800.0_wp_*h(3)+15120.0_wp_*h(2)+26400.0_wp_*h(1)+34320.0_wp_)) &
/(262144.0_wp_*t(5))
a6=11.0_wp_*(218295.0_wp_*h(6)+1071630.0_wp_*h(5)+3009825.0_wp_*h(4) &
+6142500.0_wp_*h(3)+9398025.0_wp_*h(2)+7936110.0_wp_*h(1) &
-27776385.0_wp_+t(4)*(254016.0_wp_*h(2) &
+749952.0_wp_*h(1)+1100736.0_wp_)-z*t(2)*(441000.0_wp_*h(4) &
+1814400.0_wp_*h(3)+4127760.0_wp_*h(2)+6552000.0_wp_*h(1) &
+8353800.0_wp_+31232.0_wp_*t(4)))/(4194304.0_wp_*t(6))
end if
s0=a0+(-4.0_wp_*a3/t(1)+a4)/v(4)+(-192.0_wp_*a5/t(3) &
+144.0_wp_*a6/t(2))/v(8)+z*(-a2/v(2)+(-24.0_wp_*a4/t(2) &
+12.0_wp_*a5/t(1)-a6)/v(6)+(-1920.0_wp_*a6/t(4))/v(10))
s1=a1/v(1)+(8.0_wp_*(a3/t(2)-a4/t(1))+a5)/v(5)+(384.0_wp_*a5/t(4) &
-768.0_wp_*a6/t(3))/v(9)+z*(aa*v(1)+(2.0_wp_*a2/t(1)-a3)/v(3) &
+(48.0_wp_*a4/t(3)-72.0_wp_*a5/t(2) &
+18.0_wp_*a6/t(1))/v(7)+(3840.0_wp_*a6/t(5))/v(11))
fconic=sqrt(t(1)/s)*(b0*s0+b1*s1)
return
end if
!
do
if(lta) then
y=-x1
y2=y**2
y3=y**3
w(1)=a+1.0_wp_
w(2)=a+2.0_wp_
w(3)=b+1.0_wp_
w(4)=b+2.0_wp_
w(5)=c+1.0_wp_
w(6)=c*w(5)
w(7)=a+b
w(8)=a*b
w(9)=(w(8)/c)*y
w(10)=w(1)*w(3)
w(11)=w(2)*w(4)
w(12)=1.0_wp_+(w(11)/(2.0_wp_*w(5)))*y
w(13)=w(7)-6.0_wp_
w(14)=w(7)+6.0_wp_
w(15)=2.0_wp_-w(8)
w(16)=w(15)-2.0_wp_*w(7)
!
v0=1.0_wp_
v1=1.0_wp_+(w(10)/(2.0_wp_*c))*y
v2=w(12)+(w(10)*w(11)/(12.0_wp_*w(6)))*y2
u0=1.0_wp_
u1=v1-w(9)
u2=v2-w(9)*w(12)+(w(8)*w(10)/(2.0_wp_*w(6)))*y2
!
r=1.0_wp_
n=2
do
n=n+1
if(n > nmax) then
write(nout,200) x,tau,m
return
end if
rr=r
fn=n
h(1)=fn-1.0_wp_
h(2)=fn-2.0_wp_
h(3)=fn-3.0_wp_
h(4)=2.0_wp_*fn
h(5)=h(4)-3.0_wp_
h(6)=2.0_wp_*h(5)
h(7)=4.0_wp_*(h(4)-1.0_wp_)*h(5)
h(8)=8.0_wp_*h(5)**2*(h(4)-5.0_wp_)
h(9)=3.0_wp_*fn**2
w(1)=a+h(1)
w(2)=a+h(2)
w(3)=b+h(1)
w(4)=b+h(2)
w(5)=c+h(1)
w(6)=c+h(2)
w(7)=c+h(3)
w(8)=h(2)-a
w(9)=h(2)-b
w(10)=h(1)-c
w(11)=w(1)*w(3)
w(12)=w(5)*w(6)
!
w(17)=1.0_wp_+((h(9)+w(13)*fn+w(16))/(h(6)*w(5)))*y
w(18)=-((w(11)*w(10)/h(6)+(h(9)-w(14)*fn+w(15))* &
w(11)*y/h(7))/w(12))*y
w(19)=(w(2)*w(11)*w(4)*w(8)*w(9)/(h(8)*w(7)*w(12)))*y3
vv=w(17)*v2+w(18)*v1+w(19)*v0
uu=w(17)*u2+w(18)*u1+w(19)*u0
r=uu/vv
if(abs(r-rr) < eps) exit
v0=v1
v1=v2
v2=vv
u0=u1
u1=u2
u2=uu
end do
else
r=1.0_wp_
q=1.0_wp_
do n = 1,nmax
fn=n
fn1=fn-1.0_wp_
rr=r
q=q*x1*(a+fn1)*(b+fn1)/((c+fn1)*fn)
r=r+q
if(abs(r-rr) < eps) exit
end do
if (n > nmax) then
write(nout,200) x,tau,m
return
end if
end if
if (jp/=30) exit
r1=real(r)/abs(exp(clogam(a+0.5_wp_)))**2
a=0.5_wp_*(1.5_wp_-fm-ti)
b=0.5_wp_*(1.5_wp_-fm+ti)
c=1.5_wp_
jp=31
end do
if (jp==31) then
r2=real(r)/abs(exp(clogam(a-0.5_wp_)))**2
fconic=rpi*(r1-2.0_wp_*x*r2)
if(lm1) fconic=(2.0_wp_/sqrt(1.0_wp_-x1))*fconic
return
else if (jp==32) then
fconic=real(r)
if(.not.lm0) then
fconic=0.5_wp_*(tau**2+0.25_wp_)*sqrt(abs(x**2-1.0_wp_))*fconic
if(x > 1.0_wp_) fconic=-fconic
end if
return
else if (jp==33) then
fconic=2.0_wp_*real(u*r*(0.5_wp_-fm+ti)/ti)/rpi
if(lm1) fconic=fconic/sqrt(1.0_wp_-x1)
return
end if
end if
!
200 format(1x,'fconic ... convergence difficulties for c function, x = ', &
e12.4,5x,'tau = ',e12.4,5x,'m = ',i5)
!
end function fconic
function clogam(z)
!
implicit none
complex(wp_) :: clogam
complex(wp_), intent(in) :: z
complex(wp_) :: v,h,r
integer :: i,n
real(wp_) :: x,t,a,c,d,e,f
integer, parameter :: nout=2
real(wp_), parameter :: pi=3.1415926535898_wp_
real(wp_), dimension(10), parameter :: b= &
(/+8.3333333333333e-2_wp_, -2.7777777777778e-3_wp_, &
+7.9365079365079e-4_wp_, -5.9523809523810e-4_wp_, &
+8.4175084175084e-4_wp_, -1.9175269175269e-3_wp_, &
+6.4102564102564e-3_wp_, -2.9550653594771e-2_wp_, &
+1.7964437236883e-1_wp_, -1.3924322169059e+0_wp_/)
!
x=real(z)
t=aimag(z)
if(-abs(x) == aint(x) .and. t == 0.0_wp_) then
write(nout,'(1x,f20.2)') x
clogam=(0.0_wp_,0.0_wp_)
return
end if
f=abs(t)
v=cmplx(x,f,wp_)
if(x < 0.0_wp_) v=1.0_wp_-v
h=(0.0_wp_,0.0_wp_)
c=real(v)
if(c < 7.0_wp_) then
n=6-int(c)
h=v
d=aimag(v)
a=atan2(d,c)
do i = 1,n
c=c+1.0_wp_
v=cmplx(c,d,wp_)
h=h*v
a=a+atan2(d,c)
end do
h=cmplx(0.5_wp_*log(real(h)**2+aimag(h)**2),a,wp_)
v=v+1.0_wp_
end if
r=1.0_wp_/v**2
clogam=0.91893853320467_wp_+(v-0.5_wp_)*log(v)-v+(b(1)+r*(b(2)+r*(b(3) &
+r*(b(4)+r*(b(5)+r*(b(6)+r*(b(7)+r*(b(8)+r*(b(9)+r*b(10)))))))))) &
/v-h
if(x < 0.0_wp_) then
!
a=aint(x)-1.0_wp_
c=pi*(x-a)
d=pi*f
e=exp(-2.0_wp_*d)
f=sin(c)
e=d+0.5_wp_*log(e*f**2+0.25_wp_*(1.0_wp_-e)**2)
f=atan2(cos(c)*tanh(d),f)-a*pi
clogam=1.1447298858494_wp_-cmplx(e,f,wp_)-clogam
!
end if
if(t < 0.0_wp_) clogam=conjg(clogam)
!
end function clogam
function ellick(xk)
implicit none
real(wp_), intent(in) :: xk
real(wp_) :: ellick, ellice
integer :: i
real(wp_) :: eta,pa,pb,pc,pd
real(wp_), dimension(10), parameter :: &
a=(/9.6573590280856e-2_wp_, 3.0885146271305e-2_wp_, &
1.4938013532687e-2_wp_, 8.7898018745551e-3_wp_, &
6.1796274460533e-3_wp_, 6.8479092826245e-3_wp_, &
9.8489293221769e-3_wp_, 8.0030039806500e-3_wp_, &
2.2966348983970e-3_wp_, 1.3930878570066e-4_wp_/), &
b=(/1.2499999999991e-1_wp_, 7.0312499739038e-2_wp_, &
4.8828041906862e-2_wp_, 3.7377739758624e-2_wp_, &
3.0124849012899e-2_wp_, 2.3931913323111e-2_wp_, &
1.5530941631977e-2_wp_, 5.9739042991554e-3_wp_, &
9.2155463496325e-4_wp_, 2.9700280966556e-5_wp_/), &
c=(/4.4314718056089e-1_wp_, 5.6805194567559e-2_wp_, &
2.1831811676130e-2_wp_, 1.1569595745295e-2_wp_, &
7.5950934225594e-3_wp_, 7.8204040609596e-3_wp_, &
1.0770635039866e-2_wp_, 8.6384421736041e-3_wp_, &
2.4685033304607e-3_wp_, 1.4946621757181e-4_wp_/), &
d=(/2.4999999999990e-1_wp_, 9.3749999721203e-2_wp_, &
5.8593661255531e-2_wp_, 4.2717890547383e-2_wp_, &
3.3478943665762e-2_wp_, 2.6145014700314e-2_wp_, &
1.6804023346363e-2_wp_, 6.4321465864383e-3_wp_, &
9.8983328462254e-4_wp_, 3.1859195655502e-5_wp_/)
!
if(abs(xk) >= 1.0_wp_) then
ellick=0.0_wp_
return
end if
eta=1.0_wp_-xk**2
pa=a(10)
do i = 1,9
pa=pa*eta+a(10-i)
end do
pa=pa*eta
pb=b(10)
do i = 1,9
pb=pb*eta+b(10-i)
end do
pb=pb*eta
ellick=1.3862943611199_wp_+pa-log(eta)*(0.5_wp_+pb)
return
!
entry ellice(xk)
!
if (abs(xk) >= 1.0_wp_) then
if (abs(xk) > 1.0_wp_) then
ellick=0.0_wp_
else
ellick=1.0_wp_
end if
return
end if
eta=1.0_wp_-xk**2
pc=c(10)
do i = 1,9
pc=pc*eta+c(10-i)
end do
pc=pc*eta
pd=d(10)
do i = 1,9
pd=pd*eta+d(10-i)
end do
pd=pd*eta
ellick=1.0_wp_+pc-log(eta)*pd
end function ellick
function besjy(x)
implicit none
real(wp_), intent(in) :: x
real(wp_) :: besjy,besj0l,besj1l
real(wp_) :: besy0,besy1
logical :: l
real(wp_) :: v,f,a,b,p,q
integer, parameter :: nout=2
!
entry besj0l(x)
!
l=.true.
v=abs(x)
if(v >= 8.0_wp_) go to 4
8 f=0.0625_wp_*x**2-2.0_wp_
a = - 0.0000000000000008_wp_
b = f * a + 0.0000000000000413_wp_
a = f * b - a - 0.0000000000019438_wp_
b = f * a - b + 0.0000000000784870_wp_
a = f * b - a - 0.0000000026792535_wp_
b = f * a - b + 0.0000000760816359_wp_
a = f * b - a - 0.0000017619469078_wp_
b = f * a - b + 0.0000324603288210_wp_
a = f * b - a - 0.0004606261662063_wp_
b = f * a - b + 0.0048191800694676_wp_
a = f * b - a - 0.0348937694114089_wp_
b = f * a - b + 0.1580671023320973_wp_
a = f * b - a - 0.3700949938726498_wp_
b = f * a - b + 0.2651786132033368_wp_
a = f * b - a - 0.0087234423528522_wp_
a = f * a - b + 0.3154559429497802_wp_
besjy=0.5_wp_*(a-b)
if(l) return
!
a = + 0.0000000000000016_wp_
b = f * a - 0.0000000000000875_wp_
a = f * b - a + 0.0000000000040263_wp_
b = f * a - b - 0.0000000001583755_wp_
a = f * b - a + 0.0000000052487948_wp_
b = f * a - b - 0.0000001440723327_wp_
a = f * b - a + 0.0000032065325377_wp_
b = f * a - b - 0.0000563207914106_wp_
a = f * b - a + 0.0007531135932578_wp_
b = f * a - b - 0.0072879624795521_wp_
a = f * b - a + 0.0471966895957634_wp_
b = f * a - b - 0.1773020127811436_wp_
a = f * b - a + 0.2615673462550466_wp_
b = f * a - b + 0.1790343140771827_wp_
a = f * b - a - 0.2744743055297453_wp_
a = f * a - b - 0.0662922264065699_wp_
besjy=0.636619772367581_wp_*log(x)*besjy+0.5_wp_*(a-b)
return
!
4 f=256.0_wp_/x**2-2.0_wp_
b = + 0.0000000000000007_wp_
a = f * b - 0.0000000000000051_wp_
b = f * a - b + 0.0000000000000433_wp_
a = f * b - a - 0.0000000000004305_wp_
b = f * a - b + 0.0000000000051683_wp_
a = f * b - a - 0.0000000000786409_wp_
b = f * a - b + 0.0000000016306465_wp_
a = f * b - a - 0.0000000517059454_wp_
b = f * a - b + 0.0000030751847875_wp_
a = f * b - a - 0.0005365220468132_wp_
a = f * a - b + 1.9989206986950373_wp_
p=a-b
b = - 0.0000000000000006_wp_
a = f * b + 0.0000000000000043_wp_
b = f * a - b - 0.0000000000000334_wp_
a = f * b - a + 0.0000000000003006_wp_
b = f * a - b - 0.0000000000032067_wp_
a = f * b - a + 0.0000000000422012_wp_
b = f * a - b - 0.0000000007271916_wp_
a = f * b - a + 0.0000000179724572_wp_
b = f * a - b - 0.0000007414498411_wp_
a = f * b - a + 0.0000683851994261_wp_
a = f * a - b - 0.0311117092106740_wp_
q=8.0_wp_*(a-b)/v
f=v-0.785398163397448_wp_
a=cos(f)
b=sin(f)
f=0.398942280401432_wp_/sqrt(v)
if(l) go to 6
besjy=f*(q*a+p*b)
return
6 besjy=f*(p*a-q*b)
return
!
entry besj1l(x)
!
l=.true.
v=abs(x)
if(v >= 8.0_wp_) go to 5
3 f=0.0625_wp_*x**2-2.0_wp_
b = + 0.0000000000000114_wp_
a = f * b - 0.0000000000005777_wp_
b = f * a - b + 0.0000000000252812_wp_
a = f * b - a - 0.0000000009424213_wp_
b = f * a - b + 0.0000000294970701_wp_
a = f * b - a - 0.0000007617587805_wp_
b = f * a - b + 0.0000158870192399_wp_
a = f * b - a - 0.0002604443893486_wp_
b = f * a - b + 0.0032402701826839_wp_
a = f * b - a - 0.0291755248061542_wp_
b = f * a - b + 0.1777091172397283_wp_
a = f * b - a - 0.6614439341345433_wp_
b = f * a - b + 1.2879940988576776_wp_
a = f * b - a - 1.1918011605412169_wp_
a = f * a - b + 1.2967175412105298_wp_
besjy=0.0625_wp_*(a-b)*x
if(l) return
!
b = - 0.0000000000000244_wp_
a = f * b + 0.0000000000012114_wp_
b = f * a - b - 0.0000000000517212_wp_
a = f * b - a + 0.0000000018754703_wp_
b = f * a - b - 0.0000000568844004_wp_
a = f * b - a + 0.0000014166243645_wp_
b = f * a - b - 0.0000283046401495_wp_
a = f * b - a + 0.0004404786298671_wp_
b = f * a - b - 0.0051316411610611_wp_
a = f * b - a + 0.0423191803533369_wp_
b = f * a - b - 0.2266249915567549_wp_
a = f * b - a + 0.6756157807721877_wp_
b = f * a - b - 0.7672963628866459_wp_
a = f * b - a - 0.1286973843813500_wp_
a = f * a - b + 0.0406082117718685_wp_
besjy=0.636619772367581_wp_*log(x)*besjy-0.636619772367581_wp_/x &
+0.0625_wp_*(a-b)*x
return
!
5 f=256.0_wp_/x**2-2.0_wp_
b = - 0.0000000000000007_wp_
a = f * b + 0.0000000000000055_wp_
b = f * a - b - 0.0000000000000468_wp_
a = f * b - a + 0.0000000000004699_wp_
b = f * a - b - 0.0000000000057049_wp_
a = f * b - a + 0.0000000000881690_wp_
b = f * a - b - 0.0000000018718907_wp_
a = f * b - a + 0.0000000617763396_wp_
b = f * a - b - 0.0000039872843005_wp_
a = f * b - a + 0.0008989898330859_wp_
a = f * a - b + 2.0018060817200274_wp_
p=a-b
b = + 0.0000000000000007_wp_
a = f * b - 0.0000000000000046_wp_
b = f * a - b + 0.0000000000000360_wp_
a = f * b - a - 0.0000000000003264_wp_
b = f * a - b + 0.0000000000035152_wp_
a = f * b - a - 0.0000000000468636_wp_
b = f * a - b + 0.0000000008229193_wp_
a = f * b - a - 0.0000000209597814_wp_
b = f * a - b + 0.0000009138615258_wp_
a = f * b - a - 0.0000962772354916_wp_
a = f * a - b + 0.0935555741390707_wp_
q=8.0_wp_*(a-b)/v
f=v-2.356194490192345_wp_
a=cos(f)
b=sin(f)
f=0.398942280401432_wp_/sqrt(v)
if(l) go to 7
besjy=f*(q*a+p*b)
return
7 besjy=f*(p*a-q*b)
if(x < 0.0_wp_) besjy=-besjy
return
!
entry besy0(x)
!
if(x <= 0.0_wp_) go to 9
l=.false.
v=x
if(v >= 8.0_wp_) go to 4
go to 8
entry besy1(x)
!
if(x <= 0.0_wp_) go to 9
l=.false.
v=x
if(v >= 8.0_wp_) go to 5
go to 3
!
9 besjy=0.0_wp_
write(nout,"(1x,'besjy ... non-positive argument x = ',e15.4)") x
end function besjy
function besik(x)
implicit none
real(wp_), intent(in) :: x
real(wp_) :: besik,ebesi0,besi0,ebesi1,besi1,ebesk0,besk0,ebesk1,besk1
logical :: l,e
real(wp_) :: v,f,a,b,z
integer, parameter :: nout=2
!
entry ebesi0(x)
!
e=.true.
go to 1
!
entry besi0(x)
!
e=.false.
1 l=.true.
v=abs(x)
if(v >= 8.0_wp_) go to 4
8 f=0.0625_wp_*x**2-2.0_wp_
a = 0.000000000000002_wp_
b = f * a + 0.000000000000120_wp_
a = f * b - a + 0.000000000006097_wp_
b = f * a - b + 0.000000000268828_wp_
a = f * b - a + 0.000000010169727_wp_
b = f * a - b + 0.000000326091051_wp_
a = f * b - a + 0.000008738315497_wp_
b = f * a - b + 0.000192469359688_wp_
a = f * b - a + 0.003416331766012_wp_
b = f * a - b + 0.047718748798174_wp_
a = f * b - a + 0.509493365439983_wp_
b = f * a - b + 4.011673760179349_wp_
a = f * b - a + 22.274819242462231_wp_
b = f * a - b + 82.489032744024100_wp_
a = f * b - a + 190.494320172742844_wp_
a = f * a - b + 255.466879624362167_wp_
besik=0.5_wp_*(a-b)
if(l .and. e) besik=exp(-v)*besik
if(l) return
!
a = + 0.000000000000003_wp_
b = f * a + 0.000000000000159_wp_
a = f * b - a + 0.000000000007658_wp_
b = f * a - b + 0.000000000318588_wp_
a = f * b - a + 0.000000011281211_wp_
b = f * a - b + 0.000000335195256_wp_
a = f * b - a + 0.000008216025940_wp_
b = f * a - b + 0.000162708379043_wp_
a = f * b - a + 0.002536308188086_wp_
b = f * a - b + 0.030080722420512_wp_
a = f * b - a + 0.259084432434900_wp_
b = f * a - b + 1.511535676029228_wp_
a = f * b - a + 5.283632866873920_wp_
b = f * a - b + 8.005368868700334_wp_
a = f * b - a - 4.563433586448395_wp_
a = f * a - b - 21.057660177402440_wp_
besik=-log(0.125_wp_*x)*besik+0.5_wp_*(a-b)
if(e) besik=exp(x)*besik
return
!
4 f=32.0_wp_/v-2.0_wp_
b = - 0.000000000000001_wp_
a = f * b - 0.000000000000001_wp_
b = f * a - b + 0.000000000000004_wp_
a = f * b - a + 0.000000000000010_wp_
b = f * a - b - 0.000000000000024_wp_
a = f * b - a - 0.000000000000104_wp_
b = f * a - b + 0.000000000000039_wp_
a = f * b - a + 0.000000000000966_wp_
b = f * a - b + 0.000000000001800_wp_
a = f * b - a - 0.000000000004497_wp_
b = f * a - b - 0.000000000033127_wp_
a = f * b - a - 0.000000000078957_wp_
b = f * a - b + 0.000000000029802_wp_
a = f * b - a + 0.000000001238425_wp_
b = f * a - b + 0.000000008513091_wp_
a = f * b - a + 0.000000056816966_wp_
b = f * a - b + 0.000000513587727_wp_
a = f * b - a + 0.000007247591100_wp_
b = f * a - b + 0.000172700630778_wp_
a = f * b - a + 0.008445122624921_wp_
a = f * a - b + 2.016558410917480_wp_
besik=0.199471140200717_wp_*(a-b)/sqrt(v)
if(e) return
besik=exp(v)*besik
return
!
entry ebesi1(x)
!
e=.true.
go to 2
!
entry besi1(x)
!
e=.false.
2 l=.true.
v=abs(x)
if(v >= 8.0_wp_) go to 3
7 f=0.0625_wp_*x**2-2.0_wp_
a = + 0.000000000000001_wp_
b = f * a + 0.000000000000031_wp_
a = f * b - a + 0.000000000001679_wp_
b = f * a - b + 0.000000000079291_wp_
a = f * b - a + 0.000000003227617_wp_
b = f * a - b + 0.000000111946285_wp_
a = f * b - a + 0.000003264138122_wp_
b = f * a - b + 0.000078756785754_wp_
a = f * b - a + 0.001543019015627_wp_
b = f * a - b + 0.023993079147841_wp_
a = f * b - a + 0.287855511804672_wp_
b = f * a - b + 2.571459906347755_wp_
a = f * b - a + 16.334550552522066_wp_
b = f * a - b + 69.395917633734448_wp_
a = f * b - a + 181.312616040570265_wp_
a = f * a - b + 259.890237806477292_wp_
besik=0.0625_wp_*(a-b)*x
if(l .and. e) besik=exp(-v)*besik
if(l) return
!
a = + 0.000000000000001_wp_
b = f * a + 0.000000000000042_wp_
a = f * b - a + 0.000000000002163_wp_
b = f * a - b + 0.000000000096660_wp_
a = f * b - a + 0.000000003696783_wp_
b = f * a - b + 0.000000119367971_wp_
a = f * b - a + 0.000003202510692_wp_
b = f * a - b + 0.000070010627855_wp_
a = f * b - a + 0.001217056994516_wp_
b = f * a - b + 0.016300049289816_wp_
a = f * b - a + 0.161074301656148_wp_
b = f * a - b + 1.101461993004852_wp_
a = f * b - a + 4.666387026862842_wp_
b = f * a - b + 9.361617831395389_wp_
a = f * b - a - 1.839239224286199_wp_
a = f * a - b - 26.688095480862668_wp_
besik=log(0.125_wp_*x)*besik+1.0_wp_/x-0.0625_wp_*(a-b)*x
if(e) besik=exp(x)*besik
return
!
3 f=32.0_wp_/v-2.0_wp_
b = + 0.000000000000001_wp_
a = f * b + 0.000000000000001_wp_
b = f * a - b - 0.000000000000005_wp_
a = f * b - a - 0.000000000000010_wp_
b = f * a - b + 0.000000000000026_wp_
a = f * b - a + 0.000000000000107_wp_
b = f * a - b - 0.000000000000053_wp_
a = f * b - a - 0.000000000001024_wp_
b = f * a - b - 0.000000000001804_wp_
a = f * b - a + 0.000000000005103_wp_
b = f * a - b + 0.000000000035408_wp_
a = f * b - a + 0.000000000081531_wp_
b = f * a - b - 0.000000000047563_wp_
a = f * b - a - 0.000000001401141_wp_
b = f * a - b - 0.000000009613873_wp_
a = f * b - a - 0.000000065961142_wp_
b = f * a - b - 0.000000629724239_wp_
a = f * b - a - 0.000009732146728_wp_
b = f * a - b - 0.000277205360764_wp_
a = f * b - a - 0.024467442963276_wp_
a = f * a - b + 1.951601204652572_wp_
besik=0.199471140200717_wp_*(a-b)/sqrt(v)
if(x < 0.0_wp_) besik=-besik
if(e) return
besik=exp(v)*besik
return
!
entry ebesk0 (x)
!
e=.true.
go to 11
!
entry besk0(x)
!
e=.false.
11 if(x <= 0.0_wp_) go to 9
l=.false.
v=x
if(x < 5.0_wp_) go to 8
f=20.0_wp_/x-2.0_wp_
a = - 0.000000000000002_wp_
b = f * a + 0.000000000000011_wp_
a = f * b - a - 0.000000000000079_wp_
b = f * a - b + 0.000000000000581_wp_
a = f * b - a - 0.000000000004580_wp_
b = f * a - b + 0.000000000039044_wp_
a = f * b - a - 0.000000000364547_wp_
b = f * a - b + 0.000000003792996_wp_
a = f * b - a - 0.000000045047338_wp_
b = f * a - b + 0.000000632575109_wp_
a = f * b - a - 0.000011106685197_wp_
b = f * a - b + 0.000269532612763_wp_
a = f * b - a - 0.011310504646928_wp_
a = f * a - b + 1.976816348461652_wp_
besik=0.626657068657750_wp_*(a-b)/sqrt(x)
if(e) return
z=besik
besik=0.0_wp_
if(x < 180.0_wp_) besik=exp(-x)*z
return
!
entry ebesk1(x)
!
e=.true.
go to 12
!
entry besk1(x)
!
e=.false.
12 if(x <= 0.0_wp_) go to 9
l=.false.
v=x
if(x < 5.0_wp_) go to 7
f=20.0_wp_/x-2.0_wp_
a = + 0.000000000000002_wp_
b = f * a - 0.000000000000013_wp_
a = f * b - a + 0.000000000000089_wp_
b = f * a - b - 0.000000000000663_wp_
a = f * b - a + 0.000000000005288_wp_
b = f * a - b - 0.000000000045757_wp_
a = f * b - a + 0.000000000435417_wp_
b = f * a - b - 0.000000004645555_wp_
a = f * b - a + 0.000000057132218_wp_
b = f * a - b - 0.000000845172048_wp_
a = f * b - a + 0.000016185063810_wp_
b = f * a - b - 0.000468475028167_wp_
a = f * b - a + 0.035465291243331_wp_
a = f * a - b + 2.071901717544716_wp_
besik=0.626657068657750_wp_*(a-b)/sqrt(x)
if(e) return
z=besik
besik=0.0_wp_
if(x < 180.0_wp_) besik=exp(-x)*z
return
9 besik=0.0_wp_
write(nout,"(1x,'besik ... non-positive argument x = ',e15.4)") x
end function besik
!
! routines for conical function: end
!
end module conical

View File

@ -1,17 +1,21 @@
!########################################################################!
MODULE const_and_precisions
use itm_types, only : wp_ => r8
use itm_constants, only : pi => itm_pi, e_ => itm_qe, me_ => itm_me, c_ => itm_c
!########################################################################!
IMPLICIT NONE
PUBLIC
!------------------------------------------------------------------------
! common precisions
!------------------------------------------------------------------------
! INTEGER, PARAMETER :: sp_ = 4 ! single precision
! INTEGER, PARAMETER :: dp_ = 8 ! double precision
! INTEGER, PARAMETER :: wp_ = dp_ ! work-precision
! INTEGER, PARAMETER :: i1 = SELECTED_INT_KIND (2) ! Integer*1
! INTEGER, PARAMETER :: i2 = SELECTED_INT_KIND (4) ! Integer*2
INTEGER, PARAMETER :: i4 = SELECTED_INT_KIND (9) ! Integer*4
INTEGER, PARAMETER :: i8 = SELECTED_INT_KIND (18) ! Integer*8
INTEGER, PARAMETER :: r4 = SELECTED_REAL_KIND (6, 37) ! Real*4
INTEGER, PARAMETER :: r8 = SELECTED_REAL_KIND (15, 300) ! Real*8
! INTEGER, PARAMETER :: sp_ = r4 ! single precision
! INTEGER, PARAMETER :: dp_ = r8 ! double precision
INTEGER, PARAMETER :: wp_ = r8 ! work-precision
! INTEGER, PARAMETER :: odep_ = dp_ ! ODE-solver precision
! INTEGER, PARAMETER :: xp_ = wp_ ! for ext. modules if necessary
!------------------------------------------------------------------------
@ -26,31 +30,36 @@
!!========================================================================
! Arithmetic constants
!========================================================================
integer, parameter :: izero = 0
REAL(wp_), PARAMETER :: zero = 0.0_wp_
REAL(wp_), PARAMETER :: unit = 1.0_wp_
! REAL(wp_), PARAMETER :: pi = 3.141592653589793_wp_
! REAL(wp_), PARAMETER :: sqrt_pi = 1.772453850905516_wp_
REAL(wp_), PARAMETER :: half = 0.5_wp_
REAL(wp_), PARAMETER :: one = 1.0_wp_
REAL(wp_), PARAMETER :: two = 2.0_wp_
real(wp_), parameter :: pi = 3.141592653589793_wp_ ! 3.141592653589793238462643383280
real(wp_), parameter :: pihalf = 1.57079632679489661923_wp_
REAL(wp_), PARAMETER :: sqrt_pi = 1.772453850905516_wp_
! REAL(wp_), PARAMETER :: sqrt_2 = 1.414213562373095_wp_
! REAL(wp_), PARAMETER :: rad = pi/180.0_wp_
REAL(wp_), PARAMETER :: degree = pi/180.0_wp_
REAL(wp_), PARAMETER :: emn1 = 0.367879441171442_wp_ ! exp(-1)
!---
! REAL(wp_), PARAMETER :: ex(1:3) = (/unit,zero,zero/)
! REAL(wp_), PARAMETER :: ey(1:3) = (/zero,unit,zero/)
! REAL(wp_), PARAMETER :: ez(1:3) = (/zero,zero,unit/)
! REAL(wp_), PARAMETER :: ex(1:3) = (/one ,zero,zero/)
! REAL(wp_), PARAMETER :: ey(1:3) = (/zero,one ,zero/)
! REAL(wp_), PARAMETER :: ez(1:3) = (/zero,zero,one /)
!---
! REAL(wp_), PARAMETER :: kron(3,3) = reshape((/unit,zero,zero, &
! zero,unit,zero, &
! zero,zero,unit/),(/3,3/))
! COMPLEX(wp_), PARAMETER :: im = (0.0_wp_,1.0_wp_)
! COMPLEX(wp_), PARAMETER :: czero = (0.0_wp_,0.0_wp_)
! COMPLEX(wp_), PARAMETER :: cunit = (1.0_wp_,0.0_wp_)
! REAL(wp_), PARAMETER :: kron(3,3) = reshape((/one ,zero,zero, &
! zero,one ,zero, &
! zero,zero,one /),(/3,3/))
COMPLEX(wp_), PARAMETER :: im = (0.0_wp_,1.0_wp_)
COMPLEX(wp_), PARAMETER :: czero = (0.0_wp_,0.0_wp_)
COMPLEX(wp_), PARAMETER :: cunit = (1.0_wp_,0.0_wp_)
! COMPLEX(wp_), PARAMETER :: ctwo = (2.0_wp_,0.0_wp_)
!========================================================================
! Computer constants
!========================================================================
REAL(wp_), PARAMETER :: comp_eps = EPSILON(unit)
! REAL(wp_), PARAMETER :: comp_eps2 = comp_eps**2
! REAL(wp_), PARAMETER :: comp_tiny = TINY(unit)
! REAL(wp_), PARAMETER :: comp_huge = HUGE(unit)
REAL(wp_), PARAMETER :: comp_eps = EPSILON(one)
! REAL(wp_), PARAMETER :: comp_eps2 = comp_eps**2
REAL(wp_), PARAMETER :: comp_tiny = TINY(one)
REAL(wp_), PARAMETER :: comp_huge = HUGE(one)
! REAL(wp_), PARAMETER :: comp_tinylog =-200 ! LOG10(comp_tiny)
! REAL(wp_), PARAMETER :: comp_hugelog =+200 ! LOG10(comp_huge)
! REAL(wp_), PARAMETER :: comp_tiny1 = 1d+50*comp_tiny
@ -60,26 +69,42 @@
!------------------------------------------------------------------------
! Conventional constants
!------------------------------------------------------------------------
INTEGER, PARAMETER :: int_invalid = -999999999
REAL(R8), PARAMETER :: r8_invalid = -9.0e40_r8
! REAL(wp_), PARAMETER :: output_tiny = 1.0d-66
! REAL(wp_), PARAMETER :: output_huge = 1.0d+66
!========================================================================
! Physical constants (SI)
!========================================================================
! REAL(wp_), PARAMETER :: e_ = 1.602176487d-19 ! [C]
! REAL(wp_), PARAMETER :: me_ = 9.10938215d-31 ! [kg]
! REAL(wp_), PARAMETER :: mp_ = 1.672621637d-27 ! [kg]
! REAL(wp_), PARAMETER :: rmpe_ = mp_/me_
! REAL(wp_), PARAMETER :: c_ = 2.99792458d+08 ! [m/s]
! REAL(wp_), PARAMETER :: eps0_ = 8.854187817d-12 ! [F/m]
real (wp_), parameter :: e_ = 1.602176487e-19_wp_ ! elementary charge, C
real (wp_), parameter :: me_ = 9.10938215e-31_wp_ ! electron mass, kg
! real (wp_), parameter :: mp_ = 1.672621637e-27_wp_ ! proton mass, kg
! real (wp_), parameter :: md_ = 3.34358320e-27_wp_ ! deuteron mass, kg
! real (wp_), parameter :: mt_ = 5.00735588e-27_wp_ ! triton mass, kg
! real (wp_), parameter :: ma_ = 6.64465620e-27_wp_ ! alpha mass, kg
! real (wp_), parameter :: amu_ = 1.660538782e-27_wp_ ! amu, kg
! REAL (wp_), PARAMETER :: rmpe_ = mp_/me_ ! proton-electron mass ratio
real (wp_), parameter :: c_ = 2.99792458e8_wp_ ! speed of light, m/s
real (wp_), parameter :: mu0_ = 4.0e-7_wp_ * pi ! magnetic permeability of vacuum
real (wp_), parameter :: eps0_ = 1.0_wp_ / (mu0_ * c_**2) ! dielectric constant of vacuum, F/m
! real (wp_), parameter :: avogr = 6.02214179e23_wp_
! real (wp_), parameter :: KBolt = 1.3806504e-23_wp_
!========================================================================
! Physical constants (cgs)
!========================================================================
real (wp_), parameter :: ccgs_ = c_*1.e2_wp_ ! speed of light, cm/s
real (wp_), parameter :: mecgs_ = me_*1.e3_wp_ ! electron mass, g
real (wp_), parameter :: ecgs_ = e_*c_*10._wp_ ! elementary charge, statcoul
!------------------------------------------------------------------------
! Useful definitions
!------------------------------------------------------------------------
REAL(wp_), PARAMETER :: keV_ = 1000*e_ ! [J]
REAL(wp_), PARAMETER :: keV_ = 1.e3_wp_*e_ ! [J]
REAL(wp_), PARAMETER :: mc2_SI = me_*c_**2 ! [J]
REAL(wp_), PARAMETER :: mc2_ = mc2_SI/keV_ ! [keV]
REAL(wp_), PARAMETER :: mu0inv = 1._wp_/mu0_ !
! REAL(wp_), PARAMETER :: mc_ = me_*c_ ! [kg*m/s]
! ! f_ce = fce1_*B (B in Tesla): !
! REAL(wp_), PARAMETER :: wce1_ = e_/me_ ! [rad/s]
REAL(wp_), PARAMETER :: wce1_ = e_/me_ ! [rad/s]
! REAL(wp_), PARAMETER :: fce1_ = wce1_/(2*pi) ! [1/s]
! ! f_pl = fpe1_*sqrt(Ne) (Ne in 1/m**3): !
! REAL(wp_), PARAMETER :: wpe1_ = 56.4049201 ! [rad/s]
@ -100,6 +125,33 @@
! REAL(wp_), PARAMETER :: Npar_min = 1.0d-3
!########################################################################!
interface is_valid
module procedure is_valid_int4, is_valid_int8, is_valid_real8
end interface
contains
logical function is_valid_int4(in_int)
implicit none
integer(i4), intent(in) :: in_int
is_valid_int4 = in_int /= int_invalid
return
end function is_valid_int4
logical function is_valid_int8(in_int)
implicit none
integer(i8), intent(in) :: in_int
is_valid_int8 = in_int /= int_invalid
return
end function is_valid_int8
logical function is_valid_real8(in_real)
implicit none
real(r8), intent(in) :: in_real
is_valid_real8 = abs(in_real - r8_invalid) > abs(r8_invalid) * 1.0e-15_r8
return
end function is_valid_real8
END MODULE const_and_precisions
!########################################################################!

319
src/coreprofiles.f90 Normal file
View File

@ -0,0 +1,319 @@
module coreprofiles
use const_and_precisions, only : wp_,zero,one
implicit none
INTEGER, SAVE :: npp,nsfd
REAL(wp_), SAVE :: psdbnd,psnpp,denpp,ddenpp,d2denpp
REAL(wp_), DIMENSION(:), ALLOCATABLE, SAVE :: tfn,cfn,psrad
REAL(wp_), DIMENSION(:,:), ALLOCATABLE, SAVE :: ct,cz
REAL(wp_), SAVE :: dens0,aln1,aln2,te0,dte0,alt1,alt2,zeffan
contains
subroutine density(psin,dens,ddens)
use graydata_flags, only : iprof
! use graydata_anequil, only : dens0,aln1,aln2
use dierckx, only : splev,splder
implicit none
! arguments
real(wp_), intent(in) :: psin
real(wp_), intent(out) :: dens,ddens
! local variables
integer, parameter :: nn=3, nn1=nn+1, nn2=nn+2
integer :: ier,nu
real(wp_) :: profd,dprofd,dpsib,tt,fp,dfp,fh,dfh
real(wp_), dimension(1) :: xxs,ffs
real(wp_), dimension(npp+4) :: wrkfd
!
! computation of density [10^19 m^-3] and derivative wrt psi
!
dens=zero
ddens=zero
if((psin >= psdbnd).or.(psin < zero)) return
!
if(iprof == 0) then
if(psin > one) return
profd=(one-psin**aln1)**aln2
dens=dens0*profd
dprofd=-aln1*aln2*psin**(aln1-one) &
*(one-psin**aln1)**(aln2-one)
ddens=dens0*dprofd
else
if(psin > psnpp) then
! smooth interpolation for psnpp < psi < psdbnd
! dens = fp * fh
! fp: parabola matched at psi=psnpp with given profile density
! fh=(1-t)^3(1+3t+6t^2) is a smoothing function:
! fh(0)=1, fh(1)=0 and zero first and second deriv at t=0,1
!
dpsib=psin-psnpp
fp=denpp+dpsib*ddenpp+0.5_wp_*dpsib**2*d2denpp
dfp=ddenpp+dpsib*d2denpp
tt=dpsib/(psdbnd-psnpp)
fh=(one-tt)**3*(one+3.0_wp_*tt+6.0_wp_*tt**2)
dfh=-30.0_wp_*(one-tt)**2*tt**2/(psdbnd-psnpp)
dens=fp*fh
ddens=dfp*fh+fp*dfh
else
xxs(1)=psin
ier=0
call splev(tfn,nsfd,cfn,3,xxs,ffs,1,ier)
dens=ffs(1)
nu=1
ier=0
call splder(tfn,nsfd,cfn,3,nu,xxs,ffs,1,wrkfd,ier)
ddens=ffs(1)
if(ier > 0) print*,ier
if(abs(dens) < 1.0e-10_wp_) dens=zero
end if
! if(dens < zero) print*,' DENSITY NEGATIVE',dens
if(dens < zero) then
dens=zero
ddens=zero
end if
end if
end subroutine density
function temp(psin)
use const_and_precisions, only : wp_,zero,one
use graydata_flags, only : iprof
! use graydata_anequil, only : te0,dte0,alt1,alt2
use utils, only : locate
use simplespline, only :spli
implicit none
! arguments
real(wp_), intent(in) :: psin
real(wp_) :: temp
! local variables
integer :: k
real(wp_) :: proft,dps
temp=zero
if((psin >= one).or.(psin < zero)) return
if(iprof == 0) then
proft=(1.0_wp_-psin**alt1)**alt2
temp=(te0-dte0)*proft+dte0
else
call locate(psrad,npp,psin,k)
k=max(1,min(k,npp-1))
dps=psin-psrad(k)
temp=spli(ct,npp,k,dps)
endif
end function temp
function fzeff(psin)
use const_and_precisions, only : wp_,zero,one
use graydata_flags, only : iprof
! use graydata_anequil, only : zeffan
use utils, only : locate
use simplespline, only :spli
implicit none
! arguments
real(wp_), intent(in) :: psin
real(wp_) :: fzeff
! local variables
integer :: k
real(wp_) :: dps
fzeff=one
if((psin >= one).or.(psin < zero)) return
if(iprof == 0) then
fzeff=zeffan
else
call locate(psrad,npp,psin,k)
k=max(1,min(k,npp-1))
dps=psin-psrad(k)
fzeff=spli(cz,npp,k,dps)
endif
end function fzeff
subroutine read_profiles(filenm,psin,te,ne,zeff,unit)
use utils, only : get_free_unit
implicit none
! arguments
character(len=*), intent(in) :: filenm
real(wp_), dimension(:), allocatable, intent(out) :: psin,te,ne,zeff
integer, optional, intent(in) :: unit
! local variables
integer :: u, i, n
if (present(unit)) then
u=unit
else
u=get_free_unit()
end if
open(file=trim(filenm),status='old',unit=u)
read(u,*) n
if(allocated(psin)) deallocate(psin)
if(allocated(te)) deallocate(te)
if(allocated(ne)) deallocate(ne)
if(allocated(zeff)) deallocate(zeff)
allocate(psin(n),te(n),ne(n),zeff(n))
do i=1,n
read(u,*) psin(i),te(i),ne(i),zeff(i)
end do
psin(1)=max(psin(1),zero)
close(u)
end subroutine read_profiles
subroutine read_profiles_an(filenm,te,ne,zeff,unit)
use utils, only : get_free_unit
implicit none
! arguments
character(len=*), intent(in) :: filenm
real(wp_), dimension(:), allocatable, intent(out) :: te,ne,zeff
integer, optional, intent(in) :: unit
! local variables
integer :: u
if (present(unit)) then
u=unit
else
u=get_free_unit()
end if
if(allocated(te)) deallocate(te)
if(allocated(ne)) deallocate(ne)
if(allocated(zeff)) deallocate(zeff)
allocate(te(4),ne(3),zeff(1))
open(file=trim(filenm),status='old',unit=u)
read(u,*) ne(1:3) ! dens0,aln1,aln2
read(u,*) te(1:4) ! te0,dte0,alt1,alt2
read(u,*) zeff(1) ! zeffan
close(u)
end subroutine read_profiles_an
subroutine tene_scal(te,ne,tfact,nfact,bfact,iscal)
implicit none
! arguments
real(wp_), dimension(:), intent(inout) :: te,ne
real(wp_), intent(in) :: tfact,nfact,bfact
integer, intent(in) :: iscal
! local variables
real(wp_) :: aat,aan,ffact
if (iscal==0) then
aat=2.0_wp_/3.0_wp_
aan=4.0_wp_/3.0_wp_
else
aat=1.0_wp_
aan=1.0_wp_
end if
if(iscal==2) then
ffact=1.0_wp_
else
ffact=bfact
end if
te(:)=te(:)*ffact**aat*tfact
ne(:)=ne(:)*ffact**aan*nfact
end subroutine tene_scal
subroutine set_prfspl(psin,te,ne,zeff,ssplne)
use simplespline, only : difcs
use dierckx, only : curfit, splev, splder
implicit none
! arguments
real(wp_), dimension(:), intent(in) :: psin,te,ne,zeff
real(wp_), intent(in) :: ssplne
! local variables
integer, parameter :: iopt=0, kspl=3
integer :: n, npest, lwrkf, ier
real(wp_) :: xb, xe, fp, xnv, ynv
real(wp_), dimension(:), allocatable :: wf, wrkf
integer, dimension(:), allocatable :: iwrkf
real(wp_), dimension(1) :: dedge,ddedge,d2dedge
n=size(psin)
npest=n+4
lwrkf=n*4+npest*16
allocate(wrkf(lwrkf),iwrkf(npest),wf(n))
! if necessary, reallocate spline arrays
if(.not.allocated(psrad)) then
allocate(psrad(n),ct(n,4),cz(n,4))
else
if(size(psrad)<n) then
deallocate(psrad,ct,cz)
allocate(psrad(n),ct(n,4),cz(n,4))
end if
end if
if(.not.allocated(cfn)) then
allocate(tfn(npest),cfn(npest))
else
if(size(cfn)<npest) then
deallocate(tfn,cfn)
allocate(tfn(npest),cfn(npest))
end if
end if
! spline approximation of temperature and Zeff
call difcs(psin,te, n,iopt,ct,ier)
call difcs(psin,zeff,n,iopt,cz,ier)
psrad=psin
npp=n
! spline approximation of density
xb=zero
xe=psin(n)
wf(:)=one
call curfit(iopt,n,psin,ne,wf,xb,xe,kspl,ssplne,npest, &
nsfd,tfn,cfn,fp,wrkf,lwrkf,iwrkf,ier)
! compute polinomial extrapolation matching the spline boundary up to the
! 2nd order derivative, extending the profile up to psi=psdbnd where
! ne=ne'=ne''=0
! spline value and derivatives at the edge
call splev(tfn,nsfd,cfn,3,psin(n:n),dedge(1:1),1,ier)
call splder(tfn,nsfd,cfn,3,1,psin(n:n),ddedge(1:1), 1,wrkf(1:nsfd),ier)
call splder(tfn,nsfd,cfn,3,2,psin(n:n),d2dedge(1:1),1,wrkf(1:nsfd),ier)
! determination of the boundary
psnpp=psin(n)
denpp=dedge(1)
ddenpp=ddedge(1)
d2denpp=d2dedge(1)
psdbnd=psnpp
if(ddenpp < zero) then
xnv=psnpp-ddenpp/d2denpp
ynv=denpp-0.5_wp_*ddenpp**2/d2denpp
if((d2denpp > zero).and.(ynv >= zero)) then
psdbnd=xnv
else
psdbnd=xnv+sqrt((ddenpp/d2denpp)**2-2.0_wp_*denpp/d2denpp)
end if
print*,psnpp,denpp,ddenpp,d2denpp,xnv,ynv
print*,psdbnd
end if
deallocate(iwrkf,wrkf,wf)
end subroutine set_prfspl
subroutine unset_prfspl
implicit none
if(allocated(psrad)) deallocate(psrad)
if(allocated(ct)) deallocate(ct)
if(allocated(cz)) deallocate(cz)
if(allocated(tfn)) deallocate(tfn)
if(allocated(cfn)) deallocate(cfn)
end subroutine unset_prfspl
subroutine set_prfan(te,ne,zeff)
implicit none
REAL(wp_), dimension(:), intent(in) :: te,ne,zeff
te0=te(1)
dte0=te(2)
alt1=te(3)
alt2=te(4)
dens0=ne(1)
aln1=ne(2)
aln2=ne(3)
zeffan=zeff(1)
psdbnd=1.0_wp_
end subroutine set_prfan
end module coreprofiles

4609
src/dierckx.f90 Normal file

File diff suppressed because it is too large Load Diff

1340
src/dispersion.f90 Normal file

File diff suppressed because it is too large Load Diff

884
src/eccd.f90 Normal file
View File

@ -0,0 +1,884 @@
module eccd
use const_and_precisions, only : wp_
implicit none
real(wp_), parameter, private :: cst2min=1.0e-6_wp_ ! min width of trap. cone
integer, parameter, private :: nfpp=13, & ! number of extra parameters passed
nfpp1=nfpp+ 1, nfpp2=nfpp+ 2, & ! to the integrand function fpp
nfpp3=nfpp+ 3, nfpp4=nfpp+ 4, &
nfpp5=nfpp+ 5
!########################################################################
! the following parameters are used by N.M. subroutines:
! The module contains few subroutines which are requested to calculate
! the current drive value by adjoint approach
!########################################################################
CHARACTER, PRIVATE, PARAMETER :: adj_appr(1:6) = & ! adj. approach switcher
(/ 'l', & ! (1)='l': collisionless limit
! (1)='c': collisional (classical) limit,
! w/o trap. part.
'm', & ! (2)='m': momentum conservation
! (2)='h': high-speed limit
!---
'l', & ! DO NOT CHANGE!
'r', & ! DO NOT CHANGE!
'v', & ! DO NOT CHANGE!
'i' /) ! DO NOT CHANGE!
!-------
REAL(wp_), PRIVATE :: r2,q2,gp1 ! coefficients for HSL integrand function
!-------
REAL(wp_), PRIVATE, PARAMETER :: delta = 1e-4 ! border for recalculation
!------- for N.M. subroutines (variational principle) -------
REAL(wp_), PRIVATE :: sfd(1:4) ! polyn. exp. of the "Spitzer"-function
INTEGER, PRIVATE, PARAMETER :: nre = 2 ! order of rel. correct.
REAL(wp_), PRIVATE, PARAMETER :: vp_mee(0:4,0:4,0:2) = &
RESHAPE((/0.0, 0.0, 0.0, 0.0, 0.0, &
0.0, 0.184875, 0.484304, 1.06069, 2.26175, &
0.0, 0.484304, 1.41421, 3.38514, 7.77817, &
0.0, 1.06069, 3.38514, 8.73232, 21.4005, &
0.0, 2.26175, 7.77817, 21.4005, 55.5079, &
! &
0.0, -1.33059,-2.57431, -5.07771, -10.3884, &
-0.846284,-1.46337, -1.4941, -0.799288, 2.57505, &
-1.1601, -1.4941, 2.25114, 14.159, 50.0534, &
-1.69257, -0.799288, 14.159, 61.4168, 204.389, &
-2.61022, 2.57505, 50.0534, 204.389, 683.756, &
! &
0.0, 2.62498, 0.985392,-5.57449, -27.683, &
0.0, 3.45785, 5.10096, 9.34463, 22.9831, &
-0.652555, 5.10096, 20.5135, 75.8022, 268.944, &
-2.11571, 9.34463, 75.8022, 330.42, 1248.69, &
-5.38358, 22.9831, 268.944, 1248.69, 4876.48/),&
(/5,5,3/))
REAL(wp_), PRIVATE, PARAMETER :: vp_mei(0:4,0:4,0:2) = &
RESHAPE((/0.0, 0.886227, 1.0, 1.32934, 2.0, &
0.886227,1.0, 1.32934, 2.0, 3.32335, &
1.0, 1.32934, 2.0, 3.32335, 6.0, &
1.32934, 2.0, 3.32335, 6.0, 11.6317, &
2.0, 3.32335, 6.0, 11.6317, 24.0, &
! &
0.0, 0.332335, 1.0, 2.49251, 6.0, &
1.66168, 1.0, 2.49251, 6.0, 14.5397, &
3.0, 2.49251, 6.0, 14.5397, 36.0, &
5.81586, 6.0, 14.5397, 36.0, 91.5999, &
12.0, 14.5397, 36.0, 91.5999, 240.0, &
! &
0.0, -0.103855, 0.0, 1.09047, 6.0, &
0.726983,0.0, 1.09047, 6.0, 24.5357, &
3.0, 1.09047, 6.0, 24.5357, 90.0, &
9.81427, 6.0, 24.5357, 90.0, 314.875, &
30.0, 24.5357, 90.0, 314.875, 1080.0 /), &
(/5,5,3/))
REAL(wp_), PRIVATE, PARAMETER :: vp_oee(0:4,0:4,0:2) = &
RESHAPE((/0.0, 0.56419, 0.707107, 1.0073, 1.59099, &
0.56419, 0.707107, 1.0073, 1.59099, 2.73981, &
0.707107,1.0073, 1.59099, 2.73981, 5.08233, &
1.0073, 1.59099, 2.73981, 5.08233, 10.0627, &
1.59099, 2.73981, 5.08233, 10.0627, 21.1138, &
! &
0.0, 1.16832, 1.90035, 3.5758, 7.41357, &
2.17562, 1.90035, 3.5758, 7.41357, 16.4891, &
3.49134, 3.5758, 7.41357, 16.4891, 38.7611, &
6.31562, 7.41357, 16.4891, 38.7611, 95.4472, &
12.4959, 16.4891, 38.7611, 95.4472, 244.803, &
! &
0.0, 2.65931, 4.64177, 9.6032, 22.6941, &
4.8652, 4.64177, 9.6032, 22.6941, 59.1437, &
9.51418, 9.6032, 22.6941, 59.1437, 165.282, &
21.061, 22.6941, 59.1437, 165.282, 485.785, &
50.8982, 59.1437, 165.282, 485.785, 1483.22/), &
(/5,5,3/))
REAL(wp_), PRIVATE, PARAMETER :: vp_g(0:4,0:2) = &
RESHAPE((/1.32934, 2.0, 3.32335, 6.0, 11.6317, &
2.49251, 0.0, 2.90793, 12.0, 39.2571, &
1.09047, 6.0, 11.45, 30.0, 98.9606/), &
(/5,3/))
!########################################################################
interface setcdcoeff
module procedure setcdcoeff_notrap,setcdcoeff_cohen,setcdcoeff_ncl
end interface setcdcoeff
contains
subroutine setcdcoeff_notrap(zeff,cst2,eccdpar)
implicit none
real(wp_), intent(in) :: zeff
real(wp_), intent(out) :: cst2
real(wp_), dimension(:), allocatable, intent(out) :: eccdpar
cst2=0.0_wp_
allocate(eccdpar(1))
eccdpar(1)=zeff
end subroutine setcdcoeff_notrap
subroutine setcdcoeff_cohen(zeff,rbn,rbx,cst2,eccdpar)
! cohen model
! rbn=B/B_min
! rbx=B/B_max
! cst2=1.0_wp_-B/B_max
! alams=sqrt(1-B_min/B_max)
! Zeff < 31 !!!
! fp0s= P_a (alams)
use conical, only : fconic
implicit none
real(wp_), intent(in) :: zeff,rbn,rbx
real(wp_), intent(out) :: cst2
real(wp_), dimension(:), allocatable, intent(out) :: eccdpar
real(wp_) :: alams,pa,fp0s
cst2=1.0_wp_-rbx
if(cst2<cst2min) cst2=0.0_wp_
alams=sqrt(1.0_wp_-rbx/rbn)
pa=sqrt(32.0_wp_/(Zeff+1.0_wp_)-1.0_wp_)/2.0_wp_
fp0s=fconic(alams,pa,0)
allocate(eccdpar(5))
eccdpar(1)=zeff
eccdpar(2)=rbn
eccdpar(3)=alams
eccdpar(4)=pa
eccdpar(5)=fp0s
end subroutine setcdcoeff_cohen
subroutine setcdcoeff_ncl(zeff,rbx,fc,amu,rhop,cst2,eccdpar)
use magsurf_data, only : ch,tjp,tlm,njpt,nlmt
use dierckx, only : profil
implicit none
integer, parameter :: ksp=3
real(wp_), intent(in) :: zeff,rbx,fc,amu,rhop
real(wp_), intent(out) :: cst2
real(wp_), dimension(:), allocatable, intent(out) :: eccdpar
real(wp_), dimension(nlmt) :: chlm
integer :: nlm,ierr,npar
cst2=1.0_wp_-rbx
if(cst2<cst2min) cst2=0.0_wp_
call SpitzFuncCoeff(amu,Zeff,fc)
nlm=nlmt
call profil(0,tjp,njpt,tlm,nlmt,ch,ksp,ksp,rhop,nlm,chlm,ierr)
if(ierr>0) write(*,*) ' Hlambda profil =',ierr
npar=3+2*nlm
allocate(eccdpar(npar))
eccdpar(1)=zeff
eccdpar(2) = fc
eccdpar(3) = rbx
eccdpar(4:3+nlm) = tlm
eccdpar(4+nlm:npar) = chlm
end subroutine setcdcoeff_ncl
subroutine eccdeff(yg,anpl,anprre,dens,amu,ex,ey,ez,nhmn,nhmx, &
ithn,cst2,fcur,eccdpar,effjcd,iokhawa,ierr)
use const_and_precisions, only : pi,qesi=>e_,mesi=>me_, &
vcsi=>c_,qe=>ecgs_,me=>mecgs_,vc=>ccgs_,mc2=>mc2_
use quadpack, only : dqagsmv
implicit none
! local constants
real(wp_), parameter :: mc2m2=1.0_wp_/mc2**2, &
canucc=2.0e13_wp_*pi*qe**4/(me**2*vc**3),ceff=qesi/(mesi*vcsi)
real(wp_), parameter :: epsa=0.0_wp_,epsr=1.0e-2_wp_,xxcr=16.0_wp_
real(wp_), parameter :: dumin=1.0e-6_wp_
integer, parameter :: lw=5000,liw=lw/4
! arguments
integer :: i,nhmn,nhmx,ithn,iokhawa,ierr
real(wp_) :: yg,anpl,anprre,dens,amu,cst2,effjcd
real(wp_), dimension(:) :: eccdpar
complex(wp_) :: ex,ey,ez
! local variables
integer :: nhn,neval,ier,last,npar
integer, dimension(liw) :: iw
real(wp_) :: anpl2,dnl,ygn,ygn2,resji,rdu2,upltp,upltm,uplp,uplm, &
rdu,rdu2t,duu,uu1,uu2,xx1,xx2,resj,resp,eji,epp,anum,denom, &
cstrdut,anucc
real(wp_), dimension(lw) :: w
real(wp_), dimension(nfpp+size(eccdpar)) :: apar
real(wp_), dimension(0:1) :: uleft,uright
! common/external functions/variables
real(wp_), external :: fcur
!
! effjpl = <J_parallel>/<p_d> /(B_min/<B>) [A m /W]
!
apar(1) = yg
apar(2) = anpl
apar(3) = amu
apar(4) = anprre
apar(5) = dble(ex)
apar(6) = dimag(ex)
apar(7) = dble(ey)
apar(8) = dimag(ey)
apar(9) = dble(ez)
apar(10) = dimag(ez)
apar(11) = dble(ithn)
npar=size(apar)
apar(nfpp+1:npar) = eccdpar
anpl2=anpl*anpl
effjcd=0.0_wp_
anum=0.0_wp_
denom=0.0_wp_
iokhawa=0
ierr=0
do nhn=nhmn,nhmx
ygn=nhn*yg
ygn2=ygn*ygn
rdu2=anpl2+ygn2-1.0_wp_
if (rdu2.lt.0.0_wp_) cycle
rdu=sqrt(rdu2)
dnl=1.0_wp_-anpl2
uplp=(anpl*ygn+rdu)/dnl
uplm=(anpl*ygn-rdu)/dnl
uu1=uplm
uu2=uplp
xx1=amu*(anpl*uu1+ygn-1.0_wp_)
xx2=amu*(anpl*uu2+ygn-1.0_wp_)
if(xx2.gt.xxcr) uu2=(xxcr/amu-ygn+1.0_wp_)/anpl
if(xx1.gt.xxcr) uu1=(xxcr/amu-ygn+1.0_wp_)/anpl
duu=abs(uu1-uu2)
if(duu.le.dumin) cycle
apar(12) = dble(nhn)
apar(13) = ygn
call dqagsmv(fpp,uu1,uu2,apar(1:nfpp),nfpp,epsa,epsr,resp, &
epp,neval,ier,liw,lw,last,iw,w)
if (ier.gt.0) then
ierr=90
return
end if
rdu2t=cst2*anpl2+ygn2-1.0_wp_
if (rdu2t.gt.0.0_wp_.and.cst2.gt.0.0_wp_) then
!
! resonance curve crosses the trapping region
!
iokhawa=1
cstrdut=sqrt(cst2*rdu2t)
upltm=(cst2*anpl*ygn-cstrdut)/(1.0_wp_-cst2*anpl2)
upltp=(cst2*anpl*ygn+cstrdut)/(1.0_wp_-cst2*anpl2)
uleft(0)=uplm
uright(0)=upltm
uleft(1)=upltp
uright(1)=uplp
else
!
! resonance curve does not cross the trapping region
!
iokhawa=0
uleft(0)=uplm
uright(0)=uplp
end if
resj=0.0_wp_
do i=0,1
resji=0.0_wp_
xx1=amu*(anpl*uleft(i)+ygn-1.0_wp_)
xx2=amu*(anpl*uright(i)+ygn-1.0_wp_)
if(xx1.lt.xxcr.or.xx2.lt.xxcr) then
if(xx2.gt.xxcr) uright(i)=(xxcr/amu-ygn+1.0_wp_)/anpl
if(xx1.gt.xxcr) uleft(i)=(xxcr/amu-ygn+1.0_wp_)/anpl
duu=abs(uleft(i)-uright(i))
if(duu.gt.dumin) then
call dqagsmv(fcur,uleft(i),uright(i),apar,npar,epsa,epsr, &
resji,eji,neval,ier,liw,lw,last,iw,w)
if (ier.gt.0) then
if (abs(resji).lt.1.0e-10_wp_) then
resji=0.0_wp_
else
ierr=91+iokhawa+i
return
end if
end if
end if
end if
resj=resj+resji
if(iokhawa.eq.0) exit
end do
anum=anum+resj
denom=denom+resp
end do
if(denom.gt.0.0_wp_) then
anucc=canucc*dens*(48.0_wp_-log(1.0e7_wp_*dens*mc2m2*amu**2))
effjcd=-ceff*anum/(anucc*denom)
end if
end subroutine eccdeff
function fpp(upl,extrapar,npar)
!
! computation of integral for power density, integrand function fpp
!
! ith=0 : polarization term = const
! ith=1 : polarization term Larmor radius expansion to lowest order
! ith=2 : full polarization term (J Bessel)
!
! integration variable upl passed explicitly. other variables passed
! as array of extra parameters of length npar=size(extrapar)
!
! extrapar(1) = yg
! extrapar(2) = anpl
! extrapar(3) = amu
! extrapar(4) = Re(anprw)
! extrapar(5) = Re(ex)
! extrapar(6) = Im(ex)
! extrapar(7) = Re(ey)
! extrapar(8) = Im(ey)
! extrapar(9) = Re(ez)
! extrapar(10) = Im(ez)
! extrapar(11) = double(ithn)
! extrapar(12) = double(nhn)
! extrapar(13) = ygn
!
use const_and_precisions, only : ui=>im
use math, only : fact
implicit none
! arguments
integer :: npar
real(wp_) :: upl,fpp
real(wp_), dimension(npar) :: extrapar
! local variables
integer :: ithn,nhn,nm,np
real(wp_) :: yg,anpl,amu,anprre,ygn,upr,upr2,gam,ee,thn2,thn2u,bb,cth, &
ajbnm,ajbnp,ajbn
complex(wp_) :: ex,ey,ez,emxy,epxy
yg=extrapar(1)
anpl=extrapar(2)
amu=extrapar(3)
anprre=extrapar(4)
ex=cmplx(extrapar(5),extrapar(6),wp_)
ey=cmplx(extrapar(7),extrapar(8),wp_)
ez=cmplx(extrapar(9),extrapar(10),wp_)
ithn=int(extrapar(11))
nhn=int(extrapar(12))
ygn=extrapar(13)
gam=anpl*upl+ygn
upr2=gam*gam-1.0_wp_-upl*upl
ee=exp(-amu*(gam-1))
! thn2=1.0_wp_
thn2u=upr2 !*thn2
if(ithn.gt.0) then
emxy=ex-ui*ey
epxy=ex+ui*ey
if(upr2.gt.0.0_wp_) then
upr=sqrt(upr2)
bb=anprre*upr/yg
if(ithn.eq.1) then
! Larmor radius expansion polarization term at lowest order
cth=1.0_wp_
if(nhn.gt.1) cth=(0.5_wp_*bb)**(nhn-1)*nhn/fact(nhn)
thn2=(0.5_wp_*cth*abs(emxy+ez*anprre*upl/ygn))**2
thn2u=upr2*thn2
else
! Full polarization term
nm=nhn-1
np=nhn+1
ajbnm=dbesjn(nm, bb)
ajbnp=dbesjn(np, bb)
ajbn=dbesjn(nhn, bb)
thn2u=(abs(ez*ajbn*upl+upr*(ajbnp*epxy+ajbnm*emxy)/2.0_wp_))**2
end if
end if
end if
fpp=ee*thn2u
end function fpp
function fjch(upl,extrapar,npar)
!
! computation of integral for current density
! integrand for Cohen model with trapping
!
! integration variable upl passed explicitly. Other variables passed
! as array of extra parameters of length npar=size(extrapar).
! variables with index 1..nfpp must be passed to fpp
! variable with index nfpp+1 is zeff
! variables with index gt nfpp+1 are specific of the cd model
!
! extrapar(2) = anpl
! extrapar(4) = Re(anprw)
! extrapar(13) = ygn
!
! extrapar(14) = zeff
! extrapar(15) = rb
! extrapar(16) = alams
! extrapar(17) = pa
! extrapar(18) = fp0s
!
use conical, only : fconic
implicit none
! arguments
integer :: npar
real(wp_) :: upl,fjch
real(wp_), dimension(npar) :: extrapar
! local variables
real(wp_) :: anpl,anprre,ygn,zeff,rb,alams,pa,fp0s, &
upr2,gam,u2,u,z5,xi,xib,xibi,fu2b,fu2,gu,gg,dgg,alam,fp0, &
dfp0,fh,dfhl,eta
anpl=extrapar(2)
anprre=extrapar(4)
ygn=extrapar(13)
zeff=extrapar(nfpp1)
rb=extrapar(nfpp2)
alams=extrapar(nfpp3)
pa=extrapar(nfpp4)
fp0s=extrapar(nfpp5)
gam=anpl*upl+ygn
u2=gam*gam-1.0_wp_
upr2=u2-upl*upl
u=sqrt(u2)
z5=Zeff+5.0_wp_
xi=1.0_wp_/z5**2
xib=1.0_wp_-xi
xibi=1.0_wp_/xib
fu2b=1.0_wp_+xib*u2
fu2=1.0_wp_+xi*u2
gu=(1.0_wp_-1.0_wp_/fu2b**xibi)/sqrt(fu2)
gg=u*gu/z5
dgg=(gu+u2*(2.0_wp_/fu2b**(1.0_wp_+xibi)/sqrt(fu2)-xi*gu/fu2))/z5
alam=sqrt(1.0_wp_-upr2/u2/rb)
fp0=fconic(alam,pa,0)
dfp0=-(pa*pa/2.0_wp_+0.125_wp_)
if (alam.lt.1.0_wp_) dfp0=-fconic(alam,pa,1)/sqrt(1.0_wp_-alam**2)
fh=alam*(1.0_wp_-alams*fp0/(alam*fp0s))
dfhl=1.0_wp_-alams*dfp0/fp0s
eta=gam*fh*(gg/u+dgg)+upl*(anpl*u2-upl*gam)*gg*dfhl/(u2*u*rb*alam)
if(upl.lt.0.0_wp_) eta=-eta
fjch=eta*fpp(upl,extrapar(1:nfpp),nfpp)
end function fjch
function fjch0(upl,extrapar,npar)
!
! computation of integral for current density
! integrand for Cohen model without trapping
!
! integration variable upl passed explicitly. Other variables passed
! as array of extra parameters of length npar=size(extrapar).
! variables with index 1..nfpp must be passed to fpp
! variable with index nfpp+1 is zeff
! variables with index gt nfpp+1 are specific of the cd model
!
! extrapar(2) = anpl
! extrapar(13) = ygn
!
! extrapar(14) = zeff
!
implicit none
! arguments
real(wp_) :: upl,fjch0
integer :: npar
real(wp_), dimension(npar) :: extrapar
! local variables
real(wp_) :: anpl,ygn,zeff,gam,u2,u,z5,xi,xib,xibi,fu2b,fu2,gu,gg,dgg,eta
!
anpl=extrapar(2)
ygn=extrapar(13)
zeff=extrapar(nfpp1)
gam=anpl*upl+ygn
u2=gam*gam-1.0_wp_
u=sqrt(u2)
z5=Zeff+5.0_wp_
xi=1.0_wp_/z5**2
xib=1.0_wp_-xi
xibi=1.0_wp_/xib
fu2b=1.0_wp_+xib*u2
fu2=1.0_wp_+xi*u2
gu=(1.0_wp_-1.0_wp_/fu2b**xibi)/sqrt(fu2)
gg=u*gu/z5
dgg=(gu+u2*(2.0_wp_/fu2b**(1.0_wp_+xibi)/sqrt(fu2)-xi*gu/fu2))/z5
eta=anpl*gg+gam*upl*dgg/u
fjch0=eta*fpp(upl,extrapar(1:nfpp),nfpp)
end function fjch0
function fjncl(upl,extrapar,npar)
!
! computation of integral for current density
! integrand for momentum conserv. model K(u) from Maruschenko
! gg=F(u)/u with F(u) as in Cohen paper
!
! integration variable upl passed explicitly. Other variables passed
! as array of extra parameters of length npar=size(extrapar).
! variables with index 1..nfpp must be passed to fpp
! variable with index nfpp+1 is zeff
! variables with index gt nfpp+1 are specific of the cd model
!
! extrapar(2) = anpl
! extrapar(3) = amu
! extrapar(13) = ygn
!
! extrapar(14) = zeff
! extrapar(15) = fc
! extrapar(16) = rbx
! extrapar(17:16+(npar-16)/2) = tlm
! extrapar(17+(npar-16)/2:npar) = chlm
!
use dierckx, only : splev,splder
implicit none
! arguments
integer :: npar
real(wp_) :: upl,fjncl
real(wp_), dimension(npar) :: extrapar
! local variables
integer :: nlm
real(wp_) :: anpl,amu,ygn,zeff,fc,rbx,gam,u2,u,upr2, &
bth,uth,fk,dfk,alam,fu,dfu,eta
! local variables
integer :: ier
real(wp_), dimension((npar-nfpp3)/2) :: wrk
real(wp_), dimension(1) :: xs,ys
!
anpl=extrapar(2)
amu=extrapar(3)
ygn=extrapar(13)
zeff=extrapar(nfpp1)
fc=extrapar(nfpp2)
rbx=extrapar(nfpp3)
gam=anpl*upl+ygn
u2=gam*gam-1.0_wp_
u=sqrt(u2)
upr2=u2-upl*upl
bth=sqrt(2.0_wp_/amu)
uth=u/bth
call GenSpitzFunc(Zeff,fc,uth,u,gam,fk,dfk)
fk=fk*(4.0_wp_/amu**2)
dfk=dfk*(2.0_wp_/amu)*bth
alam=upr2/u2/rbx
xs(1)=alam
nlm=(npar-nfpp3)/2
!
! extrapar(17:16+(npar-16)/2) = tlm
! extrapar(17+(npar-16)/2:npar) = chlm
!
call splev(extrapar(nfpp4:nfpp3+nlm),nlm,extrapar(nfpp4+nlm:npar),3, &
xs(1),ys(1),1,ier)
fu=ys(1)
call splder(extrapar(nfpp4:nfpp3+nlm),nlm,extrapar(nfpp4+nlm:npar),3,1, &
xs(1),ys(1),1,wrk,ier)
dfu=ys(1)
eta=gam*fu*dfk/u-2.0_wp_*(anpl-gam*upl/u2)*fk*dfu*upl/u2/rbx
if(upl.lt.0) eta=-eta
fjncl=eta*fpp(upl,extrapar(1:nfpp),nfpp)
end function fjncl
SUBROUTINE GenSpitzFunc(Zeff,fc,u,q,gam, K,dKdu)
!=======================================================================
! Author: N.B.Marushchenko
! June 2005: as start point the subroutine of Ugo Gasparino (198?)
! SpitzFunc() is taken and modified.
! 1. adapted to the Fortran-95
! 2. derivative of Spitzer function is added
! 3. separation for 2 brunches is done:
! 1st is referenced as 'with conservation of the moment',
! 2nd - as 'high speed limit'.
! The last one is taken from the Lin-Liu formulation
! (Phys.Plasmas 10 (2003) 4064) with K = F*fc.
! The asymptotical high speed limit (Taguchi-Fisch model)
! is also included as the reference case.
! Feb. 2008: non-relativ. version is replaced by the relativistic one;
! the method is the the same, but the trial-function is
! based on the relativistic formulation.
! The relativistic corrections for the collisional operator
! up to the second order, i.e. (1/mu)**2, are applied.
! Sep. 2008: generalized Spitzer function for arbitrary collisionality
! is implemented. The model is based on the concept of
! the "effective trapped particles fraction".
! The different.-integral kinetic equation for the generalized
! Spitzer function is produced with help of subroutines
! ArbColl_TrappFract_Array and ArbColl_SpitzFunc_Array,
! where the subroutines of H. Maassberg are called).
!========================================================================
! Spitzer function with & w/o trapped particle effects is given by:
!
! K(x) = x/gamma*(d1*x+d2*x^2+d4*x^3+d4*x^4),
!
! where x = v/v_th and gamma=1 for non-relativistic version (Ugo),
! or x = p/p_th for relativistic version (N.M., February 2008).
! Note, that somewhere the function F(x) instead of K(x) is applied,
!
! F(x) = K(x)/fc.
!
! Numerical inversion of the 5x5 symmetric matrix obtained from the
! generalized Spitzer problem (see paper of Taguchi for the equation
! and paper of Hirshman for the variational approach bringing to the
! matrix to be inverted).
!
! The numerical method used is an improved elimination scheme
! (Banachiewiczs-Cholesky-Crout method).
! This method is particularly simple for symmetric matrix.
! As a reference see "Mathematical Handbook" by Korn & Korn, p.635-636.
!
! Refs.: 1. S.P. Hirshman, Phys. Fluids 23 (1980) 1238
! 2. M. Rome' et al., Plasma Phys. Contr. Fus. 40 (1998) 511
! 3. N.B. Marushchenko et al., Fusion Sci. Technol. 55 (2009) 180
!========================================================================
! INPUTS:
! u - p/sqrt(2mT)
! q - p/mc;
! gam - relativistic factor;
! Zeff - effective charge;
! fc - fraction of circulating particles.
!
! OUTPUTS:
! K - Spitzer's function
! dKdu = dK/du, i.e. its derivative over normalized momentum
!=======================================================================
use const_and_precisions, only : comp_eps
IMPLICIT NONE
REAL(wp_), INTENT(in) :: Zeff,fc,u,q,gam
REAL(wp_), INTENT(out) :: K,dKdu
REAL(wp_) :: gam1,gam2,gam3
K = 0
dKdu = 0
IF (u < comp_eps) RETURN
SELECT CASE(adj_appr(2))
CASE('m') !--------------- momentum conservation ------------------!
gam1 = gam !
IF (adj_appr(4) == 'n') gam1 = 1 !
gam2 = gam1*gam1 !
gam3 = gam1*gam2 !
K = u/gam1*u*(sfd(1)+u*(sfd(2)+u*(sfd(3)+u*sfd(4)))) !
dKdu = u/gam3* (sfd(1)*(1+ gam2)+u*(sfd(2)*(1+2*gam2)+ & !
u*(sfd(3)*(1+3*gam2)+u* sfd(4)*(1+4*gam2)))) !
!--------------------- end momentum conservation -------------------!
CASE('h') !---------------- high-speed-limit ----------------------!
IF (adj_appr(4) == 'n') THEN !- non-relativ. asymptotic form -!
K = u**4 *fc/(Zeff+1+4*fc) !- (Taguchi-Fisch model) -!
dKdu = 4*u**3 *fc/(Zeff+1+4*fc) !
ELSEIF (adj_appr(4) == 'r') THEN !- relativistic, Lin-Liu form. -!
CALL SpitzFunc_HighSpeedLimit(Zeff,fc,u,q,gam, K,dKdu) !
ENDIF !
CASE default !----------------------------------------------------!
PRINT*,'GenSpitzFunc: WARNING! Spitzer function is not defined.'
RETURN
END SELECT
END SUBROUTINE GenSpitzFunc
SUBROUTINE SpitzFuncCoeff(mu,Zeff,fc)
!=======================================================================
! Calculates the matrix coefficients required for the subroutine
! "GenSpitzFunc", where the Spitzer function is defined through the
! variational principle.
!
! Weakly relativistic (upgraded) version (10.09.2008).
! Apart of the non-relativistic matrix coefficients, taken from the
! old subroutine of Ugo Gasparino, the relativistic correction written
! as series in 1/mu^n (mu=mc2/T) powers is added. Two orders are taken
! into account, i.e. n=0,1,2.
!
! In this version, the coefficients "oee", i.e. Omega_ij, are formulated
! for arbitrary collisionality.
!
! INPUT VARIABLES:
! rho = sqrt(SS) with SS - flux-surface label (norm. magn. flux)
! ne - density, 1/m^3
! mu - mc2/Te
! Zeff - effective charge
! fc - fraction of circulating particles
!
! OUTPUT VARIABLES (defined as a global ones):
! sfd(1),...,sfd(4) - coefficients of the polynomial expansion of the
! "Spitzer"-function (the same as in the Hirshman paper)
!=======================================================================
use const_and_precisions, only : mc2_
IMPLICIT NONE
REAL(wp_), INTENT(in) :: mu,Zeff,fc
INTEGER :: n,i,j
REAL(wp_) :: rtc,rtc1,y,tn(1:nre)
REAL(wp_) :: m(0:4,0:4),g(0:4)
REAL(wp_) :: gam11,gam21,gam31,gam41,gam01, &
gam22,gam32,gam42,gam02, &
gam33,gam43,gam03, &
gam44,gam04,gam00
REAL(wp_) :: alp12,alp13,alp14,alp10, &
alp23,alp24,alp20, &
alp34,alp30,alp40
REAL(wp_) :: bet0,bet1,bet2,bet3,bet4,d0
LOGICAL :: renew,rel,newmu,newZ,newfc
REAL(wp_), SAVE :: sfdx(1:4) = 0
REAL(wp_), SAVE :: mu_old =-1, Zeff_old =-1, fc_old =-1
rel = mu < mc2_
newmu = abs(mu -mu_old ) > delta*mu
newZ = abs(Zeff-Zeff_old) > delta*Zeff
newfc = abs(fc -fc_old ) > delta*fc
SELECT CASE(adj_appr(1))
CASE ('l','c')
renew = (newmu .and. rel) .OR. newZ .OR. newfc
END SELECT
IF (.not.renew) THEN
sfd(:) = sfdx(:)
RETURN
ENDIF
tn(:) = 0
IF (adj_appr(4) == 'r') THEN
IF (nre > 0) THEN
!mu = min(mu,1.e3*mc2_)
tn(1) = 1/mu
DO n=2,min(2,nre)
tn(n) = tn(n-1)/mu
ENDDO
ENDIF
ENDIF
SELECT CASE(adj_appr(1))
CASE ('l','c') !---- both classical & collisionless limits ----!
rtc = (1-fc)/fc; rtc1 = rtc+1 !
!--- !
DO i=0,4 !
g(i) = vp_g(i,0) !
DO n=1,min(2,nre) !
g(i) = g(i) + tn(n)*vp_g(i,n) !
ENDDO !
!--- !
DO j=0,4 !
IF (i == 0 .or. j == 0 .or. j >= i) THEN !
y = vp_mee(i,j,0) + rtc *vp_oee(i,j,0) + & !
Zeff*rtc1*vp_mei(i,j,0) !
DO n=1,min(2,nre) !
y = y + (vp_mee(i,j,n) + rtc *vp_oee(i,j,n) + & !
Zeff*rtc1*vp_mei(i,j,n))*tn(n) !
ENDDO !
m(i,j) = y !
ENDIF !
ENDDO !
ENDDO !
DO i=2,4 !
DO j=1,i-1 !
m(i,j) = m(j,i) !
ENDDO !
ENDDO !
m(0,0) = 0 !
CASE default !------------------------------------------------!
PRINT*,'Green_Func: WARNING! Adjoint approach is not defined.'
RETURN
END SELECT
gam11 = m(1,1)
gam21 = m(2,1)
gam31 = m(3,1)
gam41 = m(4,1)
gam01 = m(0,1)
alp12 = m(1,2)/m(1,1)
alp13 = m(1,3)/m(1,1)
alp14 = m(1,4)/m(1,1)
alp10 = m(1,0)/m(1,1)
gam22 = m(2,2)-gam21*alp12
gam32 = m(3,2)-gam31*alp12
gam42 = m(4,2)-gam41*alp12
gam02 = m(0,2)-gam01*alp12
alp23 = gam32/gam22
alp24 = gam42/gam22
alp20 = gam02/gam22
gam33 = m(3,3)-gam31*alp13-gam32*alp23
gam43 = m(4,3)-gam41*alp13-gam42*alp23
gam03 = m(0,3)-gam01*alp13-gam02*alp23
alp34 = gam43/gam33
alp30 = gam03/gam33
gam44 = m(4,4)-gam41*alp14-gam42*alp24-gam43*alp34
gam04 = m(0,4)-gam01*alp14-gam02*alp24-gam03*alp34
alp40 = gam04/gam44
gam00 = m(0,0)-gam01*alp10-gam02*alp20-gam03*alp30-gam04*alp40
bet1 = g(1)/m(1,1)
bet2 = (g(2)-gam21*bet1)/gam22
bet3 = (g(3)-gam31*bet1-gam32*bet2)/gam33
bet4 = (g(4)-gam41*bet1-gam42*bet2-gam43*bet3)/gam44
bet0 = (g(0)-gam01*bet1-gam02*bet2-gam03*bet3-gam04*bet4)/gam00
d0 = bet0
sfd(4) = bet4-alp40*d0
sfd(3) = bet3-alp30*d0-alp34*sfd(4)
sfd(2) = bet2-alp20*d0-alp24*sfd(4)-alp23*sfd(3)
sfd(1) = bet1-alp10*d0-alp14*sfd(4)-alp13*sfd(3)-alp12*sfd(2)
fc_old = fc
mu_old = mu
Zeff_old = Zeff
sfdx(1:4) = sfd(1:4)
END SUBROUTINE SpitzFuncCoeff
SUBROUTINE SpitzFunc_HighSpeedLimit(Zeff,fc,u,q,gam, K,dKdu)
!=======================================================================
! Calculates the "Spitzer function" in high velocity limit, relativistic
! formulation: Lin-Liu et al., Phys.Pl. (2003),v10, 4064, Eq.(33).
!
! Inputs:
! Zeff - effective charge
! fc - fraction of circulating electrons
! u - p/(m*vte)
! q - p/mc
! gam - relativ. factor
!
! Outputs:
! K - Spitzer function
! dKdu - its derivative
!=======================================================================
use const_and_precisions, only : zero,one
use numint, only : quanc8
IMPLICIT NONE
REAL(wp_), INTENT(in) :: Zeff,fc,u,q,gam
REAL(wp_), INTENT(out) :: K,dKdu
INTEGER :: nfun
REAL(wp_) :: gam2,err,flag,Integr
REAL(wp_), PARAMETER :: a = zero, b = one, rtol = 1e-4_wp_, atol = 1e-12_wp_
r2 = (1+Zeff)/fc ! global parameter needed for integrand, HSL_f(t)
IF (u < 1e-2) THEN
K = u**4/(r2+4)
dKdu = 4*u**3/(r2+4)
RETURN
ENDIF
q2 = q*q ! for the integrand, HSL_f
gp1 = gam+1 ! ..
CALL quanc8(HSL_f,zero,one,atol,rtol,Integr,err,nfun,flag)
gam2 = gam*gam
K = u**4 * Integr
dKdu = (u/gam)**3 * (1-r2*gam2*Integr)
END SUBROUTINE SpitzFunc_HighSpeedLimit
FUNCTION HSL_f(t) RESULT(f)
!=======================================================================
! Integrand for the high-speed limit approach (Lin-Liu's formulation)
!=======================================================================
IMPLICIT NONE
REAL(wp_), INTENT(in) :: t
REAL(wp_) :: f,g
g = sqrt(1+t*t*q2)
f = t**(3+r2)/g**3 * (gp1/(g+1))**r2
END FUNCTION HSL_f
end module eccd

906
src/eierf.f90 Normal file
View File

@ -0,0 +1,906 @@
module eierf
use const_and_precisions, only : wp_, zero, one
implicit none
real(wp_), parameter, private :: half=0.5_wp_, two=2.0_wp_, three=3.0_wp_, &
four=4.0_wp_, six=6.0_wp_, twelve=12._wp_, sixten=16.0_wp_, &
two4=24.0_wp_, fourty=40.0_wp_
contains
! ======================================================================
! nist guide to available math software.
! fullsource for module ei from package specfun.
! retrieved from netlib on fri mar 26 05:52:39 1999.
! ======================================================================
subroutine calcei(arg,result,intt)
!----------------------------------------------------------------------
!
! this fortran 77 packet computes the exponential integrals ei(x),
! e1(x), and exp(-x)*ei(x) for real arguments x where
!
! integral (from t=-infinity to t=x) (exp(t)/t), x > 0,
! ei(x) =
! -integral (from t=-x to t=infinity) (exp(t)/t), x < 0,
!
! and where the first integral is a principal value integral.
! the packet contains three function type subprograms: ei, eone,
! and expei; and one subroutine type subprogram: calcei. the
! calling statements for the primary entries are
!
! y = ei(x), where x /= 0,
!
! y = eone(x), where x > 0,
! and
! y = expei(x), where x /= 0,
!
! and where the entry points correspond to the functions ei(x),
! e1(x), and exp(-x)*ei(x), respectively. the routine calcei
! is intended for internal packet use only, all computations within
! the packet being concentrated in this routine. the function
! subprograms invoke calcei with the fortran statement
! call calcei(arg,result,intt)
! where the parameter usage is as follows
!
! function parameters for calcei
! call arg result intt
!
! ei(x) x /= 0 ei(x) 1
! eone(x) x > 0 -ei(-x) 2
! expei(x) x /= 0 exp(-x)*ei(x) 3
!----------------------------------------------------------------------
implicit none
integer, intent(in) :: intt
real(wp_), intent(in) :: arg
real(wp_), intent(out) :: result
integer :: i
real(wp_) :: ei,frac,sump,sumq,t,w,x,xmx0,y,ysq
real(wp_), dimension(10) :: px,qx
!----------------------------------------------------------------------
! mathematical constants
! exp40 = exp(40)
! x0 = zero of ei
! x01/x11 + x02 = zero of ei to extra precision
!----------------------------------------------------------------------
real(wp_), parameter :: p037=0.037_wp_, &
exp40=2.3538526683701998541e17_wp_, x01=381.5_wp_, x11=1024.0_wp_, &
x02=-5.1182968633365538008e-5_wp_, x0=3.7250741078136663466e-1_wp_
!----------------------------------------------------------------------
! machine-dependent constants
!----------------------------------------------------------------------
real(wp_), parameter :: xinf=1.79e+308_wp_,xmax=716.351_wp_,xbig=701.84_wp_
!----------------------------------------------------------------------
! coefficients for -1.0 <= x < 0.0
!----------------------------------------------------------------------
real(wp_), dimension(7), parameter :: &
a=(/1.1669552669734461083368e2_wp_, 2.1500672908092918123209e3_wp_, &
1.5924175980637303639884e4_wp_, 8.9904972007457256553251e4_wp_, &
1.5026059476436982420737e5_wp_,-1.4815102102575750838086e5_wp_, &
5.0196785185439843791020_wp_/)
real(wp_), dimension(6), parameter :: &
b=(/4.0205465640027706061433e1_wp_, 7.5043163907103936624165e2_wp_, &
8.1258035174768735759855e3_wp_, 5.2440529172056355429883e4_wp_, &
1.8434070063353677359298e5_wp_, 2.5666493484897117319268e5_wp_/)
!----------------------------------------------------------------------
! coefficients for -4.0 <= x < -1.0
!----------------------------------------------------------------------
real(wp_), dimension(9), parameter :: &
c=(/3.828573121022477169108e-1_wp_, 1.107326627786831743809e+1_wp_, &
7.246689782858597021199e+1_wp_, 1.700632978311516129328e+2_wp_, &
1.698106763764238382705e+2_wp_, 7.633628843705946890896e+1_wp_, &
1.487967702840464066613e+1_wp_, 9.999989642347613068437e-1_wp_, &
1.737331760720576030932e-8_wp_/), &
d=(/8.258160008564488034698e-2_wp_, 4.344836335509282083360e+0_wp_, &
4.662179610356861756812e+1_wp_, 1.775728186717289799677e+2_wp_, &
2.953136335677908517423e+2_wp_, 2.342573504717625153053e+2_wp_, &
9.021658450529372642314e+1_wp_, 1.587964570758947927903e+1_wp_, &
1.000000000000000000000e+0_wp_/)
!----------------------------------------------------------------------
! coefficients for x < -4.0
!----------------------------------------------------------------------
real(wp_), dimension(10), parameter :: &
e=(/1.3276881505637444622987e+2_wp_,3.5846198743996904308695e+4_wp_, &
1.7283375773777593926828e+5_wp_,2.6181454937205639647381e+5_wp_, &
1.7503273087497081314708e+5_wp_,5.9346841538837119172356e+4_wp_, &
1.0816852399095915622498e+4_wp_,1.0611777263550331766871e03_wp_, &
5.2199632588522572481039e+1_wp_,9.9999999999999999087819e-1_wp_/),&
f=(/3.9147856245556345627078e+4_wp_,2.5989762083608489777411e+5_wp_, &
5.5903756210022864003380e+5_wp_,5.4616842050691155735758e+5_wp_, &
2.7858134710520842139357e+5_wp_,7.9231787945279043698718e+4_wp_, &
1.2842808586627297365998e+4_wp_,1.1635769915320848035459e+3_wp_, &
5.4199632588522559414924e+1_wp_,1.0_wp_/)
!----------------------------------------------------------------------
! coefficients for rational approximation to ln(x/a), |1-x/a| < .1
!----------------------------------------------------------------------
real(wp_), dimension(4), parameter :: &
plg=(/-2.4562334077563243311e+01_wp_,2.3642701335621505212e+02_wp_, &
-5.4989956895857911039e+02_wp_,3.5687548468071500413e+02_wp_/), &
qlg=(/-3.5553900764052419184e+01_wp_,1.9400230218539473193e+02_wp_, &
-3.3442903192607538956e+02_wp_,1.7843774234035750207e+02_wp_/)
!----------------------------------------------------------------------
! coefficients for 0.0 < x < 6.0,
! ratio of chebyshev polynomials
!----------------------------------------------------------------------
real(wp_), dimension(10), parameter :: &
p=(/-1.2963702602474830028590e01_wp_,-1.2831220659262000678155e03_wp_, &
-1.4287072500197005777376e04_wp_,-1.4299841572091610380064e06_wp_, &
-3.1398660864247265862050e05_wp_,-3.5377809694431133484800e08_wp_, &
3.1984354235237738511048e08_wp_,-2.5301823984599019348858e10_wp_, &
1.2177698136199594677580e10_wp_,-2.0829040666802497120940e11_wp_/),&
q=(/ 7.6886718750000000000000e01_wp_,-5.5648470543369082846819e03_wp_, &
1.9418469440759880361415e05_wp_,-4.2648434812177161405483e06_wp_, &
6.4698830956576428587653e07_wp_,-7.0108568774215954065376e08_wp_, &
5.4229617984472955011862e09_wp_,-2.8986272696554495342658e10_wp_, &
9.8900934262481749439886e10_wp_,-8.9673749185755048616855e10_wp_/)
!----------------------------------------------------------------------
! j-fraction coefficients for 6.0 <= x < 12.0
!----------------------------------------------------------------------
real(wp_), dimension(10), parameter :: &
r=(/-2.645677793077147237806_wp_,-2.378372882815725244124_wp_, &
-2.421106956980653511550e01_wp_, 1.052976392459015155422e01_wp_, &
1.945603779539281810439e01_wp_,-3.015761863840593359165e01_wp_, &
1.120011024227297451523e01_wp_,-3.988850730390541057912_wp_, &
9.565134591978630774217_wp_, 9.981193787537396413219e-1_wp_/)
real(wp_), dimension(9), parameter :: &
s=(/ 1.598517957704779356479e-4_wp_, 4.644185932583286942650_wp_, &
3.697412299772985940785e02_wp_,-8.791401054875438925029_wp_, &
7.608194509086645763123e02_wp_, 2.852397548119248700147e01_wp_, &
4.731097187816050252967e02_wp_,-2.369210235636181001661e02_wp_, &
1.249884822712447891440_wp_/)
!----------------------------------------------------------------------
! j-fraction coefficients for 12.0 <= x < 24.0
!----------------------------------------------------------------------
real(wp_), dimension(10), parameter :: &
p1=(/-1.647721172463463140042_wp_,-1.860092121726437582253e01_wp_, &
-1.000641913989284829961e01_wp_,-2.105740799548040450394e01_wp_, &
-9.134835699998742552432e-1_wp_,-3.323612579343962284333e01_wp_, &
2.495487730402059440626e01_wp_, 2.652575818452799819855e01_wp_, &
-1.845086232391278674524_wp_, 9.999933106160568739091e-1_wp_/)
real(wp_), dimension(9), parameter :: &
q1=(/ 9.792403599217290296840e01_wp_, 6.403800405352415551324e01_wp_, &
5.994932325667407355255e01_wp_, 2.538819315630708031713e02_wp_, &
4.429413178337928401161e01_wp_, 1.192832423968601006985e03_wp_, &
1.991004470817742470726e02_wp_,-1.093556195391091143924e01_wp_, &
1.001533852045342697818_wp_/)
!----------------------------------------------------------------------
! j-fraction coefficients for x >= 24.0
!----------------------------------------------------------------------
real(wp_), dimension(10), parameter :: &
p2=(/ 1.75338801265465972390e02_wp_,-2.23127670777632409550e02_wp_, &
-1.81949664929868906455e01_wp_,-2.79798528624305389340e01_wp_, &
-7.63147701620253630855_wp_,-1.52856623636929636839e01_wp_, &
-7.06810977895029358836_wp_,-5.00006640413131002475_wp_, &
-3.00000000320981265753_wp_, 1.00000000000000485503_wp_/)
real(wp_), dimension(9), parameter :: &
q2=(/ 3.97845977167414720840e04_wp_, 3.97277109100414518365_wp_, &
1.37790390235747998793e02_wp_, 1.17179220502086455287e02_wp_, &
7.04831847180424675988e01_wp_,-1.20187763547154743238e01_wp_, &
-7.99243595776339741065_wp_,-2.99999894040324959612_wp_, &
1.99999999999048104167_wp_/)
!----------------------------------------------------------------------
x = arg
if (x == zero) then
ei = -xinf
if (intt == 2) ei = -ei
else if ((x < zero) .or. (intt == 2)) then
!----------------------------------------------------------------------
! calculate ei for negative argument or for e1.
!----------------------------------------------------------------------
y = abs(x)
if (y <= one) then
sump = a(7) * y + a(1)
sumq = y + b(1)
do i = 2, 6
sump = sump * y + a(i)
sumq = sumq * y + b(i)
end do
ei = log(y) - sump / sumq
if (intt == 3) ei = ei * exp(y)
else if (y <= four) then
w = one / y
sump = c(1)
sumq = d(1)
do i = 2, 9
sump = sump * w + c(i)
sumq = sumq * w + d(i)
end do
ei = - sump / sumq
if (intt /= 3) ei = ei * exp(-y)
else
if ((y > xbig) .and. (intt < 3)) then
ei = zero
else
w = one / y
sump = e(1)
sumq = f(1)
do i = 2, 10
sump = sump * w + e(i)
sumq = sumq * w + f(i)
end do
ei = -w * (one - w * sump / sumq )
if (intt /= 3) ei = ei * exp(-y)
end if
end if
if (intt == 2) ei = -ei
else if (x < six) then
!----------------------------------------------------------------------
! to improve conditioning, rational approximations are expressed
! in terms of chebyshev polynomials for 0 <= x < 6, and in
! continued fraction form for larger x.
!----------------------------------------------------------------------
t = x + x
t = t / three - two
px(1) = zero
qx(1) = zero
px(2) = p(1)
qx(2) = q(1)
do i = 2, 9
px(i+1) = t * px(i) - px(i-1) + p(i)
qx(i+1) = t * qx(i) - qx(i-1) + q(i)
end do
sump = half * t * px(10) - px(9) + p(10)
sumq = half * t * qx(10) - qx(9) + q(10)
frac = sump / sumq
xmx0 = (x - x01/x11) - x02
if (abs(xmx0) >= p037) then
ei = log(x/x0) + xmx0 * frac
if (intt == 3) ei = exp(-x) * ei
else
!----------------------------------------------------------------------
! special approximation to ln(x/x0) for x close to x0
!----------------------------------------------------------------------
y = xmx0 / (x + x0)
ysq = y*y
sump = plg(1)
sumq = ysq + qlg(1)
do i = 2, 4
sump = sump*ysq + plg(i)
sumq = sumq*ysq + qlg(i)
end do
ei = (sump / (sumq*(x+x0)) + frac) * xmx0
if (intt == 3) ei = exp(-x) * ei
end if
else if (x < twelve) then
frac = zero
do i = 1, 9
frac = s(i) / (r(i) + x + frac)
end do
ei = (r(10) + frac) / x
if (intt /= 3) ei = ei * exp(x)
else if (x <= two4) then
frac = zero
do i = 1, 9
frac = q1(i) / (p1(i) + x + frac)
end do
ei = (p1(10) + frac) / x
if (intt /= 3) ei = ei * exp(x)
else
if ((x >= xmax) .and. (intt < 3)) then
ei = xinf
else
y = one / x
frac = zero
do i = 1, 9
frac = q2(i) / (p2(i) + x + frac)
end do
frac = p2(10) + frac
ei = y + y * y * frac
if (intt /= 3) then
if (x <= xmax-two4) then
ei = ei * exp(x)
else
!----------------------------------------------------------------------
! calculation reformulated to avoid premature overflow
!----------------------------------------------------------------------
ei = (ei * exp(x-fourty)) * exp40
end if
end if
end if
end if
result = ei
end subroutine calcei
function ei(x)
!--------------------------------------------------------------------
!
! this function program computes approximate values for the
! exponential integral ei(x), where x is real.
!
! author: w. j. cody
!
! latest modification: january 12, 1988
!
!--------------------------------------------------------------------
implicit none
integer :: intt
real(wp_) :: ei
real(wp_), intent(in) :: x
real(wp_) :: result
!--------------------------------------------------------------------
intt = 1
call calcei(x,result,intt)
ei = result
end function ei
function expei(x)
!--------------------------------------------------------------------
!
! this function program computes approximate values for the
! function exp(-x) * ei(x), where ei(x) is the exponential
! integral, and x is real.
!
! author: w. j. cody
!
! latest modification: january 12, 1988
!
!--------------------------------------------------------------------
implicit none
integer :: intt
real(wp_) :: expei
real(wp_), intent(in) :: x
real(wp_) :: result
!--------------------------------------------------------------------
intt = 3
call calcei(x,result,intt)
expei = result
end function expei
function eone(x)
!--------------------------------------------------------------------
!
! this function program computes approximate values for the
! exponential integral e1(x), where x is real.
!
! author: w. j. cody
!
! latest modification: january 12, 1988
!
!--------------------------------------------------------------------
implicit none
integer :: intt
real(wp_) :: eone
real(wp_), intent(in) :: x
real(wp_) :: result
!--------------------------------------------------------------------
intt = 2
call calcei(x,result,intt)
eone = result
end function eone
! ======================================================================
! calcei3 = calcei for int=3
! ======================================================================
subroutine calcei3(arg,result)
!----------------------------------------------------------------------
!
! this fortran 77 packet computes the exponential integrals ei(x),
! e1(x), and exp(-x)*ei(x) for real arguments x where
!
! integral (from t=-infinity to t=x) (exp(t)/t), x > 0,
! ei(x) =
! -integral (from t=-x to t=infinity) (exp(t)/t), x < 0,
!
! and where the first integral is a principal value integral.
! the packet contains three function type subprograms: ei, eone,
! and expei; and one subroutine type subprogram: calcei. the
! calling statements for the primary entries are
!
! y = ei(x), where x /= 0,
!
! y = eone(x), where x > 0,
! and
! y = expei(x), where x /= 0,
!
! and where the entry points correspond to the functions ei(x),
! e1(x), and exp(-x)*ei(x), respectively. the routine calcei
! is intended for internal packet use only, all computations within
! the packet being concentrated in this routine. the function
! subprograms invoke calcei with the fortran statement
! call calcei(arg,result,int)
! where the parameter usage is as follows
!
! function parameters for calcei
! call arg result int
!
! ei(x) x /= 0 ei(x) 1
! eone(x) x > 0 -ei(-x) 2
! expei(x) x /= 0 exp(-x)*ei(x) 3
!----------------------------------------------------------------------
implicit none
real(wp_), intent(in) :: arg
real(wp_), intent(out) :: result
integer :: i
real(wp_) :: ei,frac,sump,sumq,t,w,x,xmx0,y,ysq
real(wp_), dimension(10) :: px,qx
!----------------------------------------------------------------------
! mathematical constants
! exp40 = exp(40)
! x0 = zero of ei
! x01/x11 + x02 = zero of ei to extra precision
!----------------------------------------------------------------------
real(wp_), parameter :: p037=0.037_wp_, &
x01=381.5_wp_, x11=1024.0_wp_, x02=-5.1182968633365538008e-5_wp_, &
x0=3.7250741078136663466e-1_wp_
!----------------------------------------------------------------------
! machine-dependent constants
!----------------------------------------------------------------------
real(wp_), parameter :: xinf=1.79e+308_wp_
!----------------------------------------------------------------------
! coefficients for -1.0 <= x < 0.0
!----------------------------------------------------------------------
real(wp_), dimension(7), parameter :: &
a=(/1.1669552669734461083368e2_wp_, 2.1500672908092918123209e3_wp_, &
1.5924175980637303639884e4_wp_, 8.9904972007457256553251e4_wp_, &
1.5026059476436982420737e5_wp_,-1.4815102102575750838086e5_wp_, &
5.0196785185439843791020_wp_/)
real(wp_), dimension(6), parameter :: &
b=(/4.0205465640027706061433e1_wp_, 7.5043163907103936624165e2_wp_, &
8.1258035174768735759855e3_wp_, 5.2440529172056355429883e4_wp_, &
1.8434070063353677359298e5_wp_, 2.5666493484897117319268e5_wp_/)
!----------------------------------------------------------------------
! coefficients for -4.0 <= x < -1.0
!----------------------------------------------------------------------
real(wp_), dimension(9), parameter :: &
c=(/3.828573121022477169108e-1_wp_, 1.107326627786831743809e+1_wp_, &
7.246689782858597021199e+1_wp_, 1.700632978311516129328e+2_wp_, &
1.698106763764238382705e+2_wp_, 7.633628843705946890896e+1_wp_, &
1.487967702840464066613e+1_wp_, 9.999989642347613068437e-1_wp_, &
1.737331760720576030932e-8_wp_/), &
d=(/8.258160008564488034698e-2_wp_, 4.344836335509282083360e+0_wp_, &
4.662179610356861756812e+1_wp_, 1.775728186717289799677e+2_wp_, &
2.953136335677908517423e+2_wp_, 2.342573504717625153053e+2_wp_, &
9.021658450529372642314e+1_wp_, 1.587964570758947927903e+1_wp_, &
1.000000000000000000000e+0_wp_/)
!----------------------------------------------------------------------
! coefficients for x < -4.0
!----------------------------------------------------------------------
real(wp_), dimension(10), parameter :: &
e=(/1.3276881505637444622987e+2_wp_,3.5846198743996904308695e+4_wp_, &
1.7283375773777593926828e+5_wp_,2.6181454937205639647381e+5_wp_, &
1.7503273087497081314708e+5_wp_,5.9346841538837119172356e+4_wp_, &
1.0816852399095915622498e+4_wp_,1.0611777263550331766871e03_wp_, &
5.2199632588522572481039e+1_wp_,9.9999999999999999087819e-1_wp_/), &
f=(/3.9147856245556345627078e+4_wp_,2.5989762083608489777411e+5_wp_, &
5.5903756210022864003380e+5_wp_,5.4616842050691155735758e+5_wp_, &
2.7858134710520842139357e+5_wp_,7.9231787945279043698718e+4_wp_, &
1.2842808586627297365998e+4_wp_,1.1635769915320848035459e+3_wp_, &
5.4199632588522559414924e+1_wp_,1.0_wp_/)
!----------------------------------------------------------------------
! coefficients for rational approximation to ln(x/a), |1-x/a| < .1
!----------------------------------------------------------------------
real(wp_), dimension(4), parameter :: &
plg=(/-2.4562334077563243311e+01_wp_,2.3642701335621505212e+02_wp_, &
-5.4989956895857911039e+02_wp_,3.5687548468071500413e+02_wp_/), &
qlg=(/-3.5553900764052419184e+01_wp_,1.9400230218539473193e+02_wp_, &
-3.3442903192607538956e+02_wp_,1.7843774234035750207e+02_wp_/)
!----------------------------------------------------------------------
! coefficients for 0.0 < x < 6.0,
! ratio of chebyshev polynomials
!----------------------------------------------------------------------
real(wp_), dimension(10), parameter :: &
p=(/-1.2963702602474830028590e01_wp_,-1.2831220659262000678155e03_wp_, &
-1.4287072500197005777376e04_wp_,-1.4299841572091610380064e06_wp_, &
-3.1398660864247265862050e05_wp_,-3.5377809694431133484800e08_wp_, &
3.1984354235237738511048e08_wp_,-2.5301823984599019348858e10_wp_, &
1.2177698136199594677580e10_wp_,-2.0829040666802497120940e11_wp_/),&
q=(/ 7.6886718750000000000000e01_wp_,-5.5648470543369082846819e03_wp_, &
1.9418469440759880361415e05_wp_,-4.2648434812177161405483e06_wp_, &
6.4698830956576428587653e07_wp_,-7.0108568774215954065376e08_wp_, &
5.4229617984472955011862e09_wp_,-2.8986272696554495342658e10_wp_, &
9.8900934262481749439886e10_wp_,-8.9673749185755048616855e10_wp_/)
!----------------------------------------------------------------------
! j-fraction coefficients for 6.0 <= x < 12.0
!----------------------------------------------------------------------
real(wp_), dimension(10), parameter :: &
r=(/-2.645677793077147237806_wp_,-2.378372882815725244124_wp_, &
-2.421106956980653511550e01_wp_, 1.052976392459015155422e01_wp_, &
1.945603779539281810439e01_wp_,-3.015761863840593359165e01_wp_, &
1.120011024227297451523e01_wp_,-3.988850730390541057912_wp_, &
9.565134591978630774217_wp_, 9.981193787537396413219e-1_wp_/)
real(wp_), dimension(9), parameter :: &
s=(/ 1.598517957704779356479e-4_wp_, 4.644185932583286942650_wp_, &
3.697412299772985940785e02_wp_,-8.791401054875438925029_wp_, &
7.608194509086645763123e02_wp_, 2.852397548119248700147e01_wp_, &
4.731097187816050252967e02_wp_,-2.369210235636181001661e02_wp_, &
1.249884822712447891440_wp_/)
!----------------------------------------------------------------------
! j-fraction coefficients for 12.0 <= x < 24.0
!----------------------------------------------------------------------
real(wp_), dimension(10), parameter :: &
p1=(/-1.647721172463463140042_wp_,-1.860092121726437582253e01_wp_, &
-1.000641913989284829961e01_wp_,-2.105740799548040450394e01_wp_, &
-9.134835699998742552432e-1_wp_,-3.323612579343962284333e01_wp_, &
2.495487730402059440626e01_wp_, 2.652575818452799819855e01_wp_, &
-1.845086232391278674524_wp_, 9.999933106160568739091e-1_wp_/)
real(wp_), dimension(9), parameter :: &
q1=(/ 9.792403599217290296840e01_wp_, 6.403800405352415551324e01_wp_, &
5.994932325667407355255e01_wp_, 2.538819315630708031713e02_wp_, &
4.429413178337928401161e01_wp_, 1.192832423968601006985e03_wp_, &
1.991004470817742470726e02_wp_,-1.093556195391091143924e01_wp_, &
1.001533852045342697818_wp_/)
!----------------------------------------------------------------------
! j-fraction coefficients for x >= 24.0
!----------------------------------------------------------------------
real(wp_), dimension(10), parameter :: &
p2=(/ 1.75338801265465972390e02_wp_,-2.23127670777632409550e02_wp_, &
-1.81949664929868906455e01_wp_,-2.79798528624305389340e01_wp_, &
-7.63147701620253630855_wp_,-1.52856623636929636839e01_wp_, &
-7.06810977895029358836_wp_,-5.00006640413131002475_wp_, &
-3.00000000320981265753_wp_, 1.00000000000000485503_wp_/)
real(wp_), dimension(9), parameter :: &
q2=(/ 3.97845977167414720840e04_wp_, 3.97277109100414518365_wp_, &
1.37790390235747998793e02_wp_, 1.17179220502086455287e02_wp_, &
7.04831847180424675988e01_wp_,-1.20187763547154743238e01_wp_, &
-7.99243595776339741065_wp_,-2.99999894040324959612_wp_, &
1.99999999999048104167_wp_/)
!----------------------------------------------------------------------
x = arg
if (x == zero) then
ei = -xinf
else if ((x < zero)) then
!----------------------------------------------------------------------
! calculate ei for negative argument or for e1.
!----------------------------------------------------------------------
y = abs(x)
if (y <= one) then
sump = a(7) * y + a(1)
sumq = y + b(1)
do i = 2, 6
sump = sump * y + a(i)
sumq = sumq * y + b(i)
end do
ei = (log(y) - sump / sumq ) * exp(y)
else if (y <= four) then
w = one / y
sump = c(1)
sumq = d(1)
do i = 2, 9
sump = sump * w + c(i)
sumq = sumq * w + d(i)
end do
ei = - sump / sumq
else
w = one / y
sump = e(1)
sumq = f(1)
do i = 2, 10
sump = sump * w + e(i)
sumq = sumq * w + f(i)
end do
ei = -w * (one - w * sump / sumq )
end if
else if (x < six) then
!----------------------------------------------------------------------
! to improve conditioning, rational approximations are expressed
! in terms of chebyshev polynomials for 0 <= x < 6, and in
! continued fraction form for larger x.
!----------------------------------------------------------------------
t = x + x
t = t / three - two
px(1) = zero
qx(1) = zero
px(2) = p(1)
qx(2) = q(1)
do i = 2, 9
px(i+1) = t * px(i) - px(i-1) + p(i)
qx(i+1) = t * qx(i) - qx(i-1) + q(i)
end do
sump = half * t * px(10) - px(9) + p(10)
sumq = half * t * qx(10) - qx(9) + q(10)
frac = sump / sumq
xmx0 = (x - x01/x11) - x02
if (abs(xmx0) >= p037) then
ei = exp(-x) * ( log(x/x0) + xmx0 * frac )
else
!----------------------------------------------------------------------
! special approximation to ln(x/x0) for x close to x0
!----------------------------------------------------------------------
y = xmx0 / (x + x0)
ysq = y*y
sump = plg(1)
sumq = ysq + qlg(1)
do i = 2, 4
sump = sump*ysq + plg(i)
sumq = sumq*ysq + qlg(i)
end do
ei = exp(-x) * (sump / (sumq*(x+x0)) + frac) * xmx0
end if
else if (x < twelve) then
frac = zero
do i = 1, 9
frac = s(i) / (r(i) + x + frac)
end do
ei = (r(10) + frac) / x
else if (x <= two4) then
frac = zero
do i = 1, 9
frac = q1(i) / (p1(i) + x + frac)
end do
ei = (p1(10) + frac) / x
else
y = one / x
frac = zero
do i = 1, 9
frac = q2(i) / (p2(i) + x + frac)
end do
frac = p2(10) + frac
ei = y + y * y * frac
end if
result = ei
end subroutine calcei3
! subroutine calerf(arg,result,jintt)
!!------------------------------------------------------------------
!!
!! this packet evaluates erf(x), erfc(x), and exp(x*x)*erfc(x)
!! for a real argument x. it contains three function type
!! subprograms: erf, erfc, and erfcx (or derf, derfc, and derfcx),
!! and one subroutine type subprogram, calerf. the calling
!! statements for the primary entries are:
!!
!! y=erf(x) (or y=derf(x)),
!!
!! y=erfc(x) (or y=derfc(x)),
!! and
!! y=erfcx(x) (or y=derfcx(x)).
!!
!! the routine calerf is intended for internal packet use only,
!! all computations within the packet being concentrated in this
!! routine. the function subprograms invoke calerf with the
!! statement
!!
!! call calerf(arg,result,jintt)
!!
!! where the parameter usage is as follows
!!
!! function parameters for calerf
!! call arg result jintt
!!
!! erf(arg) any real argument erf(arg) 0
!! erfc(arg) abs(arg) < xbig erfc(arg) 1
!! erfcx(arg) xneg < arg < xmax erfcx(arg) 2
!!
!!*******************************************************************
!!*******************************************************************
!!
!! Explanation of machine-dependent constants
!!
!! XMIN = the smallest positive floating-point number.
!! XINF = the largest positive finite floating-point number.
!! XNEG = the largest negative argument acceptable to ERFCX;
!! the negative of the solution to the equation
!! 2*exp(x*x) = XINF.
!! XSMALL = argument below which erf(x) may be represented by
!! 2*x/sqrt(pi) and above which x*x will not underflow.
!! A conservative value is the largest machine number X
!! such that 1.0 + X = 1.0 to machine precision.
!! XBIG = largest argument acceptable to ERFC; solution to
!! the equation: W(x) * (1-0.5/x**2) = XMIN, where
!! W(x) = exp(-x*x)/[x*sqrt(pi)].
!! XHUGE = argument above which 1.0 - 1/(2*x*x) = 1.0 to
!! machine precision. A conservative value is
!! 1/[2*sqrt(XSMALL)]
!! XMAX = largest acceptable argument to ERFCX; the minimum
!! of XINF and 1/[sqrt(pi)*XMIN].
!!
!!*******************************************************************
!!*******************************************************************
!!
!! error returns
!!
!! the program returns erfc = 0 for arg >= xbig;
!!
!! erfcx = xinf for arg < xneg;
!! and
!! erfcx = 0 for arg >= xmax.
!!
!!
!! intrinsic functions required are:
!!
!! abs, aint, exp
!!
!!
!! author: w. j. cody
!! mathematics and computer science division
!! argonne national laboratory
!! argonne, il 60439
!!
!! latest modification: march 19, 1990
!!
!!------------------------------------------------------------------
! implicit none
! real(wp_), intent(in) :: arg
! real(wp_), intent(out) :: result
! integer, intent(in) :: jintt
! integer :: i
! real(wp_) :: del,x,xden,xnum,y,ysq
!!------------------------------------------------------------------
!! mathematical constants
!!------------------------------------------------------------------
! real(wp_), parameter :: sqrpi=5.6418958354775628695e-1_wp_, &
! thresh=0.46875_wp_
!!------------------------------------------------------------------
!! machine-dependent constants
!!------------------------------------------------------------------
! real(wp_), parameter :: xinf=1.79e308_wp_, & ! ~huge
! xneg=-26.628_wp_, & ! ?
! xsmall=1.11e-16_wp_, & ! ~epsilon/2
! xbig=26.543_wp_, & ! ?
! xhuge=6.71e7_wp_, & ! ~1/sqrt(epsilon)
! xmax=2.53e307_wp_ ! ?
!!------------------------------------------------------------------
!! coefficients for approximation to erf in first interval
!!------------------------------------------------------------------
! real(wp_), dimension(5), parameter :: &
! a=(/3.16112374387056560_wp_,1.13864154151050156e02_wp_, &
! 3.77485237685302021e02_wp_,3.20937758913846947e03_wp_, &
! 1.85777706184603153e-1_wp_/)
! real(wp_), dimension(4), parameter :: &
! b=(/2.36012909523441209e01_wp_,2.44024637934444173e02_wp_, &
! 1.28261652607737228e03_wp_,2.84423683343917062e03_wp_/)
!!------------------------------------------------------------------
!! coefficients for approximation to erfc in second interval
!!------------------------------------------------------------------
! real(wp_), dimension(9), parameter :: &
! c=(/5.64188496988670089e-1_wp_,8.88314979438837594_wp_, &
! 6.61191906371416295e01_wp_,2.98635138197400131e02_wp_, &
! 8.81952221241769090e02_wp_,1.71204761263407058e03_wp_, &
! 2.05107837782607147e03_wp_,1.23033935479799725e03_wp_, &
! 2.15311535474403846e-8_wp_/)
! real(wp_), dimension(8), parameter :: &
! d=(/1.57449261107098347e01_wp_,1.17693950891312499e02_wp_, &
! 5.37181101862009858e02_wp_,1.62138957456669019e03_wp_, &
! 3.29079923573345963e03_wp_,4.36261909014324716e03_wp_, &
! 3.43936767414372164e03_wp_,1.23033935480374942e03_wp_/)
!!------------------------------------------------------------------
!! coefficients for approximation to erfc in third interval
!!------------------------------------------------------------------
! real(wp_), dimension(6), parameter :: &
! p=(/3.05326634961232344e-1_wp_,3.60344899949804439e-1_wp_, &
! 1.25781726111229246e-1_wp_,1.60837851487422766e-2_wp_, &
! 6.58749161529837803e-4_wp_,1.63153871373020978e-2_wp_/)
! real(wp_), dimension(5), parameter :: &
! q=(/2.56852019228982242_wp_,1.87295284992346047_wp_, &
! 5.27905102951428412e-1_wp_,6.05183413124413191e-2_wp_, &
! 2.33520497626869185e-3_wp_/)
!!------------------------------------------------------------------
! x = arg
! y = abs(x)
! if (y <= thresh) then
!!------------------------------------------------------------------
!! evaluate erf for |x| <= 0.46875
!!------------------------------------------------------------------
! ysq = zero
! if (y > xsmall) ysq = y * y
! xnum = a(5)*ysq
! xden = ysq
! do i = 1, 3
! xnum = (xnum + a(i)) * ysq
! xden = (xden + b(i)) * ysq
! end do
! result = x * (xnum + a(4)) / (xden + b(4))
! if (jintt /= 0) result = one - result
! if (jintt == 2) result = exp(ysq) * result
! return
!!------------------------------------------------------------------
!! evaluate erfc for 0.46875 <= |x| <= 4.0
!!------------------------------------------------------------------
! else if (y <= four) then
! xnum = c(9)*y
! xden = y
! do i = 1, 7
! xnum = (xnum + c(i)) * y
! xden = (xden + d(i)) * y
! end do
! result = (xnum + c(8)) / (xden + d(8))
! if (jintt /= 2) then
! ysq = aint(y*sixten)/sixten
! del = (y-ysq)*(y+ysq)
! result = exp(-ysq*ysq) * exp(-del) * result
! end if
!!------------------------------------------------------------------
!! evaluate erfc for |x| > 4.0
!!------------------------------------------------------------------
! else if (y < xbig .or. (y < xmax .and. jintt == 2)) then
! ysq = one / (y * y)
! xnum = p(6)*ysq
! xden = ysq
! do i = 1, 4
! xnum = (xnum + p(i)) * ysq
! xden = (xden + q(i)) * ysq
! end do
! result = ysq *(xnum + p(5)) / (xden + q(5))
! result = (sqrpi - result) / y
! if (jintt /= 2) then
! ysq = aint(y*sixten)/sixten
! del = (y-ysq)*(y+ysq)
! result = exp(-ysq*ysq) * exp(-del) * result
! end if
! else if (y >= xhuge) then
! result = sqrpi / y
! else
! result = zero
! end if
!!------------------------------------------------------------------
!! fix up for negative argument, erf, etc.
!!------------------------------------------------------------------
! if (jintt == 0) then
! result = (half - result) + half
! if (x < zero) result = -result
! else if (jintt == 1) then
! if (x < zero) result = two - result
! else
! if (x < zero) then
! if (x < xneg) then
! result = xinf
! else
! ysq = aint(x*sixten)/sixten
! del = (x-ysq)*(x+ysq)
! y = exp(ysq*ysq) * exp(del)
! result = (y+y) - result
! end if
! end if
! end if
! end subroutine calerf
!
! function derf(x)
!!--------------------------------------------------------------------
!!
!! this subprogram computes approximate values for erf(x).
!! (see comments heading calerf).
!!
!! author/date: w. j. cody, january 8, 1985
!!
!!--------------------------------------------------------------------
! implicit none
! real(wp_) :: derf
! real(wp_), intent(in) :: x
! integer :: jintt
! real(wp_) :: result
!!------------------------------------------------------------------
! jintt = 0
! call calerf(x,result,jintt)
! derf = result
! end function derf
!
! function derfc(x)
!!--------------------------------------------------------------------
!!
!! this subprogram computes approximate values for erfc(x).
!! (see comments heading calerf).
!!
!! author/date: w. j. cody, january 8, 1985
!!
!!--------------------------------------------------------------------
! implicit none
! real(wp_) :: derfc
! real(wp_), intent(in) :: x
! integer :: jintt
! real(wp_) :: result
!!------------------------------------------------------------------
! jintt = 1
! call calerf(x,result,jintt)
! derfc = result
! end function derfc
!
! function derfcx(x)
!!------------------------------------------------------------------
!!
!! this subprogram computes approximate values for exp(x*x) * erfc(x).
!! (see comments heading calerf).
!!
!! author/date: w. j. cody, march 30, 1987
!!
!!------------------------------------------------------------------
! implicit none
! real(wp_) :: derfcx
! real(wp_), intent(in) :: x
! integer :: jintt
! real(wp_) :: result
!!------------------------------------------------------------------
! jintt = 2
! call calerf(x,result,jintt)
! derfcx = result
! end function derfcx
end module eierf

979
src/equilibrium.f90 Normal file
View File

@ -0,0 +1,979 @@
module equilibrium
use const_and_precisions, only : wp_
implicit none
REAL(wp_), SAVE :: btaxis,rmaxis,zmaxis
REAL(wp_), SAVE :: btrcen ! used only for Jcd_ASTRA def.
REAL(wp_), SAVE :: rcen ! computed as fpol(a)/btrcen
REAL(wp_), SAVE :: rmnm,rmxm,zmnm,zmxm
REAL(wp_), SAVE :: zbinf,zbsup
REAL(wp_), SAVE :: rup,zup,rlw,zlw
INTEGER, PARAMETER :: kspl=3,ksplp=kspl+1
! === 2D spline psi(R,z), normalization and derivatives ==========
INTEGER, SAVE :: nsr, nsz
REAL(wp_), SAVE :: psia, psiant, psinop
REAL(wp_), DIMENSION(:), ALLOCATABLE, SAVE :: tr,tz
REAL(wp_), DIMENSION(:), ALLOCATABLE, SAVE :: cceq, cceq01, cceq10, &
cceq20, cceq02, cceq11
! === 1D spline Fpol(psi) ========================================
! INTEGER, SAVE :: npsiest
INTEGER, SAVE :: nsf
REAL(wp_), DIMENSION(:), ALLOCATABLE, SAVE :: tfp, cfp
REAL(wp_), SAVE :: fpolas
! === 1D spline rhot(rhop), rhop(rhot), q(psi) ===================
! computed on psinr,rhopnr [,rhotnr] arrays
INTEGER, SAVE :: nq,nrho
REAL(wp_), DIMENSION(:), ALLOCATABLE, SAVE :: psinr,rhopr,rhotr
REAL(wp_), DIMENSION(:,:), ALLOCATABLE, SAVE :: cq,crhop,crhot
REAL(wp_), SAVE :: phitedge,aminor
REAL(wp_), SAVE :: q0,qa,alq
contains
subroutine read_eqdsk(filenm,rv,zv,psin,psia,psinr,fpol,q,rvac,rax,zax, &
rbnd,zbnd,rlim,zlim,ipsinorm,idesc,ifreefmt,unit)
use const_and_precisions, only : one
use utils, only : get_free_unit
implicit none
! arguments
character(len=*), intent(in) :: filenm
real(wp_), intent(out) :: psia,rvac,rax,zax
real(wp_), dimension(:), allocatable, intent(out) :: rv,zv,psinr,fpol,q
real(wp_), dimension(:), allocatable, intent(out) :: rbnd,zbnd,rlim,zlim
real(wp_), dimension(:,:), allocatable, intent(out) :: psin
integer, optional, intent(in) :: ipsinorm,idesc,ifreefmt,unit
! local variables
integer, parameter :: indef=0,iddef=1,iffdef=0
integer :: in,id,iffmt,u,idum,i,j,nr,nz,nbnd,nlim
character(len=48) :: string
real(wp_) :: dr,dz,dps,rleft,zmid,zleft,xdum,psiedge,psiaxis
! set default values if optional arguments are absent
in=indef; id=iddef; iffmt=iffdef
if(present(ipsinorm)) in=ipsinorm
if(present(idesc)) id=idesc
if(present(ifreefmt)) iffmt=ifreefmt
if (present(unit)) then
u=unit
else
u=get_free_unit()
end if
! open G EQDSK file (see http://fusion.gat.com/efit/g_eqdsk.html)
open(file=trim(filenm),status='old',unit=u)
! get size of main arrays and allocate them
if (id==1) then
read (u,'(a48,3i4)') string,idum,nr,nz
else
read (u,*) nr,nz
end if
if (allocated(rv)) deallocate(rv)
if (allocated(zv)) deallocate(zv)
if (allocated(psin)) deallocate(psin)
if (allocated(psinr)) deallocate(psinr)
if (allocated(fpol)) deallocate(fpol)
if (allocated(q)) deallocate(q)
allocate(rv(nr),zv(nz),psin(nr,nz),psinr(nr),fpol(nr),q(nr))
! store 0D data and main arrays
if (iffmt==1) then
read (u,*) dr,dz,rvac,rleft,zmid
read (u,*) rax,zax,psiaxis,psiedge,xdum
read (u,*) xdum,xdum,xdum,xdum,xdum
read (u,*) xdum,xdum,xdum,xdum,xdum
read (u,*) (fpol(i),i=1,nr)
read (u,*) (xdum,i=1,nr)
read (u,*) (xdum,i=1,nr)
read (u,*) (xdum,i=1,nr)
read (u,*) ((psin(i,j),i=1,nr),j=1,nz)
read (u,*) (q(i),i=1,nr)
else
read (u,'(5e16.9)') dr,dz,rvac,rleft,zmid
read (u,'(5e16.9)') rax,zax,psiaxis,psiedge,xdum
read (u,'(5e16.9)') xdum,xdum,xdum,xdum,xdum
read (u,'(5e16.9)') xdum,xdum,xdum,xdum,xdum
read (u,'(5e16.9)') (fpol(i),i=1,nr)
read (u,'(5e16.9)') (xdum,i=1,nr)
read (u,'(5e16.9)') (xdum,i=1,nr)
read (u,'(5e16.9)') (xdum,i=1,nr)
read (u,'(5e16.9)') ((psin(i,j),i=1,nr),j=1,nz)
read (u,'(5e16.9)') (q(i),i=1,nr)
end if
! get size of boundary and limiter arrays and allocate them
read (u,*) nbnd,nlim
if (allocated(rbnd)) deallocate(rbnd)
if (allocated(zbnd)) deallocate(zbnd)
if (allocated(rlim)) deallocate(rlim)
if (allocated(zlim)) deallocate(zlim)
! store boundary and limiter data
if(nbnd>0) then
allocate(rbnd(nbnd),zbnd(nbnd))
if (iffmt==1) then
read(u,*) (rbnd(i),zbnd(i),i=1,nbnd)
else
read(u,'(5e16.9)') (rbnd(i),zbnd(i),i=1,nbnd)
end if
end if
if(nlim>0) then
allocate(rlim(nlim),zlim(nlim))
if (iffmt==1) then
read(u,*) (rlim(i),zlim(i),i=1,nlim)
else
read(u,'(5e16.9)') (rlim(i),zlim(i),i=1,nlim)
end if
end if
! reading of G EQDSK file completed
close(u)
! build rv,zv,psinr arrays and normalize psin
zleft=zmid-0.5_wp_*dz
dr=dr/(nr-1)
dz=dz/(nz-1)
dps=one/(nr-1)
do i=1,nr
psinr(i)=(i-1)*dps
rv(i)=rleft+(i-1)*dr
end do
do i=1,nz
zv(i)=zleft+(i-1)*dz
end do
psia=psiedge-psiaxis
if(in==0) psin=(psin-psiaxis)/psia
end subroutine read_eqdsk
subroutine read_equil_an(filenm,rv,zv,fpol,q,unit)
use utils, only : get_free_unit
implicit none
! arguments
character(len=*), intent(in) :: filenm
integer, optional, intent(in) :: unit
! integer, intent(in) :: isgnbphi
! real(wp_), intent(in) :: factb
! real(wp_), intent(out) :: rvac,rax,zax
real(wp_), dimension(:), allocatable, intent(out) :: rv,zv,fpol,q
! local variables
integer :: u
real(wp_) :: rr0m,zr0m,rpam,b0,q0,qa,alq !,rcen,btrcen
if (present(unit)) then
u=unit
else
u=get_free_unit()
end if
open(file=trim(filenm),status='old',unit=u)
read(u,*) rr0m,zr0m,rpam
read(u,*) b0
read(u,*) q0,qa,alq
! rcen=rr0m
! btrcen=b0
! b0=isgnbphi*b0*factb
! rvac=rr0m
! rax=rr0m
! zax=zr0m
! zbmin=(zr0-rpa)/1.0e2_wp_
! zbmax=(zr0+rpa)/1.0e2_wp_
if(allocated(rv)) deallocate(rv)
if(allocated(zv)) deallocate(zv)
if(allocated(fpol)) deallocate(fpol)
if(allocated(q)) deallocate(q)
allocate(rv(2),zv(1),fpol(1),q(3))
rv(1)=rr0m
rv(2)=rpam
zv(1)=zr0m
fpol(1)=b0*rr0m
q(1)=q0
q(2)=qa
q(3)=alq
close(u)
end subroutine read_equil_an
subroutine change_cocos(psia,fpol,q,cocosin,cocosout,ierr)
use const_and_precisions, only : zero,one,pi
implicit none
! arguments
real(wp_), intent(inout) :: psia
real(wp_), dimension(:), intent(inout) :: fpol,q
integer, intent(in) :: cocosin, cocosout
! real(wp_), intent(out) :: isign,bsign
integer, intent(out), optional :: ierr
! local variables
real(wp_) :: isign,bsign
integer :: exp2pi,exp2piout
logical :: phiccw,psiincr,qpos,phiccwout,psiincrout,qposout
call decode_cocos(cocosin,exp2pi,phiccw,psiincr,qpos)
call decode_cocos(cocosout,exp2piout,phiccwout,psiincrout,qposout)
! check sign consistency
isign=sign(one,psia)
if (.not.psiincr) isign=-isign
bsign=sign(one,fpol(size(fpol)))
if (qpos.neqv.isign*bsign*q(size(q))>zero) then
! warning: sign inconsistency found among q, Ipla and Bref
q=-q
if(present(ierr)) ierr=1
else
if(present(ierr)) ierr=0
end if
! convert cocosin to cocosout
if (phiccw.neqv.phiccwout) then
! opposite direction of toroidal angle phi in cocosin and cocosout
! bsign=-bsign
! isign=-isign
fpol=-fpol
end if
! q has opposite sign for given sign of Bphi*Ip
if (qpos .neqv. qposout) q=-q
! psi and Ip signs don't change accordingly
if ((phiccw.eqv.phiccwout) .neqv. (psiincr.eqv.psiincrout)) psia=-psia
! convert Wb to Wb/rad or viceversa
psia=psia*(2.0_wp_*pi)**(exp2piout-exp2pi)
end subroutine change_cocos
subroutine decode_cocos(cocos,exp2pi,phiccw,psiincr,qpos)
implicit none
integer, intent(in) :: cocos
integer, intent(out) :: exp2pi
logical, intent(out) :: phiccw,psiincr,qpos
integer :: cmod10,cmod4
cmod10=mod(cocos,10)
cmod4=mod(cmod10,4)
! cocos>10 psi in Wb, cocos<10 psi in Wb/rad
exp2pi=(cocos-cmod10)/10
! cocos mod 10 = 1,3,5,7: toroidal angle phi increasing CCW
phiccw=(mod(cmod10,2)==1)
! cocos mod 10 = 1,2,5,6: psi increasing with positive Ip
psiincr=(cmod4==1 .or. cmod4==2)
! cocos mod 10 = 1,2,7,8: q positive for positive Bphi*Ip
qpos=(cmod10<3 .or. cmod10>6)
end subroutine decode_cocos
subroutine eq_scal(psia,fpol,isign,bsign,factb)
use const_and_precisions, only : one
implicit none
real(wp_), intent(inout) :: psia
integer, intent(inout) :: isign,bsign
real(wp_), dimension(:), intent(inout) :: fpol
real(wp_), intent(in) :: factb
! isign and bsign ignored on input if equal to 0
! used to assign the direction of Bphi and Ipla BEFORE scaling
! cocos=3 assumed: CCW direction is >0
! Bphi and Ipla scaled by the same factor factb to keep q unchanged
! factb<0 reverses the directions of Bphi and Ipla
if(isign/=0) psia=sign(psia,real(-isign,wp_))
if(bsign/=0 .and. bsign*fpol(size(fpol))<0) fpol=-fpol
psia=psia*factb
fpol=fpol*factb
isign=int(sign(one,-psia))
bsign=int(sign(one,fpol(size(fpol))))
end subroutine eq_scal
subroutine set_eqspl(rv,zv,psin,psiwbrad,psinr,fpol,sspl,ssfp, &
r0,rax,zax,rbnd,zbnd,ixp)
use const_and_precisions, only : zero,one
use dierckx, only : regrid,coeff_parder,curfit,splev
use utils, only : vmaxmin,vmaxmini
implicit none
! arguments
real(wp_), dimension(:), intent(in) :: rv,zv,psinr,fpol
real(wp_), dimension(:,:), intent(in) :: psin
real(wp_), intent(in) :: psiwbrad
real(wp_), intent(inout) :: sspl,ssfp
real(wp_), intent(in), optional :: r0,rax,zax
real(wp_), dimension(:), intent(in), optional :: rbnd,zbnd
integer, intent(in), optional :: ixp
! local constants
integer, parameter :: iopt=0
! local variables
integer :: liwrk,lwrk,lw10,lw01,lw20,lw02,lw11,lwrkf
integer :: nr,nz,nrest,nzest,npsest,nrz,npsi,nbnd,ibinf,ibsup
real(wp_) :: fp,rax0,zax0,psinoptmp,psinxptmp,rbmin,rbmax,rbinf,rbsup,r1,z1
real(wp_), dimension(1) :: fpoli
real(wp_), dimension(:), allocatable :: fvpsi,wf,wrk
integer, dimension(:), allocatable :: iwrk
integer :: ier,ixploc,info
!
! compute array sizes and prepare working space arrays
nr=size(rv)
nz=size(zv)
nrz=nr*nz
nrest=nr+ksplp
nzest=nz+ksplp
lwrk=4+nrest*nz+(nrest+nzest)*(2*kspl+5)+(nr+nz)*ksplp+max(nz,nrest)
liwrk=nz+nr+nrest+nzest+kspl
!
npsi=size(psinr)
npsest=npsi+ksplp
lwrkf=npsi*ksplp+npsest*(7+3*kspl)
!
allocate(wrk(max(lwrk,lwrkf)),iwrk(max(liwrk,npsest)))
!
! spline fitting/interpolation of psin(i,j) and derivatives
!
! length in m !!!
!
rmnm=rv(1)
rmxm=rv(nr)
zmnm=zv(1)
zmxm=zv(nz)
! allocate knots and spline coefficients arrays
if (allocated(tr)) deallocate(tr)
if (allocated(tz)) deallocate(tz)
allocate(tr(nrest),tz(nzest),cceq(nrz))
! allocate work arrays
! reshape 2D psi array to 1D (transposed) array and compute spline coeffs
allocate(fvpsi(nrz))
fvpsi=reshape(transpose(psin),(/nrz/))
call regrid(iopt,nr,rv,nz,zv,fvpsi,rmnm,rmxm,zmnm,zmxm, &
kspl,kspl,sspl,nrest,nzest,nsr,tr,nsz,tz,cceq,fp, &
wrk(1:lwrk),lwrk,iwrk(1:liwrk),liwrk,ier)
! if ier=-1 data are re-fitted using sspl=0
if(ier==-1) then
sspl=0.0_wp_
call regrid(iopt,nr,rv,nz,zv,fvpsi,rmnm,rmxm,zmnm,zmxm, &
kspl,kspl,sspl,nrest,nzest,nsr,tr,nsz,tz,cceq,fp, &
wrk(1:lwrk),lwrk,iwrk(1:liwrk),liwrk,ier)
end if
deallocate(fvpsi)
! compute spline coefficients for psi partial derivatives
lw10 = nr*(ksplp-1) + nz*ksplp + nrz
lw01 = nr*ksplp + nz*(ksplp-1) + nrz
lw20 = nr*(ksplp-2) + nz*ksplp + nrz
lw02 = nr*ksplp + nz*(ksplp-2) + nrz
lw11 = nr*(ksplp-1) + nz*(ksplp-1) + nrz
if (allocated(cceq10)) deallocate(cceq10)
if (allocated(cceq01)) deallocate(cceq01)
if (allocated(cceq20)) deallocate(cceq20)
if (allocated(cceq02)) deallocate(cceq02)
if (allocated(cceq11)) deallocate(cceq11)
allocate(cceq10(lw10),cceq01(lw01),cceq20(lw20),cceq02(lw02),cceq11(lw11))
call coeff_parder(tr,nsr,tz,nsz,cceq,kspl,kspl,1,0,cceq10,lw10,ier)
call coeff_parder(tr,nsr,tz,nsz,cceq,kspl,kspl,0,1,cceq01,lw01,ier)
call coeff_parder(tr,nsr,tz,nsz,cceq,kspl,kspl,2,0,cceq20,lw20,ier)
call coeff_parder(tr,nsr,tz,nsz,cceq,kspl,kspl,0,2,cceq02,lw02,ier)
call coeff_parder(tr,nsr,tz,nsz,cceq,kspl,kspl,1,1,cceq11,lw11,ier)
!
! spline interpolation of fpol(i)
!
! allocate knots and spline coefficients arrays
if (allocated(tfp)) deallocate(tfp)
if (allocated(cfp)) deallocate(cfp)
allocate(tfp(npsest),cfp(npsest))
allocate(wf(npsi))
wf(1:npsi-1)=one
wf(npsi)=1.0e2_wp_
call curfit(iopt,npsi,psinr,fpol,wf,zero,one,kspl,ssfp,npsest,nsf, &
tfp,cfp,fp,wrk(1:lwrkf),lwrkf,iwrk(1:npsest),ier)
call splev(tfp,nsf,cfp,kspl,psinr(npsi:npsi),fpoli,1,ier)
! set vacuum value used outside 0<=psin<=1 range
fpolas=fpoli(1)
! free temporary arrays
deallocate(wrk,iwrk,wf)
!
! re-normalize psi after spline computation
!
! start with un-corrected psi
!
psia=psiwbrad
psinop=0.0_wp_
psiant=1.0_wp_
!
! use provided boundary to set an initial guess for the search of O/X points
!
nbnd=0
if(present(rbnd).and.present(zbnd)) then
nbnd=min(size(rbnd),size(zbnd))
end if
if (nbnd>0) then
call vmaxmini(zbnd,nbnd,zbinf,zbsup,ibinf,ibsup)
rbinf=rbnd(ibinf)
rbsup=rbnd(ibsup)
call vmaxmin(rbnd,nbnd,rbmin,rbmax)
else
zbinf=zv(2)
zbsup=zv(nz-1)
rbinf=rv((nr+1)/2)
rbsup=rbinf
rbmin=rv(2)
rbmax=rv(nr-1)
end if
!
! search for exact location of the magnetic axis
!
if(present(rax)) then
rax0=rax
else
rax0=0.5_wp_*(rbmin+rbmax)
end if
if(present(zax)) then
zax0=zax
else
zax0=0.5_wp_*(zbinf+zbsup)
end if
call points_ox(rax0,zax0,rmaxis,zmaxis,psinoptmp,info)
print'(a,2f8.4,es12.5)','O-point',rmaxis,zmaxis,psinoptmp
!
! search for X-point if ixp not = 0
!
if(present(ixp)) then
ixploc=ixp
else
ixploc=0
end if
if(ixploc/=0) then
if(ixploc<0) then
call points_ox(rbinf,zbinf,r1,z1,psinxptmp,info)
if(psinxptmp/=-1.0_wp_) then
print'(a,2f8.4,es12.5)','X-point',r1,z1,psinxptmp
zbinf=z1
psinop=psinoptmp
psiant=psinxptmp-psinop
call points_tgo(rmaxis,0.5_wp_*(zmaxis+zbsup),r1,z1,one,info)
zbsup=z1
else
ixploc=0
end if
else
call points_ox(rbsup,zbsup,r1,z1,psinxptmp,info)
if(psinxptmp.ne.-1.0_wp_) then
print'(a,2f8.4,e16.8)','X-point',r1,z1,psinxptmp
zbsup=z1
psinop=psinoptmp
psiant=psinxptmp-psinop
call points_tgo(rmaxis,0.5_wp_*(zmaxis+zbinf),r1,z1,one,info)
zbinf=z1
else
ixploc=0
end if
end if
end if
if (ixploc==0) then
psinop=psinoptmp
psiant=one-psinop
! find upper horizontal tangent point
call points_tgo(rmaxis,0.5_wp_*(zmaxis+zbsup),r1,z1,one,info)
zbsup=z1
rbsup=r1
! find lower horizontal tangent point
call points_tgo(rmaxis,0.5_wp_*(zmaxis+zbinf),r1,z1,one,info)
zbinf=z1
rbinf=r1
print'(a,4f8.4)','no X-point ',rbinf,zbinf,rbsup,zbsup
end if
print*,' '
!
! save Bt value on axis (required in flux_average and used in Jcd def)
! and vacuum value B0 at ref. radius R0 (used in Jcd_astra def)
!
call equinum_fpol(0.0_wp_,btaxis)
btaxis=btaxis/rmaxis
if(present(r0)) then
btrcen=fpolas/r0
rcen=r0
else
btrcen=fpolas/rmaxis
rcen=rmaxis
end if
print'(a,f8.4)','BT_centr= ',btrcen
print'(a,f8.4)','BT_axis = ',btaxis
end subroutine set_eqspl
subroutine unset_eqspl
implicit none
if(allocated(tr)) deallocate(tr)
if(allocated(tz)) deallocate(tz)
if(allocated(tfp)) deallocate(tfp)
if(allocated(cfp)) deallocate(cfp)
if(allocated(cceq)) deallocate(cceq)
if(allocated(cceq01)) deallocate(cceq01)
if(allocated(cceq10)) deallocate(cceq10)
if(allocated(cceq02)) deallocate(cceq02)
if(allocated(cceq20)) deallocate(cceq20)
if(allocated(cceq11)) deallocate(cceq11)
nsr=0
nsz=0
nsf=0
end subroutine unset_eqspl
subroutine equinum_psi(rpsim,zpsim,psinv,dpsidr,dpsidz, &
ddpsidrr,ddpsidzz,ddpsidrz)
use dierckx, only : fpbisp
implicit none
! local constants
integer, parameter :: lwrk=8,liwrk=2
! arguments
real(wp_), intent(in) :: rpsim,zpsim
real(wp_), intent(out), optional :: psinv,dpsidr,dpsidz, &
ddpsidrr,ddpsidzz,ddpsidrz
! local variables
integer, dimension(liwrk) :: iwrk
real(wp_), dimension(1) :: rrs,zzs,ffspl
real(wp_), dimension(lwrk) :: wrk
!
! here lengths are measured in meters
!
if (rpsim.le.rmxm .and. rpsim.ge.rmnm .and. &
zpsim.le.zmxm .and. zpsim.ge.zmnm) then
if (present(psinv)) then
rrs(1)=rpsim
zzs(1)=zpsim
call fpbisp(tr,nsr,tz,nsz,cceq,3,3,rrs,1,zzs,1,ffspl, &
wrk(1),wrk(5),iwrk(1),iwrk(2))
psinv=(ffspl(1)-psinop)/psiant
end if
if (present(dpsidr)) then
call sub_derpsi(rpsim,zpsim,1,0,dpsidr,cceq10)
end if
if (present(dpsidz)) then
call sub_derpsi(rpsim,zpsim,0,1,dpsidz,cceq01)
end if
if (present(ddpsidrr)) then
call sub_derpsi(rpsim,zpsim,2,0,ddpsidrr,cceq20)
end if
if (present(ddpsidzz)) then
call sub_derpsi(rpsim,zpsim,0,2,ddpsidzz,cceq02)
end if
if (present(ddpsidrz)) then
call sub_derpsi(rpsim,zpsim,1,1,ddpsidrz,cceq11)
end if
else
if(present(psinv)) psinv=-1.0_wp_
if(present(dpsidr)) dpsidr=0.0_wp_
if(present(dpsidz)) dpsidz=0.0_wp_
if(present(ddpsidrr)) ddpsidrr=0.0_wp_
if(present(ddpsidzz)) ddpsidzz=0.0_wp_
if(present(ddpsidrz)) ddpsidrz=0.0_wp_
end if
end subroutine equinum_psi
subroutine sub_derpsi(rpsim,zpsim,nur,nuz,derpsi,cc)
use dierckx, only : fpbisp
implicit none
! arguments
real(wp_), intent(in) :: rpsim,zpsim
integer, intent(in) :: nur,nuz
real(wp_), intent(out) :: derpsi
real(wp_), dimension(:) :: cc
! local variables
integer, dimension(1) :: iwrkr,iwrkz
real(wp_), dimension(1) :: rrs,zzs,ffspl
real(wp_), dimension(1,ksplp) :: wrkr
real(wp_), dimension(1,ksplp) :: wrkz
rrs(1)=rpsim
zzs(1)=zpsim
call fpbisp(tr(nur+1),nsr-2*nur,tz(nuz+1),nsz-2*nuz,cc,kspl-nur,kspl-nuz, &
rrs,1,zzs,1,ffspl,wrkr,wrkz,iwrkr,iwrkz)
derpsi=ffspl(1)*psia
end subroutine sub_derpsi
subroutine equinum_fpol(psinv,fpolv,dfpv)
use dierckx, only : splev,splder
implicit none
! arguments
real(wp_), intent(in) :: psinv
real(wp_), intent(out) :: fpolv
real(wp_), intent(out), optional :: dfpv
! local variables
integer :: ier
real(wp_), dimension(1) :: rrs,ffspl
real(wp_), dimension(nsf) :: wrkfd
!
if(psinv.le.1.0_wp_.and.psinv.ge.0.0_wp_) then
rrs(1)=psinv
call splev(tfp,nsf,cfp,3,rrs,ffspl,1,ier)
fpolv=ffspl(1)
if(present(dfpv)) then
call splder(tfp,nsf,cfp,3,1,rrs,ffspl,1,wrkfd,ier)
dfpv=ffspl(1)/psia
end if
else
fpolv=fpolas
if (present(dfpv)) dfpv=0._wp_
end if
end subroutine equinum_fpol
subroutine bfield(rpsim,zpsim,bphi,br,bz)
implicit none
! arguments
real(wp_), intent(in) :: rpsim,zpsim
real(wp_), intent(out), optional :: bphi,br,bz
! local variables
real(wp_) :: psin,fpol
call equinum_psi(rpsim,zpsim,psinv=bphi,dpsidr=bz,dpsidz=br)
if (present(bphi)) then
psin=bphi
call equinum_fpol(psin,fpol)
bphi=fpol/rpsim
end if
if (present(br)) br=-br/rpsim
if (present(bz)) bz= bz/rpsim
end subroutine bfield
subroutine setqphi_num(psinq,q,psia,rhotn)
use const_and_precisions, only : pi
use simplespline, only : difcs
implicit none
! arguments
real(wp_), dimension(:), intent(in) :: psinq,q
real(wp_), intent(in) :: psia
real(wp_), dimension(:), intent(out), optional :: rhotn
! local variables
real(wp_), dimension(size(q)) :: phit
real(wp_) :: dx
integer, parameter :: iopt=0
integer :: k,ier
nq=size(q)
if(allocated(psinr)) deallocate(psinr)
if(allocated(cq)) deallocate(cq)
allocate(psinr(nq),cq(nq,4))
psinr=psinq
call difcs(psinr,q,nq,iopt,cq,ier)
!
! Toroidal flux phi = 2*pi*Integral q dpsi
!
phit(1)=0.0_wp_
do k=1,nq-1
dx=psinr(k+1)-psinr(k)
phit(k+1)=phit(k) + dx*(cq(k,1) + dx*(cq(k,2)/2.0_wp_ + &
dx*(cq(k,3)/3.0_wp_ + dx* cq(k,4)/4.0_wp_) ) )
end do
phitedge=phit(nq)
if(present(rhotn)) rhotn(1:nq)=sqrt(phit/phitedge)
phitedge=2*pi*psia*phitedge
end subroutine setqphi_num
subroutine unset_q
implicit none
if(allocated(psinr)) deallocate(psinr)
if(allocated(cq)) deallocate(cq)
nq=0
end subroutine unset_q
function fq(psin)
use const_and_precisions, only : wp_
use simplespline, only :spli
use utils, only : locate
implicit none
! arguments
real(wp_), intent(in) :: psin
real(wp_) :: fq
! local variables
integer :: i
real(wp_) :: dps
call locate(psinr,nq,psin,i)
i=min(max(1,i),nq-1)
dps=psin-psinr(i)
fq=spli(cq,nq,i,dps)
end function fq
subroutine set_rhospl(rhop,rhot)
use simplespline, only : difcs
implicit none
! arguments
real(wp_), dimension(:), intent(in) :: rhop, rhot
! local variables
integer, parameter :: iopt=0
integer :: ier
nrho=size(rhop)
if(allocated(rhopr)) deallocate(rhopr)
if(allocated(rhotr)) deallocate(rhotr)
if(allocated(crhop)) deallocate(crhop)
if(allocated(crhot)) deallocate(crhot)
allocate(rhopr(nrho),rhotr(nrho),crhop(nrho,4),crhot(nrho,4))
rhopr=rhop
rhotr=rhot
call difcs(rhotr,rhopr,nrho,iopt,crhop,ier)
call difcs(rhopr,rhotr,nrho,iopt,crhot,ier)
end subroutine set_rhospl
subroutine unset_rhospl
implicit none
if(allocated(rhopr)) deallocate(rhopr)
if(allocated(rhotr)) deallocate(rhotr)
if(allocated(crhop)) deallocate(crhop)
if(allocated(crhot)) deallocate(crhot)
nrho=0
end subroutine unset_rhospl
function frhopol(rhot)
use utils, only : locate
use simplespline, only : spli
implicit none
! arguments
real(wp_), intent(in) :: rhot
real(wp_) :: frhopol
! local variables
integer :: i
real(wp_) :: dr
call locate(rhotr,nrho,rhot,i)
i=min(max(1,i),nrho-1)
dr=rhot-rhotr(i)
frhopol=spli(crhop,nrho,i,dr)
end function frhopol
function frhotor(rhop)
use utils, only : locate
use simplespline, only : spli
implicit none
! arguments
real(wp_), intent(in) :: rhop
real(wp_) :: frhotor
! local variables
integer :: i
real(wp_) :: dr
call locate(rhopr,nrho,rhop,i)
i=min(max(1,i),nrho-1)
dr=rhop-rhopr(i)
frhotor=spli(crhot,nrho,i,dr)
end function frhotor
subroutine points_ox(rz,zz,rf,zf,psinvf,info)
use const_and_precisions, only : comp_eps
use minpack, only : hybrj1
implicit none
! local constants
integer, parameter :: n=2,ldfjac=n,lwa=(n*(n+13))/2
! arguments
real(wp_), intent(in) :: rz,zz
real(wp_), intent(out) :: rf,zf,psinvf
integer, intent(out) :: info
! local variables
real(wp_) :: tol
real(wp_), dimension(n) :: xvec,fvec
real(wp_), dimension(lwa) :: wa
real(wp_), dimension(ldfjac,n) :: fjac
xvec(1)=rz
xvec(2)=zz
tol = sqrt(comp_eps)
call hybrj1(fcnox,n,xvec,fvec,fjac,ldfjac,tol,info,wa,lwa)
if(info.gt.1) then
print'(a,i2,a,2f8.4)',' info subr points_ox =',info, &
' O/X coord.',xvec
end if
rf=xvec(1)
zf=xvec(2)
call equinum_psi(rf,zf,psinvf)
end subroutine points_ox
subroutine fcnox(n,x,fvec,fjac,ldfjac,iflag)
implicit none
! arguments
integer, intent(in) :: n,iflag,ldfjac
real(wp_), dimension(n), intent(in) :: x
real(wp_), dimension(n), intent(inout) :: fvec
real(wp_), dimension(ldfjac,n), intent(inout) :: fjac
! local variables
real(wp_) :: dpsidr,dpsidz,ddpsidrr,ddpsidzz,ddpsidrz
!
select case(iflag)
case(1)
call equinum_psi(x(1),x(2),dpsidr=dpsidr,dpsidz=dpsidz)
fvec(1) = dpsidr/psia
fvec(2) = dpsidz/psia
case(2)
call equinum_psi(x(1),x(2),ddpsidrr=ddpsidrr,ddpsidzz=ddpsidzz, &
ddpsidrz=ddpsidrz)
fjac(1,1) = ddpsidrr/psia
fjac(1,2) = ddpsidrz/psia
fjac(2,1) = ddpsidrz/psia
fjac(2,2) = ddpsidzz/psia
case default
print*,'iflag undefined'
end select
end subroutine fcnox
subroutine points_tgo(rz,zz,rf,zf,psin0,info)
use const_and_precisions, only : comp_eps
use minpack, only : hybrj1mv
implicit none
! local constants
integer, parameter :: n=2,ldfjac=n,lwa=(n*(n+13))/2
! arguments
real(wp_), intent(in) :: rz,zz,psin0
real(wp_), intent(out) :: rf,zf
integer, intent(out) :: info
! local variables
real(wp_) :: tol
real(wp_), dimension(n) :: xvec,fvec,f0
real(wp_), dimension(lwa) :: wa
real(wp_), dimension(ldfjac,n) :: fjac
! common/external functions/variables
xvec(1)=rz
xvec(2)=zz
f0(1)=psin0
f0(2)=0.0_wp_
tol = sqrt(comp_eps)
call hybrj1mv(fcntgo,n,xvec,f0,fvec,fjac,ldfjac,tol,info,wa,lwa)
if(info.gt.1) then
print'(a,i2,a,2f8.4)',' info subr points_tgo =',info, &
' R,z coord.',xvec
end if
rf=xvec(1)
zf=xvec(2)
end
subroutine fcntgo(n,x,f0,fvec,fjac,ldfjac,iflag)
use const_and_precisions, only : wp_
implicit none
! arguments
integer, intent(in) :: n,ldfjac,iflag
real(wp_), dimension(n), intent(in) :: x,f0
real(wp_), dimension(n), intent(inout) :: fvec
real(wp_), dimension(ldfjac,n), intent(inout) :: fjac
! internal variables
real(wp_) :: psinv,dpsidr,dpsidz,ddpsidrr,ddpsidrz
select case(iflag)
case(1)
call equinum_psi(x(1),x(2),psinv,dpsidr)
fvec(1) = psinv-f0(1)
fvec(2) = dpsidr/psia-f0(2)
case(2)
call equinum_psi(x(1),x(2),dpsidr=dpsidr,dpsidz=dpsidz, &
ddpsidrr=ddpsidrr,ddpsidrz=ddpsidrz)
fjac(1,1) = dpsidr/psia
fjac(1,2) = dpsidz/psia
fjac(2,1) = ddpsidrr/psia
fjac(2,2) = ddpsidrz/psia
case default
print*,'iflag undefined'
end select
end subroutine fcntgo
subroutine set_equian(rax,zax,a,bax,qax,q1,qexp,n)
use const_and_precisions, only : pi,zero,one
implicit none
! arguments
real(wp_), intent(in) :: rax,zax,a,bax,qax,q1,qexp
integer, intent(in), optional :: n
! local variables
integer, parameter :: nqdef=101
integer :: i
real(wp_) :: dr,fq0,fq1,qq,res,rn
real(wp_), dimension(:), allocatable :: rhotn,rhopn
btaxis=bax
rmaxis=rax
zmaxis=zax
btrcen=bax
rcen=rax
aminor=a
zbinf=zmaxis-a
zbsup=zmaxis+a
q0=qax
qa=q1
alq=qexp
if (present(n)) then
nq=n
else
nq=nqdef
end if
if (allocated(psinr)) deallocate(psinr)
allocate(psinr(nq),rhotn(nq),rhopn(nq))
dr=one/(nq-1)
rhotn(1)=zero
psinr(1)=zero
res=zero
fq0=zero
do i=2,n
rn=(i-1)*dr
qq=q0+(q1-q0)*rn**qexp
fq1=rn/qq
res=res+0.5_wp_*(fq1+fq0)*dr
fq0=fq1
rhotn(i)=rn
psinr(i)=res
end do
phitedge=btaxis*aminor**2 ! temporary
psia=res*phitedge
phitedge=pi*phitedge ! final
psinr=psinr/res
rhopn=sqrt(psinr)
call set_rhospl(rhopn,rhotn)
end subroutine set_equian
subroutine equian(rrm,zzm,psinv,fpolv,dfpv,dpsidr,dpsidz, &
ddpsidrr,ddpsidzz,ddpsidrz)
use const_and_precisions, only : wp_
implicit none
! arguments
real(wp_), intent(in) :: rrm,zzm
real(wp_), intent(out), optional :: psinv,fpolv,dfpv,dpsidr,dpsidz, &
ddpsidrr,ddpsidzz,ddpsidrz
! local variables
integer :: sgn
real(wp_) :: cst,dpsidrp,d2psidrp,dqq,qq,rn,rpm,snt,rhop,rhot
! real(wp_) :: frhopol
! simple model for equilibrium: large aspect ratio
! outside plasma: analytical continuation, not solution Maxwell eqs
rpm=sqrt((rrm-rmaxis)**2+(zzm-zmaxis)**2) !!! rpm==rho_tor[m], rn=rho_tor_norm
rn=rpm/aminor
snt=0.0_wp_
cst=1.0_wp_
if (rpm > 0.0_wp_) then
snt=(zzm-zmaxis)/rpm
cst=(rrm-rmaxis)/rpm
end if
if (present(psinv)) then
rhot=rn
if(rn <= 1.0_wp_) then
rhop=frhopol(rhot)
psinv=rhop*rhop
else
psinv=1.0_wp_+btaxis*aminor**2/2.0_wp_/psia/qa*(rn*rn-1.0_wp_)
rhop=sqrt(psinv)
end if
end if
if(rn <= 1.0_wp_) then
qq=q0+(qa-q0)*rn**alq
dpsidrp=-btaxis*aminor*rn/qq
dqq=alq*(qa-q0)*rn**(alq-1.0_wp_)
d2psidrp=-btaxis*(1.0_wp_-rn*dqq/qq)/qq
else
dpsidrp=-btaxis*aminor/qa*rn
d2psidrp=-btaxis/qa
end if
if(present(fpolv)) fpolv=btaxis*rmaxis
if(present(dfpv)) dfpv=0.0_wp_
if(present(dpsidr)) dpsidr=dpsidrp*cst
if(present(dpsidz)) dpsidz=dpsidrp*snt
if(present(ddpsidrr)) ddpsidrr=dpsidrp*snt**2/rpm+cst**2*d2psidrp
if(present(ddpsidrz)) ddpsidrz=cst*snt*(d2psidrp-dpsidrp/rpm)
if(present(ddpsidzz)) ddpsidzz=dpsidrp*cst**2/rpm+snt**2*d2psidrp
end subroutine equian
end module equilibrium

6822
src/gray.f

File diff suppressed because it is too large Load Diff

12
src/graydata_anequil.f90 Normal file
View File

@ -0,0 +1,12 @@
module graydata_anequil
use const_and_precisions, only : wp_
implicit none
real(wp_), save :: dens0,aln1,aln2
real(wp_), save :: te0,dte0,alt1,alt2
real(wp_), save :: rr0,zr0,rpa
real(wp_), save :: b0,rr0m,zr0m,rpam
real(wp_), save :: q0,qa,alq
real(wp_), save :: zeffan
end module graydata_anequil

14
src/graydata_flags.f90 Normal file
View File

@ -0,0 +1,14 @@
module graydata_flags
use const_and_precisions, only : wp_
implicit none
character*255, save :: filenmeqq,filenmprf,filenmbm
real(wp_), save :: sspl, dst
integer, save :: ibeam,iequil,ixp,iprof
integer, save :: iwarm,ilarm,imx,ieccd,ipec,idst
integer, save :: igrad,ipass
integer, save :: ipsinorm,iscal,icocos
integer, save :: nnd,istpr0,istpl0,ipol
integer, save :: neqdsk,nprof
end module graydata_flags

10
src/graydata_par.f90 Normal file
View File

@ -0,0 +1,10 @@
module graydata_par
use const_and_precisions, only : wp_
implicit none
real(wp_), save :: rwmax,rwallm
real(wp_), save :: psipol0,chipol0
real(wp_), save :: factb,factt,factn
real(wp_), save :: sgnbphi,sgniphi
end module graydata_par

11681
src/grayl.f

File diff suppressed because it is too large Load Diff

View File

@ -1,437 +0,0 @@
!########################################################################
MODULE green_func_p
!########################################################################
!
! The module contains few subroutines which are requested to calculate
! the current drive value by adjoint approach
!
!########################################################################
USE const_and_precisions
!-------
IMPLICIT NONE
CHARACTER(Len=1), PRIVATE :: adj_appr(6) ! adjoint approach switcher
!-------
REAL(wp_), PRIVATE :: r2,q2,gp1,Rfactor
!-------
REAL(wp_), PRIVATE, PARAMETER :: delta = 1e-4 ! border for recalculation
!------- for N.M. subroutines (variational principle) -------
REAL(wp_), PRIVATE :: sfd(1:4)
INTEGER, PRIVATE, PARAMETER :: nre = 2 ! order of rel. correct.
REAL(wp_), PRIVATE, PARAMETER :: vp_mee(0:4,0:4,0:2) = &
RESHAPE((/0.0, 0.0, 0.0, 0.0, 0.0, &
0.0, 0.184875, 0.484304, 1.06069, 2.26175, &
0.0, 0.484304, 1.41421, 3.38514, 7.77817, &
0.0, 1.06069, 3.38514, 8.73232, 21.4005, &
0.0, 2.26175, 7.77817, 21.4005, 55.5079, &
! &
0.0, -1.33059,-2.57431, -5.07771, -10.3884, &
-0.846284,-1.46337, -1.4941, -0.799288, 2.57505, &
-1.1601, -1.4941, 2.25114, 14.159, 50.0534, &
-1.69257, -0.799288, 14.159, 61.4168, 204.389, &
-2.61022, 2.57505, 50.0534, 204.389, 683.756, &
! &
0.0, 2.62498, 0.985392,-5.57449, -27.683, &
0.0, 3.45785, 5.10096, 9.34463, 22.9831, &
-0.652555, 5.10096, 20.5135, 75.8022, 268.944, &
-2.11571, 9.34463, 75.8022, 330.42, 1248.69, &
-5.38358, 22.9831, 268.944, 1248.69, 4876.48/),&
(/5,5,3/))
REAL(wp_), PRIVATE, PARAMETER :: vp_mei(0:4,0:4,0:2) = &
RESHAPE((/0.0, 0.886227, 1.0, 1.32934, 2.0, &
0.886227,1.0, 1.32934, 2.0, 3.32335, &
1.0, 1.32934, 2.0, 3.32335, 6.0, &
1.32934, 2.0, 3.32335, 6.0, 11.6317, &
2.0, 3.32335, 6.0, 11.6317, 24.0, &
! &
0.0, 0.332335, 1.0, 2.49251, 6.0, &
1.66168, 1.0, 2.49251, 6.0, 14.5397, &
3.0, 2.49251, 6.0, 14.5397, 36.0, &
5.81586, 6.0, 14.5397, 36.0, 91.5999, &
12.0, 14.5397, 36.0, 91.5999, 240.0, &
! &
0.0, -0.103855, 0.0, 1.09047, 6.0, &
0.726983,0.0, 1.09047, 6.0, 24.5357, &
3.0, 1.09047, 6.0, 24.5357, 90.0, &
9.81427, 6.0, 24.5357, 90.0, 314.875, &
30.0, 24.5357, 90.0, 314.875, 1080.0 /), &
(/5,5,3/))
REAL(wp_), PRIVATE, PARAMETER :: vp_oee(0:4,0:4,0:2) = &
RESHAPE((/0.0, 0.56419, 0.707107, 1.0073, 1.59099, &
0.56419, 0.707107, 1.0073, 1.59099, 2.73981, &
0.707107,1.0073, 1.59099, 2.73981, 5.08233, &
1.0073, 1.59099, 2.73981, 5.08233, 10.0627, &
1.59099, 2.73981, 5.08233, 10.0627, 21.1138, &
! &
0.0, 1.16832, 1.90035, 3.5758, 7.41357, &
2.17562, 1.90035, 3.5758, 7.41357, 16.4891, &
3.49134, 3.5758, 7.41357, 16.4891, 38.7611, &
6.31562, 7.41357, 16.4891, 38.7611, 95.4472, &
12.4959, 16.4891, 38.7611, 95.4472, 244.803, &
! &
0.0, 2.65931, 4.64177, 9.6032, 22.6941, &
4.8652, 4.64177, 9.6032, 22.6941, 59.1437, &
9.51418, 9.6032, 22.6941, 59.1437, 165.282, &
21.061, 22.6941, 59.1437, 165.282, 485.785, &
50.8982, 59.1437, 165.282, 485.785, 1483.22/), &
(/5,5,3/))
REAL(wp_), PRIVATE, PARAMETER :: vp_g(0:4,0:2) = &
RESHAPE((/1.32934, 2.0, 3.32335, 6.0, 11.6317, &
2.49251, 0.0, 2.90793, 12.0, 39.2571, &
1.09047, 6.0, 11.45, 30.0, 98.9606/), &
(/5,3/))
!########################################################################
CONTAINS
!#######################################################################
SUBROUTINE Setup_SpitzFunc
!=======================================================================
IMPLICIT NONE
!=======================================================================
adj_appr(1) = 'l' ! collisionless limit
! adj_appr(1) = 'c' ! collisional (classical) limit, w/o trap. part.
adj_appr(2) = 'm' ! momentum conservation
! adj_appr(2) = 'h' ! high-speed limit
!---
adj_appr(3) = 'l' ! DO NOT CHANGE!
adj_appr(4) = 'r' ! DO NOT CHANGE!
adj_appr(5) = 'v' ! DO NOT CHANGE!
adj_appr(6) = 'i' ! DO NOT CHANGE!
!=======================================================================
!.....
!=======================================================================
RETURN
END SUBROUTINE Setup_SpitzFunc
SUBROUTINE GenSpitzFunc(Te,Zeff,fc,u,q,gam, K,dKdu)
!=======================================================================
! Author: N.B.Marushchenko
! June 2005: as start point the subroutine of Ugo Gasparino (198?)
! SpitzFunc() is taken and modified.
! 1. adapted to the Fortran-95
! 2. derivative of Spitzer function is added
! 3. separation for 2 brunches is done:
! 1st is referenced as 'with conservation of the moment',
! 2nd - as 'high speed limit'.
! The last one is taken from the Lin-Liu formulation
! (Phys.Plasmas 10 (2003) 4064) with K = F*fc.
! The asymptotical high speed limit (Taguchi-Fisch model)
! is also included as the reference case.
! Feb. 2008: non-relativ. version is replaced by the relativistic one;
! the method is the the same, but the trial-function is
! based on the relativistic formulation.
! The relativistic corrections for the collisional operator
! up to the second order, i.e. (1/mu)**2, are applied.
! Sep. 2008: generalized Spitzer function for arbitrary collisionality
! is implemented. The model is based on the concept of
! the "effective trapped particles fraction".
! The different.-integral kinetic equation for the generalized
! Spitzer function is produced with help of subroutines
! ArbColl_TrappFract_Array and ArbColl_SpitzFunc_Array,
! where the subroutines of H. Maassberg are called).
!========================================================================
! Spitzer function with & w/o trapped particle effects is given by:
!
! K(x) = x/gamma*(d1*x+d2*x^2+d4*x^3+d4*x^4),
!
! where x = v/v_th and gamma=1 for non-relativistic version (Ugo),
! or x = p/p_th for relativistic version (N.M., February 2008).
! Note, that somewhere the function F(x) instead of K(x) is applied,
!
! F(x) = K(x)/fc.
!
! Numerical inversion of the 5x5 symmetric matrix obtained from the
! generalized Spitzer problem (see paper of Taguchi for the equation
! and paper of Hirshman for the variational approach bringing to the
! matrix to be inverted).
!
! The numerical method used is an improved elimination scheme
! (Banachiewiczs-Cholesky-Crout method).
! This method is particularly simple for symmetric matrix.
! As a reference see "Mathematical Handbook" by Korn & Korn, p.635-636.
!
! Refs.: 1. S.P. Hirshman, Phys. Fluids 23 (1980) 1238
! 2. M. Rome' et al., Plasma Phys. Contr. Fus. 40 (1998) 511
! 3. N.B. Marushchenko et al., Fusion Sci. Technol. 55 (2009) 180
!========================================================================
! INPUTS:
! u - p/sqrt(2mT)
! q - p/mc;
! gam - relativistic factor;
! mu - mc2/Te
! Zeff - effective charge;
! fc - fraction of circulating particles.
!
! OUTPUTS:
! K - Spitzer's function
! dKdu = dK/du, i.e. its derivative over normalized momentum
!=======================================================================
IMPLICIT NONE
REAL(wp_), INTENT(in) :: Te,Zeff,fc,u,q,gam
REAL(wp_), INTENT(out) :: K,dKdu
REAL(wp_) :: mu,gam1,gam2,gam3,w,dwdu
!=======================================================================
K = 0
dKdu = 0
IF (u < comp_eps) RETURN
!---
mu = mc2_/max(Te,1d-3)
SELECT CASE(adj_appr(2))
CASE('m') !--------------- momentum conservation ------------------!
gam1 = gam !
IF (adj_appr(4) == 'n') gam1 = 1 !
gam2 = gam1*gam1 !
gam3 = gam1*gam2 !
K = u/gam1*u*(sfd(1)+u*(sfd(2)+u*(sfd(3)+u*sfd(4)))) !
dKdu = u/gam3* (sfd(1)*(1+ gam2)+u*(sfd(2)*(1+2*gam2)+ & !
u*(sfd(3)*(1+3*gam2)+u* sfd(4)*(1+4*gam2)))) !
!--------------------- end momentum conservation -------------------!
CASE('h') !---------------- high-speed-limit ----------------------!
IF (adj_appr(4) == 'n') THEN !- non-relativ. asymptotic form -!
K = u**4 *fc/(Zeff+1+4*fc) !- (Taguchi-Fisch model) -!
dKdu = 4*u**3 *fc/(Zeff+1+4*fc) !
ELSEIF (adj_appr(4) == 'r') THEN !- relativistic, Lin-Liu form. -!
CALL SpitzFunc_HighSpeedLimit(Zeff,fc,u,q,gam, K,dKdu) !
ENDIF !
CASE default !----------------------------------------------------!
PRINT*,'GenSpitzFunc: WARNING! Spitzer function is not defined.'
RETURN
END SELECT
!=======================================================================
RETURN
END SUBROUTINE GenSpitzFunc
!#######################################################################
!#######################################################################
!#######################################################################
SUBROUTINE SpitzFuncCoeff(Te,Zeff,fc)
!=======================================================================
! Calculates the matrix coefficients required for the subroutine
! "GenSpitzFunc", where the Spitzer function is defined through the
! variational principle.
!
! Weakly relativistic (upgraded) version (10.09.2008).
! Apart of the non-relativistic matrix coefficients, taken from the
! old subroutine of Ugo Gasparino, the relativistic correction written
! as series in 1/mu^n (mu=mc2/T) powers is added. Two orders are taken
! into account, i.e. n=0,1,2.
!
! In this version, the coefficients "oee", i.e. Omega_ij, are formulated
! for arbitrary collisionality.
!
! INPUT VARIABLES:
! rho = sqrt(SS) with SS - flux-surface label (norm. magn. flux)
! ne - density, 1/m^3
! Te - temperature, keV
! Zeff - effective charge
! fc - fraction of circulating particles
!
! OUTPUT VARIABLES (defined as a global ones):
! sfd(1),...,sfd(4) - coefficients of the polynomial expansion of the
! "Spitzer"-function (the same as in the Hirshman paper)
!=======================================================================
IMPLICIT NONE
REAL(wp_), INTENT(in) :: Te,Zeff,fc
INTEGER :: n,i,j
REAL(wp_) :: rtc,rtc1,mu,y,tn(1:nre)
REAL(wp_) :: m(0:4,0:4),g(0:4)
REAL(wp_) :: om(0:4,0:4)
REAL(wp_) :: gam11,gam21,gam31,gam41,gam01, &
gam22,gam32,gam42,gam02, &
gam33,gam43,gam03, &
gam44,gam04,gam00
REAL(wp_) :: alp12,alp13,alp14,alp10, &
alp23,alp24,alp20, &
alp34,alp30,alp40
REAL(wp_) :: bet0,bet1,bet2,bet3,bet4,d0
LOGICAL :: renew,rel,newTe,newne,newZ,newfc
REAL(wp_), SAVE :: sfdx(1:4) = 0
REAL(wp_), SAVE :: ne_old =-1, Te_old =-1, Zeff_old =-1, fc_old =-1
!=======================================================================
rel = Te > 1
newTe = abs(Te -Te_old ) > delta*Te
newZ = abs(Zeff-Zeff_old) > delta*Zeff
newfc = abs(fc -fc_old ) > delta*fc
SELECT CASE(adj_appr(1))
CASE ('l','c')
renew = (newTe .and. rel) .OR. newZ .OR. newfc
END SELECT
!---
IF (.not.renew) THEN
sfd(:) = sfdx(:)
RETURN
ENDIF
!=======================================================================
tn(:) = 0
IF (adj_appr(4) == 'r') THEN
IF (nre > 0) THEN
mu = mc2_/max(Te,1d-3)
tn(1) = 1/mu
DO n=2,min(2,nre)
tn(n) = tn(n-1)/mu
ENDDO
ENDIF
ENDIF
!---
SELECT CASE(adj_appr(1))
CASE ('l','c') !---- both classical & collisionless limits ----!
rtc = (1-fc)/fc; rtc1 = rtc+1 !
!--- !
DO i=0,4 !
g(i) = vp_g(i,0) !
DO n=1,min(2,nre) !
g(i) = g(i) + tn(n)*vp_g(i,n) !
ENDDO !
!--- !
DO j=0,4 !
IF (i == 0 .or. j == 0 .or. j >= i) THEN !
y = vp_mee(i,j,0) + rtc *vp_oee(i,j,0) + & !
Zeff*rtc1*vp_mei(i,j,0) !
DO n=1,min(2,nre) !
y = y + (vp_mee(i,j,n) + rtc *vp_oee(i,j,n) + & !
Zeff*rtc1*vp_mei(i,j,n))*tn(n) !
ENDDO !
m(i,j) = y !
ENDIF !
ENDDO !
ENDDO !
DO i=2,4 !
DO j=1,i-1 !
m(i,j) = m(j,i) !
ENDDO !
ENDDO !
m(0,0) = 0 !
CASE default !------------------------------------------------!
PRINT*,'Green_Func: WARNING! Adjoint approach is not defined.'
RETURN
END SELECT
!=======================================================================
gam11 = m(1,1)
gam21 = m(2,1)
gam31 = m(3,1)
gam41 = m(4,1)
gam01 = m(0,1)
!
alp12 = m(1,2)/m(1,1)
alp13 = m(1,3)/m(1,1)
alp14 = m(1,4)/m(1,1)
alp10 = m(1,0)/m(1,1)
!
gam22 = m(2,2)-gam21*alp12
gam32 = m(3,2)-gam31*alp12
gam42 = m(4,2)-gam41*alp12
gam02 = m(0,2)-gam01*alp12
!
alp23 = gam32/gam22
alp24 = gam42/gam22
alp20 = gam02/gam22
!
gam33 = m(3,3)-gam31*alp13-gam32*alp23
gam43 = m(4,3)-gam41*alp13-gam42*alp23
gam03 = m(0,3)-gam01*alp13-gam02*alp23
!
alp34 = gam43/gam33
alp30 = gam03/gam33
!
gam44 = m(4,4)-gam41*alp14-gam42*alp24-gam43*alp34
gam04 = m(0,4)-gam01*alp14-gam02*alp24-gam03*alp34
!
alp40 = gam04/gam44
!
gam00 = m(0,0)-gam01*alp10-gam02*alp20-gam03*alp30-gam04*alp40
!
bet1 = g(1)/m(1,1)
bet2 = (g(2)-gam21*bet1)/gam22
bet3 = (g(3)-gam31*bet1-gam32*bet2)/gam33
bet4 = (g(4)-gam41*bet1-gam42*bet2-gam43*bet3)/gam44
bet0 = (g(0)-gam01*bet1-gam02*bet2-gam03*bet3-gam04*bet4)/gam00
!
d0 = bet0
sfd(4) = bet4-alp40*d0
sfd(3) = bet3-alp30*d0-alp34*sfd(4)
sfd(2) = bet2-alp20*d0-alp24*sfd(4)-alp23*sfd(3)
sfd(1) = bet1-alp10*d0-alp14*sfd(4)-alp13*sfd(3)-alp12*sfd(2)
!=======================================================================
fc_old = fc
Te_old = Te
Zeff_old = Zeff
!---
sfdx(1:4) = sfd(1:4)
!=======================================================================
RETURN
END SUBROUTINE SpitzFuncCoeff
!#######################################################################
!#######################################################################
!#######################################################################
SUBROUTINE SpitzFunc_HighSpeedLimit(Zeff,fc,u,q,gam, K,dKdu)
!=======================================================================
! Calculates the "Spitzer function" in high velocity limit, relativistic
! formulation: Lin-Liu et al., Phys.Pl. (2003),v10, 4064, Eq.(33).
!
! Inputs:
! Zeff - effective charge
! fc - fraction of circulating electrons
! u - p/(m*vte)
! q - p/mc
! gam - relativ. factor
!
! Outputs:
! K - Spitzer function
! dKdu - its derivative
!=======================================================================
IMPLICIT NONE
REAL(wp_), INTENT(in) :: Zeff,fc,u,q,gam
REAL(wp_), INTENT(out) :: K,dKdu
INTEGER :: nfun
REAL(8) :: gam2,err,flag,Integr
REAL(8), PARAMETER :: a = 0d0, b = 1d0, rtol = 1d-4, atol = 1d-12
!=======================================================================
r2 = (1+Zeff)/fc ! global parameter needed for integrand, HSL_f(t)
!------------------
IF (u < 1e-2) THEN
K = u**4/(r2+4)
dKdu = 4*u**3/(r2+4)
RETURN
ENDIF
!=======================================================================
q2 = q*q ! for the integrand, HSL_f
gp1 = gam+1 ! ..
!---
CALL quanc8(HSL_f,zero,unit,atol,rtol,Integr,err,nfun,flag)
!=======================================================================
gam2 = gam*gam
!---
K = u**4 * Integr
dKdu = (u/gam)**3 * (1-r2*gam2*Integr)
!=======================================================================
RETURN
END SUBROUTINE SpitzFunc_HighSpeedLimit
!#######################################################################
!#######################################################################
!#######################################################################
FUNCTION HSL_f(t) RESULT(f)
!=======================================================================
! Integrand for the high-speed limit approach (Lin-Liu's formulation)
!=======================================================================
IMPLICIT NONE
REAL(8), INTENT(in) :: t
REAL(8) :: f,g
g = sqrt(1+t*t*q2)
f = t**(3+r2)/g**3 * (gp1/(g+1))**r2
END FUNCTION HSL_f
!#######################################################################
END MODULE green_func_p
!#######################################################################

View File

@ -1,32 +0,0 @@
!> Module implementing the ITM physics constants
!>
!> Source:
!> based on SOLPS b2mod_constants.F
!> '09/12/07 xpb : source CODATA 2006 (http://www.nist.gov/)'
!> pulled from ets r100
!>
!> \author David Coster
!>
!> \version "$Id: itm_constants.f90 37 2009-08-17 17:15:00Z coster $"
module itm_constants
use itm_types
real (kind = R8), parameter :: itm_pi = 3.141592653589793238462643383280_R8
real (kind = R8), parameter :: itm_c = 2.99792458e8_R8 ! speed of light, m/s
real (kind = R8), parameter :: itm_me = 9.10938215e-31_R8 ! electron mass, kg
real (kind = R8), parameter :: itm_mp = 1.672621637e-27_R8 ! proton mass, kg
real (kind = R8), parameter :: itm_md = 3.34358320e-27_R8 ! deuteron mass, kg
real (kind = R8), parameter :: itm_mt = 5.00735588e-27_R8 ! triton mass, kg
real (kind = R8), parameter :: itm_ma = 6.64465620e-27_R8 ! alpha mass, kg
real (kind = R8), parameter :: itm_amu = 1.660538782e-27_R8 ! amu, kg
real (kind = R8), parameter :: itm_ev = 1.602176487e-19_R8
real (kind = R8), parameter :: itm_qe = itm_ev
real (kind = R8), parameter :: itm_mu0 = 4.0e-7_R8 * itm_pi
real (kind = R8), parameter :: itm_eps0 = 1.0_R8 / (itm_mu0 * itm_c * itm_c)
real (kind = R8), parameter :: itm_avogr = 6.02214179e23_R8
real (kind = R8), parameter :: itm_KBolt = 1.3806504e-23_R8
character (len=64), parameter :: itm_constants_version = '$Id: itm_constants.f90 37 2009-08-17 17:15:00Z coster $'
end module itm_constants

View File

@ -1,50 +0,0 @@
!> Module implementing the ITM basic types
!>
!> Source:
!> based on SOLPS b2mod_types.F
!> pulled from ets r100 and extended with input from C. Konz, T. Ribeiro & B. Scott
!>
!> \author David Coster
!>
!> \version "$Id: itm_types.f90 144 2010-10-07 09:26:24Z konz $"
module itm_types
INTEGER, PARAMETER :: ITM_I1 = SELECTED_INT_KIND (2) ! Integer*1
INTEGER, PARAMETER :: ITM_I2 = SELECTED_INT_KIND (4) ! Integer*2
INTEGER, PARAMETER :: ITM_I4 = SELECTED_INT_KIND (9) ! Integer*4
INTEGER, PARAMETER :: ITM_I8 = SELECTED_INT_KIND (18) ! Integer*8
INTEGER, PARAMETER :: R4 = SELECTED_REAL_KIND (6, 37) ! Real*4
INTEGER, PARAMETER :: R8 = SELECTED_REAL_KIND (15, 300) ! Real*8
INTEGER, PARAMETER :: itm_int_invalid = -999999999
REAL(R8), PARAMETER :: itm_r8_invalid = -9.0D40
interface itm_is_valid
module procedure itm_is_valid_int4, itm_is_valid_int8, itm_is_valid_real8
end interface
contains
logical function itm_is_valid_int4(in_int)
implicit none
integer(ITM_I4) in_int
itm_is_valid_int4 = in_int .ne. itm_int_invalid
return
end function itm_is_valid_int4
logical function itm_is_valid_int8(in_int)
implicit none
integer(ITM_I8) in_int
itm_is_valid_int8 = in_int .ne. itm_int_invalid
return
end function itm_is_valid_int8
logical function itm_is_valid_real8(in_real)
implicit none
real(R8) in_real
itm_is_valid_real8 = abs(in_real - itm_r8_invalid) .gt. abs(itm_r8_invalid) * 1.0e-15_R8
return
end function itm_is_valid_real8
end module itm_types

106
src/magsurf_data.f90 Normal file
View File

@ -0,0 +1,106 @@
module magsurf_data
use const_and_precisions, only : wp_
implicit none
INTEGER, SAVE :: npsi, npoints !# sup mag, # punti per sup
INTEGER, SAVE :: njpt, nlmt
REAL(wp_), SAVE :: rarea
REAL(wp_), DIMENSION(:), ALLOCATABLE, SAVE :: psicon,pstab,rhot_eq, &
rhotqv,bav,varea,vcurrp,vajphiav,qqv,ffc,vratja,vratjb
REAL(wp_), DIMENSION(:), ALLOCATABLE, SAVE :: rpstab
REAL(wp_), DIMENSION(:), ALLOCATABLE, SAVE :: vvol,rri,rbav,bmxpsi,bmnpsi
REAL(wp_), DIMENSION(:), ALLOCATABLE, SAVE :: tjp,tlm,ch,ch01
REAL(wp_), DIMENSION(:,:), ALLOCATABLE, SAVE :: rcon,zcon
REAL(wp_), DIMENSION(:,:), ALLOCATABLE, SAVE :: cdadrhot,cdvdrhot
REAL(wp_), DIMENSION(:,:), ALLOCATABLE, SAVE :: cvol,crri,crbav,cbmx,cbmn,carea,cfc
REAL(wp_), DIMENSION(:,:), ALLOCATABLE, SAVE :: crhotq
REAL(wp_), DIMENSION(:,:), ALLOCATABLE, SAVE :: cratja,cratjb,cratjpl
contains
subroutine alloc_surf_anal(ierr)
implicit none
integer, intent(out) :: ierr
if(npsi.le.0.or.npoints.le.0) then
ierr = -1
return
end if
call dealloc_surf_anal
allocate(psicon(npsi),rcon(npsi,npoints), &
zcon(npsi,npoints),stat=ierr)
if (ierr/=0) call dealloc_surf_anal
end subroutine alloc_surf_anal
subroutine dealloc_surf_anal
implicit none
if(allocated(psicon)) deallocate(psicon)
if(allocated(rcon)) deallocate(rcon)
if(allocated(zcon)) deallocate(zcon)
end subroutine dealloc_surf_anal
subroutine alloc_surfvec(ierr)
implicit none
integer, intent(out) :: ierr
if(npsi.le.0.or.npoints.le.0) then
ierr = -1
return
end if
call dealloc_surfvec
allocate(psicon(npsi),rcon(npsi,npoints),zcon(npsi,npoints),pstab(npsi), &
rhot_eq(npsi),rhotqv(npsi),bav(npsi),bmxpsi(npsi),bmnpsi(npsi),varea(npsi), &
vvol(npsi),vcurrp(npsi),vajphiav(npsi),qqv(npsi),ffc(npsi),vratja(npsi), &
vratjb(npsi),rpstab(npsi),rri(npsi),rbav(npsi),cdadrhot(npsi,4), &
cdvdrhot(npsi,4),cbmx(npsi,4),cbmn(npsi,4),crbav(npsi,4),cvol(npsi,4), &
crri(npsi,4),carea(npsi,4),cfc(npsi,4),crhotq(npsi,4),cratjpl(npsi,4), &
cratja(npsi,4),cratjb(npsi,4),stat=ierr)
if (ierr/=0) call dealloc_surf_anal
end subroutine alloc_surfvec
subroutine dealloc_surfvec
implicit none
if(allocated(psicon)) deallocate(psicon)
if(allocated(rcon)) deallocate(rcon)
if(allocated(zcon)) deallocate(zcon)
if(allocated(pstab)) deallocate(pstab)
if(allocated(rhot_eq)) deallocate(rhot_eq)
if(allocated(rhotqv)) deallocate(rhotqv)
if(allocated(bav)) deallocate(bav)
if(allocated(bmxpsi)) deallocate(bmxpsi)
if(allocated(bmnpsi)) deallocate(bmnpsi)
if(allocated(varea)) deallocate(varea)
if(allocated(vvol)) deallocate(vvol)
if(allocated(vcurrp)) deallocate(vcurrp)
if(allocated(vajphiav)) deallocate(vajphiav)
if(allocated(qqv)) deallocate(qqv)
if(allocated(ffc)) deallocate(ffc)
if(allocated(vratja)) deallocate(vratja)
if(allocated(vratjb)) deallocate(vratjb)
if(allocated(rpstab)) deallocate(rpstab)
if(allocated(rri)) deallocate(rri)
if(allocated(rbav)) deallocate(rbav)
if(allocated(cdadrhot)) deallocate(cdadrhot)
if(allocated(cdvdrhot)) deallocate(cdvdrhot)
if(allocated(cbmx)) deallocate(cbmx)
if(allocated(cbmn)) deallocate(cbmn)
if(allocated(crbav)) deallocate(crbav)
if(allocated(cvol)) deallocate(cvol)
if(allocated(crri)) deallocate(crri)
if(allocated(carea)) deallocate(carea)
if(allocated(cfc)) deallocate(cfc)
if(allocated(crhotq)) deallocate(crhotq)
if(allocated(cratjpl)) deallocate(cratjpl)
if(allocated(cratja)) deallocate(cratja)
if(allocated(cratjb)) deallocate(cratjb)
end subroutine dealloc_surfvec
end module magsurf_data

125
src/math.f90 Normal file
View File

@ -0,0 +1,125 @@
module math
use const_and_precisions, only : wp_, zero, one
implicit none
contains
function catand(z)
!***begin prologue catan
!***purpose compute the complex arc tangent.
!***library slatec (fnlib)
!***category c4a
!***type complex (catan-c)
!***keywords arc tangent, elementary functions, fnlib, trigonometric
!***author fullerton, w., (lanl)
!***description
!
! catan(z) calculates the complex trigonometric arc tangent of z.
! the result is in units of radians, and the real part is in the first
! or fourth quadrant.
!
!***references (none)
!***routines called (none)
!***revision history (yymmdd)
! 770801 date written
! 890531 changed all specific intrinsics to generic. (wrb)
! 890531 revision date from version 3.2
! 891214 prologue converted to version 4.0 format. (bab)
! 900315 calls to xerror changed to calls to xermsg. (thj)
! 900326 removed duplicate information from description section.
! (wrb)
!***end prologue catan
use const_and_precisions, only : comp_eps, pi2=>pihalf, czero, cunit
implicit none
complex(wp_) :: catand
complex(wp_), intent(in) :: z
complex(wp_) :: z2
real(wp_) :: r,x,y,r2,xans,yans,twoi
integer :: i
logical, save :: first=.true.
integer, save :: nterms
real(wp_), save :: rmin, rmax, sqeps
!***first executable statement catan
if (first) then
! nterms = log(eps)/log(rbnd) where rbnd = 0.1
nterms = int(-0.4343_wp_*log(0.5_wp_*comp_eps) + 1.0_wp_)
sqeps = sqrt(comp_eps)
rmin = sqrt (1.5_wp_*comp_eps)
rmax = 2.0_wp_/comp_eps
endif
first = .false.
!
r = abs(z)
if (r<=0.1_wp_) then
!
catand = z
if (r<rmin) return
!
catand = czero
z2 = z*z
do i=1,nterms
twoi = 2*(nterms-i) + 1
catand = 1.0_wp_/twoi - z2*catand
end do
catand = z*catand
!
else if (r<=rmax) then
x = real(z)
y = aimag(z)
r2 = r*r
if (r2==one.and.x==zero) print*,'catand, z is +i or -i'
if (abs(r2-one)<=sqeps) then
if (abs(cunit+z*z) < sqeps) &
print*,'catand, answer lt half precision, z**2 close to -1'
!
end if
xans = 0.5_wp_*atan2(2.0_wp_*x, one)
yans = 0.25_wp_*log((r2+2.0_wp_*y+one)/(r2-2.0_wp_*y+one))
catand = cmplx(xans, yans, wp_)
!
else
catand = cmplx(pi2, zero, wp_)
if (real(z)<zero) catand = cmplx(-pi2, zero, wp_)
end if
end function catand
function fact(k)
implicit none
integer, intent(in) :: k
real(wp_) :: fact
integer :: i
! Factorial function
fact=zero
if(k<0) return
fact=one
if(k==0) return
do i=1,k
fact=fact*i
end do
end function fact
function gamm(xx)
implicit none
real(wp_) :: gamm
real(wp_), intent(in) :: xx
! Returns the value Gamma(xx) for xx > 0.
INTEGER :: j
real(wp_) :: ser,tmp,x,y
real(wp_), parameter :: stp=2.5066282746310005_wp_
real(wp_), dimension(6), parameter :: cof=(/76.18009172947146_wp_, &
-86.50532032941677_wp_,24.01409824083091_wp_,-1.231739572450155_wp_, &
.1208650973866179e-2_wp_,-.5395239384953e-5_wp_/)
x=xx
y=x
tmp=x+5.5_wp_
tmp=(x+0.5_wp_)*log(tmp)-tmp
ser=1.000000000190015_wp_
do j=1,6
y=y+1._wp_
ser=ser+cof(j)/y
end do
gamm=exp(tmp)*(stp*ser/x)
end function gamm
end module math

1985
src/minpack.f90 Normal file

File diff suppressed because it is too large Load Diff

257
src/numint.f90 Normal file
View File

@ -0,0 +1,257 @@
module numint
use const_and_precisions, only : wp_, zero, one
implicit none
contains
subroutine simpson (n,h,fi,s)
! subroutine for integration over f(x) with the simpson rule. fi:
! integrand f(x); h: interval; s: integral. copyright (c) tao pang 1997.
implicit none
integer, intent(in) :: n
real(wp_), intent(in) :: h
real(wp_), dimension(n), intent(in) :: fi
real(wp_), intent(out) :: s
integer :: i
real(wp_) :: s0,s1,s2
s = zero
s0 = zero
s1 = zero
s2 = zero
do i = 2, n-1, 2
s1 = s1+fi(i-1)
s0 = s0+fi(i)
s2 = s2+fi(i+1)
end do
s = h*(s1+4.0_wp_*s0+s2)/3.0_wp_
! if n is even, add the last slice separately
if (mod(n,2).eq.0) s = s+h*(5.0_wp_*fi(n)+8.0_wp_*fi(n-1)-fi(n-2))/12.0_wp_
end subroutine simpson
subroutine trapezoid(n,xi,fi,s)
! subroutine for integration with the trapezoidal rule.
! fi: integrand f(x); xi: abscissa x;
! s: integral Int_{xi(1)}^{xi(n)} f(x)dx
implicit none
integer, intent(in) :: n
real(wp_), dimension(n), intent(in) :: xi,fi
real(wp_), intent(out) :: s
integer :: i
s = zero
do i = 1, n-1
s = s+(xi(i+1)-xi(i))*(fi(i+1)-fi(i))
end do
s = 0.5_wp_*s
end subroutine trapezoid
subroutine quanc8(fun,a,b,abserr,relerr,result,errest,nofun,flag)
implicit none
real(wp_), intent(in) :: a, b, abserr, relerr
real(wp_), intent(out) :: result, errest, flag
integer, intent(out) :: nofun
!
! estimate the integral of fun(x) from a to b
! to a user provided tolerance.
! an automatic adaptive routine based on
! the 8-panel newton-cotes rule.
!
! input ..
!
! fun the name of the integrand function subprogram fun(x).
! a the lower limit of integration.
! b the upper limit of integration.(b may be less than a.)
! relerr a relative error tolerance. (should be non-negative)
! abserr an absolute error tolerance. (should be non-negative)
!
! output ..
!
! result an approximation to the integral hopefully satisfying the
! least stringent of the two error tolerances.
! errest an estimate of the magnitude of the actual error.
! nofun the number of function values used in calculation of result.
! flag a reliability indicator. if flag is zero, then result
! probably satisfies the error tolerance. if flag is
! xxx.yyy , then xxx = the number of intervals which have
! not converged and 0.yyy = the fraction of the interval
! left to do when the limit on nofun was approached.
!
real(wp_) :: w0,w1,w2,w3,w4,area,x0,f0,stone,step,cor11,temp
real(wp_) :: qprev,qnow,qdiff,qleft,esterr,tolerr
real(wp_), dimension(31) :: qright
real(wp_), dimension(16) :: f,x
real(wp_), dimension(8,30) :: fsave,xsave
integer :: levmin,levmax,levout,nomax,nofin,lev,nim,i,j
interface
function fun(x)
use const_and_precisions, only : wp_
implicit none
real(wp_), intent(in) :: x
real(wp_) :: fun
end function fun
end interface
!
! *** stage 1 *** general initialization
! set constants.
!
levmin = 1
levmax = 30
levout = 6
nomax = 5000
nofin = nomax - 8*(levmax-levout+2**(levout+1))
!
! trouble when nofun reaches nofin
!
w0 = 3956.0_wp_ / 14175.0_wp_
w1 = 23552.0_wp_ / 14175.0_wp_
w2 = -3712.0_wp_ / 14175.0_wp_
w3 = 41984.0_wp_ / 14175.0_wp_
w4 = -18160.0_wp_ / 14175.0_wp_
!
! initialize running sums to zero.
!
flag = zero
result = zero
cor11 = zero
errest = zero
area = zero
nofun = 0
if (a .eq. b) return
!
! *** stage 2 *** initialization for first interval
!
lev = 0
nim = 1
x0 = a
x(16) = b
qprev = zero
f0 = fun(x0)
stone = (b - a) / 16.0_wp_
x(8) = (x0 + x(16)) / 2.0_wp_
x(4) = (x0 + x(8)) / 2.0_wp_
x(12) = (x(8) + x(16)) / 2.0_wp_
x(2) = (x0 + x(4)) / 2.0_wp_
x(6) = (x(4) + x(8)) / 2.0_wp_
x(10) = (x(8) + x(12)) / 2.0_wp_
x(14) = (x(12) + x(16)) / 2.0_wp_
do j = 2, 16, 2
f(j) = fun(x(j))
end do
nofun = 9
!
! *** stage 3 *** central calculation
! requires qprev,x0,x2,x4,...,x16,f0,f2,f4,...,f16.
! calculates x1,x3,...x15, f1,f3,...f15,qleft,qright,qnow,qdiff,area.
!
do
do
x(1) = (x0 + x(2)) / 2.0_wp_
f(1) = fun(x(1))
do j = 3, 15, 2
x(j) = (x(j-1) + x(j+1)) / 2.0_wp_
f(j) = fun(x(j))
end do
nofun = nofun + 8
step = (x(16) - x0) / 16.0_wp_
qleft = (w0*(f0 + f(8)) + w1*(f(1)+f(7)) + w2*(f(2)+f(6)) &
+ w3*(f(3)+f(5)) + w4*f(4)) * step
qright(lev+1)=(w0*(f(8)+f(16))+w1*(f(9)+f(15))+w2*(f(10)+f(14)) &
+ w3*(f(11)+f(13)) + w4*f(12)) * step
qnow = qleft + qright(lev+1)
qdiff = qnow - qprev
area = area + qdiff
!
! *** stage 4 *** interval convergence test
!
esterr = abs(qdiff) / 1023.0_wp_
tolerr = max(abserr,relerr*abs(area)) * (step/stone)
if (lev .ge. levmin) then
!
! *** stage 6 *** trouble section
! number of function values is about to exceed limit.
!
if (lev .ge. levmax) then
!
! current level is levmax.
!
flag = flag + one
exit
end if
if (nofun .gt. nofin) then
nofin = 2*nofin
levmax = levout
flag = flag + (b - x0) / (b - a)
exit
end if
if (esterr .le. tolerr) exit
end if
!
! *** stage 5 *** no convergence
! locate next interval.
!
nim = 2*nim
lev = lev+1
!
! store right hand elements for future use.
!
do i = 1, 8
fsave(i,lev) = f(i+8)
xsave(i,lev) = x(i+8)
end do
!
! assemble left hand elements for immediate use.
!
qprev = qleft
do i = 1, 8
j = -i
f(2*j+18) = f(j+9)
x(2*j+18) = x(j+9)
end do
end do
!
! *** stage 7 *** interval converged
! add contributions into running sums.
!
result = result + qnow
errest = errest + esterr
cor11 = cor11 + qdiff / 1023.0_wp_
!
! locate next interval.
!
do
if (nim .eq. 2*(nim/2)) exit
nim = nim/2
lev = lev-1
end do
nim = nim + 1
if (lev .le. 0) exit
!
! assemble elements required for the next interval.
!
qprev = qright(lev)
x0 = x(16)
f0 = f(16)
do i = 1, 8
f(2*i) = fsave(i,lev)
x(2*i) = xsave(i,lev)
end do
end do
!
! *** stage 8 *** finalize and return
!
result = result + cor11
!
! make sure errest not less than roundoff level.
!
if (errest .eq. zero) return
do
temp = abs(result) + errest
if (temp .ne. abs(result)) return
errest = 2.0_wp_*errest
end do
end subroutine quanc8
end module numint

4541
src/quadpack.f90 Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +1,27 @@
module reflections
use const_and_precisions, only : wp_, comp_tiny, comp_eps, comp_huge, zero, one
implicit none
! === 1D array limiter Rlim_i, Zlim_i
integer, public, save :: nlim
real(wp_), public, dimension(:), allocatable, save :: rlim,zlim
private
integer, parameter :: r8=selected_real_kind(15,300)
real(r8), parameter :: tinyr8=tiny(1._r8)
public :: reflect,inters_linewall,inside
public :: linecone_coord,interssegm_coord,interssegm
public :: alloc_lim,wall_refl
contains
subroutine reflect(ki,nsurf,ko)
implicit none
real(r8), intent(in), dimension(3) :: ki
real(r8), intent(in), dimension(3) :: nsurf
real(r8), intent(out), dimension(3) :: ko
real(r8) :: twokn,norm2
real(wp_), intent(in), dimension(3) :: ki
real(wp_), intent(in), dimension(3) :: nsurf
real(wp_), intent(out), dimension(3) :: ko
real(wp_) :: twokn,norm2
norm2 = dot_product(nsurf,nsurf)
if (norm2>0.0_r8) then
twokn = 2.0_r8*dot_product(ki,nsurf)/norm2
if (norm2>zero) then
twokn = 2.0_wp_*dot_product(ki,nsurf)/norm2
ko=ki-twokn*nsurf
else
ko=ki
@ -24,30 +30,38 @@ end subroutine reflect
subroutine inters_linewall(xv,kv,rw,zw,nw,sint,normw)
implicit none
real(r8), intent(in), dimension(3) :: xv,kv
real(wp_), intent(in), dimension(3) :: xv,kv
integer, intent(in) :: nw
real(r8), dimension(nw), intent(in) :: rw,zw
real(r8), intent(out) :: sint
real(r8), dimension(3), intent(out) :: normw
integer :: i,j,ni,iint
real(r8), dimension(2) :: si,ti
real(r8) :: drw,dzw,xint,yint,rint,l,kxy
real(r8) :: tol
tol=sqrt(epsilon(1.0_r8))
sint=huge(sint)
real(wp_), dimension(nw), intent(in) :: rw,zw
real(wp_), intent(out) :: sint
real(wp_), dimension(3), intent(out) :: normw
integer :: i,j,ni,iint,nneg
real(wp_), dimension(2) :: si,ti
real(wp_) :: drw,dzw,xint,yint,rint,l,kxy
real(wp_) :: tol
tol=sqrt(comp_eps)
sint=comp_huge
iint=0
normw=0.0_r8
normw=zero
do i=1,nw-1
!search intersections with i-th wall segment
call linecone_coord(xv,kv,rw(i:i+1),zw(i:i+1),si,ti,ni)
do while (ni>0 .and. si(1)<=tol)
!remove solutions with s<=0
ni = ni-1
si(1) = si(2)
ti(1) = ti(2)
end do
!discard solutions with s<=0
nneg=0
do j=1,ni
if ((si(j)<sint .or. iint==0) .and. ti(j)>=0._r8 .and. ti(j)<=1._r8) then
if (si(j)<=tol) then
nneg=j
else
exit
end if
end do
! do while (ni>0 .and. si(1)<=tol)
! ni = ni-1
! si(1) = si(2) ???
! ti(1) = ti(2) ???
! end do
do j=nneg+1,ni
if ((si(j)<sint .or. iint==0) .and. ti(j)>=zero .and. ti(j)<=one) then
!check intersection is in r,z range and keep the closest
sint = si(j)
iint = i
@ -64,7 +78,7 @@ subroutine inters_linewall(xv,kv,rw,zw,nw,sint,normw)
l = sqrt(drw**2+dzw**2)
kxy = sqrt(kv(1)**2+kv(2)**2)
normw(3) = -drw/l
if (rint>0.0_r8) then
if (rint>zero) then
normw(1) = xint/rint*dzw/l
normw(2) = yint/rint*dzw/l
else
@ -72,17 +86,18 @@ subroutine inters_linewall(xv,kv,rw,zw,nw,sint,normw)
normw(2) = kv(2)/kxy*dzw/l
end if
!reverse normal if k.n>0
if (dot_product(normw,kv)>0.0_r8) normw=-normw
if (dot_product(normw,kv)>zero) normw=-normw
end subroutine inters_linewall
subroutine linecone_coord(xv,kv,rs,zs,s,t,n)
use utils, only : bubble
implicit none
real(r8), intent(in), dimension(3) :: xv,kv
real(r8), intent(in), dimension(2) :: rs,zs
real(r8), dimension(2), intent(out) :: s,t
real(wp_), intent(in), dimension(3) :: xv,kv
real(wp_), intent(in), dimension(2) :: rs,zs
real(wp_), dimension(2), intent(out) :: s,t
integer, intent(out) :: n
real(r8) :: x0,y0,z0,kx,ky,kz
real(r8) :: dr,dz,r,a,bhalf,c,delta,tvertex,zvertex,srmin,rmin,zrmin
real(wp_) :: x0,y0,z0,kx,ky,kz
real(wp_) :: dr,dz,r,a,bhalf,c,delta,tvertex,zvertex,srmin,rmin,zrmin
x0=xv(1)
y0=xv(2)
z0=xv(3)
@ -93,9 +108,9 @@ subroutine linecone_coord(xv,kv,rs,zs,s,t,n)
dz = zs(2)-zs(1)
s = 0
t = 0
if (abs(dz)<tinyr8) then
if (abs(dz)<comp_tiny) then
!surface in horizontal plane
if (abs(kz)<tinyr8 .or. abs(dr)<tinyr8) then
if (abs(kz)<comp_tiny .or. abs(dr)<comp_tiny) then
n = 0
else
s(1) = (zs(1)-z0)/kz
@ -107,9 +122,9 @@ subroutine linecone_coord(xv,kv,rs,zs,s,t,n)
a = (kx**2+ky**2) - (dr/dz*kz)**2
bhalf = -dr/dz*kz*rs(1) + (kx*x0 + ky*y0) - (dr/dz)**2*kz*(z0-zs(1))
c = (x0**2+y0**2) - (rs(1) + dr/dz*(z0-zs(1)))**2
if (abs(a)<tinyr8) then
if (abs(a)<comp_tiny) then
!line parallel to cone generator
if (abs(dr)<tinyr8) then
if (abs(dr)<comp_tiny) then
!cylinder and vertical line
n = 0
else
@ -118,14 +133,14 @@ subroutine linecone_coord(xv,kv,rs,zs,s,t,n)
srmin = -(kx*x0 + ky*y0)/(kx**2+ky**2)
rmin = sqrt((x0+srmin*kx)**2+(y0+srmin*ky)**2)
zrmin = z0 + srmin*kz
if (rmin<tinyr8 .and. abs(zrmin-zvertex)<tinyr8) then
if (rmin<comp_tiny .and. abs(zrmin-zvertex)<comp_tiny) then
!line passing by cone vertex
!s(1) = srmin
!t(1) = tvertex
!n = 1
n = 0
else
s(1) = -0.5_r8*c/bhalf
s(1) = -0.5_wp_*c/bhalf
t(1) = (kz*s(1)+(z0-zs(1)))/dz
n = 1
end if
@ -147,18 +162,18 @@ end subroutine linecone_coord
subroutine interssegm_coord(xa,ya,xb,yb,s,t,ierr)
implicit none
real(r8), dimension(2), intent(in) :: xa,ya,xb,yb
real(r8), intent(out) :: s,t
real(wp_), dimension(2), intent(in) :: xa,ya,xb,yb
real(wp_), intent(out) :: s,t
integer, intent(out) :: ierr
real(r8) :: crossprod,dxa,dya,dxb,dyb
real(wp_) :: crossprod,dxa,dya,dxb,dyb
dxa = xa(2)-xa(1)
dya = ya(2)-ya(1)
dxb = xb(2)-xb(1)
dyb = yb(2)-yb(1)
crossprod = dxb*dya - dxa*dyb
if (abs(crossprod)<tiny(crossprod)) then
s = 0.0_r8
t = 0.0_r8
if (abs(crossprod)<comp_tiny) then
s = zero
t = zero
ierr = 1
else
s = (dyb*(xa(1)-xb(1)) - dxb*(ya(1)-yb(1)))/crossprod
@ -169,25 +184,26 @@ end subroutine interssegm_coord
function interssegm(xa,ya,xb,yb)
implicit none
real(r8), dimension(2), intent(in) :: xa,ya,xb,yb
real(wp_), dimension(2), intent(in) :: xa,ya,xb,yb
logical :: interssegm
real(r8) :: s,t
real(wp_) :: s,t
integer :: ierr
interssegm = .false.
call interssegm_coord(xa,ya,xb,yb,s,t,ierr)
if (ierr==0 .and. s>=0._r8 .and. s<=1._r8 .and. &
t>=0._r8 .and. t<=1._r8) interssegm = .true.
if (ierr==0 .and. s>=zero .and. s<=one .and. &
t>=zero .and. t<=one) interssegm = .true.
end function interssegm
function inside(xc,yc,n,x,y)
use utils, only : locatef, locate_unord, intlinf, bubble
implicit none
integer, intent(in) :: n
real(r8), dimension(n), intent(in) :: xc,yc
real(r8), intent(in) :: x,y
real(wp_), dimension(n), intent(in) :: xc,yc
real(wp_), intent(in) :: x,y
logical :: inside
integer, dimension(n) :: jint
real(r8), dimension(n) :: xint
real(r8), dimension(n+1) :: xclosed,yclosed
real(wp_), dimension(n) :: xint
real(wp_), dimension(n+1) :: xclosed,yclosed
integer :: i,nj
xclosed(1:n)=xc(1:n)
yclosed(1:n)=yc(1:n)
@ -197,92 +213,107 @@ function inside(xc,yc,n,x,y)
inside=.false.
if (nj==0) return
do i=1,nj
xint(i)=intlin(yclosed(jint(i)),xclosed(jint(i)), &
xint(i)=intlinf(yclosed(jint(i)),xclosed(jint(i)), &
yclosed(jint(i)+1),xclosed(jint(i)+1),y)
end do
call bubble(xint,nj)
inside=(mod(locate(xint,nj,x),2)==1)
inside=(mod(locatef(xint,nj,x),2)==1)
end function inside
function intlin(x1,y1,x2,y2,x) result(y)
!linear interpolation
!must be x1 != x2
subroutine alloc_lim(ier)
implicit none
real(r8),intent(in) :: x1,y1,x2,y2,x
real(r8) :: y
real(r8) :: a
a=(x2-x)/(x2-x1)
y=a*y1+(1._r8-a)*y2
end function intlin
subroutine locate_unord(a,n,x,j,m,nj)
implicit none
integer, intent(in) :: n,m
integer, intent(out) :: nj
real(r8), dimension(n), intent(in) :: a
real(r8), intent(in) :: x
integer, dimension(m), intent(inout) :: j
integer :: i
nj=0
do i=1,n-1
if (x>a(i).neqv.x>a(i+1)) then
nj=nj+1
if (nj<=m) j(nj)=i
end if
end do
end subroutine locate_unord
function locate(a,n,x) result(j)
!Given an array a(n), and a value x, with a(n) monotonic, either
!increasing or decreasing, returns a value j such that
!a(j) < x <= a(j+1) for a increasing, and such that
!a(j+1) < x <= a(j) for a decreasing.
!j=0 or j=n indicate that x is out of range (Numerical Recipes)
implicit none
integer, intent(in) :: n
real(r8), dimension(n), intent(in) :: a
real(r8), intent(in) :: x
integer :: j
integer :: jl,ju,jm
logical :: incr
jl=0
ju=n+1
incr=a(n)>a(1)
do while ((ju-jl)>1)
jm=(ju+jl)/2
if(incr.eqv.(x>a(jm))) then
jl=jm
else
ju=jm
endif
end do
j=jl
end function locate
subroutine order(p,q)
!returns p,q in ascending order
implicit none
real(r8), intent(inout) :: p,q
real(r8) :: temp
if (p>q) then
temp=p
p=q
q=temp
integer, intent(out) :: ier
if(nlim.lt.0) then
ier = -1
return
end if
end subroutine order
call dealloc_lim
allocate(rlim(nlim),zlim(nlim), &
stat=ier)
if (ier/=0) call dealloc_lim
end subroutine alloc_lim
subroutine bubble(a,n)
!bubble sorting of array a
subroutine dealloc_lim
implicit none
integer, intent(in) :: n
real(r8), dimension(n), intent(inout) :: a
integer :: i, j
do i=1,n
do j=n,i+1,-1
call order(a(j-1), a(j))
end do
end do
end subroutine bubble
if(allocated(rlim)) deallocate(rlim)
if(allocated(zlim)) deallocate(zlim)
end subroutine dealloc_lim
subroutine wall_refl(xv,anv,ext,eyt,xvrfl,anvrfl,extr,eytr,walln,irfl)
implicit none
! arguments
integer :: irfl
real(wp_), dimension(3) :: xv,anv,xvrfl,anvrfl,walln
complex(wp_) :: ext,eyt,extr,eytr
! local variables
real(wp_) :: smax,rrm,zzm
real(wp_), dimension(3) :: anv0,vv1,vv2,vv3
complex(wp_) :: eztr
complex(wp_), dimension(3) :: evin,evrfl
!
anv0=anv/sqrt(anv(1)**2+anv(2)**2+anv(3)**2)
rrm=1.0e-2_wp_*sqrt(xv(1)**2+xv(2)**2)
zzm=1.0e-2_wp_*xv(3)
!
! computation of reflection coordinates and normal to the wall
call inters_linewall(xv/1.0e2_wp_,anv0,rlim(1:nlim),zlim(1:nlim), &
nlim,smax,walln)
smax=smax*1.0e2_wp_
xvrfl=xv+smax*anv0
irfl=1
if (.not.inside(rlim,zlim,nlim,rrm,zzm)) then
! first wall interface is outside-inside
if (dot_product(walln,walln)<tiny(walln)) then
! wall never hit
xvrfl=xv
anvrfl=anv0
extr=ext
eytr=eyt
irfl=0
return
end if
! search second wall interface (inside-outside)
call inters_linewall(xvrfl/1.0e2_wp_,anv0,rlim(1:nlim), &
zlim(1:nlim),nlim,smax,walln)
smax=smax*1.0e2_wp_
xvrfl=xvrfl+smax*anv0
irfl=2
end if
!
! rotation matrix from local to lab frame
vv1(1)=anv0(2)
vv1(2)=-anv0(1)
vv1(3)=0.0_wp_
vv2(1)=anv0(1)*anv0(3)
vv2(2)=anv0(2)*anv0(3)
vv2(3)=-anv0(1)*anv0(1)-anv0(2)*anv0(2)
vv1=vv1/sqrt(vv1(1)**2+vv1(2)**2+vv1(3)**2)
vv2=vv2/sqrt(vv2(1)**2+vv2(2)**2+vv2(3)**2)
vv3=anv0
!
evin=ext*vv1+eyt*vv2
! wave vector and electric field after reflection in lab frame
anvrfl=anv0-2.0_wp_* &
(anv0(1)*walln(1)+anv0(2)*walln(2)+anv0(3)*walln(3))*walln
evrfl=-evin+2.0_wp_* &
(evin(1)*walln(1)+evin(2)*walln(2)+evin(3)*walln(3))*walln
!
vv1(1)=anvrfl(2)
vv1(2)=-anvrfl(1)
vv1(3)=0.0_wp_
vv2(1)=anvrfl(1)*anvrfl(3)
vv2(2)=anvrfl(2)*anvrfl(3)
vv2(3)=-anvrfl(1)*anvrfl(1)-anvrfl(2)*anvrfl(2)
vv1=vv1/sqrt(vv1(1)**2+vv1(2)**2+vv1(3)**2)
vv2=vv2/sqrt(vv2(1)**2+vv2(2)**2+vv2(3)**2)
vv3=anvrfl/sqrt(anvrfl(1)**2+anvrfl(2)**2+anvrfl(3)**2)
!
extr=dot_product(vv1,evrfl)
eytr=dot_product(vv2,evrfl)
eztr=dot_product(vv3,evrfl)
end
end module reflections

273
src/simplespline.f90 Normal file
View File

@ -0,0 +1,273 @@
module simplespline
use const_and_precisions, only : wp_
implicit none
contains
function spli(cspli,n,k,dx)
implicit none
integer, intent(in) :: n, k
real(wp_), intent(in) :: cspli(n,4), dx
real(wp_) :: spli
spli=cspli(k,1)+dx*(cspli(k,2)+dx*(cspli(k,3)+dx*cspli(k,4)))
end function spli
function splid(cspli,n,k,dx)
implicit none
integer, intent(in) :: n, k
real(wp_), intent(in) :: cspli(n,4), dx
real(wp_) :: splid
splid=cspli(k,2)+dx*(2.0_wp_*cspli(k,3)+3.0_wp_*dx*cspli(k,4))
end function splid
subroutine difcs(x,y,n,iopt,c,ier)
implicit none
integer, intent(in) :: n, iopt
real(wp_), intent(in) :: x(n), y(n)
real(wp_), intent(inout) :: c(n*4)
integer :: ier
integer :: jmp,iol,ioh,i,ii,j,j1,j2,j3
real(wp_) :: xb,xc,ya,yb,h,a,r,dya,dyb,dy2
jmp =1
if (n <= 1) return
!
! initialization
!
xc =x(1)
yb =y(1)
h =0.0_wp_
a =0.0_wp_
r =0.0_wp_
dyb =0.0_wp_
!
! iol=0 - given derivative at first point
! ioh=0 - given derivative at last point
!
iol =iopt-1
ioh =iopt-2
if (ioh == 1) then
iol =0
ioh =0
end if
dy2 =c(2)
!
! form the system of linear equations
! and eliminate subsequentially
!
j =1
do i=1,n
j2 =n+i
j3 =j2+n
a =h*(2.0_wp_-a)
dya =dyb+h*r
if (i>=n) then
!
! set derivative dy2 at last point
!
dyb =dy2
h =0.0_wp_
if (ioh/=0) then
dyb =dya
goto 13
end if
else
j =j+jmp
xb =xc
xc =x(j)
h =xc-xb
!
! ii=0 - increasing abscissae
! ii=1 - decreasing abscissae
!
ii =0
if (h==0) return
if (h<0) ii =1
ya =yb
yb =y(j)
dyb =(yb-ya)/h
if (i<=1) then
j1 =ii
if (iol/=0) goto 13
dya =c(1)
end if
end if
if (j1-ii /= 0) return
a =1.0_wp_/(h+h+a)
13 continue
r =a*(dyb-dya)
c(j3)=r
a =h*a
c(j2)=a
c(i) =dyb
end do
!
! back substitution of the system of linear equations
! and computation of the other coefficients
!
a =1.0_wp_
j1 =j3+n+ii-ii*n
i =n
do iol=1,n
xb =x(j)
h =xc-xb
xc =xb
a =a+h
yb =r
r =c(j3)-r*c(j2)
ya =r+r
c(j3)=ya+r
c(j2)=c(i)-h*(ya+yb)
c(j1)=(yb-r)/a
c(i) =y(j)
a =0.0_wp_
j =j-jmp
i =i-1
j2 =j2-1
j3 =j3-1
j1 =j3+n+ii
end do
ier =0
end subroutine difcs
subroutine difcsn(xx,yy,nmx,n,iopt,cc,ier)
!
! same as difcs but with dimension(xx,yy) = nmx > n
!
implicit none
integer, intent(in) :: nmx, n, iopt
real(wp_), intent(in) :: xx(nmx), yy(nmx)
real(wp_), intent(inout) :: cc(nmx,4)
integer :: ier
integer :: jmp,iol,ioh,i,ii,j,j1,j2,j3
real(wp_) :: x(n),y(n),c(n*4),xb,xc,ya,yb,h,a,r,dya,dyb,dy2
!
do i=1,n
x(i)=xx(i)
y(i)=yy(i)
end do
ii=0
do j=1,4
do i=1,n
ii=ii+1
c(ii)=cc(i,j)
end do
end do
!
jmp =1
if (n>1) then
!
! initialization
!
xc =x(1)
yb =y(1)
h =0.0_wp_
a =0.0_wp_
r =0.0_wp_
dyb =0.0_wp_
!
! iol=0 - given derivative at first point
! ioh=0 - given derivative at last point
!
iol =iopt-1
ioh =iopt-2
if (ioh==1) then
iol =0
ioh =0
end if
dy2 =c(2)
!
! form the system of linear equations
! and eliminate subsequentially
!
j =1
do i=1,n
j2 =n+i
j3 =j2+n
a =h*(2.0_wp_-a)
dya =dyb+h*r
if (i>=n) then
!
! set derivative dy2 at last point
!
dyb =dy2
h =0.0_wp_
if (ioh/=0) then
dyb =dya
goto 13
end if
else
j =j+jmp
xb =xc
xc =x(j)
h =xc-xb
!
! ii=0 - increasing abscissae
! ii=1 - decreasing abscissae
!
ii =0
if (h==0) goto 16
if (h<0) ii =1
ya =yb
yb =y(j)
dyb =(yb-ya)/h
if (i<=1) then
j1 =ii
if (iol/=0) goto 13
dya =c(1)
end if
end if
if (j1/=ii) goto 16
a =1.0_wp_/(h+h+a)
13 continue
r =a*(dyb-dya)
c(j3)=r
a =h*a
c(j2)=a
c(i) =dyb
end do
!
! back substitution of the system of linear equations
! and computation of the other coefficients
!
a =1.0_wp_
j1 =j3+n+ii-ii*n
i =n
do iol=1,n
xb =x(j)
h =xc-xb
xc =xb
a =a+h
yb =r
r =c(j3)-r*c(j2)
ya =r+r
c(j3)=ya+r
c(j2)=c(i)-h*(ya+yb)
c(j1)=(yb-r)/a
c(i) =y(j)
a =0.0_wp_
j =j-jmp
i =i-1
j2 =j2-1
j3 =j3-1
j1 =j3+n+ii
end do
ier =0
end if
!
16 continue
ii=0
do j=1,4
do i=1,nmx
if(i<=n) then
ii=ii+1
cc(i,j)=c(ii)
else
cc(i,j)=0.0_wp_
end if
end do
end do
!
end subroutine difcsn
end module simplespline

278
src/utils.f90 Normal file
View File

@ -0,0 +1,278 @@
module utils
use const_and_precisions, only : wp_
implicit none
contains
function locatef(a,n,x) result(j)
! Given an array a(n), and a value x, with a(n) monotonic, either
! increasing or decreasing, returns a value j such that
! a(j) < x <= a(j+1) for a increasing, and such that
! a(j+1) < x <= a(j) for a decreasing.
! j=0 or j=n indicate that x is out of range (Numerical Recipes)
implicit none
integer, intent(in) :: n
real(wp_), dimension(n), intent(in) :: a
real(wp_), intent(in) :: x
integer :: j
integer :: jl,ju,jm
logical :: incr
jl=0
ju=n+1
incr=a(n)>a(1)
do while ((ju-jl)>1)
jm=(ju+jl)/2
if(incr.eqv.(x>a(jm))) then
jl=jm
else
ju=jm
endif
end do
j=jl
end function locatef
subroutine locate(xx,n,x,j)
implicit none
integer, intent(in) :: n
real(wp_), intent(in) :: xx(n), x
integer, intent(out) :: j
integer :: jl,ju,jm
logical :: incr
!
! Given an array xx(n), and a value x
! returns a value j such that xx(j) < x < xx(j+1)
! xx(n) must be monotonic, either increasing or decreasing.
! j=0 or j=n indicate that x is out of range (Numerical Recipes)
!
jl=0
ju=n+1
incr=xx(n)>xx(1)
do while ((ju-jl)>1)
jm=(ju+jl)/2
if(incr .eqv. (x>xx(jm))) then
jl=jm
else
ju=jm
endif
end do
j=jl
end subroutine locate
subroutine locatex(xx,n,n1,n2,x,j)
implicit none
integer, intent(in) :: n,n1,n2
real(wp_), intent(in) :: xx(n), x
integer, intent(out) :: j
integer :: jl,ju,jm
!
! Given an array xx(n), and a value x
! returns a value j such that xx(j) < x < xx(j+1)
! xx(n) must be monotonic, either increasing or decreasing.
! j=n1-1or j=n2+1 indicate that x is out of range
! modified from subr. locate (Numerical Recipes)
!
jl=n1-1
ju=n2+1
do while ((ju-jl)>1)
jm=(ju+jl)/2
if((xx(n2)>xx(n1)) .eqv. (x>xx(jm))) then
jl=jm
else
ju=jm
endif
end do
j=jl
end subroutine locatex
subroutine locate_unord(a,n,x,j,m,nj)
implicit none
integer, intent(in) :: n,m
integer, intent(out) :: nj
real(wp_), dimension(n), intent(in) :: a
real(wp_), intent(in) :: x
integer, dimension(m), intent(inout) :: j
integer :: i
nj=0
do i=1,n-1
if (x>a(i).neqv.x>a(i+1)) then
nj=nj+1
if (nj<=m) j(nj)=i
end if
end do
end subroutine locate_unord
function intlinf(x1,y1,x2,y2,x) result(y)
!linear interpolation
!must be x1 != x2
use const_and_precisions, only : one
implicit none
real(wp_),intent(in) :: x1,y1,x2,y2,x
real(wp_) :: y
real(wp_) :: a
a=(x2-x)/(x2-x1)
y=a*y1+(one-a)*y2
end function intlinf
subroutine intlin(x1,y1,x2,y2,x,y)
implicit none
real(wp_), intent(in) :: x1,y1,x2,y2,x
real(wp_), intent(out) :: y
real(wp_) :: dx,aa,bb
!
! linear interpolation
! (x1,y1) < (x,y) < (x2,y2)
!
dx=x2-x1
aa=(x2-x)/dx
bb=1.0_wp_-aa
y=aa*y1+bb*y2
end subroutine intlin
subroutine vmax(x,n,xmax,imx)
implicit none
integer, intent(in) :: n
real(wp_), intent(in) :: x(n)
real(wp_), intent(out) :: xmax
integer, intent(out) :: imx
integer :: i
if (n<1) then
imx=0
return
end if
imx=1
xmax=x(1)
do i=2,n
if(x(i)>xmax) then
xmax=x(i)
imx=i
end if
end do
end subroutine vmax
subroutine vmin(x,n,xmin,imn)
implicit none
integer, intent(in) :: n
real(wp_), intent(in) :: x(n)
real(wp_), intent(out) :: xmin
integer, intent(out) :: imn
integer :: i
if (n<1) then
imn=0
return
end if
imn=1
xmin=x(1)
do i=2,n
if(x(i)<xmin) then
xmin=x(i)
imn=i
end if
end do
end subroutine vmin
subroutine vmaxmini(x,n,xmin,xmax,imn,imx)
implicit none
integer, intent(in) :: n
real(wp_), intent(in) :: x(n)
real(wp_), intent(out) :: xmin, xmax
integer, intent(out) :: imn, imx
integer :: i
if (n<1) then
imn=0
imx=0
return
end if
imn=1
imx=1
xmin=x(1)
xmax=x(1)
do i=2,n
if(x(i)<xmin) then
xmin=x(i)
imn=i
else if(x(i)>xmax) then
xmax=x(i)
imx=i
end if
end do
end subroutine vmaxmini
subroutine vmaxmin(x,n,xmin,xmax)
implicit none
integer, intent(in) :: n
real(wp_), intent(in) :: x(n)
real(wp_), intent(out) :: xmin, xmax
integer :: i
if (n<1) then
return
end if
xmin=x(1)
xmax=x(1)
do i=2,n
if(x(i)<xmin) then
xmin=x(i)
else if(x(i)>xmax) then
xmax=x(i)
end if
end do
end subroutine vmaxmin
subroutine order(p,q)
! returns p,q in ascending order
implicit none
real(wp_), intent(inout) :: p,q
real(wp_) :: temp
if (p>q) then
temp=p
p=q
q=temp
end if
end subroutine order
subroutine bubble(a,n)
! bubble sorting of array a
implicit none
integer, intent(in) :: n
real(wp_), dimension(n), intent(inout) :: a
integer :: i, j
do i=1,n
do j=n,i+1,-1
call order(a(j-1), a(j))
end do
end do
end subroutine bubble
function get_free_unit(umin,umax) result(i)
implicit none
integer :: i
integer, intent(in), optional :: umin, umax
integer, parameter :: max_allowed = 999
integer :: ierr, iend
logical :: ex, op
if (present(umin)) then
i = max(0,umin) ! start searching from unit min
else
i = 0
end if
if (present(umax)) then
iend = min(max(0,umax),max_allowed)
else
iend = max_allowed
end if
do
if (i>iend) then
i=-1 ! no free units found
exit
end if
inquire(unit=i,exist=ex,opened=op,iostat=ierr)
if (ierr==0.and.ex.and..not.op) exit ! unit i exists and is not open
i = i + 1
end do
end function get_free_unit
end module utils