From 59890750099ad650e0f7e310cea7bd74126c4fc6 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 10 Apr 2019 13:23:57 +0200 Subject: [PATCH 01/61] working for grid_mech_spectral_basic --- src/CPFEM2.f90 | 2 +- src/grid_mech_spectral_basic.f90 | 70 ++++++++++++++------------------ 2 files changed, 32 insertions(+), 40 deletions(-) diff --git a/src/CPFEM2.f90 b/src/CPFEM2.f90 index 13d7f06c4..aba6006b2 100644 --- a/src/CPFEM2.f90 +++ b/src/CPFEM2.f90 @@ -257,7 +257,7 @@ subroutine CPFEM_age() write(6,'(a)') '<< CPFEM >> writing restart variables of last converged step to hdf5 file' write(rankStr,'(a1,i0)')'_',worldrank - fileHandle = HDF5_openFile(trim(getSolverJobName())//trim(rankStr)//'.hdf5','w') + fileHandle = HDF5_openFile(trim(getSolverJobName())//trim(rankStr)//'.hdf5','a') call HDF5_write(fileHandle,material_phase, 'recordedPhase') call HDF5_write(fileHandle,crystallite_F0, 'convergedF') diff --git a/src/grid_mech_spectral_basic.f90 b/src/grid_mech_spectral_basic.f90 index 99839e50f..2ed8bc683 100644 --- a/src/grid_mech_spectral_basic.f90 +++ b/src/grid_mech_spectral_basic.f90 @@ -7,6 +7,8 @@ module grid_mech_spectral_basic #include #include + use DAMASK_interface + use HDF5_utilities use PETScdmda use PETScsnes use prec, only: & @@ -114,8 +116,9 @@ subroutine grid_mech_spectral_basic_init PetscErrorCode :: ierr PetscScalar, pointer, dimension(:,:,:,:) :: & - F ! pointer to solution data + F ! pointer to solution data PetscInt, dimension(worldsize) :: localK + integer(HID_T) :: fileHandle integer :: fileUnit character(len=1024) :: rankStr @@ -174,19 +177,13 @@ subroutine grid_mech_spectral_basic_init restart: if (restartInc > 0) then write(6,'(/,a,'//IO_intOut(restartInc)//',a)') ' reading values of increment ', restartInc, ' from file' - fileUnit = IO_open_jobFile_binary('F_aim') - read(fileUnit) F_aim; close(fileUnit) - fileUnit = IO_open_jobFile_binary('F_aim_lastInc') - read(fileUnit) F_aim_lastInc; close(fileUnit) - fileUnit = IO_open_jobFile_binary('F_aimDot') - read(fileUnit) F_aimDot; close(fileUnit) - write(rankStr,'(a1,i0)')'_',worldrank - - fileUnit = IO_open_jobFile_binary('F'//trim(rankStr)) - read(fileUnit) F; close (fileUnit) - fileUnit = IO_open_jobFile_binary('F_lastInc'//trim(rankStr)) - read(fileUnit) F_lastInc; close (fileUnit) + fileHandle = HDF5_openFile(trim(getSolverJobName())//trim(rankStr)//'.hdf5') + call HDF5_read(fileHandle,F_aim, 'F_aim') + call HDF5_read(fileHandle,F_aim_lastInc,'F_aim_lastInc') + call HDF5_read(fileHandle,F_aimDot, 'F_aimDot') + call HDF5_read(fileHandle,F, 'F') + call HDF5_read(fileHandle,F_lastInc, 'F_lastInc') elseif (restartInc == 0) then restart F_lastInc = spread(spread(spread(math_I3,3,grid(1)),4,grid(2)),5,grid3) ! initialize to identity @@ -203,10 +200,10 @@ subroutine grid_mech_spectral_basic_init restartRead: if (restartInc > 0) then write(6,'(/,a,'//IO_intOut(restartInc)//',a)') 'reading more values of increment ', restartInc, ' from file' - fileUnit = IO_open_jobFile_binary('C_volAvg') - read(fileUnit) C_volAvg; close(fileUnit) - fileUnit = IO_open_jobFile_binary('C_volAvgLastInv') - read(fileUnit) C_volAvgLastInc; close(fileUnit) + call HDF5_read(fileHandle,C_volAvg, 'C_volAvg') + call HDF5_read(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') + call HDF5_closeFile(fileHandle) + fileUnit = IO_open_jobFile_binary('C_ref') read(fileUnit) C_minMaxAvg; close(fileUnit) endif restartRead @@ -321,7 +318,7 @@ subroutine grid_mech_spectral_basic_forward(guess,timeinc,timeinc_old,loadCaseTi PetscErrorCode :: ierr PetscScalar, dimension(:,:,:,:), pointer :: F - integer :: fileUnit + integer(HID_T) :: fileHandle character(len=32) :: rankStr call DMDAVecGetArrayF90(da,solution_vec,F,ierr); CHKERRQ(ierr) @@ -331,29 +328,24 @@ subroutine grid_mech_spectral_basic_forward(guess,timeinc,timeinc_old,loadCaseTi C_minMaxAvg = C_minMaxAvgLastInc ! QUESTION: where is this required? else !-------------------------------------------------------------------------------------------------- - ! restart information for spectral solver + ! restart information for spectral solver if (restartWrite) then ! QUESTION: where is this logical properly set? - write(6,'(/,a)') ' writing converged results for restart' - flush(6) - - if (worldrank == 0) then - fileUnit = IO_open_jobFile_binary('C_volAvg','w') - write(fileUnit) C_volAvg; close(fileUnit) - fileUnit = IO_open_jobFile_binary('C_volAvgLastInv','w') - write(fileUnit) C_volAvgLastInc; close(fileUnit) - fileUnit = IO_open_jobFile_binary('F_aim','w') - write(fileUnit) F_aim; close(fileUnit) - fileUnit = IO_open_jobFile_binary('F_aim_lastInc','w') - write(fileUnit) F_aim_lastInc; close(fileUnit) - fileUnit = IO_open_jobFile_binary('F_aimDot','w') - write(fileUnit) F_aimDot; close(fileUnit) - endif - + write(6,'(/,a)') ' writing converged results for restart';flush(6) + write(rankStr,'(a1,i0)')'_',worldrank - fileUnit = IO_open_jobFile_binary('F'//trim(rankStr),'w') - write(fileUnit) F; close (fileUnit) - fileUnit = IO_open_jobFile_binary('F_lastInc'//trim(rankStr),'w') - write(fileUnit) F_lastInc; close (fileUnit) + fileHandle = HDF5_openFile(trim(getSolverJobName())//trim(rankStr)//'.hdf5','w') + + print*, trim(getSolverJobName())//trim(rankStr)//'.hdf5';flush(6) + call HDF5_write(fileHandle,F_aim, 'F_aim') + call HDF5_write(fileHandle,F_aim_lastInc,'F_aim_lastInc') + call HDF5_write(fileHandle,F_aimDot, 'F_aimDot') + call HDF5_write(fileHandle,F, 'F') + call HDF5_write(fileHandle,F_lastInc, 'F_lastInc') + + call HDF5_write(fileHandle,C_volAvg, 'C_volAvg') + call HDF5_write(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') + call HDF5_write(fileHandle,C_minMaxAvg, 'C_minMaxAvg') + call HDF5_closeFile(fileHandle) endif call CPFEM_age ! age state and kinematics From 1852f580adf220b3bead9c2b13cd1e4f2ade4dce Mon Sep 17 00:00:00 2001 From: Vitesh Shah Date: Wed, 10 Apr 2019 18:19:10 +0200 Subject: [PATCH 02/61] grid_mech_FEM works --- src/grid_mech_FEM.f90 | 70 ++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 41 deletions(-) diff --git a/src/grid_mech_FEM.f90 b/src/grid_mech_FEM.f90 index e31d93637..adcbb626b 100644 --- a/src/grid_mech_FEM.f90 +++ b/src/grid_mech_FEM.f90 @@ -7,6 +7,8 @@ module grid_mech_FEM #include #include + use DAMASK_interface + use HDF5_utilities use PETScdmda use PETScsnes use prec, only: & @@ -115,6 +117,7 @@ subroutine grid_mech_FEM_init PetscErrorCode :: ierr integer(pInt) :: rank integer :: fileUnit + integer(HID_T) :: fileHandle character(len=1024) :: rankStr real(pReal), dimension(3,3,3,3) :: devNull PetscScalar, pointer, dimension(:,:,:,:) :: & @@ -203,24 +206,16 @@ subroutine grid_mech_FEM_init restart: if (restartInc > 0) then write(6,'(/,a,'//IO_intOut(restartInc)//',a)') 'reading values of increment ', restartInc, ' from file' - fileUnit = IO_open_jobFile_binary('F_aim') - read(fileUnit) F_aim; close(fileUnit) - fileUnit = IO_open_jobFile_binary('F_aim_lastInc') - read(fileUnit) F_aim_lastInc; close(fileUnit) - fileUnit = IO_open_jobFile_binary('F_aimDot') - read(fileUnit) F_aimDot; close(fileUnit) - write(rankStr,'(a1,i0)')'_',worldrank - - fileUnit = IO_open_jobFile_binary('F'//trim(rankStr)) - read(fileUnit) F; close (fileUnit) - fileUnit = IO_open_jobFile_binary('F_lastInc'//trim(rankStr)) - read(fileUnit) F_lastInc; close (fileUnit) - fileUnit = IO_open_jobFile_binary('u'//trim(rankStr)) - read(fileUnit) u_current; close (fileUnit) - fileUnit = IO_open_jobFile_binary('u_lastInc'//trim(rankStr)) - read(fileUnit) u_lastInc; close (fileUnit) - + fileHandle = HDF5_openFile(trim(getSolverJobName())//trim(rankStr)//'.hdf5') + call HDF5_read(fileHandle,F_aim, 'F_aim') + call HDF5_read(fileHandle,F_aim_lastInc,'F_aim_lastInc') + call HDF5_read(fileHandle,F_aimDot, 'F_aimDot') + call HDF5_read(fileHandle,F, 'F') + call HDF5_read(fileHandle,F_lastInc, 'F_lastInc') + call HDF5_read(fileHandle,u_current, 'u') + call HDF5_read(fileHandle,u_lastInc, 'u_lastInc') + elseif (restartInc == 0) then restart F_lastInc = spread(spread(spread(math_I3,3,grid(1)),4,grid(2)),5,grid3) ! initialize to identity F = spread(spread(spread(math_I3,3,grid(1)),4,grid(2)),5,grid3) @@ -238,10 +233,9 @@ subroutine grid_mech_FEM_init restartRead: if (restartInc > 0_pInt) then write(6,'(/,a,'//IO_intOut(restartInc)//',a)') 'reading more values of increment ', restartInc, ' from file' - fileUnit = IO_open_jobFile_binary('C_volAvg') - read(fileUnit) C_volAvg; close(fileUnit) - fileUnit = IO_open_jobFile_binary('C_volAvgLastInv') - read(fileUnit) C_volAvgLastInc; close(fileUnit) + call HDF5_read(fileHandle,C_volAvg, 'C_volAvg') + call HDF5_read(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') + call HDF5_closeFile(fileHandle) endif restartRead end subroutine grid_mech_FEM_init @@ -348,6 +342,7 @@ subroutine grid_mech_FEM_forward(guess,timeinc,timeinc_old,loadCaseTime,deformat real(pReal), dimension(3,3), intent(in) :: & rotation_BC PetscErrorCode :: ierr + integer(HID_T) :: fileHandle integer :: fileUnit character(len=32) :: rankStr PetscScalar, pointer, dimension(:,:,:,:) :: & @@ -364,30 +359,23 @@ subroutine grid_mech_FEM_forward(guess,timeinc,timeinc_old,loadCaseTime,deformat if (restartWrite) then ! QUESTION: where is this logical properly set? write(6,'(/,a)') ' writing converged results for restart' flush(6) + + write(rankStr,'(a1,i0)')'_',worldrank + fileHandle = HDF5_openFile(trim(getSolverJobName())//trim(rankStr)//'.hdf5','w') if (worldrank == 0) then - fileUnit = IO_open_jobFile_binary('C_volAvg','w') - write(fileUnit) C_volAvg; close(fileUnit) - fileUnit = IO_open_jobFile_binary('C_volAvgLastInv','w') - write(fileUnit) C_volAvgLastInc; close(fileUnit) - fileUnit = IO_open_jobFile_binary('F_aim','w') - write(fileUnit) F_aim; close(fileUnit) - fileUnit = IO_open_jobFile_binary('F_aim_lastInc','w') - write(fileUnit) F_aim_lastInc; close(fileUnit) - fileUnit = IO_open_jobFile_binary('F_aimDot','w') - write(fileUnit) F_aimDot; close(fileUnit) + call HDF5_write(fileHandle,C_volAvg, 'C_volAvg') + call HDF5_write(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') + call HDF5_write(fileHandle,F_aim, 'F_aim') + call HDF5_write(fileHandle,F_aim_lastInc, 'F_aim_lastInc') + call HDF5_write(fileHandle,F_aimDot, 'F_aimDot') + call HDF5_write(fileHandle,F, 'F') + call HDF5_write(fileHandle,F_lastInc, 'F_lastInc') + call HDF5_write(fileHandle,u_current, 'u') + call HDF5_write(fileHandle,u_lastInc, 'u_lastInc') + call HDF5_closeFile(fileHandle) endif - write(rankStr,'(a1,i0)')'_',worldrank - fileUnit = IO_open_jobFile_binary('F'//trim(rankStr),'w') - write(fileUnit) F; close (fileUnit) - fileUnit = IO_open_jobFile_binary('F_lastInc'//trim(rankStr),'w') - write(fileUnit) F_lastInc; close (fileUnit) - fileUnit = IO_open_jobFile_binary('u'//trim(rankStr),'w') - write(fileUnit) u_current; close (fileUnit) - fileUnit = IO_open_jobFile_binary('u_lastInc'//trim(rankStr),'w') - write(fileUnit) u_lastInc; close (fileUnit) - endif call CPFEM_age() ! age state and kinematics call utilities_updateIPcoords(F) From 8609c959dffae0aaad950ce01db697c472fdefc7 Mon Sep 17 00:00:00 2001 From: Vitesh Shah Date: Thu, 11 Apr 2019 15:51:34 +0200 Subject: [PATCH 03/61] grid_mech_polarisation works --- src/grid_mech_spectral_polarisation.f90 | 121 +++++++++++++++--------- 1 file changed, 77 insertions(+), 44 deletions(-) diff --git a/src/grid_mech_spectral_polarisation.f90 b/src/grid_mech_spectral_polarisation.f90 index aff4913b1..e87b8ec46 100644 --- a/src/grid_mech_spectral_polarisation.f90 +++ b/src/grid_mech_spectral_polarisation.f90 @@ -7,6 +7,8 @@ module grid_mech_spectral_polarisation #include #include + use DAMASK_interface + use HDF5_utilities use PETScdmda use PETScsnes use prec, only: & @@ -124,6 +126,7 @@ subroutine grid_mech_spectral_polarisation_init F, & ! specific (sub)pointer F_tau ! specific (sub)pointer PetscInt, dimension(worldsize) :: localK + integer(HID_T) :: fileHandle integer :: fileUnit character(len=1024) :: rankStr @@ -183,23 +186,34 @@ subroutine grid_mech_spectral_polarisation_init restart: if (restartInc > 0) then write(6,'(/,a,'//IO_intOut(restartInc)//',a)') ' reading values of increment ', restartInc, ' from file' - fileUnit = IO_open_jobFile_binary('F_aim') - read(fileUnit) F_aim; close(fileUnit) - fileUnit = IO_open_jobFile_binary('F_aim_lastInc') - read(fileUnit) F_aim_lastInc; close(fileUnit) - fileUnit = IO_open_jobFile_binary('F_aimDot') - read(fileUnit) F_aimDot; close(fileUnit) - write(rankStr,'(a1,i0)')'_',worldrank + fileHandle = HDF5_openFile(trim(getSolverJobName())//trim(rankStr)//'.hdf5') - fileUnit = IO_open_jobFile_binary('F'//trim(rankStr)) - read(fileUnit) F; close (fileUnit) - fileUnit = IO_open_jobFile_binary('F_lastInc'//trim(rankStr)) - read(fileUnit) F_lastInc; close (fileUnit) - fileUnit = IO_open_jobFile_binary('F_tau'//trim(rankStr)) - read(fileUnit) F_tau; close (fileUnit) - fileUnit = IO_open_jobFile_binary('F_tau_lastInc'//trim(rankStr)) - read(fileUnit) F_tau_lastInc; close (fileUnit) + call HDF5_read(fileHandle,F_aim, 'F_aim') + call HDF5_read(fileHandle,F_aim_lastInc,'F_aim_lastInc') + call HDF5_read(fileHandle,F_aimDot, 'F_aimDot') + call HDF5_read(fileHandle,F, 'F') + call HDF5_read(fileHandle,F_lastInc, 'F_lastInc') + call HDF5_read(fileHandle,F_tau, 'F_tau') + call HDF5_read(fileHandle,F_tau_lastInc, 'F_tau_lastInc') + + ! fileUnit = IO_open_jobFile_binary('F_aim') + ! read(fileUnit) F_aim; close(fileUnit) + ! fileUnit = IO_open_jobFile_binary('F_aim_lastInc') + ! read(fileUnit) F_aim_lastInc; close(fileUnit) + ! fileUnit = IO_open_jobFile_binary('F_aimDot') + ! read(fileUnit) F_aimDot; close(fileUnit) + + ! write(rankStr,'(a1,i0)')'_',worldrank + + ! fileUnit = IO_open_jobFile_binary('F'//trim(rankStr)) + ! read(fileUnit) F; close (fileUnit) + ! fileUnit = IO_open_jobFile_binary('F_lastInc'//trim(rankStr)) + ! read(fileUnit) F_lastInc; close (fileUnit) + ! fileUnit = IO_open_jobFile_binary('F_tau'//trim(rankStr)) + ! read(fileUnit) F_tau; close (fileUnit) + ! fileUnit = IO_open_jobFile_binary('F_tau_lastInc'//trim(rankStr)) + ! read(fileUnit) F_tau_lastInc; close (fileUnit) elseif (restartInc == 0) then restart F_lastInc = spread(spread(spread(math_I3,3,grid(1)),4,grid(2)),5,grid3) ! initialize to identity @@ -218,12 +232,16 @@ subroutine grid_mech_spectral_polarisation_init restartRead: if (restartInc > 0) then write(6,'(/,a,'//IO_intOut(restartInc)//',a)') ' reading more values of increment ', restartInc, ' from file' - fileUnit = IO_open_jobFile_binary('C_volAvg') - read(fileUnit) C_volAvg; close(fileUnit) - fileUnit = IO_open_jobFile_binary('C_volAvgLastInv') - read(fileUnit) C_volAvgLastInc; close(fileUnit) - fileUnit = IO_open_jobFile_binary('C_ref') - read(fileUnit) C_minMaxAvg; close(fileUnit) + call HDF5_read(fileHandle,C_volAvg, 'C_volAvg') + call HDF5_read(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') + call HDF5_read(fileHandle,C_minMaxAvg,'C_ref') + call HDF5_closeFile(fileHandle) + ! fileUnit = IO_open_jobFile_binary('C_volAvg') + ! read(fileUnit) C_volAvg; close(fileUnit) + ! fileUnit = IO_open_jobFile_binary('C_volAvgLastInv') + ! read(fileUnit) C_volAvgLastInc; close(fileUnit) + ! fileUnit = IO_open_jobFile_binary('C_ref') + ! read(fileUnit) C_minMaxAvg; close(fileUnit) endif restartRead call Utilities_updateGamma(C_minMaxAvg,.true.) @@ -348,6 +366,7 @@ subroutine grid_mech_spectral_polarisation_forward(guess,timeinc,timeinc_old,loa real(pReal), dimension(3,3) :: F_lambda33 integer :: fileUnit + integer(HID_T) :: fileHandle character(len=32) :: rankStr call DMDAVecGetArrayF90(da,solution_vec,FandF_tau,ierr); CHKERRQ(ierr) @@ -361,31 +380,45 @@ subroutine grid_mech_spectral_polarisation_forward(guess,timeinc,timeinc_old,loa !-------------------------------------------------------------------------------------------------- ! restart information for spectral solver if (restartWrite) then ! QUESTION: where is this logical properly set? - write(6,'(/,a)') ' writing converged results for restart' - flush(6) - - if (worldrank == 0) then - fileUnit = IO_open_jobFile_binary('C_volAvg','w') - write(fileUnit) C_volAvg; close(fileUnit) - fileUnit = IO_open_jobFile_binary('C_volAvgLastInv','w') - write(fileUnit) C_volAvgLastInc; close(fileUnit) - fileUnit = IO_open_jobFile_binary('F_aim','w') - write(fileUnit) F_aim; close(fileUnit) - fileUnit = IO_open_jobFile_binary('F_aim_lastInc','w') - write(fileUnit) F_aim_lastInc; close(fileUnit) - fileUnit = IO_open_jobFile_binary('F_aimDot','w') - write(fileUnit) F_aimDot; close(fileUnit) - endif + write(6,'(/,a)') ' writing converged results for restart';flush(6) write(rankStr,'(a1,i0)')'_',worldrank - fileUnit = IO_open_jobFile_binary('F'//trim(rankStr),'w') - write(fileUnit) F; close (fileUnit) - fileUnit = IO_open_jobFile_binary('F_lastInc'//trim(rankStr),'w') - write(fileUnit) F_lastInc; close (fileUnit) - fileUnit = IO_open_jobFile_binary('F_tau'//trim(rankStr),'w') - write(fileUnit) F_tau; close (fileUnit) - fileUnit = IO_open_jobFile_binary('F_tau_lastInc'//trim(rankStr),'w') - write(fileUnit) F_tau_lastInc; close (fileUnit) + fileHandle = HDF5_openFile(trim(getSolverJobName())//trim(rankStr)//'.hdf5','w') + + if (worldrank == 0) then + call HDF5_write(fileHandle,C_volAvg, 'C_volAvg') + call HDF5_write(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') + call HDF5_write(fileHandle,F_aim, 'F_aim') + call HDF5_write(fileHandle,F_aimDot, 'F_aimDot') + call HDF5_write(fileHandle,F_lastInc, 'F_lastInc') + ! fileUnit = IO_open_jobFile_binary('C_volAvg','w') + ! write(fileUnit) C_volAvg; close(fileUnit) + ! fileUnit = IO_open_jobFile_binary('C_volAvgLastInv','w') + ! write(fileUnit) C_volAvgLastInc; close(fileUnit) + ! fileUnit = IO_open_jobFile_binary('F_aim','w') + ! write(fileUnit) F_aim; close(fileUnit) + ! fileUnit = IO_open_jobFile_binary('F_aim_lastInc','w') + ! write(fileUnit) F_aim_lastInc; close(fileUnit) + ! fileUnit = IO_open_jobFile_binary('F_aimDot','w') + call HDF5_closeFile(fileHandle) + !write(fileUnit) F_aimDot; close(fileUnit) + endif + + !write(rankStr,'(a1,i0)')'_',worldrank + call HDF5_write(fileHandle,F, 'F') + call HDF5_write(fileHandle,F_lastInc, 'F_lastInc') + call HDF5_write(fileHandle,F_tau, 'F_tau') + call HDF5_write(fileHandle,F_tau_lastInc, 'F_tau_lastInc') + call HDF5_closeFile(fileHandle) + +! fileUnit = IO_open_jobFile_binary('F'//trim(rankStr),'w') +! write(fileUnit) F; close (fileUnit) +! fileUnit = IO_open_jobFile_binary('F_lastInc'//trim(rankStr),'w') +! write(fileUnit) F_lastInc; close (fileUnit) +! fileUnit = IO_open_jobFile_binary('F_tau'//trim(rankStr),'w') +! write(fileUnit) F_tau; close (fileUnit) +! fileUnit = IO_open_jobFile_binary('F_tau_lastInc'//trim(rankStr),'w') +! write(fileUnit) F_tau_lastInc; close (fileUnit) endif call CPFEM_age ! age state and kinematics From a5b3fa565f1299add358bddcae65e7d70203f84c Mon Sep 17 00:00:00 2001 From: Vitesh Shah Date: Thu, 11 Apr 2019 18:36:28 +0200 Subject: [PATCH 04/61] Some incorrect variable names fixed --- src/grid_mech_spectral_polarisation.f90 | 68 ++++++++++++------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/src/grid_mech_spectral_polarisation.f90 b/src/grid_mech_spectral_polarisation.f90 index e87b8ec46..1f64be0a0 100644 --- a/src/grid_mech_spectral_polarisation.f90 +++ b/src/grid_mech_spectral_polarisation.f90 @@ -232,16 +232,16 @@ subroutine grid_mech_spectral_polarisation_init restartRead: if (restartInc > 0) then write(6,'(/,a,'//IO_intOut(restartInc)//',a)') ' reading more values of increment ', restartInc, ' from file' - call HDF5_read(fileHandle,C_volAvg, 'C_volAvg') - call HDF5_read(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') - call HDF5_read(fileHandle,C_minMaxAvg,'C_ref') - call HDF5_closeFile(fileHandle) - ! fileUnit = IO_open_jobFile_binary('C_volAvg') - ! read(fileUnit) C_volAvg; close(fileUnit) - ! fileUnit = IO_open_jobFile_binary('C_volAvgLastInv') - ! read(fileUnit) C_volAvgLastInc; close(fileUnit) - ! fileUnit = IO_open_jobFile_binary('C_ref') - ! read(fileUnit) C_minMaxAvg; close(fileUnit) + ! call HDF5_read(fileHandle,C_volAvg, 'C_volAvg') + ! call HDF5_read(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') + ! call HDF5_read(fileHandle,C_minMaxAvg,'C_ref') + ! call HDF5_closeFile(fileHandle) + fileUnit = IO_open_jobFile_binary('C_volAvg') + read(fileUnit) C_volAvg; close(fileUnit) + fileUnit = IO_open_jobFile_binary('C_volAvgLastInv') + read(fileUnit) C_volAvgLastInc; close(fileUnit) + fileUnit = IO_open_jobFile_binary('C_ref') + read(fileUnit) C_minMaxAvg; close(fileUnit) endif restartRead call Utilities_updateGamma(C_minMaxAvg,.true.) @@ -384,41 +384,41 @@ subroutine grid_mech_spectral_polarisation_forward(guess,timeinc,timeinc_old,loa write(rankStr,'(a1,i0)')'_',worldrank fileHandle = HDF5_openFile(trim(getSolverJobName())//trim(rankStr)//'.hdf5','w') - + if (worldrank == 0) then - call HDF5_write(fileHandle,C_volAvg, 'C_volAvg') - call HDF5_write(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') + ! call HDF5_write(fileHandle,C_volAvg, 'C_volAvg') + ! call HDF5_write(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') call HDF5_write(fileHandle,F_aim, 'F_aim') call HDF5_write(fileHandle,F_aimDot, 'F_aimDot') - call HDF5_write(fileHandle,F_lastInc, 'F_lastInc') - ! fileUnit = IO_open_jobFile_binary('C_volAvg','w') - ! write(fileUnit) C_volAvg; close(fileUnit) - ! fileUnit = IO_open_jobFile_binary('C_volAvgLastInv','w') - ! write(fileUnit) C_volAvgLastInc; close(fileUnit) - ! fileUnit = IO_open_jobFile_binary('F_aim','w') - ! write(fileUnit) F_aim; close(fileUnit) - ! fileUnit = IO_open_jobFile_binary('F_aim_lastInc','w') - ! write(fileUnit) F_aim_lastInc; close(fileUnit) - ! fileUnit = IO_open_jobFile_binary('F_aimDot','w') - call HDF5_closeFile(fileHandle) - !write(fileUnit) F_aimDot; close(fileUnit) + call HDF5_write(fileHandle,F_aim_lastInc, 'F_aim_lastInc') + fileUnit = IO_open_jobFile_binary('C_volAvg','w') + write(fileUnit) C_volAvg; close(fileUnit) + fileUnit = IO_open_jobFile_binary('C_volAvgLastInv','w') + write(fileUnit) C_volAvgLastInc; close(fileUnit) + ! fileUnit = IO_open_jobFile_binary('F_aim','w') + ! write(fileUnit) F_aim; close(fileUnit) + ! fileUnit = IO_open_jobFile_binary('F_aim_lastInc','w') + ! write(fileUnit) F_aim_lastInc; close(fileUnit) + ! fileUnit = IO_open_jobFile_binary('F_aimDot','w') + ! call HDF5_closeFile(fileHandle) + ! write(fileUnit) F_aimDot; close(fileUnit) endif - !write(rankStr,'(a1,i0)')'_',worldrank + write(rankStr,'(a1,i0)')'_',worldrank call HDF5_write(fileHandle,F, 'F') call HDF5_write(fileHandle,F_lastInc, 'F_lastInc') call HDF5_write(fileHandle,F_tau, 'F_tau') call HDF5_write(fileHandle,F_tau_lastInc, 'F_tau_lastInc') call HDF5_closeFile(fileHandle) -! fileUnit = IO_open_jobFile_binary('F'//trim(rankStr),'w') -! write(fileUnit) F; close (fileUnit) -! fileUnit = IO_open_jobFile_binary('F_lastInc'//trim(rankStr),'w') -! write(fileUnit) F_lastInc; close (fileUnit) -! fileUnit = IO_open_jobFile_binary('F_tau'//trim(rankStr),'w') -! write(fileUnit) F_tau; close (fileUnit) -! fileUnit = IO_open_jobFile_binary('F_tau_lastInc'//trim(rankStr),'w') -! write(fileUnit) F_tau_lastInc; close (fileUnit) + !fileUnit = IO_open_jobFile_binary('F'//trim(rankStr),'w') + !write(fileUnit) F; close (fileUnit) + !fileUnit = IO_open_jobFile_binary('F_lastInc'//trim(rankStr),'w') + !write(fileUnit) F_lastInc; close (fileUnit) + !fileUnit = IO_open_jobFile_binary('F_tau'//trim(rankStr),'w') + !write(fileUnit) F_tau; close (fileUnit) + !fileUnit = IO_open_jobFile_binary('F_tau_lastInc'//trim(rankStr),'w') + !write(fileUnit) F_tau_lastInc; close (fileUnit) endif call CPFEM_age ! age state and kinematics From 057bee92afe0d055c58630bafd5c985b256a8414 Mon Sep 17 00:00:00 2001 From: Vitesh Shah Date: Thu, 11 Apr 2019 18:43:20 +0200 Subject: [PATCH 05/61] adding C_ref to HDF5 file doesnt work --- src/grid_mech_spectral_polarisation.f90 | 28 ++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/grid_mech_spectral_polarisation.f90 b/src/grid_mech_spectral_polarisation.f90 index 1f64be0a0..c549cd591 100644 --- a/src/grid_mech_spectral_polarisation.f90 +++ b/src/grid_mech_spectral_polarisation.f90 @@ -232,14 +232,14 @@ subroutine grid_mech_spectral_polarisation_init restartRead: if (restartInc > 0) then write(6,'(/,a,'//IO_intOut(restartInc)//',a)') ' reading more values of increment ', restartInc, ' from file' - ! call HDF5_read(fileHandle,C_volAvg, 'C_volAvg') - ! call HDF5_read(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') - ! call HDF5_read(fileHandle,C_minMaxAvg,'C_ref') - ! call HDF5_closeFile(fileHandle) - fileUnit = IO_open_jobFile_binary('C_volAvg') - read(fileUnit) C_volAvg; close(fileUnit) - fileUnit = IO_open_jobFile_binary('C_volAvgLastInv') - read(fileUnit) C_volAvgLastInc; close(fileUnit) + call HDF5_read(fileHandle,C_volAvg, 'C_volAvg') + call HDF5_read(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') + !call HDF5_read(fileHandle,C_minMaxAvg,'C_ref') + call HDF5_closeFile(fileHandle) + ! fileUnit = IO_open_jobFile_binary('C_volAvg') + ! read(fileUnit) C_volAvg; close(fileUnit) + ! fileUnit = IO_open_jobFile_binary('C_volAvgLastInv') + ! read(fileUnit) C_volAvgLastInc; close(fileUnit) fileUnit = IO_open_jobFile_binary('C_ref') read(fileUnit) C_minMaxAvg; close(fileUnit) endif restartRead @@ -386,15 +386,15 @@ subroutine grid_mech_spectral_polarisation_forward(guess,timeinc,timeinc_old,loa fileHandle = HDF5_openFile(trim(getSolverJobName())//trim(rankStr)//'.hdf5','w') if (worldrank == 0) then - ! call HDF5_write(fileHandle,C_volAvg, 'C_volAvg') - ! call HDF5_write(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') + call HDF5_write(fileHandle,C_volAvg, 'C_volAvg') + call HDF5_write(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') call HDF5_write(fileHandle,F_aim, 'F_aim') call HDF5_write(fileHandle,F_aimDot, 'F_aimDot') call HDF5_write(fileHandle,F_aim_lastInc, 'F_aim_lastInc') - fileUnit = IO_open_jobFile_binary('C_volAvg','w') - write(fileUnit) C_volAvg; close(fileUnit) - fileUnit = IO_open_jobFile_binary('C_volAvgLastInv','w') - write(fileUnit) C_volAvgLastInc; close(fileUnit) + ! fileUnit = IO_open_jobFile_binary('C_volAvg','w') + ! write(fileUnit) C_volAvg; close(fileUnit) + ! fileUnit = IO_open_jobFile_binary('C_volAvgLastInv','w') + ! write(fileUnit) C_volAvgLastInc; close(fileUnit) ! fileUnit = IO_open_jobFile_binary('F_aim','w') ! write(fileUnit) F_aim; close(fileUnit) ! fileUnit = IO_open_jobFile_binary('F_aim_lastInc','w') From a59c5c30c90e134ea58cefdf2f429ab0f81cd16a Mon Sep 17 00:00:00 2001 From: Vitesh Shah Date: Thu, 11 Apr 2019 18:48:28 +0200 Subject: [PATCH 06/61] some cleanup --- src/grid_mech_spectral_polarisation.f90 | 41 ------------------------- 1 file changed, 41 deletions(-) diff --git a/src/grid_mech_spectral_polarisation.f90 b/src/grid_mech_spectral_polarisation.f90 index c549cd591..12183db0e 100644 --- a/src/grid_mech_spectral_polarisation.f90 +++ b/src/grid_mech_spectral_polarisation.f90 @@ -197,23 +197,6 @@ subroutine grid_mech_spectral_polarisation_init call HDF5_read(fileHandle,F_tau, 'F_tau') call HDF5_read(fileHandle,F_tau_lastInc, 'F_tau_lastInc') - ! fileUnit = IO_open_jobFile_binary('F_aim') - ! read(fileUnit) F_aim; close(fileUnit) - ! fileUnit = IO_open_jobFile_binary('F_aim_lastInc') - ! read(fileUnit) F_aim_lastInc; close(fileUnit) - ! fileUnit = IO_open_jobFile_binary('F_aimDot') - ! read(fileUnit) F_aimDot; close(fileUnit) - - ! write(rankStr,'(a1,i0)')'_',worldrank - - ! fileUnit = IO_open_jobFile_binary('F'//trim(rankStr)) - ! read(fileUnit) F; close (fileUnit) - ! fileUnit = IO_open_jobFile_binary('F_lastInc'//trim(rankStr)) - ! read(fileUnit) F_lastInc; close (fileUnit) - ! fileUnit = IO_open_jobFile_binary('F_tau'//trim(rankStr)) - ! read(fileUnit) F_tau; close (fileUnit) - ! fileUnit = IO_open_jobFile_binary('F_tau_lastInc'//trim(rankStr)) - ! read(fileUnit) F_tau_lastInc; close (fileUnit) elseif (restartInc == 0) then restart F_lastInc = spread(spread(spread(math_I3,3,grid(1)),4,grid(2)),5,grid3) ! initialize to identity @@ -234,12 +217,7 @@ subroutine grid_mech_spectral_polarisation_init write(6,'(/,a,'//IO_intOut(restartInc)//',a)') ' reading more values of increment ', restartInc, ' from file' call HDF5_read(fileHandle,C_volAvg, 'C_volAvg') call HDF5_read(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') - !call HDF5_read(fileHandle,C_minMaxAvg,'C_ref') call HDF5_closeFile(fileHandle) - ! fileUnit = IO_open_jobFile_binary('C_volAvg') - ! read(fileUnit) C_volAvg; close(fileUnit) - ! fileUnit = IO_open_jobFile_binary('C_volAvgLastInv') - ! read(fileUnit) C_volAvgLastInc; close(fileUnit) fileUnit = IO_open_jobFile_binary('C_ref') read(fileUnit) C_minMaxAvg; close(fileUnit) endif restartRead @@ -391,17 +369,6 @@ subroutine grid_mech_spectral_polarisation_forward(guess,timeinc,timeinc_old,loa call HDF5_write(fileHandle,F_aim, 'F_aim') call HDF5_write(fileHandle,F_aimDot, 'F_aimDot') call HDF5_write(fileHandle,F_aim_lastInc, 'F_aim_lastInc') - ! fileUnit = IO_open_jobFile_binary('C_volAvg','w') - ! write(fileUnit) C_volAvg; close(fileUnit) - ! fileUnit = IO_open_jobFile_binary('C_volAvgLastInv','w') - ! write(fileUnit) C_volAvgLastInc; close(fileUnit) - ! fileUnit = IO_open_jobFile_binary('F_aim','w') - ! write(fileUnit) F_aim; close(fileUnit) - ! fileUnit = IO_open_jobFile_binary('F_aim_lastInc','w') - ! write(fileUnit) F_aim_lastInc; close(fileUnit) - ! fileUnit = IO_open_jobFile_binary('F_aimDot','w') - ! call HDF5_closeFile(fileHandle) - ! write(fileUnit) F_aimDot; close(fileUnit) endif write(rankStr,'(a1,i0)')'_',worldrank @@ -411,14 +378,6 @@ subroutine grid_mech_spectral_polarisation_forward(guess,timeinc,timeinc_old,loa call HDF5_write(fileHandle,F_tau_lastInc, 'F_tau_lastInc') call HDF5_closeFile(fileHandle) - !fileUnit = IO_open_jobFile_binary('F'//trim(rankStr),'w') - !write(fileUnit) F; close (fileUnit) - !fileUnit = IO_open_jobFile_binary('F_lastInc'//trim(rankStr),'w') - !write(fileUnit) F_lastInc; close (fileUnit) - !fileUnit = IO_open_jobFile_binary('F_tau'//trim(rankStr),'w') - !write(fileUnit) F_tau; close (fileUnit) - !fileUnit = IO_open_jobFile_binary('F_tau_lastInc'//trim(rankStr),'w') - !write(fileUnit) F_tau_lastInc; close (fileUnit) endif call CPFEM_age ! age state and kinematics From b8285d57493e184387e1d966f42e0bc9f1b7274b Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Thu, 11 Apr 2019 17:18:32 -0400 Subject: [PATCH 07/61] restored orientation averaging capability --- python/damask/orientation.py | 102 ++++++++++++++++++++--------------- 1 file changed, 59 insertions(+), 43 deletions(-) diff --git a/python/damask/orientation.py b/python/damask/orientation.py index 7cb05af40..463dfeb1b 100644 --- a/python/damask/orientation.py +++ b/python/damask/orientation.py @@ -35,14 +35,6 @@ class Quaternion: """Components""" return iter(self.asList()) - def asArray(self): - """As numpy array""" - return np.array((self.q,self.p[0],self.p[1],self.p[2])) - - def asList(self): - return [self.q]+list(self.p) - - def __repr__(self): """Readable string""" return 'Quaternion: (real={q:+.6f}, imag=<{p[0]:+.6f}, {p[1]:+.6f}, {p[2]:+.6f}>)'.format(q=self.q,p=self.p) @@ -116,7 +108,7 @@ class Quaternion: return self else: return NotImplemented - + def __truediv__(self, other): """Divsion with quaternion or scalar""" @@ -180,6 +172,17 @@ class Quaternion: return not self.__eq__(other) + def asM(self): + """Intermediate representation useful for quaternion averaging (see F. Landis Markley et al.)""" + return np.outer(self.asArray(),self.asArray()) + + def asArray(self): + """As numpy array""" + return np.array((self.q,self.p[0],self.p[1],self.p[2])) + + def asList(self): + return [self.q]+list(self.p) + def normalize(self): d = self.magnitude() if d > 0.0: @@ -190,7 +193,7 @@ class Quaternion: def normalized(self): return self.copy().normalize() - + def conjugate(self): self.p = -self.p return self @@ -294,6 +297,10 @@ class Rotation: def asCubochoric(self): return qu2cu(self.quaternion.asArray()) + def asM(self): + """Intermediate representation useful fro quaternion averaging (see F. Landis Markley et al.)""" + return self.quaternion.asM() + ################################################################################################ # static constructors. The input data needs to follow the convention, options allow to @@ -503,7 +510,7 @@ class Symmetry: otherOrder = Symmetry.lattices.index(other.lattice) return (myOrder > otherOrder) - (myOrder < otherOrder) - def symmetryOperations(self): + def symmetryOperations(self,who=[]): """List of symmetry operations as quaternions.""" if self.lattice == 'cubic': symQuats = [ @@ -570,7 +577,8 @@ class Symmetry: [ 1.0,0.0,0.0,0.0 ], ] - return [Rotation(q) for q in symQuats] + return list(map(Rotation, + np.array(symQuats)[np.atleast_1d(np.array(who)) if who != [] else range(len(symQuats))])) def inFZ(self,R): @@ -579,6 +587,8 @@ class Symmetry: Fundamental zone in Rodrigues space is point symmetric around origin. """ + if np.any(R == np.inf): return False + Rabs = abs(R[0:3]*R[3]) if self.lattice == 'cubic': @@ -1050,7 +1060,8 @@ class Orientation: def disorientation(self, other, - SST = True): + SST = True, + symmetries = False): """ Disorientation between myself and given other orientation. @@ -1076,15 +1087,18 @@ class Orientation: if breaker: break if breaker: break - return r + return (r, i,j, k == 1) if symmetries else r # disorientation ... + # ... own sym, other sym, + # self-->other: True, self<--other: False + def inFZ(self): return self.lattice.symmetry.inFZ(self.rotation.asRodrigues()) - def equivalentOrientations(self): + def equivalentOrientations(self, who=[]): """List of orientations which are symmetrically equivalent""" return [self.__class__(q*self.rotation,self.lattice) \ - for q in self.lattice.symmetry.symmetryOperations()] + for q in self.lattice.symmetry.symmetryOperations(who)] def relatedOrientations(self,model): """List of orientations related by the given orientation relationship""" @@ -1125,37 +1139,39 @@ class Orientation: return color - # @classmethod - # def average(cls, - # orientations, - # multiplicity = []): - # """ - # Average orientation + @classmethod + def average(cls, + orientations, + multiplicity = []): + """ + Average orientation - # ref: F. Landis Markley, Yang Cheng, John Lucas Crassidis, and Yaakov Oshman. - # Averaging Quaternions, - # Journal of Guidance, Control, and Dynamics, Vol. 30, No. 4 (2007), pp. 1193-1197. - # doi: 10.2514/1.28949 - # usage: - # a = Orientation(Eulers=np.radians([10, 10, 0]), symmetry='hexagonal') - # b = Orientation(Eulers=np.radians([20, 0, 0]), symmetry='hexagonal') - # avg = Orientation.average([a,b]) - # """ - # if not all(isinstance(item, Orientation) for item in orientations): - # raise TypeError("Only instances of Orientation can be averaged.") + ref: F. Landis Markley, Yang Cheng, John Lucas Crassidis, and Yaakov Oshman. + Averaging Quaternions, + Journal of Guidance, Control, and Dynamics, Vol. 30, No. 4 (2007), pp. 1193-1197. + doi: 10.2514/1.28949 + usage: + a = Orientation(Eulers=np.radians([10, 10, 0]), symmetry='hexagonal') + b = Orientation(Eulers=np.radians([20, 0, 0]), symmetry='hexagonal') + avg = Orientation.average([a,b]) + """ + if not all(isinstance(item, Orientation) for item in orientations): + print('got a list of {}'.format(orientations)) + raise TypeError("Only instances of Orientation can be averaged.") - # N = len(orientations) - # if multiplicity == [] or not multiplicity: - # multiplicity = np.ones(N,dtype='i') + N = len(orientations) + if multiplicity == [] or not multiplicity: + multiplicity = np.ones(N,dtype='i') - # reference = orientations[0] # take first as reference - # for i,(o,n) in enumerate(zip(orientations,multiplicity)): - # closest = o.equivalentOrientations(reference.disorientation(o,SST = False)[2])[0] # select sym orientation with lowest misorientation - # M = closest.quaternion.asM() * n if i == 0 else M + closest.quaternion.asM() * n # noqa add (multiples) of this orientation to average noqa - # eig, vec = np.linalg.eig(M/N) + ref = orientations[0] # take first as reference + for i,(o,n) in enumerate(zip(orientations,multiplicity)): + closest = o.equivalentOrientations(ref.disorientation(o,SST=False,symmetries=True)[2])[0] # select sym orientation with lowest misorientation + M = closest.rotation.asM() * n if i == 0 \ + else M + closest.rotation.asM() * n # noqa add (multiples) of this orientation to average noqa + eig, vec = np.linalg.eig(M/N) - # return Orientation(quaternion = Quaternion(quat = np.real(vec.T[eig.argmax()])), - # symmetry = reference.symmetry.lattice) + return Orientation(Rotation.fromQuaternion(np.real(vec.T[eig.argmax()]),acceptHomomorph = True), + ref.lattice) #################################################################################################### From 2190c3ef466f0ac08100276671393293d4b9b05d Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Thu, 11 Apr 2019 18:32:07 -0400 Subject: [PATCH 08/61] fixed serious disorientation bug; sorted transformation functions --- python/damask/orientation.py | 530 ++++++++++++++++++----------------- 1 file changed, 274 insertions(+), 256 deletions(-) diff --git a/python/damask/orientation.py b/python/damask/orientation.py index 463dfeb1b..f4df909c6 100644 --- a/python/damask/orientation.py +++ b/python/damask/orientation.py @@ -286,9 +286,9 @@ class Rotation: """Rotation matrix""" return qu2om(self.quaternion.asArray()) - def asRodrigues(self): + def asRodrigues(self,vector=False): """Rodrigues-Frank vector: ([n_1, n_2, n_3], tan(ω/2))""" - return qu2ro(self.quaternion.asArray()) + return qu2ro(self.quaternion.asArray(),vector) def asHomochoric(self): """Homochoric vector: (h_1, h_2, h_3)""" @@ -1072,15 +1072,16 @@ class Orientation: #if self.lattice.symmetry != other.lattice.symmetry: # raise NotImplementedError('disorientation between different symmetry classes not supported yet.') - mis = other.rotation*self.rotation.inversed() - mySymEqs = self.equivalentOrientations() if SST else self.equivalentOrientations()[:1] # take all or only first sym operation + mySymEqs = self.equivalentOrientations() if SST else self.equivalentOrientations([0]) # take all or only first sym operation otherSymEqs = other.equivalentOrientations() for i,sA in enumerate(mySymEqs): + aInv = sA.rotation.inversed() for j,sB in enumerate(otherSymEqs): - r = sB.rotation*mis*sA.rotation.inversed() + b = sB.rotation + r = b*aInv for k in range(2): - r.inversed() + r.inverse() breaker = self.lattice.symmetry.inFZ(r.asRodrigues()) \ and (not SST or other.lattice.symmetry.inDisorientationSST(r.asRodrigues())) if breaker: break @@ -1211,94 +1212,7 @@ def isone(a): def iszero(a): return np.isclose(a,0.0,atol=1.0e-12,rtol=0.0) - -def eu2om(eu): - """Euler angles to orientation matrix""" - c = np.cos(eu) - s = np.sin(eu) - - om = np.array([[+c[0]*c[2]-s[0]*s[2]*c[1], +s[0]*c[2]+c[0]*s[2]*c[1], +s[2]*s[1]], - [-c[0]*s[2]-s[0]*c[2]*c[1], -s[0]*s[2]+c[0]*c[2]*c[1], +c[2]*s[1]], - [+s[0]*s[1], -c[0]*s[1], +c[1] ]]) - - om[np.where(iszero(om))] = 0.0 - return om - - -def eu2ax(eu): - """Euler angles to axis angle""" - t = np.tan(eu[1]*0.5) - sigma = 0.5*(eu[0]+eu[2]) - delta = 0.5*(eu[0]-eu[2]) - tau = np.linalg.norm([t,np.sin(sigma)]) - alpha = np.pi if iszero(np.cos(sigma)) else \ - 2.0*np.arctan(tau/np.cos(sigma)) - - if iszero(alpha): - ax = np.array([ 0.0, 0.0, 1.0, 0.0 ]) - else: - ax = -P/tau * np.array([ t*np.cos(delta), t*np.sin(delta), np.sin(sigma) ]) # passive axis-angle pair so a minus sign in front - ax = np.append(ax,alpha) - if alpha < 0.0: ax *= -1.0 # ensure alpha is positive - - return ax - - -def eu2ro(eu): - """Euler angles to Rodrigues vector""" - ro = eu2ax(eu) # convert to axis angle representation - if ro[3] >= np.pi: # Differs from original implementation. check convention 5 - ro[3] = np.inf - elif iszero(ro[3]): - ro = np.array([ 0.0, 0.0, P, 0.0 ]) - else: - ro[3] = np.tan(ro[3]*0.5) - - return ro - - -def eu2qu(eu): - """Euler angles to quaternion""" - ee = 0.5*eu - cPhi = np.cos(ee[1]) - sPhi = np.sin(ee[1]) - qu = np.array([ cPhi*np.cos(ee[0]+ee[2]), - -P*sPhi*np.cos(ee[0]-ee[2]), - -P*sPhi*np.sin(ee[0]-ee[2]), - -P*cPhi*np.sin(ee[0]+ee[2]) ]) - #if qu[0] < 0.0: qu.homomorph() !ToDo: Check with original - return qu - - -def om2eu(om): - """Euler angles to orientation matrix""" - if isone(om[2,2]**2): - eu = np.array([np.arctan2( om[0,1],om[0,0]), np.pi*0.5*(1-om[2,2]),0.0]) # following the paper, not the reference implementation - else: - zeta = 1.0/np.sqrt(1.0-om[2,2]**2) - eu = np.array([np.arctan2(om[2,0]*zeta,-om[2,1]*zeta), - np.arccos(om[2,2]), - np.arctan2(om[0,2]*zeta, om[1,2]*zeta)]) - - # reduce Euler angles to definition range, i.e a lower limit of 0.0 - eu = np.where(eu<0, (eu+2.0*np.pi)%np.array([2.0*np.pi,np.pi,2.0*np.pi]),eu) - return eu - - -def ax2om(ax): - """Axis angle to orientation matrix""" - c = np.cos(ax[3]) - s = np.sin(ax[3]) - omc = 1.0-c - om=np.diag(ax[0:3]**2*omc + c) - - for idx in [[0,1,2],[1,2,0],[2,0,1]]: - q = omc*ax[idx[0]] * ax[idx[1]] - om[idx[0],idx[1]] = q + s*ax[idx[2]] - om[idx[1],idx[0]] = q - s*ax[idx[2]] - - return om if P < 0.0 else om.T - +#---------- quaternion ---------- def qu2eu(qu): """Quaternion to Euler angles""" @@ -1318,113 +1232,6 @@ def qu2eu(qu): eu = np.where(eu<0, (eu+2.0*np.pi)%np.array([2.0*np.pi,np.pi,2.0*np.pi]),eu) return eu - -def ax2ho(ax): - """Axis angle to homochoric""" - f = (0.75 * ( ax[3] - np.sin(ax[3]) ))**(1.0/3.0) - ho = ax[0:3] * f - return ho - - -def ho2ax(ho): - """Homochoric to axis angle""" - tfit = np.array([+1.0000000000018852, -0.5000000002194847, - -0.024999992127593126, -0.003928701544781374, - -0.0008152701535450438, -0.0002009500426119712, - -0.00002397986776071756, -0.00008202868926605841, - +0.00012448715042090092, -0.0001749114214822577, - +0.0001703481934140054, -0.00012062065004116828, - +0.000059719705868660826, -0.00001980756723965647, - +0.000003953714684212874, -0.00000036555001439719544]) - # normalize h and store the magnitude - hmag_squared = np.sum(ho**2.) - if iszero(hmag_squared): - ax = np.array([ 0.0, 0.0, 1.0, 0.0 ]) - else: - hm = hmag_squared - - # convert the magnitude to the rotation angle - s = tfit[0] + tfit[1] * hmag_squared - for i in range(2,16): - hm *= hmag_squared - s += tfit[i] * hm - ax = np.append(ho/np.sqrt(hmag_squared),2.0*np.arccos(np.clip(s,-1.0,1.0))) - return ax - - -def om2ax(om): - """Orientation matrix to axis angle""" - ax=np.empty(4) - - # first get the rotation angle - t = 0.5*(om.trace() -1.0) - ax[3] = np.arccos(np.clip(t,-1.0,1.0)) - - if iszero(ax[3]): - ax = [ 0.0, 0.0, 1.0, 0.0] - else: - w,vr = np.linalg.eig(om) - # next, find the eigenvalue (1,0j) - i = np.where(np.isclose(w,1.0+0.0j))[0][0] - ax[0:3] = np.real(vr[0:3,i]) - diagDelta = np.array([om[1,2]-om[2,1],om[2,0]-om[0,2],om[0,1]-om[1,0]]) - ax[0:3] = np.where(iszero(diagDelta), ax[0:3],np.abs(ax[0:3])*np.sign(-P*diagDelta)) - - return np.array(ax) - - -def ro2ax(ro): - """Rodrigues vector to axis angle""" - ta = ro[3] - - if iszero(ta): - ax = [ 0.0, 0.0, 1.0, 0.0 ] - elif not np.isfinite(ta): - ax = [ ro[0], ro[1], ro[2], np.pi ] - else: - angle = 2.0*np.arctan(ta) - ta = 1.0/np.linalg.norm(ro[0:3]) - ax = [ ro[0]/ta, ro[1]/ta, ro[2]/ta, angle ] - - return np.array(ax) - - -def ax2ro(ax): - """Axis angle to Rodrigues vector""" - if iszero(ax[3]): - ro = [ 0.0, 0.0, P, 0.0 ] - else: - ro = [ax[0], ax[1], ax[2]] - # 180 degree case - ro += [np.inf] if np.isclose(ax[3],np.pi,atol=1.0e-15,rtol=0.0) else \ - [np.tan(ax[3]*0.5)] - - return np.array(ro) - - -def ax2qu(ax): - """Axis angle to quaternion""" - if iszero(ax[3]): - qu = np.array([ 1.0, 0.0, 0.0, 0.0 ]) - else: - c = np.cos(ax[3]*0.5) - s = np.sin(ax[3]*0.5) - qu = np.array([ c, ax[0]*s, ax[1]*s, ax[2]*s ]) - - return qu - - -def ro2ho(ro): - """Rodrigues vector to homochoric""" - if iszero(np.sum(ro[0:3]**2.0)): - ho = [ 0.0, 0.0, 0.0 ] - else: - f = 2.0*np.arctan(ro[3]) -np.sin(2.0*np.arctan(ro[3])) if np.isfinite(ro[3]) else np.pi - ho = ro[0:3] * (0.75*f)**(1.0/3.0) - - return np.array(ho) - - def qu2om(qu): """Quaternion to orientation matrix""" qq = qu[0]**2-(qu[1]**2 + qu[2]**2 + qu[3]**2) @@ -1457,7 +1264,7 @@ def qu2ax(qu): return np.array(ax) -def qu2ro(qu): +def qu2ro(qu,vector=False): """Quaternion to Rodrigues vector""" if iszero(qu[0]): ro = [qu[1], qu[2], qu[3], np.inf] @@ -1466,7 +1273,7 @@ def qu2ro(qu): ro = [0.0,0.0,P,0.0] if iszero(s) else \ [ qu[1]/s, qu[2]/s, qu[3]/s, np.tan(np.arccos(np.clip(qu[0],-1.0,1.0)))] # avoid numerical difficulties - return np.array(ro) + return np.array(ro[:3])*ro[3] if vector else np.array(ro) def qu2ho(qu): @@ -1483,19 +1290,120 @@ def qu2ho(qu): return ho -def ho2cu(ho): - """Homochoric to cubochoric""" - return Lambert.BallToCube(ho) +def qu2cu(qu): + """Quaternion to cubochoric""" + return ho2cu(qu2ho(qu)) -def cu2ho(cu): - """Cubochoric to homochoric""" - return Lambert.CubeToBall(cu) +#---------- orientation matrix ---------- -def ro2eu(ro): - """Rodrigues vector to orientation matrix""" - return om2eu(ro2om(ro)) +def om2eu(om): + """Euler angles to orientation matrix""" + if isone(om[2,2]**2): + eu = np.array([np.arctan2( om[0,1],om[0,0]), np.pi*0.5*(1-om[2,2]),0.0]) # following the paper, not the reference implementation + else: + zeta = 1.0/np.sqrt(1.0-om[2,2]**2) + eu = np.array([np.arctan2(om[2,0]*zeta,-om[2,1]*zeta), + np.arccos(om[2,2]), + np.arctan2(om[0,2]*zeta, om[1,2]*zeta)]) + + # reduce Euler angles to definition range, i.e a lower limit of 0.0 + eu = np.where(eu<0, (eu+2.0*np.pi)%np.array([2.0*np.pi,np.pi,2.0*np.pi]),eu) + return eu + + +def om2ax(om): + """Orientation matrix to axis angle""" + ax=np.empty(4) + + # first get the rotation angle + t = 0.5*(om.trace() -1.0) + ax[3] = np.arccos(np.clip(t,-1.0,1.0)) + + if iszero(ax[3]): + ax = [ 0.0, 0.0, 1.0, 0.0] + else: + w,vr = np.linalg.eig(om) + # next, find the eigenvalue (1,0j) + i = np.where(np.isclose(w,1.0+0.0j))[0][0] + ax[0:3] = np.real(vr[0:3,i]) + diagDelta = np.array([om[1,2]-om[2,1],om[2,0]-om[0,2],om[0,1]-om[1,0]]) + ax[0:3] = np.where(iszero(diagDelta), ax[0:3],np.abs(ax[0:3])*np.sign(-P*diagDelta)) + + return np.array(ax) + + +def om2qu(om): + """ + Orientation matrix to quaternion + + The original formulation (direct conversion) had numerical issues + """ + return ax2qu(om2ax(om)) + + +def om2ro(om,vector=False): + """Orientation matrix to Rodriques vector""" + return eu2ro(om2eu(om,vector)) + + +def om2cu(om): + """Orientation matrix to cubochoric""" + return ho2cu(om2ho(om)) + + +def om2ho(om): + """Orientation matrix to homochoric""" + return ax2ho(om2ax(om)) + + +#---------- Euler angles ---------- + + +def eu2om(eu): + """Euler angles to orientation matrix""" + c = np.cos(eu) + s = np.sin(eu) + + om = np.array([[+c[0]*c[2]-s[0]*s[2]*c[1], +s[0]*c[2]+c[0]*s[2]*c[1], +s[2]*s[1]], + [-c[0]*s[2]-s[0]*c[2]*c[1], -s[0]*s[2]+c[0]*c[2]*c[1], +c[2]*s[1]], + [+s[0]*s[1], -c[0]*s[1], +c[1] ]]) + + om[np.where(iszero(om))] = 0.0 + return om + + +def eu2ax(eu): + """Euler angles to axis angle""" + t = np.tan(eu[1]*0.5) + sigma = 0.5*(eu[0]+eu[2]) + delta = 0.5*(eu[0]-eu[2]) + tau = np.linalg.norm([t,np.sin(sigma)]) + alpha = np.pi if iszero(np.cos(sigma)) else \ + 2.0*np.arctan(tau/np.cos(sigma)) + + if iszero(alpha): + ax = np.array([ 0.0, 0.0, 1.0, 0.0 ]) + else: + ax = -P/tau * np.array([ t*np.cos(delta), t*np.sin(delta), np.sin(sigma) ]) # passive axis-angle pair so a minus sign in front + ax = np.append(ax,alpha) + if alpha < 0.0: ax *= -1.0 # ensure alpha is positive + + return ax + + +def eu2ro(eu,vector=False): + """Euler angles to Rodrigues vector""" + ro = eu2ax(eu) # convert to axis angle representation + if ro[3] >= np.pi: # Differs from original implementation. check convention 5 + ro[3] = np.inf + elif iszero(ro[3]): + ro = np.array([ 0.0, 0.0, P, 0.0 ]) + else: + ro[3] = np.tan(ro[3]*0.5) + + return ro[:3] * ro[3] if vector else ro def eu2ho(eu): @@ -1503,21 +1411,108 @@ def eu2ho(eu): return ax2ho(eu2ax(eu)) -def om2ro(om): - """Orientation matrix to Rodriques vector""" - return eu2ro(om2eu(om)) +def eu2qu(eu): + """Euler angles to quaternion""" + ee = 0.5*eu + cPhi = np.cos(ee[1]) + sPhi = np.sin(ee[1]) + qu = np.array([ cPhi*np.cos(ee[0]+ee[2]), + -P*sPhi*np.cos(ee[0]-ee[2]), + -P*sPhi*np.sin(ee[0]-ee[2]), + -P*cPhi*np.sin(ee[0]+ee[2]) ]) + #if qu[0] < 0.0: qu.homomorph() !ToDo: Check with original + return qu -def om2ho(om): - """Orientation matrix to homochoric""" - return ax2ho(om2ax(om)) +def eu2cu(eu): + """Euler angles to cubochoric""" + return ho2cu(eu2ho(eu)) +#---------- axis angle ---------- + + def ax2eu(ax): """Orientation matrix to Euler angles""" return om2eu(ax2om(ax)) +def ax2om(ax): + """Axis angle to orientation matrix""" + c = np.cos(ax[3]) + s = np.sin(ax[3]) + omc = 1.0-c + om=np.diag(ax[0:3]**2*omc + c) + + for idx in [[0,1,2],[1,2,0],[2,0,1]]: + q = omc*ax[idx[0]] * ax[idx[1]] + om[idx[0],idx[1]] = q + s*ax[idx[2]] + om[idx[1],idx[0]] = q - s*ax[idx[2]] + + return om if P < 0.0 else om.T + + +def ax2ro(ax,vector=False): + """Axis angle to Rodrigues vector""" + if iszero(ax[3]): + ro = [ 0.0, 0.0, P, 0.0 ] + else: + ro = [ax[0], ax[1], ax[2]] + # 180 degree case + ro += [np.inf] if np.isclose(ax[3],np.pi,atol=1.0e-15,rtol=0.0) else \ + [np.tan(ax[3]*0.5)] + + return np.array(ro[:3])*ro[3] if vector else np.array(ro) + + +def ax2qu(ax): + """Axis angle to quaternion""" + if iszero(ax[3]): + qu = np.array([ 1.0, 0.0, 0.0, 0.0 ]) + else: + c = np.cos(ax[3]*0.5) + s = np.sin(ax[3]*0.5) + qu = np.array([ c, ax[0]*s, ax[1]*s, ax[2]*s ]) + + return qu + + +def ax2ho(ax): + """Axis angle to homochoric""" + f = (0.75 * ( ax[3] - np.sin(ax[3]) ))**(1.0/3.0) + ho = ax[0:3] * f + return ho + + +def ax2cu(ax): + """Axis angle to cubochoric""" + return ho2cu(ax2ho(ax)) + + +#---------- Rodrigues--Frank ---------- + + +def ro2ax(ro): + """Rodrigues vector to axis angle""" + ta = ro[3] + + if iszero(ta): + ax = [ 0.0, 0.0, 1.0, 0.0 ] + elif not np.isfinite(ta): + ax = [ ro[0], ro[1], ro[2], np.pi ] + else: + angle = 2.0*np.arctan(ta) + ta = 1.0/np.linalg.norm(ro[0:3]) + ax = [ ro[0]/ta, ro[1]/ta, ro[2]/ta, angle ] + + return np.array(ax) + + +def ro2eu(ro): + """Rodrigues vector to orientation matrix""" + return om2eu(ro2om(ro)) + + def ro2om(ro): """Rodgrigues vector to orientation matrix""" return ax2om(ro2ax(ro)) @@ -1528,6 +1523,56 @@ def ro2qu(ro): return ax2qu(ro2ax(ro)) +def ro2ho(ro): + """Rodrigues vector to homochoric""" + if iszero(np.sum(ro[0:3]**2.0)): + ho = [ 0.0, 0.0, 0.0 ] + else: + f = 2.0*np.arctan(ro[3]) -np.sin(2.0*np.arctan(ro[3])) if np.isfinite(ro[3]) else np.pi + ho = ro[0:3] * (0.75*f)**(1.0/3.0) + + return np.array(ho) + + +def ro2cu(ro): + """Rodrigues vector to cubochoric""" + return ho2cu(ro2ho(ro)) + + +#---------- homochoric ---------- + + +def ho2ax(ho): + """Homochoric to axis angle""" + tfit = np.array([+1.0000000000018852, -0.5000000002194847, + -0.024999992127593126, -0.003928701544781374, + -0.0008152701535450438, -0.0002009500426119712, + -0.00002397986776071756, -0.00008202868926605841, + +0.00012448715042090092, -0.0001749114214822577, + +0.0001703481934140054, -0.00012062065004116828, + +0.000059719705868660826, -0.00001980756723965647, + +0.000003953714684212874, -0.00000036555001439719544]) + # normalize h and store the magnitude + hmag_squared = np.sum(ho**2.) + if iszero(hmag_squared): + ax = np.array([ 0.0, 0.0, 1.0, 0.0 ]) + else: + hm = hmag_squared + + # convert the magnitude to the rotation angle + s = tfit[0] + tfit[1] * hmag_squared + for i in range(2,16): + hm *= hmag_squared + s += tfit[i] * hm + ax = np.append(ho/np.sqrt(hmag_squared),2.0*np.arccos(np.clip(s,-1.0,1.0))) + return ax + + +def ho2cu(ho): + """Homochoric to cubochoric""" + return Lambert.BallToCube(ho) + + def ho2eu(ho): """Homochoric to Euler angles""" return ax2eu(ho2ax(ho)) @@ -1538,9 +1583,9 @@ def ho2om(ho): return ax2om(ho2ax(ho)) -def ho2ro(ho): +def ho2ro(ho,vector=False): """Axis angle to Rodriques vector""" - return ax2ro(ho2ax(ho)) + return ax2ro(ho2ax(ho,vector)) def ho2qu(ho): @@ -1548,40 +1593,6 @@ def ho2qu(ho): return ax2qu(ho2ax(ho)) -def eu2cu(eu): - """Euler angles to cubochoric""" - return ho2cu(eu2ho(eu)) - - -def om2cu(om): - """Orientation matrix to cubochoric""" - return ho2cu(om2ho(om)) - - -def om2qu(om): - """ - Orientation matrix to quaternion - - The original formulation (direct conversion) had numerical issues - """ - return ax2qu(om2ax(om)) - - -def ax2cu(ax): - """Axis angle to cubochoric""" - return ho2cu(ax2ho(ax)) - - -def ro2cu(ro): - """Rodrigues vector to cubochoric""" - return ho2cu(ro2ho(ro)) - - -def qu2cu(qu): - """Quaternion to cubochoric""" - return ho2cu(qu2ho(qu)) - - def cu2eu(cu): """Cubochoric to Euler angles""" return ho2eu(cu2ho(cu)) @@ -1597,11 +1608,18 @@ def cu2ax(cu): return ho2ax(cu2ho(cu)) -def cu2ro(cu): +def cu2ro(cu,vector=False): """Cubochoric to Rodrigues vector""" - return ho2ro(cu2ho(cu)) + return ho2ro(cu2ho(cu,vector)) def cu2qu(cu): """Cubochoric to quaternion""" return ho2qu(cu2ho(cu)) + + +def cu2ho(cu): + """Cubochoric to homochoric""" + return Lambert.CubeToBall(cu) + + From 3d6eb76da3992d64a37edb170e77beb7efb6c696 Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Thu, 11 Apr 2019 19:07:41 -0400 Subject: [PATCH 09/61] equivalentOrientations accepts scalar argument to directly return single rotation object (not single element list) --- python/damask/orientation.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/python/damask/orientation.py b/python/damask/orientation.py index f4df909c6..227f02cda 100644 --- a/python/damask/orientation.py +++ b/python/damask/orientation.py @@ -510,7 +510,7 @@ class Symmetry: otherOrder = Symmetry.lattices.index(other.lattice) return (myOrder > otherOrder) - (myOrder < otherOrder) - def symmetryOperations(self,who=[]): + def symmetryOperations(self,members=[]): """List of symmetry operations as quaternions.""" if self.lattice == 'cubic': symQuats = [ @@ -577,8 +577,14 @@ class Symmetry: [ 1.0,0.0,0.0,0.0 ], ] - return list(map(Rotation, - np.array(symQuats)[np.atleast_1d(np.array(who)) if who != [] else range(len(symQuats))])) + symOps = list(map(Rotation, + np.array(symQuats)[np.atleast_1d(members) if members != [] else range(len(symQuats))])) + try: + iter(members) # asking for (even empty) list of members? + except TypeError: + return symOps[0] # no, return rotation object + else: + return symOps # yes, return list of rotations def inFZ(self,R): @@ -1096,10 +1102,15 @@ class Orientation: def inFZ(self): return self.lattice.symmetry.inFZ(self.rotation.asRodrigues()) - def equivalentOrientations(self, who=[]): + def equivalentOrientations(self,members=[]): """List of orientations which are symmetrically equivalent""" - return [self.__class__(q*self.rotation,self.lattice) \ - for q in self.lattice.symmetry.symmetryOperations(who)] + try: + iter(members) # asking for (even empty) list of members? + except TypeError: + return self.__class__(self.lattice.symmetry.symmetryOperations(members)*self.rotation,self.lattice) # no, return rotation object + else: + return [self.__class__(q*self.rotation,self.lattice) \ + for q in self.lattice.symmetry.symmetryOperations(members)] # yes, return list of rotations def relatedOrientations(self,model): """List of orientations related by the given orientation relationship""" From 3a7408a2131a825d2c4b4b2103031896c4a46e1c Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Fri, 12 Apr 2019 09:02:00 -0400 Subject: [PATCH 10/61] averaging possible for rotations and orientations; Rodrigues 3Dvector output only at top-level; code reordering --- python/damask/orientation.py | 186 ++++++++++++++++++++--------------- 1 file changed, 104 insertions(+), 82 deletions(-) diff --git a/python/damask/orientation.py b/python/damask/orientation.py index 227f02cda..fde168d27 100644 --- a/python/damask/orientation.py +++ b/python/damask/orientation.py @@ -260,6 +260,63 @@ class Rotation: 'Bunge Eulers / deg: {}'.format('\t'.join(list(map(str,self.asEulers(degrees=True)))) ), ]) + def __mul__(self, other): + """ + Multiplication + + Rotation: Details needed (active/passive), rotation of (3,3,3,3)-matrix should be considered + """ + if isinstance(other, Rotation): # rotate a rotation + return self.__class__((self.quaternion * other.quaternion).asArray()) + elif isinstance(other, np.ndarray): + if other.shape == (3,): # rotate a single (3)-vector + ( x, y, z) = self.quaternion.p + (Vx,Vy,Vz) = other[0:3] + A = self.quaternion.q*self.quaternion.q - np.dot(self.quaternion.p,self.quaternion.p) + B = 2.0 * (x*Vx + y*Vy + z*Vz) + C = 2.0 * P*self.quaternion.q + + return np.array([ + A*Vx + B*x + C*(y*Vz - z*Vy), + A*Vy + B*y + C*(z*Vx - x*Vz), + A*Vz + B*z + C*(x*Vy - y*Vx), + ]) + elif other.shape == (3,3,): # rotate a single (3x3)-matrix + return np.dot(self.asMatrix(),np.dot(other,self.asMatrix().T)) + elif other.shape == (3,3,3,3): + raise NotImplementedError + else: + return NotImplemented + elif isinstance(other, tuple): # used to rotate a meshgrid-tuple + ( x, y, z) = self.quaternion.p + (Vx,Vy,Vz) = other[0:3] + A = self.quaternion.q*self.quaternion.q - np.dot(self.quaternion.p,self.quaternion.p) + B = 2.0 * (x*Vx + y*Vy + z*Vz) + C = 2.0 * P*self.quaternion.q + + return np.array([ + A*Vx + B*x + C*(y*Vz - z*Vy), + A*Vy + B*y + C*(z*Vx - x*Vz), + A*Vz + B*z + C*(x*Vy - y*Vx), + ]) + else: + return NotImplemented + + + def inverse(self): + """In-place inverse rotation/backward rotation""" + self.quaternion.conjugate() + return self + + def inversed(self): + """Inverse rotation/backward rotation""" + return self.__class__(self.quaternion.conjugated()) + + + def misorientation(self,other): + """Misorientation""" + return self.__class__(other.quaternion*self.quaternion.conjugated()) + ################################################################################################ # convert to different orientation representations (numpy arrays) @@ -288,7 +345,8 @@ class Rotation: def asRodrigues(self,vector=False): """Rodrigues-Frank vector: ([n_1, n_2, n_3], tan(ω/2))""" - return qu2ro(self.quaternion.asArray(),vector) + ro = qu2ro(self.quaternion.asArray()) + return ro[:3]*ro[3] if vector else ro def asHomochoric(self): """Homochoric vector: (h_1, h_2, h_3)""" @@ -298,7 +356,7 @@ class Rotation: return qu2cu(self.quaternion.asArray()) def asM(self): - """Intermediate representation useful fro quaternion averaging (see F. Landis Markley et al.)""" + """Intermediate representation supporting quaternion averaging (see F. Landis Markley et al.)""" return self.quaternion.asM() @@ -409,63 +467,32 @@ class Rotation: return cls(ho2qu(ho)) - def __mul__(self, other): + @classmethod + def average(cls, + rotations, + weights = []): """ - Multiplication - - Rotation: Details needed (active/passive), rotation of (3,3,3,3)-matrix should be considered + Average rotation + + ref: F. Landis Markley, Yang Cheng, John Lucas Crassidis, and Yaakov Oshman. + Averaging Quaternions, + Journal of Guidance, Control, and Dynamics, Vol. 30, No. 4 (2007), pp. 1193-1197. + doi: 10.2514/1.28949 """ - if isinstance(other, Rotation): # rotate a rotation - return self.__class__((self.quaternion * other.quaternion).asArray()) - elif isinstance(other, np.ndarray): - if other.shape == (3,): # rotate a single (3)-vector - ( x, y, z) = self.quaternion.p - (Vx,Vy,Vz) = other[0:3] - A = self.quaternion.q*self.quaternion.q - np.dot(self.quaternion.p,self.quaternion.p) - B = 2.0 * (x*Vx + y*Vy + z*Vz) - C = 2.0 * P*self.quaternion.q + if not all(isinstance(item, Rotation) for item in rotations): + raise TypeError("Only instances of Rotation can be averaged.") - return np.array([ - A*Vx + B*x + C*(y*Vz - z*Vy), - A*Vy + B*y + C*(z*Vx - x*Vz), - A*Vz + B*z + C*(x*Vy - y*Vx), - ]) - elif other.shape == (3,3,): # rotate a single (3x3)-matrix - return np.dot(self.asMatrix(),np.dot(other,self.asMatrix().T)) - elif other.shape == (3,3,3,3): - raise NotImplementedError - else: - return NotImplemented - elif isinstance(other, tuple): # used to rotate a meshgrid-tuple - ( x, y, z) = self.quaternion.p - (Vx,Vy,Vz) = other[0:3] - A = self.quaternion.q*self.quaternion.q - np.dot(self.quaternion.p,self.quaternion.p) - B = 2.0 * (x*Vx + y*Vy + z*Vz) - C = 2.0 * P*self.quaternion.q + N = len(rotations) + if weights == [] or not weights: + weights = np.ones(N,dtype='i') - return np.array([ - A*Vx + B*x + C*(y*Vz - z*Vy), - A*Vy + B*y + C*(z*Vx - x*Vz), - A*Vz + B*z + C*(x*Vy - y*Vx), - ]) - else: - return NotImplemented - - - def inverse(self): - """Inverse rotation/backward rotation""" - self.quaternion.conjugate() - return self - - def inversed(self): - """In-place inverse rotation/backward rotation""" - return self.__class__(self.quaternion.conjugated()) + for i,(r,n) in enumerate(zip(rotations,weights)): + M = r.asM() * n if i == 0 \ + else M + r.asM() * n # noqa add (multiples) of this rotation to average noqa + eig, vec = np.linalg.eig(M/N) + return Rotation.fromQuaternion(np.real(vec.T[eig.argmax()]),acceptHomomorph = True) - def misorientation(self,other): - """Misorientation""" - return self.__class__(other.quaternion*self.quaternion.conjugated()) - # ****************************************************************************************** class Symmetry: @@ -511,7 +538,7 @@ class Symmetry: return (myOrder > otherOrder) - (myOrder < otherOrder) def symmetryOperations(self,members=[]): - """List of symmetry operations as quaternions.""" + """List (or single element) of symmetry operations as rotations.""" if self.lattice == 'cubic': symQuats = [ [ 1.0, 0.0, 0.0, 0.0 ], @@ -880,7 +907,7 @@ class Lattice: # Greninger--Troiano' orientation relationship for fcc <-> bcc transformation # from Y. He et al./Journal of Applied Crystallography (2006). 39, 72-81 - GTdash = {'mapping':{'fcc':0,'bcc':1}, + GTprime = {'mapping':{'fcc':0,'bcc':1}, 'planes': np.array([ [[ 7, 17, 17],[ 12, 5, 17]], [[ 17, 7, 17],[ 17, 12, 5]], @@ -1006,7 +1033,7 @@ class Lattice: def relationOperations(self,model): - models={'KS':self.KS, 'GT':self.GT, "GT'":self.GTdash, + models={'KS':self.KS, 'GT':self.GT, "GT'":self.GTprime, 'NW':self.NW, 'Pitsch': self.Pitsch, 'Bain':self.Bain} try: relationship = models[model] @@ -1154,7 +1181,7 @@ class Orientation: @classmethod def average(cls, orientations, - multiplicity = []): + weights = []): """ Average orientation @@ -1168,22 +1195,17 @@ class Orientation: avg = Orientation.average([a,b]) """ if not all(isinstance(item, Orientation) for item in orientations): - print('got a list of {}'.format(orientations)) raise TypeError("Only instances of Orientation can be averaged.") - N = len(orientations) - if multiplicity == [] or not multiplicity: - multiplicity = np.ones(N,dtype='i') + closest = [] + ref = orientations[0] + for o in orientations: + closest.append(o.equivalentOrientations( + ref.disorientation(o, + SST = False, # select (o[ther]'s) sym orientation + symmetries = True)[2]).rotation) # with lowest misorientation - ref = orientations[0] # take first as reference - for i,(o,n) in enumerate(zip(orientations,multiplicity)): - closest = o.equivalentOrientations(ref.disorientation(o,SST=False,symmetries=True)[2])[0] # select sym orientation with lowest misorientation - M = closest.rotation.asM() * n if i == 0 \ - else M + closest.rotation.asM() * n # noqa add (multiples) of this orientation to average noqa - eig, vec = np.linalg.eig(M/N) - - return Orientation(Rotation.fromQuaternion(np.real(vec.T[eig.argmax()]),acceptHomomorph = True), - ref.lattice) + return Orientation(Rotation.average(closest,weights),ref.lattice) #################################################################################################### @@ -1275,7 +1297,7 @@ def qu2ax(qu): return np.array(ax) -def qu2ro(qu,vector=False): +def qu2ro(qu): """Quaternion to Rodrigues vector""" if iszero(qu[0]): ro = [qu[1], qu[2], qu[3], np.inf] @@ -1284,7 +1306,7 @@ def qu2ro(qu,vector=False): ro = [0.0,0.0,P,0.0] if iszero(s) else \ [ qu[1]/s, qu[2]/s, qu[3]/s, np.tan(np.arccos(np.clip(qu[0],-1.0,1.0)))] # avoid numerical difficulties - return np.array(ro[:3])*ro[3] if vector else np.array(ro) + return np.array(ro) def qu2ho(qu): @@ -1354,9 +1376,9 @@ def om2qu(om): return ax2qu(om2ax(om)) -def om2ro(om,vector=False): +def om2ro(om): """Orientation matrix to Rodriques vector""" - return eu2ro(om2eu(om,vector)) + return eu2ro(om2eu(om)) def om2cu(om): @@ -1404,7 +1426,7 @@ def eu2ax(eu): return ax -def eu2ro(eu,vector=False): +def eu2ro(eu): """Euler angles to Rodrigues vector""" ro = eu2ax(eu) # convert to axis angle representation if ro[3] >= np.pi: # Differs from original implementation. check convention 5 @@ -1414,7 +1436,7 @@ def eu2ro(eu,vector=False): else: ro[3] = np.tan(ro[3]*0.5) - return ro[:3] * ro[3] if vector else ro + return ro def eu2ho(eu): @@ -1463,7 +1485,7 @@ def ax2om(ax): return om if P < 0.0 else om.T -def ax2ro(ax,vector=False): +def ax2ro(ax): """Axis angle to Rodrigues vector""" if iszero(ax[3]): ro = [ 0.0, 0.0, P, 0.0 ] @@ -1473,7 +1495,7 @@ def ax2ro(ax,vector=False): ro += [np.inf] if np.isclose(ax[3],np.pi,atol=1.0e-15,rtol=0.0) else \ [np.tan(ax[3]*0.5)] - return np.array(ro[:3])*ro[3] if vector else np.array(ro) + return np.array(ro) def ax2qu(ax): @@ -1594,9 +1616,9 @@ def ho2om(ho): return ax2om(ho2ax(ho)) -def ho2ro(ho,vector=False): +def ho2ro(ho): """Axis angle to Rodriques vector""" - return ax2ro(ho2ax(ho,vector)) + return ax2ro(ho2ax(ho)) def ho2qu(ho): @@ -1619,9 +1641,9 @@ def cu2ax(cu): return ho2ax(cu2ho(cu)) -def cu2ro(cu,vector=False): +def cu2ro(cu): """Cubochoric to Rodrigues vector""" - return ho2ro(cu2ho(cu,vector)) + return ho2ro(cu2ho(cu)) def cu2qu(cu): From 18f9deef1a7f59b9ebc26cacaafcc2368a91a528 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 15 Apr 2019 15:27:58 +0200 Subject: [PATCH 11/61] fixed deadlock --- src/grid_mech_spectral_basic.f90 | 1 - src/grid_mech_spectral_polarisation.f90 | 19 +++++++------------ 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/grid_mech_spectral_basic.f90 b/src/grid_mech_spectral_basic.f90 index 2ed8bc683..d07c4c4d9 100644 --- a/src/grid_mech_spectral_basic.f90 +++ b/src/grid_mech_spectral_basic.f90 @@ -335,7 +335,6 @@ subroutine grid_mech_spectral_basic_forward(guess,timeinc,timeinc_old,loadCaseTi write(rankStr,'(a1,i0)')'_',worldrank fileHandle = HDF5_openFile(trim(getSolverJobName())//trim(rankStr)//'.hdf5','w') - print*, trim(getSolverJobName())//trim(rankStr)//'.hdf5';flush(6) call HDF5_write(fileHandle,F_aim, 'F_aim') call HDF5_write(fileHandle,F_aim_lastInc,'F_aim_lastInc') call HDF5_write(fileHandle,F_aimDot, 'F_aimDot') diff --git a/src/grid_mech_spectral_polarisation.f90 b/src/grid_mech_spectral_polarisation.f90 index 12183db0e..568451971 100644 --- a/src/grid_mech_spectral_polarisation.f90 +++ b/src/grid_mech_spectral_polarisation.f90 @@ -107,8 +107,7 @@ subroutine grid_mech_spectral_polarisation_init use spectral_utilities, only: & utilities_constitutiveResponse, & utilities_updateGamma, & - utilities_updateIPcoords, & - wgt + utilities_updateIPcoords use mesh, only: & grid, & grid3 @@ -196,7 +195,6 @@ subroutine grid_mech_spectral_polarisation_init call HDF5_read(fileHandle,F_lastInc, 'F_lastInc') call HDF5_read(fileHandle,F_tau, 'F_tau') call HDF5_read(fileHandle,F_tau_lastInc, 'F_tau_lastInc') - elseif (restartInc == 0) then restart F_lastInc = spread(spread(spread(math_I3,3,grid(1)),4,grid(2)),5,grid3) ! initialize to identity @@ -343,7 +341,6 @@ subroutine grid_mech_spectral_polarisation_forward(guess,timeinc,timeinc_old,loa integer :: i, j, k real(pReal), dimension(3,3) :: F_lambda33 - integer :: fileUnit integer(HID_T) :: fileHandle character(len=32) :: rankStr @@ -363,15 +360,13 @@ subroutine grid_mech_spectral_polarisation_forward(guess,timeinc,timeinc_old,loa write(rankStr,'(a1,i0)')'_',worldrank fileHandle = HDF5_openFile(trim(getSolverJobName())//trim(rankStr)//'.hdf5','w') - if (worldrank == 0) then - call HDF5_write(fileHandle,C_volAvg, 'C_volAvg') - call HDF5_write(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') - call HDF5_write(fileHandle,F_aim, 'F_aim') - call HDF5_write(fileHandle,F_aimDot, 'F_aimDot') - call HDF5_write(fileHandle,F_aim_lastInc, 'F_aim_lastInc') - endif + call HDF5_write(fileHandle,C_volAvg, 'C_volAvg') + call HDF5_write(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') + call HDF5_write(fileHandle,F_aim, 'F_aim') + call HDF5_write(fileHandle,F_aimDot, 'F_aimDot') + call HDF5_write(fileHandle,F_aim_lastInc, 'F_aim_lastInc') + - write(rankStr,'(a1,i0)')'_',worldrank call HDF5_write(fileHandle,F, 'F') call HDF5_write(fileHandle,F_lastInc, 'F_lastInc') call HDF5_write(fileHandle,F_tau, 'F_tau') From 4793f964f8cc309f8126f6c4e948164012575bc0 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 15 Apr 2019 15:53:46 +0200 Subject: [PATCH 12/61] unified style --- src/grid_mech_spectral_basic.f90 | 33 +- src/grid_mech_spectral_polarisation.f90 | 830 ++++++++++++------------ 2 files changed, 430 insertions(+), 433 deletions(-) diff --git a/src/grid_mech_spectral_basic.f90 b/src/grid_mech_spectral_basic.f90 index d07c4c4d9..06f898224 100644 --- a/src/grid_mech_spectral_basic.f90 +++ b/src/grid_mech_spectral_basic.f90 @@ -27,8 +27,7 @@ module grid_mech_spectral_basic type(tSolutionParams), private :: params type, private :: tNumerics - logical :: & - update_gamma !< update gamma operator with current stiffness + logical :: update_gamma !< update gamma operator with current stiffness end type tNumerics type(tNumerics) :: num ! numerics parameters. Better name? @@ -42,8 +41,8 @@ module grid_mech_spectral_basic !-------------------------------------------------------------------------------------------------- ! common pointwise data real(pReal), private, dimension(:,:,:,:,:), allocatable :: & - F_lastInc, & - Fdot + F_lastInc, & !< field of previous compatible deformation gradients + Fdot !< field of assumed rate of compatible deformation gradient !-------------------------------------------------------------------------------------------------- ! stress, stiffness and compliance average etc. @@ -101,8 +100,7 @@ subroutine grid_mech_spectral_basic_init use spectral_utilities, only: & utilities_constitutiveResponse, & utilities_updateGamma, & - utilities_updateIPcoords, & - wgt + utilities_updateIPcoords use mesh, only: & grid, & grid3 @@ -179,6 +177,7 @@ subroutine grid_mech_spectral_basic_init write(rankStr,'(a1,i0)')'_',worldrank fileHandle = HDF5_openFile(trim(getSolverJobName())//trim(rankStr)//'.hdf5') + call HDF5_read(fileHandle,F_aim, 'F_aim') call HDF5_read(fileHandle,F_aim_lastInc,'F_aim_lastInc') call HDF5_read(fileHandle,F_aimDot, 'F_aimDot') @@ -226,7 +225,6 @@ function grid_mech_spectral_basic_solution(incInfoIn,timeinc,timeinc_old,stress_ terminallyIll implicit none - !-------------------------------------------------------------------------------------------------- ! input data for solution character(len=*), intent(in) :: & @@ -248,8 +246,8 @@ function grid_mech_spectral_basic_solution(incInfoIn,timeinc,timeinc_old,stress_ !-------------------------------------------------------------------------------------------------- ! update stiffness (and gamma operator) - S = Utilities_maskedCompliance(rotation_BC,stress_BC%maskLogical,C_volAvg) - if (num%update_gamma) call Utilities_updateGamma(C_minMaxAvg,restartWrite) + S = utilities_maskedCompliance(rotation_BC,stress_BC%maskLogical,C_volAvg) + if (num%update_gamma) call utilities_updateGamma(C_minMaxAvg,restartWrite) !-------------------------------------------------------------------------------------------------- ! set module wide available data @@ -329,7 +327,7 @@ subroutine grid_mech_spectral_basic_forward(guess,timeinc,timeinc_old,loadCaseTi else !-------------------------------------------------------------------------------------------------- ! restart information for spectral solver - if (restartWrite) then ! QUESTION: where is this logical properly set? + if (restartWrite) then write(6,'(/,a)') ' writing converged results for restart';flush(6) write(rankStr,'(a1,i0)')'_',worldrank @@ -344,6 +342,7 @@ subroutine grid_mech_spectral_basic_forward(guess,timeinc,timeinc_old,loadCaseTi call HDF5_write(fileHandle,C_volAvg, 'C_volAvg') call HDF5_write(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') call HDF5_write(fileHandle,C_minMaxAvg, 'C_minMaxAvg') + call HDF5_closeFile(fileHandle) endif @@ -390,7 +389,7 @@ end subroutine grid_mech_spectral_basic_forward !-------------------------------------------------------------------------------------------------- !> @brief convergence check !-------------------------------------------------------------------------------------------------- -subroutine converged(snes_local,PETScIter,xnorm,snorm,fnorm,reason,dummy,ierr) +subroutine converged(snes_local,PETScIter,devNull1,devNull2,devNull3,reason,dummy,ierr) use numerics, only: & itmax, & itmin, & @@ -403,11 +402,11 @@ subroutine converged(snes_local,PETScIter,xnorm,snorm,fnorm,reason,dummy,ierr) implicit none SNES :: snes_local - PetscInt :: PETScIter - PetscReal :: & - xnorm, & ! not used - snorm, & ! not used - fnorm ! not used + PetscInt, intent(in) :: PETScIter + PetscReal, intent(in) :: & + devNull1, & + devNull2, & + devNull3 SNESConvergedReason :: reason PetscObject :: dummy PetscErrorCode :: ierr @@ -506,7 +505,7 @@ subroutine formResidual(in, F, & !-------------------------------------------------------------------------------------------------- ! evaluate constitutive response - call Utilities_constitutiveResponse(residuum, & ! "residuum" gets field of first PK stress (to save memory) + call utilities_constitutiveResponse(residuum, & ! "residuum" gets field of first PK stress (to save memory) P_av,C_volAvg,C_minMaxAvg, & F,params%timeinc,params%rotation_BC) call MPI_Allreduce(MPI_IN_PLACE,terminallyIll,1,MPI_LOGICAL,MPI_LOR,PETSC_COMM_WORLD,ierr) diff --git a/src/grid_mech_spectral_polarisation.f90 b/src/grid_mech_spectral_polarisation.f90 index 568451971..1d470bed3 100644 --- a/src/grid_mech_spectral_polarisation.f90 +++ b/src/grid_mech_spectral_polarisation.f90 @@ -7,80 +7,79 @@ module grid_mech_spectral_polarisation #include #include - use DAMASK_interface - use HDF5_utilities - use PETScdmda - use PETScsnes - use prec, only: & - pReal - use math, only: & - math_I3 - use spectral_utilities, only: & - tSolutionState, & - tSolutionParams - - implicit none - private + use DAMASK_interface + use HDF5_utilities + use PETScdmda + use PETScsnes + use prec, only: & + pReal + use math, only: & + math_I3 + use spectral_utilities, only: & + tSolutionState, & + tSolutionParams + + implicit none + private !-------------------------------------------------------------------------------------------------- ! derived types type(tSolutionParams), private :: params type, private :: tNumerics - logical :: & - update_gamma !< update gamma operator with current stiffness + logical :: update_gamma !< update gamma operator with current stiffness end type tNumerics type(tNumerics) :: num ! numerics parameters. Better name? !-------------------------------------------------------------------------------------------------- ! PETSc data - DM, private :: da - SNES, private :: snes - Vec, private :: solution_vec + DM, private :: da + SNES, private :: snes + Vec, private :: solution_vec !-------------------------------------------------------------------------------------------------- ! common pointwise data - real(pReal), private, dimension(:,:,:,:,:), allocatable :: & - F_lastInc, & !< field of previous compatible deformation gradients - F_tau_lastInc, & !< field of previous incompatible deformation gradient - Fdot, & !< field of assumed rate of compatible deformation gradient - F_tauDot !< field of assumed rate of incopatible deformation gradient + real(pReal), private, dimension(:,:,:,:,:), allocatable :: & + F_lastInc, & !< field of previous compatible deformation gradients + F_tau_lastInc, & !< field of previous incompatible deformation gradient + Fdot, & !< field of assumed rate of compatible deformation gradient + F_tauDot !< field of assumed rate of incopatible deformation gradient !-------------------------------------------------------------------------------------------------- ! stress, stiffness and compliance average etc. - real(pReal), private, dimension(3,3) :: & - F_aimDot = 0.0_pReal, & !< assumed rate of average deformation gradient - F_aim = math_I3, & !< current prescribed deformation gradient - F_aim_lastInc = math_I3, & !< previous average deformation gradient - F_av = 0.0_pReal, & !< average incompatible def grad field - P_av = 0.0_pReal !< average 1st Piola--Kirchhoff stress - - character(len=1024), private :: incInfo !< time and increment information - real(pReal), private, dimension(3,3,3,3) :: & - C_volAvg = 0.0_pReal, & !< current volume average stiffness - C_volAvgLastInc = 0.0_pReal, & !< previous volume average stiffness - C_minMaxAvg = 0.0_pReal, & !< current (min+max)/2 stiffness - C_minMaxAvgLastInc = 0.0_pReal, & !< previous (min+max)/2 stiffness - S = 0.0_pReal, & !< current compliance (filled up with zeros) - C_scale = 0.0_pReal, & - S_scale = 0.0_pReal - - real(pReal), private :: & - err_BC, & !< deviation from stress BC - err_curl, & !< RMS of curl of F - err_div !< RMS of div of P + real(pReal), private, dimension(3,3) :: & + F_aimDot = 0.0_pReal, & !< assumed rate of average deformation gradient + F_aim = math_I3, & !< current prescribed deformation gradient + F_aim_lastInc = math_I3, & !< previous average deformation gradient + F_av = 0.0_pReal, & !< average incompatible def grad field + P_av = 0.0_pReal !< average 1st Piola--Kirchhoff stress - integer, private :: & - totalIter = 0 !< total iteration in current increment + character(len=1024), private :: incInfo !< time and increment information + real(pReal), private, dimension(3,3,3,3) :: & + C_volAvg = 0.0_pReal, & !< current volume average stiffness + C_volAvgLastInc = 0.0_pReal, & !< previous volume average stiffness + C_minMaxAvg = 0.0_pReal, & !< current (min+max)/2 stiffness + C_minMaxAvgLastInc = 0.0_pReal, & !< previous (min+max)/2 stiffness + S = 0.0_pReal, & !< current compliance (filled up with zeros) + C_scale = 0.0_pReal, & + S_scale = 0.0_pReal - public :: & - grid_mech_spectral_polarisation_init, & - grid_mech_spectral_polarisation_solution, & - grid_mech_spectral_polarisation_forward - private :: & - converged, & - formResidual + real(pReal), private :: & + err_BC, & !< deviation from stress BC + err_curl, & !< RMS of curl of F + err_div !< RMS of div of P + + integer, private :: & + totalIter = 0 !< total iteration in current increment + + public :: & + grid_mech_spectral_polarisation_init, & + grid_mech_spectral_polarisation_solution, & + grid_mech_spectral_polarisation_forward + private :: & + converged, & + formResidual contains @@ -88,141 +87,142 @@ contains !> @brief allocates all necessary fields and fills them with data, potentially from restart info !-------------------------------------------------------------------------------------------------- subroutine grid_mech_spectral_polarisation_init - use IO, only: & - IO_intOut, & - IO_error, & - IO_open_jobFile_binary - use FEsolving, only: & - restartInc - use config, only :& - config_numerics - use numerics, only: & - worldrank, & - worldsize, & - petsc_options - use homogenization, only: & - materialpoint_F0 - use DAMASK_interface, only: & - getSolverJobName - use spectral_utilities, only: & - utilities_constitutiveResponse, & - utilities_updateGamma, & - utilities_updateIPcoords - use mesh, only: & - grid, & - grid3 - use math, only: & - math_invSym3333 - - implicit none - real(pReal), dimension(3,3,grid(1),grid(2),grid3) :: P - real(pReal), dimension(3,3) :: & - temp33_Real = 0.0_pReal - - PetscErrorCode :: ierr - PetscScalar, pointer, dimension(:,:,:,:) :: & - FandF_tau, & ! overall pointer to solution data - F, & ! specific (sub)pointer - F_tau ! specific (sub)pointer - PetscInt, dimension(worldsize) :: localK - integer(HID_T) :: fileHandle - integer :: fileUnit - character(len=1024) :: rankStr + use IO, only: & + IO_intOut, & + IO_error, & + IO_open_jobFile_binary + use FEsolving, only: & + restartInc + use config, only :& + config_numerics + use numerics, only: & + worldrank, & + worldsize, & + petsc_options + use homogenization, only: & + materialpoint_F0 + use DAMASK_interface, only: & + getSolverJobName + use spectral_utilities, only: & + utilities_constitutiveResponse, & + utilities_updateGamma, & + utilities_updateIPcoords + use mesh, only: & + grid, & + grid3 + use math, only: & + math_invSym3333 + + implicit none + real(pReal), dimension(3,3,grid(1),grid(2),grid3) :: P + real(pReal), dimension(3,3) :: & + temp33_Real = 0.0_pReal - write(6,'(/,a)') ' <<<+- grid_mech_spectral_polarisation init -+>>>' - - write(6,'(/,a)') ' Shanthraj et al., International Journal of Plasticity 66:31–45, 2015' - write(6,'(a)') ' https://doi.org/10.1016/j.ijplas.2014.02.006' + PetscErrorCode :: ierr + PetscScalar, pointer, dimension(:,:,:,:) :: & + FandF_tau, & ! overall pointer to solution data + F, & ! specific (sub)pointer + F_tau ! specific (sub)pointer + PetscInt, dimension(worldsize) :: localK + integer(HID_T) :: fileHandle + integer :: fileUnit + character(len=1024) :: rankStr + + write(6,'(/,a)') ' <<<+- grid_mech_spectral_polarisation init -+>>>' - num%update_gamma = config_numerics%getInt('update_gamma',defaultVal=0) > 0 + write(6,'(/,a)') ' Shanthraj et al., International Journal of Plasticity 66:31–45, 2015' + write(6,'(a)') ' https://doi.org/10.1016/j.ijplas.2014.02.006' + + num%update_gamma = config_numerics%getInt('update_gamma',defaultVal=0) > 0 !-------------------------------------------------------------------------------------------------- ! set default and user defined options for PETSc - call PETScOptionsInsertString(PETSC_NULL_OPTIONS,'-mech_snes_type ngmres',ierr) - CHKERRQ(ierr) - call PETScOptionsInsertString(PETSC_NULL_OPTIONS,trim(petsc_options),ierr) - CHKERRQ(ierr) + call PETScOptionsInsertString(PETSC_NULL_OPTIONS,'-mech_snes_type ngmres',ierr) + CHKERRQ(ierr) + call PETScOptionsInsertString(PETSC_NULL_OPTIONS,trim(petsc_options),ierr) + CHKERRQ(ierr) !-------------------------------------------------------------------------------------------------- ! allocate global fields - allocate (F_lastInc (3,3,grid(1),grid(2),grid3),source = 0.0_pReal) - allocate (Fdot (3,3,grid(1),grid(2),grid3),source = 0.0_pReal) - allocate (F_tau_lastInc(3,3,grid(1),grid(2),grid3),source = 0.0_pReal) - allocate (F_tauDot (3,3,grid(1),grid(2),grid3),source = 0.0_pReal) + allocate(F_lastInc (3,3,grid(1),grid(2),grid3),source = 0.0_pReal) + allocate(Fdot (3,3,grid(1),grid(2),grid3),source = 0.0_pReal) + allocate(F_tau_lastInc(3,3,grid(1),grid(2),grid3),source = 0.0_pReal) + allocate(F_tauDot (3,3,grid(1),grid(2),grid3),source = 0.0_pReal) !-------------------------------------------------------------------------------------------------- ! initialize solver specific parts of PETSc - call SNESCreate(PETSC_COMM_WORLD,snes,ierr); CHKERRQ(ierr) - call SNESSetOptionsPrefix(snes,'mech_',ierr);CHKERRQ(ierr) - localK = 0 - localK(worldrank+1) = grid3 - call MPI_Allreduce(MPI_IN_PLACE,localK,worldsize,MPI_INTEGER,MPI_SUM,PETSC_COMM_WORLD,ierr) - call DMDACreate3d(PETSC_COMM_WORLD, & - DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, & ! cut off stencil at boundary - DMDA_STENCIL_BOX, & ! Moore (26) neighborhood around central point - grid(1),grid(2),grid(3), & ! global grid - 1 , 1, worldsize, & - 18, 0, & ! #dof (F tensor), ghost boundary width (domain overlap) - [grid(1)],[grid(2)],localK, & ! local grid - da,ierr) ! handle, error - CHKERRQ(ierr) - call SNESSetDM(snes,da,ierr); CHKERRQ(ierr) ! connect snes to da - call DMsetFromOptions(da,ierr); CHKERRQ(ierr) - call DMsetUp(da,ierr); CHKERRQ(ierr) - call DMcreateGlobalVector(da,solution_vec,ierr); CHKERRQ(ierr) ! global solution vector (grid x 18, i.e. every def grad tensor) - call DMDASNESsetFunctionLocal(da,INSERT_VALUES,formResidual,PETSC_NULL_SNES,ierr) ! residual vector of same shape as solution vector - CHKERRQ(ierr) - call SNESsetConvergenceTest(snes,converged,PETSC_NULL_SNES,PETSC_NULL_FUNCTION,ierr) ! specify custom convergence check function "converged" - CHKERRQ(ierr) - call SNESsetFromOptions(snes,ierr); CHKERRQ(ierr) ! pull it all together with additional CLI arguments + call SNESCreate(PETSC_COMM_WORLD,snes,ierr); CHKERRQ(ierr) + call SNESSetOptionsPrefix(snes,'mech_',ierr);CHKERRQ(ierr) + localK = 0 + localK(worldrank+1) = grid3 + call MPI_Allreduce(MPI_IN_PLACE,localK,worldsize,MPI_INTEGER,MPI_SUM,PETSC_COMM_WORLD,ierr) + call DMDACreate3d(PETSC_COMM_WORLD, & + DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, & ! cut off stencil at boundary + DMDA_STENCIL_BOX, & ! Moore (26) neighborhood around central point + grid(1),grid(2),grid(3), & ! global grid + 1 , 1, worldsize, & + 18, 0, & ! #dof (F tensor), ghost boundary width (domain overlap) + [grid(1)],[grid(2)],localK, & ! local grid + da,ierr) ! handle, error + CHKERRQ(ierr) + call SNESSetDM(snes,da,ierr); CHKERRQ(ierr) ! connect snes to da + call DMsetFromOptions(da,ierr); CHKERRQ(ierr) + call DMsetUp(da,ierr); CHKERRQ(ierr) + call DMcreateGlobalVector(da,solution_vec,ierr); CHKERRQ(ierr) ! global solution vector (grid x 18, i.e. every def grad tensor) + call DMDASNESsetFunctionLocal(da,INSERT_VALUES,formResidual,PETSC_NULL_SNES,ierr) ! residual vector of same shape as solution vector + CHKERRQ(ierr) + call SNESsetConvergenceTest(snes,converged,PETSC_NULL_SNES,PETSC_NULL_FUNCTION,ierr) ! specify custom convergence check function "converged" + CHKERRQ(ierr) + call SNESsetFromOptions(snes,ierr); CHKERRQ(ierr) ! pull it all together with additional CLI arguments !-------------------------------------------------------------------------------------------------- ! init fields - call DMDAVecGetArrayF90(da,solution_vec,FandF_tau,ierr); CHKERRQ(ierr) ! places pointer on PETSc data - F => FandF_tau( 0: 8,:,:,:) - F_tau => FandF_tau( 9:17,:,:,:) + call DMDAVecGetArrayF90(da,solution_vec,FandF_tau,ierr); CHKERRQ(ierr) ! places pointer on PETSc data + F => FandF_tau( 0: 8,:,:,:) + F_tau => FandF_tau( 9:17,:,:,:) + + restart: if (restartInc > 0) then + write(6,'(/,a,'//IO_intOut(restartInc)//',a)') ' reading values of increment ', restartInc, ' from file' + + write(rankStr,'(a1,i0)')'_',worldrank + fileHandle = HDF5_openFile(trim(getSolverJobName())//trim(rankStr)//'.hdf5') + + call HDF5_read(fileHandle,F_aim, 'F_aim') + call HDF5_read(fileHandle,F_aim_lastInc,'F_aim_lastInc') + call HDF5_read(fileHandle,F_aimDot, 'F_aimDot') + call HDF5_read(fileHandle,F, 'F') + call HDF5_read(fileHandle,F_lastInc, 'F_lastInc') + call HDF5_read(fileHandle,F_tau, 'F_tau') + call HDF5_read(fileHandle,F_tau_lastInc,'F_tau_lastInc') + + elseif (restartInc == 0) then restart + F_lastInc = spread(spread(spread(math_I3,3,grid(1)),4,grid(2)),5,grid3) ! initialize to identity + F = reshape(F_lastInc,[9,grid(1),grid(2),grid3]) + F_tau = 2.0_pReal*F + F_tau_lastInc = 2.0_pReal*F_lastInc + endif restart + + materialpoint_F0 = reshape(F_lastInc, [3,3,1,product(grid(1:2))*grid3]) ! set starting condition for materialpoint_stressAndItsTangent + call Utilities_updateIPcoords(reshape(F,shape(F_lastInc))) + call Utilities_constitutiveResponse(P,temp33_Real,C_volAvg,C_minMaxAvg, & ! stress field, stress avg, global average of stiffness and (min+max)/2 + reshape(F,shape(F_lastInc)), & ! target F + 0.0_pReal, & ! time increment + math_I3) ! no rotation of boundary condition + call DMDAVecRestoreArrayF90(da,solution_vec,FandF_tau,ierr); CHKERRQ(ierr) ! deassociate pointer + + restartRead: if (restartInc > 0) then + write(6,'(/,a,'//IO_intOut(restartInc)//',a)') ' reading more values of increment ', restartInc, ' from file' + call HDF5_read(fileHandle,C_volAvg, 'C_volAvg') + call HDF5_read(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') + call HDF5_closeFile(fileHandle) - restart: if (restartInc > 0) then - write(6,'(/,a,'//IO_intOut(restartInc)//',a)') ' reading values of increment ', restartInc, ' from file' - - write(rankStr,'(a1,i0)')'_',worldrank - fileHandle = HDF5_openFile(trim(getSolverJobName())//trim(rankStr)//'.hdf5') - - call HDF5_read(fileHandle,F_aim, 'F_aim') - call HDF5_read(fileHandle,F_aim_lastInc,'F_aim_lastInc') - call HDF5_read(fileHandle,F_aimDot, 'F_aimDot') - call HDF5_read(fileHandle,F, 'F') - call HDF5_read(fileHandle,F_lastInc, 'F_lastInc') - call HDF5_read(fileHandle,F_tau, 'F_tau') - call HDF5_read(fileHandle,F_tau_lastInc, 'F_tau_lastInc') - - elseif (restartInc == 0) then restart - F_lastInc = spread(spread(spread(math_I3,3,grid(1)),4,grid(2)),5,grid3) ! initialize to identity - F = reshape(F_lastInc,[9,grid(1),grid(2),grid3]) - F_tau = 2.0_pReal*F - F_tau_lastInc = 2.0_pReal*F_lastInc - endif restart - - materialpoint_F0 = reshape(F_lastInc, [3,3,1,product(grid(1:2))*grid3]) ! set starting condition for materialpoint_stressAndItsTangent - call Utilities_updateIPcoords(reshape(F,shape(F_lastInc))) - call Utilities_constitutiveResponse(P,temp33_Real,C_volAvg,C_minMaxAvg, & ! stress field, stress avg, global average of stiffness and (min+max)/2 - reshape(F,shape(F_lastInc)), & ! target F - 0.0_pReal, & ! time increment - math_I3) ! no rotation of boundary condition - call DMDAVecRestoreArrayF90(da,solution_vec,FandF_tau,ierr); CHKERRQ(ierr) ! deassociate pointer - - restartRead: if (restartInc > 0) then - write(6,'(/,a,'//IO_intOut(restartInc)//',a)') ' reading more values of increment ', restartInc, ' from file' - call HDF5_read(fileHandle,C_volAvg, 'C_volAvg') - call HDF5_read(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') - call HDF5_closeFile(fileHandle) - fileUnit = IO_open_jobFile_binary('C_ref') - read(fileUnit) C_minMaxAvg; close(fileUnit) - endif restartRead - - call Utilities_updateGamma(C_minMaxAvg,.true.) - C_scale = C_minMaxAvg - S_scale = math_invSym3333(C_minMaxAvg) + fileUnit = IO_open_jobFile_binary('C_ref') + read(fileUnit) C_minMaxAvg; close(fileUnit) + endif restartRead + + call Utilities_updateGamma(C_minMaxAvg,.true.) + C_scale = C_minMaxAvg + S_scale = math_invSym3333(C_minMaxAvg) end subroutine grid_mech_spectral_polarisation_init @@ -231,66 +231,65 @@ end subroutine grid_mech_spectral_polarisation_init !> @brief solution for the Polarisation scheme with internal iterations !-------------------------------------------------------------------------------------------------- function grid_mech_spectral_polarisation_solution(incInfoIn,timeinc,timeinc_old,stress_BC,rotation_BC) result(solution) - use math, only: & - math_invSym3333 - use spectral_utilities, only: & - tBoundaryCondition, & - utilities_maskedCompliance, & - utilities_updateGamma - use FEsolving, only: & - restartWrite, & - terminallyIll + use math, only: & + math_invSym3333 + use spectral_utilities, only: & + tBoundaryCondition, & + utilities_maskedCompliance, & + utilities_updateGamma + use FEsolving, only: & + restartWrite, & + terminallyIll implicit none - !-------------------------------------------------------------------------------------------------- ! input data for solution - character(len=*), intent(in) :: & - incInfoIn - real(pReal), intent(in) :: & - timeinc, & !< time increment of current solution - timeinc_old !< time increment of last successful increment - type(tBoundaryCondition), intent(in) :: & - stress_BC - real(pReal), dimension(3,3), intent(in) :: rotation_BC - type(tSolutionState) :: & - solution + character(len=*), intent(in) :: & + incInfoIn + real(pReal), intent(in) :: & + timeinc, & !< time increment of current solution + timeinc_old !< time increment of last successful increment + type(tBoundaryCondition), intent(in) :: & + stress_BC + real(pReal), dimension(3,3), intent(in) :: rotation_BC + type(tSolutionState) :: & + solution !-------------------------------------------------------------------------------------------------- ! PETSc Data - PetscErrorCode :: ierr - SNESConvergedReason :: reason - - incInfo = incInfoIn + PetscErrorCode :: ierr + SNESConvergedReason :: reason + + incInfo = incInfoIn !-------------------------------------------------------------------------------------------------- ! update stiffness (and gamma operator) - S = Utilities_maskedCompliance(rotation_BC,stress_BC%maskLogical,C_volAvg) - if (num%update_gamma) then - call utilities_updateGamma(C_minMaxAvg,restartWrite) - C_scale = C_minMaxAvg - S_scale = math_invSym3333(C_minMaxAvg) - endif + S = utilities_maskedCompliance(rotation_BC,stress_BC%maskLogical,C_volAvg) + if (num%update_gamma) then + call utilities_updateGamma(C_minMaxAvg,restartWrite) + C_scale = C_minMaxAvg + S_scale = math_invSym3333(C_minMaxAvg) + endif !-------------------------------------------------------------------------------------------------- ! set module wide available data - params%stress_mask = stress_BC%maskFloat - params%stress_BC = stress_BC%values - params%rotation_BC = rotation_BC - params%timeinc = timeinc - params%timeincOld = timeinc_old + params%stress_mask = stress_BC%maskFloat + params%stress_BC = stress_BC%values + params%rotation_BC = rotation_BC + params%timeinc = timeinc + params%timeincOld = timeinc_old !-------------------------------------------------------------------------------------------------- ! solve BVP - call SNESsolve(snes,PETSC_NULL_VEC,solution_vec,ierr); CHKERRQ(ierr) + call SNESsolve(snes,PETSC_NULL_VEC,solution_vec,ierr); CHKERRQ(ierr) !-------------------------------------------------------------------------------------------------- ! check convergence - call SNESGetConvergedReason(snes,reason,ierr); CHKERRQ(ierr) - - solution%converged = reason > 0 - solution%iterationsNeeded = totalIter - solution%termIll = terminallyIll - terminallyIll = .false. + call SNESGetConvergedReason(snes,reason,ierr); CHKERRQ(ierr) + + solution%converged = reason > 0 + solution%iterationsNeeded = totalIter + solution%termIll = terminallyIll + terminallyIll = .false. end function grid_mech_spectral_polarisation_solution @@ -324,13 +323,12 @@ subroutine grid_mech_spectral_polarisation_forward(guess,timeinc,timeinc_old,loa use FEsolving, only: & restartWrite - implicit none logical, intent(in) :: & guess real(pReal), intent(in) :: & timeinc_old, & timeinc, & - loadCaseTime !< remaining time of current load case + loadCaseTime !< remaining time of current load case type(tBoundaryCondition), intent(in) :: & stress_BC, & deformation_BC @@ -349,30 +347,29 @@ subroutine grid_mech_spectral_polarisation_forward(guess,timeinc,timeinc_old,loa F_tau => FandF_tau( 9:17,:,:,:) if (cutBack) then - C_volAvg = C_volAvgLastInc ! QUESTION: where is this required? - C_minMaxAvg = C_minMaxAvgLastInc ! QUESTION: where is this required? + C_volAvg = C_volAvgLastInc ! QUESTION: where is this required? + C_minMaxAvg = C_minMaxAvgLastInc ! QUESTION: where is this required? else !-------------------------------------------------------------------------------------------------- ! restart information for spectral solver - if (restartWrite) then ! QUESTION: where is this logical properly set? + if (restartWrite) then write(6,'(/,a)') ' writing converged results for restart';flush(6) write(rankStr,'(a1,i0)')'_',worldrank fileHandle = HDF5_openFile(trim(getSolverJobName())//trim(rankStr)//'.hdf5','w') + call HDF5_write(fileHandle,F_aim, 'F_aim') + call HDF5_write(fileHandle,F_aim_lastInc, 'F_aim_lastInc') + call HDF5_write(fileHandle,F_aimDot, 'F_aimDot') + call HDF5_write(fileHandle,F, 'F') + call HDF5_write(fileHandle,F_lastInc, 'F_lastInc') + call HDF5_write(fileHandle,F_tau, 'F_tau') + call HDF5_write(fileHandle,F_tau_lastInc, 'F_tau_lastInc') + call HDF5_write(fileHandle,C_volAvg, 'C_volAvg') call HDF5_write(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') - call HDF5_write(fileHandle,F_aim, 'F_aim') - call HDF5_write(fileHandle,F_aimDot, 'F_aimDot') - call HDF5_write(fileHandle,F_aim_lastInc, 'F_aim_lastInc') - - call HDF5_write(fileHandle,F, 'F') - call HDF5_write(fileHandle,F_lastInc, 'F_lastInc') - call HDF5_write(fileHandle,F_tau, 'F_tau') - call HDF5_write(fileHandle,F_tau_lastInc, 'F_tau_lastInc') call HDF5_closeFile(fileHandle) - endif call CPFEM_age ! age state and kinematics @@ -386,13 +383,13 @@ subroutine grid_mech_spectral_polarisation_forward(guess,timeinc,timeinc_old,loa !-------------------------------------------------------------------------------------------------- ! calculate rate for aim - if (deformation_BC%myType=='l') then ! calculate F_aimDot from given L and current F + if (deformation_BC%myType=='l') then ! calculate F_aimDot from given L and current F F_aimDot = & F_aimDot + deformation_BC%maskFloat * matmul(deformation_BC%values, F_aim_lastInc) - elseif(deformation_BC%myType=='fdot') then ! F_aimDot is prescribed + elseif(deformation_BC%myType=='fdot') then ! F_aimDot is prescribed F_aimDot = & F_aimDot + deformation_BC%maskFloat * deformation_BC%values - elseif (deformation_BC%myType=='f') then ! aim at end of load case is prescribed + elseif (deformation_BC%myType=='f') then ! aim at end of load case is prescribed F_aimDot = & F_aimDot + deformation_BC%maskFloat * (deformation_BC%values - F_aim_lastInc)/loadCaseTime endif @@ -404,33 +401,33 @@ subroutine grid_mech_spectral_polarisation_forward(guess,timeinc,timeinc_old,loa F_tauDot = utilities_calculateRate(guess, & F_tau_lastInc,reshape(F_tau,[3,3,grid(1),grid(2),grid3]), timeinc_old, & math_rotate_backward33(F_aimDot,rotation_BC)) - F_lastInc = reshape(F, [3,3,grid(1),grid(2),grid3]) ! winding F forward - F_tau_lastInc = reshape(F_tau, [3,3,grid(1),grid(2),grid3]) ! winding F_tau forward - materialpoint_F0 = reshape(F_lastInc, [3,3,1,product(grid(1:2))*grid3]) ! set starting condition for materialpoint_stressAndItsTangent + F_lastInc = reshape(F, [3,3,grid(1),grid(2),grid3]) ! winding F forward + F_tau_lastInc = reshape(F_tau, [3,3,grid(1),grid(2),grid3]) ! winding F_tau forward + materialpoint_F0 = reshape(F_lastInc, [3,3,1,product(grid(1:2))*grid3]) ! set starting condition for materialpoint_stressAndItsTangent endif !-------------------------------------------------------------------------------------------------- ! update average and local deformation gradients F_aim = F_aim_lastInc + F_aimDot * timeinc - F = reshape(utilities_forwardField(timeinc,F_lastInc,Fdot, & ! estimate of F at end of time+timeinc that matches rotated F_aim on average + F = reshape(utilities_forwardField(timeinc,F_lastInc,Fdot, & ! estimate of F at end of time+timeinc that matches rotated F_aim on average math_rotate_backward33(F_aim,rotation_BC)),& [9,grid(1),grid(2),grid3]) - if (guess) then - F_tau = reshape(Utilities_forwardField(timeinc,F_tau_lastInc,F_taudot), & - [9,grid(1),grid(2),grid3]) ! does not have any average value as boundary condition - else - do k = 1, grid3; do j = 1, grid(2); do i = 1, grid(1) - F_lambda33 = reshape(F_tau(1:9,i,j,k)-F(1:9,i,j,k),[3,3]) - F_lambda33 = math_mul3333xx33(S_scale,matmul(F_lambda33, & - math_mul3333xx33(C_scale,& - matmul(transpose(F_lambda33),& - F_lambda33)-math_I3))*0.5_pReal)& - + math_I3 - F_tau(1:9,i,j,k) = reshape(F_lambda33,[9])+F(1:9,i,j,k) - enddo; enddo; enddo - endif - - call DMDAVecRestoreArrayF90(da,solution_vec,FandF_tau,ierr); CHKERRQ(ierr) + if (guess) then + F_tau = reshape(Utilities_forwardField(timeinc,F_tau_lastInc,F_taudot), & + [9,grid(1),grid(2),grid3]) ! does not have any average value as boundary condition + else + do k = 1, grid3; do j = 1, grid(2); do i = 1, grid(1) + F_lambda33 = reshape(F_tau(1:9,i,j,k)-F(1:9,i,j,k),[3,3]) + F_lambda33 = math_mul3333xx33(S_scale,matmul(F_lambda33, & + math_mul3333xx33(C_scale,& + matmul(transpose(F_lambda33),& + F_lambda33)-math_I3))*0.5_pReal)& + + math_I3 + F_tau(1:9,i,j,k) = reshape(F_lambda33,[9])+F(1:9,i,j,k) + enddo; enddo; enddo + endif + + call DMDAVecRestoreArrayF90(da,solution_vec,FandF_tau,ierr); CHKERRQ(ierr) end subroutine grid_mech_spectral_polarisation_forward @@ -438,61 +435,61 @@ end subroutine grid_mech_spectral_polarisation_forward !-------------------------------------------------------------------------------------------------- !> @brief convergence check !-------------------------------------------------------------------------------------------------- -subroutine converged(snes_local,PETScIter,xnorm,snorm,fnorm,reason,dummy,ierr) - use numerics, only: & - itmax, & - itmin, & - err_div_tolRel, & - err_div_tolAbs, & - err_curl_tolRel, & - err_curl_tolAbs, & - err_stress_tolRel, & - err_stress_tolAbs - use FEsolving, only: & - terminallyIll - - implicit none - SNES :: snes_local - PetscInt :: PETScIter - PetscReal :: & - xnorm, & ! not used - snorm, & ! not used - fnorm ! not used - SNESConvergedReason :: reason - PetscObject :: dummy - PetscErrorCode :: ierr - real(pReal) :: & - curlTol, & - divTol, & - BCTol - - curlTol = max(maxval(abs(F_aim-math_I3))*err_curl_tolRel ,err_curl_tolAbs) - divTol = max(maxval(abs(P_av)) *err_div_tolRel ,err_div_tolAbs) - BCTol = max(maxval(abs(P_av)) *err_stress_tolRel,err_stress_tolAbs) - - if ((totalIter >= itmin .and. & - all([ err_div /divTol, & - err_curl/curlTol, & - err_BC /BCTol ] < 1.0_pReal)) & - .or. terminallyIll) then - reason = 1 - elseif (totalIter >= itmax) then - reason = -1 - else - reason = 0 - endif +subroutine converged(snes_local,PETScIter,devNull1,devNull2,devNull3,reason,dummy,ierr) + use numerics, only: & + itmax, & + itmin, & + err_div_tolRel, & + err_div_tolAbs, & + err_curl_tolRel, & + err_curl_tolAbs, & + err_stress_tolRel, & + err_stress_tolAbs + use FEsolving, only: & + terminallyIll + + implicit none + SNES :: snes_local + PetscInt, intent(in) :: PETScIter + PetscReal, intent(in) :: & + devNull1, & + devNull2, & + devNull3 + SNESConvergedReason :: reason + PetscObject :: dummy + PetscErrorCode :: ierr + real(pReal) :: & + curlTol, & + divTol, & + BCTol + + curlTol = max(maxval(abs(F_aim-math_I3))*err_curl_tolRel ,err_curl_tolAbs) + divTol = max(maxval(abs(P_av)) *err_div_tolRel ,err_div_tolAbs) + BCTol = max(maxval(abs(P_av)) *err_stress_tolRel,err_stress_tolAbs) + + if ((totalIter >= itmin .and. & + all([ err_div /divTol, & + err_curl/curlTol, & + err_BC /BCTol ] < 1.0_pReal)) & + .or. terminallyIll) then + reason = 1 + elseif (totalIter >= itmax) then + reason = -1 + else + reason = 0 + endif !-------------------------------------------------------------------------------------------------- ! report - write(6,'(1/,a)') ' ... reporting .............................................................' - write(6,'(1/,a,f12.2,a,es8.2,a,es9.2,a)') ' error divergence = ', & - err_div/divTol, ' (',err_div, ' / m, tol = ',divTol,')' - write(6, '(a,f12.2,a,es8.2,a,es9.2,a)') ' error curl = ', & - err_curl/curlTol,' (',err_curl,' -, tol = ',curlTol,')' - write(6, '(a,f12.2,a,es8.2,a,es9.2,a)') ' error BC = ', & - err_BC/BCTol, ' (',err_BC, ' Pa, tol = ',BCTol,')' - write(6,'(/,a)') ' ===========================================================================' - flush(6) + write(6,'(1/,a)') ' ... reporting .............................................................' + write(6,'(1/,a,f12.2,a,es8.2,a,es9.2,a)') ' error divergence = ', & + err_div/divTol, ' (',err_div, ' / m, tol = ',divTol,')' + write(6, '(a,f12.2,a,es8.2,a,es9.2,a)') ' error curl = ', & + err_curl/curlTol,' (',err_curl,' -, tol = ',curlTol,')' + write(6, '(a,f12.2,a,es8.2,a,es9.2,a)') ' error BC = ', & + err_BC/BCTol, ' (',err_BC, ' Pa, tol = ',BCTol,')' + write(6,'(/,a)') ' ===========================================================================' + flush(6) end subroutine converged @@ -502,144 +499,145 @@ end subroutine converged !-------------------------------------------------------------------------------------------------- subroutine formResidual(in, FandF_tau, & residuum, dummy,ierr) - use numerics, only: & - itmax, & - itmin, & - polarAlpha, & - polarBeta - use mesh, only: & - grid, & - grid3 - use math, only: & - math_rotate_forward33, & - math_rotate_backward33, & - math_mul3333xx33, & - math_invSym3333 - use debug, only: & - debug_level, & - debug_spectral, & - debug_spectralRotation - use spectral_utilities, only: & - wgt, & - tensorField_real, & - utilities_FFTtensorForward, & - utilities_fourierGammaConvolution, & - utilities_FFTtensorBackward, & - utilities_constitutiveResponse, & - utilities_divergenceRMS, & - utilities_curlRMS - use IO, only: & - IO_intOut - use homogenization, only: & - materialpoint_dPdF - use FEsolving, only: & - terminallyIll + use numerics, only: & + itmax, & + itmin, & + polarAlpha, & + polarBeta + use mesh, only: & + grid, & + grid3 + use math, only: & + math_rotate_forward33, & + math_rotate_backward33, & + math_mul3333xx33, & + math_invSym3333 + use debug, only: & + debug_level, & + debug_spectral, & + debug_spectralRotation + use spectral_utilities, only: & + wgt, & + tensorField_real, & + utilities_FFTtensorForward, & + utilities_fourierGammaConvolution, & + utilities_FFTtensorBackward, & + utilities_constitutiveResponse, & + utilities_divergenceRMS, & + utilities_curlRMS + use IO, only: & + IO_intOut + use homogenization, only: & + materialpoint_dPdF + use FEsolving, only: & + terminallyIll - implicit none - DMDALocalInfo, dimension(DMDA_LOCAL_INFO_SIZE) :: in !< DMDA info (needs to be named "in" for macros like XRANGE to work) - PetscScalar, dimension(3,3,2,XG_RANGE,YG_RANGE,ZG_RANGE), & - target, intent(in) :: FandF_tau - PetscScalar, dimension(3,3,2,X_RANGE,Y_RANGE,Z_RANGE),& - target, intent(out) :: residuum !< residuum field - PetscScalar, pointer, dimension(:,:,:,:,:) :: & - F, & - F_tau, & - residual_F, & - residual_F_tau - PetscInt :: & - PETScIter, & - nfuncs - PetscObject :: dummy - PetscErrorCode :: ierr - integer :: & - i, j, k, e + implicit none + DMDALocalInfo, dimension(DMDA_LOCAL_INFO_SIZE) :: in !< DMDA info (needs to be named "in" for macros like XRANGE to work) + PetscScalar, dimension(3,3,2,XG_RANGE,YG_RANGE,ZG_RANGE), & + target, intent(in) :: FandF_tau + PetscScalar, dimension(3,3,2,X_RANGE,Y_RANGE,Z_RANGE),& + target, intent(out) :: residuum !< residuum field + PetscScalar, pointer, dimension(:,:,:,:,:) :: & + F, & + F_tau, & + residual_F, & + residual_F_tau + PetscInt :: & + PETScIter, & + nfuncs + PetscObject :: dummy + PetscErrorCode :: ierr + integer :: & + i, j, k, e - F => FandF_tau(1:3,1:3,1,& - XG_RANGE,YG_RANGE,ZG_RANGE) - F_tau => FandF_tau(1:3,1:3,2,& - XG_RANGE,YG_RANGE,ZG_RANGE) - residual_F => residuum(1:3,1:3,1,& - X_RANGE, Y_RANGE, Z_RANGE) - residual_F_tau => residuum(1:3,1:3,2,& - X_RANGE, Y_RANGE, Z_RANGE) + F => FandF_tau(1:3,1:3,1,& + XG_RANGE,YG_RANGE,ZG_RANGE) + F_tau => FandF_tau(1:3,1:3,2,& + XG_RANGE,YG_RANGE,ZG_RANGE) + residual_F => residuum(1:3,1:3,1,& + X_RANGE, Y_RANGE, Z_RANGE) + residual_F_tau => residuum(1:3,1:3,2,& + X_RANGE, Y_RANGE, Z_RANGE) - F_av = sum(sum(sum(F,dim=5),dim=4),dim=3) * wgt - call MPI_Allreduce(MPI_IN_PLACE,F_av,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - - call SNESGetNumberFunctionEvals(snes,nfuncs,ierr); CHKERRQ(ierr) - call SNESGetIterationNumber(snes,PETScIter,ierr); CHKERRQ(ierr) + F_av = sum(sum(sum(F,dim=5),dim=4),dim=3) * wgt + call MPI_Allreduce(MPI_IN_PLACE,F_av,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + + call SNESGetNumberFunctionEvals(snes,nfuncs,ierr); CHKERRQ(ierr) + call SNESGetIterationNumber(snes,PETScIter,ierr); CHKERRQ(ierr) - if (nfuncs == 0 .and. PETScIter == 0) totalIter = -1 ! new increment + if (nfuncs == 0 .and. PETScIter == 0) totalIter = -1 ! new increment !-------------------------------------------------------------------------------------------------- ! begin of new iteration - newIteration: if (totalIter <= PETScIter) then - totalIter = totalIter + 1 - write(6,'(1x,a,3(a,'//IO_intOut(itmax)//'))') & - trim(incInfo), ' @ Iteration ', itmin, '≤',totalIter, '≤', itmax - if (iand(debug_level(debug_spectral),debug_spectralRotation) /= 0) & - write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') & - ' deformation gradient aim (lab) =', transpose(math_rotate_backward33(F_aim,params%rotation_BC)) - write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') & - ' deformation gradient aim =', transpose(F_aim) - flush(6) - endif newIteration + newIteration: if (totalIter <= PETScIter) then + totalIter = totalIter + 1 + write(6,'(1x,a,3(a,'//IO_intOut(itmax)//'))') & + trim(incInfo), ' @ Iteration ', itmin, '≤',totalIter, '≤', itmax + if (iand(debug_level(debug_spectral),debug_spectralRotation) /= 0) & + write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') & + ' deformation gradient aim (lab) =', transpose(math_rotate_backward33(F_aim,params%rotation_BC)) + write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') & + ' deformation gradient aim =', transpose(F_aim) + flush(6) + endif newIteration !-------------------------------------------------------------------------------------------------- ! - tensorField_real = 0.0_pReal - do k = 1, grid3; do j = 1, grid(2); do i = 1, grid(1) - tensorField_real(1:3,1:3,i,j,k) = & - polarBeta*math_mul3333xx33(C_scale,F(1:3,1:3,i,j,k) - math_I3) -& - polarAlpha*matmul(F(1:3,1:3,i,j,k), & - math_mul3333xx33(C_scale,F_tau(1:3,1:3,i,j,k) - F(1:3,1:3,i,j,k) - math_I3)) - enddo; enddo; enddo + tensorField_real = 0.0_pReal + do k = 1, grid3; do j = 1, grid(2); do i = 1, grid(1) + tensorField_real(1:3,1:3,i,j,k) = & + polarBeta*math_mul3333xx33(C_scale,F(1:3,1:3,i,j,k) - math_I3) -& + polarAlpha*matmul(F(1:3,1:3,i,j,k), & + math_mul3333xx33(C_scale,F_tau(1:3,1:3,i,j,k) - F(1:3,1:3,i,j,k) - math_I3)) + enddo; enddo; enddo !-------------------------------------------------------------------------------------------------- ! doing convolution in Fourier space - call utilities_FFTtensorForward - call utilities_fourierGammaConvolution(math_rotate_backward33(polarBeta*F_aim,params%rotation_BC)) - call utilities_FFTtensorBackward + call utilities_FFTtensorForward + call utilities_fourierGammaConvolution(math_rotate_backward33(polarBeta*F_aim,params%rotation_BC)) + call utilities_FFTtensorBackward !-------------------------------------------------------------------------------------------------- ! constructing residual - residual_F_tau = polarBeta*F - tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) + residual_F_tau = polarBeta*F - tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) !-------------------------------------------------------------------------------------------------- ! evaluate constitutive response - call utilities_constitutiveResponse(residual_F, & ! "residuum" gets field of first PK stress (to save memory) - P_av,C_volAvg,C_minMaxAvg, & - F - residual_F_tau/polarBeta,params%timeinc,params%rotation_BC) - call MPI_Allreduce(MPI_IN_PLACE,terminallyIll,1,MPI_LOGICAL,MPI_LOR,PETSC_COMM_WORLD,ierr) + call utilities_constitutiveResponse(residual_F, & ! "residuum" gets field of first PK stress (to save memory) + P_av,C_volAvg,C_minMaxAvg, & + F - residual_F_tau/polarBeta,params%timeinc,params%rotation_BC) + call MPI_Allreduce(MPI_IN_PLACE,terminallyIll,1,MPI_LOGICAL,MPI_LOR,PETSC_COMM_WORLD,ierr) !-------------------------------------------------------------------------------------------------- ! stress BC handling - F_aim = F_aim - math_mul3333xx33(S, ((P_av - params%stress_BC))) ! S = 0.0 for no bc - err_BC = maxval(abs((1.0_pReal-params%stress_mask) * math_mul3333xx33(C_scale,F_aim & - -math_rotate_forward33(F_av,params%rotation_BC)) + & - params%stress_mask * (P_av-params%stress_BC))) ! mask = 0.0 for no bc + F_aim = F_aim - math_mul3333xx33(S, ((P_av - params%stress_BC))) ! S = 0.0 for no bc + err_BC = maxval(abs((1.0_pReal-params%stress_mask) * math_mul3333xx33(C_scale,F_aim & + -math_rotate_forward33(F_av,params%rotation_BC)) + & + params%stress_mask * (P_av-params%stress_BC))) ! mask = 0.0 for no bc ! calculate divergence - tensorField_real = 0.0_pReal - tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) = residual_F !< stress field in disguise - call utilities_FFTtensorForward - err_div = Utilities_divergenceRMS() !< root mean squared error in divergence of stress + tensorField_real = 0.0_pReal + tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) = residual_F !< stress field in disguise + call utilities_FFTtensorForward + err_div = Utilities_divergenceRMS() !< root mean squared error in divergence of stress + !-------------------------------------------------------------------------------------------------- ! constructing residual - e = 0 - do k = 1, grid3; do j = 1, grid(2); do i = 1, grid(1) - e = e + 1 - residual_F(1:3,1:3,i,j,k) = & - math_mul3333xx33(math_invSym3333(materialpoint_dPdF(1:3,1:3,1:3,1:3,1,e) + C_scale), & - residual_F(1:3,1:3,i,j,k) - matmul(F(1:3,1:3,i,j,k), & - math_mul3333xx33(C_scale,F_tau(1:3,1:3,i,j,k) - F(1:3,1:3,i,j,k) - math_I3))) & - + residual_F_tau(1:3,1:3,i,j,k) - enddo; enddo; enddo + e = 0 + do k = 1, grid3; do j = 1, grid(2); do i = 1, grid(1) + e = e + 1 + residual_F(1:3,1:3,i,j,k) = & + math_mul3333xx33(math_invSym3333(materialpoint_dPdF(1:3,1:3,1:3,1:3,1,e) + C_scale), & + residual_F(1:3,1:3,i,j,k) - matmul(F(1:3,1:3,i,j,k), & + math_mul3333xx33(C_scale,F_tau(1:3,1:3,i,j,k) - F(1:3,1:3,i,j,k) - math_I3))) & + + residual_F_tau(1:3,1:3,i,j,k) + enddo; enddo; enddo !-------------------------------------------------------------------------------------------------- ! calculating curl - tensorField_real = 0.0_pReal - tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) = F - call utilities_FFTtensorForward - err_curl = Utilities_curlRMS() + tensorField_real = 0.0_pReal + tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) = F + call utilities_FFTtensorForward + err_curl = Utilities_curlRMS() end subroutine formResidual From 19dfefc2f48ed34255e1595a7814441af4dea7c3 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 15 Apr 2019 16:16:14 +0200 Subject: [PATCH 13/61] fixed deadlock in grid_mech_FEM --- src/grid_mech_FEM.f90 | 58 ++++++++++++------------- src/grid_mech_spectral_basic.f90 | 9 ++-- src/grid_mech_spectral_polarisation.f90 | 7 +-- 3 files changed, 33 insertions(+), 41 deletions(-) diff --git a/src/grid_mech_FEM.f90 b/src/grid_mech_FEM.f90 index adcbb626b..8ec42d918 100644 --- a/src/grid_mech_FEM.f90 +++ b/src/grid_mech_FEM.f90 @@ -208,6 +208,7 @@ subroutine grid_mech_FEM_init write(rankStr,'(a1,i0)')'_',worldrank fileHandle = HDF5_openFile(trim(getSolverJobName())//trim(rankStr)//'.hdf5') + call HDF5_read(fileHandle,F_aim, 'F_aim') call HDF5_read(fileHandle,F_aim_lastInc,'F_aim_lastInc') call HDF5_read(fileHandle,F_aimDot, 'F_aimDot') @@ -221,8 +222,8 @@ subroutine grid_mech_FEM_init F = spread(spread(spread(math_I3,3,grid(1)),4,grid(2)),5,grid3) endif restart materialpoint_F0 = reshape(F_lastInc, [3,3,1,product(grid(1:2))*grid3]) ! set starting condition for materialpoint_stressAndItsTangent - call Utilities_updateIPcoords(F) - call Utilities_constitutiveResponse(P_current,temp33_Real,C_volAvg,devNull, & ! stress field, stress avg, global average of stiffness and (min+max)/2 + call utilities_updateIPcoords(F) + call utilities_constitutiveResponse(P_current,temp33_Real,C_volAvg,devNull, & ! stress field, stress avg, global average of stiffness and (min+max)/2 F, & ! target F 0.0_pReal, & ! time increment math_I3) ! no rotation of boundary condition @@ -255,7 +256,6 @@ function grid_mech_FEM_solution(incInfoIn,timeinc,timeinc_old,stress_BC,rotation terminallyIll implicit none - !-------------------------------------------------------------------------------------------------- ! input data for solution character(len=*), intent(in) :: & @@ -268,7 +268,6 @@ function grid_mech_FEM_solution(incInfoIn,timeinc,timeinc_old,stress_BC,rotation real(pReal), dimension(3,3), intent(in) :: rotation_BC type(tSolutionState) :: & solution - !-------------------------------------------------------------------------------------------------- ! PETSc Data PetscErrorCode :: ierr @@ -278,7 +277,7 @@ function grid_mech_FEM_solution(incInfoIn,timeinc,timeinc_old,stress_BC,rotation !-------------------------------------------------------------------------------------------------- ! update stiffness (and gamma operator) - S = Utilities_maskedCompliance(rotation_BC,stress_BC%maskLogical,C_volAvg) + S = utilities_maskedCompliance(rotation_BC,stress_BC%maskLogical,C_volAvg) !-------------------------------------------------------------------------------------------------- ! set module wide available data params%stress_mask = stress_BC%maskFloat @@ -357,27 +356,26 @@ subroutine grid_mech_FEM_forward(guess,timeinc,timeinc_old,loadCaseTime,deformat !-------------------------------------------------------------------------------------------------- ! restart information for spectral solver if (restartWrite) then ! QUESTION: where is this logical properly set? - write(6,'(/,a)') ' writing converged results for restart' - flush(6) + write(6,'(/,a)') ' writing converged results for restart';flush(6) write(rankStr,'(a1,i0)')'_',worldrank fileHandle = HDF5_openFile(trim(getSolverJobName())//trim(rankStr)//'.hdf5','w') - if (worldrank == 0) then - call HDF5_write(fileHandle,C_volAvg, 'C_volAvg') - call HDF5_write(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') - call HDF5_write(fileHandle,F_aim, 'F_aim') - call HDF5_write(fileHandle,F_aim_lastInc, 'F_aim_lastInc') - call HDF5_write(fileHandle,F_aimDot, 'F_aimDot') - call HDF5_write(fileHandle,F, 'F') - call HDF5_write(fileHandle,F_lastInc, 'F_lastInc') - call HDF5_write(fileHandle,u_current, 'u') - call HDF5_write(fileHandle,u_lastInc, 'u_lastInc') - call HDF5_closeFile(fileHandle) - endif + call HDF5_write(fileHandle,F_aim, 'F_aim') + call HDF5_write(fileHandle,F_aim_lastInc, 'F_aim_lastInc') + call HDF5_write(fileHandle,F_aimDot, 'F_aimDot') + call HDF5_write(fileHandle,F, 'F') + call HDF5_write(fileHandle,F_lastInc, 'F_lastInc') + call HDF5_write(fileHandle,u_current, 'u') + call HDF5_write(fileHandle,u_lastInc, 'u_lastInc') + + call HDF5_write(fileHandle,C_volAvg, 'C_volAvg') + call HDF5_write(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') + + call HDF5_closeFile(fileHandle) endif - call CPFEM_age() ! age state and kinematics + call CPFEM_age ! age state and kinematics call utilities_updateIPcoords(F) C_volAvgLastInc = C_volAvg @@ -429,9 +427,9 @@ end subroutine grid_mech_FEM_forward !-------------------------------------------------------------------------------------------------- !> @brief convergence check !-------------------------------------------------------------------------------------------------- -subroutine converged(snes_local,PETScIter,xnorm,snorm,fnorm,reason,dummy,ierr) -use mesh -use spectral_utilities +subroutine converged(snes_local,PETScIter,devNull1,devNull2,devNull3,reason,dummy,ierr) + use mesh + use spectral_utilities use numerics, only: & itmax, & itmin, & @@ -444,11 +442,11 @@ use spectral_utilities implicit none SNES :: snes_local - PetscInt :: PETScIter - PetscReal :: & - xnorm, & ! not used - snorm, & ! not used - fnorm + PetscInt, intent(in) :: PETScIter + PetscReal, intent(in) :: & + devNull1, & + devNull2, & + devNull3 SNESConvergedReason :: reason PetscObject :: dummy PetscErrorCode :: ierr @@ -461,7 +459,6 @@ use spectral_utilities divTol = max(maxval(abs(P_av))*err_div_tolRel ,err_div_tolAbs) BCTol = max(maxval(abs(P_av))*err_stress_tolRel,err_stress_tolAbs) - if ((totalIter >= itmin .and. & all([ err_div/divTol, & err_BC /BCTol ] < 1.0_pReal)) & @@ -489,7 +486,8 @@ end subroutine converged !-------------------------------------------------------------------------------------------------- !> @brief forms the residual vector !-------------------------------------------------------------------------------------------------- -subroutine formResidual(da_local,x_local,f_local,dummy,ierr) +subroutine formResidual(da_local,x_local, & + f_local,dummy,ierr) use numerics, only: & itmax, & itmin diff --git a/src/grid_mech_spectral_basic.f90 b/src/grid_mech_spectral_basic.f90 index 06f898224..91dcd03b4 100644 --- a/src/grid_mech_spectral_basic.f90 +++ b/src/grid_mech_spectral_basic.f90 @@ -117,7 +117,6 @@ subroutine grid_mech_spectral_basic_init F ! pointer to solution data PetscInt, dimension(worldsize) :: localK integer(HID_T) :: fileHandle - integer :: fileUnit character(len=1024) :: rankStr write(6,'(/,a)') ' <<<+- grid_mech_spectral_basic init -+>>>' @@ -164,7 +163,7 @@ subroutine grid_mech_spectral_basic_init call DMcreateGlobalVector(da,solution_vec,ierr); CHKERRQ(ierr) ! global solution vector (grid x 9, i.e. every def grad tensor) call DMDASNESsetFunctionLocal(da,INSERT_VALUES,formResidual,PETSC_NULL_SNES,ierr) ! residual vector of same shape as solution vector CHKERRQ(ierr) - call SNESsetConvergenceTest(snes,converged,PETSC_NULL_SNES,PETSC_NULL_FUNCTION,ierr)! specify custom convergence check function "converged" + call SNESsetConvergenceTest(snes,converged,PETSC_NULL_SNES,PETSC_NULL_FUNCTION,ierr) ! specify custom convergence check function "converged" CHKERRQ(ierr) call SNESsetFromOptions(snes,ierr); CHKERRQ(ierr) ! pull it all together with additional CLI arguments @@ -203,11 +202,9 @@ subroutine grid_mech_spectral_basic_init call HDF5_read(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') call HDF5_closeFile(fileHandle) - fileUnit = IO_open_jobFile_binary('C_ref') - read(fileUnit) C_minMaxAvg; close(fileUnit) endif restartRead - call Utilities_updateGamma(C_minMaxAvg,.true.) + call utilities_updateGamma(C_minMaxAvg,.true.) end subroutine grid_mech_spectral_basic_init @@ -442,7 +439,7 @@ end subroutine converged !-------------------------------------------------------------------------------------------------- -!> @brief forms the basic residual vector +!> @brief forms the residual vector !-------------------------------------------------------------------------------------------------- subroutine formResidual(in, F, & residuum, dummy, ierr) diff --git a/src/grid_mech_spectral_polarisation.f90 b/src/grid_mech_spectral_polarisation.f90 index 1d470bed3..a7bf75209 100644 --- a/src/grid_mech_spectral_polarisation.f90 +++ b/src/grid_mech_spectral_polarisation.f90 @@ -125,7 +125,6 @@ subroutine grid_mech_spectral_polarisation_init F_tau ! specific (sub)pointer PetscInt, dimension(worldsize) :: localK integer(HID_T) :: fileHandle - integer :: fileUnit character(len=1024) :: rankStr write(6,'(/,a)') ' <<<+- grid_mech_spectral_polarisation init -+>>>' @@ -216,11 +215,9 @@ subroutine grid_mech_spectral_polarisation_init call HDF5_read(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') call HDF5_closeFile(fileHandle) - fileUnit = IO_open_jobFile_binary('C_ref') - read(fileUnit) C_minMaxAvg; close(fileUnit) endif restartRead - call Utilities_updateGamma(C_minMaxAvg,.true.) + call utilities_updateGamma(C_minMaxAvg,.true.) C_scale = C_minMaxAvg S_scale = math_invSym3333(C_minMaxAvg) @@ -495,7 +492,7 @@ end subroutine converged !-------------------------------------------------------------------------------------------------- -!> @brief forms the polarisation residual vector +!> @brief forms the residual vector !-------------------------------------------------------------------------------------------------- subroutine formResidual(in, FandF_tau, & residuum, dummy,ierr) From 8f58f1348ea91d6b55190ee607b1a4c9dc34f357 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 15 Apr 2019 16:19:30 +0200 Subject: [PATCH 14/61] _pInt not needed --- src/grid_mech_FEM.f90 | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/grid_mech_FEM.f90 b/src/grid_mech_FEM.f90 index 8ec42d918..70332a040 100644 --- a/src/grid_mech_FEM.f90 +++ b/src/grid_mech_FEM.f90 @@ -12,7 +12,6 @@ module grid_mech_FEM use PETScdmda use PETScsnes use prec, only: & - pInt, & pReal use math, only: & math_I3 @@ -61,8 +60,8 @@ module grid_mech_FEM real(pReal), private :: & err_BC !< deviation from stress BC - integer(pInt), private :: & - totalIter = 0_pInt !< total iteration in current increment + integer, private :: & + totalIter = 0 !< total iteration in current increment public :: & grid_mech_FEM_init, & @@ -115,8 +114,7 @@ subroutine grid_mech_FEM_init 1.0_pReal,-1.0_pReal,-1.0_pReal,-1.0_pReal, & 1.0_pReal, 1.0_pReal, 1.0_pReal, 1.0_pReal], [4,8]) PetscErrorCode :: ierr - integer(pInt) :: rank - integer :: fileUnit + integer :: rank integer(HID_T) :: fileHandle character(len=1024) :: rankStr real(pReal), dimension(3,3,3,3) :: devNull @@ -232,7 +230,7 @@ subroutine grid_mech_FEM_init call DMDAVecRestoreArrayF90(mech_grid,solution_lastInc,u_lastInc,ierr) CHKERRQ(ierr) - restartRead: if (restartInc > 0_pInt) then + restartRead: if (restartInc > 0) then write(6,'(/,a,'//IO_intOut(restartInc)//',a)') 'reading more values of increment ', restartInc, ' from file' call HDF5_read(fileHandle,C_volAvg, 'C_volAvg') call HDF5_read(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') @@ -342,7 +340,6 @@ subroutine grid_mech_FEM_forward(guess,timeinc,timeinc_old,loadCaseTime,deformat rotation_BC PetscErrorCode :: ierr integer(HID_T) :: fileHandle - integer :: fileUnit character(len=32) :: rankStr PetscScalar, pointer, dimension(:,:,:,:) :: & u_current,u_lastInc @@ -530,12 +527,12 @@ subroutine formResidual(da_local,x_local, & call SNESGetNumberFunctionEvals(mech_snes,nfuncs,ierr); CHKERRQ(ierr) call SNESGetIterationNumber(mech_snes,PETScIter,ierr); CHKERRQ(ierr) - if (nfuncs == 0 .and. PETScIter == 0) totalIter = -1_pInt ! new increment + if (nfuncs == 0 .and. PETScIter == 0) totalIter = -1 ! new increment !-------------------------------------------------------------------------------------------------- ! begin of new iteration newIteration: if (totalIter <= PETScIter) then - totalIter = totalIter + 1_pInt + totalIter = totalIter + 1 write(6,'(1x,a,3(a,'//IO_intOut(itmax)//'))') & trim(incInfo), ' @ Iteration ', itmin, '≤',totalIter+1, '≤', itmax if (iand(debug_level(debug_spectral),debug_spectralRotation) /= 0) & From d0a4cbf8d5804d4e6c093970e924f206fbfabb79 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 15 Apr 2019 16:30:54 +0200 Subject: [PATCH 15/61] one implicit none is enough --- src/grid_damage_spectral.f90 | 4 - src/grid_mech_FEM.f90 | 962 ++++++++++++------------ src/grid_mech_spectral_basic.f90 | 5 - src/grid_mech_spectral_polarisation.f90 | 4 - src/grid_thermal_spectral.f90 | 4 - 5 files changed, 478 insertions(+), 501 deletions(-) diff --git a/src/grid_damage_spectral.f90 b/src/grid_damage_spectral.f90 index c5e9a254b..3ce37c5ff 100644 --- a/src/grid_damage_spectral.f90 +++ b/src/grid_damage_spectral.f90 @@ -64,7 +64,6 @@ subroutine grid_damage_spectral_init worldsize, & petsc_options - implicit none PetscInt, dimension(worldsize) :: localK integer :: i, j, k, cell DM :: damage_grid @@ -164,7 +163,6 @@ function grid_damage_spectral_solution(timeinc,timeinc_old,loadCaseTime) result( use damage_nonlocal, only: & damage_nonlocal_putNonLocalDamage - implicit none real(pReal), intent(in) :: & timeinc, & !< increment in time for current solution timeinc_old, & !< increment in time of last increment @@ -236,7 +234,6 @@ subroutine grid_damage_spectral_forward damage_nonlocal_getDiffusion33, & damage_nonlocal_getMobility - implicit none integer :: i, j, k, cell DM :: dm_local PetscScalar, dimension(:,:,:), pointer :: x_scal @@ -301,7 +298,6 @@ subroutine formResidual(in,x_scal,f_scal,dummy,ierr) damage_nonlocal_getDiffusion33, & damage_nonlocal_getMobility - implicit none DMDALocalInfo, dimension(DMDA_LOCAL_INFO_SIZE) :: & in PetscScalar, dimension( & diff --git a/src/grid_mech_FEM.f90 b/src/grid_mech_FEM.f90 index 70332a040..2feec76df 100644 --- a/src/grid_mech_FEM.f90 +++ b/src/grid_mech_FEM.f90 @@ -7,66 +7,66 @@ module grid_mech_FEM #include #include - use DAMASK_interface - use HDF5_utilities - use PETScdmda - use PETScsnes - use prec, only: & - pReal - use math, only: & - math_I3 - use spectral_utilities, only: & - tSolutionState, & - tSolutionParams - - implicit none - private + use DAMASK_interface + use HDF5_utilities + use PETScdmda + use PETScsnes + use prec, only: & + pReal + use math, only: & + math_I3 + use spectral_utilities, only: & + tSolutionState, & + tSolutionParams + + implicit none + private !-------------------------------------------------------------------------------------------------- ! derived types - type(tSolutionParams), private :: params + type(tSolutionParams), private :: params !-------------------------------------------------------------------------------------------------- ! PETSc data - DM, private :: mech_grid - SNES, private :: mech_snes - Vec, private :: solution_current, solution_lastInc, solution_rate + DM, private :: mech_grid + SNES, private :: mech_snes + Vec, private :: solution_current, solution_lastInc, solution_rate !-------------------------------------------------------------------------------------------------- ! common pointwise data - real(pReal), private, dimension(:,:,:,:,:), allocatable :: F, P_current, F_lastInc - real(pReal), private :: detJ - real(pReal), private, dimension(3) :: delta - real(pReal), private, dimension(3,8) :: BMat - real(pReal), private, dimension(8,8) :: HGMat - PetscInt, private :: xstart,ystart,zstart,xend,yend,zend + real(pReal), private, dimension(:,:,:,:,:), allocatable :: F, P_current, F_lastInc + real(pReal), private :: detJ + real(pReal), private, dimension(3) :: delta + real(pReal), private, dimension(3,8) :: BMat + real(pReal), private, dimension(8,8) :: HGMat + PetscInt, private :: xstart,ystart,zstart,xend,yend,zend !-------------------------------------------------------------------------------------------------- ! stress, stiffness and compliance average etc. - real(pReal), private, dimension(3,3) :: & - F_aimDot = 0.0_pReal, & !< assumed rate of average deformation gradient - F_aim = math_I3, & !< current prescribed deformation gradient - F_aim_lastIter = math_I3, & - F_aim_lastInc = math_I3, & !< previous average deformation gradient - P_av = 0.0_pReal !< average 1st Piola--Kirchhoff stress - - character(len=1024), private :: incInfo !< time and increment information - - real(pReal), private, dimension(3,3,3,3) :: & - C_volAvg = 0.0_pReal, & !< current volume average stiffness - C_volAvgLastInc = 0.0_pReal, & !< previous volume average stiffness - S = 0.0_pReal !< current compliance (filled up with zeros) - - real(pReal), private :: & - err_BC !< deviation from stress BC - - integer, private :: & - totalIter = 0 !< total iteration in current increment - - public :: & - grid_mech_FEM_init, & - grid_mech_FEM_solution, & - grid_mech_FEM_forward + real(pReal), private, dimension(3,3) :: & + F_aimDot = 0.0_pReal, & !< assumed rate of average deformation gradient + F_aim = math_I3, & !< current prescribed deformation gradient + F_aim_lastIter = math_I3, & + F_aim_lastInc = math_I3, & !< previous average deformation gradient + P_av = 0.0_pReal !< average 1st Piola--Kirchhoff stress + + character(len=1024), private :: incInfo !< time and increment information + + real(pReal), private, dimension(3,3,3,3) :: & + C_volAvg = 0.0_pReal, & !< current volume average stiffness + C_volAvgLastInc = 0.0_pReal, & !< previous volume average stiffness + S = 0.0_pReal !< current compliance (filled up with zeros) + + real(pReal), private :: & + err_BC !< deviation from stress BC + + integer, private :: & + totalIter = 0 !< total iteration in current increment + + public :: & + grid_mech_FEM_init, & + grid_mech_FEM_solution, & + grid_mech_FEM_forward contains @@ -78,164 +78,163 @@ subroutine grid_mech_FEM_init IO_intOut, & IO_error, & IO_open_jobFile_binary - use FEsolving, only: & - restartInc - use numerics, only: & - worldrank, & - worldsize, & - petsc_options - use homogenization, only: & - materialpoint_F0 - use DAMASK_interface, only: & - getSolverJobName - use spectral_utilities, only: & - utilities_constitutiveResponse, & - utilities_updateIPcoords, & - wgt - use mesh, only: & - geomSize, & - grid, & - grid3 - use math, only: & - math_invSym3333 - - implicit none - real(pReal) :: HGCoeff = 0e-2_pReal - PetscInt, dimension(:), allocatable :: localK - real(pReal), dimension(3,3) :: & - temp33_Real = 0.0_pReal - real(pReal), dimension(4,8) :: & - HGcomp = reshape([ 1.0_pReal, 1.0_pReal, 1.0_pReal,-1.0_pReal, & - 1.0_pReal,-1.0_pReal,-1.0_pReal, 1.0_pReal, & - -1.0_pReal, 1.0_pReal,-1.0_pReal, 1.0_pReal, & - -1.0_pReal,-1.0_pReal, 1.0_pReal,-1.0_pReal, & - -1.0_pReal,-1.0_pReal, 1.0_pReal, 1.0_pReal, & - -1.0_pReal, 1.0_pReal,-1.0_pReal,-1.0_pReal, & - 1.0_pReal,-1.0_pReal,-1.0_pReal,-1.0_pReal, & - 1.0_pReal, 1.0_pReal, 1.0_pReal, 1.0_pReal], [4,8]) - PetscErrorCode :: ierr - integer :: rank - integer(HID_T) :: fileHandle - character(len=1024) :: rankStr - real(pReal), dimension(3,3,3,3) :: devNull - PetscScalar, pointer, dimension(:,:,:,:) :: & - u_current,u_lastInc - - write(6,'(/,a)') ' <<<+- grid_mech_FEM init -+>>>' + use FEsolving, only: & + restartInc + use numerics, only: & + worldrank, & + worldsize, & + petsc_options + use homogenization, only: & + materialpoint_F0 + use DAMASK_interface, only: & + getSolverJobName + use spectral_utilities, only: & + utilities_constitutiveResponse, & + utilities_updateIPcoords, & + wgt + use mesh, only: & + geomSize, & + grid, & + grid3 + use math, only: & + math_invSym3333 + + real(pReal) :: HGCoeff = 0e-2_pReal + PetscInt, dimension(:), allocatable :: localK + real(pReal), dimension(3,3) :: & + temp33_Real = 0.0_pReal + real(pReal), dimension(4,8) :: & + HGcomp = reshape([ 1.0_pReal, 1.0_pReal, 1.0_pReal,-1.0_pReal, & + 1.0_pReal,-1.0_pReal,-1.0_pReal, 1.0_pReal, & + -1.0_pReal, 1.0_pReal,-1.0_pReal, 1.0_pReal, & + -1.0_pReal,-1.0_pReal, 1.0_pReal,-1.0_pReal, & + -1.0_pReal,-1.0_pReal, 1.0_pReal, 1.0_pReal, & + -1.0_pReal, 1.0_pReal,-1.0_pReal,-1.0_pReal, & + 1.0_pReal,-1.0_pReal,-1.0_pReal,-1.0_pReal, & + 1.0_pReal, 1.0_pReal, 1.0_pReal, 1.0_pReal], [4,8]) + PetscErrorCode :: ierr + integer :: rank + integer(HID_T) :: fileHandle + character(len=1024) :: rankStr + real(pReal), dimension(3,3,3,3) :: devNull + PetscScalar, pointer, dimension(:,:,:,:) :: & + u_current,u_lastInc + + write(6,'(/,a)') ' <<<+- grid_mech_FEM init -+>>>' !-------------------------------------------------------------------------------------------------- ! set default and user defined options for PETSc - call PETScOptionsInsertString(PETSC_NULL_OPTIONS,'-mech_snes_type newtonls -mech_ksp_type fgmres & - &-mech_ksp_max_it 25 -mech_pc_type ml -mech_mg_levels_ksp_type chebyshev',ierr) - CHKERRQ(ierr) - call PETScOptionsInsertString(PETSC_NULL_OPTIONS,trim(petsc_options),ierr) - CHKERRQ(ierr) + call PETScOptionsInsertString(PETSC_NULL_OPTIONS,'-mech_snes_type newtonls -mech_ksp_type fgmres & + &-mech_ksp_max_it 25 -mech_pc_type ml -mech_mg_levels_ksp_type chebyshev',ierr) + CHKERRQ(ierr) + call PETScOptionsInsertString(PETSC_NULL_OPTIONS,trim(petsc_options),ierr) + CHKERRQ(ierr) !-------------------------------------------------------------------------------------------------- ! allocate global fields - allocate (F (3,3,grid(1),grid(2),grid3),source = 0.0_pReal) - allocate (P_current (3,3,grid(1),grid(2),grid3),source = 0.0_pReal) - allocate (F_lastInc (3,3,grid(1),grid(2),grid3),source = 0.0_pReal) + allocate(F (3,3,grid(1),grid(2),grid3),source = 0.0_pReal) + allocate(P_current (3,3,grid(1),grid(2),grid3),source = 0.0_pReal) + allocate(F_lastInc (3,3,grid(1),grid(2),grid3),source = 0.0_pReal) !-------------------------------------------------------------------------------------------------- ! initialize solver specific parts of PETSc - call SNESCreate(PETSC_COMM_WORLD,mech_snes,ierr); CHKERRQ(ierr) - call SNESSetOptionsPrefix(mech_snes,'mech_',ierr);CHKERRQ(ierr) - allocate(localK(worldsize), source = 0); localK(worldrank+1) = grid3 - do rank = 1, worldsize - call MPI_Bcast(localK(rank),1,MPI_INTEGER,rank-1,PETSC_COMM_WORLD,ierr) - enddo - call DMDACreate3d(PETSC_COMM_WORLD, & - DM_BOUNDARY_PERIODIC, DM_BOUNDARY_PERIODIC, DM_BOUNDARY_PERIODIC, & - DMDA_STENCIL_BOX, & - grid(1),grid(2),grid(3), & - 1, 1, worldsize, & - 3, 1, & - [grid(1)],[grid(2)],localK, & - mech_grid,ierr) - CHKERRQ(ierr) - call DMDASetUniformCoordinates(mech_grid,0.0_pReal,geomSize(1),0.0_pReal,geomSize(2),0.0_pReal,geomSize(3),ierr) - CHKERRQ(ierr) - call SNESSetDM(mech_snes,mech_grid,ierr); CHKERRQ(ierr) - call DMsetFromOptions(mech_grid,ierr); CHKERRQ(ierr) - call DMsetUp(mech_grid,ierr); CHKERRQ(ierr) - call DMCreateGlobalVector(mech_grid,solution_current,ierr); CHKERRQ(ierr) - call DMCreateGlobalVector(mech_grid,solution_lastInc,ierr); CHKERRQ(ierr) - call DMCreateGlobalVector(mech_grid,solution_rate ,ierr); CHKERRQ(ierr) - call DMSNESSetFunctionLocal(mech_grid,formResidual,PETSC_NULL_SNES,ierr) - CHKERRQ(ierr) - call DMSNESSetJacobianLocal(mech_grid,formJacobian,PETSC_NULL_SNES,ierr) - CHKERRQ(ierr) - call SNESSetConvergenceTest(mech_snes,converged,PETSC_NULL_SNES,PETSC_NULL_FUNCTION,ierr) - CHKERRQ(ierr) ! specify custom convergence check function "_converged" - call SNESSetMaxLinearSolveFailures(mech_snes, huge(1), ierr); CHKERRQ(ierr) ! ignore linear solve failures - call SNESSetFromOptions(mech_snes,ierr); CHKERRQ(ierr) ! pull it all together with additional cli arguments + call SNESCreate(PETSC_COMM_WORLD,mech_snes,ierr); CHKERRQ(ierr) + call SNESSetOptionsPrefix(mech_snes,'mech_',ierr);CHKERRQ(ierr) + allocate(localK(worldsize), source = 0); localK(worldrank+1) = grid3 + do rank = 1, worldsize + call MPI_Bcast(localK(rank),1,MPI_INTEGER,rank-1,PETSC_COMM_WORLD,ierr) + enddo + call DMDACreate3d(PETSC_COMM_WORLD, & + DM_BOUNDARY_PERIODIC, DM_BOUNDARY_PERIODIC, DM_BOUNDARY_PERIODIC, & + DMDA_STENCIL_BOX, & + grid(1),grid(2),grid(3), & + 1, 1, worldsize, & + 3, 1, & + [grid(1)],[grid(2)],localK, & + mech_grid,ierr) + CHKERRQ(ierr) + call DMDASetUniformCoordinates(mech_grid,0.0_pReal,geomSize(1),0.0_pReal,geomSize(2),0.0_pReal,geomSize(3),ierr) + CHKERRQ(ierr) + call SNESSetDM(mech_snes,mech_grid,ierr); CHKERRQ(ierr) + call DMsetFromOptions(mech_grid,ierr); CHKERRQ(ierr) + call DMsetUp(mech_grid,ierr); CHKERRQ(ierr) + call DMCreateGlobalVector(mech_grid,solution_current,ierr); CHKERRQ(ierr) + call DMCreateGlobalVector(mech_grid,solution_lastInc,ierr); CHKERRQ(ierr) + call DMCreateGlobalVector(mech_grid,solution_rate ,ierr); CHKERRQ(ierr) + call DMSNESSetFunctionLocal(mech_grid,formResidual,PETSC_NULL_SNES,ierr) + CHKERRQ(ierr) + call DMSNESSetJacobianLocal(mech_grid,formJacobian,PETSC_NULL_SNES,ierr) + CHKERRQ(ierr) + call SNESSetConvergenceTest(mech_snes,converged,PETSC_NULL_SNES,PETSC_NULL_FUNCTION,ierr) ! specify custom convergence check function "_converged" + CHKERRQ(ierr) + call SNESSetMaxLinearSolveFailures(mech_snes, huge(1), ierr); CHKERRQ(ierr) ! ignore linear solve failures + call SNESSetFromOptions(mech_snes,ierr); CHKERRQ(ierr) ! pull it all together with additional cli arguments !-------------------------------------------------------------------------------------------------- ! init fields - call VecSet(solution_current,0.0_pReal,ierr);CHKERRQ(ierr) - call VecSet(solution_lastInc,0.0_pReal,ierr);CHKERRQ(ierr) - call VecSet(solution_rate ,0.0_pReal,ierr);CHKERRQ(ierr) - call DMDAVecGetArrayF90(mech_grid,solution_current,u_current,ierr); CHKERRQ(ierr) - call DMDAVecGetArrayF90(mech_grid,solution_lastInc,u_lastInc,ierr); CHKERRQ(ierr) - - call DMDAGetCorners(mech_grid,xstart,ystart,zstart,xend,yend,zend,ierr) ! local grid extent - CHKERRQ(ierr) - xend = xstart+xend-1 - yend = ystart+yend-1 - zend = zstart+zend-1 - delta = geomSize/real(grid,pReal) ! grid spacing - detJ = product(delta) ! cell volume - - BMat = reshape(real([-1.0_pReal/delta(1),-1.0_pReal/delta(2),-1.0_pReal/delta(3), & - 1.0_pReal/delta(1),-1.0_pReal/delta(2),-1.0_pReal/delta(3), & - -1.0_pReal/delta(1), 1.0_pReal/delta(2),-1.0_pReal/delta(3), & - 1.0_pReal/delta(1), 1.0_pReal/delta(2),-1.0_pReal/delta(3), & - -1.0_pReal/delta(1),-1.0_pReal/delta(2), 1.0_pReal/delta(3), & - 1.0_pReal/delta(1),-1.0_pReal/delta(2), 1.0_pReal/delta(3), & - -1.0_pReal/delta(1), 1.0_pReal/delta(2), 1.0_pReal/delta(3), & - 1.0_pReal/delta(1), 1.0_pReal/delta(2), 1.0_pReal/delta(3)],pReal), [3,8])/4.0_pReal ! shape function derivative matrix - - HGMat = matmul(transpose(HGcomp),HGcomp) & - * HGCoeff*(delta(1)*delta(2) + delta(2)*delta(3) + delta(3)*delta(1))/16.0_pReal ! hourglass stabilization matrix + call VecSet(solution_current,0.0_pReal,ierr);CHKERRQ(ierr) + call VecSet(solution_lastInc,0.0_pReal,ierr);CHKERRQ(ierr) + call VecSet(solution_rate ,0.0_pReal,ierr);CHKERRQ(ierr) + call DMDAVecGetArrayF90(mech_grid,solution_current,u_current,ierr); CHKERRQ(ierr) + call DMDAVecGetArrayF90(mech_grid,solution_lastInc,u_lastInc,ierr); CHKERRQ(ierr) + + call DMDAGetCorners(mech_grid,xstart,ystart,zstart,xend,yend,zend,ierr) ! local grid extent + CHKERRQ(ierr) + xend = xstart+xend-1 + yend = ystart+yend-1 + zend = zstart+zend-1 + delta = geomSize/real(grid,pReal) ! grid spacing + detJ = product(delta) ! cell volume + + BMat = reshape(real([-1.0_pReal/delta(1),-1.0_pReal/delta(2),-1.0_pReal/delta(3), & + 1.0_pReal/delta(1),-1.0_pReal/delta(2),-1.0_pReal/delta(3), & + -1.0_pReal/delta(1), 1.0_pReal/delta(2),-1.0_pReal/delta(3), & + 1.0_pReal/delta(1), 1.0_pReal/delta(2),-1.0_pReal/delta(3), & + -1.0_pReal/delta(1),-1.0_pReal/delta(2), 1.0_pReal/delta(3), & + 1.0_pReal/delta(1),-1.0_pReal/delta(2), 1.0_pReal/delta(3), & + -1.0_pReal/delta(1), 1.0_pReal/delta(2), 1.0_pReal/delta(3), & + 1.0_pReal/delta(1), 1.0_pReal/delta(2), 1.0_pReal/delta(3)],pReal), [3,8])/4.0_pReal ! shape function derivative matrix + + HGMat = matmul(transpose(HGcomp),HGcomp) & + * HGCoeff*(delta(1)*delta(2) + delta(2)*delta(3) + delta(3)*delta(1))/16.0_pReal ! hourglass stabilization matrix !-------------------------------------------------------------------------------------------------- ! init fields - restart: if (restartInc > 0) then - write(6,'(/,a,'//IO_intOut(restartInc)//',a)') 'reading values of increment ', restartInc, ' from file' - - write(rankStr,'(a1,i0)')'_',worldrank - fileHandle = HDF5_openFile(trim(getSolverJobName())//trim(rankStr)//'.hdf5') - - call HDF5_read(fileHandle,F_aim, 'F_aim') - call HDF5_read(fileHandle,F_aim_lastInc,'F_aim_lastInc') - call HDF5_read(fileHandle,F_aimDot, 'F_aimDot') - call HDF5_read(fileHandle,F, 'F') - call HDF5_read(fileHandle,F_lastInc, 'F_lastInc') - call HDF5_read(fileHandle,u_current, 'u') - call HDF5_read(fileHandle,u_lastInc, 'u_lastInc') - - elseif (restartInc == 0) then restart - F_lastInc = spread(spread(spread(math_I3,3,grid(1)),4,grid(2)),5,grid3) ! initialize to identity - F = spread(spread(spread(math_I3,3,grid(1)),4,grid(2)),5,grid3) - endif restart - materialpoint_F0 = reshape(F_lastInc, [3,3,1,product(grid(1:2))*grid3]) ! set starting condition for materialpoint_stressAndItsTangent - call utilities_updateIPcoords(F) - call utilities_constitutiveResponse(P_current,temp33_Real,C_volAvg,devNull, & ! stress field, stress avg, global average of stiffness and (min+max)/2 - F, & ! target F - 0.0_pReal, & ! time increment - math_I3) ! no rotation of boundary condition - call DMDAVecRestoreArrayF90(mech_grid,solution_current,u_current,ierr) - CHKERRQ(ierr) - call DMDAVecRestoreArrayF90(mech_grid,solution_lastInc,u_lastInc,ierr) - CHKERRQ(ierr) - - restartRead: if (restartInc > 0) then - write(6,'(/,a,'//IO_intOut(restartInc)//',a)') 'reading more values of increment ', restartInc, ' from file' - call HDF5_read(fileHandle,C_volAvg, 'C_volAvg') - call HDF5_read(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') - call HDF5_closeFile(fileHandle) - endif restartRead + restart: if (restartInc > 0) then + write(6,'(/,a,'//IO_intOut(restartInc)//',a)') 'reading values of increment ', restartInc, ' from file' + + write(rankStr,'(a1,i0)')'_',worldrank + fileHandle = HDF5_openFile(trim(getSolverJobName())//trim(rankStr)//'.hdf5') + + call HDF5_read(fileHandle,F_aim, 'F_aim') + call HDF5_read(fileHandle,F_aim_lastInc,'F_aim_lastInc') + call HDF5_read(fileHandle,F_aimDot, 'F_aimDot') + call HDF5_read(fileHandle,F, 'F') + call HDF5_read(fileHandle,F_lastInc, 'F_lastInc') + call HDF5_read(fileHandle,u_current, 'u') + call HDF5_read(fileHandle,u_lastInc, 'u_lastInc') + + elseif (restartInc == 0) then restart + F_lastInc = spread(spread(spread(math_I3,3,grid(1)),4,grid(2)),5,grid3) ! initialize to identity + F = spread(spread(spread(math_I3,3,grid(1)),4,grid(2)),5,grid3) + endif restart + materialpoint_F0 = reshape(F_lastInc, [3,3,1,product(grid(1:2))*grid3]) ! set starting condition for materialpoint_stressAndItsTangent + call utilities_updateIPcoords(F) + call utilities_constitutiveResponse(P_current,temp33_Real,C_volAvg,devNull, & ! stress field, stress avg, global average of stiffness and (min+max)/2 + F, & ! target F + 0.0_pReal, & ! time increment + math_I3) ! no rotation of boundary condition + call DMDAVecRestoreArrayF90(mech_grid,solution_current,u_current,ierr) + CHKERRQ(ierr) + call DMDAVecRestoreArrayF90(mech_grid,solution_lastInc,u_lastInc,ierr) + CHKERRQ(ierr) + + restartRead: if (restartInc > 0) then + write(6,'(/,a,'//IO_intOut(restartInc)//',a)') 'reading more values of increment ', restartInc, ' from file' + call HDF5_read(fileHandle,C_volAvg, 'C_volAvg') + call HDF5_read(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') + call HDF5_closeFile(fileHandle) + endif restartRead end subroutine grid_mech_FEM_init @@ -244,58 +243,57 @@ end subroutine grid_mech_FEM_init !> @brief solution for the FEM scheme with internal iterations !-------------------------------------------------------------------------------------------------- function grid_mech_FEM_solution(incInfoIn,timeinc,timeinc_old,stress_BC,rotation_BC) result(solution) - use IO, only: & - IO_error - use spectral_utilities, only: & - tBoundaryCondition, & - utilities_maskedCompliance - use FEsolving, only: & - restartWrite, & - terminallyIll + use IO, only: & + IO_error + use spectral_utilities, only: & + tBoundaryCondition, & + utilities_maskedCompliance + use FEsolving, only: & + restartWrite, & + terminallyIll - implicit none !-------------------------------------------------------------------------------------------------- ! input data for solution - character(len=*), intent(in) :: & - incInfoIn - real(pReal), intent(in) :: & - timeinc, & !< time increment of current solution - timeinc_old !< time increment of last successful increment - type(tBoundaryCondition), intent(in) :: & - stress_BC - real(pReal), dimension(3,3), intent(in) :: rotation_BC - type(tSolutionState) :: & - solution + character(len=*), intent(in) :: & + incInfoIn + real(pReal), intent(in) :: & + timeinc, & !< time increment of current solution + timeinc_old !< time increment of last successful increment + type(tBoundaryCondition), intent(in) :: & + stress_BC + real(pReal), dimension(3,3), intent(in) :: rotation_BC + type(tSolutionState) :: & + solution !-------------------------------------------------------------------------------------------------- ! PETSc Data - PetscErrorCode :: ierr - SNESConvergedReason :: reason - - incInfo = incInfoIn + PetscErrorCode :: ierr + SNESConvergedReason :: reason + + incInfo = incInfoIn !-------------------------------------------------------------------------------------------------- ! update stiffness (and gamma operator) - S = utilities_maskedCompliance(rotation_BC,stress_BC%maskLogical,C_volAvg) + S = utilities_maskedCompliance(rotation_BC,stress_BC%maskLogical,C_volAvg) !-------------------------------------------------------------------------------------------------- ! set module wide available data - params%stress_mask = stress_BC%maskFloat - params%stress_BC = stress_BC%values - params%rotation_BC = rotation_BC - params%timeinc = timeinc - params%timeincOld = timeinc_old + params%stress_mask = stress_BC%maskFloat + params%stress_BC = stress_BC%values + params%rotation_BC = rotation_BC + params%timeinc = timeinc + params%timeincOld = timeinc_old !-------------------------------------------------------------------------------------------------- ! solve BVP - call SNESsolve(mech_snes,PETSC_NULL_VEC,solution_current,ierr);CHKERRQ(ierr) + call SNESsolve(mech_snes,PETSC_NULL_VEC,solution_current,ierr);CHKERRQ(ierr) !-------------------------------------------------------------------------------------------------- ! check convergence - call SNESGetConvergedReason(mech_snes,reason,ierr);CHKERRQ(ierr) - - solution%converged = reason > 0 - solution%iterationsNeeded = totalIter - solution%termIll = terminallyIll - terminallyIll = .false. + call SNESGetConvergedReason(mech_snes,reason,ierr);CHKERRQ(ierr) + + solution%converged = reason > 0 + solution%iterationsNeeded = totalIter + solution%termIll = terminallyIll + terminallyIll = .false. end function grid_mech_FEM_solution @@ -326,13 +324,12 @@ subroutine grid_mech_FEM_forward(guess,timeinc,timeinc_old,loadCaseTime,deformat use FEsolving, only: & restartWrite - implicit none logical, intent(in) :: & guess real(pReal), intent(in) :: & timeinc_old, & timeinc, & - loadCaseTime !< remaining time of current load case + loadCaseTime !< remaining time of current load case type(tBoundaryCondition), intent(in) :: & stress_BC, & deformation_BC @@ -344,15 +341,15 @@ subroutine grid_mech_FEM_forward(guess,timeinc,timeinc_old,loadCaseTime,deformat PetscScalar, pointer, dimension(:,:,:,:) :: & u_current,u_lastInc - call DMDAVecGetArrayF90(mech_grid,solution_current,u_current,ierr); CHKERRQ(ierr) - call DMDAVecGetArrayF90(mech_grid,solution_lastInc,u_lastInc,ierr); CHKERRQ(ierr) + call DMDAVecGetArrayF90(mech_grid,solution_current,u_current,ierr); CHKERRQ(ierr) + call DMDAVecGetArrayF90(mech_grid,solution_lastInc,u_lastInc,ierr); CHKERRQ(ierr) if (cutBack) then C_volAvg = C_volAvgLastInc ! QUESTION: where is this required? else !-------------------------------------------------------------------------------------------------- ! restart information for spectral solver - if (restartWrite) then ! QUESTION: where is this logical properly set? + if (restartWrite) then write(6,'(/,a)') ' writing converged results for restart';flush(6) write(rankStr,'(a1,i0)')'_',worldrank @@ -372,7 +369,7 @@ subroutine grid_mech_FEM_forward(guess,timeinc,timeinc_old,loadCaseTime,deformat call HDF5_closeFile(fileHandle) endif - call CPFEM_age ! age state and kinematics + call CPFEM_age ! age state and kinematics call utilities_updateIPcoords(F) C_volAvgLastInc = C_volAvg @@ -382,13 +379,13 @@ subroutine grid_mech_FEM_forward(guess,timeinc,timeinc_old,loadCaseTime,deformat !-------------------------------------------------------------------------------------------------- ! calculate rate for aim - if (deformation_BC%myType=='l') then ! calculate F_aimDot from given L and current F + if (deformation_BC%myType=='l') then ! calculate F_aimDot from given L and current F F_aimDot = & F_aimDot + deformation_BC%maskFloat * matmul(deformation_BC%values, F_aim_lastInc) - elseif(deformation_BC%myType=='fdot') then ! F_aimDot is prescribed + elseif(deformation_BC%myType=='fdot') then ! F_aimDot is prescribed F_aimDot = & F_aimDot + deformation_BC%maskFloat * deformation_BC%values - elseif (deformation_BC%myType=='f') then ! aim at end of load case is prescribed + elseif (deformation_BC%myType=='f') then ! aim at end of load case is prescribed F_aimDot = & F_aimDot + deformation_BC%maskFloat * (deformation_BC%values - F_aim_lastInc)/loadCaseTime endif @@ -403,20 +400,20 @@ subroutine grid_mech_FEM_forward(guess,timeinc,timeinc_old,loadCaseTime,deformat endif call VecCopy(solution_current,solution_lastInc,ierr); CHKERRQ(ierr) - F_lastInc = F ! winding F forward - materialpoint_F0 = reshape(F_lastInc, [3,3,1,product(grid(1:2))*grid3]) ! set starting condition for materialpoint_stressAndItsTangent + F_lastInc = F ! winding F forward + materialpoint_F0 = reshape(F_lastInc, [3,3,1,product(grid(1:2))*grid3]) ! set starting condition for materialpoint_stressAndItsTangent endif !-------------------------------------------------------------------------------------------------- ! update average and local deformation gradients - F_aim = F_aim_lastInc + F_aimDot * timeinc - call VecAXPY(solution_current,timeinc,solution_rate,ierr); CHKERRQ(ierr) + F_aim = F_aim_lastInc + F_aimDot * timeinc + call VecAXPY(solution_current,timeinc,solution_rate,ierr); CHKERRQ(ierr) - call DMDAVecRestoreArrayF90(mech_grid,solution_current,u_current,ierr) - CHKERRQ(ierr) - call DMDAVecRestoreArrayF90(mech_grid,solution_lastInc,u_lastInc,ierr) - CHKERRQ(ierr) + call DMDAVecRestoreArrayF90(mech_grid,solution_current,u_current,ierr) + CHKERRQ(ierr) + call DMDAVecRestoreArrayF90(mech_grid,solution_lastInc,u_lastInc,ierr) + CHKERRQ(ierr) end subroutine grid_mech_FEM_forward @@ -424,58 +421,57 @@ end subroutine grid_mech_FEM_forward !-------------------------------------------------------------------------------------------------- !> @brief convergence check !-------------------------------------------------------------------------------------------------- -subroutine converged(snes_local,PETScIter,devNull1,devNull2,devNull3,reason,dummy,ierr) - use mesh - use spectral_utilities - use numerics, only: & - itmax, & - itmin, & - err_div_tolRel, & - err_div_tolAbs, & - err_stress_tolRel, & - err_stress_tolAbs - use FEsolving, only: & - terminallyIll +subroutine converged(snes_local,PETScIter,devNull1,devNull2,fnorm,reason,dummy,ierr) + use mesh + use spectral_utilities + use numerics, only: & + itmax, & + itmin, & + err_div_tolRel, & + err_div_tolAbs, & + err_stress_tolRel, & + err_stress_tolAbs + use FEsolving, only: & + terminallyIll - implicit none - SNES :: snes_local - PetscInt, intent(in) :: PETScIter - PetscReal, intent(in) :: & - devNull1, & - devNull2, & - devNull3 - SNESConvergedReason :: reason - PetscObject :: dummy - PetscErrorCode :: ierr - real(pReal) :: & - err_div, & - divTol, & - BCTol + SNES :: snes_local + PetscInt, intent(in) :: PETScIter + PetscReal, intent(in) :: & + devNull1, & + devNull2, & + fnorm + SNESConvergedReason :: reason + PetscObject :: dummy + PetscErrorCode :: ierr + real(pReal) :: & + err_div, & + divTol, & + BCTol - err_div = fnorm*sqrt(wgt)*geomSize(1)/scaledGeomSize(1)/detJ - divTol = max(maxval(abs(P_av))*err_div_tolRel ,err_div_tolAbs) - BCTol = max(maxval(abs(P_av))*err_stress_tolRel,err_stress_tolAbs) + err_div = fnorm*sqrt(wgt)*geomSize(1)/scaledGeomSize(1)/detJ + divTol = max(maxval(abs(P_av))*err_div_tolRel ,err_div_tolAbs) + BCTol = max(maxval(abs(P_av))*err_stress_tolRel,err_stress_tolAbs) - if ((totalIter >= itmin .and. & - all([ err_div/divTol, & - err_BC /BCTol ] < 1.0_pReal)) & - .or. terminallyIll) then - reason = 1 - elseif (totalIter >= itmax) then - reason = -1 - else - reason = 0 - endif + if ((totalIter >= itmin .and. & + all([ err_div/divTol, & + err_BC /BCTol ] < 1.0_pReal)) & + .or. terminallyIll) then + reason = 1 + elseif (totalIter >= itmax) then + reason = -1 + else + reason = 0 + endif !-------------------------------------------------------------------------------------------------- ! report - write(6,'(1/,a)') ' ... reporting .............................................................' - write(6,'(1/,a,f12.2,a,es8.2,a,es9.2,a)') ' error divergence = ', & - err_div/divTol, ' (',err_div,' / m, tol = ',divTol,')' - write(6,'(a,f12.2,a,es8.2,a,es9.2,a)') ' error stress BC = ', & - err_BC/BCTol, ' (',err_BC, ' Pa, tol = ',BCTol,')' - write(6,'(/,a)') ' ===========================================================================' - flush(6) + write(6,'(1/,a)') ' ... reporting .............................................................' + write(6,'(1/,a,f12.2,a,es8.2,a,es9.2,a)') ' error divergence = ', & + err_div/divTol, ' (',err_div,' / m, tol = ',divTol,')' + write(6,'(a,f12.2,a,es8.2,a,es9.2,a)') ' error stress BC = ', & + err_BC/BCTol, ' (',err_BC, ' Pa, tol = ',BCTol,')' + write(6,'(/,a)') ' ===========================================================================' + flush(6) end subroutine converged @@ -485,135 +481,134 @@ end subroutine converged !-------------------------------------------------------------------------------------------------- subroutine formResidual(da_local,x_local, & f_local,dummy,ierr) - use numerics, only: & - itmax, & - itmin - use numerics, only: & - worldrank - use mesh, only: & - grid - use math, only: & - math_rotate_backward33, & - math_mul3333xx33 - use debug, only: & - debug_level, & - debug_spectral, & - debug_spectralRotation - use spectral_utilities, only: & - utilities_constitutiveResponse - use IO, only: & - IO_intOut - use FEsolving, only: & - terminallyIll - use homogenization, only: & - materialpoint_dPdF + use numerics, only: & + itmax, & + itmin + use numerics, only: & + worldrank + use mesh, only: & + grid + use math, only: & + math_rotate_backward33, & + math_mul3333xx33 + use debug, only: & + debug_level, & + debug_spectral, & + debug_spectralRotation + use spectral_utilities, only: & + utilities_constitutiveResponse + use IO, only: & + IO_intOut + use FEsolving, only: & + terminallyIll + use homogenization, only: & + materialpoint_dPdF - implicit none - DM :: da_local - Vec :: x_local, f_local - PetscScalar, pointer,dimension(:,:,:,:) :: x_scal, f_scal - PetscScalar, dimension(8,3) :: x_elem, f_elem - PetscInt :: i, ii, j, jj, k, kk, ctr, ele - real(pReal), dimension(3,3) :: & - deltaF_aim - PetscInt :: & - PETScIter, & - nfuncs - PetscObject :: dummy - PetscErrorCode :: ierr - real(pReal), dimension(3,3,3,3) :: devNull + DM :: da_local + Vec :: x_local, f_local + PetscScalar, pointer,dimension(:,:,:,:) :: x_scal, f_scal + PetscScalar, dimension(8,3) :: x_elem, f_elem + PetscInt :: i, ii, j, jj, k, kk, ctr, ele + real(pReal), dimension(3,3) :: & + deltaF_aim + PetscInt :: & + PETScIter, & + nfuncs + PetscObject :: dummy + PetscErrorCode :: ierr + real(pReal), dimension(3,3,3,3) :: devNull - call SNESGetNumberFunctionEvals(mech_snes,nfuncs,ierr); CHKERRQ(ierr) - call SNESGetIterationNumber(mech_snes,PETScIter,ierr); CHKERRQ(ierr) + call SNESGetNumberFunctionEvals(mech_snes,nfuncs,ierr); CHKERRQ(ierr) + call SNESGetIterationNumber(mech_snes,PETScIter,ierr); CHKERRQ(ierr) - if (nfuncs == 0 .and. PETScIter == 0) totalIter = -1 ! new increment + if (nfuncs == 0 .and. PETScIter == 0) totalIter = -1 ! new increment !-------------------------------------------------------------------------------------------------- ! begin of new iteration - newIteration: if (totalIter <= PETScIter) then - totalIter = totalIter + 1 - write(6,'(1x,a,3(a,'//IO_intOut(itmax)//'))') & - trim(incInfo), ' @ Iteration ', itmin, '≤',totalIter+1, '≤', itmax - if (iand(debug_level(debug_spectral),debug_spectralRotation) /= 0) & - write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') & - ' deformation gradient aim (lab) =', transpose(math_rotate_backward33(F_aim,params%rotation_BC)) - write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') & - ' deformation gradient aim =', transpose(F_aim) - flush(6) - endif newIteration + newIteration: if (totalIter <= PETScIter) then + totalIter = totalIter + 1 + write(6,'(1x,a,3(a,'//IO_intOut(itmax)//'))') & + trim(incInfo), ' @ Iteration ', itmin, '≤',totalIter+1, '≤', itmax + if (iand(debug_level(debug_spectral),debug_spectralRotation) /= 0) & + write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') & + ' deformation gradient aim (lab) =', transpose(math_rotate_backward33(F_aim,params%rotation_BC)) + write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') & + ' deformation gradient aim =', transpose(F_aim) + flush(6) + endif newIteration !-------------------------------------------------------------------------------------------------- ! get deformation gradient - call DMDAVecGetArrayF90(da_local,x_local,x_scal,ierr);CHKERRQ(ierr) - do k = zstart, zend; do j = ystart, yend; do i = xstart, xend - ctr = 0 - do kk = 0, 1; do jj = 0, 1; do ii = 0, 1 - ctr = ctr + 1 - x_elem(ctr,1:3) = x_scal(0:2,i+ii,j+jj,k+kk) - enddo; enddo; enddo - ii = i-xstart+1; jj = j-ystart+1; kk = k-zstart+1 - F(1:3,1:3,ii,jj,kk) = math_rotate_backward33(F_aim,params%rotation_BC) + transpose(matmul(BMat,x_elem)) - enddo; enddo; enddo - call DMDAVecRestoreArrayF90(da_local,x_local,x_scal,ierr);CHKERRQ(ierr) + call DMDAVecGetArrayF90(da_local,x_local,x_scal,ierr);CHKERRQ(ierr) + do k = zstart, zend; do j = ystart, yend; do i = xstart, xend + ctr = 0 + do kk = 0, 1; do jj = 0, 1; do ii = 0, 1 + ctr = ctr + 1 + x_elem(ctr,1:3) = x_scal(0:2,i+ii,j+jj,k+kk) + enddo; enddo; enddo + ii = i-xstart+1; jj = j-ystart+1; kk = k-zstart+1 + F(1:3,1:3,ii,jj,kk) = math_rotate_backward33(F_aim,params%rotation_BC) + transpose(matmul(BMat,x_elem)) + enddo; enddo; enddo + call DMDAVecRestoreArrayF90(da_local,x_local,x_scal,ierr);CHKERRQ(ierr) !-------------------------------------------------------------------------------------------------- ! evaluate constitutive response - call Utilities_constitutiveResponse(P_current,& - P_av,C_volAvg,devNull, & - F,params%timeinc,params%rotation_BC) - call MPI_Allreduce(MPI_IN_PLACE,terminallyIll,1,MPI_LOGICAL,MPI_LOR,PETSC_COMM_WORLD,ierr) + call Utilities_constitutiveResponse(P_current,& + P_av,C_volAvg,devNull, & + F,params%timeinc,params%rotation_BC) + call MPI_Allreduce(MPI_IN_PLACE,terminallyIll,1,MPI_LOGICAL,MPI_LOR,PETSC_COMM_WORLD,ierr) !-------------------------------------------------------------------------------------------------- ! stress BC handling - F_aim_lastIter = F_aim - deltaF_aim = math_mul3333xx33(S, P_av - params%stress_BC) - F_aim = F_aim - deltaF_aim - err_BC = maxval(abs(params%stress_mask * (P_av - params%stress_BC))) ! mask = 0.0 when no stress bc + F_aim_lastIter = F_aim + deltaF_aim = math_mul3333xx33(S, P_av - params%stress_BC) + F_aim = F_aim - deltaF_aim + err_BC = maxval(abs(params%stress_mask * (P_av - params%stress_BC))) ! mask = 0.0 when no stress bc !-------------------------------------------------------------------------------------------------- ! constructing residual - call VecSet(f_local,0.0_pReal,ierr);CHKERRQ(ierr) - call DMDAVecGetArrayF90(da_local,f_local,f_scal,ierr);CHKERRQ(ierr) - call DMDAVecGetArrayF90(da_local,x_local,x_scal,ierr);CHKERRQ(ierr) - ele = 0 - do k = zstart, zend; do j = ystart, yend; do i = xstart, xend - ctr = 0 - do kk = 0, 1; do jj = 0, 1; do ii = 0, 1 - ctr = ctr + 1 - x_elem(ctr,1:3) = x_scal(0:2,i+ii,j+jj,k+kk) - enddo; enddo; enddo - ii = i-xstart+1; jj = j-ystart+1; kk = k-zstart+1 - ele = ele + 1 - f_elem = matmul(transpose(BMat),transpose(P_current(1:3,1:3,ii,jj,kk)))*detJ + & - matmul(HGMat,x_elem)*(materialpoint_dPdF(1,1,1,1,1,ele) + & - materialpoint_dPdF(2,2,2,2,1,ele) + & - materialpoint_dPdF(3,3,3,3,1,ele))/3.0_pReal - ctr = 0 - do kk = 0, 1; do jj = 0, 1; do ii = 0, 1 - ctr = ctr + 1 - f_scal(0:2,i+ii,j+jj,k+kk) = f_scal(0:2,i+ii,j+jj,k+kk) + f_elem(ctr,1:3) - enddo; enddo; enddo - enddo; enddo; enddo - call DMDAVecRestoreArrayF90(da_local,x_local,x_scal,ierr);CHKERRQ(ierr) - call DMDAVecRestoreArrayF90(da_local,f_local,f_scal,ierr);CHKERRQ(ierr) + call VecSet(f_local,0.0_pReal,ierr);CHKERRQ(ierr) + call DMDAVecGetArrayF90(da_local,f_local,f_scal,ierr);CHKERRQ(ierr) + call DMDAVecGetArrayF90(da_local,x_local,x_scal,ierr);CHKERRQ(ierr) + ele = 0 + do k = zstart, zend; do j = ystart, yend; do i = xstart, xend + ctr = 0 + do kk = 0, 1; do jj = 0, 1; do ii = 0, 1 + ctr = ctr + 1 + x_elem(ctr,1:3) = x_scal(0:2,i+ii,j+jj,k+kk) + enddo; enddo; enddo + ii = i-xstart+1; jj = j-ystart+1; kk = k-zstart+1 + ele = ele + 1 + f_elem = matmul(transpose(BMat),transpose(P_current(1:3,1:3,ii,jj,kk)))*detJ + & + matmul(HGMat,x_elem)*(materialpoint_dPdF(1,1,1,1,1,ele) + & + materialpoint_dPdF(2,2,2,2,1,ele) + & + materialpoint_dPdF(3,3,3,3,1,ele))/3.0_pReal + ctr = 0 + do kk = 0, 1; do jj = 0, 1; do ii = 0, 1 + ctr = ctr + 1 + f_scal(0:2,i+ii,j+jj,k+kk) = f_scal(0:2,i+ii,j+jj,k+kk) + f_elem(ctr,1:3) + enddo; enddo; enddo + enddo; enddo; enddo + call DMDAVecRestoreArrayF90(da_local,x_local,x_scal,ierr);CHKERRQ(ierr) + call DMDAVecRestoreArrayF90(da_local,f_local,f_scal,ierr);CHKERRQ(ierr) !-------------------------------------------------------------------------------------------------- ! applying boundary conditions - call DMDAVecGetArrayF90(da_local,f_local,f_scal,ierr);CHKERRQ(ierr) - if (zstart == 0) then - f_scal(0:2,xstart,ystart,zstart) = 0.0 - f_scal(0:2,xend+1,ystart,zstart) = 0.0 - f_scal(0:2,xstart,yend+1,zstart) = 0.0 - f_scal(0:2,xend+1,yend+1,zstart) = 0.0 - endif - if (zend + 1 == grid(3)) then - f_scal(0:2,xstart,ystart,zend+1) = 0.0 - f_scal(0:2,xend+1,ystart,zend+1) = 0.0 - f_scal(0:2,xstart,yend+1,zend+1) = 0.0 - f_scal(0:2,xend+1,yend+1,zend+1) = 0.0 - endif - call DMDAVecRestoreArrayF90(da_local,f_local,f_scal,ierr);CHKERRQ(ierr) + call DMDAVecGetArrayF90(da_local,f_local,f_scal,ierr);CHKERRQ(ierr) + if (zstart == 0) then + f_scal(0:2,xstart,ystart,zstart) = 0.0 + f_scal(0:2,xend+1,ystart,zstart) = 0.0 + f_scal(0:2,xstart,yend+1,zstart) = 0.0 + f_scal(0:2,xend+1,yend+1,zstart) = 0.0 + endif + if (zend + 1 == grid(3)) then + f_scal(0:2,xstart,ystart,zend+1) = 0.0 + f_scal(0:2,xend+1,ystart,zend+1) = 0.0 + f_scal(0:2,xstart,yend+1,zend+1) = 0.0 + f_scal(0:2,xend+1,yend+1,zend+1) = 0.0 + endif + call DMDAVecRestoreArrayF90(da_local,f_local,f_scal,ierr);CHKERRQ(ierr) end subroutine formResidual @@ -622,97 +617,96 @@ end subroutine formResidual !> @brief forms the FEM stiffness matrix !-------------------------------------------------------------------------------------------------- subroutine formJacobian(da_local,x_local,Jac_pre,Jac,dummy,ierr) - use mesh, only: & - mesh_ipCoordinates - use homogenization, only: & - materialpoint_dPdF - - implicit none - - DM :: da_local - Vec :: x_local, coordinates - Mat :: Jac_pre, Jac - MatStencil,dimension(4,24) :: row, col - PetscScalar,pointer,dimension(:,:,:,:) :: x_scal - PetscScalar,dimension(24,24) :: K_ele - PetscScalar,dimension(9,24) :: BMatFull - PetscInt :: i, ii, j, jj, k, kk, ctr, ele - PetscInt,dimension(3) :: rows - PetscScalar :: diag - PetscObject :: dummy - MatNullSpace :: matnull - PetscErrorCode :: ierr + use mesh, only: & + mesh_ipCoordinates + use homogenization, only: & + materialpoint_dPdF - BMatFull = 0.0 - BMatFull(1:3,1 :8 ) = BMat - BMatFull(4:6,9 :16) = BMat - BMatFull(7:9,17:24) = BMat - call MatSetOption(Jac,MAT_KEEP_NONZERO_PATTERN,PETSC_TRUE,ierr); CHKERRQ(ierr) - call MatSetOption(Jac,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_FALSE,ierr); CHKERRQ(ierr) - call MatZeroEntries(Jac,ierr); CHKERRQ(ierr) - ele = 0 - do k = zstart, zend; do j = ystart, yend; do i = xstart, xend - ctr = 0 - do kk = 0, 1; do jj = 0, 1; do ii = 0, 1 - ctr = ctr + 1 - col(MatStencil_i,ctr ) = i+ii - col(MatStencil_j,ctr ) = j+jj - col(MatStencil_k,ctr ) = k+kk - col(MatStencil_c,ctr ) = 0 - col(MatStencil_i,ctr+8 ) = i+ii - col(MatStencil_j,ctr+8 ) = j+jj - col(MatStencil_k,ctr+8 ) = k+kk - col(MatStencil_c,ctr+8 ) = 1 - col(MatStencil_i,ctr+16) = i+ii - col(MatStencil_j,ctr+16) = j+jj - col(MatStencil_k,ctr+16) = k+kk - col(MatStencil_c,ctr+16) = 2 - enddo; enddo; enddo - row = col - ele = ele + 1 - K_ele = 0.0 - K_ele(1 :8 ,1 :8 ) = HGMat*(materialpoint_dPdF(1,1,1,1,1,ele) + & - materialpoint_dPdF(2,2,2,2,1,ele) + & - materialpoint_dPdF(3,3,3,3,1,ele))/3.0_pReal - K_ele(9 :16,9 :16) = HGMat*(materialpoint_dPdF(1,1,1,1,1,ele) + & - materialpoint_dPdF(2,2,2,2,1,ele) + & - materialpoint_dPdF(3,3,3,3,1,ele))/3.0_pReal - K_ele(17:24,17:24) = HGMat*(materialpoint_dPdF(1,1,1,1,1,ele) + & - materialpoint_dPdF(2,2,2,2,1,ele) + & - materialpoint_dPdF(3,3,3,3,1,ele))/3.0_pReal - K_ele = K_ele + & - matmul(transpose(BMatFull), & - matmul(reshape(reshape(materialpoint_dPdF(1:3,1:3,1:3,1:3,1,ele), & - shape=[3,3,3,3], order=[2,1,4,3]),shape=[9,9]),BMatFull))*detJ - call MatSetValuesStencil(Jac,24,row,24,col,K_ele,ADD_VALUES,ierr) - CHKERRQ(ierr) - enddo; enddo; enddo - call MatAssemblyBegin(Jac,MAT_FINAL_ASSEMBLY,ierr); CHKERRQ(ierr) - call MatAssemblyEnd(Jac,MAT_FINAL_ASSEMBLY,ierr); CHKERRQ(ierr) - call MatAssemblyBegin(Jac_pre,MAT_FINAL_ASSEMBLY,ierr); CHKERRQ(ierr) - call MatAssemblyEnd(Jac_pre,MAT_FINAL_ASSEMBLY,ierr); CHKERRQ(ierr) + + DM :: da_local + Vec :: x_local, coordinates + Mat :: Jac_pre, Jac + MatStencil,dimension(4,24) :: row, col + PetscScalar,pointer,dimension(:,:,:,:) :: x_scal + PetscScalar,dimension(24,24) :: K_ele + PetscScalar,dimension(9,24) :: BMatFull + PetscInt :: i, ii, j, jj, k, kk, ctr, ele + PetscInt,dimension(3) :: rows + PetscScalar :: diag + PetscObject :: dummy + MatNullSpace :: matnull + PetscErrorCode :: ierr + + BMatFull = 0.0 + BMatFull(1:3,1 :8 ) = BMat + BMatFull(4:6,9 :16) = BMat + BMatFull(7:9,17:24) = BMat + call MatSetOption(Jac,MAT_KEEP_NONZERO_PATTERN,PETSC_TRUE,ierr); CHKERRQ(ierr) + call MatSetOption(Jac,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_FALSE,ierr); CHKERRQ(ierr) + call MatZeroEntries(Jac,ierr); CHKERRQ(ierr) + ele = 0 + do k = zstart, zend; do j = ystart, yend; do i = xstart, xend + ctr = 0 + do kk = 0, 1; do jj = 0, 1; do ii = 0, 1 + ctr = ctr + 1 + col(MatStencil_i,ctr ) = i+ii + col(MatStencil_j,ctr ) = j+jj + col(MatStencil_k,ctr ) = k+kk + col(MatStencil_c,ctr ) = 0 + col(MatStencil_i,ctr+8 ) = i+ii + col(MatStencil_j,ctr+8 ) = j+jj + col(MatStencil_k,ctr+8 ) = k+kk + col(MatStencil_c,ctr+8 ) = 1 + col(MatStencil_i,ctr+16) = i+ii + col(MatStencil_j,ctr+16) = j+jj + col(MatStencil_k,ctr+16) = k+kk + col(MatStencil_c,ctr+16) = 2 + enddo; enddo; enddo + row = col + ele = ele + 1 + K_ele = 0.0 + K_ele(1 :8 ,1 :8 ) = HGMat*(materialpoint_dPdF(1,1,1,1,1,ele) + & + materialpoint_dPdF(2,2,2,2,1,ele) + & + materialpoint_dPdF(3,3,3,3,1,ele))/3.0_pReal + K_ele(9 :16,9 :16) = HGMat*(materialpoint_dPdF(1,1,1,1,1,ele) + & + materialpoint_dPdF(2,2,2,2,1,ele) + & + materialpoint_dPdF(3,3,3,3,1,ele))/3.0_pReal + K_ele(17:24,17:24) = HGMat*(materialpoint_dPdF(1,1,1,1,1,ele) + & + materialpoint_dPdF(2,2,2,2,1,ele) + & + materialpoint_dPdF(3,3,3,3,1,ele))/3.0_pReal + K_ele = K_ele + & + matmul(transpose(BMatFull), & + matmul(reshape(reshape(materialpoint_dPdF(1:3,1:3,1:3,1:3,1,ele), & + shape=[3,3,3,3], order=[2,1,4,3]),shape=[9,9]),BMatFull))*detJ + call MatSetValuesStencil(Jac,24,row,24,col,K_ele,ADD_VALUES,ierr) + CHKERRQ(ierr) + enddo; enddo; enddo + call MatAssemblyBegin(Jac,MAT_FINAL_ASSEMBLY,ierr); CHKERRQ(ierr) + call MatAssemblyEnd(Jac,MAT_FINAL_ASSEMBLY,ierr); CHKERRQ(ierr) + call MatAssemblyBegin(Jac_pre,MAT_FINAL_ASSEMBLY,ierr); CHKERRQ(ierr) + call MatAssemblyEnd(Jac_pre,MAT_FINAL_ASSEMBLY,ierr); CHKERRQ(ierr) !-------------------------------------------------------------------------------------------------- ! applying boundary conditions - rows = [0, 1, 2] - diag = (C_volAvg(1,1,1,1)/delta(1)**2.0_pReal + & - C_volAvg(2,2,2,2)/delta(2)**2.0_pReal + & - C_volAvg(3,3,3,3)/delta(3)**2.0_pReal)*detJ - call MatZeroRowsColumns(Jac,size(rows),rows,diag,PETSC_NULL_VEC,PETSC_NULL_VEC,ierr) - CHKERRQ(ierr) - call DMGetGlobalVector(da_local,coordinates,ierr);CHKERRQ(ierr) - call DMDAVecGetArrayF90(da_local,coordinates,x_scal,ierr);CHKERRQ(ierr) - ele = 0 - do k = zstart, zend; do j = ystart, yend; do i = xstart, xend - ele = ele + 1 - x_scal(0:2,i,j,k) = mesh_ipCoordinates(1:3,1,ele) - enddo; enddo; enddo - call DMDAVecRestoreArrayF90(da_local,coordinates,x_scal,ierr);CHKERRQ(ierr) ! initialize to undeformed coordinates (ToDo: use ip coordinates) - call MatNullSpaceCreateRigidBody(coordinates,matnull,ierr);CHKERRQ(ierr) ! get rigid body deformation modes - call DMRestoreGlobalVector(da_local,coordinates,ierr);CHKERRQ(ierr) - call MatSetNullSpace(Jac,matnull,ierr); CHKERRQ(ierr) - call MatSetNearNullSpace(Jac,matnull,ierr); CHKERRQ(ierr) - call MatNullSpaceDestroy(matnull,ierr); CHKERRQ(ierr) + rows = [0, 1, 2] + diag = (C_volAvg(1,1,1,1)/delta(1)**2.0_pReal + & + C_volAvg(2,2,2,2)/delta(2)**2.0_pReal + & + C_volAvg(3,3,3,3)/delta(3)**2.0_pReal)*detJ + call MatZeroRowsColumns(Jac,size(rows),rows,diag,PETSC_NULL_VEC,PETSC_NULL_VEC,ierr) + CHKERRQ(ierr) + call DMGetGlobalVector(da_local,coordinates,ierr);CHKERRQ(ierr) + call DMDAVecGetArrayF90(da_local,coordinates,x_scal,ierr);CHKERRQ(ierr) + ele = 0 + do k = zstart, zend; do j = ystart, yend; do i = xstart, xend + ele = ele + 1 + x_scal(0:2,i,j,k) = mesh_ipCoordinates(1:3,1,ele) + enddo; enddo; enddo + call DMDAVecRestoreArrayF90(da_local,coordinates,x_scal,ierr);CHKERRQ(ierr) ! initialize to undeformed coordinates (ToDo: use ip coordinates) + call MatNullSpaceCreateRigidBody(coordinates,matnull,ierr);CHKERRQ(ierr) ! get rigid body deformation modes + call DMRestoreGlobalVector(da_local,coordinates,ierr);CHKERRQ(ierr) + call MatSetNullSpace(Jac,matnull,ierr); CHKERRQ(ierr) + call MatSetNearNullSpace(Jac,matnull,ierr); CHKERRQ(ierr) + call MatNullSpaceDestroy(matnull,ierr); CHKERRQ(ierr) end subroutine formJacobian diff --git a/src/grid_mech_spectral_basic.f90 b/src/grid_mech_spectral_basic.f90 index 91dcd03b4..f698fdc6d 100644 --- a/src/grid_mech_spectral_basic.f90 +++ b/src/grid_mech_spectral_basic.f90 @@ -107,7 +107,6 @@ subroutine grid_mech_spectral_basic_init use math, only: & math_invSym3333 - implicit none real(pReal), dimension(3,3,grid(1),grid(2),grid3) :: P real(pReal), dimension(3,3) :: & temp33_Real = 0.0_pReal @@ -221,7 +220,6 @@ function grid_mech_spectral_basic_solution(incInfoIn,timeinc,timeinc_old,stress_ restartWrite, & terminallyIll - implicit none !-------------------------------------------------------------------------------------------------- ! input data for solution character(len=*), intent(in) :: & @@ -298,7 +296,6 @@ subroutine grid_mech_spectral_basic_forward(guess,timeinc,timeinc_old,loadCaseTi use FEsolving, only: & restartWrite - implicit none logical, intent(in) :: & guess real(pReal), intent(in) :: & @@ -397,7 +394,6 @@ subroutine converged(snes_local,PETScIter,devNull1,devNull2,devNull3,reason,dumm use FEsolving, only: & terminallyIll - implicit none SNES :: snes_local PetscInt, intent(in) :: PETScIter PetscReal, intent(in) :: & @@ -468,7 +464,6 @@ subroutine formResidual(in, F, & use FEsolving, only: & terminallyIll - implicit none DMDALocalInfo, dimension(DMDA_LOCAL_INFO_SIZE) :: in !< DMDA info (needs to be named "in" for macros like XRANGE to work) PetscScalar, dimension(3,3,XG_RANGE,YG_RANGE,ZG_RANGE), & intent(in) :: F !< deformation gradient field diff --git a/src/grid_mech_spectral_polarisation.f90 b/src/grid_mech_spectral_polarisation.f90 index a7bf75209..55df4455f 100644 --- a/src/grid_mech_spectral_polarisation.f90 +++ b/src/grid_mech_spectral_polarisation.f90 @@ -113,7 +113,6 @@ subroutine grid_mech_spectral_polarisation_init use math, only: & math_invSym3333 - implicit none real(pReal), dimension(3,3,grid(1),grid(2),grid3) :: P real(pReal), dimension(3,3) :: & temp33_Real = 0.0_pReal @@ -238,7 +237,6 @@ function grid_mech_spectral_polarisation_solution(incInfoIn,timeinc,timeinc_old, restartWrite, & terminallyIll - implicit none !-------------------------------------------------------------------------------------------------- ! input data for solution character(len=*), intent(in) :: & @@ -445,7 +443,6 @@ subroutine converged(snes_local,PETScIter,devNull1,devNull2,devNull3,reason,dumm use FEsolving, only: & terminallyIll - implicit none SNES :: snes_local PetscInt, intent(in) :: PETScIter PetscReal, intent(in) :: & @@ -529,7 +526,6 @@ subroutine formResidual(in, FandF_tau, & use FEsolving, only: & terminallyIll - implicit none DMDALocalInfo, dimension(DMDA_LOCAL_INFO_SIZE) :: in !< DMDA info (needs to be named "in" for macros like XRANGE to work) PetscScalar, dimension(3,3,2,XG_RANGE,YG_RANGE,ZG_RANGE), & target, intent(in) :: FandF_tau diff --git a/src/grid_thermal_spectral.f90 b/src/grid_thermal_spectral.f90 index 31740feb9..e899fd89a 100644 --- a/src/grid_thermal_spectral.f90 +++ b/src/grid_thermal_spectral.f90 @@ -69,7 +69,6 @@ subroutine grid_thermal_spectral_init worldsize, & petsc_options - implicit none PetscInt, dimension(worldsize) :: localK integer :: i, j, k, cell DM :: thermal_grid @@ -167,7 +166,6 @@ function grid_thermal_spectral_solution(timeinc,timeinc_old,loadCaseTime) result use thermal_conduction, only: & thermal_conduction_putTemperatureAndItsRate - implicit none real(pReal), intent(in) :: & timeinc, & !< increment in time for current solution timeinc_old, & !< increment in time of last increment @@ -242,7 +240,6 @@ subroutine grid_thermal_spectral_forward thermal_conduction_getMassDensity, & thermal_conduction_getSpecificHeat - implicit none integer :: i, j, k, cell DM :: dm_local PetscScalar, dimension(:,:,:), pointer :: x_scal @@ -311,7 +308,6 @@ subroutine formResidual(in,x_scal,f_scal,dummy,ierr) thermal_conduction_getMassDensity, & thermal_conduction_getSpecificHeat - implicit none DMDALocalInfo, dimension(DMDA_LOCAL_INFO_SIZE) :: & in PetscScalar, dimension( & From ed8270d432ab971b09d8f4838fcf700470492718 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 16 Apr 2019 14:53:36 +0200 Subject: [PATCH 16/61] need to read reference stiffness --- src/grid_mech_spectral_basic.f90 | 3 +++ src/grid_mech_spectral_polarisation.f90 | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/grid_mech_spectral_basic.f90 b/src/grid_mech_spectral_basic.f90 index f698fdc6d..2daebefbd 100644 --- a/src/grid_mech_spectral_basic.f90 +++ b/src/grid_mech_spectral_basic.f90 @@ -116,6 +116,7 @@ subroutine grid_mech_spectral_basic_init F ! pointer to solution data PetscInt, dimension(worldsize) :: localK integer(HID_T) :: fileHandle + integer :: fileUnit character(len=1024) :: rankStr write(6,'(/,a)') ' <<<+- grid_mech_spectral_basic init -+>>>' @@ -201,6 +202,8 @@ subroutine grid_mech_spectral_basic_init call HDF5_read(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') call HDF5_closeFile(fileHandle) + fileUnit = IO_open_jobFile_binary('C_ref') + read(fileUnit) C_minMaxAvg; close(fileUnit) endif restartRead call utilities_updateGamma(C_minMaxAvg,.true.) diff --git a/src/grid_mech_spectral_polarisation.f90 b/src/grid_mech_spectral_polarisation.f90 index 55df4455f..3bd30a360 100644 --- a/src/grid_mech_spectral_polarisation.f90 +++ b/src/grid_mech_spectral_polarisation.f90 @@ -124,6 +124,7 @@ subroutine grid_mech_spectral_polarisation_init F_tau ! specific (sub)pointer PetscInt, dimension(worldsize) :: localK integer(HID_T) :: fileHandle + integer :: fileUnit character(len=1024) :: rankStr write(6,'(/,a)') ' <<<+- grid_mech_spectral_polarisation init -+>>>' @@ -214,6 +215,8 @@ subroutine grid_mech_spectral_polarisation_init call HDF5_read(fileHandle,C_volAvgLastInc,'C_volAvgLastInc') call HDF5_closeFile(fileHandle) + fileUnit = IO_open_jobFile_binary('C_ref') + read(fileUnit) C_minMaxAvg; close(fileUnit) endif restartRead call utilities_updateGamma(C_minMaxAvg,.true.) From d842902a76b41c19a0ccffacc721617c9c470739 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 16 Apr 2019 21:47:29 +0200 Subject: [PATCH 17/61] consistent ordering - qu, om, eu, ax, ro, ho, cu --- python/damask/orientation.py | 198 +++++++++++++++++------------------ 1 file changed, 97 insertions(+), 101 deletions(-) diff --git a/python/damask/orientation.py b/python/damask/orientation.py index fde168d27..007aecfd9 100644 --- a/python/damask/orientation.py +++ b/python/damask/orientation.py @@ -1247,6 +1247,20 @@ def iszero(a): #---------- quaternion ---------- +def qu2om(qu): + """Quaternion to orientation matrix""" + qq = qu[0]**2-(qu[1]**2 + qu[2]**2 + qu[3]**2) + om = np.diag(qq + 2.0*np.array([qu[1],qu[2],qu[3]])**2) + + om[1,0] = 2.0*(qu[2]*qu[1]+qu[0]*qu[3]) + om[0,1] = 2.0*(qu[1]*qu[2]-qu[0]*qu[3]) + om[2,1] = 2.0*(qu[3]*qu[2]+qu[0]*qu[1]) + om[1,2] = 2.0*(qu[2]*qu[3]-qu[0]*qu[1]) + om[0,2] = 2.0*(qu[1]*qu[3]+qu[0]*qu[2]) + om[2,0] = 2.0*(qu[3]*qu[1]-qu[0]*qu[2]) + return om if P > 0.0 else om.T + + def qu2eu(qu): """Quaternion to Euler angles""" q03 = qu[0]**2+qu[3]**2 @@ -1265,19 +1279,6 @@ def qu2eu(qu): eu = np.where(eu<0, (eu+2.0*np.pi)%np.array([2.0*np.pi,np.pi,2.0*np.pi]),eu) return eu -def qu2om(qu): - """Quaternion to orientation matrix""" - qq = qu[0]**2-(qu[1]**2 + qu[2]**2 + qu[3]**2) - om = np.diag(qq + 2.0*np.array([qu[1],qu[2],qu[3]])**2) - - om[1,0] = 2.0*(qu[2]*qu[1]+qu[0]*qu[3]) - om[0,1] = 2.0*(qu[1]*qu[2]-qu[0]*qu[3]) - om[2,1] = 2.0*(qu[3]*qu[2]+qu[0]*qu[1]) - om[1,2] = 2.0*(qu[2]*qu[3]-qu[0]*qu[1]) - om[0,2] = 2.0*(qu[1]*qu[3]+qu[0]*qu[2]) - om[2,0] = 2.0*(qu[3]*qu[1]-qu[0]*qu[2]) - return om if P > 0.0 else om.T - def qu2ax(qu): """ @@ -1330,6 +1331,14 @@ def qu2cu(qu): #---------- orientation matrix ---------- +def om2qu(om): + """ + Orientation matrix to quaternion + + The original formulation (direct conversion) had numerical issues + """ + return ax2qu(om2ax(om)) + def om2eu(om): """Euler angles to orientation matrix""" @@ -1365,25 +1374,11 @@ def om2ax(om): ax[0:3] = np.where(iszero(diagDelta), ax[0:3],np.abs(ax[0:3])*np.sign(-P*diagDelta)) return np.array(ax) - - -def om2qu(om): - """ - Orientation matrix to quaternion - - The original formulation (direct conversion) had numerical issues - """ - return ax2qu(om2ax(om)) def om2ro(om): """Orientation matrix to Rodriques vector""" return eu2ro(om2eu(om)) - - -def om2cu(om): - """Orientation matrix to cubochoric""" - return ho2cu(om2ho(om)) def om2ho(om): @@ -1391,9 +1386,26 @@ def om2ho(om): return ax2ho(om2ax(om)) +def om2cu(om): + """Orientation matrix to cubochoric""" + return ho2cu(om2ho(om)) + + #---------- Euler angles ---------- - +def eu2qu(eu): + """Euler angles to quaternion""" + ee = 0.5*eu + cPhi = np.cos(ee[1]) + sPhi = np.sin(ee[1]) + qu = np.array([ cPhi*np.cos(ee[0]+ee[2]), + -P*sPhi*np.cos(ee[0]-ee[2]), + -P*sPhi*np.sin(ee[0]-ee[2]), + -P*cPhi*np.sin(ee[0]+ee[2]) ]) + #if qu[0] < 0.0: qu.homomorph() !ToDo: Check with original + return qu + + def eu2om(eu): """Euler angles to orientation matrix""" c = np.cos(eu) @@ -1444,19 +1456,6 @@ def eu2ho(eu): return ax2ho(eu2ax(eu)) -def eu2qu(eu): - """Euler angles to quaternion""" - ee = 0.5*eu - cPhi = np.cos(ee[1]) - sPhi = np.sin(ee[1]) - qu = np.array([ cPhi*np.cos(ee[0]+ee[2]), - -P*sPhi*np.cos(ee[0]-ee[2]), - -P*sPhi*np.sin(ee[0]-ee[2]), - -P*cPhi*np.sin(ee[0]+ee[2]) ]) - #if qu[0] < 0.0: qu.homomorph() !ToDo: Check with original - return qu - - def eu2cu(eu): """Euler angles to cubochoric""" return ho2cu(eu2ho(eu)) @@ -1464,10 +1463,16 @@ def eu2cu(eu): #---------- axis angle ---------- - -def ax2eu(ax): - """Orientation matrix to Euler angles""" - return om2eu(ax2om(ax)) +def ax2qu(ax): + """Axis angle to quaternion""" + if iszero(ax[3]): + qu = np.array([ 1.0, 0.0, 0.0, 0.0 ]) + else: + c = np.cos(ax[3]*0.5) + s = np.sin(ax[3]*0.5) + qu = np.array([ c, ax[0]*s, ax[1]*s, ax[2]*s ]) + + return qu def ax2om(ax): @@ -1484,6 +1489,11 @@ def ax2om(ax): return om if P < 0.0 else om.T + +def ax2eu(ax): + """Orientation matrix to Euler angles""" + return om2eu(ax2om(ax)) + def ax2ro(ax): """Axis angle to Rodrigues vector""" @@ -1498,18 +1508,6 @@ def ax2ro(ax): return np.array(ro) -def ax2qu(ax): - """Axis angle to quaternion""" - if iszero(ax[3]): - qu = np.array([ 1.0, 0.0, 0.0, 0.0 ]) - else: - c = np.cos(ax[3]*0.5) - s = np.sin(ax[3]*0.5) - qu = np.array([ c, ax[0]*s, ax[1]*s, ax[2]*s ]) - - return qu - - def ax2ho(ax): """Axis angle to homochoric""" f = (0.75 * ( ax[3] - np.sin(ax[3]) ))**(1.0/3.0) @@ -1524,6 +1522,20 @@ def ax2cu(ax): #---------- Rodrigues--Frank ---------- +def ro2qu(ro): + """Rodrigues vector to quaternion""" + return ax2qu(ro2ax(ro)) + + +def ro2om(ro): + """Rodgrigues vector to orientation matrix""" + return ax2om(ro2ax(ro)) + + +def ro2eu(ro): + """Rodrigues vector to orientation matrix""" + return om2eu(ro2om(ro)) + def ro2ax(ro): """Rodrigues vector to axis angle""" @@ -1541,21 +1553,6 @@ def ro2ax(ro): return np.array(ax) -def ro2eu(ro): - """Rodrigues vector to orientation matrix""" - return om2eu(ro2om(ro)) - - -def ro2om(ro): - """Rodgrigues vector to orientation matrix""" - return ax2om(ro2ax(ro)) - - -def ro2qu(ro): - """Rodrigues vector to quaternion""" - return ax2qu(ro2ax(ro)) - - def ro2ho(ro): """Rodrigues vector to homochoric""" if iszero(np.sum(ro[0:3]**2.0)): @@ -1574,7 +1571,21 @@ def ro2cu(ro): #---------- homochoric ---------- - +def ho2qu(ho): + """Homochoric to quaternion""" + return ax2qu(ho2ax(ho)) + + +def ho2om(ho): + """Homochoric to orientation matrix""" + return ax2om(ho2ax(ho)) + + +def ho2eu(ho): + """Homochoric to Euler angles""" + return ax2eu(ho2ax(ho)) + + def ho2ax(ho): """Homochoric to axis angle""" tfit = np.array([+1.0000000000018852, -0.5000000002194847, @@ -1601,34 +1612,21 @@ def ho2ax(ho): return ax -def ho2cu(ho): - """Homochoric to cubochoric""" - return Lambert.BallToCube(ho) - - -def ho2eu(ho): - """Homochoric to Euler angles""" - return ax2eu(ho2ax(ho)) - - -def ho2om(ho): - """Homochoric to orientation matrix""" - return ax2om(ho2ax(ho)) - - def ho2ro(ho): """Axis angle to Rodriques vector""" return ax2ro(ho2ax(ho)) -def ho2qu(ho): - """Homochoric to quaternion""" - return ax2qu(ho2ax(ho)) +def ho2cu(ho): + """Homochoric to cubochoric""" + return Lambert.BallToCube(ho) -def cu2eu(cu): - """Cubochoric to Euler angles""" - return ho2eu(cu2ho(cu)) +#---------- cubochoric ---------- + +def cu2qu(cu): + """Cubochoric to quaternion""" + return ho2qu(cu2ho(cu)) def cu2om(cu): @@ -1636,6 +1634,11 @@ def cu2om(cu): return ho2om(cu2ho(cu)) +def cu2eu(cu): + """Cubochoric to Euler angles""" + return ho2eu(cu2ho(cu)) + + def cu2ax(cu): """Cubochoric to axis angle""" return ho2ax(cu2ho(cu)) @@ -1646,13 +1649,6 @@ def cu2ro(cu): return ho2ro(cu2ho(cu)) -def cu2qu(cu): - """Cubochoric to quaternion""" - return ho2qu(cu2ho(cu)) - - def cu2ho(cu): """Cubochoric to homochoric""" return Lambert.CubeToBall(cu) - - From 5d23a61fb0a381a6a9a3192c1b9be634b43213b2 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 16 Apr 2019 22:17:56 +0200 Subject: [PATCH 18/61] same order as in the python module ... and only one "implicit none" --- src/rotations.f90 | 1307 ++++++++++++++++++++++----------------------- 1 file changed, 626 insertions(+), 681 deletions(-) diff --git a/src/rotations.f90 b/src/rotations.f90 index b899adacb..aed4c5773 100644 --- a/src/rotations.f90 +++ b/src/rotations.f90 @@ -77,7 +77,6 @@ contains !--------------------------------------------------------------------------------------------------- function asQuaternion(self) - implicit none class(rotation), intent(in) :: self real(pReal), dimension(4) :: asQuaternion @@ -87,7 +86,6 @@ end function asQuaternion !--------------------------------------------------------------------------------------------------- function asEulerAngles(self) - implicit none class(rotation), intent(in) :: self real(pReal), dimension(3) :: asEulerAngles @@ -97,7 +95,6 @@ end function asEulerAngles !--------------------------------------------------------------------------------------------------- function asAxisAnglePair(self) - implicit none class(rotation), intent(in) :: self real(pReal), dimension(4) :: asAxisAnglePair @@ -107,7 +104,6 @@ end function asAxisAnglePair !--------------------------------------------------------------------------------------------------- function asRotationMatrix(self) - implicit none class(rotation), intent(in) :: self real(pReal), dimension(3,3) :: asRotationMatrix @@ -117,7 +113,6 @@ end function asRotationMatrix !--------------------------------------------------------------------------------------------------- function asRodriguesFrankVector(self) - implicit none class(rotation), intent(in) :: self real(pReal), dimension(4) :: asRodriguesFrankVector @@ -127,7 +122,6 @@ end function asRodriguesFrankVector !--------------------------------------------------------------------------------------------------- function asHomochoric(self) - implicit none class(rotation), intent(in) :: self real(pReal), dimension(3) :: asHomochoric @@ -140,7 +134,6 @@ end function asHomochoric !--------------------------------------------------------------------------------------------------- subroutine fromRotationMatrix(self,om) - implicit none class(rotation), intent(out) :: self real(pReal), dimension(3,3), intent(in) :: om @@ -158,7 +151,6 @@ function rotVector(self,v,active) use prec, only: & dEq - implicit none real(pReal), dimension(3) :: rotVector class(rotation), intent(in) :: self real(pReal), intent(in), dimension(3) :: v @@ -198,7 +190,6 @@ end function rotVector !--------------------------------------------------------------------------------------------------- function rotTensor(self,m,active) - implicit none real(pReal), dimension(3,3) :: rotTensor class(rotation), intent(in) :: self real(pReal), intent(in), dimension(3,3) :: m @@ -226,7 +217,6 @@ end function rotTensor !--------------------------------------------------------------------------------------------------- function misorientation(self,other) - implicit none type(rotation) :: misorientation class(rotation), intent(in) :: self, other @@ -235,469 +225,12 @@ function misorientation(self,other) end function misorientation -!--------------------------------------------------------------------------------------------------- -! The following routines convert between different representations -!--------------------------------------------------------------------------------------------------- - - -!--------------------------------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @brief Euler angles to orientation matrix -!--------------------------------------------------------------------------------------------------- -pure function eu2om(eu) result(om) - use prec, only: & - dEq0 - - implicit none - real(pReal), intent(in), dimension(3) :: eu - real(pReal), dimension(3,3) :: om - - real(pReal), dimension(3) :: c, s - - c = cos(eu) - s = sin(eu) - - om(1,1) = c(1)*c(3)-s(1)*s(3)*c(2) - om(1,2) = s(1)*c(3)+c(1)*s(3)*c(2) - om(1,3) = s(3)*s(2) - om(2,1) = -c(1)*s(3)-s(1)*c(3)*c(2) - om(2,2) = -s(1)*s(3)+c(1)*c(3)*c(2) - om(2,3) = c(3)*s(2) - om(3,1) = s(1)*s(2) - om(3,2) = -c(1)*s(2) - om(3,3) = c(2) - - where(dEq0(om)) om = 0.0_pReal - -end function eu2om - - -!--------------------------------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @brief convert euler to axis angle -!--------------------------------------------------------------------------------------------------- -pure function eu2ax(eu) result(ax) - use prec, only: & - dEq0, & - dEq - use math, only: & - PI - - implicit none - real(pReal), intent(in), dimension(3) :: eu - real(pReal), dimension(4) :: ax - - real(pReal) :: t, delta, tau, alpha, sigma - - t = tan(eu(2)*0.5) - sigma = 0.5*(eu(1)+eu(3)) - delta = 0.5*(eu(1)-eu(3)) - tau = sqrt(t**2+sin(sigma)**2) - - alpha = merge(PI, 2.0*atan(tau/cos(sigma)), dEq(sigma,PI*0.5_pReal,tol=1.0e-15_pReal)) - - if (dEq0(alpha)) then ! return a default identity axis-angle pair - ax = [ 0.0_pReal, 0.0_pReal, 1.0_pReal, 0.0_pReal ] - else - ax(1:3) = -P/tau * [ t*cos(delta), t*sin(delta), sin(sigma) ] ! passive axis-angle pair so a minus sign in front - ax(4) = alpha - if (alpha < 0.0) ax = -ax ! ensure alpha is positive - end if - -end function eu2ax - - -!--------------------------------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @brief Euler angles to Rodrigues vector -!--------------------------------------------------------------------------------------------------- -pure function eu2ro(eu) result(ro) - use prec, only: & - dEq0 - use, intrinsic :: IEEE_ARITHMETIC, only: & - IEEE_value, & - IEEE_positive_inf - use math, only: & - PI - - implicit none - real(pReal), intent(in), dimension(3) :: eu - real(pReal), dimension(4) :: ro - - ro = eu2ax(eu) - if (ro(4) >= PI) then - ro(4) = IEEE_value(ro(4),IEEE_positive_inf) - elseif(dEq0(ro(4))) then - ro = [ 0.0_pReal, 0.0_pReal, P, 0.0_pReal ] - else - ro(4) = tan(ro(4)*0.5) - end if - -end function eu2ro - - -!--------------------------------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @brief Euler angles to unit quaternion -!--------------------------------------------------------------------------------------------------- -pure function eu2qu(eu) result(qu) - - implicit none - real(pReal), intent(in), dimension(3) :: eu - type(quaternion) :: qu - real(pReal), dimension(3) :: ee - real(pReal) :: cPhi, sPhi - - ee = 0.5_pReal*eu - - cPhi = cos(ee(2)) - sPhi = sin(ee(2)) - - qu = quaternion([ cPhi*cos(ee(1)+ee(3)), & - -P*sPhi*cos(ee(1)-ee(3)), & - -P*sPhi*sin(ee(1)-ee(3)), & - -P*cPhi*sin(ee(1)+ee(3))]) - if(qu%w < 0.0_pReal) qu = qu%homomorphed() - -end function eu2qu - - -!--------------------------------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @brief orientation matrix to Euler angles -!--------------------------------------------------------------------------------------------------- -pure function om2eu(om) result(eu) - use math, only: & - PI - - implicit none - real(pReal), intent(in), dimension(3,3) :: om - real(pReal), dimension(3) :: eu - real(pReal) :: zeta - - if (abs(om(3,3))>1.0_pReal) then - eu = [ atan2( om(1,2),om(1,1)), 0.5*PI*(1-om(3,3)),0.0_pReal ] - else - zeta = 1.0_pReal/sqrt(1.0_pReal-om(3,3)**2.0_pReal) - eu = [atan2(om(3,1)*zeta,-om(3,2)*zeta), & - acos(om(3,3)), & - atan2(om(1,3)*zeta, om(2,3)*zeta)] - end if - where(eu<0.0_pReal) eu = mod(eu+2.0_pReal*PI,[2.0_pReal*PI,PI,2.0_pReal*PI]) - -end function om2eu - - -!--------------------------------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @brief convert axis angle pair to orientation matrix -!--------------------------------------------------------------------------------------------------- -pure function ax2om(ax) result(om) - - implicit none - real(pReal), intent(in), dimension(4) :: ax - real(pReal), dimension(3,3) :: om - - real(pReal) :: q, c, s, omc - integer :: i - - c = cos(ax(4)) - s = sin(ax(4)) - omc = 1.0-c - - forall(i=1:3) om(i,i) = ax(i)**2*omc + c - - q = omc*ax(1)*ax(2) - om(1,2) = q + s*ax(3) - om(2,1) = q - s*ax(3) - - q = omc*ax(2)*ax(3) - om(2,3) = q + s*ax(1) - om(3,2) = q - s*ax(1) - - q = omc*ax(3)*ax(1) - om(3,1) = q + s*ax(2) - om(1,3) = q - s*ax(2) - - if (P > 0.0) om = transpose(om) - -end function ax2om - - -!--------------------------------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @brief convert unit quaternion to Euler angles -!--------------------------------------------------------------------------------------------------- -pure function qu2eu(qu) result(eu) - use prec, only: & - dEq0 - use math, only: & - PI - - implicit none - type(quaternion), intent(in) :: qu - real(pReal), dimension(3) :: eu - - real(pReal) :: q12, q03, chi, chiInv - - q03 = qu%w**2+qu%z**2 - q12 = qu%x**2+qu%y**2 - chi = sqrt(q03*q12) - - degenerated: if (dEq0(chi)) then - eu = merge([atan2(-P*2.0*qu%w*qu%z,qu%w**2-qu%z**2), 0.0_pReal, 0.0_pReal], & - [atan2(2.0*qu%x*qu%y,qu%x**2-qu%y**2), PI, 0.0_pReal], & - dEq0(q12)) - else degenerated - chiInv = 1.0/chi - eu = [atan2((-P*qu%w*qu%y+qu%x*qu%z)*chi, (-P*qu%w*qu%x-qu%y*qu%z)*chi ), & - atan2( 2.0*chi, q03-q12 ), & - atan2(( P*qu%w*qu%y+qu%x*qu%z)*chi, (-P*qu%w*qu%x+qu%y*qu%z)*chi )] - endif degenerated - where(eu<0.0_pReal) eu = mod(eu+2.0_pReal*PI,[2.0_pReal*PI,PI,2.0_pReal*PI]) - -end function qu2eu - - -!--------------------------------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @brief convert axis angle pair to homochoric -!--------------------------------------------------------------------------------------------------- -pure function ax2ho(ax) result(ho) - - implicit none - real(pReal), intent(in), dimension(4) :: ax - real(pReal), dimension(3) :: ho - - real(pReal) :: f - - f = 0.75 * ( ax(4) - sin(ax(4)) ) - f = f**(1.0/3.0) - ho = ax(1:3) * f - -end function ax2ho - - -!--------------------------------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @brief convert homochoric to axis angle pair -!--------------------------------------------------------------------------------------------------- -pure function ho2ax(ho) result(ax) - use prec, only: & - dEq0 - - implicit none - real(pReal), intent(in), dimension(3) :: ho - real(pReal), dimension(4) :: ax - - integer :: i - real(pReal) :: hmag_squared, s, hm - real(pReal), parameter, dimension(16) :: & - tfit = [ 1.0000000000018852_pReal, -0.5000000002194847_pReal, & - -0.024999992127593126_pReal, -0.003928701544781374_pReal, & - -0.0008152701535450438_pReal, -0.0002009500426119712_pReal, & - -0.00002397986776071756_pReal, -0.00008202868926605841_pReal, & - +0.00012448715042090092_pReal, -0.0001749114214822577_pReal, & - +0.0001703481934140054_pReal, -0.00012062065004116828_pReal, & - +0.000059719705868660826_pReal, -0.00001980756723965647_pReal, & - +0.000003953714684212874_pReal, -0.00000036555001439719544_pReal ] - - ! normalize h and store the magnitude - hmag_squared = sum(ho**2.0_pReal) - if (dEq0(hmag_squared)) then - ax = [ 0.0_pReal, 0.0_pReal, 1.0_pReal, 0.0_pReal ] - else - hm = hmag_squared - - ! convert the magnitude to the rotation angle - s = tfit(1) + tfit(2) * hmag_squared - do i=3,16 - hm = hm*hmag_squared - s = s + tfit(i) * hm - end do - ax = [ho/sqrt(hmag_squared), 2.0_pReal*acos(s)] - end if - -end function ho2ax - - -!--------------------------------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @brief convert orientation matrix to axis angle pair -!--------------------------------------------------------------------------------------------------- -function om2ax(om) result(ax) - use prec, only: & - dEq0, & - cEq, & - dNeq0 - use IO, only: & - IO_error - use math, only: & - math_clip, & - math_trace33 - - implicit none - real(pReal), intent(in) :: om(3,3) - real(pReal) :: ax(4) - - real(pReal) :: t - real(pReal), dimension(3) :: Wr, Wi - real(pReal), dimension(10) :: WORK - real(pReal), dimension(3,3) :: VR, devNull, o - integer :: INFO, LWORK, i - - external :: dgeev,sgeev - - o = om - - ! first get the rotation angle - t = 0.5_pReal * (math_trace33(om) - 1.0) - ax(4) = acos(math_clip(t,-1.0_pReal,1.0_pReal)) - - if (dEq0(ax(4))) then - ax(1:3) = [ 0.0, 0.0, 1.0 ] - else - ! set some initial LAPACK variables - INFO = 0 - ! first initialize the parameters for the LAPACK DGEEV routines - LWORK = 20 - - ! call the eigenvalue solver - call dgeev('N','V',3,o,3,Wr,Wi,devNull,3,VR,3,WORK,LWORK,INFO) - if (INFO /= 0) call IO_error(0,ext_msg='Error in om2ax DGEEV return not zero') - i = maxloc(merge(1.0_pReal,0.0_pReal,cEq(cmplx(Wr,Wi,pReal),cmplx(1.0_pReal,0.0_pReal,pReal),tol=1.0e-14_pReal)),dim=1) ! poor substitute for findloc - ax(1:3) = VR(1:3,i) - where ( dNeq0([om(2,3)-om(3,2), om(3,1)-om(1,3), om(1,2)-om(2,1)])) & - ax(1:3) = sign(ax(1:3),-P *[om(2,3)-om(3,2), om(3,1)-om(1,3), om(1,2)-om(2,1)]) - endif - -end function om2ax - - -!--------------------------------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @brief convert Rodrigues vector to axis angle pair -!--------------------------------------------------------------------------------------------------- -pure function ro2ax(ro) result(ax) - use, intrinsic :: IEEE_ARITHMETIC, only: & - IEEE_is_finite - use prec, only: & - dEq0 - use math, only: & - PI - - implicit none - real(pReal), intent(in), dimension(4) :: ro - real(pReal), dimension(4) :: ax - - real(pReal) :: ta, angle - - ta = ro(4) - - if (dEq0(ta)) then - ax = [ 0.0, 0.0, 1.0, 0.0 ] - elseif (.not. IEEE_is_finite(ta)) then - ax = [ ro(1), ro(2), ro(3), PI ] - else - angle = 2.0*atan(ta) - ta = 1.0/norm2(ro(1:3)) - ax = [ ro(1)/ta, ro(2)/ta, ro(3)/ta, angle ] - end if - -end function ro2ax - - -!--------------------------------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @brief convert axis angle pair to Rodrigues vector -!--------------------------------------------------------------------------------------------------- -pure function ax2ro(ax) result(ro) - use, intrinsic :: IEEE_ARITHMETIC, only: & - IEEE_value, & - IEEE_positive_inf - use prec, only: & - dEq0 - use math, only: & - PI - - implicit none - real(pReal), intent(in), dimension(4) :: ax - real(pReal), dimension(4) :: ro - - real(pReal), parameter :: thr = 1.0E-7 - - if (dEq0(ax(4))) then - ro = [ 0.0_pReal, 0.0_pReal, P, 0.0_pReal ] - else - ro(1:3) = ax(1:3) - ! we need to deal with the 180 degree case - ro(4) = merge(IEEE_value(ro(4),IEEE_positive_inf),tan(ax(4)*0.5 ),abs(ax(4)-PI) < thr) - end if - -end function ax2ro - - -!--------------------------------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @brief convert axis angle pair to quaternion -!--------------------------------------------------------------------------------------------------- -pure function ax2qu(ax) result(qu) - use prec, only: & - dEq0 - - implicit none - real(pReal), intent(in), dimension(4) :: ax - type(quaternion) :: qu - - real(pReal) :: c, s - - - if (dEq0(ax(4))) then - qu = quaternion([ 1.0_pReal, 0.0_pReal, 0.0_pReal, 0.0_pReal ]) - else - c = cos(ax(4)*0.5) - s = sin(ax(4)*0.5) - qu = quaternion([ c, ax(1)*s, ax(2)*s, ax(3)*s ]) - end if - -end function ax2qu - - -!--------------------------------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @brief convert Rodrigues vector to homochoric -!--------------------------------------------------------------------------------------------------- -pure function ro2ho(ro) result(ho) - use, intrinsic :: IEEE_ARITHMETIC, only: & - IEEE_is_finite - use prec, only: & - dEq0 - use math, only: & - PI - - implicit none - real(pReal), intent(in), dimension(4) :: ro - real(pReal), dimension(3) :: ho - - real(pReal) :: f - - if (dEq0(norm2(ro(1:3)))) then - ho = [ 0.0, 0.0, 0.0 ] - else - f = merge(2.0*atan(ro(4)) - sin(2.0*atan(ro(4))),PI, IEEE_is_finite(ro(4))) - ho = ro(1:3) * (0.75_pReal*f)**(1.0/3.0) - end if - -end function ro2ho - - !--------------------------------------------------------------------------------------------------- !> @author Marc De Graef, Carnegie Mellon University !> @brief convert unit quaternion to rotation matrix !--------------------------------------------------------------------------------------------------- pure function qu2om(qu) result(om) - implicit none type(quaternion), intent(in) :: qu real(pReal), dimension(3,3) :: om @@ -724,39 +257,36 @@ end function qu2om !--------------------------------------------------------------------------------------------------- !> @author Marc De Graef, Carnegie Mellon University -!> @brief convert rotation matrix to a unit quaternion +!> @brief convert unit quaternion to Euler angles !--------------------------------------------------------------------------------------------------- -function om2qu(om) result(qu) +pure function qu2eu(qu) result(eu) use prec, only: & - dEq + dEq0 + use math, only: & + PI - implicit none - real(pReal), intent(in), dimension(3,3) :: om - type(quaternion) :: qu + type(quaternion), intent(in) :: qu + real(pReal), dimension(3) :: eu - real(pReal), dimension(4) :: qu_A - real(pReal), dimension(4) :: s - - s = [+om(1,1) +om(2,2) +om(3,3) +1.0_pReal, & - +om(1,1) -om(2,2) -om(3,3) +1.0_pReal, & - -om(1,1) +om(2,2) -om(3,3) +1.0_pReal, & - -om(1,1) -om(2,2) +om(3,3) +1.0_pReal] - - qu_A = sqrt(max(s,0.0_pReal))*0.5_pReal*[1.0_pReal,P,P,P] - qu_A = qu_A/norm2(qu_A) - - if(any(dEq(abs(qu_A),1.0_pReal,1.0e-15_pReal))) & - where (.not.(dEq(abs(qu_A),1.0_pReal,1.0e-15_pReal))) qu_A = 0.0_pReal - - if (om(3,2) < om(2,3)) qu_A(2) = -qu_A(2) - if (om(1,3) < om(3,1)) qu_A(3) = -qu_A(3) - if (om(2,1) < om(1,2)) qu_A(4) = -qu_A(4) + real(pReal) :: q12, q03, chi, chiInv - qu = quaternion(qu_A) - !qu_A = om2ax(om) - !if(any(qu_A(1:3) * [qu%x,qu%y,qu%z] < 0.0)) print*, 'sign error' + q03 = qu%w**2+qu%z**2 + q12 = qu%x**2+qu%y**2 + chi = sqrt(q03*q12) + + degenerated: if (dEq0(chi)) then + eu = merge([atan2(-P*2.0*qu%w*qu%z,qu%w**2-qu%z**2), 0.0_pReal, 0.0_pReal], & + [atan2(2.0*qu%x*qu%y,qu%x**2-qu%y**2), PI, 0.0_pReal], & + dEq0(q12)) + else degenerated + chiInv = 1.0/chi + eu = [atan2((-P*qu%w*qu%y+qu%x*qu%z)*chi, (-P*qu%w*qu%x-qu%y*qu%z)*chi ), & + atan2( 2.0*chi, q03-q12 ), & + atan2(( P*qu%w*qu%y+qu%x*qu%z)*chi, (-P*qu%w*qu%x+qu%y*qu%z)*chi )] + endif degenerated + where(eu<0.0_pReal) eu = mod(eu+2.0_pReal*PI,[2.0_pReal*PI,PI,2.0_pReal*PI]) -end function om2qu +end function qu2eu !--------------------------------------------------------------------------------------------------- @@ -771,7 +301,6 @@ pure function qu2ax(qu) result(ax) PI, & math_clip - implicit none type(quaternion), intent(in) :: qu real(pReal), dimension(4) :: ax @@ -835,7 +364,6 @@ pure function qu2ho(qu) result(ho) use math, only: & math_clip - implicit none type(quaternion), intent(in) :: qu real(pReal), dimension(3) :: ho @@ -856,66 +384,129 @@ end function qu2ho !--------------------------------------------------------------------------------------------------- !> @author Marc De Graef, Carnegie Mellon University -!> @brief convert homochoric to cubochoric +!> @brief convert unit quaternion to cubochoric !--------------------------------------------------------------------------------------------------- -function ho2cu(ho) result(cu) - use Lambert, only: & - LambertBallToCube +function qu2cu(qu) result(cu) + + type(quaternion), intent(in) :: qu + real(pReal), dimension(3) :: cu - implicit none - real(pReal), intent(in), dimension(3) :: ho - real(pReal), dimension(3) :: cu + cu = ho2cu(qu2ho(qu)) - cu = LambertBallToCube(ho) - -end function ho2cu +end function qu2cu !--------------------------------------------------------------------------------------------------- !> @author Marc De Graef, Carnegie Mellon University -!> @brief convert cubochoric to homochoric +!> @brief convert rotation matrix to a unit quaternion !--------------------------------------------------------------------------------------------------- -function cu2ho(cu) result(ho) - use Lambert, only: & - LambertCubeToBall +function om2qu(om) result(qu) + use prec, only: & + dEq - implicit none - real(pReal), intent(in), dimension(3) :: cu - real(pReal), dimension(3) :: ho + real(pReal), intent(in), dimension(3,3) :: om + type(quaternion) :: qu + + real(pReal), dimension(4) :: qu_A + real(pReal), dimension(4) :: s - ho = LambertCubeToBall(cu) + s = [+om(1,1) +om(2,2) +om(3,3) +1.0_pReal, & + +om(1,1) -om(2,2) -om(3,3) +1.0_pReal, & + -om(1,1) +om(2,2) -om(3,3) +1.0_pReal, & + -om(1,1) -om(2,2) +om(3,3) +1.0_pReal] -end function cu2ho + qu_A = sqrt(max(s,0.0_pReal))*0.5_pReal*[1.0_pReal,P,P,P] + qu_A = qu_A/norm2(qu_A) + + if(any(dEq(abs(qu_A),1.0_pReal,1.0e-15_pReal))) & + where (.not.(dEq(abs(qu_A),1.0_pReal,1.0e-15_pReal))) qu_A = 0.0_pReal + + if (om(3,2) < om(2,3)) qu_A(2) = -qu_A(2) + if (om(1,3) < om(3,1)) qu_A(3) = -qu_A(3) + if (om(2,1) < om(1,2)) qu_A(4) = -qu_A(4) + + qu = quaternion(qu_A) + !qu_A = om2ax(om) + !if(any(qu_A(1:3) * [qu%x,qu%y,qu%z] < 0.0)) print*, 'sign error' + +end function om2qu !--------------------------------------------------------------------------------------------------- !> @author Marc De Graef, Carnegie Mellon University -!> @brief convert Rodrigues vector to Euler angles +!> @brief orientation matrix to Euler angles !--------------------------------------------------------------------------------------------------- -pure function ro2eu(ro) result(eu) +pure function om2eu(om) result(eu) + use math, only: & + PI - implicit none - real(pReal), intent(in), dimension(4) :: ro - real(pReal), dimension(3) :: eu - - eu = om2eu(ro2om(ro)) - -end function ro2eu + real(pReal), intent(in), dimension(3,3) :: om + real(pReal), dimension(3) :: eu + real(pReal) :: zeta + + if (abs(om(3,3))>1.0_pReal) then + eu = [ atan2( om(1,2),om(1,1)), 0.5*PI*(1-om(3,3)),0.0_pReal ] + else + zeta = 1.0_pReal/sqrt(1.0_pReal-om(3,3)**2.0_pReal) + eu = [atan2(om(3,1)*zeta,-om(3,2)*zeta), & + acos(om(3,3)), & + atan2(om(1,3)*zeta, om(2,3)*zeta)] + end if + where(eu<0.0_pReal) eu = mod(eu+2.0_pReal*PI,[2.0_pReal*PI,PI,2.0_pReal*PI]) + +end function om2eu !--------------------------------------------------------------------------------------------------- !> @author Marc De Graef, Carnegie Mellon University -!> @brief convert Euler angles to homochoric +!> @brief convert orientation matrix to axis angle pair !--------------------------------------------------------------------------------------------------- -pure function eu2ho(eu) result(ho) +function om2ax(om) result(ax) + use prec, only: & + dEq0, & + cEq, & + dNeq0 + use IO, only: & + IO_error + use math, only: & + math_clip, & + math_trace33 - implicit none - real(pReal), intent(in), dimension(3) :: eu - real(pReal), dimension(3) :: ho + real(pReal), intent(in) :: om(3,3) + real(pReal) :: ax(4) + + real(pReal) :: t + real(pReal), dimension(3) :: Wr, Wi + real(pReal), dimension(10) :: WORK + real(pReal), dimension(3,3) :: VR, devNull, o + integer :: INFO, LWORK, i + + external :: dgeev,sgeev + + o = om + + ! first get the rotation angle + t = 0.5_pReal * (math_trace33(om) - 1.0) + ax(4) = acos(math_clip(t,-1.0_pReal,1.0_pReal)) + + if (dEq0(ax(4))) then + ax(1:3) = [ 0.0, 0.0, 1.0 ] + else + ! set some initial LAPACK variables + INFO = 0 + ! first initialize the parameters for the LAPACK DGEEV routines + LWORK = 20 + + ! call the eigenvalue solver + call dgeev('N','V',3,o,3,Wr,Wi,devNull,3,VR,3,WORK,LWORK,INFO) + if (INFO /= 0) call IO_error(0,ext_msg='Error in om2ax DGEEV return not zero') + i = maxloc(merge(1.0_pReal,0.0_pReal,cEq(cmplx(Wr,Wi,pReal),cmplx(1.0_pReal,0.0_pReal,pReal),tol=1.0e-14_pReal)),dim=1) ! poor substitute for findloc + ax(1:3) = VR(1:3,i) + where ( dNeq0([om(2,3)-om(3,2), om(3,1)-om(1,3), om(1,2)-om(2,1)])) & + ax(1:3) = sign(ax(1:3),-P *[om(2,3)-om(3,2), om(3,1)-om(1,3), om(1,2)-om(2,1)]) + endif - ho = ax2ho(eu2ax(eu)) - -end function eu2ho +end function om2ax !--------------------------------------------------------------------------------------------------- @@ -924,7 +515,6 @@ end function eu2ho !--------------------------------------------------------------------------------------------------- pure function om2ro(om) result(ro) - implicit none real(pReal), intent(in), dimension(3,3) :: om real(pReal), dimension(4) :: ro @@ -939,133 +529,12 @@ end function om2ro !--------------------------------------------------------------------------------------------------- function om2ho(om) result(ho) - implicit none real(pReal), intent(in), dimension(3,3) :: om real(pReal), dimension(3) :: ho ho = ax2ho(om2ax(om)) -end function om2ho - - -!--------------------------------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @brief convert axis angle pair to Euler angles -!--------------------------------------------------------------------------------------------------- -pure function ax2eu(ax) result(eu) - - implicit none - real(pReal), intent(in), dimension(4) :: ax - real(pReal), dimension(3) :: eu - - eu = om2eu(ax2om(ax)) - -end function ax2eu - - -!--------------------------------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @brief convert Rodrigues vector to rotation matrix -!--------------------------------------------------------------------------------------------------- -pure function ro2om(ro) result(om) - - implicit none - real(pReal), intent(in), dimension(4) :: ro - real(pReal), dimension(3,3) :: om - - om = ax2om(ro2ax(ro)) - -end function ro2om - - -!--------------------------------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @brief convert Rodrigues vector to unit quaternion -!--------------------------------------------------------------------------------------------------- -pure function ro2qu(ro) result(qu) - - implicit none - real(pReal), intent(in), dimension(4) :: ro - type(quaternion) :: qu - - qu = ax2qu(ro2ax(ro)) - -end function ro2qu - - -!--------------------------------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @brief convert homochoric to Euler angles -!--------------------------------------------------------------------------------------------------- -pure function ho2eu(ho) result(eu) - - implicit none - real(pReal), intent(in), dimension(3) :: ho - real(pReal), dimension(3) :: eu - - eu = ax2eu(ho2ax(ho)) - -end function ho2eu - - -!--------------------------------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @brief convert homochoric to rotation matrix -!--------------------------------------------------------------------------------------------------- -pure function ho2om(ho) result(om) - - implicit none - real(pReal), intent(in), dimension(3) :: ho - real(pReal), dimension(3,3) :: om - - om = ax2om(ho2ax(ho)) - -end function ho2om - - -!--------------------------------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @brief convert homochoric to Rodrigues vector -!--------------------------------------------------------------------------------------------------- -pure function ho2ro(ho) result(ro) - - implicit none - real(pReal), intent(in), dimension(3) :: ho - real(pReal), dimension(4) :: ro - - ro = ax2ro(ho2ax(ho)) - -end function ho2ro - - -!--------------------------------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @brief convert homochoric to unit quaternion -!--------------------------------------------------------------------------------------------------- -pure function ho2qu(ho) result(qu) - - implicit none - real(pReal), intent(in), dimension(3) :: ho - type(quaternion) :: qu - - qu = ax2qu(ho2ax(ho)) - -end function ho2qu - - -!--------------------------------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @brief convert Euler angles to cubochoric -!--------------------------------------------------------------------------------------------------- -function eu2cu(eu) result(cu) - - implicit none - real(pReal), intent(in), dimension(3) :: eu - real(pReal), dimension(3) :: cu - - cu = ho2cu(eu2ho(eu)) - -end function eu2cu +end function om2ho !--------------------------------------------------------------------------------------------------- @@ -1074,7 +543,6 @@ end function eu2cu !--------------------------------------------------------------------------------------------------- function om2cu(om) result(cu) - implicit none real(pReal), intent(in), dimension(3,3) :: om real(pReal), dimension(3) :: cu @@ -1083,13 +551,279 @@ function om2cu(om) result(cu) end function om2cu +!--------------------------------------------------------------------------------------------------- +!> @author Marc De Graef, Carnegie Mellon University +!> @brief Euler angles to unit quaternion +!--------------------------------------------------------------------------------------------------- +pure function eu2qu(eu) result(qu) + + real(pReal), intent(in), dimension(3) :: eu + type(quaternion) :: qu + real(pReal), dimension(3) :: ee + real(pReal) :: cPhi, sPhi + + ee = 0.5_pReal*eu + + cPhi = cos(ee(2)) + sPhi = sin(ee(2)) + + qu = quaternion([ cPhi*cos(ee(1)+ee(3)), & + -P*sPhi*cos(ee(1)-ee(3)), & + -P*sPhi*sin(ee(1)-ee(3)), & + -P*cPhi*sin(ee(1)+ee(3))]) + if(qu%w < 0.0_pReal) qu = qu%homomorphed() + +end function eu2qu + + +!--------------------------------------------------------------------------------------------------- +!> @author Marc De Graef, Carnegie Mellon University +!> @brief Euler angles to orientation matrix +!--------------------------------------------------------------------------------------------------- +pure function eu2om(eu) result(om) + use prec, only: & + dEq0 + + real(pReal), intent(in), dimension(3) :: eu + real(pReal), dimension(3,3) :: om + + real(pReal), dimension(3) :: c, s + + c = cos(eu) + s = sin(eu) + + om(1,1) = c(1)*c(3)-s(1)*s(3)*c(2) + om(1,2) = s(1)*c(3)+c(1)*s(3)*c(2) + om(1,3) = s(3)*s(2) + om(2,1) = -c(1)*s(3)-s(1)*c(3)*c(2) + om(2,2) = -s(1)*s(3)+c(1)*c(3)*c(2) + om(2,3) = c(3)*s(2) + om(3,1) = s(1)*s(2) + om(3,2) = -c(1)*s(2) + om(3,3) = c(2) + + where(dEq0(om)) om = 0.0_pReal + +end function eu2om + + +!--------------------------------------------------------------------------------------------------- +!> @author Marc De Graef, Carnegie Mellon University +!> @brief convert euler to axis angle +!--------------------------------------------------------------------------------------------------- +pure function eu2ax(eu) result(ax) + use prec, only: & + dEq0, & + dEq + use math, only: & + PI + + real(pReal), intent(in), dimension(3) :: eu + real(pReal), dimension(4) :: ax + + real(pReal) :: t, delta, tau, alpha, sigma + + t = tan(eu(2)*0.5) + sigma = 0.5*(eu(1)+eu(3)) + delta = 0.5*(eu(1)-eu(3)) + tau = sqrt(t**2+sin(sigma)**2) + + alpha = merge(PI, 2.0*atan(tau/cos(sigma)), dEq(sigma,PI*0.5_pReal,tol=1.0e-15_pReal)) + + if (dEq0(alpha)) then ! return a default identity axis-angle pair + ax = [ 0.0_pReal, 0.0_pReal, 1.0_pReal, 0.0_pReal ] + else + ax(1:3) = -P/tau * [ t*cos(delta), t*sin(delta), sin(sigma) ] ! passive axis-angle pair so a minus sign in front + ax(4) = alpha + if (alpha < 0.0) ax = -ax ! ensure alpha is positive + end if + +end function eu2ax + + +!--------------------------------------------------------------------------------------------------- +!> @author Marc De Graef, Carnegie Mellon University +!> @brief Euler angles to Rodrigues vector +!--------------------------------------------------------------------------------------------------- +pure function eu2ro(eu) result(ro) + use prec, only: & + dEq0 + use, intrinsic :: IEEE_ARITHMETIC, only: & + IEEE_value, & + IEEE_positive_inf + use math, only: & + PI + + real(pReal), intent(in), dimension(3) :: eu + real(pReal), dimension(4) :: ro + + ro = eu2ax(eu) + if (ro(4) >= PI) then + ro(4) = IEEE_value(ro(4),IEEE_positive_inf) + elseif(dEq0(ro(4))) then + ro = [ 0.0_pReal, 0.0_pReal, P, 0.0_pReal ] + else + ro(4) = tan(ro(4)*0.5) + end if + +end function eu2ro + + +!--------------------------------------------------------------------------------------------------- +!> @author Marc De Graef, Carnegie Mellon University +!> @brief convert Euler angles to homochoric +!--------------------------------------------------------------------------------------------------- +pure function eu2ho(eu) result(ho) + + real(pReal), intent(in), dimension(3) :: eu + real(pReal), dimension(3) :: ho + + ho = ax2ho(eu2ax(eu)) + +end function eu2ho + + +!--------------------------------------------------------------------------------------------------- +!> @author Marc De Graef, Carnegie Mellon University +!> @brief convert Euler angles to cubochoric +!--------------------------------------------------------------------------------------------------- +function eu2cu(eu) result(cu) + + real(pReal), intent(in), dimension(3) :: eu + real(pReal), dimension(3) :: cu + + cu = ho2cu(eu2ho(eu)) + +end function eu2cu + + +!--------------------------------------------------------------------------------------------------- +!> @author Marc De Graef, Carnegie Mellon University +!> @brief convert axis angle pair to quaternion +!--------------------------------------------------------------------------------------------------- +pure function ax2qu(ax) result(qu) + use prec, only: & + dEq0 + + real(pReal), intent(in), dimension(4) :: ax + type(quaternion) :: qu + + real(pReal) :: c, s + + + if (dEq0(ax(4))) then + qu = quaternion([ 1.0_pReal, 0.0_pReal, 0.0_pReal, 0.0_pReal ]) + else + c = cos(ax(4)*0.5) + s = sin(ax(4)*0.5) + qu = quaternion([ c, ax(1)*s, ax(2)*s, ax(3)*s ]) + end if + +end function ax2qu + + +!--------------------------------------------------------------------------------------------------- +!> @author Marc De Graef, Carnegie Mellon University +!> @brief convert axis angle pair to orientation matrix +!--------------------------------------------------------------------------------------------------- +pure function ax2om(ax) result(om) + + real(pReal), intent(in), dimension(4) :: ax + real(pReal), dimension(3,3) :: om + + real(pReal) :: q, c, s, omc + integer :: i + + c = cos(ax(4)) + s = sin(ax(4)) + omc = 1.0-c + + forall(i=1:3) om(i,i) = ax(i)**2*omc + c + + q = omc*ax(1)*ax(2) + om(1,2) = q + s*ax(3) + om(2,1) = q - s*ax(3) + + q = omc*ax(2)*ax(3) + om(2,3) = q + s*ax(1) + om(3,2) = q - s*ax(1) + + q = omc*ax(3)*ax(1) + om(3,1) = q + s*ax(2) + om(1,3) = q - s*ax(2) + + if (P > 0.0) om = transpose(om) + +end function ax2om + + +!--------------------------------------------------------------------------------------------------- +!> @author Marc De Graef, Carnegie Mellon University +!> @brief convert axis angle pair to Euler angles +!--------------------------------------------------------------------------------------------------- +pure function ax2eu(ax) result(eu) + + real(pReal), intent(in), dimension(4) :: ax + real(pReal), dimension(3) :: eu + + eu = om2eu(ax2om(ax)) + +end function ax2eu + + +!--------------------------------------------------------------------------------------------------- +!> @author Marc De Graef, Carnegie Mellon University +!> @brief convert axis angle pair to Rodrigues vector +!--------------------------------------------------------------------------------------------------- +pure function ax2ro(ax) result(ro) + use, intrinsic :: IEEE_ARITHMETIC, only: & + IEEE_value, & + IEEE_positive_inf + use prec, only: & + dEq0 + use math, only: & + PI + + real(pReal), intent(in), dimension(4) :: ax + real(pReal), dimension(4) :: ro + + real(pReal), parameter :: thr = 1.0E-7 + + if (dEq0(ax(4))) then + ro = [ 0.0_pReal, 0.0_pReal, P, 0.0_pReal ] + else + ro(1:3) = ax(1:3) + ! we need to deal with the 180 degree case + ro(4) = merge(IEEE_value(ro(4),IEEE_positive_inf),tan(ax(4)*0.5 ),abs(ax(4)-PI) < thr) + end if + +end function ax2ro + + +!--------------------------------------------------------------------------------------------------- +!> @author Marc De Graef, Carnegie Mellon University +!> @brief convert axis angle pair to homochoric +!--------------------------------------------------------------------------------------------------- +pure function ax2ho(ax) result(ho) + + real(pReal), intent(in), dimension(4) :: ax + real(pReal), dimension(3) :: ho + + real(pReal) :: f + + f = 0.75 * ( ax(4) - sin(ax(4)) ) + f = f**(1.0/3.0) + ho = ax(1:3) * f + +end function ax2ho + + !--------------------------------------------------------------------------------------------------- !> @author Marc De Graef, Carnegie Mellon University !> @brief convert axis angle pair to cubochoric !--------------------------------------------------------------------------------------------------- function ax2cu(ax) result(cu) - implicit none real(pReal), intent(in), dimension(4) :: ax real(pReal), dimension(3) :: cu @@ -1098,13 +832,113 @@ function ax2cu(ax) result(cu) end function ax2cu +!--------------------------------------------------------------------------------------------------- +!> @author Marc De Graef, Carnegie Mellon University +!> @brief convert Rodrigues vector to unit quaternion +!--------------------------------------------------------------------------------------------------- +pure function ro2qu(ro) result(qu) + + real(pReal), intent(in), dimension(4) :: ro + type(quaternion) :: qu + + qu = ax2qu(ro2ax(ro)) + +end function ro2qu + + +!--------------------------------------------------------------------------------------------------- +!> @author Marc De Graef, Carnegie Mellon University +!> @brief convert Rodrigues vector to rotation matrix +!--------------------------------------------------------------------------------------------------- +pure function ro2om(ro) result(om) + + real(pReal), intent(in), dimension(4) :: ro + real(pReal), dimension(3,3) :: om + + om = ax2om(ro2ax(ro)) + +end function ro2om + + +!--------------------------------------------------------------------------------------------------- +!> @author Marc De Graef, Carnegie Mellon University +!> @brief convert Rodrigues vector to Euler angles +!--------------------------------------------------------------------------------------------------- +pure function ro2eu(ro) result(eu) + + real(pReal), intent(in), dimension(4) :: ro + real(pReal), dimension(3) :: eu + + eu = om2eu(ro2om(ro)) + +end function ro2eu + + +!--------------------------------------------------------------------------------------------------- +!> @author Marc De Graef, Carnegie Mellon University +!> @brief convert Rodrigues vector to axis angle pair +!--------------------------------------------------------------------------------------------------- +pure function ro2ax(ro) result(ax) + use, intrinsic :: IEEE_ARITHMETIC, only: & + IEEE_is_finite + use prec, only: & + dEq0 + use math, only: & + PI + + real(pReal), intent(in), dimension(4) :: ro + real(pReal), dimension(4) :: ax + + real(pReal) :: ta, angle + + ta = ro(4) + + if (dEq0(ta)) then + ax = [ 0.0, 0.0, 1.0, 0.0 ] + elseif (.not. IEEE_is_finite(ta)) then + ax = [ ro(1), ro(2), ro(3), PI ] + else + angle = 2.0*atan(ta) + ta = 1.0/norm2(ro(1:3)) + ax = [ ro(1)/ta, ro(2)/ta, ro(3)/ta, angle ] + end if + +end function ro2ax + + +!--------------------------------------------------------------------------------------------------- +!> @author Marc De Graef, Carnegie Mellon University +!> @brief convert Rodrigues vector to homochoric +!--------------------------------------------------------------------------------------------------- +pure function ro2ho(ro) result(ho) + use, intrinsic :: IEEE_ARITHMETIC, only: & + IEEE_is_finite + use prec, only: & + dEq0 + use math, only: & + PI + + real(pReal), intent(in), dimension(4) :: ro + real(pReal), dimension(3) :: ho + + real(pReal) :: f + + if (dEq0(norm2(ro(1:3)))) then + ho = [ 0.0, 0.0, 0.0 ] + else + f = merge(2.0*atan(ro(4)) - sin(2.0*atan(ro(4))),PI, IEEE_is_finite(ro(4))) + ho = ro(1:3) * (0.75_pReal*f)**(1.0/3.0) + end if + +end function ro2ho + + !--------------------------------------------------------------------------------------------------- !> @author Marc De Graef, Carnegie Mellon University !> @brief convert Rodrigues vector to cubochoric !--------------------------------------------------------------------------------------------------- function ro2cu(ro) result(cu) - implicit none real(pReal), intent(in), dimension(4) :: ro real(pReal), dimension(3) :: cu @@ -1115,32 +949,130 @@ end function ro2cu !--------------------------------------------------------------------------------------------------- !> @author Marc De Graef, Carnegie Mellon University -!> @brief convert unit quaternion to cubochoric +!> @brief convert homochoric to unit quaternion !--------------------------------------------------------------------------------------------------- -function qu2cu(qu) result(cu) - - implicit none - type(quaternion), intent(in) :: qu - real(pReal), dimension(3) :: cu +pure function ho2qu(ho) result(qu) - cu = ho2cu(qu2ho(qu)) + real(pReal), intent(in), dimension(3) :: ho + type(quaternion) :: qu -end function qu2cu + qu = ax2qu(ho2ax(ho)) + +end function ho2qu !--------------------------------------------------------------------------------------------------- !> @author Marc De Graef, Carnegie Mellon University -!> @brief convert cubochoric to Euler angles +!> @brief convert homochoric to rotation matrix !--------------------------------------------------------------------------------------------------- -function cu2eu(cu) result(eu) +pure function ho2om(ho) result(om) - implicit none - real(pReal), intent(in), dimension(3) :: cu + real(pReal), intent(in), dimension(3) :: ho + real(pReal), dimension(3,3) :: om + + om = ax2om(ho2ax(ho)) + +end function ho2om + + +!--------------------------------------------------------------------------------------------------- +!> @author Marc De Graef, Carnegie Mellon University +!> @brief convert homochoric to Euler angles +!--------------------------------------------------------------------------------------------------- +pure function ho2eu(ho) result(eu) + + real(pReal), intent(in), dimension(3) :: ho real(pReal), dimension(3) :: eu - eu = ho2eu(cu2ho(cu)) + eu = ax2eu(ho2ax(ho)) -end function cu2eu +end function ho2eu + + +!--------------------------------------------------------------------------------------------------- +!> @author Marc De Graef, Carnegie Mellon University +!> @brief convert homochoric to axis angle pair +!--------------------------------------------------------------------------------------------------- +pure function ho2ax(ho) result(ax) + use prec, only: & + dEq0 + + real(pReal), intent(in), dimension(3) :: ho + real(pReal), dimension(4) :: ax + + integer :: i + real(pReal) :: hmag_squared, s, hm + real(pReal), parameter, dimension(16) :: & + tfit = [ 1.0000000000018852_pReal, -0.5000000002194847_pReal, & + -0.024999992127593126_pReal, -0.003928701544781374_pReal, & + -0.0008152701535450438_pReal, -0.0002009500426119712_pReal, & + -0.00002397986776071756_pReal, -0.00008202868926605841_pReal, & + +0.00012448715042090092_pReal, -0.0001749114214822577_pReal, & + +0.0001703481934140054_pReal, -0.00012062065004116828_pReal, & + +0.000059719705868660826_pReal, -0.00001980756723965647_pReal, & + +0.000003953714684212874_pReal, -0.00000036555001439719544_pReal ] + + ! normalize h and store the magnitude + hmag_squared = sum(ho**2.0_pReal) + if (dEq0(hmag_squared)) then + ax = [ 0.0_pReal, 0.0_pReal, 1.0_pReal, 0.0_pReal ] + else + hm = hmag_squared + + ! convert the magnitude to the rotation angle + s = tfit(1) + tfit(2) * hmag_squared + do i=3,16 + hm = hm*hmag_squared + s = s + tfit(i) * hm + end do + ax = [ho/sqrt(hmag_squared), 2.0_pReal*acos(s)] + end if + +end function ho2ax + + +!--------------------------------------------------------------------------------------------------- +!> @author Marc De Graef, Carnegie Mellon University +!> @brief convert homochoric to Rodrigues vector +!--------------------------------------------------------------------------------------------------- +pure function ho2ro(ho) result(ro) + + real(pReal), intent(in), dimension(3) :: ho + real(pReal), dimension(4) :: ro + + ro = ax2ro(ho2ax(ho)) + +end function ho2ro + + +!--------------------------------------------------------------------------------------------------- +!> @author Marc De Graef, Carnegie Mellon University +!> @brief convert homochoric to cubochoric +!--------------------------------------------------------------------------------------------------- +function ho2cu(ho) result(cu) + use Lambert, only: & + LambertBallToCube + + real(pReal), intent(in), dimension(3) :: ho + real(pReal), dimension(3) :: cu + + cu = LambertBallToCube(ho) + +end function ho2cu + + +!--------------------------------------------------------------------------------------------------- +!> @author Marc De Graef, Carnegie Mellon University +!> @brief convert cubochoric to unit quaternion +!--------------------------------------------------------------------------------------------------- +function cu2qu(cu) result(qu) + + real(pReal), intent(in), dimension(3) :: cu + type(quaternion) :: qu + + qu = ho2qu(cu2ho(cu)) + +end function cu2qu !--------------------------------------------------------------------------------------------------- @@ -1149,7 +1081,6 @@ end function cu2eu !--------------------------------------------------------------------------------------------------- function cu2om(cu) result(om) - implicit none real(pReal), intent(in), dimension(3) :: cu real(pReal), dimension(3,3) :: om @@ -1158,13 +1089,26 @@ function cu2om(cu) result(om) end function cu2om +!--------------------------------------------------------------------------------------------------- +!> @author Marc De Graef, Carnegie Mellon University +!> @brief convert cubochoric to Euler angles +!--------------------------------------------------------------------------------------------------- +function cu2eu(cu) result(eu) + + real(pReal), intent(in), dimension(3) :: cu + real(pReal), dimension(3) :: eu + + eu = ho2eu(cu2ho(cu)) + +end function cu2eu + + !--------------------------------------------------------------------------------------------------- !> @author Marc De Graef, Carnegie Mellon University !> @brief convert cubochoric to axis angle pair !--------------------------------------------------------------------------------------------------- function cu2ax(cu) result(ax) - implicit none real(pReal), intent(in), dimension(3) :: cu real(pReal), dimension(4) :: ax @@ -1179,7 +1123,6 @@ end function cu2ax !--------------------------------------------------------------------------------------------------- function cu2ro(cu) result(ro) - implicit none real(pReal), intent(in), dimension(3) :: cu real(pReal), dimension(4) :: ro @@ -1190,16 +1133,18 @@ end function cu2ro !--------------------------------------------------------------------------------------------------- !> @author Marc De Graef, Carnegie Mellon University -!> @brief convert cubochoric to unit quaternion +!> @brief convert cubochoric to homochoric !--------------------------------------------------------------------------------------------------- -function cu2qu(cu) result(qu) +function cu2ho(cu) result(ho) + use Lambert, only: & + LambertCubeToBall - implicit none real(pReal), intent(in), dimension(3) :: cu - type(quaternion) :: qu + real(pReal), dimension(3) :: ho - qu = ho2qu(cu2ho(cu)) + ho = LambertCubeToBall(cu) + +end function cu2ho -end function cu2qu end module rotations From fa182004470eb67f0e7f8a4a253b4b43787b6dce Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 17 Apr 2019 08:46:03 +0200 Subject: [PATCH 19/61] quaternion is now in separate module avoid long modules with multiple, only loosely related classes --- python/damask/orientation.py | 212 +---------------------------------- python/damask/quaternion.py | 210 ++++++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+), 209 deletions(-) create mode 100644 python/damask/quaternion.py diff --git a/python/damask/orientation.py b/python/damask/orientation.py index 007aecfd9..349c368fa 100644 --- a/python/damask/orientation.py +++ b/python/damask/orientation.py @@ -3,214 +3,8 @@ import math import numpy as np from . import Lambert - -P = -1 - -#################################################################################################### -class Quaternion: - u""" - Quaternion with basic operations - - q is the real part, p = (x, y, z) are the imaginary parts. - Defintion of multiplication depends on variable P, P ∉ {-1,1}. - """ - - def __init__(self, - q = 0.0, - p = np.zeros(3,dtype=float)): - """Initializes to identity unless specified""" - self.q = q - self.p = np.array(p) - - - def __copy__(self): - """Copy""" - return self.__class__(q=self.q, - p=self.p.copy()) - - copy = __copy__ - - - def __iter__(self): - """Components""" - return iter(self.asList()) - - def __repr__(self): - """Readable string""" - return 'Quaternion: (real={q:+.6f}, imag=<{p[0]:+.6f}, {p[1]:+.6f}, {p[2]:+.6f}>)'.format(q=self.q,p=self.p) - - - def __add__(self, other): - """Addition""" - if isinstance(other, Quaternion): - return self.__class__(q=self.q + other.q, - p=self.p + other.p) - else: - return NotImplemented - - def __iadd__(self, other): - """In-place addition""" - if isinstance(other, Quaternion): - self.q += other.q - self.p += other.p - return self - else: - return NotImplemented - - def __pos__(self): - """Unary positive operator""" - return self - - - def __sub__(self, other): - """Subtraction""" - if isinstance(other, Quaternion): - return self.__class__(q=self.q - other.q, - p=self.p - other.p) - else: - return NotImplemented - - def __isub__(self, other): - """In-place subtraction""" - if isinstance(other, Quaternion): - self.q -= other.q - self.p -= other.p - return self - else: - return NotImplemented - - def __neg__(self): - """Unary positive operator""" - self.q *= -1.0 - self.p *= -1.0 - return self - - - def __mul__(self, other): - """Multiplication with quaternion or scalar""" - if isinstance(other, Quaternion): - return self.__class__(q=self.q*other.q - np.dot(self.p,other.p), - p=self.q*other.p + other.q*self.p + P * np.cross(self.p,other.p)) - elif isinstance(other, (int, float)): - return self.__class__(q=self.q*other, - p=self.p*other) - else: - return NotImplemented - - def __imul__(self, other): - """In-place multiplication with quaternion or scalar""" - if isinstance(other, Quaternion): - self.q = self.q*other.q - np.dot(self.p,other.p) - self.p = self.q*other.p + other.q*self.p + P * np.cross(self.p,other.p) - return self - elif isinstance(other, (int, float)): - self *= other - return self - else: - return NotImplemented - - - def __truediv__(self, other): - """Divsion with quaternion or scalar""" - if isinstance(other, Quaternion): - s = other.conjugate()/abs(other)**2. - return self.__class__(q=self.q * s, - p=self.p * s) - elif isinstance(other, (int, float)): - self.q /= other - self.p /= other - return self - else: - return NotImplemented - - def __itruediv__(self, other): - """In-place divsion with quaternion or scalar""" - if isinstance(other, Quaternion): - s = other.conjugate()/abs(other)**2. - self *= s - return self - elif isinstance(other, (int, float)): - self.q /= other - return self - else: - return NotImplemented - - - def __pow__(self, exponent): - """Power""" - if isinstance(exponent, (int, float)): - omega = np.acos(self.q) - return self.__class__(q= np.cos(exponent*omega), - p=self.p * np.sin(exponent*omega)/np.sin(omega)) - else: - return NotImplemented - - def __ipow__(self, exponent): - """In-place power""" - if isinstance(exponent, (int, float)): - omega = np.acos(self.q) - self.q = np.cos(exponent*omega) - self.p *= np.sin(exponent*omega)/np.sin(omega) - else: - return NotImplemented - - - def __abs__(self): - """Norm""" - return math.sqrt(self.q ** 2 + np.dot(self.p,self.p)) - - magnitude = __abs__ - - - def __eq__(self,other): - """Equal (sufficiently close) to each other""" - return np.isclose(( self-other).magnitude(),0.0) \ - or np.isclose((-self-other).magnitude(),0.0) - - def __ne__(self,other): - """Not equal (sufficiently close) to each other""" - return not self.__eq__(other) - - - def asM(self): - """Intermediate representation useful for quaternion averaging (see F. Landis Markley et al.)""" - return np.outer(self.asArray(),self.asArray()) - - def asArray(self): - """As numpy array""" - return np.array((self.q,self.p[0],self.p[1],self.p[2])) - - def asList(self): - return [self.q]+list(self.p) - - def normalize(self): - d = self.magnitude() - if d > 0.0: - self.q /= d - self.p /= d - return self - - def normalized(self): - return self.copy().normalize() - - - def conjugate(self): - self.p = -self.p - return self - - def conjugated(self): - return self.copy().conjugate() - - - def homomorph(self): - if self.q < 0.0: - self.q = -self.q - self.p = -self.p - return self - - def homomorphed(self): - return self.copy().homomorph() - +from quaternion import Quaternion +from quaternion import P as P #################################################################################################### @@ -488,7 +282,7 @@ class Rotation: for i,(r,n) in enumerate(zip(rotations,weights)): M = r.asM() * n if i == 0 \ - else M + r.asM() * n # noqa add (multiples) of this rotation to average noqa + else M + r.asM() * n # noqa add (multiples) of this rotation to average noqa eig, vec = np.linalg.eig(M/N) return Rotation.fromQuaternion(np.real(vec.T[eig.argmax()]),acceptHomomorph = True) diff --git a/python/damask/quaternion.py b/python/damask/quaternion.py new file mode 100644 index 000000000..7c98a6d1c --- /dev/null +++ b/python/damask/quaternion.py @@ -0,0 +1,210 @@ +# -*- coding: UTF-8 no BOM -*- + +import numpy as np + +P = -1 # convention (sed DOI:10.1088/0965-0393/23/8/083501) + +#################################################################################################### +class Quaternion: + u""" + Quaternion with basic operations + + q is the real part, p = (x, y, z) are the imaginary parts. + Defintion of multiplication depends on variable P, P ∈ {-1,1}. + """ + + def __init__(self, + q = 0.0, + p = np.zeros(3,dtype=float)): + """Initializes to identity unless specified""" + self.q = q + self.p = np.array(p) + + + def __copy__(self): + """Copy""" + return self.__class__(q=self.q, + p=self.p.copy()) + + copy = __copy__ + + + def __iter__(self): + """Components""" + return iter(self.asList()) + + def __repr__(self): + """Readable string""" + return 'Quaternion: (real={q:+.6f}, imag=<{p[0]:+.6f}, {p[1]:+.6f}, {p[2]:+.6f}>)'.format(q=self.q,p=self.p) + + + def __add__(self, other): + """Addition""" + if isinstance(other, Quaternion): + return self.__class__(q=self.q + other.q, + p=self.p + other.p) + else: + return NotImplemented + + def __iadd__(self, other): + """In-place addition""" + if isinstance(other, Quaternion): + self.q += other.q + self.p += other.p + return self + else: + return NotImplemented + + def __pos__(self): + """Unary positive operator""" + return self + + + def __sub__(self, other): + """Subtraction""" + if isinstance(other, Quaternion): + return self.__class__(q=self.q - other.q, + p=self.p - other.p) + else: + return NotImplemented + + def __isub__(self, other): + """In-place subtraction""" + if isinstance(other, Quaternion): + self.q -= other.q + self.p -= other.p + return self + else: + return NotImplemented + + def __neg__(self): + """Unary positive operator""" + self.q *= -1.0 + self.p *= -1.0 + return self + + + def __mul__(self, other): + """Multiplication with quaternion or scalar""" + if isinstance(other, Quaternion): + return self.__class__(q=self.q*other.q - np.dot(self.p,other.p), + p=self.q*other.p + other.q*self.p + P * np.cross(self.p,other.p)) + elif isinstance(other, (int, float)): + return self.__class__(q=self.q*other, + p=self.p*other) + else: + return NotImplemented + + def __imul__(self, other): + """In-place multiplication with quaternion or scalar""" + if isinstance(other, Quaternion): + self.q = self.q*other.q - np.dot(self.p,other.p) + self.p = self.q*other.p + other.q*self.p + P * np.cross(self.p,other.p) + return self + elif isinstance(other, (int, float)): + self *= other + return self + else: + return NotImplemented + + + def __truediv__(self, other): + """Divsion with quaternion or scalar""" + if isinstance(other, Quaternion): + s = other.conjugate()/abs(other)**2. + return self.__class__(q=self.q * s, + p=self.p * s) + elif isinstance(other, (int, float)): + self.q /= other + self.p /= other + return self + else: + return NotImplemented + + def __itruediv__(self, other): + """In-place divsion with quaternion or scalar""" + if isinstance(other, Quaternion): + s = other.conjugate()/abs(other)**2. + self *= s + return self + elif isinstance(other, (int, float)): + self.q /= other + return self + else: + return NotImplemented + + + def __pow__(self, exponent): + """Power""" + if isinstance(exponent, (int, float)): + omega = np.acos(self.q) + return self.__class__(q= np.cos(exponent*omega), + p=self.p * np.sin(exponent*omega)/np.sin(omega)) + else: + return NotImplemented + + def __ipow__(self, exponent): + """In-place power""" + if isinstance(exponent, (int, float)): + omega = np.acos(self.q) + self.q = np.cos(exponent*omega) + self.p *= np.sin(exponent*omega)/np.sin(omega) + else: + return NotImplemented + + + def __abs__(self): + """Norm""" + return np.sqrt(self.q ** 2 + np.dot(self.p,self.p)) + + magnitude = __abs__ + + + def __eq__(self,other): + """Equal (sufficiently close) to each other""" + return np.isclose(( self-other).magnitude(),0.0) \ + or np.isclose((-self-other).magnitude(),0.0) + + def __ne__(self,other): + """Not equal (sufficiently close) to each other""" + return not self.__eq__(other) + + + def asM(self): + """Intermediate representation useful for quaternion averaging (see F. Landis Markley et al.)""" + return np.outer(self.asArray(),self.asArray()) + + def asArray(self): + """As numpy array""" + return np.array((self.q,self.p[0],self.p[1],self.p[2])) + + def asList(self): + return [self.q]+list(self.p) + + def normalize(self): + d = self.magnitude() + if d > 0.0: + self.q /= d + self.p /= d + return self + + def normalized(self): + return self.copy().normalize() + + + def conjugate(self): + self.p = -self.p + return self + + def conjugated(self): + return self.copy().conjugate() + + + def homomorph(self): + if self.q < 0.0: + self.q = -self.q + self.p = -self.p + return self + + def homomorphed(self): + return self.copy().homomorph() From c7c6627dfb7e1871b3dc334338bd22974862c010 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 17 Apr 2019 08:49:26 +0200 Subject: [PATCH 20/61] don't try to figure out the input --- python/damask/orientation.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/python/damask/orientation.py b/python/damask/orientation.py index 349c368fa..f2302e992 100644 --- a/python/damask/orientation.py +++ b/python/damask/orientation.py @@ -446,13 +446,7 @@ class Symmetry: Representation of Orientation and Disorientation Data for Cubic, Hexagonal, Tetragonal and Orthorhombic Crystals Acta Cryst. (1991). A47, 780-789 """ - if isinstance(rodrigues, Quaternion): - R = rodrigues.asRodrigues() # translate accidentially passed quaternion - else: - R = rodrigues - - if R.shape[0]==4: # transition old (length not stored separately) to new - R = (R[0:3]*R[3]) + R = rodrigues epsilon = 0.0 if self.lattice == 'cubic': @@ -910,7 +904,7 @@ class Orientation: for k in range(2): r.inverse() breaker = self.lattice.symmetry.inFZ(r.asRodrigues()) \ - and (not SST or other.lattice.symmetry.inDisorientationSST(r.asRodrigues())) + and (not SST or other.lattice.symmetry.inDisorientationSST(r.asRodrigues(vector=True))) if breaker: break if breaker: break if breaker: break From 8609eb6eb77ec62c2dec93d994d966cc0abc9b2c Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 17 Apr 2019 09:29:49 +0200 Subject: [PATCH 21/61] improved names and layout --- python/damask/orientation.py | 129 ++++++++++++++++++----------------- 1 file changed, 66 insertions(+), 63 deletions(-) diff --git a/python/damask/orientation.py b/python/damask/orientation.py index f2302e992..c989bc7c0 100644 --- a/python/damask/orientation.py +++ b/python/damask/orientation.py @@ -110,6 +110,11 @@ class Rotation: def misorientation(self,other): """Misorientation""" return self.__class__(other.quaternion*self.quaternion.conjugated()) + + + def average(self,other): + """Calculate the average rotation""" + return Rotation.fromAverage([self,other]) ################################################################################################ @@ -262,9 +267,9 @@ class Rotation: @classmethod - def average(cls, - rotations, - weights = []): + def fromAverage(cls, + rotations, + weights = []): """ Average rotation @@ -272,6 +277,8 @@ class Rotation: Averaging Quaternions, Journal of Guidance, Control, and Dynamics, Vol. 30, No. 4 (2007), pp. 1193-1197. doi: 10.2514/1.28949 + + usage: input a list of rotations and optional weights """ if not all(isinstance(item, Rotation) for item in rotations): raise TypeError("Only instances of Rotation can be averaged.") @@ -335,56 +342,56 @@ class Symmetry: """List (or single element) of symmetry operations as rotations.""" if self.lattice == 'cubic': symQuats = [ - [ 1.0, 0.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0, 0.0 ], - [ 0.0, 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 0.0, 1.0 ], - [ 0.0, 0.0, 0.5*math.sqrt(2), 0.5*math.sqrt(2) ], - [ 0.0, 0.0, 0.5*math.sqrt(2),-0.5*math.sqrt(2) ], - [ 0.0, 0.5*math.sqrt(2), 0.0, 0.5*math.sqrt(2) ], - [ 0.0, 0.5*math.sqrt(2), 0.0, -0.5*math.sqrt(2) ], - [ 0.0, 0.5*math.sqrt(2),-0.5*math.sqrt(2), 0.0 ], - [ 0.0, -0.5*math.sqrt(2),-0.5*math.sqrt(2), 0.0 ], - [ 0.5, 0.5, 0.5, 0.5 ], - [-0.5, 0.5, 0.5, 0.5 ], - [-0.5, 0.5, 0.5, -0.5 ], - [-0.5, 0.5, -0.5, 0.5 ], - [-0.5, -0.5, 0.5, 0.5 ], - [-0.5, -0.5, 0.5, -0.5 ], - [-0.5, -0.5, -0.5, 0.5 ], - [-0.5, 0.5, -0.5, -0.5 ], - [-0.5*math.sqrt(2), 0.0, 0.0, 0.5*math.sqrt(2) ], - [ 0.5*math.sqrt(2), 0.0, 0.0, 0.5*math.sqrt(2) ], - [-0.5*math.sqrt(2), 0.0, 0.5*math.sqrt(2), 0.0 ], - [-0.5*math.sqrt(2), 0.0, -0.5*math.sqrt(2), 0.0 ], - [-0.5*math.sqrt(2), 0.5*math.sqrt(2), 0.0, 0.0 ], - [-0.5*math.sqrt(2),-0.5*math.sqrt(2), 0.0, 0.0 ], + [ 1.0, 0.0, 0.0, 0.0 ], + [ 0.0, 1.0, 0.0, 0.0 ], + [ 0.0, 0.0, 1.0, 0.0 ], + [ 0.0, 0.0, 0.0, 1.0 ], + [ 0.0, 0.0, 0.5*np.sqrt(2), 0.5*np.sqrt(2) ], + [ 0.0, 0.0, 0.5*np.sqrt(2),-0.5*np.sqrt(2) ], + [ 0.0, 0.5*np.sqrt(2), 0.0, 0.5*np.sqrt(2) ], + [ 0.0, 0.5*np.sqrt(2), 0.0, -0.5*np.sqrt(2) ], + [ 0.0, 0.5*np.sqrt(2),-0.5*np.sqrt(2), 0.0 ], + [ 0.0, -0.5*np.sqrt(2),-0.5*np.sqrt(2), 0.0 ], + [ 0.5, 0.5, 0.5, 0.5 ], + [-0.5, 0.5, 0.5, 0.5 ], + [-0.5, 0.5, 0.5, -0.5 ], + [-0.5, 0.5, -0.5, 0.5 ], + [-0.5, -0.5, 0.5, 0.5 ], + [-0.5, -0.5, 0.5, -0.5 ], + [-0.5, -0.5, -0.5, 0.5 ], + [-0.5, 0.5, -0.5, -0.5 ], + [-0.5*np.sqrt(2), 0.0, 0.0, 0.5*np.sqrt(2) ], + [ 0.5*np.sqrt(2), 0.0, 0.0, 0.5*np.sqrt(2) ], + [-0.5*np.sqrt(2), 0.0, 0.5*np.sqrt(2), 0.0 ], + [-0.5*np.sqrt(2), 0.0, -0.5*np.sqrt(2), 0.0 ], + [-0.5*np.sqrt(2), 0.5*np.sqrt(2), 0.0, 0.0 ], + [-0.5*np.sqrt(2),-0.5*np.sqrt(2), 0.0, 0.0 ], ] elif self.lattice == 'hexagonal': symQuats = [ - [ 1.0,0.0,0.0,0.0 ], - [-0.5*math.sqrt(3), 0.0, 0.0,-0.5 ], - [ 0.5, 0.0, 0.0, 0.5*math.sqrt(3) ], - [ 0.0,0.0,0.0,1.0 ], - [-0.5, 0.0, 0.0, 0.5*math.sqrt(3) ], - [-0.5*math.sqrt(3), 0.0, 0.0, 0.5 ], - [ 0.0,1.0,0.0,0.0 ], - [ 0.0,-0.5*math.sqrt(3), 0.5, 0.0 ], - [ 0.0, 0.5,-0.5*math.sqrt(3), 0.0 ], - [ 0.0,0.0,1.0,0.0 ], - [ 0.0,-0.5,-0.5*math.sqrt(3), 0.0 ], - [ 0.0, 0.5*math.sqrt(3), 0.5, 0.0 ], + [ 1.0, 0.0, 0.0, 0.0 ], + [-0.5*np.sqrt(3), 0.0, 0.0, -0.5 ], + [ 0.5, 0.0, 0.0, 0.5*np.sqrt(3) ], + [ 0.0, 0.0, 0.0, 1.0 ], + [-0.5, 0.0, 0.0, 0.5*np.sqrt(3) ], + [-0.5*np.sqrt(3), 0.0, 0.0, 0.5 ], + [ 0.0, 1.0, 0.0, 0.0 ], + [ 0.0, -0.5*np.sqrt(3), 0.5, 0.0 ], + [ 0.0, 0.5, -0.5*np.sqrt(3), 0.0 ], + [ 0.0, 0.0, 1.0, 0.0 ], + [ 0.0, -0.5, -0.5*np.sqrt(3), 0.0 ], + [ 0.0, 0.5*np.sqrt(3), 0.5, 0.0 ], ] elif self.lattice == 'tetragonal': symQuats = [ - [ 1.0,0.0,0.0,0.0 ], - [ 0.0,1.0,0.0,0.0 ], - [ 0.0,0.0,1.0,0.0 ], - [ 0.0,0.0,0.0,1.0 ], - [ 0.0, 0.5*math.sqrt(2), 0.5*math.sqrt(2), 0.0 ], - [ 0.0,-0.5*math.sqrt(2), 0.5*math.sqrt(2), 0.0 ], - [ 0.5*math.sqrt(2), 0.0, 0.0, 0.5*math.sqrt(2) ], - [-0.5*math.sqrt(2), 0.0, 0.0, 0.5*math.sqrt(2) ], + [ 1.0, 0.0, 0.0, 0.0 ], + [ 0.0, 1.0, 0.0, 0.0 ], + [ 0.0, 0.0, 1.0, 0.0 ], + [ 0.0, 0.0, 0.0, 1.0 ], + [ 0.0, 0.5*np.sqrt(2), 0.5*np.sqrt(2), 0.0 ], + [ 0.0, -0.5*np.sqrt(2), 0.5*np.sqrt(2), 0.0 ], + [ 0.5*np.sqrt(2), 0.0, 0.0, 0.5*np.sqrt(2) ], + [-0.5*np.sqrt(2), 0.0, 0.0, 0.5*np.sqrt(2) ], ] elif self.lattice == 'orthorhombic': symQuats = [ @@ -447,6 +454,8 @@ class Symmetry: Acta Cryst. (1991). A47, 780-789 """ R = rodrigues + if (len(R) != 3): + raise ValueError('Input is not a Rodriques-Frank vector.\n') epsilon = 0.0 if self.lattice == 'cubic': @@ -967,21 +976,10 @@ class Orientation: @classmethod - def average(cls, - orientations, - weights = []): - """ - Average orientation - - ref: F. Landis Markley, Yang Cheng, John Lucas Crassidis, and Yaakov Oshman. - Averaging Quaternions, - Journal of Guidance, Control, and Dynamics, Vol. 30, No. 4 (2007), pp. 1193-1197. - doi: 10.2514/1.28949 - usage: - a = Orientation(Eulers=np.radians([10, 10, 0]), symmetry='hexagonal') - b = Orientation(Eulers=np.radians([20, 0, 0]), symmetry='hexagonal') - avg = Orientation.average([a,b]) - """ + def fromAverage(cls, + orientations, + weights = []): + """Create orientation from average of list of orientations""" if not all(isinstance(item, Orientation) for item in orientations): raise TypeError("Only instances of Orientation can be averaged.") @@ -993,7 +991,12 @@ class Orientation: SST = False, # select (o[ther]'s) sym orientation symmetries = True)[2]).rotation) # with lowest misorientation - return Orientation(Rotation.average(closest,weights),ref.lattice) + return Orientation(Rotation.fromAverage(closest,weights),ref.lattice) + + + def average(self,other): + """Calculate the average rotation""" + return Orientation.fromAverage([self,other]) #################################################################################################### From 3f8c16262e6ea32bc18a6937c11bbc991cc6b657 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 17 Apr 2019 09:45:18 +0200 Subject: [PATCH 22/61] fixed import statement previous form only worked in python/damask folder --- python/damask/orientation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/damask/orientation.py b/python/damask/orientation.py index c989bc7c0..4a6d4e05d 100644 --- a/python/damask/orientation.py +++ b/python/damask/orientation.py @@ -3,8 +3,8 @@ import math import numpy as np from . import Lambert -from quaternion import Quaternion -from quaternion import P as P +from .quaternion import Quaternion +from .quaternion import P #################################################################################################### From 079e683dd181be27bf26c6fd7b4860555793899f Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 17 Apr 2019 10:48:18 +0200 Subject: [PATCH 23/61] disorientation returns Orientation, not Rotation --- python/damask/orientation.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/damask/orientation.py b/python/damask/orientation.py index 4a6d4e05d..94ce9c416 100644 --- a/python/damask/orientation.py +++ b/python/damask/orientation.py @@ -899,8 +899,8 @@ class Orientation: (Currently requires same symmetry for both orientations. Look into A. Heinz and P. Neumann 1991 for cases with differing sym.) """ - #if self.lattice.symmetry != other.lattice.symmetry: - # raise NotImplementedError('disorientation between different symmetry classes not supported yet.') + if self.lattice.symmetry != other.lattice.symmetry: + raise NotImplementedError('disorientation between different symmetry classes not supported yet.') mySymEqs = self.equivalentOrientations() if SST else self.equivalentOrientations([0]) # take all or only first sym operation otherSymEqs = other.equivalentOrientations() @@ -918,7 +918,7 @@ class Orientation: if breaker: break if breaker: break - return (r, i,j, k == 1) if symmetries else r # disorientation ... + return (Orientation(r,self.lattice), i,j, k == 1) if symmetries else Orientation(r,self.lattice)# disorientation ... # ... own sym, other sym, # self-->other: True, self<--other: False From a6e6db05590c4d8ebfcc4e19a4a875a7e7fedbbc Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 17 Apr 2019 12:51:00 +0200 Subject: [PATCH 24/61] more stable/robust conversions --- python/damask/orientation.py | 8 ++++---- src/rotations.f90 | 40 ++++++++---------------------------- 2 files changed, 13 insertions(+), 35 deletions(-) diff --git a/python/damask/orientation.py b/python/damask/orientation.py index 94ce9c416..d9472581a 100644 --- a/python/damask/orientation.py +++ b/python/damask/orientation.py @@ -1077,11 +1077,11 @@ def qu2ax(qu): Modified version of the original formulation, should be numerically more stable """ - if isone(abs(qu[0])): # set axis to [001] if the angle is 0/360 + if iszero(qu[1]**2+qu[2]**2+qu[3]**2): # set axis to [001] if the angle is 0/360 ax = [ 0.0, 0.0, 1.0, 0.0 ] elif not iszero(qu[0]): - omega = 2.0 * np.arccos(qu[0]) s = np.sign(qu[0])/np.sqrt(qu[1]**2+qu[2]**2+qu[3]**2) + omega = 2.0 * np.arccos(np.clip(qu[0],-1.0,1.0)) ax = [ qu[1]*s, qu[2]*s, qu[3]*s, omega ] else: ax = [ qu[1], qu[2], qu[3], np.pi] @@ -1126,9 +1126,9 @@ def om2qu(om): """ Orientation matrix to quaternion - The original formulation (direct conversion) had numerical issues + The original formulation (direct conversion) had (numerical?) issues """ - return ax2qu(om2ax(om)) + return eu2qu(om2eu(om)) def om2eu(om): diff --git a/src/rotations.f90 b/src/rotations.f90 index aed4c5773..5279b179c 100644 --- a/src/rotations.f90 +++ b/src/rotations.f90 @@ -306,12 +306,11 @@ pure function qu2ax(qu) result(ax) real(pReal) :: omega, s - omega = 2.0 * acos(math_clip(qu%w,-1.0_pReal,1.0_pReal)) - ! if the angle equals zero, then we return the rotation axis as [001] - if (dEq0(omega)) then - ax = [ 0.0, 0.0, 1.0, 0.0 ] + if (dEq0(qu%x**2+qu%y**2+qu%z**2)) then + ax = [ 0.0_pReal, 0.0_pReal, 1.0_pReal, 0.0_pReal ] ! axis = [001] elseif (dNeq0(qu%w)) then s = sign(1.0_pReal,qu%w)/sqrt(qu%x**2+qu%y**2+qu%z**2) + omega = 2.0_pReal * acos(math_clip(qu%w,-1.0_pReal,1.0_pReal)) ax = [ qu%x*s, qu%y*s, qu%z*s, omega ] else ax = [ qu%x, qu%y, qu%z, PI ] @@ -397,37 +396,16 @@ end function qu2cu !--------------------------------------------------------------------------------------------------- -!> @author Marc De Graef, Carnegie Mellon University -!> @brief convert rotation matrix to a unit quaternion +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @brief convert rotation matrix to cubochoric +!> @details the original formulation (direct conversion) had (numerical?) issues !--------------------------------------------------------------------------------------------------- function om2qu(om) result(qu) - use prec, only: & - dEq - real(pReal), intent(in), dimension(3,3) :: om - type(quaternion) :: qu - - real(pReal), dimension(4) :: qu_A - real(pReal), dimension(4) :: s + real(pReal), intent(in), dimension(3,3) :: om + type(quaternion) :: qu - s = [+om(1,1) +om(2,2) +om(3,3) +1.0_pReal, & - +om(1,1) -om(2,2) -om(3,3) +1.0_pReal, & - -om(1,1) +om(2,2) -om(3,3) +1.0_pReal, & - -om(1,1) -om(2,2) +om(3,3) +1.0_pReal] - - qu_A = sqrt(max(s,0.0_pReal))*0.5_pReal*[1.0_pReal,P,P,P] - qu_A = qu_A/norm2(qu_A) - - if(any(dEq(abs(qu_A),1.0_pReal,1.0e-15_pReal))) & - where (.not.(dEq(abs(qu_A),1.0_pReal,1.0e-15_pReal))) qu_A = 0.0_pReal - - if (om(3,2) < om(2,3)) qu_A(2) = -qu_A(2) - if (om(1,3) < om(3,1)) qu_A(3) = -qu_A(3) - if (om(2,1) < om(1,2)) qu_A(4) = -qu_A(4) - - qu = quaternion(qu_A) - !qu_A = om2ax(om) - !if(any(qu_A(1:3) * [qu%x,qu%y,qu%z] < 0.0)) print*, 'sign error' + qu = eu2qu(om2eu(om)) end function om2qu From fdd5b93e7c28ab892d4dc5cc9ed418e30d5f18fd Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 17 Apr 2019 15:19:41 +0200 Subject: [PATCH 25/61] avoid FPE exceptions --- python/damask/orientation.py | 8 ++++---- src/rotations.f90 | 7 ++++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/python/damask/orientation.py b/python/damask/orientation.py index d9472581a..89a4638ca 100644 --- a/python/damask/orientation.py +++ b/python/damask/orientation.py @@ -1132,14 +1132,14 @@ def om2qu(om): def om2eu(om): - """Euler angles to orientation matrix""" - if isone(om[2,2]**2): - eu = np.array([np.arctan2( om[0,1],om[0,0]), np.pi*0.5*(1-om[2,2]),0.0]) # following the paper, not the reference implementation - else: + """Orientation matrix to Euler angles""" + if abs(om[2,2]) < 1.0: zeta = 1.0/np.sqrt(1.0-om[2,2]**2) eu = np.array([np.arctan2(om[2,0]*zeta,-om[2,1]*zeta), np.arccos(om[2,2]), np.arctan2(om[0,2]*zeta, om[1,2]*zeta)]) + else: + eu = np.array([np.arctan2( om[0,1],om[0,0]), np.pi*0.5*(1-om[2,2]),0.0]) # following the paper, not the reference implementation # reduce Euler angles to definition range, i.e a lower limit of 0.0 eu = np.where(eu<0, (eu+2.0*np.pi)%np.array([2.0*np.pi,np.pi,2.0*np.pi]),eu) diff --git a/src/rotations.f90 b/src/rotations.f90 index 5279b179c..69529ed24 100644 --- a/src/rotations.f90 +++ b/src/rotations.f90 @@ -422,14 +422,15 @@ pure function om2eu(om) result(eu) real(pReal), dimension(3) :: eu real(pReal) :: zeta - if (abs(om(3,3))>1.0_pReal) then - eu = [ atan2( om(1,2),om(1,1)), 0.5*PI*(1-om(3,3)),0.0_pReal ] - else + if (abs(om(3,3)) < 1.0_pReal) then zeta = 1.0_pReal/sqrt(1.0_pReal-om(3,3)**2.0_pReal) eu = [atan2(om(3,1)*zeta,-om(3,2)*zeta), & acos(om(3,3)), & atan2(om(1,3)*zeta, om(2,3)*zeta)] + else + eu = [ atan2( om(1,2),om(1,1)), 0.5*PI*(1-om(3,3)),0.0_pReal ] end if + where(eu<0.0_pReal) eu = mod(eu+2.0_pReal*PI,[2.0_pReal*PI,PI,2.0_pReal*PI]) end function om2eu From 481aac795254e447680ad377ed31a42715c08734 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 18 Apr 2019 13:46:58 +0200 Subject: [PATCH 26/61] misorientation calculation did not always follow convention - return homomorphed quaternion to ensure that real component is > 0 (equivalent to have axis angle limited to [0, pi] --- python/damask/orientation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/damask/orientation.py b/python/damask/orientation.py index 89a4638ca..1f0dc521a 100644 --- a/python/damask/orientation.py +++ b/python/damask/orientation.py @@ -109,7 +109,7 @@ class Rotation: def misorientation(self,other): """Misorientation""" - return self.__class__(other.quaternion*self.quaternion.conjugated()) + return self.__class__((other.quaternion*self.quaternion.conjugated()).homomorph()) def average(self,other): From 71b00363239634477ab4689f0778b65f7bce0807 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 18 Apr 2019 14:26:53 +0200 Subject: [PATCH 27/61] return rotation as misorientation --- python/damask/orientation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/damask/orientation.py b/python/damask/orientation.py index 1f0dc521a..c0c817ca6 100644 --- a/python/damask/orientation.py +++ b/python/damask/orientation.py @@ -918,7 +918,7 @@ class Orientation: if breaker: break if breaker: break - return (Orientation(r,self.lattice), i,j, k == 1) if symmetries else Orientation(r,self.lattice)# disorientation ... + return (r, i,j, k == 1) if symmetries else r # disorientation ... # ... own sym, other sym, # self-->other: True, self<--other: False From c702441bcc9f3a61c628e79ccd7ae31aa7202945 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 18 Apr 2019 14:27:07 +0200 Subject: [PATCH 28/61] now testing averaging and misorientation calculation --- .gitlab-ci.yml | 8 ++++++++ PRIVATE | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 45fb4e4f4..fa9cab906 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -213,6 +213,14 @@ Post_OrientationConversion: - master - release +Post_OrientationAverageMisorientation: + stage: postprocessing + script: + - OrientationAverageMisorientation/test.py + except: + - master + - release + ################################################################################################### grid_mech_compile_Intel: stage: compilePETSc diff --git a/PRIVATE b/PRIVATE index c7bc54a26..293d04c73 160000 --- a/PRIVATE +++ b/PRIVATE @@ -1 +1 @@ -Subproject commit c7bc54a26c8b6ed404aabec4653227e93fa028e2 +Subproject commit 293d04c7372ddda2f79d4487795b983b0b552f0f From e8464814ae295d430443cb030efbdf8385871258 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 18 Apr 2019 14:46:12 +0200 Subject: [PATCH 29/61] explicit is better than implicit - if the quaternion does not follow the convention, use "fromQuaternion(acceptHomomorph=True)" --- python/damask/orientation.py | 1 - 1 file changed, 1 deletion(-) diff --git a/python/damask/orientation.py b/python/damask/orientation.py index c0c817ca6..b34875a1f 100644 --- a/python/damask/orientation.py +++ b/python/damask/orientation.py @@ -44,7 +44,6 @@ class Rotation: self.quaternion = quaternion.copy() else: self.quaternion = Quaternion(q=quaternion[0],p=quaternion[1:4]) - self.quaternion.homomorph() # ToDo: Needed? def __repr__(self): """Value in selected representation""" From ce1bb589c7992927b553892d81bf518ab7abb365 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 18 Apr 2019 15:30:54 +0200 Subject: [PATCH 30/61] complicated use statements confuse CMake probably we should adopt a similar "use" policy in Fortran as recommended for Python "import" and have all imports at the beginning https://www.python.org/dev/peps/pep-0008/ --- src/plastic_disloUCLA.f90 | 10 +--------- src/plastic_dislotwin.f90 | 10 +--------- src/plastic_isotropic.f90 | 13 +------------ src/plastic_kinematichardening.f90 | 13 +------------ src/plastic_none.f90 | 8 +------- src/plastic_nonlocal.f90 | 10 +--------- src/plastic_phenopowerlaw.f90 | 10 +--------- 7 files changed, 7 insertions(+), 67 deletions(-) diff --git a/src/plastic_disloUCLA.f90 b/src/plastic_disloUCLA.f90 index 88aa27432..ccb37be48 100644 --- a/src/plastic_disloUCLA.f90 +++ b/src/plastic_disloUCLA.f90 @@ -121,15 +121,7 @@ subroutine plastic_disloUCLA_init() math_expand use IO, only: & IO_error - use material, only: & - phase_plasticity, & - phase_plasticityInstance, & - phase_Noutput, & - material_allocatePlasticState, & - PLASTICITY_DISLOUCLA_label, & - PLASTICITY_DISLOUCLA_ID, & - material_phase, & - plasticState + use material use config, only: & config_phase use lattice diff --git a/src/plastic_dislotwin.f90 b/src/plastic_dislotwin.f90 index cb13265b4..ed6638c4f 100644 --- a/src/plastic_dislotwin.f90 +++ b/src/plastic_dislotwin.f90 @@ -185,15 +185,7 @@ subroutine plastic_dislotwin_init PI use IO, only: & IO_error - use material, only: & - phase_plasticity, & - phase_plasticityInstance, & - phase_Noutput, & - material_allocatePlasticState, & - PLASTICITY_DISLOTWIN_label, & - PLASTICITY_DISLOTWIN_ID, & - material_phase, & - plasticState + use material use config, only: & config_phase use lattice diff --git a/src/plastic_isotropic.f90 b/src/plastic_isotropic.f90 index 05a31ab75..45bc136db 100644 --- a/src/plastic_isotropic.f90 +++ b/src/plastic_isotropic.f90 @@ -91,18 +91,7 @@ subroutine plastic_isotropic_init debug_levelBasic use IO, only: & IO_error - use material, only: & -#ifdef DEBUG - phasememberAt, & -#endif - phase_plasticity, & - phase_plasticityInstance, & - phase_Noutput, & - material_allocatePlasticState, & - PLASTICITY_ISOTROPIC_label, & - PLASTICITY_ISOTROPIC_ID, & - material_phase, & - plasticState + use material use config, only: & config_phase use lattice diff --git a/src/plastic_kinematichardening.f90 b/src/plastic_kinematichardening.f90 index 0a4a6b3bc..6890c7006 100644 --- a/src/plastic_kinematichardening.f90 +++ b/src/plastic_kinematichardening.f90 @@ -112,18 +112,7 @@ subroutine plastic_kinehardening_init math_expand use IO, only: & IO_error - use material, only: & -#ifdef DEBUG - phasememberAt, & -#endif - phase_plasticity, & - phase_plasticityInstance, & - phase_Noutput, & - material_allocatePlasticState, & - PLASTICITY_kinehardening_label, & - PLASTICITY_kinehardening_ID, & - material_phase, & - plasticState + use material use config, only: & config_phase use lattice diff --git a/src/plastic_none.f90 b/src/plastic_none.f90 index f8a64b55b..fb19a9968 100644 --- a/src/plastic_none.f90 +++ b/src/plastic_none.f90 @@ -23,13 +23,7 @@ subroutine plastic_none_init debug_level, & debug_constitutive, & debug_levelBasic - use material, only: & - phase_plasticity, & - material_allocatePlasticState, & - PLASTICITY_NONE_label, & - PLASTICITY_NONE_ID, & - material_phase, & - plasticState + use material implicit none integer :: & diff --git a/src/plastic_nonlocal.f90 b/src/plastic_nonlocal.f90 index f5f48ed11..19f6b38cc 100644 --- a/src/plastic_nonlocal.f90 +++ b/src/plastic_nonlocal.f90 @@ -248,15 +248,7 @@ subroutine plastic_nonlocal_init debug_levelBasic use mesh, only: & theMesh - use material, only: & - phase_plasticity, & - phase_plasticityInstance, & - phase_Noutput, & - PLASTICITY_NONLOCAL_label, & - PLASTICITY_NONLOCAL_ID, & - plasticState, & - material_phase, & - material_allocatePlasticState + use material use config use lattice diff --git a/src/plastic_phenopowerlaw.f90 b/src/plastic_phenopowerlaw.f90 index 4124856d1..8e7ee82d0 100644 --- a/src/plastic_phenopowerlaw.f90 +++ b/src/plastic_phenopowerlaw.f90 @@ -116,15 +116,7 @@ subroutine plastic_phenopowerlaw_init math_expand use IO, only: & IO_error - use material, only: & - phase_plasticity, & - phase_plasticityInstance, & - phase_Noutput, & - material_allocatePlasticState, & - PLASTICITY_PHENOPOWERLAW_LABEL, & - PLASTICITY_PHENOPOWERLAW_ID, & - material_phase, & - plasticState + use material use config, only: & config_phase use lattice From 7570b187e75536d23ee90219d3a57e8641ebffd0 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 18 Apr 2019 16:26:05 +0200 Subject: [PATCH 31/61] do explicit homomorphing only in cases when the underlying math cannot guarantee that the resulting quaternion follows the convention --- python/damask/orientation.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/python/damask/orientation.py b/python/damask/orientation.py index b34875a1f..1cf570583 100644 --- a/python/damask/orientation.py +++ b/python/damask/orientation.py @@ -45,6 +45,7 @@ class Rotation: else: self.quaternion = Quaternion(q=quaternion[0],p=quaternion[1:4]) + def __repr__(self): """Value in selected representation""" return '\n'.join([ @@ -60,7 +61,7 @@ class Rotation: Rotation: Details needed (active/passive), rotation of (3,3,3,3)-matrix should be considered """ if isinstance(other, Rotation): # rotate a rotation - return self.__class__((self.quaternion * other.quaternion).asArray()) + return self.__class__((self.quaternion * other.quaternion).homomorph()) elif isinstance(other, np.ndarray): if other.shape == (3,): # rotate a single (3)-vector ( x, y, z) = self.quaternion.p @@ -108,7 +109,7 @@ class Rotation: def misorientation(self,other): """Misorientation""" - return self.__class__((other.quaternion*self.quaternion.conjugated()).homomorph()) + return other*self.inversed() def average(self,other): @@ -1192,7 +1193,7 @@ def eu2qu(eu): -P*sPhi*np.cos(ee[0]-ee[2]), -P*sPhi*np.sin(ee[0]-ee[2]), -P*cPhi*np.sin(ee[0]+ee[2]) ]) - #if qu[0] < 0.0: qu.homomorph() !ToDo: Check with original + if qu[0] < 0.0: qu*=-1 return qu From 1904ac211e9a173c8cb7c3fbffff04ce2db85862 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 18 Apr 2019 16:44:39 +0200 Subject: [PATCH 32/61] test working for more explicit rotation class --- PRIVATE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PRIVATE b/PRIVATE index 293d04c73..f6171a748 160000 --- a/PRIVATE +++ b/PRIVATE @@ -1 +1 @@ -Subproject commit 293d04c7372ddda2f79d4487795b983b0b552f0f +Subproject commit f6171a748e51b994db27c2cc74cc0168b7aea93f From c4f56703a405da3c7609190bfd5af1d933c17c36 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 18 Apr 2019 17:04:00 +0200 Subject: [PATCH 33/61] proper definition of homomorph --- python/damask/orientation.py | 4 +++- python/damask/quaternion.py | 5 ++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/python/damask/orientation.py b/python/damask/orientation.py index 1cf570583..626acc0f2 100644 --- a/python/damask/orientation.py +++ b/python/damask/orientation.py @@ -61,7 +61,9 @@ class Rotation: Rotation: Details needed (active/passive), rotation of (3,3,3,3)-matrix should be considered """ if isinstance(other, Rotation): # rotate a rotation - return self.__class__((self.quaternion * other.quaternion).homomorph()) + qu = self.quaternion * other.quaternion + if qu.q < 0: qu.homomorph() + return self.__class__(qu) elif isinstance(other, np.ndarray): if other.shape == (3,): # rotate a single (3)-vector ( x, y, z) = self.quaternion.p diff --git a/python/damask/quaternion.py b/python/damask/quaternion.py index 7c98a6d1c..1d476e598 100644 --- a/python/damask/quaternion.py +++ b/python/damask/quaternion.py @@ -201,9 +201,8 @@ class Quaternion: def homomorph(self): - if self.q < 0.0: - self.q = -self.q - self.p = -self.p + self.q = -self.q + self.p = -self.p return self def homomorphed(self): From 4183eeaeca1b15a9ec5f66cbb65b071b5baf84ba Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Thu, 18 Apr 2019 18:05:46 -0400 Subject: [PATCH 34/61] [skip ci] disorientation may return full-fledged orientation obj and aux info, added rotation.standardize(d) --- python/damask/orientation.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/python/damask/orientation.py b/python/damask/orientation.py index 626acc0f2..26e926357 100644 --- a/python/damask/orientation.py +++ b/python/damask/orientation.py @@ -109,6 +109,15 @@ class Rotation: return self.__class__(self.quaternion.conjugated()) + def standardize(self): + """Ensure quaternion representation with positive q""" + if self.quaternion.q < 0.0: self.quaternion.homomorph() + + def standardized(self): + """Ensure quaternion representation with positive q""" + return self.__class__(self.quaternion.homomorphed() if self.quaternion.q < 0.0 else self.quaternion) + + def misorientation(self,other): """Misorientation""" return other*self.inversed() @@ -920,7 +929,7 @@ class Orientation: if breaker: break if breaker: break - return (r, i,j, k == 1) if symmetries else r # disorientation ... + return (Orientation(r,self.symmetry), i,j, k == 1) if symmetries else r # disorientation ... # ... own sym, other sym, # self-->other: True, self<--other: False From 25518df80c67f270b3cfbab57e299060d2bcb76b Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 19 Apr 2019 00:42:20 +0200 Subject: [PATCH 35/61] fixes to quaternion class - always store data as float (solves issues with truediv) - fixed in-place multiplication and division - consistent handling of "..ed()" functions --- python/damask/quaternion.py | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/python/damask/quaternion.py b/python/damask/quaternion.py index 1d476e598..1bb6f5f0d 100644 --- a/python/damask/quaternion.py +++ b/python/damask/quaternion.py @@ -10,15 +10,15 @@ class Quaternion: Quaternion with basic operations q is the real part, p = (x, y, z) are the imaginary parts. - Defintion of multiplication depends on variable P, P ∈ {-1,1}. + Definition of multiplication depends on variable P, P ∈ {-1,1}. """ def __init__(self, q = 0.0, p = np.zeros(3,dtype=float)): """Initializes to identity unless specified""" - self.q = q - self.p = np.array(p) + self.q = float(q) + self.p = np.array(p,dtype=float) def __copy__(self): @@ -102,7 +102,8 @@ class Quaternion: self.p = self.q*other.p + other.q*self.p + P * np.cross(self.p,other.p) return self elif isinstance(other, (int, float)): - self *= other + self.q *= other + self.p *= other return self else: return NotImplemented @@ -115,9 +116,8 @@ class Quaternion: return self.__class__(q=self.q * s, p=self.p * s) elif isinstance(other, (int, float)): - self.q /= other - self.p /= other - return self + return self.__class__(q=self.q / other, + p=self.p / other) else: return NotImplemented @@ -129,6 +129,7 @@ class Quaternion: return self elif isinstance(other, (int, float)): self.q /= other + self.p /= other return self else: return NotImplemented @@ -149,6 +150,7 @@ class Quaternion: omega = np.acos(self.q) self.q = np.cos(exponent*omega) self.p *= np.sin(exponent*omega)/np.sin(omega) + return self else: return NotImplemented @@ -179,31 +181,34 @@ class Quaternion: return np.array((self.q,self.p[0],self.p[1],self.p[2])) def asList(self): + """As list""" return [self.q]+list(self.p) + def normalize(self): + """Normalizes in-place (no return value)""" d = self.magnitude() - if d > 0.0: - self.q /= d - self.p /= d - return self + if d > 0.0: self /= d def normalized(self): + """Returns normalized copy""" return self.copy().normalize() - + def conjugate(self): + """Conjugates in-place (no return value)""" self.p = -self.p - return self def conjugated(self): + """Returns conjugated copy""" return self.copy().conjugate() def homomorph(self): + """Homomorphs in-place (no return value)""" self.q = -self.q self.p = -self.p - return self def homomorphed(self): + """Returns homomorphed copy""" return self.copy().homomorph() From 9a43c2e4c5102101026dfc2e973e167c0b5509b4 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 19 Apr 2019 01:05:48 +0200 Subject: [PATCH 36/61] fixed return values - homomorph, standardize, etc. are silent in-place operations (return None) - homomorphed, standardized, etc. are out-of place operations that report --- python/damask/orientation.py | 23 ++++++++++++++++------- python/damask/quaternion.py | 12 +++++++++--- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/python/damask/orientation.py b/python/damask/orientation.py index 26e926357..dc3389977 100644 --- a/python/damask/orientation.py +++ b/python/damask/orientation.py @@ -44,6 +44,12 @@ class Rotation: self.quaternion = quaternion.copy() else: self.quaternion = Quaternion(q=quaternion[0],p=quaternion[1:4]) + + def __copy__(self): + """Copy""" + return self.__class__(self.quaternion) + + copy = __copy__ def __repr__(self): @@ -61,9 +67,9 @@ class Rotation: Rotation: Details needed (active/passive), rotation of (3,3,3,3)-matrix should be considered """ if isinstance(other, Rotation): # rotate a rotation - qu = self.quaternion * other.quaternion - if qu.q < 0: qu.homomorph() - return self.__class__(qu) + qu = self.__class__(self.quaternion * other.quaternion) + qu.standardize() + return qu elif isinstance(other, np.ndarray): if other.shape == (3,): # rotate a single (3)-vector ( x, y, z) = self.quaternion.p @@ -102,11 +108,12 @@ class Rotation: def inverse(self): """In-place inverse rotation/backward rotation""" self.quaternion.conjugate() - return self def inversed(self): """Inverse rotation/backward rotation""" - return self.__class__(self.quaternion.conjugated()) + c = self.copy() + c.inverse() + return c def standardize(self): @@ -115,7 +122,9 @@ class Rotation: def standardized(self): """Ensure quaternion representation with positive q""" - return self.__class__(self.quaternion.homomorphed() if self.quaternion.q < 0.0 else self.quaternion) + c = self.copy() + c.standardize() + return c def misorientation(self,other): @@ -929,7 +938,7 @@ class Orientation: if breaker: break if breaker: break - return (Orientation(r,self.symmetry), i,j, k == 1) if symmetries else r # disorientation ... + return (Orientation(r,self.lattice), i,j, k == 1) if symmetries else r # disorientation ... # ... own sym, other sym, # self-->other: True, self<--other: False diff --git a/python/damask/quaternion.py b/python/damask/quaternion.py index 1bb6f5f0d..69f4e6ef0 100644 --- a/python/damask/quaternion.py +++ b/python/damask/quaternion.py @@ -192,7 +192,9 @@ class Quaternion: def normalized(self): """Returns normalized copy""" - return self.copy().normalize() + c = self.copy() + c.normalize() + return c def conjugate(self): @@ -201,7 +203,9 @@ class Quaternion: def conjugated(self): """Returns conjugated copy""" - return self.copy().conjugate() + c = self.copy() + c.conjugate() + return c def homomorph(self): @@ -211,4 +215,6 @@ class Quaternion: def homomorphed(self): """Returns homomorphed copy""" - return self.copy().homomorph() + c = self.copy() + c.homomorph() + return c From feca9fe0a0c51aab090e42fc66002b5699a20226 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 19 Apr 2019 08:04:04 +0200 Subject: [PATCH 37/61] Again changes to the return values. A python function with no return value returns 'None' --- python/damask/orientation.py | 16 +++++++--------- python/damask/quaternion.py | 23 ++++++++++------------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/python/damask/orientation.py b/python/damask/orientation.py index dc3389977..77fa3665c 100644 --- a/python/damask/orientation.py +++ b/python/damask/orientation.py @@ -108,23 +108,21 @@ class Rotation: def inverse(self): """In-place inverse rotation/backward rotation""" self.quaternion.conjugate() + return self def inversed(self): """Inverse rotation/backward rotation""" - c = self.copy() - c.inverse() - return c + return self.copy.inverse() def standardize(self): - """Ensure quaternion representation with positive q""" - if self.quaternion.q < 0.0: self.quaternion.homomorph() + """In-place quaternion representation with positive q""" + if self.quaternion.q < 0.0: self.quaternion.homomorph() + return self def standardized(self): - """Ensure quaternion representation with positive q""" - c = self.copy() - c.standardize() - return c + """Quaternion representation with positive q""" + return self.copy.standardize() def misorientation(self,other): diff --git a/python/damask/quaternion.py b/python/damask/quaternion.py index 69f4e6ef0..9a361cb3d 100644 --- a/python/damask/quaternion.py +++ b/python/damask/quaternion.py @@ -2,7 +2,7 @@ import numpy as np -P = -1 # convention (sed DOI:10.1088/0965-0393/23/8/083501) +P = -1 # convention (see DOI:10.1088/0965-0393/23/8/083501) #################################################################################################### class Quaternion: @@ -186,35 +186,32 @@ class Quaternion: def normalize(self): - """Normalizes in-place (no return value)""" + """Normalizes in-place""" d = self.magnitude() if d > 0.0: self /= d + return self def normalized(self): """Returns normalized copy""" - c = self.copy() - c.normalize() - return c + return self.copy.normalize() def conjugate(self): - """Conjugates in-place (no return value)""" + """Conjugates in-place""" self.p = -self.p + return self def conjugated(self): """Returns conjugated copy""" - c = self.copy() - c.conjugate() - return c + return self.copy.conjugate() def homomorph(self): - """Homomorphs in-place (no return value)""" + """Homomorphs in-place""" self.q = -self.q self.p = -self.p + return self def homomorphed(self): """Returns homomorphed copy""" - c = self.copy() - c.homomorph() - return c + return self.copy.homomorph() From b97f10b6ff7322c97c07dc5c3e0e5fcdc7296be4 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 19 Apr 2019 08:17:02 +0200 Subject: [PATCH 38/61] forgotten changes in last commit + fromRandom --- python/damask/orientation.py | 42 ++++++++++++++++++++++++------------ python/damask/quaternion.py | 6 +++--- 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/python/damask/orientation.py b/python/damask/orientation.py index 77fa3665c..e584415b0 100644 --- a/python/damask/orientation.py +++ b/python/damask/orientation.py @@ -67,9 +67,7 @@ class Rotation: Rotation: Details needed (active/passive), rotation of (3,3,3,3)-matrix should be considered """ if isinstance(other, Rotation): # rotate a rotation - qu = self.__class__(self.quaternion * other.quaternion) - qu.standardize() - return qu + return self.__class__(self.quaternion * other.quaternion).standardize() elif isinstance(other, np.ndarray): if other.shape == (3,): # rotate a single (3)-vector ( x, y, z) = self.quaternion.p @@ -112,7 +110,7 @@ class Rotation: def inversed(self): """Inverse rotation/backward rotation""" - return self.copy.inverse() + return self.copy().inverse() def standardize(self): @@ -122,7 +120,7 @@ class Rotation: def standardized(self): """Quaternion representation with positive q""" - return self.copy.standardize() + return self.copy().standardize() def misorientation(self,other): @@ -310,7 +308,20 @@ class Rotation: else M + r.asM() * n # noqa add (multiples) of this rotation to average noqa eig, vec = np.linalg.eig(M/N) - return Rotation.fromQuaternion(np.real(vec.T[eig.argmax()]),acceptHomomorph = True) + return cls.fromQuaternion(np.real(vec.T[eig.argmax()]),acceptHomomorph = True) + + + @classmethod + def fromRandom(cls): + r = np.random.random(3) + A = np.sqrt(r[2]) + B = np.sqrt(1.0-r[2]) + w = np.cos(2.0*np.pi*r[0])*A + x = np.sin(2.0*np.pi*r[1])*B + y = np.cos(2.0*np.pi*r[1])*B + z = np.sin(2.0*np.pi*r[0])*A + return cls.fromQuaternion([w,x,y,z],acceptHomomorph=True) + # ****************************************************************************************** @@ -433,15 +444,18 @@ class Symmetry: return symOps # yes, return list of rotations - def inFZ(self,R): + def inFZ(self,rodrigues): """ Check whether given Rodrigues vector falls into fundamental zone of own symmetry. Fundamental zone in Rodrigues space is point symmetric around origin. """ - if np.any(R == np.inf): return False + if (len(rodrigues) != 3): + raise ValueError('Input is not a Rodriques-Frank vector.\n') + + if np.any(rodrigues == np.inf): return False - Rabs = abs(R[0:3]*R[3]) + Rabs = abs(rodrigues) if self.lattice == 'cubic': return math.sqrt(2.0)-1.0 >= Rabs[0] \ @@ -471,10 +485,10 @@ class Symmetry: Representation of Orientation and Disorientation Data for Cubic, Hexagonal, Tetragonal and Orthorhombic Crystals Acta Cryst. (1991). A47, 780-789 """ - R = rodrigues - if (len(R) != 3): + if (len(rodrigues) != 3): raise ValueError('Input is not a Rodriques-Frank vector.\n') - + R = rodrigues + epsilon = 0.0 if self.lattice == 'cubic': return R[0] >= R[1]+epsilon and R[1] >= R[2]+epsilon and R[2] >= epsilon @@ -930,7 +944,7 @@ class Orientation: r = b*aInv for k in range(2): r.inverse() - breaker = self.lattice.symmetry.inFZ(r.asRodrigues()) \ + breaker = self.lattice.symmetry.inFZ(r.asRodrigues(vector=True)) \ and (not SST or other.lattice.symmetry.inDisorientationSST(r.asRodrigues(vector=True))) if breaker: break if breaker: break @@ -942,7 +956,7 @@ class Orientation: def inFZ(self): - return self.lattice.symmetry.inFZ(self.rotation.asRodrigues()) + return self.lattice.symmetry.inFZ(self.rotation.asRodrigues(vector=True)) def equivalentOrientations(self,members=[]): """List of orientations which are symmetrically equivalent""" diff --git a/python/damask/quaternion.py b/python/damask/quaternion.py index 9a361cb3d..3a5fa9a89 100644 --- a/python/damask/quaternion.py +++ b/python/damask/quaternion.py @@ -193,7 +193,7 @@ class Quaternion: def normalized(self): """Returns normalized copy""" - return self.copy.normalize() + return self.copy().normalize() def conjugate(self): @@ -203,7 +203,7 @@ class Quaternion: def conjugated(self): """Returns conjugated copy""" - return self.copy.conjugate() + return self.copy().conjugate() def homomorph(self): @@ -214,4 +214,4 @@ class Quaternion: def homomorphed(self): """Returns homomorphed copy""" - return self.copy.homomorph() + return self.copy().homomorph() From 13307307174276952a207da4d3c8660f8e3ef2c4 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 19 Apr 2019 09:04:54 +0200 Subject: [PATCH 39/61] inFZ needs 'proper' Rodriques--Franck vector --- python/damask/orientation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/damask/orientation.py b/python/damask/orientation.py index e584415b0..00550d986 100644 --- a/python/damask/orientation.py +++ b/python/damask/orientation.py @@ -976,7 +976,7 @@ class Orientation: def reduced(self): """Transform orientation to fall into fundamental zone according to symmetry""" for me in self.equivalentOrientations(): - if self.lattice.symmetry.inFZ(me.rotation.asRodrigues()): break + if self.lattice.symmetry.inFZ(me.rotation.asRodrigues(vector=True)): break return self.__class__(me.rotation,self.lattice) From c3a7b7b068184d1938e11a39954ceb61a0617aae Mon Sep 17 00:00:00 2001 From: Test User Date: Tue, 30 Apr 2019 16:10:23 +0200 Subject: [PATCH 40/61] [skip ci] updated version information after successful test of v2.0.3-183-gb72b6b66 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 00ca40975..40b83075b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.3-152-gd74599d3 +v2.0.3-183-gb72b6b66 From ced3a13b1cd004cc51e34e18816ee53d3272a015 Mon Sep 17 00:00:00 2001 From: Test User Date: Wed, 1 May 2019 01:58:40 +0200 Subject: [PATCH 41/61] [skip ci] updated version information after successful test of v2.0.3-198-g1c762860 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 40b83075b..9096149dc 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.3-183-gb72b6b66 +v2.0.3-198-g1c762860 From a881205561dee2b2eadef7875792c3d645a8343f Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 3 May 2019 06:21:43 +0200 Subject: [PATCH 42/61] CLI options not used to control PETSc --- src/DAMASK_interface.f90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/DAMASK_interface.f90 b/src/DAMASK_interface.f90 index 87a73af37..a3996c417 100644 --- a/src/DAMASK_interface.f90 +++ b/src/DAMASK_interface.f90 @@ -45,7 +45,7 @@ contains !> @brief initializes the solver by interpreting the command line arguments. Also writes !! information on computation to screen !-------------------------------------------------------------------------------------------------- -subroutine DAMASK_interface_init() +subroutine DAMASK_interface_init use, intrinsic :: & iso_fortran_env use, intrinsic :: & @@ -134,7 +134,7 @@ subroutine DAMASK_interface_init() call quit(1) endif #endif - call PETScInitialize(PETSC_NULL_CHARACTER,petsc_err) ! according to PETSc manual, that should be the first line in the code + call PETScInitializeNoArguments(petsc_err) ! according to PETSc manual, that should be the first line in the code CHKERRQ(petsc_err) ! this is a macro definition, it is case sensitive call MPI_Comm_rank(PETSC_COMM_WORLD,worldrank,mpi_err) From ebf01dee4f68c1fde0350703abfef06fd1bbc531 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 3 May 2019 06:46:22 +0200 Subject: [PATCH 43/61] store grid/size at geometry group as outlined in the DAMASK results paper --- python/damask/dadf5.py | 8 ++++---- src/grid/DAMASK_grid.f90 | 16 ++++++++-------- src/results.f90 | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/python/damask/dadf5.py b/python/damask/dadf5.py index 4214f4922..841029af8 100644 --- a/python/damask/dadf5.py +++ b/python/damask/dadf5.py @@ -20,14 +20,14 @@ class DADF5(): with h5py.File(filename,'r') as f: - if f.attrs['DADF5-major'] != 0 or f.attrs['DADF5-minor'] != 1: + if f.attrs['DADF5-major'] != 0 or f.attrs['DADF5-minor'] != 2: raise TypeError('Unsupported DADF5 version {} '.format(f.attrs['DADF5-version'])) - self.structured = 'grid' in f['mapping'].attrs.keys() + self.structured = 'grid' in f['geometry'].attrs.keys() if self.structured: - self.grid = f['mapping'].attrs['grid'] - self.size = f['mapping'].attrs['size'] + self.grid = f['geometry'].attrs['grid'] + self.size = f['geometry'].attrs['size'] r=re.compile('inc[0-9]+') self.increments = [{'inc': int(u[3:]), diff --git a/src/grid/DAMASK_grid.f90 b/src/grid/DAMASK_grid.f90 index f2f52bb2f..2adf72f89 100644 --- a/src/grid/DAMASK_grid.f90 +++ b/src/grid/DAMASK_grid.f90 @@ -77,6 +77,7 @@ program DAMASK_spectral use grid_mech_FEM use grid_damage_spectral use grid_thermal_spectral + use HDF5_utilities use results implicit none @@ -155,8 +156,6 @@ program DAMASK_spectral write(6,'(/,a)') ' Shanthraj et al., Handbook of Mechanics of Materials, 2019' write(6,'(a)') ' https://doi.org/10.1007/978-981-10-6855-3_80' - call results_openJobFile() - call results_closeJobFile() !-------------------------------------------------------------------------------------------------- ! initialize field solver information nActiveFields = 1 @@ -301,7 +300,7 @@ program DAMASK_spectral reportAndCheck: if (worldrank == 0) then write (loadcase_string, '(i6)' ) currentLoadCase - write(6,'(1x,a,i6)') 'load case: ', currentLoadCase + write(6,'(/,1x,a,i6)') 'load case: ', currentLoadCase if (.not. newLoadCase%followFormerTrajectory) write(6,'(2x,a)') 'drop guessing along trajectory' if (newLoadCase%deformation%myType == 'l') then do j = 1_pInt, 3_pInt @@ -348,10 +347,10 @@ program DAMASK_spectral if (newLoadCase%time < 0.0_pReal) errorID = 834_pInt ! negative time increment write(6,'(2x,a,f12.6)') 'time: ', newLoadCase%time if (newLoadCase%incs < 1_pInt) errorID = 835_pInt ! non-positive incs count - write(6,'(2x,a,i5)') 'increments: ', newLoadCase%incs + write(6,'(2x,a,i5)') 'increments: ', newLoadCase%incs if (newLoadCase%outputfrequency < 1_pInt) errorID = 836_pInt ! non-positive result frequency - write(6,'(2x,a,i5)') 'output frequency: ', newLoadCase%outputfrequency - write(6,'(2x,a,i5,/)') 'restart frequency: ', newLoadCase%restartfrequency + write(6,'(2x,a,i5)') 'output frequency: ', newLoadCase%outputfrequency + write(6,'(2x,a,i5)') 'restart frequency: ', newLoadCase%restartfrequency if (errorID > 0_pInt) call IO_error(error_ID = errorID, ext_msg = loadcase_string) ! exit with error message endif reportAndCheck loadCases = [loadCases,newLoadCase] ! load case is ok, append it @@ -359,8 +358,9 @@ program DAMASK_spectral close(fileUnit) call results_openJobFile - call results_addAttribute('grid',grid,'mapping') - call results_addAttribute('size',geomSize,'mapping') + call HDF5_closeGroup(results_addGroup('geometry')) + call results_addAttribute('grid',grid,'geometry') + call results_addAttribute('size',geomSize,'geometry') call results_closeJobFile !-------------------------------------------------------------------------------------------------- diff --git a/src/results.f90 b/src/results.f90 index 516c64552..677858ada 100644 --- a/src/results.f90 +++ b/src/results.f90 @@ -66,9 +66,9 @@ subroutine results_init write(6,'(a)') ' https://doi.org/10.1007/s40192-018-0118-7' resultsFile = HDF5_openFile(trim(getSolverJobName())//'.hdf5','w',.true.) - call HDF5_addAttribute(resultsFile,'DADF5-version',0.1) + call HDF5_addAttribute(resultsFile,'DADF5-version',0.2) call HDF5_addAttribute(resultsFile,'DADF5-major',0) - call HDF5_addAttribute(resultsFile,'DADF5-minor',1) + call HDF5_addAttribute(resultsFile,'DADF5-minor',2) call HDF5_addAttribute(resultsFile,'DAMASK',DAMASKVERSION) call get_command(commandLine) call HDF5_addAttribute(resultsFile,'call',trim(commandLine)) From 5bdc7f8e38111559fe71c3e22ae116e89cc1ca77 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 4 May 2019 13:51:48 +0200 Subject: [PATCH 44/61] test working also without populate grains --- PRIVATE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PRIVATE b/PRIVATE index 212ac3b32..992cc5f6b 160000 --- a/PRIVATE +++ b/PRIVATE @@ -1 +1 @@ -Subproject commit 212ac3b326f3a15926d71109fec0173d95931b6b +Subproject commit 992cc5f6b56eaccb0b34a045799e6522cc4c02c5 From bf4c5741b9374c16cb65fc6add9b508d8c79e7fc Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 4 May 2019 14:19:27 +0200 Subject: [PATCH 45/61] cleaning --- src/material.f90 | 36 +++++++++++------------------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/src/material.f90 b/src/material.f90 index 383462ae1..e1d860c4e 100644 --- a/src/material.f90 +++ b/src/material.f90 @@ -183,14 +183,11 @@ module material integer(pInt), private :: & microstructure_maxNconstituents, & !< max number of constituents in any phase - texture_maxNgauss, & !< max number of Gauss components in any texture - texture_maxNfiber !< max number of Fiber components in any texture + texture_maxNgauss !< max number of Gauss components in any texture integer(pInt), dimension(:), allocatable, private :: & microstructure_Nconstituents, & !< number of constituents in each microstructure - texture_symmetry, & !< number of symmetric orientations per texture - texture_Ngauss, & !< number of Gauss components per texture - texture_Nfiber !< number of Fiber components per texture + texture_Ngauss !< number of Gauss components per texture integer(pInt), dimension(:,:), allocatable, private :: & microstructure_phase, & !< phase IDs of each microstructure @@ -202,7 +199,6 @@ module material real(pReal), dimension(:,:,:), allocatable, private :: & material_volume, & !< volume of each grain,IP,element texture_Gauss, & !< data of each Gauss component - texture_Fiber, & !< data of each Fiber component texture_transformation !< transformation for each texture logical, dimension(:), allocatable, private :: & @@ -807,31 +803,27 @@ subroutine material_parseTexture math_det33 implicit none - integer(pInt) :: section, gauss, fiber, j, t, i + integer(pInt) :: section, gauss, j, t, i character(len=65536), dimension(:), allocatable :: strings ! Values for given key in material config integer(pInt), dimension(:), allocatable :: chunkPos - allocate(texture_symmetry(size(config_texture)), source=1_pInt) allocate(texture_Ngauss(size(config_texture)), source=0_pInt) - allocate(texture_Nfiber(size(config_texture)), source=0_pInt) do t=1_pInt, size(config_texture) - texture_Ngauss(t) = config_texture(t)%countKeys('(gauss)') & - + config_texture(t)%countKeys('(random)') - texture_Nfiber(t) = config_texture(t)%countKeys('(fiber)') + texture_Ngauss(t) = config_texture(t)%countKeys('(gauss)') + if (config_texture(t)%keyExists('symmetry')) call IO_error(147,ext_msg='symmetry') + if (config_texture(t)%keyExists('(random)')) call IO_error(147,ext_msg='(random)') + if (config_texture(t)%keyExists('(fiber)')) call IO_error(147,ext_msg='(fiber)') enddo texture_maxNgauss = maxval(texture_Ngauss) - texture_maxNfiber = maxval(texture_Nfiber) allocate(texture_Gauss (5,texture_maxNgauss,size(config_texture)), source=0.0_pReal) - allocate(texture_Fiber (6,texture_maxNfiber,size(config_texture)), source=0.0_pReal) allocate(texture_transformation(3,3,size(config_texture)), source=0.0_pReal) texture_transformation = spread(math_I3,3,size(config_texture)) do t=1_pInt, size(config_texture) section = t gauss = 0_pInt - fiber = 0_pInt if (config_texture(t)%keyExists('axes')) then strings = config_texture(t)%getStrings('axes') @@ -856,10 +848,6 @@ subroutine material_parseTexture if(dNeq(math_det33(texture_transformation(1:3,1:3,t)),1.0_pReal)) call IO_error(157_pInt,t) endif - if (config_texture(t)%keyExists('symmetry')) call IO_error(147,ext_msg='symmetry') - if (config_texture(t)%keyExists('(random)')) call IO_error(147,ext_msg='(random)') - if (config_texture(t)%keyExists('(fiber)')) call IO_error(147,ext_msg='(fiber)') - if (config_texture(t)%keyExists('(gauss)')) then gauss = gauss + 1_pInt strings = config_texture(t)%getStrings('(gauss)',raw= .true.) @@ -1018,11 +1006,10 @@ subroutine material_populateGrains real(pReal), dimension (:), allocatable :: volumeOfGrain real(pReal), dimension (:,:), allocatable :: orientationOfGrain real(pReal), dimension (3) :: orientation - real(pReal), dimension (3,3) :: symOrientation integer(pInt), dimension (:), allocatable :: phaseOfGrain, textureOfGrain integer(pInt) :: t,e,i,g,j,m,c,r,homog,micro,sgn,hme, myDebug, & phaseID,textureID,dGrains,myNgrains,myNorientations,myNconstituents, & - grain,constituentGrain,ipGrain,symExtension, ip + grain,constituentGrain,ipGrain,ip real(pReal) :: deviation,extreme,rnd integer(pInt), dimension (:,:), allocatable :: Nelems ! counts number of elements in homog, micro array type(group_int), dimension (:,:), allocatable :: elemsOfHomogMicro ! lists element number in homog, micro array @@ -1165,8 +1152,7 @@ subroutine material_populateGrains phaseOfGrain (grain+1_pInt:grain+NgrainsOfConstituent(i)) = phaseID ! assign resp. phase textureOfGrain(grain+1_pInt:grain+NgrainsOfConstituent(i)) = textureID ! assign resp. texture - myNorientations = ceiling(real(NgrainsOfConstituent(i),pReal)/& - real(texture_symmetry(textureID),pReal),pInt) ! max number of unique orientations (excl. symmetry) + myNorientations = ceiling(real(NgrainsOfConstituent(i),pReal)/1.0,pInt) ! max number of unique orientations (excl. symmetry) !-------------------------------------------------------------------------------------------------- ! has texture components @@ -1196,7 +1182,7 @@ subroutine material_populateGrains do j = 1_pInt,NgrainsOfConstituent(i)-1_pInt ! walk thru grains of current constituent call random_number(rnd) - t = nint(rnd*real(NgrainsOfConstituent(i)-j,pReal)+real(j,pReal)+0.5_pReal,pInt) ! select a grain in remaining list + t = nint(rnd*real(NgrainsOfConstituent(i)-j,pReal)+real(j,pReal)+0.5_pReal,pInt) ! select a grain in remaining list m = phaseOfGrain(grain+t) ! exchange current with random phaseOfGrain(grain+t) = phaseOfGrain(grain+j) phaseOfGrain(grain+j) = m @@ -1275,7 +1261,7 @@ subroutine material_populateGrains enddo homogenizationLoop deallocate(texture_transformation) - deallocate(elemsOfHomogMicro) + call config_deallocate('material.config/microstructure') end subroutine material_populateGrains From 464a2e217e791e7bc3172c15f1dd2445dbc35cfb Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 4 May 2019 17:18:05 +0200 Subject: [PATCH 46/61] not needed --- src/material.f90 | 42 +++--------------------------------------- 1 file changed, 3 insertions(+), 39 deletions(-) diff --git a/src/material.f90 b/src/material.f90 index e1d860c4e..51b51fe47 100644 --- a/src/material.f90 +++ b/src/material.f90 @@ -197,7 +197,6 @@ module material microstructure_fraction !< vol fraction of each constituent in microstructure real(pReal), dimension(:,:,:), allocatable, private :: & - material_volume, & !< volume of each grain,IP,element texture_Gauss, & !< data of each Gauss component texture_transformation !< transformation for each texture @@ -980,14 +979,11 @@ subroutine material_populateGrains math_mul33x33, & math_range use mesh, only: & - theMesh, & - mesh_ipVolume + theMesh use config, only: & config_homogenization, & config_microstructure, & - config_deallocate, & - homogenization_name, & - microstructure_name + config_deallocate use IO, only: & IO_error use debug, only: & @@ -1003,7 +999,6 @@ subroutine material_populateGrains randomOrder real(pReal), dimension (microstructure_maxNconstituents) :: & rndArray - real(pReal), dimension (:), allocatable :: volumeOfGrain real(pReal), dimension (:,:), allocatable :: orientationOfGrain real(pReal), dimension (3) :: orientation integer(pInt), dimension (:), allocatable :: phaseOfGrain, textureOfGrain @@ -1016,7 +1011,6 @@ subroutine material_populateGrains myDebug = debug_level(debug_material) - allocate(material_volume(homogenization_maxNgrains,theMesh%elem%nIPs,theMesh%Nelems), source=0.0_pReal) allocate(material_phase(homogenization_maxNgrains,theMesh%elem%nIPs,theMesh%Nelems), source=0_pInt) allocate(material_texture(homogenization_maxNgrains,theMesh%elem%nIPs,theMesh%Nelems), source=0_pInt) allocate(material_EulerAngles(3,homogenization_maxNgrains,theMesh%elem%nIPs,theMesh%Nelems),source=0.0_pReal) @@ -1062,7 +1056,6 @@ subroutine material_populateGrains elemsOfHomogMicro(homog,micro)%p(Nelems(homog,micro)) = e ! remember elements active in this homog/micro pair enddo elementLooping - allocate(volumeOfGrain(maxval(Ngrains)), source=0.0_pReal) ! reserve memory for maximum case allocate(phaseOfGrain(maxval(Ngrains)), source=0_pInt) ! reserve memory for maximum case allocate(textureOfGrain(maxval(Ngrains)), source=0_pInt) ! reserve memory for maximum case allocate(orientationOfGrain(3,maxval(Ngrains)),source=0.0_pReal) ! reserve memory for maximum case @@ -1073,36 +1066,10 @@ subroutine material_populateGrains endif homogenizationLoop: do homog = 1_pInt,size(config_homogenization) dGrains = homogenization_Ngrains(homog) ! grain number per material point - microstructureLoop: do micro = 1_pInt,size(config_microstructure) ! all pairs of homog and micro + microstructureLoop: do micro = 1_pInt,size(config_microstructure) ! all pairs of homog and micro activePair: if (Ngrains(homog,micro) > 0_pInt) then myNgrains = Ngrains(homog,micro) ! assign short name for total number of grains to populate myNconstituents = microstructure_Nconstituents(micro) ! assign short name for number of constituents - if (iand(myDebug,debug_levelBasic) /= 0_pInt) & - write(6,'(/,a32,1x,a32,1x,i6)') homogenization_name(homog),microstructure_name(micro),myNgrains - - -!-------------------------------------------------------------------------------------------------- -! calculate volume of each grain - - volumeOfGrain = 0.0_pReal - grain = 0_pInt - - do hme = 1_pInt, Nelems(homog,micro) - e = elemsOfHomogMicro(homog,micro)%p(hme) ! my combination of homog and micro, only perform calculations for elements with homog, micro combinations which is indexed in cpElemsindex - if (microstructure_elemhomo(micro)) then ! homogeneous distribution of grains over each element's IPs - volumeOfGrain(grain+1_pInt:grain+dGrains) = sum(mesh_ipVolume(1:theMesh%elem%nIPs,e))/& - real(dGrains,pReal) ! each grain combines size of all IPs in that element - grain = grain + dGrains ! wind forward by Ngrains@IP - else - forall (i = 1_pInt:theMesh%elem%nIPs) & ! loop over IPs - volumeOfGrain(grain+(i-1)*dGrains+1_pInt:grain+i*dGrains) = & - mesh_ipVolume(i,e)/real(dGrains,pReal) ! assign IPvolume/Ngrains@IP to all grains of IP - grain = grain + theMesh%elem%nIPs * dGrains ! wind forward by Nips*Ngrains@IP - endif - enddo - - if (grain /= myNgrains) & - call IO_error(0,el = homog,ip = micro,ext_msg = 'inconsistent grain count after volume calc') !-------------------------------------------------------------------------------------------------- ! divide myNgrains as best over constituents @@ -1230,7 +1197,6 @@ subroutine material_populateGrains currentGrainOfConstituent(c))) ipGrain = ipGrain + 1_pInt ! advance IP grain counter currentGrainOfConstituent(c) = currentGrainOfConstituent(c) + 1_pInt ! advance index of grain population for constituent c - material_volume(ipGrain,i,e) = volumeOfGrain(grain+currentGrainOfConstituent(c)) ! assign properties material_phase(ipGrain,i,e) = phaseOfGrain(grain+currentGrainOfConstituent(c)) material_texture(ipGrain,i,e) = textureOfGrain(grain+currentGrainOfConstituent(c)) material_EulerAngles(1:3,ipGrain,i,e) = orientationOfGrain(1:3,grain+currentGrainOfConstituent(c)) @@ -1240,7 +1206,6 @@ subroutine material_populateGrains grain = sum(NgrainsOfConstituent(1:c-1_pInt)) ! figure out actual starting index in overall/consecutive grain population do ipGrain = ipGrain + 1_pInt, dGrains ! ensure last constituent fills up to dGrains currentGrainOfConstituent(c) = currentGrainOfConstituent(c) + 1_pInt - material_volume(ipGrain,i,e) = volumeOfGrain(grain+currentGrainOfConstituent(c)) material_phase(ipGrain,i,e) = phaseOfGrain(grain+currentGrainOfConstituent(c)) material_texture(ipGrain,i,e) = textureOfGrain(grain+currentGrainOfConstituent(c)) material_EulerAngles(1:3,ipGrain,i,e) = orientationOfGrain(1:3,grain+currentGrainOfConstituent(c)) @@ -1249,7 +1214,6 @@ subroutine material_populateGrains enddo do i = i, theMesh%elem%nIPs ! loop over IPs to (possibly) distribute copies from first IP - material_volume (1_pInt:dGrains,i,e) = material_volume (1_pInt:dGrains,1,e) material_phase (1_pInt:dGrains,i,e) = material_phase (1_pInt:dGrains,1,e) material_texture(1_pInt:dGrains,i,e) = material_texture(1_pInt:dGrains,1,e) material_EulerAngles(1:3,1_pInt:dGrains,i,e) = material_EulerAngles(1:3,1_pInt:dGrains,1,e) From 21a36b5a7dcacdbe886ef5eb1d96c5352316c544 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 4 May 2019 17:47:52 +0200 Subject: [PATCH 47/61] errors better visible --- src/DAMASK_interface.f90 | 16 ++++++++-------- src/quit.f90 | 14 +++++++------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/DAMASK_interface.f90 b/src/DAMASK_interface.f90 index a3996c417..ebe625ef6 100644 --- a/src/DAMASK_interface.f90 +++ b/src/DAMASK_interface.f90 @@ -130,7 +130,7 @@ subroutine DAMASK_interface_init call MPI_Init_Thread(MPI_THREAD_FUNNELED,threadLevel,mpi_err) if (mpi_err /= 0) call quit(1) if (threadLevel Date: Sat, 4 May 2019 19:26:53 +0200 Subject: [PATCH 48/61] cleaning --- src/material.f90 | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/material.f90 b/src/material.f90 index 51b51fe47..4834d040a 100644 --- a/src/material.f90 +++ b/src/material.f90 @@ -971,11 +971,9 @@ end subroutine material_allocateSourceState !! calculates the volume of the grains and deals with texture components !-------------------------------------------------------------------------------------------------- subroutine material_populateGrains - use prec, only: & - dEq use math, only: & + math_EulertoR, & math_RtoEuler, & - math_EulerToR, & math_mul33x33, & math_range use mesh, only: & @@ -986,10 +984,6 @@ subroutine material_populateGrains config_deallocate use IO, only: & IO_error - use debug, only: & - debug_level, & - debug_material, & - debug_levelBasic implicit none integer(pInt), dimension (:,:), allocatable :: Ngrains @@ -1002,14 +996,13 @@ subroutine material_populateGrains real(pReal), dimension (:,:), allocatable :: orientationOfGrain real(pReal), dimension (3) :: orientation integer(pInt), dimension (:), allocatable :: phaseOfGrain, textureOfGrain - integer(pInt) :: t,e,i,g,j,m,c,r,homog,micro,sgn,hme, myDebug, & + integer(pInt) :: t,e,i,g,j,m,c,r,homog,micro,sgn,hme, & phaseID,textureID,dGrains,myNgrains,myNorientations,myNconstituents, & grain,constituentGrain,ipGrain,ip real(pReal) :: deviation,extreme,rnd integer(pInt), dimension (:,:), allocatable :: Nelems ! counts number of elements in homog, micro array type(group_int), dimension (:,:), allocatable :: elemsOfHomogMicro ! lists element number in homog, micro array - myDebug = debug_level(debug_material) allocate(material_phase(homogenization_maxNgrains,theMesh%elem%nIPs,theMesh%Nelems), source=0_pInt) allocate(material_texture(homogenization_maxNgrains,theMesh%elem%nIPs,theMesh%Nelems), source=0_pInt) @@ -1060,10 +1053,7 @@ subroutine material_populateGrains allocate(textureOfGrain(maxval(Ngrains)), source=0_pInt) ! reserve memory for maximum case allocate(orientationOfGrain(3,maxval(Ngrains)),source=0.0_pReal) ! reserve memory for maximum case - if (iand(myDebug,debug_levelBasic) /= 0_pInt) then - write(6,'(/,a/)') ' MATERIAL grain population' - write(6,'(a32,1x,a32,1x,a6)') 'homogenization_name','microstructure_name','grain#' - endif + homogenizationLoop: do homog = 1_pInt,size(config_homogenization) dGrains = homogenization_Ngrains(homog) ! grain number per material point microstructureLoop: do micro = 1_pInt,size(config_microstructure) ! all pairs of homog and micro From 11eb5a62b8513a79668e2d91711e4a85f1ae5561 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 4 May 2019 22:07:10 +0200 Subject: [PATCH 49/61] removed complex population of grains - more explicit material.config - simulation results do not depend on random number/compiler - more suitable for phase field simulations with changing constituents --- PRIVATE | 2 +- src/material.f90 | 23 +++++++++++++++++++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/PRIVATE b/PRIVATE index 992cc5f6b..aadf2d82a 160000 --- a/PRIVATE +++ b/PRIVATE @@ -1 +1 @@ -Subproject commit 992cc5f6b56eaccb0b34a045799e6522cc4c02c5 +Subproject commit aadf2d82a7e04646e3f20c3d526f27a6f90acef0 diff --git a/src/material.f90 b/src/material.f90 index 4834d040a..64c3c2529 100644 --- a/src/material.f90 +++ b/src/material.f90 @@ -860,10 +860,6 @@ subroutine material_parseTexture texture_Gauss(2,gauss,t) = IO_floatValue(strings(i),chunkPos,j+1_pInt)*inRad case('phi2') texture_Gauss(3,gauss,t) = IO_floatValue(strings(i),chunkPos,j+1_pInt)*inRad - case('scatter') - texture_Gauss(4,gauss,t) = IO_floatValue(strings(i),chunkPos,j+1_pInt)*inRad - case('fraction') - texture_Gauss(5,gauss,t) = IO_floatValue(strings(i),chunkPos,j+1_pInt) end select enddo enddo @@ -1012,6 +1008,25 @@ subroutine material_populateGrains allocate(Nelems (size(config_homogenization),size(config_microstructure)), source=0_pInt) + do e = 1, theMesh%Nelems + do i = 1, theMesh%elem%nIPs + homog = theMesh%homogenizationAt(e) + micro = theMesh%microstructureAt(e) + do c = 1, homogenization_Ngrains(homog) + material_phase(c,i,e) = microstructure_phase(c,micro) + material_texture(c,i,e) = microstructure_texture(c,micro) + material_EulerAngles(1:3,c,i,e) = texture_Gauss(1:3,1,material_texture(c,i,e)) + material_EulerAngles(1:3,c,i,e) = math_RtoEuler( & ! translate back to Euler angles + math_mul33x33( & ! pre-multiply + math_EulertoR(material_EulerAngles(1:3,c,i,e)), & ! face-value orientation + texture_transformation(1:3,1:3,material_texture(c,i,e)) & ! and transformation matrix + ) & + ) + enddo + enddo + enddo + + return !-------------------------------------------------------------------------------------------------- ! precounting of elements for each homog/micro pair do e = 1_pInt, theMesh%Nelems From f65423fe9fc7c26433766296518c43c3f6ecccb6 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 5 May 2019 10:09:23 +0200 Subject: [PATCH 50/61] rudimentary postResults for HDF5 output only meant for compatibility during transition --- processing/post/DADF5_postResults.py | 68 ++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100755 processing/post/DADF5_postResults.py diff --git a/processing/post/DADF5_postResults.py b/processing/post/DADF5_postResults.py new file mode 100755 index 000000000..73b126487 --- /dev/null +++ b/processing/post/DADF5_postResults.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 no BOM -*- + +import os +import numpy as np +import argparse +import damask + +scriptName = os.path.splitext(os.path.basename(__file__))[0] +scriptID = ' '.join([scriptName,damask.version]) + +# -------------------------------------------------------------------- +# MAIN +# -------------------------------------------------------------------- +parser = argparse.ArgumentParser() + +#ToDo: We need to decide on a way of handling arguments of variable lentght +#https://stackoverflow.com/questions/15459997/passing-integer-lists-to-python + +#parser.add_argument('--version', action='version', version='%(prog)s {}'.format(scriptID)) +parser.add_argument('filenames', nargs='+', + help='DADF5 files') + +options = parser.parse_args() + +options.labels = ['Fe','Fp','xi_sl'] + +# --- loop over input files ------------------------------------------------------------------------ + +for filename in options.filenames: + results = damask.DADF5(filename) + + if not results.structured: continue + delta = results.size/results.grid*0.5 + x, y, z = np.meshgrid(np.linspace(delta[2],results.size[2]-delta[2],results.grid[2]), + np.linspace(delta[1],results.size[1]-delta[1],results.grid[1]), + np.linspace(delta[0],results.size[0]-delta[0],results.grid[0]), + indexing = 'ij') + + coords = np.concatenate((z[:,:,:,None],y[:,:,:,None],x[:,:,:,None]),axis = 3) + + for i,inc in enumerate(results.increments): + print('Output step {}/{}'.format(i+1,len(results.increments))) + + header = '1 header\n' + + data = np.array([inc['inc'] for j in range(np.product(results.grid))]).reshape([np.product(results.grid),1]) + header+= 'inc' + + data = np.concatenate((data,np.array([j+1 for j in range(np.product(results.grid))]).reshape([np.product(results.grid),1])),1) + header+=' node' + + coords = coords.reshape([np.product(results.grid),3]) + data = np.concatenate((data,coords),1) + header+=' 1_pos 2_pos 3_pos' + + np.savetxt('{}_inc{}.txt'.format(filename.split('.')[0],i),data,header=header,comments='') + + results.active['increments'] = [inc] + for label in options.labels: + for o in results.c_output_types: + results.active['c_output_types'] = [o] + for c in results.constituents: + results.active['constituents'] = [c] + x = results.get_dataset_location(label) + if len(x) == 0: + continue + array = results.read_dataset(x,0) From 4a0584fe2519e0721d18dd5c69cabc1b80ebed67 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 5 May 2019 12:06:55 +0200 Subject: [PATCH 51/61] commercial FEM solvers write results to HDF5 --- src/CPFEM.f90 | 34 ++++++++++++++++++++++++++++++++- src/CPFEM2.f90 | 1 + src/DAMASK_marc.f90 | 46 ++++++++++++++++++++++++++++----------------- 3 files changed, 63 insertions(+), 18 deletions(-) diff --git a/src/CPFEM.f90 b/src/CPFEM.f90 index d2eaa7979..a1e562c24 100644 --- a/src/CPFEM.f90 +++ b/src/CPFEM.f90 @@ -47,7 +47,8 @@ module CPFEM public :: & CPFEM_general, & - CPFEM_initAll + CPFEM_initAll, & + CPFEM_results contains @@ -633,4 +634,35 @@ subroutine CPFEM_general(mode, parallelExecution, ffn, ffn1, temperature_inp, dt end subroutine CPFEM_general + +!-------------------------------------------------------------------------------------------------- +!> @brief triggers writing of the results +!-------------------------------------------------------------------------------------------------- +subroutine CPFEM_results(inc,time) + use prec, only: & + pInt +#ifdef DAMASK_HDF5 + use results + use HDF5_utilities +#endif + use constitutive, only: & + constitutive_results + use crystallite, only: & + crystallite_results + + implicit none + integer(pInt), intent(in) :: inc + real(pReal), intent(in) :: time + +#ifdef DAMASK_HDF5 + call results_openJobFile + call results_addIncrement(inc,time) + call constitutive_results + call crystallite_results + call results_removeLink('current') ! ToDo: put this into closeJobFile + call results_closeJobFile +#endif + +end subroutine CPFEM_results + end module CPFEM diff --git a/src/CPFEM2.f90 b/src/CPFEM2.f90 index 0ecea2b44..bf8deeb78 100644 --- a/src/CPFEM2.f90 +++ b/src/CPFEM2.f90 @@ -290,6 +290,7 @@ subroutine CPFEM_age() end subroutine CPFEM_age + !-------------------------------------------------------------------------------------------------- !> @brief triggers writing of the results !-------------------------------------------------------------------------------------------------- diff --git a/src/DAMASK_marc.f90 b/src/DAMASK_marc.f90 index edf00a203..0ff94f3d7 100644 --- a/src/DAMASK_marc.f90 +++ b/src/DAMASK_marc.f90 @@ -16,6 +16,7 @@ !> @details Marc subroutines used: !> @details - hypela2 !> @details - plotv +!> @details - uedinc !> @details - flux !> @details - quit !> @details Marc common blocks included: @@ -273,26 +274,20 @@ subroutine hypela2(d,g,e,de,s,t,dt,ngens,m,nn,kcus,matus,ndi,nshear,disp, & outdatedByNewInc = .false. ! no aging of state calcMode = .false. ! pretend last step was collection lastLovl = lovl ! pretend that this is NOT the first after a lovl change - !$OMP CRITICAL (write2out) - write(6,'(a,i6,1x,i2)') '<< HYPELA2 >> start of analysis..! ',m(1),nn - flush(6) - !$OMP END CRITICAL (write2out) + write(6,'(a,i6,1x,i2)') '<< HYPELA2 >> start of analysis..! ',m(1),nn + flush(6) else if (inc - theInc > 1) then ! >> restart of broken analysis << lastIncConverged = .false. ! no Jacobian backup outdatedByNewInc = .false. ! no aging of state calcMode = .true. ! pretend last step was calculation - !$OMP CRITICAL (write2out) - write(6,'(a,i6,1x,i2)') '<< HYPELA2 >> restart of analysis..! ',m(1),nn - flush(6) - !$OMP END CRITICAL (write2out) + write(6,'(a,i6,1x,i2)') '<< HYPELA2 >> restart of analysis..! ',m(1),nn + flush(6) else ! >> just the next inc << lastIncConverged = .true. ! request Jacobian backup outdatedByNewInc = .true. ! request aging of state calcMode = .true. ! assure last step was calculation - !$OMP CRITICAL (write2out) - write(6,'(a,i6,1x,i2)') '<< HYPELA2 >> new increment..! ',m(1),nn - flush(6) - !$OMP END CRITICAL (write2out) + write(6,'(a,i6,1x,i2)') '<< HYPELA2 >> new increment..! ',m(1),nn + flush(6) endif else if ( timinc < theDelta ) then ! >> cutBack << lastIncConverged = .false. ! no Jacobian backup @@ -300,10 +295,8 @@ subroutine hypela2(d,g,e,de,s,t,dt,ngens,m,nn,kcus,matus,ndi,nshear,disp, & terminallyIll = .false. cycleCounter = -1 ! first calc step increments this to cycle = 0 calcMode = .true. ! pretend last step was calculation - !$OMP CRITICAL (write2out) - write(6,'(a,i6,1x,i2)') '<< HYPELA2 >> cutback detected..! ',m(1),nn - flush(6) - !$OMP END CRITICAL (write2out) + write(6,'(a,i6,1x,i2)') '<< HYPELA2 >> cutback detected..! ',m(1),nn + flush(6) endif ! convergence treatment end @@ -365,7 +358,6 @@ subroutine hypela2(d,g,e,de,s,t,dt,ngens,m,nn,kcus,matus,ndi,nshear,disp, & lastLovl = lovl ! record lovl call CPFEM_general(computationMode,usePingPong,ffn,ffn1,t(1),timinc,m(1),nn,stress,ddsdde) - ! Mandel: 11, 22, 33, SQRT(2)*12, SQRT(2)*23, SQRT(2)*13 ! Marc: 11, 22, 33, 12, 23, 13 ! Marc: 11, 22, 33, 12 @@ -407,6 +399,26 @@ subroutine flux(f,ts,n,time) end subroutine flux +!-------------------------------------------------------------------------------------------------- +!> @brief sets user defined output variables for Marc +!> @details select a variable contour plotting (user subroutine). +!-------------------------------------------------------------------------------------------------- +subroutine uedinc(inc,incsub) + use prec, only: & + pReal, & + pInt + use CPFEM, only: & + CPFEM_results + + implicit none + integer, intent(in) :: inc, incsub +#include QUOTE(PASTE(./MarcInclude/creeps,Marc4DAMASK)) ! creeps is needed for timinc (time increment) + + call CPFEM_results(inc,cptim) + +end subroutine uedinc + + !-------------------------------------------------------------------------------------------------- !> @brief sets user defined output variables for Marc !> @details select a variable contour plotting (user subroutine). From f873d84e5cc7aadb73ffab7be9a97c28ef397f1c Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 5 May 2019 15:40:27 +0200 Subject: [PATCH 52/61] enable HDF5 out for non-MPI --- src/results.f90 | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/results.f90 b/src/results.f90 index 677858ada..4ca609020 100644 --- a/src/results.f90 +++ b/src/results.f90 @@ -250,6 +250,8 @@ subroutine results_writeScalarDataset_real(group,dataset,label,description,SIuni #ifdef PETSc call HDF5_write(groupHandle,dataset,label,.true.) +#else + call HDF5_write(groupHandle,dataset,label,.false.) #endif if (HDF5_objectExists(groupHandle,label)) & @@ -277,6 +279,8 @@ subroutine results_writeVectorDataset_real(group,dataset,label,description,SIuni #ifdef PETSc call HDF5_write(groupHandle,dataset,label,.true.) +#else + call HDF5_write(groupHandle,dataset,label,.false.) #endif if (HDF5_objectExists(groupHandle,label)) & @@ -305,6 +309,8 @@ subroutine results_writeTensorDataset_real(group,dataset,label,description,SIuni #ifdef PETSc call HDF5_write(groupHandle,dataset,label,.true.) +#else + call HDF5_write(groupHandle,dataset,label,.false.) #endif if (HDF5_objectExists(groupHandle,label)) & @@ -333,6 +339,8 @@ subroutine results_writeVectorDataset_int(group,dataset,label,description,SIunit #ifdef PETSc call HDF5_write(groupHandle,dataset,label,.true.) +#else + call HDF5_write(groupHandle,dataset,label,.false.) #endif if (HDF5_objectExists(groupHandle,label)) & @@ -361,6 +369,8 @@ subroutine results_writeTensorDataset_int(group,dataset,label,description,SIunit #ifdef PETSc call HDF5_write(groupHandle,dataset,label,.true.) +#else + call HDF5_write(groupHandle,dataset,label,.false.) #endif if (HDF5_objectExists(groupHandle,label)) & @@ -391,6 +401,8 @@ subroutine results_writeScalarDataset_rotation(group,dataset,label,description,l #ifdef PETSc call HDF5_write(groupHandle,dataset,label,.true.) +#else + call HDF5_write(groupHandle,dataset,label,.false.) #endif if (HDF5_objectExists(groupHandle,label)) & From 9b0d3def1d2fafce03d7d833224e027549bdfd09 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 5 May 2019 22:35:12 +0200 Subject: [PATCH 53/61] small changes suggested by Franz --- python/damask/orientation.py | 2 +- python/damask/quaternion.py | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/python/damask/orientation.py b/python/damask/orientation.py index 51b6f849f..b19037b0c 100644 --- a/python/damask/orientation.py +++ b/python/damask/orientation.py @@ -83,7 +83,7 @@ class Rotation: ]) elif other.shape == (3,3,): # rotate a single (3x3)-matrix return np.dot(self.asMatrix(),np.dot(other,self.asMatrix().T)) - elif other.shape == (3,3,3,3): + elif other.shape == (3,3,3,3,): raise NotImplementedError else: return NotImplemented diff --git a/python/damask/quaternion.py b/python/damask/quaternion.py index 3a5fa9a89..fd681fe9b 100644 --- a/python/damask/quaternion.py +++ b/python/damask/quaternion.py @@ -78,10 +78,8 @@ class Quaternion: return NotImplemented def __neg__(self): - """Unary positive operator""" - self.q *= -1.0 - self.p *= -1.0 - return self + """Unary negative operator""" + return self * -1.0 def __mul__(self, other): @@ -208,8 +206,7 @@ class Quaternion: def homomorph(self): """Homomorphs in-place""" - self.q = -self.q - self.p = -self.p + self *= -1.0 return self def homomorphed(self): From 8dd2a131fefcc25a2a62ba58cefdf07987fffbc1 Mon Sep 17 00:00:00 2001 From: Test User Date: Mon, 6 May 2019 14:30:22 +0200 Subject: [PATCH 54/61] [skip ci] updated version information after successful test of v2.0.3-229-g90fa809f --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 9096149dc..c24732ae9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.3-198-g1c762860 +v2.0.3-229-g90fa809f From 1eaf67ad8225411d722f6616e3518524428affc3 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 7 May 2019 13:30:05 +0200 Subject: [PATCH 55/61] store results in subdirectory defaults to postProc --- processing/post/DADF5_postResults.py | 10 +++++++++- processing/post/DADF5_vtk_cells.py | 15 +++++++++++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/processing/post/DADF5_postResults.py b/processing/post/DADF5_postResults.py index 73b126487..66ef52588 100755 --- a/processing/post/DADF5_postResults.py +++ b/processing/post/DADF5_postResults.py @@ -20,6 +20,8 @@ parser = argparse.ArgumentParser() #parser.add_argument('--version', action='version', version='%(prog)s {}'.format(scriptID)) parser.add_argument('filenames', nargs='+', help='DADF5 files') +parser.add_argument('-d','--dir', dest='dir',default='postProc',metavar='string', + help='name of subdirectory to hold output') options = parser.parse_args() @@ -54,7 +56,13 @@ for filename in options.filenames: data = np.concatenate((data,coords),1) header+=' 1_pos 2_pos 3_pos' - np.savetxt('{}_inc{}.txt'.format(filename.split('.')[0],i),data,header=header,comments='') + dirname = os.path.abspath(os.path.join(os.path.dirname(filename),options.dir)) + try: + os.mkdir(dirname) + except FileExistsError: + pass + file_out = '{}_inc{:04d}.txt'.format(filename.split('.')[0],i) + np.savetxt(os.path.join(dirname,file_out),data,header=header,comments='') results.active['increments'] = [inc] for label in options.labels: diff --git a/processing/post/DADF5_vtk_cells.py b/processing/post/DADF5_vtk_cells.py index 3bbf9fd45..0aa2ff275 100755 --- a/processing/post/DADF5_vtk_cells.py +++ b/processing/post/DADF5_vtk_cells.py @@ -21,6 +21,8 @@ parser = argparse.ArgumentParser() #parser.add_argument('--version', action='version', version='%(prog)s {}'.format(scriptID)) parser.add_argument('filenames', nargs='+', help='DADF5 files') +parser.add_argument('-d','--dir', dest='dir',default='postProc',metavar='string', + help='name of subdirectory to hold output') options = parser.parse_args() @@ -80,12 +82,17 @@ for filename in options.filenames: if results.structured: writer = vtk.vtkXMLRectilinearGridWriter() + + dirname = os.path.abspath(os.path.join(os.path.dirname(filename),options.dir)) + try: + os.mkdir(dirname) + except FileExistsError: + pass + file_out = '{}_inc{:04d}.{}'.format(filename.split('.')[0],i,writer.GetDefaultFileExtension()) + writer.SetCompressorTypeToZLib() writer.SetDataModeToBinary() - writer.SetFileName(os.path.join(os.path.split(filename)[0], - os.path.splitext(os.path.split(filename)[1])[0] + - '_inc{:04d}'.format(i) + # ToDo: adjust to length of increments - '.' + writer.GetDefaultFileExtension())) + writer.SetFileName(os.path.join(dirname,file_out)) if results.structured: writer.SetInputData(rGrid) From 0cc2b1214d285009213cc989fc0e8c3893e6bda3 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 7 May 2019 15:18:12 +0200 Subject: [PATCH 56/61] store requested data in ASCII file --- processing/post/DADF5_postResults.py | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/processing/post/DADF5_postResults.py b/processing/post/DADF5_postResults.py index 66ef52588..f66fb5b03 100755 --- a/processing/post/DADF5_postResults.py +++ b/processing/post/DADF5_postResults.py @@ -55,15 +55,7 @@ for filename in options.filenames: coords = coords.reshape([np.product(results.grid),3]) data = np.concatenate((data,coords),1) header+=' 1_pos 2_pos 3_pos' - - dirname = os.path.abspath(os.path.join(os.path.dirname(filename),options.dir)) - try: - os.mkdir(dirname) - except FileExistsError: - pass - file_out = '{}_inc{:04d}.txt'.format(filename.split('.')[0],i) - np.savetxt(os.path.join(dirname,file_out),data,header=header,comments='') - + results.active['increments'] = [inc] for label in options.labels: for o in results.c_output_types: @@ -73,4 +65,19 @@ for filename in options.filenames: x = results.get_dataset_location(label) if len(x) == 0: continue + label = x[0].split('/')[-1] array = results.read_dataset(x,0) + d = np.product(np.shape(array)[1:]) + array = np.reshape(array,[np.product(results.grid),d]) + data = np.concatenate((data,array),1) + + header+= ''.join([' {}_{}'.format(j+1,label) for j in range(d)]) + + + dirname = os.path.abspath(os.path.join(os.path.dirname(filename),options.dir)) + try: + os.mkdir(dirname) + except FileExistsError: + pass + file_out = '{}_inc{:04d}.txt'.format(filename.split('.')[0],i) + np.savetxt(os.path.join(dirname,file_out),data,header=header,comments='') From f40b2e895f28cd1172d325ee24831703a1aa7a0b Mon Sep 17 00:00:00 2001 From: Test User Date: Wed, 8 May 2019 14:03:38 +0200 Subject: [PATCH 57/61] [skip ci] updated version information after successful test of v2.0.3-236-g77856159 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index c24732ae9..136a266e9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.3-229-g90fa809f +v2.0.3-236-g77856159 From 1060b13c1f263dae73b6d28383a7604089aa486c Mon Sep 17 00:00:00 2001 From: Vitesh Shah Date: Wed, 8 May 2019 16:50:46 +0200 Subject: [PATCH 58/61] Corrected the comment --- src/results.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/results.f90 b/src/results.f90 index 4ca609020..315e972f8 100644 --- a/src/results.f90 +++ b/src/results.f90 @@ -103,7 +103,7 @@ end subroutine results_closeJobFile !-------------------------------------------------------------------------------------------------- -!> @brief closes the results file +!> @brief creates the group of increment and adds time as attribute to the file !-------------------------------------------------------------------------------------------------- subroutine results_addIncrement(inc,time) From feb1465803f8f467baa8d4962c4d83fb55c8784f Mon Sep 17 00:00:00 2001 From: Vitesh Shah Date: Wed, 8 May 2019 17:31:18 +0200 Subject: [PATCH 59/61] Better to have actual increment num in output file --- processing/post/DADF5_postResults.py | 2 +- processing/post/DADF5_vtk_cells.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/processing/post/DADF5_postResults.py b/processing/post/DADF5_postResults.py index f66fb5b03..caf09d536 100755 --- a/processing/post/DADF5_postResults.py +++ b/processing/post/DADF5_postResults.py @@ -79,5 +79,5 @@ for filename in options.filenames: os.mkdir(dirname) except FileExistsError: pass - file_out = '{}_inc{:04d}.txt'.format(filename.split('.')[0],i) + file_out = '{}_inc{:04d}.txt'.format(filename.split('.')[0],inc['inc']) np.savetxt(os.path.join(dirname,file_out),data,header=header,comments='') diff --git a/processing/post/DADF5_vtk_cells.py b/processing/post/DADF5_vtk_cells.py index 0aa2ff275..dc1177488 100755 --- a/processing/post/DADF5_vtk_cells.py +++ b/processing/post/DADF5_vtk_cells.py @@ -88,7 +88,7 @@ for filename in options.filenames: os.mkdir(dirname) except FileExistsError: pass - file_out = '{}_inc{:04d}.{}'.format(filename.split('.')[0],i,writer.GetDefaultFileExtension()) + file_out = '{}_inc{:04d}.{}'.format(filename.split('.')[0],inc['inc'],writer.GetDefaultFileExtension()) writer.SetCompressorTypeToZLib() writer.SetDataModeToBinary() From 9b698cbdf5706f39002d2ea21bc44a96b32d6880 Mon Sep 17 00:00:00 2001 From: Vitesh Shah Date: Wed, 8 May 2019 17:56:20 +0200 Subject: [PATCH 60/61] correct description of subroutines --- src/results.f90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/results.f90 b/src/results.f90 index 315e972f8..c5582b927 100644 --- a/src/results.f90 +++ b/src/results.f90 @@ -355,7 +355,7 @@ end subroutine results_writeVectorDataset_int !-------------------------------------------------------------------------------------------------- -!> @brief stores a vector dataset in a group +!> @brief stores a tensor dataset in a group !-------------------------------------------------------------------------------------------------- subroutine results_writeTensorDataset_int(group,dataset,label,description,SIunit) @@ -385,7 +385,7 @@ end subroutine results_writeTensorDataset_int !-------------------------------------------------------------------------------------------------- -!> @brief stores a vector dataset in a group +!> @brief stores a scalar dataset in a group !-------------------------------------------------------------------------------------------------- subroutine results_writeScalarDataset_rotation(group,dataset,label,description,lattice_structure) use rotations, only: & From 0ad3814f249cdbee8cd5c5afca941d474ccf6c60 Mon Sep 17 00:00:00 2001 From: Test User Date: Thu, 9 May 2019 10:52:35 +0200 Subject: [PATCH 61/61] [skip ci] updated version information after successful test of v2.0.3-252-g0e77be25 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 136a266e9..4b8c1b29a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.3-236-g77856159 +v2.0.3-252-g0e77be25