-4

我已经工作了很多天,试图找出这段代码有什么问题。它用于模拟通过非饱和土壤的水流。方程组采用三对角矩阵的形式,用 Thomas 算法求解。我有解决方案,但代码不代表它。例如,节点 A 应该是一条从初始条件 aprox -100 cm 到 aprox -20 cm 的曲线。这是一个很长的代码,但如果有人在这个代码中帮助我,我将非常感激。

program EcuacionRichards

implicit none

!Declaring variables

integer, parameter :: nodos = 100
integer :: i, it, max_it, nodo_a, nodo_b, nodo_c, nodo_d, it_bajo, it_alto
double precision, dimension(1:nodos) :: H, H_ant, C, K, theta, theta_ant, aa, bb, cc, dd, rr, th_ant
double precision :: dz, zbot, tfin, dt, rz, Ksup, Kinf, t, th_lisimetro, h_lisimetro  
double precision :: q_ent, tol_h, tol_th, cambio_h, cambio_th
double precision :: mult_alto, mult_bajo, maxdt, mindt, qlibre
logical lisimetro

!Hydraulic Parameters
double precision :: theta_sat=0.43      !cm/cm 
double precision :: theta_res=0.078     !cm/cm
double precision :: alpha=0.0325        !1/cm
double precision :: n=1.346
double precision :: m
double precision :: K_sat=86.4          !cm/d

!Grid and iteration parameters
lisimetro=.true.
dt=0.01             !days
zbot=160            !depth of the column in cm
dz=zbot/nodos       !cm
tfin=30             !days
max_it=500          !max number of Picard iterations
tol_h=0.1           !tolerance for H iteration, cm
tol_th=0.001        !tolerance for theta iteration, 1/1
it_bajo=3           !minimum recommended number of iterations
it_alto=7           !maximum recommended number of iterations
mult_bajo=1.3       !time multiplicator for low iterations
mult_alto=0.7       !time multiplicator for low iterations
maxdt=0.5           !max value for dt 
mindt=0.001         !min value for dt 
m=1-1/n

!Initializing other variables
th_lisimetro=0.32
h_lisimetro=HfTH(th_lisimetro)

nodo_a=nodos
nodo_b=2*nodos/3
nodo_c=nodos/3
nodo_d=1

!*********Initial Conditions************************************************************

call theta_ini(theta,nodos) !Fill array with initial moisture values
do i=1,nodos
    H(i)=HfTH(theta(i))
    call actualiza(H(i), theta(i), C(i), K(i))
end do

!************* OPEN WRITING FILES ************************************************
open(unit=1,file='succion2.txt')
open(unit=2,file='humedad2.txt')
open(unit=3,file='conducti2.txt')
open(unit=4,file='parametr2.txt')
write(4,'("dt(días) =",f7.4)') dt 
write(4,'("dz(cm) =",f7.4)') dz
write(4,'("nodos =",i5)') nodos
write(4,'("altura(cm) =",f8.3)') zbot
write(4,'("tfin(días) =",f7.2)') tfin
write(4,'("theta_sat =",f7.4)') theta_sat
write(4,'("theta_res =",f7.4)') theta_res
write(4,'("K_saturada =",g11.3)') K_sat
write(4,'("n =",f7.4)') n
write(4,'("m =",f7.5)') m
write(4,'("alpha =",f7.5)') alpha
write(4,'("max_it =",i4)') max_it
close(4)
write(1,*) "T(días) H_a(cm) H_b(cm) H_c(cm) H_d(cm)"
write(2,*) "T(días) th_a(cm) th_b(cm) th_c(cm) th_d(cm)"
write(3,*) "T(días) K_a(cm/d) K_b(cm/d) K_c(cm/d) K_d(cm/d)" 


!*************TIME LOOP**********************************************************************************************
t=0.d0
do while ((t.le.tfin).and.(dt.gt.0))
    rz=dz/dt
    t=t+dt
    theta_ant=theta !Previous time
    !Water flow that enters at the top (constant)
    q_ent=0.1       !cm/dia
!*************     PICARD LOOP              ******************************************
Picard:do it=1,max_it

            if(it.eq.max_it) pause "MAXIMUM ITERATIONS REACHED"

            !Interior Nodes
            do i=2, nodos-1
                 Ksup=2*(K(i+1)*K(i))/(K(i+1)+K(i))
                 Kinf=2*(K(i-1)*K(i))/(K(i-1)+K(i))
                 aa(i)=-Kinf/dz !K(i-1/2)
                 cc(i)=-Ksup/dz !K(i+1/2)
                 bb(i)=rz*C(i)-aa(i)-cc(i)
                 rr(i)=rz*C(i)*h(i)-rz*(theta(i)-theta_ant(i))+Ksup-Kinf
            end do

            !Inferior Node
            if (lisimetro) then
              !Changing inferior node
              if (theta(1).lt.th_lisimetro) then
                    !Water flow 0, Neumann
                    Ksup=2*(K(1)*K(2))/(K(1)+K(2))
                    aa(1)=0
                    cc(1)=-Ksup/dz
                    bb(1)=-cc(1)
                    rr(1)=Ksup
              else
                    !H(1)=0 condition, Dirichlet
                    Ksup=2*(K(1)*K(2))/(K(1)+K(2))
                    aa(1)=0
                    bb(1)=1
                    cc(1)=0
                    rr(1)=h_lisimetro
                    aa(2)=0
                    rr(2)=rr(2)+Ksup/dz*(h_lisimetro)
              end if
            else
              !Inferior node, free drainage, Neumann
              Ksup=2*(K(1)*K(2))/(K(1)+K(2))
              qlibre=-K(1)
              aa(1)=0
              cc(1)=-Ksup/dz
              bb(1)=-cc(1)
              rr(1)=Ksup+qlibre
            end if

            !Superior node, known water flow
            Kinf=2*(K(nodos)*K(nodos-1))/(K(nodos)+K(nodos-1))
            aa(nodos)=-Kinf/dz
            cc(nodos)=0
            bb(nodos)=0.5*rz*C(nodos)-aa(nodos)
            rr(nodos)=0.5*rz*C(nodos)*h(nodos)-0.5*rz*(theta(nodos)-theta_ant(nodos))-Kinf-q_ent

            call tridiag(aa,bb,cc,rr,dd,nodos)

            !Suction modification and H functions actualization
            h_ant=h
            th_ant=theta !Save iteration
            h=dd         !Advance to next iteration 
            do i=1,nodos
                call actualiza(H(i),theta(i), C(i), K(i))
            end do

            !End of iterations condition
            cambio_h=maxval(dabs(h-h_ant))
            cambio_th=maxval(dabs(theta-th_ant))

            if((cambio_h.lt.tol_h).and.(cambio_th.lt.tol_th)) then

                if(.true.) then !(t.eq.tprint)
                write (1,'(f8.3,f9.3,f9.3,f9.3,f9.3)') t,H(nodo_a),H(nodo_b),H(nodo_c),H(nodo_d)
                write (2,'(f8.3,f7.4,f7.4,f7.4,f7.4)') t,theta(nodo_a),theta(nodo_b),theta(nodo_c),theta(nodo_d)
                write (3,'(f8.3,g11.4,g11.4,g11.4,g11.4)') t,k(nodo_a),k(nodo_b),k(nodo_c),k(nodo_d)
                end if

                if (it.lt.it_bajo) dt=min(dt*mult_bajo,maxdt)
                if (it.gt.it_alto) dt=max(dt*mult_alto,mindt)

                exit Picard

            else
                cycle Picard
            end if
       end do Picard !Picard loop end
       if ((tfin-t).le.1E-4) t=huge(1.d0)
end do
!Time Loop End***************************************************************
!******** Close files
close(1)
close(2)
close(3)

!********END OF PROGRAM**********************************************************
!******************************************************************************
!Subroutines and functions
contains

!Initial moistures assignment
subroutine theta_ini(theta,nodos)
integer :: nodos
double precision, dimension(1:nodos) :: theta
integer i
do i=1, nodos
    theta(i)=0.30
end do
end subroutine theta_ini

!Subroutine that actualizes salues according to pressure
subroutine actualiza(p,theta,c,k)
    double precision p, theta, c, k
    double precision se, te
    if(p.lt.0) then           
                  te=1+(-alpha*p)**n
                  se=te**(-m)
                  theta=theta_res+(theta_sat-theta_res)*se
                  K=K_sat*se**(0.5)*(1-(1-se**(1/m))**m)**2
                  c=((alpha**n)*(theta_sat-theta_res)*n*m*(-p)**(n-1))/(te**(m+1)) !d(theta)/dh
    else 
                  theta=theta_sat
                  K=K_sat
                  c=0
    end if
    return
end subroutine actualiza

!Tridiag(alpha,beta, gamma, Resto, delta, nodos)
      subroutine tridiag(a,b,c,d,x,n)
      implicit none
!        a - sub-diagonal (means it is the diagonal below the main diagonal)
!        b - the main diagonal
!        c - sup-diagonal (means it is the diagonal above the main diagonal)
!        d - right part
!        x - the answer
!        n - number of equations

        integer,intent(in) :: n
        double precision,dimension(n),intent(in) :: a,b,c,d
        double precision,dimension(n),intent(out) :: x
        double precision,dimension(n) :: cp,dp
        double precision :: m
        integer i

! initialize c-prime and d-prime
        cp(1) = c(1)/b(1)
        dp(1) = d(1)/b(1)
! solve for vectors c-prime and d-prime
         do i = 2,n
           m = b(i)-cp(i-1)*a(i)
           cp(i) = c(i)/m
           dp(i) = (d(i)-dp(i-1)*a(i))/m
         enddo
! initialize x
         x(n) = dp(n)
! solve for x from the vectors c-prime and d-prime
        do i = n-1, 1, -1
          x(i) = dp(i)-cp(i)*x(i+1)
        end do

    end subroutine tridiag

!Head in terms of moisture
Function HfTH(humedad)
    double precision HfTH
    double precision humedad
    if (humedad.lt.theta_sat) then
              HfTH=-1/alpha*(((humedad-theta_res)/(theta_sat-theta_res))**(-1/m)-1)**(1/n) !cm
    else
              HfTH=0
    end if
    Return
end function HfTH

end program EcuacionRichards
4

1 回答 1

2

我可以看到你的代码有很多问题,但我的注意力有限,所以这里只是最令人震惊的

double precision例如,您将一堆变量声明为theta_sat,但您使用默认类型的文字初始化它们。该声明

double precision :: theta_sat=0.43      !cm/cm 

不做真实的0.43double precision好吧,准确地说,它可能在大多数编译器上,并且只要编译没有将默认实变量设置为 kind double precision,它就不会。几乎可以肯定的0.43是 4 字节实数,而theta_sat8 字节实数,您不能依赖编译器将其设置theta_sat为最接近 的 8 字节值0.43

在现代 Fortrandouble precision中,仍然可用于向后兼容,但不推荐使用,以支持使用 kind 类型指定变量的种类。SO充满了如何做到这一点的建议。我最喜欢的是使用内部模块中定义的常量iso_fortran_env,如下所示:

use, intrinsic :: iso_fortran_env

然后像这样声明变量:

real(real64) :: theta_sat=0.43_real64      !cm/cm 

请注意将种类规范附加_real64到该值。

你的算法是否足够敏感以至于你的这个错误会严重影响我不知道的结果。

最后,您告诉我们程序不正确,但您对程序不正确的方式保持沉默。

于 2013-06-11T08:38:35.160 回答