betterr_inter_sample.zip
源代码:
Module global
Implicit None
Integer, Save :: elem(1000000, 8), pindex(1000000), pmatche(100000), ii, elnum, nnum, pnum, kk, iii, key, ninnitial, keya, vec(3, 8), count, courier, e(1000000)
!单元节点,插值点编号索引,插值点与单元对应关系
Real (Kind=8), Save :: node(1000000, 3), erange(1000000, 6), point(100000, 3), locc(100000, 3), innitial(100, 3), toler, error(3), judge(2, 3), l(3), s(8), ds(8, 3), f(3), jacob(3, 3), dl(3), lamita, fsave(3, 2), lsave(3)
!节点坐标,单元的坐标范围,插值点坐标,L代表本地坐标,S(8)代表8个型函数,DS(8,3)代表八个型函数在不同自变量方向上的偏导数
End Module global
!*********************************主程序***********************************************
Program main
Use global
Implicit None
Call intro
Call input
Do ii = 1, pnum
iii = pindex(ii)
Do kk = 1, elnum
Call test
If (key==1) Then
Exit
End If
End Do
End Do
Pause
End Program main
!******************************输入数据的子程序************************************************************
Subroutine input
Use global
Integer i, k, j, a
Write (*, *) 'READING FILES'
Open (20, File='MESH.DAT')
Open (30, File='POINT.DAT')
Open (50, File='LOC.DAT')
Open (60, File='UFOUND.DAT')
Open (70, File='DEBUGINFOR.TXT')
Open (80, File='LOCCOD.TXT')
Open (170, File='NOTE.TXT')
Read (20, *) elnum, nnum, ninnitial
Do i = 1, nnum
Read (20, *) a, node(a, :)
End Do
Do i = 1, elnum
Read (20, *) a, elem(a, :)
e(i) = a
End Do
Do i = 1, ninnitial
Read (20, *) a, innitial(i, :)
End Do
Read (30, *) pnum, toler, error
Do i = 1, pnum
Read (30, *) pindex(i), (point(pindex(i),k), k=1, 3)
End Do
Close (20)
Close (30) !开始做erange数组
Write (50, *) pnum
Do i = 1, elnum
erange(e(i), 1) = minval(node(elem(e(i),:),1)) !要了解min()函数与minval()函数的关系.min函数括号里面跟的是变量,minval跟的是数组。同时,隐循环不能出现在表达式中,只能出现在IO列表中。
erange(e(i), 2) = maxval(node(elem(e(i),:),1))
erange(e(i), 3) = minval(node(elem(e(i),:),2))
erange(e(i), 4) = maxval(node(elem(e(i),:),2))
erange(e(i), 5) = minval(node(elem(e(i),:),3))
erange(e(i), 6) = maxval(node(elem(e(i),:),3))
End Do
Write (*, *) 'FINISH READING'
End Subroutine input
!*********************寻找本地坐标子程序********************************
Subroutine test
Use global
key = 0
If (point(iii,1)>=erange(e(kk),1)-0.1 .And. point(iii,1)<=erange(e(kk),2)+0.1 .And. point(iii,2)>=erange(e(kk),3)-0.1 .And. point(iii,2)<=erange(e(kk),4)+0.1 .And. point(iii,3)>=erange(e(kk),5)-0.1 .And. point(iii,3)<=erange(e(kk),6)+0.1) Then
Call issac_newton
If (key==1) Then
Return
End If
If (e(kk)==elnum) Then
Write (*, *) 'POINT', iii, 'NOT FOUND'
Write (60, *) 'POINT', iii, 'NOT FOUND'
End If
End If
End Subroutine test
!*********************牛顿爵士的迭代法********************************
Subroutine issac_newton
Include 'link_f90_static.h'
Use wrrrn_int
Use global
Implicit None
Integer i, j, k
Real :: monitor1, monitor2
key = 0
count = 1
j = 0
l = innitial(count, :)
!JUDGE=20000.0
Do While (.True.)
j = j + 1
courier = 0
jacob = 0.0
lamita = 1
Call fem !做雅可比矩阵
fsave(:, 1) = f
lsave = l
monitor1 = abs(fsave(1,1)) + abs(fsave(2,1)) + abs(fsave(3,1))
Do While (.True.) !这个循环必须新值比旧值小才能跳出,符合牛顿下山的精神
Call fem
f = f
fsave(:, 1) = f
monitor1 = abs(fsave(1,1)) + abs(fsave(2,1)) + abs(fsave(3,1)) !MONITOR1是无穷向量
!CALL WRRRN('jacob',jacob)
Call solve(jacob, -1*f, dl, courier)
!CALL WRRRN('JACOB',JACOB)
l = l + dl
Call fem
fsave(:, 2) = f
monitor2 = abs(fsave(1,2)) + abs(fsave(2,2)) + abs(fsave(3,2))
If (monitor2<=0.1) Then !如果新F的无穷向量小的话,就直接跳出循环。
Exit
End If
If (monitor1>=monitor2) Then
Exit
End If
!LAMITA=LAMITA/2
!IF(LAMITA<=0.000001)THEN
! WRITE(170,*)'初值选在了坑里面'
!COUNT=COUNT+1
!L=INNITIAL(COUNT,:)
!J=0
!KEYA=0
!JUDGE=20000.0
!EXIT
!ENDIF
!L=LSAVE
End Do
!IF(J==0)THEN
! CYCLE
! ENDIF
!!!WRITE(*,'(a12,I8,a12,I8,a12,I8)')'插值点为',II,'单元为',e(KK),'初值更换次数为',COUNT
Write (170, *)
Write (170, *)
Write (170, '(a8,I8,A10,I8,A18,I8,A14,I8)') '插值点为', ii, '单元为', e(kk), '初值更换次数为', count, '迭代步数为', j
!!!WRITE(*,'(a12,I8)')'迭代步数为',J
!!!WRITE(*,'(a10,3F20.8)')'迭代增量为',DL
Write (170, '(a10,3F20.8)') '目标量为', l
Write (170, '(a10,3F20.8)') '迭代增量为', dl
!!!WRITE(*,*)
!IF((-1)**J==-1)THEN
! JUDGE(1,:)=DL
!ELSE IF((-1)**J==1)THEN
! JUDGE(2,:)=DL
!ENDIF
!
!
!IF ( ABS((JUDGE(1,1)+JUDGE(2,1)))<=0.000001 .AND. ABS((JUDGE(1,2)+JUDGE(2,2))<=0.000001) .AND. ABS((JUDGE(1,3)+JUDGE(2,3))<=0.000001))THEN
!KEYA=1
!ENDIF
If (courier==1 .Or. abs(dl(1))>=10000 .Or. abs(dl(2))>=10000 .Or. abs(dl(3))>=10000 .Or. j>=1000 .Or. keya==1) Then
!给出了判断不收敛的4个条件:1.迭代方程无唯一解 2.解的数值过大 3.迭代次数过多 4.发生数值震荡。 这4个条件是在调程序时候遇到的问题的解决办法。
If (count==ninnitial) Then
Write (170, *) '穷尽初值,未能收敛,请增加初值。'
Write (170, *) '****************************************************************'
Return
End If
!!!WRITE(*,*)'迭代不收敛,更换初值再次迭代'
Write (170, *) '迭代不收敛,更换初值再次迭代'
Write (170, *) '****************************************************************'
count = count + 1
l = innitial(count, :)
j = 0
keya = 0
!JUDGE=20000.0
Cycle
End If
If (monitor2<=0.01) Then
!!!write(*,'(a12,I8,A12,3F20.8)')'收敛迭代次数',j,'本地坐标为',l
Write (170, '(a12,I8,A12,3F20.8)') '收敛迭代次数', j, '本地坐标为', l
Write (170, *) '****************************************************'
Write (170, *)
Write (170, *)
Write (70, '(4I8,3F20.8)') iii, e(kk), j, l
If (abs(l(1))<=1.00+error(1) .And. abs(l(2))<=1.00+error(2) .And. abs(l(3))<=1.00+error(3)) Then
locc(iii, :) = l
Write (80, '(2i8,3f20.8)') ii, e(kk), l
Write (*, *) '第', ii, '个点的本地坐标已经找到了'
key = 1
End If
Return
End If
End Do
End Subroutine issac_newton
!*********************高斯消元法********************************
Subroutine solve(left, right, x, courier)
Use wrrrn_int
Integer i, j, courier
Real (Kind=8) :: left(3, 3), right(3), a(3, 4), b(3), c, d(4), x(3)
a(1, 1:3) = left(1, :)
a(2, 1:3) = left(2, :)
a(3, 1:3) = left(3, :)
a(:, 4) = right
c = maxval(abs(a(:,1)))
Do i = 1, 3
If (abs(a(i,1))==c) Then
Goto 100
End If
End Do
100 Continue
d = a(1, :)
a(1, :) = a(i, :)
a(i, :) = d
!CALL WRRRN('A',A)
Do i = 2, 3
c = a(i, 1)
Do j = 1, 4
a(i, j) = a(1, j)*c - a(i, j)*a(1, 1)
End Do
End Do
!CALL WRRRN('A',A)
c = maxval(abs(a(2:3,2)))
Do i = 2, 3
If (abs(a(i,2))==c) Then
Goto 300
End If
End Do
300 Continue
d = a(2, :)
a(2, :) = a(i, :)
a(i, :) = d
c = a(3, 2)
Do j = 2, 4
a(3, j) = a(2, j)*c - a(3, j)*a(2, 2)
End Do
!CALL WRRRN('A',A)
If (a(1,1)*a(2,2)*a(3,3)==0) Then
courier = 1
Return
End If
x(3) = a(3, 4)/a(3, 3)
x(2) = (a(2,4)-a(2,3)*x(3))/a(2, 2)
x(1) = (a(1,4)-a(1,3)*x(3)-a(1,2)*x(2))/a(1, 1)
End Subroutine solve
!*********************高斯消元法********************************
Subroutine fem
Use global
Integer i, j, k
f = 0.0
Do i = 1, 8
vec(1, i) = (-1)**floor(1.5+0.45*i) !系数
vec(2, i) = (-1)**floor(1.05+0.45*i)
vec(3, i) = (-1)**floor(1.05+0.20*i)
s(i) = 0.125*(1+vec(1,i)*l(1))*(1+vec(2,i)*l(2))*(1+vec(3,i)*l(3)) !型函数N(i)
ds(i, 1) = 0.125*vec(1, i)*(1+vec(2,i)*l(2))*(1+vec(3,i)*l(3)) !型函数n(i)的偏导
ds(i, 2) = 0.125*vec(2, i)*(1+vec(1,i)*l(1))*(1+vec(3,i)*l(3))
ds(i, 3) = 0.125*vec(3, i)*(1+vec(1,i)*l(1))*(1+vec(2,i)*l(2))
f(1) = s(i)*node(elem(e(kk),i), 1) + f(1)
f(2) = s(i)*node(elem(e(kk),i), 2) + f(2)
f(3) = s(i)*node(elem(e(kk),i), 3) + f(3)
If (i==8) Then
f(1) = f(1) - point(iii, 1)
f(2) = f(2) - point(iii, 2)
f(3) = f(3) - point(iii, 3)
End If
jacob(1, 1) = ds(i, 1)*node(elem(e(kk),i), 1) + jacob(1, 1) !雅可比矩阵一定要仔细想想,做对
jacob(1, 2) = ds(i, 2)*node(elem(e(kk),i), 1) + jacob(1, 2)
jacob(1, 3) = ds(i, 3)*node(elem(e(kk),i), 1) + jacob(1, 3)
jacob(2, 1) = ds(i, 1)*node(elem(e(kk),i), 2) + jacob(2, 1)
jacob(2, 2) = ds(i, 2)*node(elem(e(kk),i), 2) + jacob(2, 2)
jacob(2, 3) = ds(i, 3)*node(elem(e(kk),i), 2) + jacob(2, 3)
jacob(3, 1) = ds(i, 1)*node(elem(e(kk),i), 3) + jacob(3, 1)
jacob(3, 2) = ds(i, 2)*node(elem(e(kk),i), 3) + jacob(3, 2)
jacob(3, 3) = ds(i, 3)*node(elem(e(kk),i), 3) + jacob(3, 3)
End Do
End Subroutine fem
Subroutine intro
Write (*, *) '*************************************************************'
Write (*, *) '* by:石中岳 *'
Write (*, *) '* tips:仅供学习使用,提供源代码 *'
Write (*, *) '* 欢迎讨论,联系方式qq641240961 *'
Write (*, *) '*************************************************************'
End Subroutine intro



