From 8aeb4a115ef455d5935a9b0b3d2428d014c3c4bc Mon Sep 17 00:00:00 2001 From: Jaeyong Jung Date: Mon, 18 Jun 2018 16:19:03 +0200 Subject: [PATCH 01/10] first commit. --- src/spectral_interface.f90 | 140 ++++++++++++++++++++++++++++++++++++- 1 file changed, 137 insertions(+), 3 deletions(-) diff --git a/src/spectral_interface.f90 b/src/spectral_interface.f90 index d2adcf9ba..9b1808e0f 100644 --- a/src/spectral_interface.f90 +++ b/src/spectral_interface.f90 @@ -195,9 +195,17 @@ subroutine DAMASK_interface_init() call quit(1_pInt) endif - workingDirectory = trim(storeWorkingDirectory(trim(workingDirArg),trim(geometryArg))) - geometryFile = getGeometryFile(geometryArg) - loadCaseFile = getLoadCaseFile(loadCaseArg) +! workingDirectory = trim(storeWorkingDirectory(trim(workingDirArg),trim(geometryArg))) +! geometryFile = getGeometryFile(geometryArg) +! loadCaseFile = getLoadCaseFile(loadCaseArg) + + workingDirectory = trim(storeWorkingDirectory2(trim(workingDirArg),trim(geometryArg))) + geometryFile = getGeometryFile2(geometryArg,workingDirectory) + loadCaseFile = getLoadCaseFile2(loadCaseArg,workingDirectory) + + +! write(*,*) trim(workingDirectory) +! write(*,*) trim(workingDirectory)//'/' ! put '/' next to workingDirectory call get_environment_variable('USER',userName) error = getHostName(hostName) @@ -216,9 +224,135 @@ subroutine DAMASK_interface_init() write(6,'(a,i6.6)') ' Restart from increment: ', spectralRestartInc write(6,'(a,l1,/)') ' Append to result file: ', appendToOutFile + read(*,*) + end subroutine DAMASK_interface_init + +!-------------------------------------------------------------------------------------------------- +!> @brief extract working directory from given argument or from location of geometry file, +!! possibly converting relative arguments to absolut path +!> @todo change working directory with call chdir(storeWorkingDirectory)? +!-------------------------------------------------------------------------------------------------- +character(len=1024) function storeWorkingDirectory2(workingDirectoryArg,geometryArg) + use system_routines, only: & + isDirectory, & + getCWD + + implicit none + character(len=*), intent(in) :: workingDirectoryArg !< working directory argument + character(len=*), intent(in) :: geometryArg !< geometry argument + character(len=1024) :: cwd + logical :: error + external :: quit + + wdGiven: if (len(workingDirectoryArg)>0) then !< -d is given + absolutePath: if (workingDirectoryArg(1:1) == '/') then !< absolute path is given to workingDirectoryArg + storeWorkingDirectory2 = workingDirectoryArg + else absolutePath !< relative path is given + error = getCWD(cwd) + if (error) call quit(1_pInt) + storeWorkingDirectory2 = trim(cwd)//'/'//workingDirectoryArg !< add relative path to cwd + endif absolutePath + if (storeWorkingDirectory2(len(trim(storeWorkingDirectory2)):len(trim(storeWorkingDirectory2))) /= '/') & + storeWorkingDirectory2 = trim(storeWorkingDirectory2)//'/' ! if path seperator is not given, append it + else wdGiven !< -d is not given + error = getCWD(cwd) + if (error) call quit(1_pInt) + storeWorkingDirectory2 = trim(cwd)//'/' + +! if (geometryArg(1:1) == '/') then ! absolute path given as command line argument +! storeWorkingDirectory2 = geometryArg(1:scan(geometryArg,'/',back=.true.)) +! else +! error = getCWD(cwd) ! relative path given as command line argument +! if (error) call quit(1_pInt) +! storeWorkingDirectory2 = trim(cwd)//'/'//geometryArg(1:scan(geometryArg,'/',back=.true.)) !< workingDirectory should not depend on geometryArg +! endif + endif wdGiven + + storeWorkingDirectory2 = trim(rectifyPath(storeWorkingDirectory2)) + if(.not. isDirectory(trim(storeWorkingDirectory2))) then ! check if the directory exists + write(6,'(a20,a,a16)') ' working directory "',trim(storeWorkingDirectory2),'" does not exist' + call quit(1_pInt) + endif + +end function storeWorkingDirectory2 + + + +!-------------------------------------------------------------------------------------------------- +!> @brief basename of geometry file with extension from command line arguments +!-------------------------------------------------------------------------------------------------- +character(len=1024) function getGeometryFile2(geometryParameter,workingDirectory) + use system_routines, only: & + getCWD + + implicit none + character(len=1024), intent(in) :: & + geometryParameter + character(len=*), intent(in) :: workingDirectory !< working directory +! character(len=1024) :: & +! cwd + integer :: posExt, posSep + logical :: error + external :: quit + + getGeometryFile2 = geometryParameter + posExt = scan(getGeometryFile2,'.',back=.true.) + posSep = scan(getGeometryFile2,'/',back=.true.) + + if (posExt <= posSep) getGeometryFile2 = trim(getGeometryFile2)//('.geom') ! no extension present + if (scan(getGeometryFile2,'/') /= 1) then ! relative path given as command line argument +! error = getcwd(cwd) ! no more cwd +! cwd = workingDirectory + if (error) call quit(1_pInt) + getGeometryFile2 = rectifyPath(trim(workingDirectory)//'/'//getGeometryFile2) + else + getGeometryFile2 = rectifyPath(getGeometryFile2) + endif + + getGeometryFile2 = makeRelativePath(getSolverWorkingDirectoryName(), getGeometryFile2) + +end function getGeometryFile2 + + +!-------------------------------------------------------------------------------------------------- +!> @brief relative path of loadcase from command line arguments +!-------------------------------------------------------------------------------------------------- +character(len=1024) function getLoadCaseFile2(loadCaseParameter,workingDirectory) + use system_routines, only: & + getCWD + + implicit none + character(len=1024), intent(in) :: & + loadCaseParameter + character(len=*), intent(in) :: workingDirectory !< working directory +! character(len=1024) :: & +! cwd + integer :: posExt, posSep + logical :: error + external :: quit + + getLoadCaseFile2 = loadcaseParameter + posExt = scan(getLoadCaseFile2,'.',back=.true.) + posSep = scan(getLoadCaseFile2,'/',back=.true.) + + if (posExt <= posSep) getLoadCaseFile2 = trim(getLoadCaseFile2)//('.load') ! no extension present + if (scan(getLoadCaseFile2,'/') /= 1) then ! relative path given as command line argument +! error = getcwd(cwd) +! cwd = workingDirectory + if (error) call quit(1_pInt) + getLoadCaseFile2 = rectifyPath(trim(workingDirectory)//'/'//getLoadCaseFile2) + else + getLoadCaseFile2 = rectifyPath(getLoadCaseFile2) + endif + + getLoadCaseFile2 = makeRelativePath(getSolverWorkingDirectoryName(), getLoadCaseFile2) + +end function getLoadCaseFile2 + + !-------------------------------------------------------------------------------------------------- !> @brief extract working directory from given argument or from location of geometry file, !! possibly converting relative arguments to absolut path From a8c69dfcadcbe3aa433364b011251e9c8f68dbb1 Mon Sep 17 00:00:00 2001 From: Jaeyong Jung Date: Tue, 26 Jun 2018 16:09:37 +0200 Subject: [PATCH 02/10] commit spectral_interface --- src/spectral_interface.f90 | 165 ++++--------------------------------- 1 file changed, 15 insertions(+), 150 deletions(-) mode change 100644 => 100755 src/spectral_interface.f90 diff --git a/src/spectral_interface.f90 b/src/spectral_interface.f90 old mode 100644 new mode 100755 index 9b1808e0f..41d62a3a9 --- a/src/spectral_interface.f90 +++ b/src/spectral_interface.f90 @@ -195,17 +195,9 @@ subroutine DAMASK_interface_init() call quit(1_pInt) endif -! workingDirectory = trim(storeWorkingDirectory(trim(workingDirArg),trim(geometryArg))) -! geometryFile = getGeometryFile(geometryArg) -! loadCaseFile = getLoadCaseFile(loadCaseArg) - - workingDirectory = trim(storeWorkingDirectory2(trim(workingDirArg),trim(geometryArg))) - geometryFile = getGeometryFile2(geometryArg,workingDirectory) - loadCaseFile = getLoadCaseFile2(loadCaseArg,workingDirectory) - - -! write(*,*) trim(workingDirectory) -! write(*,*) trim(workingDirectory)//'/' ! put '/' next to workingDirectory + workingDirectory = trim(storeWorkingDirectory(trim(workingDirArg))) + geometryFile = getGeometryFile(geometryArg) + loadCaseFile = getLoadCaseFile(loadCaseArg) call get_environment_variable('USER',userName) error = getHostName(hostName) @@ -224,148 +216,21 @@ subroutine DAMASK_interface_init() write(6,'(a,i6.6)') ' Restart from increment: ', spectralRestartInc write(6,'(a,l1,/)') ' Append to result file: ', appendToOutFile - read(*,*) - end subroutine DAMASK_interface_init - !-------------------------------------------------------------------------------------------------- !> @brief extract working directory from given argument or from location of geometry file, !! possibly converting relative arguments to absolut path !> @todo change working directory with call chdir(storeWorkingDirectory)? !-------------------------------------------------------------------------------------------------- -character(len=1024) function storeWorkingDirectory2(workingDirectoryArg,geometryArg) +character(len=1024) function storeWorkingDirectory(workingDirectoryArg) use system_routines, only: & isDirectory, & getCWD implicit none character(len=*), intent(in) :: workingDirectoryArg !< working directory argument - character(len=*), intent(in) :: geometryArg !< geometry argument - character(len=1024) :: cwd - logical :: error - external :: quit - - wdGiven: if (len(workingDirectoryArg)>0) then !< -d is given - absolutePath: if (workingDirectoryArg(1:1) == '/') then !< absolute path is given to workingDirectoryArg - storeWorkingDirectory2 = workingDirectoryArg - else absolutePath !< relative path is given - error = getCWD(cwd) - if (error) call quit(1_pInt) - storeWorkingDirectory2 = trim(cwd)//'/'//workingDirectoryArg !< add relative path to cwd - endif absolutePath - if (storeWorkingDirectory2(len(trim(storeWorkingDirectory2)):len(trim(storeWorkingDirectory2))) /= '/') & - storeWorkingDirectory2 = trim(storeWorkingDirectory2)//'/' ! if path seperator is not given, append it - else wdGiven !< -d is not given - error = getCWD(cwd) - if (error) call quit(1_pInt) - storeWorkingDirectory2 = trim(cwd)//'/' - -! if (geometryArg(1:1) == '/') then ! absolute path given as command line argument -! storeWorkingDirectory2 = geometryArg(1:scan(geometryArg,'/',back=.true.)) -! else -! error = getCWD(cwd) ! relative path given as command line argument -! if (error) call quit(1_pInt) -! storeWorkingDirectory2 = trim(cwd)//'/'//geometryArg(1:scan(geometryArg,'/',back=.true.)) !< workingDirectory should not depend on geometryArg -! endif - endif wdGiven - - storeWorkingDirectory2 = trim(rectifyPath(storeWorkingDirectory2)) - if(.not. isDirectory(trim(storeWorkingDirectory2))) then ! check if the directory exists - write(6,'(a20,a,a16)') ' working directory "',trim(storeWorkingDirectory2),'" does not exist' - call quit(1_pInt) - endif - -end function storeWorkingDirectory2 - - - -!-------------------------------------------------------------------------------------------------- -!> @brief basename of geometry file with extension from command line arguments -!-------------------------------------------------------------------------------------------------- -character(len=1024) function getGeometryFile2(geometryParameter,workingDirectory) - use system_routines, only: & - getCWD - - implicit none - character(len=1024), intent(in) :: & - geometryParameter - character(len=*), intent(in) :: workingDirectory !< working directory -! character(len=1024) :: & -! cwd - integer :: posExt, posSep - logical :: error - external :: quit - - getGeometryFile2 = geometryParameter - posExt = scan(getGeometryFile2,'.',back=.true.) - posSep = scan(getGeometryFile2,'/',back=.true.) - - if (posExt <= posSep) getGeometryFile2 = trim(getGeometryFile2)//('.geom') ! no extension present - if (scan(getGeometryFile2,'/') /= 1) then ! relative path given as command line argument -! error = getcwd(cwd) ! no more cwd -! cwd = workingDirectory - if (error) call quit(1_pInt) - getGeometryFile2 = rectifyPath(trim(workingDirectory)//'/'//getGeometryFile2) - else - getGeometryFile2 = rectifyPath(getGeometryFile2) - endif - - getGeometryFile2 = makeRelativePath(getSolverWorkingDirectoryName(), getGeometryFile2) - -end function getGeometryFile2 - - -!-------------------------------------------------------------------------------------------------- -!> @brief relative path of loadcase from command line arguments -!-------------------------------------------------------------------------------------------------- -character(len=1024) function getLoadCaseFile2(loadCaseParameter,workingDirectory) - use system_routines, only: & - getCWD - - implicit none - character(len=1024), intent(in) :: & - loadCaseParameter - character(len=*), intent(in) :: workingDirectory !< working directory -! character(len=1024) :: & -! cwd - integer :: posExt, posSep - logical :: error - external :: quit - - getLoadCaseFile2 = loadcaseParameter - posExt = scan(getLoadCaseFile2,'.',back=.true.) - posSep = scan(getLoadCaseFile2,'/',back=.true.) - - if (posExt <= posSep) getLoadCaseFile2 = trim(getLoadCaseFile2)//('.load') ! no extension present - if (scan(getLoadCaseFile2,'/') /= 1) then ! relative path given as command line argument -! error = getcwd(cwd) -! cwd = workingDirectory - if (error) call quit(1_pInt) - getLoadCaseFile2 = rectifyPath(trim(workingDirectory)//'/'//getLoadCaseFile2) - else - getLoadCaseFile2 = rectifyPath(getLoadCaseFile2) - endif - - getLoadCaseFile2 = makeRelativePath(getSolverWorkingDirectoryName(), getLoadCaseFile2) - -end function getLoadCaseFile2 - - -!-------------------------------------------------------------------------------------------------- -!> @brief extract working directory from given argument or from location of geometry file, -!! possibly converting relative arguments to absolut path -!> @todo change working directory with call chdir(storeWorkingDirectory)? -!-------------------------------------------------------------------------------------------------- -character(len=1024) function storeWorkingDirectory(workingDirectoryArg,geometryArg) - use system_routines, only: & - isDirectory, & - getCWD - - implicit none - character(len=*), intent(in) :: workingDirectoryArg !< working directory argument - character(len=*), intent(in) :: geometryArg !< geometry argument character(len=1024) :: cwd logical :: error external :: quit @@ -381,13 +246,9 @@ character(len=1024) function storeWorkingDirectory(workingDirectoryArg,geometryA if (storeWorkingDirectory(len(trim(storeWorkingDirectory)):len(trim(storeWorkingDirectory))) /= '/') & storeWorkingDirectory = trim(storeWorkingDirectory)//'/' ! if path seperator is not given, append it else wdGiven - if (geometryArg(1:1) == '/') then ! absolute path given as command line argument - storeWorkingDirectory = geometryArg(1:scan(geometryArg,'/',back=.true.)) - else error = getCWD(cwd) ! relative path given as command line argument if (error) call quit(1_pInt) - storeWorkingDirectory = trim(cwd)//'/'//geometryArg(1:scan(geometryArg,'/',back=.true.)) - endif + storeWorkingDirectory = trim(cwd)//'/' endif wdGiven storeWorkingDirectory = trim(rectifyPath(storeWorkingDirectory)) @@ -458,12 +319,15 @@ character(len=1024) function getGeometryFile(geometryParameter) if (posExt <= posSep) getGeometryFile = trim(getGeometryFile)//('.geom') ! no extension present if (scan(getGeometryFile,'/') /= 1) then ! relative path given as command line argument - error = getcwd(cwd) - if (error) call quit(1_pInt) - getGeometryFile = rectifyPath(trim(cwd)//'/'//getGeometryFile) +! error = getcwd(cwd) +! if (error) call quit(1_pInt) +! getGeometryFile = rectifyPath(trim(workingDirectory)//'/'//getGeometryFile) + getGeometryFile = rectifyPath(trim(getSolverWorkingDirectoryName())//trim(getGeometryFile)) else getGeometryFile = rectifyPath(getGeometryFile) endif + write(*,*) 'getsolv.. ', (getSolverWorkingDirectoryName()) + write(*,*) 'getGeometryFile.. ', (getGeometryFile) getGeometryFile = makeRelativePath(getSolverWorkingDirectoryName(), getGeometryFile) @@ -492,9 +356,10 @@ character(len=1024) function getLoadCaseFile(loadCaseParameter) if (posExt <= posSep) getLoadCaseFile = trim(getLoadCaseFile)//('.load') ! no extension present if (scan(getLoadCaseFile,'/') /= 1) then ! relative path given as command line argument - error = getcwd(cwd) - if (error) call quit(1_pInt) - getLoadCaseFile = rectifyPath(trim(cwd)//'/'//getLoadCaseFile) +! error = getcwd(cwd) +! if (error) call quit(1_pInt) +! getLoadCaseFile = rectifyPath(trim(workingDirectory)//'/'//getLoadCaseFile) + getLoadCaseFile = rectifyPath(trim(getSolverWorkingDirectoryName())//trim(getLoadCaseFile)) else getLoadCaseFile = rectifyPath(getLoadCaseFile) endif From 613e976a86a02522d19de0e47fdc58d1f77cc8a5 Mon Sep 17 00:00:00 2001 From: Jaeyong Jung Date: Fri, 29 Jun 2018 15:36:12 +0200 Subject: [PATCH 03/10] the working directory and pathes of load and geometry files are now consistent. --- PRIVATE | 2 +- src/spectral_interface.f90 | 70 +++++++++++++------------------------- 2 files changed, 24 insertions(+), 48 deletions(-) diff --git a/PRIVATE b/PRIVATE index cd02f6c1a..798facf8e 160000 --- a/PRIVATE +++ b/PRIVATE @@ -1 +1 @@ -Subproject commit cd02f6c1a481491eb4517651516b8311348b4777 +Subproject commit 798facf8e983c26dd635aca6a4b2c0b7ae3568fc diff --git a/src/spectral_interface.f90 b/src/spectral_interface.f90 index 41d62a3a9..88fbd2dae 100755 --- a/src/spectral_interface.f90 +++ b/src/spectral_interface.f90 @@ -222,7 +222,6 @@ end subroutine DAMASK_interface_init !-------------------------------------------------------------------------------------------------- !> @brief extract working directory from given argument or from location of geometry file, !! possibly converting relative arguments to absolut path -!> @todo change working directory with call chdir(storeWorkingDirectory)? !-------------------------------------------------------------------------------------------------- character(len=1024) function storeWorkingDirectory(workingDirectoryArg) use system_routines, only: & @@ -231,7 +230,6 @@ character(len=1024) function storeWorkingDirectory(workingDirectoryArg) implicit none character(len=*), intent(in) :: workingDirectoryArg !< working directory argument - character(len=1024) :: cwd logical :: error external :: quit @@ -239,16 +237,13 @@ character(len=1024) function storeWorkingDirectory(workingDirectoryArg) absolutePath: if (workingDirectoryArg(1:1) == '/') then storeWorkingDirectory = workingDirectoryArg else absolutePath - error = getCWD(cwd) + error = getCWD(storeWorkingDirectory) if (error) call quit(1_pInt) - storeWorkingDirectory = trim(cwd)//'/'//workingDirectoryArg + storeWorkingDirectory = trim(storeWorkingDirectory)//'/'//workingDirectoryArg endif absolutePath - if (storeWorkingDirectory(len(trim(storeWorkingDirectory)):len(trim(storeWorkingDirectory))) /= '/') & - storeWorkingDirectory = trim(storeWorkingDirectory)//'/' ! if path seperator is not given, append it else wdGiven - error = getCWD(cwd) ! relative path given as command line argument - if (error) call quit(1_pInt) - storeWorkingDirectory = trim(cwd)//'/' + error = getCWD(storeWorkingDirectory) ! relative path given as command line argument + if (error) call quit(1_pInt) endif wdGiven storeWorkingDirectory = trim(rectifyPath(storeWorkingDirectory)) @@ -257,6 +252,9 @@ character(len=1024) function storeWorkingDirectory(workingDirectoryArg) call quit(1_pInt) endif + if (storeWorkingDirectory(len_trim(storeWorkingDirectory):len_trim(storeWorkingDirectory)) /= '/') & + storeWorkingDirectory = trim(storeWorkingDirectory)//'/' ! if path seperator is not given, append it + end function storeWorkingDirectory @@ -301,35 +299,23 @@ end function getSolverJobName !> @brief basename of geometry file with extension from command line arguments !-------------------------------------------------------------------------------------------------- character(len=1024) function getGeometryFile(geometryParameter) - use system_routines, only: & - getCWD implicit none character(len=1024), intent(in) :: & geometryParameter - character(len=1024) :: & - cwd integer :: posExt, posSep - logical :: error external :: quit - getGeometryFile = geometryParameter + getGeometryFile = trim(geometryParameter) posExt = scan(getGeometryFile,'.',back=.true.) posSep = scan(getGeometryFile,'/',back=.true.) - if (posExt <= posSep) getGeometryFile = trim(getGeometryFile)//('.geom') ! no extension present - if (scan(getGeometryFile,'/') /= 1) then ! relative path given as command line argument -! error = getcwd(cwd) -! if (error) call quit(1_pInt) -! getGeometryFile = rectifyPath(trim(workingDirectory)//'/'//getGeometryFile) - getGeometryFile = rectifyPath(trim(getSolverWorkingDirectoryName())//trim(getGeometryFile)) - else - getGeometryFile = rectifyPath(getGeometryFile) - endif - write(*,*) 'getsolv.. ', (getSolverWorkingDirectoryName()) - write(*,*) 'getGeometryFile.. ', (getGeometryFile) + if (posExt <= posSep) getGeometryFile = trim(getGeometryFile)//('.geom') + if (scan(getGeometryFile,'/') /= 1) & + getGeometryFile = trim(getSolverWorkingDirectoryName())//trim(getGeometryFile) + + getGeometryFile = makeRelativePath(getSolverWorkingDirectoryName(), rectifyPath(getGeometryFile)) - getGeometryFile = makeRelativePath(getSolverWorkingDirectoryName(), getGeometryFile) end function getGeometryFile @@ -338,39 +324,29 @@ end function getGeometryFile !> @brief relative path of loadcase from command line arguments !-------------------------------------------------------------------------------------------------- character(len=1024) function getLoadCaseFile(loadCaseParameter) - use system_routines, only: & - getCWD implicit none character(len=1024), intent(in) :: & loadCaseParameter - character(len=1024) :: & - cwd integer :: posExt, posSep - logical :: error external :: quit - getLoadCaseFile = loadcaseParameter + getLoadCaseFile = trim(loadCaseParameter) posExt = scan(getLoadCaseFile,'.',back=.true.) posSep = scan(getLoadCaseFile,'/',back=.true.) - if (posExt <= posSep) getLoadCaseFile = trim(getLoadCaseFile)//('.load') ! no extension present - if (scan(getLoadCaseFile,'/') /= 1) then ! relative path given as command line argument -! error = getcwd(cwd) -! if (error) call quit(1_pInt) -! getLoadCaseFile = rectifyPath(trim(workingDirectory)//'/'//getLoadCaseFile) - getLoadCaseFile = rectifyPath(trim(getSolverWorkingDirectoryName())//trim(getLoadCaseFile)) - else - getLoadCaseFile = rectifyPath(getLoadCaseFile) - endif + if (posExt <= posSep) getLoadCaseFile = trim(getLoadCaseFile)//('.load') + if (scan(getLoadCaseFile,'/') /= 1) & + getLoadCaseFile = trim(getSolverWorkingDirectoryName())//trim(getLoadCaseFile) - getLoadCaseFile = makeRelativePath(getSolverWorkingDirectoryName(), getLoadCaseFile) + getLoadCaseFile = makeRelativePath(getSolverWorkingDirectoryName(), rectifyPath(getLoadCaseFile)) end function getLoadCaseFile !-------------------------------------------------------------------------------------------------- -!> @brief remove ../ and /./ from path +!> @brief remove ../ and /./ from path. +!> @details works only if absolute path is given !-------------------------------------------------------------------------------------------------- function rectifyPath(path) @@ -384,14 +360,14 @@ function rectifyPath(path) l = len_trim(path) rectifyPath = path do i = l,3,-1 - if (rectifyPath(i-2:i) == '/'//'.'//'/') & + if (rectifyPath(i-2:i) == '/./') & rectifyPath(i-1:l) = rectifyPath(i+1:l)//' ' enddo !-------------------------------------------------------------------------------------------------- ! remove ../ and corresponding directory from rectifyPath l = len_trim(rectifyPath) - i = index(rectifyPath(i:l),'..'//'/') + i = index(rectifyPath(i:l),'../') j = 0 do while (i > j) j = scan(rectifyPath(1:i-2),'/',back=.true.) @@ -401,7 +377,7 @@ function rectifyPath(path) rectifyPath(j+1:k-1) = rectifyPath(j+2:k) rectifyPath(k:k) = ' ' endif - i = j+index(rectifyPath(j+1:l),'..'//'/') + i = j+index(rectifyPath(j+1:l),'../') enddo if(len_trim(rectifyPath) == 0) rectifyPath = '/' From ac7bc4b9ed1a74cb1c4c145b3e4ea22f8bb25f72 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 10 Jul 2018 08:24:45 +0200 Subject: [PATCH 04/10] dont' store the working directory but set it centrally makes life easier, writing and reading always to CWD unless absolute path is given Spectral: using --wd argrument and C code MSC.Marc: using directory of input deck and Intel extension Abaqus: using function and Intel extension --- src/DAMASK_abaqus.f | 59 +++++++++++++++--------------- src/DAMASK_marc.f90 | 73 ++++++++++++++------------------------ src/DAMASK_spectral.f90 | 19 +++++----- src/IO.f90 | 57 ++++++++++------------------- src/debug.f90 | 2 -- src/spectral_interface.f90 | 57 +++++++++++++---------------- 6 files changed, 110 insertions(+), 157 deletions(-) diff --git a/src/DAMASK_abaqus.f b/src/DAMASK_abaqus.f index e91cbb0bb..e0045a2eb 100644 --- a/src/DAMASK_abaqus.f +++ b/src/DAMASK_abaqus.f @@ -3,38 +3,42 @@ !> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH !> @author Koen Janssens, Paul Scherrer Institut !> @author Arun Prakash, Fraunhofer IWM +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH !> @brief interfaces DAMASK with Abaqus/Standard !> @details put the included file abaqus_v6.env in either your home or model directory, !> it is a minimum Abaqus environment file containing all changes necessary to use the !> DAMASK subroutine (see Abaqus documentation for more information on the use of abaqus_v6.env) !-------------------------------------------------------------------------------------------------- - -#ifndef INT -#define INT 4 -#endif - -#ifndef FLOAT -#define FLOAT 8 -#endif - #define Abaqus #include "prec.f90" module DAMASK_interface -implicit none -character(len=4), dimension(2), parameter :: INPUTFILEEXTENSION = ['.pes','.inp'] -character(len=4), parameter :: LOGFILEEXTENSION = '.log' + implicit none + private + character(len=4), dimension(2), parameter, public :: INPUTFILEEXTENSION = ['.pes','.inp'] + character(len=4), parameter, public :: LOGFILEEXTENSION = '.log' + + public :: & + DAMASK_interface_init, & + getSolverJobName contains !-------------------------------------------------------------------------------------------------- -!> @brief just reporting +!> @brief reports and sets working directory !-------------------------------------------------------------------------------------------------- subroutine DAMASK_interface_init + use ifport, only: & + CHDIR + + implicit none integer, dimension(8) :: & dateAndTime ! type default integer + integer :: lenOutDir,ierr + character(len=256) :: wd + call date_and_time(values = dateAndTime) write(6,'(/,a)') ' <<<+- DAMASK_abaqus_std -+>>>' write(6,'(/,a)') ' Roters et al., Computational Materials Science, 2018' @@ -46,26 +50,16 @@ subroutine DAMASK_interface_init dateAndTime(6),':',& dateAndTime(7) write(6,'(/,a)') ' <<<+- DAMASK_interface init -+>>>' + + call getoutdir(wd, lenOutDir) + ierr = CHDIR(wd) + if (ierr /= 0) call quit(0) + #include "compilation_info.f90" end subroutine DAMASK_interface_init -!-------------------------------------------------------------------------------------------------- -!> @brief using Abaqus/Standard function to get working directory name -!-------------------------------------------------------------------------------------------------- -character(1024) function getSolverWorkingDirectoryName() - - implicit none - integer :: lenOutDir - - getSolverWorkingDirectoryName='' - call getoutdir(getSolverWorkingDirectoryName, lenOutDir) - getSolverWorkingDirectoryName=trim(getSolverWorkingDirectoryName)//'/' - -end function getSolverWorkingDirectoryName - - !-------------------------------------------------------------------------------------------------- !> @brief using Abaqus/Standard function to get solver job name !-------------------------------------------------------------------------------------------------- @@ -79,10 +73,17 @@ character(1024) function getSolverJobName() end function getSolverJobName + end module DAMASK_interface -#include "commercialFEM_fileList.f90" + + +#include "commercialFEM_fileList.f90" + +!-------------------------------------------------------------------------------------------------- +!> @brief This is the Abaqus std user subroutine for defining material behavior +!-------------------------------------------------------------------------------------------------- subroutine UMAT(STRESS,STATEV,DDSDDE,SSE,SPD,SCD,& RPL,DDSDDT,DRPLDE,DRPLDT,STRAN,DSTRAN,& TIME,DTIME,TEMP,DTEMP,PREDEF,DPRED,CMNAME,NDI,NSHR,NTENS,& diff --git a/src/DAMASK_marc.f90 b/src/DAMASK_marc.f90 index 81465350c..51006de72 100644 --- a/src/DAMASK_marc.f90 +++ b/src/DAMASK_marc.f90 @@ -1,15 +1,3 @@ -#define QUOTE(x) #x -#define PASTE(x,y) x ## y - -#ifndef INT -#define INT 4 -#endif - -#ifndef FLOAT -#define FLOAT 8 -#endif - -#include "prec.f90" !-------------------------------------------------------------------------------------------------- !> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH !> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH @@ -17,13 +5,12 @@ !> @author W.A. Counts !> @author Denny Tjahjanto, Max-Planck-Institut für Eisenforschung GmbH !> @author Christoph Kords, Max-Planck-Institut für Eisenforschung GmbH -!> @brief Material subroutine for MSC.Marc +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @brief Interfaces DAMASK with MSC.Marc !> @details Usage: !> @details - choose material as hypela2 !> @details - set statevariable 2 to index of homogenization !> @details - set statevariable 3 to index of microstructure -!> @details - make sure the file "material.config" exists in the working directory -!> @details - make sure the file "numerics.config" exists in the working directory !> @details - use nonsymmetric option for solver (e.g. direct profile or multifrontal sparse, the latter seems to be faster!) !> @details - in case of ddm (domain decomposition) a SYMMETRIC solver has to be used, i.e uncheck "non-symmetric" !> @details Marc subroutines used: @@ -34,23 +21,36 @@ !> @details - concom: lovl, inc !> @details - creeps: timinc !-------------------------------------------------------------------------------------------------- +#define QUOTE(x) #x +#define PASTE(x,y) x ## y + +#include "prec.f90" + module DAMASK_interface implicit none - character(len=4), parameter :: InputFileExtension = '.dat' - character(len=4), parameter :: LogFileExtension = '.log' + private + character(len=4), parameter, public :: InputFileExtension = '.dat' + character(len=4), parameter, public :: LogFileExtension = '.log' + + public :: & + DAMASK_interface_init, & + getSolverJobName contains - !-------------------------------------------------------------------------------------------------- -!> @brief only output of current version +!> @brief reports and sets working directory !-------------------------------------------------------------------------------------------------- subroutine DAMASK_interface_init + use ifport, only: & + CHDIR implicit none integer, dimension(8) :: & dateAndTime ! type default integer + integer :: ierr + character(len=1024) :: wd call date_and_time(values = dateAndTime) write(6,'(/,a)') ' <<<+- DAMASK_Marc -+>>>' @@ -64,27 +64,14 @@ subroutine DAMASK_interface_init dateAndTime(7) write(6,'(/,a)') ' <<<+- DAMASK_interface init -+>>>' #include "compilation_info.f90" + inquire(5, name=wd) ! determine inputputfile + wd = wd(1:scan(wd,'/',back=.true.)) + ierr = CHDIR(wd) + if (ierr /= 0) call quit(0) end subroutine DAMASK_interface_init -!-------------------------------------------------------------------------------------------------- -!> @brief returns the current workingDir -!-------------------------------------------------------------------------------------------------- -function getSolverWorkingDirectoryName() - - implicit none - character(1024) getSolverWorkingDirectoryName, inputName - character(len=*), parameter :: pathSep = achar(47)//achar(92) ! forward and backward slash - - getSolverWorkingDirectoryName='' - inputName='' - inquire(5, name=inputName) ! determine inputputfile - getSolverWorkingDirectoryName=inputName(1:scan(inputName,pathSep,back=.true.)) - -end function getSolverWorkingDirectoryName - - !-------------------------------------------------------------------------------------------------- !> @brief solver job name (no extension) as combination of geometry and load case name !-------------------------------------------------------------------------------------------------- @@ -109,6 +96,9 @@ end function getSolverJobName end module DAMASK_interface + + + #include "commercialFEM_fileList.f90" !-------------------------------------------------------------------------------------------------- @@ -118,17 +108,6 @@ end module DAMASK_interface !> @details !> @details (2) Use the -> 'Plasticity,3' card(=update+finite+large disp+constant d) !> @details in the parameter section of input deck (updated Lagrangian formulation). -!> @details -!> @details The following operation obtains U (stretch tensor) at t=n+1 : -!> @details -!> @details call scla(un1,0.d0,itel,itel,1) -!> @details do k=1,3 -!> @details do i=1,3 -!> @details do j=1,3 -!> @details un1(i,j)=un1(i,j)+dsqrt(strechn1(k))*eigvn1(i,k)*eigvn1(j,k) -!> @details enddo -!> @details enddo -!> @details enddo !-------------------------------------------------------------------------------------------------- subroutine hypela2(d,g,e,de,s,t,dt,ngens,m,nn,kcus,matus,ndi,nshear,disp, & dispt,coord,ffn,frotn,strechn,eigvn,ffn1,frotn1, & diff --git a/src/DAMASK_spectral.f90 b/src/DAMASK_spectral.f90 index 0d77c57f5..2ed94d06a 100644 --- a/src/DAMASK_spectral.f90 +++ b/src/DAMASK_spectral.f90 @@ -20,11 +20,12 @@ program DAMASK_spectral pReal, & tol_math_check, & dNeq + use system_routines, only: & + getCWD use DAMASK_interface, only: & DAMASK_interface_init, & loadCaseFile, & geometryFile, & - getSolverWorkingDirectoryName, & getSolverJobName, & appendToOutFile use IO, only: & @@ -133,7 +134,9 @@ program DAMASK_spectral lastRestartWritten = 0_pInt, & !< total increment # at which last restart information was written stagIter character(len=6) :: loadcase_string - character(len=1024) :: incInfo !< string parsed to solution with information about current load case + character(len=1024) :: & + incInfo, & !< string parsed to solution with information about current load case + workingDir type(tLoadCase), allocatable, dimension(:) :: loadCases !< array of all load cases type(tSolutionState), allocatable, dimension(:) :: solres integer(MPI_OFFSET_KIND) :: fileOffset @@ -381,10 +384,11 @@ program DAMASK_spectral ! write header of output file if (worldrank == 0) then if (.not. appendToOutFile) then ! after restart, append to existing results file - open(newunit=resUnit,file=trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//& + if (getCWD(workingDir)) call IO_error(106_pInt,ext_msg=trim(workingDir)) + open(newunit=resUnit,file=trim(getSolverJobName())//& '.spectralOut',form='UNFORMATTED',status='REPLACE') write(resUnit) 'load:', trim(loadCaseFile) ! ... and write header - write(resUnit) 'workingdir:', trim(getSolverWorkingDirectoryName()) + write(resUnit) 'workingdir:', trim(workingDir) write(resUnit) 'geometry:', trim(geometryFile) write(resUnit) 'grid:', grid write(resUnit) 'size:', geomSize @@ -397,14 +401,14 @@ program DAMASK_spectral write(resUnit) 'startingIncrement:', restartInc ! start with writing out the previous inc write(resUnit) 'eoh' close(resUnit) ! end of header - open(newunit=statUnit,file=trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//& + open(newunit=statUnit,file=trim(getSolverJobName())//& '.sta',form='FORMATTED',status='REPLACE') write(statUnit,'(a)') 'Increment Time CutbackLevel Converged IterationsNeeded' ! statistics file if (iand(debug_level(debug_spectral),debug_levelBasic) /= 0) & write(6,'(/,a)') ' header of result and statistics file written out' flush(6) else ! open new files ... - open(newunit=statUnit,file=trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//& + open(newunit=statUnit,file=trim(getSolverJobName())//& '.sta',form='FORMATTED', position='APPEND', status='OLD') endif endif @@ -415,8 +419,7 @@ program DAMASK_spectral outputSize(worldrank+1) = size(materialpoint_results,kind=MPI_OFFSET_KIND)*int(pReal,MPI_OFFSET_KIND) call MPI_allreduce(MPI_IN_PLACE,outputSize,worldsize,MPI_LONG,MPI_SUM,PETSC_COMM_WORLD,ierr) ! get total output size over each process if (ierr /= 0_pInt) call IO_error(error_ID=894_pInt, ext_msg='MPI_allreduce') - call MPI_file_open(PETSC_COMM_WORLD, & - trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//'.spectralOut', & + call MPI_file_open(PETSC_COMM_WORLD, trim(getSolverJobName())//'.spectralOut', & MPI_MODE_WRONLY + MPI_MODE_APPEND, & MPI_INFO_NULL, & resUnit, & diff --git a/src/IO.f90 b/src/IO.f90 index a7e77f0f4..fd1a36339 100644 --- a/src/IO.f90 +++ b/src/IO.f90 @@ -195,18 +195,14 @@ end subroutine IO_checkAndRewind !> @details like IO_open_file_stat, but error is handled via call to IO_error and not via return !! value !-------------------------------------------------------------------------------------------------- -subroutine IO_open_file(fileUnit,relPath) - use DAMASK_interface, only: & - getSolverWorkingDirectoryName +subroutine IO_open_file(fileUnit,path) implicit none integer(pInt), intent(in) :: fileUnit !< file unit - character(len=*), intent(in) :: relPath !< relative path from working directory + character(len=*), intent(in) :: path !< relative path from working directory integer(pInt) :: myStat - character(len=1024) :: path - path = trim(getSolverWorkingDirectoryName())//relPath open(fileUnit,status='old',iostat=myStat,file=path) if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=path) @@ -218,18 +214,14 @@ end subroutine IO_open_file !! directory !> @details Like IO_open_file, but error is handled via return value and not via call to IO_error !-------------------------------------------------------------------------------------------------- -logical function IO_open_file_stat(fileUnit,relPath) - use DAMASK_interface, only: & - getSolverWorkingDirectoryName +logical function IO_open_file_stat(fileUnit,path) implicit none integer(pInt), intent(in) :: fileUnit !< file unit - character(len=*), intent(in) :: relPath !< relative path from working directory + character(len=*), intent(in) :: path !< relative path from working directory integer(pInt) :: myStat - character(len=1024) :: path - path = trim(getSolverWorkingDirectoryName())//relPath open(fileUnit,status='old',iostat=myStat,file=path) IO_open_file_stat = (myStat == 0_pInt) @@ -244,7 +236,6 @@ end function IO_open_file_stat !-------------------------------------------------------------------------------------------------- subroutine IO_open_jobFile(fileUnit,ext) use DAMASK_interface, only: & - getSolverWorkingDirectoryName, & getSolverJobName implicit none @@ -254,7 +245,7 @@ subroutine IO_open_jobFile(fileUnit,ext) integer(pInt) :: myStat character(len=1024) :: path - path = trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//'.'//ext + path = trim(getSolverJobName())//'.'//ext open(fileUnit,status='old',iostat=myStat,file=path) if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=path) @@ -269,7 +260,6 @@ end subroutine IO_open_jobFile !-------------------------------------------------------------------------------------------------- logical function IO_open_jobFile_stat(fileUnit,ext) use DAMASK_interface, only: & - getSolverWorkingDirectoryName, & getSolverJobName implicit none @@ -279,7 +269,7 @@ logical function IO_open_jobFile_stat(fileUnit,ext) integer(pInt) :: myStat character(len=1024) :: path - path = trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//'.'//ext + path = trim(getSolverJobName())//'.'//ext open(fileUnit,status='old',iostat=myStat,file=path) IO_open_jobFile_stat = (myStat == 0_pInt) @@ -292,7 +282,6 @@ end function IO_open_JobFile_stat !-------------------------------------------------------------------------------------------------- subroutine IO_open_inputFile(fileUnit,modelName) use DAMASK_interface, only: & - getSolverWorkingDirectoryName,& getSolverJobName, & inputFileExtension @@ -306,23 +295,23 @@ subroutine IO_open_inputFile(fileUnit,modelName) integer(pInt) :: fileType fileType = 1_pInt ! assume .pes - path = trim(getSolverWorkingDirectoryName())//trim(modelName)//inputFileExtension(fileType) ! attempt .pes, if it exists: it should be used + path = trim(modelName)//inputFileExtension(fileType) ! attempt .pes, if it exists: it should be used open(fileUnit+1,status='old',iostat=myStat,file=path) if(myStat /= 0_pInt) then ! if .pes does not work / exist; use conventional extension, i.e.".inp" fileType = 2_pInt - path = trim(getSolverWorkingDirectoryName())//trim(modelName)//inputFileExtension(fileType) + path = trim(modelName)//inputFileExtension(fileType) open(fileUnit+1,status='old',iostat=myStat,file=path) endif if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=path) - path = trim(getSolverWorkingDirectoryName())//trim(modelName)//inputFileExtension(fileType)//'_assembly' + path = trim(modelName)//inputFileExtension(fileType)//'_assembly' open(fileUnit,iostat=myStat,file=path) if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=path) if (.not.abaqus_assembleInputFile(fileUnit,fileUnit+1_pInt)) call IO_error(103_pInt) ! strip comments and concatenate any "include"s close(fileUnit+1_pInt) #endif #ifdef Marc4DAMASK - path = trim(getSolverWorkingDirectoryName())//trim(modelName)//inputFileExtension + path = trim(modelName)//inputFileExtension open(fileUnit,status='old',iostat=myStat,file=path) if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=path) #endif @@ -336,7 +325,6 @@ end subroutine IO_open_inputFile !-------------------------------------------------------------------------------------------------- subroutine IO_open_logFile(fileUnit) use DAMASK_interface, only: & - getSolverWorkingDirectoryName, & getSolverJobName, & LogFileExtension @@ -346,7 +334,7 @@ subroutine IO_open_logFile(fileUnit) integer(pInt) :: myStat character(len=1024) :: path - path = trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//LogFileExtension + path = trim(getSolverJobName())//LogFileExtension open(fileUnit,status='old',iostat=myStat,file=path) if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=path) @@ -360,7 +348,6 @@ end subroutine IO_open_logFile !-------------------------------------------------------------------------------------------------- subroutine IO_write_jobFile(fileUnit,ext) use DAMASK_interface, only: & - getSolverWorkingDirectoryName, & getSolverJobName implicit none @@ -370,7 +357,7 @@ subroutine IO_write_jobFile(fileUnit,ext) integer(pInt) :: myStat character(len=1024) :: path - path = trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//'.'//ext + path = trim(getSolverJobName())//'.'//ext open(fileUnit,status='replace',iostat=myStat,file=path) if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=path) @@ -383,7 +370,6 @@ end subroutine IO_write_jobFile !-------------------------------------------------------------------------------------------------- subroutine IO_write_jobRealFile(fileUnit,ext,recMultiplier) use DAMASK_interface, only: & - getSolverWorkingDirectoryName, & getSolverJobName implicit none @@ -394,7 +380,7 @@ subroutine IO_write_jobRealFile(fileUnit,ext,recMultiplier) integer(pInt) :: myStat character(len=1024) :: path - path = trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//'.'//ext + path = trim(getSolverJobName())//'.'//ext if (present(recMultiplier)) then open(fileUnit,status='replace',form='unformatted',access='direct', & recl=pReal*recMultiplier,iostat=myStat,file=path) @@ -414,7 +400,6 @@ end subroutine IO_write_jobRealFile !-------------------------------------------------------------------------------------------------- subroutine IO_write_jobIntFile(fileUnit,ext,recMultiplier) use DAMASK_interface, only: & - getSolverWorkingDirectoryName, & getSolverJobName implicit none @@ -425,7 +410,7 @@ subroutine IO_write_jobIntFile(fileUnit,ext,recMultiplier) integer(pInt) :: myStat character(len=1024) :: path - path = trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//'.'//ext + path = trim(getSolverJobName())//'.'//ext if (present(recMultiplier)) then open(fileUnit,status='replace',form='unformatted',access='direct', & recl=pInt*recMultiplier,iostat=myStat,file=path) @@ -444,8 +429,6 @@ end subroutine IO_write_jobIntFile !! located in current working directory !-------------------------------------------------------------------------------------------------- subroutine IO_read_realFile(fileUnit,ext,modelName,recMultiplier) - use DAMASK_interface, only: & - getSolverWorkingDirectoryName implicit none integer(pInt), intent(in) :: fileUnit !< file unit @@ -456,7 +439,7 @@ subroutine IO_read_realFile(fileUnit,ext,modelName,recMultiplier) integer(pInt) :: myStat character(len=1024) :: path - path = trim(getSolverWorkingDirectoryName())//trim(modelName)//'.'//ext + path = trim(modelName)//'.'//ext if (present(recMultiplier)) then open(fileUnit,status='old',form='unformatted',access='direct', & recl=pReal*recMultiplier,iostat=myStat,file=path) @@ -474,8 +457,6 @@ end subroutine IO_read_realFile !! located in current working directory !-------------------------------------------------------------------------------------------------- subroutine IO_read_intFile(fileUnit,ext,modelName,recMultiplier) - use DAMASK_interface, only: & - getSolverWorkingDirectoryName implicit none integer(pInt), intent(in) :: fileUnit !< file unit @@ -486,7 +467,7 @@ subroutine IO_read_intFile(fileUnit,ext,modelName,recMultiplier) integer(pInt) :: myStat character(len=1024) :: path - path = trim(getSolverWorkingDirectoryName())//trim(modelName)//'.'//ext + path = trim(modelName)//'.'//ext if (present(recMultiplier)) then open(fileUnit,status='old',form='unformatted',access='direct', & recl=pInt*recMultiplier,iostat=myStat,file=path) @@ -1534,6 +1515,8 @@ subroutine IO_error(error_ID,el,ip,g,instance,ext_msg) msg = '{input} recursion limit reached' case (105_pInt) msg = 'unknown output:' + case (106_pInt) + msg = 'working directory does not exist:' !-------------------------------------------------------------------------------------------------- ! lattice error messages @@ -1905,8 +1888,6 @@ end function IO_verifyFloatValue !> including "include"s !-------------------------------------------------------------------------------------------------- recursive function abaqus_assembleInputFile(unit1,unit2) result(createSuccess) - use DAMASK_interface, only: & - getSolverWorkingDirectoryName implicit none integer(pInt), intent(in) :: unit1, & @@ -1923,7 +1904,7 @@ recursive function abaqus_assembleInputFile(unit1,unit2) result(createSuccess) chunkPos = IO_stringPos(line) if (IO_lc(IO_StringValue(line,chunkPos,1_pInt))=='*include') then - fname = trim(getSolverWorkingDirectoryName())//trim(line(9+scan(line(9:),'='):)) + fname = trim(line(9+scan(line(9:),'='):)) inquire(file=fname, exist=fexist) if (.not.(fexist)) then !$OMP CRITICAL (write2out) diff --git a/src/debug.f90 b/src/debug.f90 index ea2b659a1..e5079bff2 100644 --- a/src/debug.f90 +++ b/src/debug.f90 @@ -283,8 +283,6 @@ end subroutine debug_reset subroutine debug_info implicit none - character(len=1) :: exceed - !$OMP CRITICAL (write2out) diff --git a/src/spectral_interface.f90 b/src/spectral_interface.f90 index 88fbd2dae..b1b536a7c 100644 --- a/src/spectral_interface.f90 +++ b/src/spectral_interface.f90 @@ -19,14 +19,13 @@ module DAMASK_interface character(len=1024), public, protected :: & geometryFile = '', & !< parameter given for geometry file loadCaseFile = '' !< parameter given for load case file - character(len=1024), private :: workingDirectory !< accessed by getSolverWorkingDirectoryName for compatibility reasons + character(len=1024), private :: workingDirectory public :: & - getSolverWorkingDirectoryName, & getSolverJobName, & DAMASK_interface_init private :: & - storeWorkingDirectory, & + setWorkingDirectory, & getGeometryFile, & getLoadCaseFile, & rectifyPath, & @@ -195,7 +194,7 @@ subroutine DAMASK_interface_init() call quit(1_pInt) endif - workingDirectory = trim(storeWorkingDirectory(trim(workingDirArg))) + workingDirectory = trim(setWorkingDirectory(trim(workingDirArg))) geometryFile = getGeometryFile(geometryArg) loadCaseFile = getLoadCaseFile(loadCaseArg) @@ -208,7 +207,7 @@ subroutine DAMASK_interface_init() write(6,'(a,a)') ' Working dir argument: ', trim(workingDirArg) write(6,'(a,a)') ' Geometry argument: ', trim(geometryArg) write(6,'(a,a)') ' Loadcase argument: ', trim(loadcaseArg) - write(6,'(a,a)') ' Working directory: ', trim(getSolverWorkingDirectoryName()) + write(6,'(a,a)') ' Working directory: ', trim(workingDirectory) write(6,'(a,a)') ' Geometry file: ', trim(geometryFile) write(6,'(a,a)') ' Loadcase file: ', trim(loadCaseFile) write(6,'(a,a)') ' Solver job name: ', trim(getSolverJobName()) @@ -223,10 +222,11 @@ end subroutine DAMASK_interface_init !> @brief extract working directory from given argument or from location of geometry file, !! possibly converting relative arguments to absolut path !-------------------------------------------------------------------------------------------------- -character(len=1024) function storeWorkingDirectory(workingDirectoryArg) +character(len=1024) function setWorkingDirectory(workingDirectoryArg) use system_routines, only: & isDirectory, & - getCWD + getCWD, & + setCWD implicit none character(len=*), intent(in) :: workingDirectoryArg !< working directory argument @@ -235,39 +235,30 @@ character(len=1024) function storeWorkingDirectory(workingDirectoryArg) wdGiven: if (len(workingDirectoryArg)>0) then absolutePath: if (workingDirectoryArg(1:1) == '/') then - storeWorkingDirectory = workingDirectoryArg + setWorkingDirectory = workingDirectoryArg else absolutePath - error = getCWD(storeWorkingDirectory) + error = getCWD(setWorkingDirectory) if (error) call quit(1_pInt) - storeWorkingDirectory = trim(storeWorkingDirectory)//'/'//workingDirectoryArg + setWorkingDirectory = trim(setWorkingDirectory)//'/'//workingDirectoryArg endif absolutePath else wdGiven - error = getCWD(storeWorkingDirectory) ! relative path given as command line argument + error = getCWD(setWorkingDirectory) ! relative path given as command line argument if (error) call quit(1_pInt) endif wdGiven - storeWorkingDirectory = trim(rectifyPath(storeWorkingDirectory)) - if(.not. isDirectory(trim(storeWorkingDirectory))) then ! check if the directory exists - write(6,'(a20,a,a16)') ' working directory "',trim(storeWorkingDirectory),'" does not exist' + setWorkingDirectory = trim(rectifyPath(setWorkingDirectory)) + if(.not. isDirectory(trim(setWorkingDirectory))) then ! check if the directory exists + write(6,'(a20,a,a16)') ' working directory "',trim(setWorkingDirectory),'" does not exist' call quit(1_pInt) endif - if (storeWorkingDirectory(len_trim(storeWorkingDirectory):len_trim(storeWorkingDirectory)) /= '/') & - storeWorkingDirectory = trim(storeWorkingDirectory)//'/' ! if path seperator is not given, append it + if (setWorkingDirectory(len_trim(setWorkingDirectory):len_trim(setWorkingDirectory)) /= '/') & + setWorkingDirectory = trim(setWorkingDirectory)//'/' ! if path seperator is not given, append it + + error = setCWD(setWorkingDirectory(1:len_trim(setWorkingDirectory)-1)) ! path seperator at end causes problems + if (error) call quit(1_pInt) -end function storeWorkingDirectory - - -!-------------------------------------------------------------------------------------------------- -!> @brief simply returns the private string workingDir -!-------------------------------------------------------------------------------------------------- -character(len=1024) function getSolverWorkingDirectoryName() - - implicit none - - getSolverWorkingDirectoryName = workingDirectory - -end function getSolverWorkingDirectoryName +end function setWorkingDirectory !-------------------------------------------------------------------------------------------------- @@ -312,9 +303,9 @@ character(len=1024) function getGeometryFile(geometryParameter) if (posExt <= posSep) getGeometryFile = trim(getGeometryFile)//('.geom') if (scan(getGeometryFile,'/') /= 1) & - getGeometryFile = trim(getSolverWorkingDirectoryName())//trim(getGeometryFile) + getGeometryFile = trim(workingDirectory)//trim(getGeometryFile) - getGeometryFile = makeRelativePath(getSolverWorkingDirectoryName(), rectifyPath(getGeometryFile)) + getGeometryFile = makeRelativePath(workingDirectory, rectifyPath(getGeometryFile)) end function getGeometryFile @@ -337,9 +328,9 @@ character(len=1024) function getLoadCaseFile(loadCaseParameter) if (posExt <= posSep) getLoadCaseFile = trim(getLoadCaseFile)//('.load') if (scan(getLoadCaseFile,'/') /= 1) & - getLoadCaseFile = trim(getSolverWorkingDirectoryName())//trim(getLoadCaseFile) + getLoadCaseFile = trim(workingDirectory)//trim(getLoadCaseFile) - getLoadCaseFile = makeRelativePath(getSolverWorkingDirectoryName(), rectifyPath(getLoadCaseFile)) + getLoadCaseFile = makeRelativePath(workingDirectory, rectifyPath(getLoadCaseFile)) end function getLoadCaseFile From 70a3db275a8bb3b896ab5967b8bfdda71bad4ccf Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 10 Jul 2018 09:53:20 +0200 Subject: [PATCH 05/10] verbose error message --- src/DAMASK_abaqus.f | 5 ++++- src/DAMASK_marc.f90 | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/DAMASK_abaqus.f b/src/DAMASK_abaqus.f index e0045a2eb..69f6fba4b 100644 --- a/src/DAMASK_abaqus.f +++ b/src/DAMASK_abaqus.f @@ -53,7 +53,10 @@ subroutine DAMASK_interface_init call getoutdir(wd, lenOutDir) ierr = CHDIR(wd) - if (ierr /= 0) call quit(0) + if (ierr /= 0) then + write(6,'(a20,a,a16)') ' working directory "',trim(wd),'" does not exist' + call quit(1) + endif #include "compilation_info.f90" diff --git a/src/DAMASK_marc.f90 b/src/DAMASK_marc.f90 index 51006de72..0f3be66d0 100644 --- a/src/DAMASK_marc.f90 +++ b/src/DAMASK_marc.f90 @@ -67,7 +67,10 @@ subroutine DAMASK_interface_init inquire(5, name=wd) ! determine inputputfile wd = wd(1:scan(wd,'/',back=.true.)) ierr = CHDIR(wd) - if (ierr /= 0) call quit(0) + if (ierr /= 0) then + write(6,'(a20,a,a16)') ' working directory "',trim(wd),'" does not exist' + call quit(1) + endif end subroutine DAMASK_interface_init From 1336f8f129155e6dbd3279c26790837e7d10634b Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 10 Jul 2018 10:23:21 +0200 Subject: [PATCH 06/10] cleanding and simplifying 1) arguments are case sensitive, i.e. -H is NOT -h 2) don't rely on trailing '/' for working dir 3) when adding '/' to working dir, rectify path should take care of '//' --- src/spectral_interface.f90 | 87 +++++++++++++++----------------------- 1 file changed, 33 insertions(+), 54 deletions(-) diff --git a/src/spectral_interface.f90 b/src/spectral_interface.f90 index b1b536a7c..c38f32723 100644 --- a/src/spectral_interface.f90 +++ b/src/spectral_interface.f90 @@ -32,7 +32,6 @@ module DAMASK_interface makeRelativePath, & IIO_stringValue, & IIO_intValue, & - IIO_lc, & IIO_stringPos contains @@ -128,7 +127,7 @@ subroutine DAMASK_interface_init() call get_command(commandLine) chunkPos = IIO_stringPos(commandLine) do i = 1, chunkPos(1) - tag = IIO_lc(IIO_stringValue(commandLine,chunkPos,i)) ! extract key + tag = IIO_stringValue(commandLine,chunkPos,i) ! extract key select case(tag) case ('-h','--help') write(6,'(a)') ' #######################################################################' @@ -224,7 +223,6 @@ end subroutine DAMASK_interface_init !-------------------------------------------------------------------------------------------------- character(len=1024) function setWorkingDirectory(workingDirectoryArg) use system_routines, only: & - isDirectory, & getCWD, & setCWD @@ -247,16 +245,12 @@ character(len=1024) function setWorkingDirectory(workingDirectoryArg) endif wdGiven setWorkingDirectory = trim(rectifyPath(setWorkingDirectory)) - if(.not. isDirectory(trim(setWorkingDirectory))) then ! check if the directory exists - write(6,'(a20,a,a16)') ' working directory "',trim(setWorkingDirectory),'" does not exist' - call quit(1_pInt) - endif - if (setWorkingDirectory(len_trim(setWorkingDirectory):len_trim(setWorkingDirectory)) /= '/') & - setWorkingDirectory = trim(setWorkingDirectory)//'/' ! if path seperator is not given, append it - - error = setCWD(setWorkingDirectory(1:len_trim(setWorkingDirectory)-1)) ! path seperator at end causes problems - if (error) call quit(1_pInt) + error = setCWD(trim(setWorkingDirectory)) + if(error) then + write(6,'(a20,a,a16)') ' working directory "',trim(setWorkingDirectory),'" does not exist' + call quit(1_pInt) + endif end function setWorkingDirectory @@ -303,9 +297,9 @@ character(len=1024) function getGeometryFile(geometryParameter) if (posExt <= posSep) getGeometryFile = trim(getGeometryFile)//('.geom') if (scan(getGeometryFile,'/') /= 1) & - getGeometryFile = trim(workingDirectory)//trim(getGeometryFile) + getGeometryFile = trim(workingDirectory)//'/'//trim(getGeometryFile) - getGeometryFile = makeRelativePath(workingDirectory, rectifyPath(getGeometryFile)) + getGeometryFile = makeRelativePath(workingDirectory, getGeometryFile) end function getGeometryFile @@ -328,15 +322,15 @@ character(len=1024) function getLoadCaseFile(loadCaseParameter) if (posExt <= posSep) getLoadCaseFile = trim(getLoadCaseFile)//('.load') if (scan(getLoadCaseFile,'/') /= 1) & - getLoadCaseFile = trim(workingDirectory)//trim(getLoadCaseFile) + getLoadCaseFile = trim(workingDirectory)//'/'//trim(getLoadCaseFile) - getLoadCaseFile = makeRelativePath(workingDirectory, rectifyPath(getLoadCaseFile)) + getLoadCaseFile = makeRelativePath(workingDirectory, getLoadCaseFile) end function getLoadCaseFile !-------------------------------------------------------------------------------------------------- -!> @brief remove ../ and /./ from path. +!> @brief remove ../, /./, and // from path. !> @details works only if absolute path is given !-------------------------------------------------------------------------------------------------- function rectifyPath(path) @@ -351,8 +345,15 @@ function rectifyPath(path) l = len_trim(path) rectifyPath = path do i = l,3,-1 - if (rectifyPath(i-2:i) == '/./') & - rectifyPath(i-1:l) = rectifyPath(i+1:l)//' ' + if (rectifyPath(i-2:i) == '/./') rectifyPath(i-1:l) = rectifyPath(i+1:l)//' ' + enddo + +!-------------------------------------------------------------------------------------------------- +! remove // from path + l = len_trim(path) + rectifyPath = path + do i = l,2,-1 + if (rectifyPath(i-1:i) == '//') rectifyPath(i-1:l) = rectifyPath(i:l)//' ' enddo !-------------------------------------------------------------------------------------------------- @@ -381,20 +382,24 @@ end function rectifyPath character(len=1024) function makeRelativePath(a,b) implicit none - character (len=*) :: a,b + character (len=*), intent(in) :: a,b + character (len=1024) :: a_cleaned,b_cleaned integer :: i,posLastCommonSlash,remainingSlashes !no pInt posLastCommonSlash = 0 remainingSlashes = 0 + a_cleaned = rectifyPath(trim(a)//'/') + b_cleaned = rectifyPath(b) - do i = 1, min(1024,len_trim(a),len_trim(b)) - if (a(i:i) /= b(i:i)) exit - if (a(i:i) == '/') posLastCommonSlash = i + do i = 1, min(1024,len_trim(a_cleaned),len_trim(rectifyPath(b_cleaned))) + if (a_cleaned(i:i) /= b_cleaned(i:i)) exit + if (a_cleaned(i:i) == '/') posLastCommonSlash = i enddo - do i = posLastCommonSlash+1,len_trim(a) - if (a(i:i) == '/') remainingSlashes = remainingSlashes + 1 + do i = posLastCommonSlash+1,len_trim(a_cleaned) + if (a_cleaned(i:i) == '/') remainingSlashes = remainingSlashes + 1 enddo - makeRelativePath = repeat('..'//'/',remainingSlashes)//b(posLastCommonSlash+1:len_trim(b)) + + makeRelativePath = repeat('..'//'/',remainingSlashes)//b_cleaned(posLastCommonSlash+1:len_trim(b_cleaned)) end function makeRelativePath @@ -411,11 +416,8 @@ pure function IIO_stringValue(string,chunkPos,myChunk) character(len=*), intent(in) :: string !< raw input with known start and end of each chunk - valuePresent: if (myChunk > chunkPos(1) .or. myChunk < 1_pInt) then - IIO_stringValue = '' - else valuePresent - IIO_stringValue = string(chunkPos(myChunk*2):chunkPos(myChunk*2+1)) - endif valuePresent + IIO_stringValue = merge('',string(chunkPos(myChunk*2):chunkPos(myChunk*2+1)) + (myChunk > chunkPos(1) .or. myChunk < 1_pInt)) end function IIO_stringValue @@ -442,29 +444,6 @@ integer(pInt) pure function IIO_intValue(string,chunkPos,myChunk) end function IIO_intValue -!-------------------------------------------------------------------------------------------------- -!> @brief taken from IO, check IO_lc for documentation -!-------------------------------------------------------------------------------------------------- -pure function IIO_lc(string) - - implicit none - character(len=*), intent(in) :: string !< string to convert - character(len=len(string)) :: IIO_lc - - character(26), parameter :: LOWER = 'abcdefghijklmnopqrstuvwxyz' - character(26), parameter :: UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' - - integer :: i,n ! no pInt (len returns default integer) - - IIO_lc = string - do i=1,len(string) - n = index(UPPER,IIO_lc(i:i)) - if (n/=0) IIO_lc(i:i) = LOWER(n:n) - enddo - -end function IIO_lc - - !-------------------------------------------------------------------------------------------------- !> @brief taken from IO, check IO_stringPos for documentation !-------------------------------------------------------------------------------------------------- From 5fbe43053f23acf2b7bfce32b8970f8311a2aafa Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 10 Jul 2018 10:26:07 +0200 Subject: [PATCH 07/10] more logical names in test --- PRIVATE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PRIVATE b/PRIVATE index 114f2bd9c..14b60c558 160000 --- a/PRIVATE +++ b/PRIVATE @@ -1 +1 @@ -Subproject commit 114f2bd9c2025b30c0c6200709bd4b3b0cc1963a +Subproject commit 14b60c558375731e80db8e5fa49cba753f0d0939 From f493a5419be0a2bf64afdfe7216399d18ad7211d Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 10 Jul 2018 10:39:24 +0200 Subject: [PATCH 08/10] forgot line continuation --- src/spectral_interface.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spectral_interface.f90 b/src/spectral_interface.f90 index c38f32723..02d4dc0d8 100644 --- a/src/spectral_interface.f90 +++ b/src/spectral_interface.f90 @@ -416,7 +416,7 @@ pure function IIO_stringValue(string,chunkPos,myChunk) character(len=*), intent(in) :: string !< raw input with known start and end of each chunk - IIO_stringValue = merge('',string(chunkPos(myChunk*2):chunkPos(myChunk*2+1)) + IIO_stringValue = merge('',string(chunkPos(myChunk*2):chunkPos(myChunk*2+1)),& (myChunk > chunkPos(1) .or. myChunk < 1_pInt)) end function IIO_stringValue From a4e4a9c4ab25da60011c7db76b7fbac29ac6ed87 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 10 Jul 2018 21:40:01 +0200 Subject: [PATCH 09/10] merge does not work for strings of different length fixed possible out of bounds access --- src/IO.f90 | 6 +----- src/spectral_interface.f90 | 41 +++++++++++++++++++------------------- 2 files changed, 21 insertions(+), 26 deletions(-) diff --git a/src/IO.f90 b/src/IO.f90 index fd1a36339..807686e86 100644 --- a/src/IO.f90 +++ b/src/IO.f90 @@ -988,11 +988,7 @@ function IO_stringValue(string,chunkPos,myChunk,silent) logical :: warn - if (.not. present(silent)) then - warn = .false. - else - warn = silent - endif + warn = merge(silent,.false.,present(silent)) IO_stringValue = '' valuePresent: if (myChunk > chunkPos(1) .or. myChunk < 1_pInt) then diff --git a/src/spectral_interface.f90 b/src/spectral_interface.f90 index 02d4dc0d8..1ab92a178 100644 --- a/src/spectral_interface.f90 +++ b/src/spectral_interface.f90 @@ -55,9 +55,9 @@ subroutine DAMASK_interface_init() implicit none character(len=1024) :: & commandLine, & !< command line call as string - loadCaseArg ='', & !< -l argument given to DAMASK_spectral.exe - geometryArg ='', & !< -g argument given to DAMASK_spectral.exe - workingDirArg ='', & !< -w argument given to DAMASK_spectral.exe + loadcaseArg = '', & !< -l argument given to DAMASK_spectral.exe + geometryArg = '', & !< -g argument given to DAMASK_spectral.exe + workingDirArg = '', & !< -w argument given to DAMASK_spectral.exe hostName, & !< name of machine on which DAMASK_spectral.exe is execute (might require export HOSTNAME) userName, & !< name of user calling DAMASK_spectral.exe tag @@ -112,7 +112,7 @@ subroutine DAMASK_interface_init() call date_and_time(values = dateAndTime) write(6,'(/,a)') ' <<<+- DAMASK_spectral -+>>>' - write(6,'(/,a)') ' Roters et al., Computational Materials Science, 2018' + write(6,'(a,/)') ' Roters et al., Computational Materials Science, 2018' write(6,'(/,a)') ' Version: '//DAMASKVERSION write(6,'(a,2(i2.2,a),i4.4)') ' Date: ',dateAndTime(3),'/',& dateAndTime(2),'/',& @@ -126,9 +126,8 @@ subroutine DAMASK_interface_init() call get_command(commandLine) chunkPos = IIO_stringPos(commandLine) - do i = 1, chunkPos(1) - tag = IIO_stringValue(commandLine,chunkPos,i) ! extract key - select case(tag) + do i = 2_pInt, chunkPos(1) + select case(IIO_stringValue(commandLine,chunkPos,i)) ! extract key case ('-h','--help') write(6,'(a)') ' #######################################################################' write(6,'(a)') ' DAMASK_spectral:' @@ -177,18 +176,20 @@ subroutine DAMASK_interface_init() write(6,'(a,/)')' Prints this message and exits' call quit(0_pInt) ! normal Termination case ('-l', '--load', '--loadcase') - loadcaseArg = IIO_stringValue(commandLine,chunkPos,i+1_pInt) + if ( i < chunkPos(1)) loadcaseArg = trim(IIO_stringValue(commandLine,chunkPos,i+1_pInt)) case ('-g', '--geom', '--geometry') - geometryArg = IIO_stringValue(commandLine,chunkPos,i+1_pInt) + if (i < chunkPos(1)) geometryArg = trim(IIO_stringValue(commandLine,chunkPos,i+1_pInt)) case ('-w', '-d', '--wd', '--directory', '--workingdir', '--workingdirectory') - workingDirArg = IIO_stringValue(commandLine,chunkPos,i+1_pInt) + if (i < chunkPos(1)) workingDirArg = trim(IIO_stringValue(commandLine,chunkPos,i+1_pInt)) case ('-r', '--rs', '--restart') - spectralRestartInc = IIO_IntValue(commandLine,chunkPos,i+1_pInt) - appendToOutFile = .true. + if (i < chunkPos(1)) then + spectralRestartInc = IIO_IntValue(commandLine,chunkPos,i+1_pInt) + appendToOutFile = .true. + endif end select enddo - - if (len(trim(loadcaseArg)) == 0 .or. len(trim(geometryArg)) == 0) then + + if (len_trim(loadcaseArg) == 0 .or. len_trim(geometryArg) == 0) then write(6,'(a)') ' Please specify geometry AND load case (-h for help)' call quit(1_pInt) endif @@ -410,14 +411,12 @@ end function makeRelativePath pure function IIO_stringValue(string,chunkPos,myChunk) implicit none - integer(pInt), dimension(:), intent(in) :: chunkPos !< positions of start and end of each tag/chunk in given string - integer(pInt), intent(in) :: myChunk !< position number of desired chunk - character(len=1+chunkPos(myChunk*2+1)-chunkPos(myChunk*2)) :: IIO_stringValue - character(len=*), intent(in) :: string !< raw input with known start and end of each chunk + integer(pInt), dimension(:), intent(in) :: chunkPos !< positions of start and end of each tag/chunk in given string + integer(pInt), intent(in) :: myChunk !< position number of desired chunk + character(len=chunkPos(myChunk*2+1)-chunkPos(myChunk*2)+1) :: IIO_stringValue + character(len=*), intent(in) :: string !< raw input with known start and end of each chunk - - IIO_stringValue = merge('',string(chunkPos(myChunk*2):chunkPos(myChunk*2+1)),& - (myChunk > chunkPos(1) .or. myChunk < 1_pInt)) + IIO_stringValue = string(chunkPos(myChunk*2):chunkPos(myChunk*2+1)) end function IIO_stringValue From 7283ee6caa42a980ecffe5db69161bbb3207dd68 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 1 Aug 2018 09:29:01 +0200 Subject: [PATCH 10/10] using updated tests from PRIVATE/master --- PRIVATE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PRIVATE b/PRIVATE index 14b60c558..a3e5f7a4b 160000 --- a/PRIVATE +++ b/PRIVATE @@ -1 +1 @@ -Subproject commit 14b60c558375731e80db8e5fa49cba753f0d0939 +Subproject commit a3e5f7a4ba42e841238af3cee1560a4429a39a6e