Principal stress space
Principal stress space에서는 응력 텐서의 전단 성분들이 zero 가 된다.
현재 응력텐서가 참조되는 (being referred to) 좌표계를 여러 Euler angle들을 시도해보며 shear component가 없어지는 각도를 찾아 볼 수도 있다.
하지만 위의 방법은, 몇번 시도해보면 알게 되겠지만, 쉽지 않다.
물론 해석적으로 응력텐서의 주값들을 구할 수도 있겠지만, 주로 ‘수치적’인 접근으로도 풀 수 있다.
Algorithm
응력 텐서를 3x3 matrix 형태로 생각한다면, 해당 행렬의 eigen values가 응력텐서의 principal value가 된다. 그리고 eigen vectors들이 principal space에서의 basis vectors가 된다.
LAPACK의 dsysev 함수를 활용하여 eigen vector와 eigen values들을 구한다.
dsyev 에서 찾아지는 eigenvector들로 이뤄지는 3x3matrix가 principal space의 basis vector들을 old axes에 참조한 값들이다.
따라서, 해당 3x3 matrix는 old axes를 principal space로 mapping 한다. 다만, 해당 3x3 matrix는 right-handedness 혹은 left-handedness 일 수 있다.
우리는 right-handedness를 지켜야 한다. 이는 간단히 determinant를 구해보면 알 수 있다. determinant가 +1 일때, righthanded-ness, -1일 때 left handed coordinate system을 이루게 된다.
이를 바탕으로 right-handed coordinate를 구성할 수 있게 끔 조정 하여 해당 matrix를 ‘transformation matrix’로 사용할 수 있다.
그리고, transformation matrix를 안다면, 손쉽게 Euler angle들로 변환가능하다.
위의 작업들을 Fortran을 사용한 프로그램으로 옮겨 보았다.
program ev
implicit none
integer lwmax
parameter(lwmax=1000)
dimension A(3,3),W(3),work(lwmax),stress(3,3),s_new(3,3),rot(3,3),
$ rotinv(3,3),aux33(3,3),rotaux(3,3),icols(6,2)
real*8 A, W, WORK, STRESS,s_new,rot,phi1,phi,phi2,rotinv,aux33,
$ dum,err,tol,rotaux,det
parameter(tol=1e-5)
integer i,j,k,l,lwork,info, ior,kerr,iopt,ipiv,iter,
$ ix,jx,icols
logical ibr
data icols /
$ 1,2,1,2,1,2,
$ 1,3,3,3,3,3/
c---------------------------------------------------------------------
c upper triangle matrix
open(1,file='stress.inp',status='unknown')
open(2,file='result.txt',status='unknown')
do i=1,3
read(1,*) stress(i,:)
enddo
close(1)
c---------------------------------------------------------------------
A(:,:)=0d0
A(:,:)=stress(:,:)*1d0
do 10 i=1,3
do 10 j=1,3
stress(j,i)=stress(i,j)
10 continue
c --------
lwork=-1
call dsyev('V','U',3,A,3,W,work,lwork,info)
lwork=min(lwmax,int(work(1)))
call dsyev('V','U',3,A,3,W,work,lwork,info)
c --------
IF( INFO.GT.0 ) THEN
WRITE(*,*)'The algorithm failed to compute eigenvalues.'
STOP -1
END IF
write(2,'(a)')'** Principal stress values'
write(2,'(3e11.3)')(w(i),i=1,3)
do 15 i=1,3
do 15 j=1,3
rot(i,j) = a(j,i)
15 continue
call keep_right_handedness(rot)
rotaux(:,:)=rot(:,:)
iter = 1
err=1.
c ----------------------------
! check if transformation matrix rotate the stress tensor correctly.
do 20 i=1,3
do 20 j=1,3
s_new(i,j)=0d0
do 20 k=1,3
do 20 l=1,3
s_new(i,j)=s_new(i,j)+ rot(i,k)*stress(k,l)*rot(j,l)
20 continue
write(2,'(a)')'** Stress tensor referred to principal space'
do i=1,3
write(2,'(3e11.3)')(s_new(i,j),j=1,3)
enddo
iopt=1
call euler(iopt, phi1,phi,phi2,rot)
write(2,'(a)')'** Euler angles that transform the old axes
$to principal space'
write(2,'(3a9)')'phi1','phi','phi2'
write(2,'(3(f7.2,2x))')phi1,phi,phi2
close(2)
write(*,'(a)')'** Completed - check result.txt'
end program ev
c----------------------------------------------------------------------
subroutine keep_right_handedness(a)
c If the determinant>0, the vectors form right-handedness.
dimension a(3,3)
real*8 a,det
if (dabs(det(a)-1d0).lt.1e-8) return
a(1,:)=-a(1,:)
if (dabs(det(a)-1d0).lt.1e-8) return
a(2,:)=-a(2,:)
if (dabs(det(a)-1d0).lt.1e-8) return
a(3,:)=-a(3,:)
if (dabs(det(a)-1d0).lt.1e-8) return
write(*,*)'could not achieve right-handedness'
stop -1
return
end subroutine keep_right_handedness
c----------------------------------------------------------------------
subroutine euler (iopt,ph,th,tm,a)
c
c CALCULATE THE EULER ANGLES ASSOCIATED WITH THE TRANSFORMATION
c MATRIX A(I,J) IF IOPT=1 AND VICEVERSA IF IOPT=2
c A(i,j) TRANSFORMS FROM SYSTEM sa TO SYSTEM ca.
c ph,th,om ARE THE EULER ANGLES (in degrees) OF ca REFERRED TO sa.
c *****************************************************************************
c tm:3 (phi2)
c th:2 (phi)
c ph:1 (phi1)
dimension a(3,3)
real*8 a,ph,th,tm
integer iopt
pi=4.*atan(1.d0)
if(iopt.eq.1) then
th=acos(a(3,3))
if(abs(a(3,3)).ge.0.9999) then
tm=0.
ph=atan2(a(1,2),a(1,1))
else
sth=sin(th)
tm=atan2(a(1,3)/sth,a(2,3)/sth)
ph=atan2(a(3,1)/sth,-a(3,2)/sth)
endif
th=th*180./pi
ph=ph*180./pi
tm=tm*180./pi
else if(iopt.eq.2) then
sph=sin(ph*pi/180.)
cph=cos(ph*pi/180.)
sth=sin(th*pi/180.)
cth=cos(th*pi/180.)
stm=sin(tm*pi/180.)
ctm=cos(tm*pi/180.)
a(1,1)=ctm*cph-sph*stm*cth !! c3*c1 - s1*s3*c2
a(2,1)=-stm*cph-sph*ctm*cth !! -s3*c1 - s1*c3*c2
a(3,1)=sph*sth !! s1*s2
a(1,2)=ctm*sph+cph*stm*cth !! c3*s1 + c1*s3*c2
a(2,2)=-sph*stm+cph*ctm*cth !! -s1*s3 + c1*c3*c2
a(3,2)=-sth*cph !! -s2*c1
a(1,3)=sth*stm !! s2*s3
a(2,3)=ctm*sth !! c3*s2
a(3,3)=cth !! c2
endif
return
end subroutine euler
c----------------------------------------------------------------------
real*8 function det(a)
dimension a(3,3)
real*8 a
det=a(1,1)*a(2,2)*a(3,3)
$ +a(1,2)*a(2,3)*a(3,1)
$ +a(1,3)*a(2,1)*a(3,2)
$ -a(1,3)*a(2,2)*a(3,1)
$ -a(2,3)*a(3,2)*a(1,1)
$ -a(1,2)*a(2,1)*a(3,3)
return
end function det
위 프로그램을 실행하기 위해서는
- 첫째, LAPACK이 설치되어 있어야 한다 - 설치방법
- 둘째, 위의 프로그램을 fortran compiler를 사용해 적절히 executable을 생성시켜야 한다.
예를 들어 위의 코드를 ex.f 로 저장했다면 아래와 같이 gfortran과 LAPACK을 활용해 compile할 수 있다.
$> gfortran ex.f -llapack -o ex
ex 파일을 실행하기 위해서는 특정 공간에서의 응력텐서를 주어야 한다. 해당 코드는 stress.inp 에서 응력 텐서를 읽어들인다.
stress.inp 파일은 아래와 같이 작성한다.
-30. 25. 11.
25. 1. -9.
11. -9. 17.
이 파일을 ex executable 파일과 같은 위치에 놓고
$> ./ex
로 실행을 하면
result.txt 라는 파일이 생성되며 다음과 같은 결과를 얻을 수 있다.
해당 파일은 아래와 같이 생성될 것이다.
** Principal stress values
-0.470E+02 0.139E+02 0.210E+02
** Stress tensor referred to principal space
-0.470E+02 -0.129E-13 -0.222E-14
-0.102E-13 0.139E+02 -0.266E-14
-0.444E-15 -0.266E-14 0.210E+02
** Euler angles that transform the old axes to principal space
phi1 phi phi2
-1.40 24.86 -30.59
여기서 -0.470E+02 는 \(-0.470\times10^2\)를 의미한다. 즉 E+02 부분은 \(10^{2}\) 형태의 지수 값이 곱해져 있음을 의미한다.
\(\phi_1, \Phi, \phi_2\) Euler angle들의 형태로 Old coordinate system을 변환하면 얻어진 주 응력값을 주는 principal stress space를 얻을 수 있다.
위의 example를 Excel spreadsheet로 직접 실습해보자.
위의 전과정을 성공적으로 마무리 했다면 … 축하드립니다!