From 3af61233c942c52c8e48e34e6702d4b3941da381 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 9 Jul 2023 13:25:37 +0200 Subject: [PATCH 1/8] option to specify numerics configuration file and jobname default jobname now includes all CLI arguments (for mesh/grid only) --- PRIVATE | 2 +- src/CLI.f90 | 236 +++++++++++++++++++++++++++++-------------------- src/config.f90 | 38 ++++---- 3 files changed, 163 insertions(+), 113 deletions(-) diff --git a/PRIVATE b/PRIVATE index 9f4ffce8b..3c4052994 160000 --- a/PRIVATE +++ b/PRIVATE @@ -1 +1 @@ -Subproject commit 9f4ffce8b2df951191a14dc3229de1aee6e544e6 +Subproject commit 3c4052994318bf41620af2e4c8795f36cabc3645 diff --git a/src/CLI.f90 b/src/CLI.f90 index e38532268..cc0fec002 100644 --- a/src/CLI.f90 +++ b/src/CLI.f90 @@ -21,14 +21,16 @@ module CLI implicit none(type,external) private integer, public, protected :: & - CLI_restartInc = 0 !< Increment at which calculation starts + CLI_restartInc = 0 !< increment at which calculation starts character(len=:), allocatable, public, protected :: & - CLI_geomFile, & !< parameter given for geometry file - CLI_loadFile, & !< parameter given for load case file - CLI_materialFile + CLI_geomFile, & !< location of the geometry file + CLI_loadFile, & !< location of the load case file + CLI_materialFile, & !< location of the material configuration file + CLI_numericsFile, & !< location of the numerics configuration file + solverJobname public :: & - getSolverJobName, & + getSolverJobname, & CLI_init contains @@ -47,10 +49,11 @@ subroutine CLI_init() character(len=:), allocatable :: & commandLine, & !< command line call as string arg, & !< individual argument - loadCaseArg, & !< -l argument given to the executable - geometryArg, & !< -g argument given to the executable - materialArg, & !< -m argument given to the executable - workingDirArg !< -w argument given to the executable + geomArg, & !< -g CLI argument + loadArg, & !< -l CLI argument + materialArg, & !< -m CLI argument + numericsArg, & !< -n CLI argument + workingDirArg !< -w CLI argument integer :: & stat, & i @@ -62,94 +65,105 @@ subroutine CLI_init() workingDirArg = getCWD() - print '(/,1x,a)', '<<<+- CLI init -+>>>' + print'(/,1x,a)', '<<<+- CLI init -+>>>' ! http://patorjk.com/software/taag/#p=display&f=Lean&t=DAMASK%203 #ifdef DEBUG - print '(a)', achar(27)//'[31m' - print '(1x,a,/)', 'debug version - debug version - debug version - debug version - debug version' + print'(a)', achar(27)//'[31m' + print'(1x,a,/)', 'debug version - debug version - debug version - debug version - debug version' #else - print '(a)', achar(27)//'[94m' + print'(a)', achar(27)//'[94m' #endif - print '(1x,a)', ' _/_/_/ _/_/ _/ _/ _/_/ _/_/_/ _/ _/ _/_/_/' - print '(1x,a)', ' _/ _/ _/ _/ _/_/ _/_/ _/ _/ _/ _/ _/ _/' - print '(1x,a)', ' _/ _/ _/_/_/_/ _/ _/ _/ _/_/_/_/ _/_/ _/_/ _/_/' - print '(1x,a)', ' _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/' - print '(1x,a)', '_/_/_/ _/ _/ _/ _/ _/ _/ _/_/_/ _/ _/ _/_/_/' + print'(1x,a)', ' _/_/_/ _/_/ _/ _/ _/_/ _/_/_/ _/ _/ _/_/_/' + print'(1x,a)', ' _/ _/ _/ _/ _/_/ _/_/ _/ _/ _/ _/ _/ _/' + print'(1x,a)', ' _/ _/ _/_/_/_/ _/ _/ _/ _/_/_/_/ _/_/ _/_/ _/_/' + print'(1x,a)', ' _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/' + print'(1x,a)', '_/_/_/ _/ _/ _/ _/ _/ _/ _/_/_/ _/ _/ _/_/_/' #if defined(GRID) - print '(1x,a)', 'Grid solver' + print'(1x,a)', 'Grid solver' #elif defined(MESH) - print '(1x,a)', 'Mesh solver' + print'(1x,a)', 'Mesh solver' #endif #ifdef DEBUG - print '(/,1x,a)', 'debug version - debug version - debug version - debug version - debug version' + print'(/,1x,a)', 'debug version - debug version - debug version - debug version - debug version' #endif - print '(a)', achar(27)//'[0m' + print'(a)', achar(27)//'[0m' - print '(1x,a)', 'F. Roters et al., Computational Materials Science 158:420–478, 2019' - print '(1x,a)', 'https://doi.org/10.1016/j.commatsci.2018.04.030' + print'(1x,a)', 'F. Roters et al., Computational Materials Science 158:420–478, 2019' + print'(1x,a)', 'https://doi.org/10.1016/j.commatsci.2018.04.030' - print '(/,1x,a)', 'Version: '//DAMASKVERSION + print'(/,1x,a)', 'Version: '//DAMASKVERSION - print '(/,1x,a)', 'Compiled with: '//compiler_version() - print '(1x,a)', 'Compiled on: '//CMAKE_SYSTEM - print '(1x,a)', 'Compiler options: '//compiler_options() + print'(/,1x,a)', 'Compiled with: '//compiler_version() + print'(1x,a)', 'Compiled on: '//CMAKE_SYSTEM + print'(1x,a)', 'Compiler options: '//compiler_options() ! https://github.com/jeffhammond/HPCInfo/blob/master/docs/Preprocessor-Macros.md - print '(/,1x,a)', 'Compiled on: '//__DATE__//' at '//__TIME__ + print'(/,1x,a)', 'Compiled on: '//__DATE__//' at '//__TIME__ - print '(/,1x,a,1x,i0,a,i0,a,i0)', & + print'(/,1x,a,1x,i0,a,i0,a,i0)', & 'PETSc version:',PETSC_VERSION_MAJOR,'.',PETSC_VERSION_MINOR,'.',PETSC_VERSION_SUBMINOR call date_and_time(values = dateAndTime) - print '(/,1x,a,1x,2(i2.2,a),i4.4)', 'Date:',dateAndTime(3),'/',dateAndTime(2),'/',dateAndTime(1) - print '(1x,a,1x,2(i2.2,a),i2.2)', 'Time:',dateAndTime(5),':',dateAndTime(6),':',dateAndTime(7) + print'(/,1x,a,1x,2(i2.2,a),i4.4)', 'Date:',dateAndTime(3),'/',dateAndTime(2),'/',dateAndTime(1) + print'(1x,a,1x,2(i2.2,a),i2.2)', 'Time:',dateAndTime(5),':',dateAndTime(6),':',dateAndTime(7) do i = 1, command_argument_count() arg = getArg(i) select case(trim(arg)) ! extract key case ('-h','--help') - print '(/,1x,a)','#######################################################################' - print '(1x,a)', 'DAMASK Command Line Interface:' - print '(1x,a)', 'Düsseldorf Advanced Material Simulation Kit with PETSc-based solvers' - print '(1x,a,/)','#######################################################################' - print '(1x,a,/)','Valid command line switches:' - print '(1x,a)', ' --geom (-g, --geometry)' - print '(1x,a)', ' --load (-l, --loadcase)' - print '(1x,a)', ' --material (-m, --materialconfig)' - print '(1x,a)', ' --workingdir (-w, --wd, --workingdirectory)' - print '(1x,a)', ' --restart (-r, --rs)' - print '(1x,a)', ' --help (-h)' - print '(/,1x,a)','-----------------------------------------------------------------------' - print '(1x,a)', 'Mandatory arguments:' - print '(/,1x,a)',' --geom PathToGeomFile/NameOfGeom' - print '(1x,a)', ' Specifies the location of the geometry definition file.' - print '(/,1x,a)',' --load PathToLoadFile/NameOfLoadFile' - print '(1x,a)', ' Specifies the location of the load case definition file.' - print '(/,1x,a)',' --material PathToMaterialConfigurationFile/NameOfMaterialConfigurationFile' - print '(1x,a)', ' Specifies the location of the material configuration file.' - print '(/,1x,a)','-----------------------------------------------------------------------' - print '(1x,a)', 'Optional arguments:' - print '(/,1x,a)',' --workingdirectory PathToWorkingDirectory' - print '(1x,a)', ' Specifies the base directory of relative paths.' - print '(/,1x,a)',' --restart N' - print '(1x,a)', ' Reads in increment N and continues with calculating' - print '(1x,a)', ' increment N+1, N+2, ... based on this.' - print '(1x,a)', ' Appends to existing results file' - print '(1x,a)', ' "NameOfGeom_NameOfLoadFile_NameOfMaterialConfigurationFile.hdf5".' - print '(1x,a)', ' Works only if the restart information for increment N' - print '(1x,a)', ' is available in the base directory.' - print '(/,1x,a)','-----------------------------------------------------------------------' - print '(1x,a)', 'Help:' - print '(/,1x,a)',' --help' - print '(1x,a,/)',' Prints this message and exits' + print'(/,1x,a)','#######################################################################' + print'(1x,a)', 'DAMASK Command Line Interface:' + print'(1x,a)', 'Düsseldorf Advanced Material Simulation Kit with PETSc-based solvers' + print'(1x,a,/)','#######################################################################' + print'(1x,a,/)','Valid command line switches:' + print'(1x,a)', ' --geom (-g, --geometry)' + print'(1x,a)', ' --load (-l, --loadcase)' + print'(1x,a)', ' --material (-m, --materialconfig)' + print'(1x,a)', ' --numerics (-n, --numericsconfig)' + print'(1x,a)', ' --jobname (-j, --job)' + print'(1x,a)', ' --workingdir (-w, --wd, --workingdirectory)' + print'(1x,a)', ' --restart (-r, --rs)' + print'(1x,a)', ' --help (-h)' + print'(/,1x,a)','-----------------------------------------------------------------------' + print'(1x,a)', 'Mandatory arguments:' + print'(/,1x,a)',' --geom GEOMFILE' + print'(1x,a)', ' specify the file path of the geometry definition' + print'(/,1x,a)',' --load LOADFILE' + print'(1x,a)', ' specify the file path of the load case definition' + print'(/,1x,a)',' --material MATERIALFILE' + print'(1x,a)', ' specify the file path of the material configuration' + print'(/,1x,a)','-----------------------------------------------------------------------' + print'(1x,a)', 'Optional arguments:' + print'(/,1x,a)',' --numerics NUMERICSFILE' + print'(1x,a)', ' Specify the file path of the numerics configuration' + print'(/,1x,a)',' --jobname JOBNAME' + print'(1x,a)', ' specify the job name.' + print'(1x,a)', ' Defaults to GEOM_LOAD_MATERIAL[_NUMERICS].' + print'(/,1x,a)',' --workingdirectory WORKINGDIRECTORY' + print'(1x,a)', ' specify the base directory of relative paths.' + print'(1x,a)', ' Defaults to the current working directory' + print'(/,1x,a)',' --restart N' + print'(1x,a)', ' read in increment N and continues with calculating' + print'(1x,a)', ' increment N+1, N+2, ... based on this' + print'(1x,a)', ' works only if the restart information for increment N' + print'(1x,a)', ' is available in JOBNAME_restart.hdf5' + print'(1x,a)', ' append to existing results file JOBNAME.hdf5' + print'(/,1x,a)','-----------------------------------------------------------------------' + print'(1x,a)', 'Help:' + print'(/,1x,a)',' --help' + print'(1x,a,/)',' Prints this message and exits' call quit(0) ! normal Termination - case ('-l', '--load', '--loadcase') - loadCaseArg = getArg(i+1) case ('-g', '--geom', '--geometry') - geometryArg = getArg(i+1) + geomArg = getArg(i+1) + case ('-l', '--load', '--loadcase') + loadArg = getArg(i+1) case ('-m', '--material', '--materialconfig') materialArg = getArg(i+1) + case ('-n', '--numerics', '--numericsconfig') + numericsArg = getArg(i+1) + case ('-j', '--job', '--jobname') + solverJobname = getArg(i+1) case ('-w', '--wd', '--workingdir', '--workingdirectory') workingDirArg = getArg(i+1) case ('-r', '--rs', '--restart') @@ -162,33 +176,46 @@ subroutine CLI_init() end select end do - if (.not. all([allocated(loadcaseArg),allocated(geometryArg),allocated(materialArg)])) then - print '(/,1x,a)', 'ERROR: Please specify geometry AND load case AND material configuration (-h for help)' + if (.not. all([allocated(loadArg),allocated(geomArg),allocated(materialArg)])) then + print'(/,1x,a)', 'ERROR: Please specify geometry AND load case AND material configuration (-h for help)' call quit(1) end if call setWorkingDirectory(trim(workingDirArg)) - CLI_geomFile = getPathRelCWD(geometryArg,'geometry') - CLI_loadFile = getPathRelCWD(loadCaseArg,'load case') + CLI_geomFile = getPathRelCWD(geomArg,'geometry') + CLI_loadFile = getPathRelCWD(loadArg,'load case') CLI_materialFile = getPathRelCWD(materialArg,'material configuration') + if (allocated(numericsArg)) then + CLI_numericsFile = getPathRelCWD(numericsArg,'numerics configuration') + else + CLI_numericsFile = '' + endif + + if (.not. allocated(solverJobname)) then + solverJobname = jobname(CLI_geomFile,CLI_loadFile,CLI_materialFile,CLI_numericsFile) + elseif (scan(solverJobname,'/') > 0) then + print'(/,1x,a)', 'ERROR: JOBNAME must not contain any slashes' + call quit(1) + endif commandLine = getArg(-1) - print '(/,1x,a)', 'Host name: '//getHostName() - print '(1x,a)', 'User name: '//getUserName() + print'(/,1x,a)', 'Host name: '//getHostName() + print'(1x,a)', 'User name: '//getUserName() - print '(/,1x,a,/)', 'Command line call: '//trim(commandLine) - print '(1x,a)', 'Working directory: '//IO_glueDiffering(getCWD(),workingDirArg) - print '(1x,a)', 'Geometry: '//IO_glueDiffering(CLI_geomFile,geometryArg) - print '(1x,a)', 'Load case: '//IO_glueDiffering(CLI_loadFile,loadCaseArg) - print '(1x,a)', 'Material config: '//IO_glueDiffering(CLI_materialFile,materialArg) - print '(1x,a)', 'Solver job name: '//getSolverJobName() + print'(/,1x,a,/)', 'Command line call: '//trim(commandLine) + print'(1x,a)', 'Working directory: '//IO_glueDiffering(getCWD(),workingDirArg) + print'(1x,a)', 'Geometry: '//IO_glueDiffering(CLI_geomFile,geomArg) + print'(1x,a)', 'Load case: '//IO_glueDiffering(CLI_loadFile,loadArg) + print'(1x,a)', 'Material config: '//IO_glueDiffering(CLI_materialFile,materialArg) + print'(1x,a)', 'Solver job name: '//getSolverJobname() if (CLI_restartInc > 0) & - print '(1x,a,i6.6)', 'Restart from increment: ', CLI_restartInc + print'(1x,a,i6.6)', 'Restart from increment: ', CLI_restartInc end subroutine CLI_init + !-------------------------------------------------------------------------------------------------- !> @brief Get argument from command line. !-------------------------------------------------------------------------------------------------- @@ -242,7 +269,7 @@ subroutine setWorkingDirectory(workingDirectoryArg) workingDirectory = trim(normpath(workingDirectory)) error = setCWD(trim(workingDirectory)) if (error) then - print '(1x,a)', 'ERROR: Invalid Working directory: '//trim(workingDirectory) + print'(1x,a)', 'ERROR: Invalid Working directory: '//trim(workingDirectory) call quit(1) end if @@ -250,26 +277,43 @@ end subroutine setWorkingDirectory !-------------------------------------------------------------------------------------------------- -!> @brief solver job name (no extension) as combination of geometry and load case name +!> @brief Return solver job name (MSC.Marc compatible). !-------------------------------------------------------------------------------------------------- -function getSolverJobName() +function getSolverJobname() - character(len=:), allocatable :: getSolverJobName - - integer :: posExt,posSep + character(len=:), allocatable :: getSolverJobname - posExt = scan(CLI_geomFile,'.',back=.true.) - posSep = scan(CLI_geomFile,'/',back=.true.) + getSolverJobname = solverJobname - getSolverJobName = CLI_geomFile(posSep+1:posExt-1) +end function getSolverJobname - posExt = scan(CLI_loadFile,'.',back=.true.) - posSep = scan(CLI_loadFile,'/',back=.true.) - getSolverJobName = getSolverJobName//'_'//CLI_loadFile(posSep+1:posExt-1) +!-------------------------------------------------------------------------------------------------- +!> @brief Determine solver job name. +!-------------------------------------------------------------------------------------------------- +function jobname(geomFile,LoadFile,materialsFile,numericsFile) -end function getSolverJobName + character(len=:), allocatable :: jobname + character(len=*), intent(in) :: geomFile,loadFile,materialsFile,numericsFile + + + jobname = stem(geomFile)//'_'//stem(loadFile)//'_'//stem(materialsFile) + if (len_trim(numericsFile) > 0) jobname = jobname//'_'//stem(numericsFile) + + contains + + function stem(fullname) + + character(len=:), allocatable :: stem + character(len=*), intent(in) :: fullname + + + stem = fullname(scan(fullname,'/',back=.true.)+1:scan(fullname,'.',back=.true.)-1) + + end function stem + +end function jobname !-------------------------------------------------------------------------------------------------- @@ -291,7 +335,7 @@ function getPathRelCWD(path,fileType) inquire(file=getPathRelCWD, exist=file_exists) if (.not. file_exists) then - print '(1x,a)', 'ERROR: '//fileType//' file does not exist: '//trim(getPathRelCWD) + print'(1x,a)', 'ERROR: '//fileType//' file does not exist: '//trim(getPathRelCWD) call quit(1) end if diff --git a/src/config.f90 b/src/config.f90 index 9006839bf..e0b2dcdad 100644 --- a/src/config.f90 +++ b/src/config.f90 @@ -68,11 +68,10 @@ end subroutine config_numerics_deallocate !-------------------------------------------------------------------------------------------------- function config_listReferences(config,indent) result(references) - type(tDict) :: config - integer, optional :: indent + type(tDict), intent(in) :: config + integer, intent(in), optional :: indent character(len=:), allocatable :: references - type(tList), pointer :: ref character(len=:), allocatable :: filler integer :: r @@ -97,13 +96,13 @@ end function config_listReferences !-------------------------------------------------------------------------------------------------- subroutine parse_material() - logical :: fileExists character(len=:), allocatable :: & fileContent, fname + if (worldrank == 0) then print'(/,1x,a)', 'reading material configuration'; flush(IO_STDOUT) -#if defined(MESH) || defined(GRID) +#if defined(MESH) || defined(GRID) fname = CLI_materialFile #else fname = 'material.yaml' @@ -126,23 +125,30 @@ end subroutine parse_material !-------------------------------------------------------------------------------------------------- subroutine parse_numerics() - logical :: fileExists - character(len=:), allocatable :: fileContent + character(len=:), allocatable :: & + fileContent, fname + logical :: parse config_numerics => emptyDict - inquire(file='numerics.yaml', exist=fileExists) - if (fileExists) then +#if defined(MESH) || defined(GRID) + fname = CLI_numericsFile + parse = len_trim(CLI_numericsFile) > 0 +#else + fname = 'numerics.yaml' + inquire(file=fname, exist=parse) +#endif + + if (parse) then if (worldrank == 0) then - print'(1x,a)', 'reading numerics.yaml'; flush(IO_STDOUT) - fileContent = IO_read('numerics.yaml') - if (len(fileContent) > 0) then - call result_openJobFile(parallel=.false.) - call result_writeDataset_str(fileContent,'setup','numerics.yaml','numerics configuration') - call result_closeJobFile() - end if + print'(1x,a)', 'reading numerics configuration'; flush(IO_STDOUT) + fileContent = IO_read(fname) + if (scan(fname,'/') /= 0) fname = fname(scan(fname,'/',.true.)+1:) + call result_openJobFile(parallel=.false.) + call result_writeDataset_str(fileContent,'setup',fname,'numerics configuration') + call result_closeJobFile() end if call parallelization_bcast_str(fileContent) From 4a1c6e7b4f237ea6331ddeb7f38c3d7dbf6d0dbb Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 10 Jul 2023 20:05:17 +0200 Subject: [PATCH 2/8] unified code --- src/CLI.f90 | 10 +++--- src/config.f90 | 82 +++++++++++++++++--------------------------------- 2 files changed, 31 insertions(+), 61 deletions(-) diff --git a/src/CLI.f90 b/src/CLI.f90 index cc0fec002..771d6da9f 100644 --- a/src/CLI.f90 +++ b/src/CLI.f90 @@ -185,11 +185,8 @@ subroutine CLI_init() CLI_geomFile = getPathRelCWD(geomArg,'geometry') CLI_loadFile = getPathRelCWD(loadArg,'load case') CLI_materialFile = getPathRelCWD(materialArg,'material configuration') - if (allocated(numericsArg)) then + if (allocated(numericsArg)) & CLI_numericsFile = getPathRelCWD(numericsArg,'numerics configuration') - else - CLI_numericsFile = '' - endif if (.not. allocated(solverJobname)) then solverJobname = jobname(CLI_geomFile,CLI_loadFile,CLI_materialFile,CLI_numericsFile) @@ -295,11 +292,12 @@ end function getSolverJobname function jobname(geomFile,LoadFile,materialsFile,numericsFile) character(len=:), allocatable :: jobname - character(len=*), intent(in) :: geomFile,loadFile,materialsFile,numericsFile + character(len=*), intent(in) :: geomFile,loadFile,materialsFile + character(len=:), allocatable, intent(in) :: numericsFile jobname = stem(geomFile)//'_'//stem(loadFile)//'_'//stem(materialsFile) - if (len_trim(numericsFile) > 0) jobname = jobname//'_'//stem(numericsFile) + if (allocated(numericsFile)) jobname = jobname//'_'//stem(numericsFile) contains diff --git a/src/config.f90 b/src/config.f90 index e0b2dcdad..edb72fbd3 100644 --- a/src/config.f90 +++ b/src/config.f90 @@ -34,8 +34,23 @@ subroutine config_init() print'(/,1x,a)', '<<<+- config init -+>>>'; flush(IO_STDOUT) - call parse_material() - call parse_numerics() +#if defined(MESH) || defined(GRID) + config_material => parse(CLI_materialFile,'material configuration') +#else + config_material => parse('material.yaml','material configuration') +#endif + + config_numerics => emptyDict +#if defined(MESH) || defined(GRID) + if (allocated(CLI_numericsFile)) & + config_numerics => parse(CLI_numericsFile,'numerics configuration') +#else + MSCMarc: block + logical :: exists + inquire(file='numerics.yaml',exist=exists) + if (exists) config_numerics => parse('numerics.yaml','numerics configuration') + end block MSCMarc +#endif end subroutine config_init @@ -92,70 +107,27 @@ end function config_listReferences !-------------------------------------------------------------------------------------------------- -!> @brief Read material.yaml. +!> @brief Read configuration, spread over all processes, and add to DADF5. !-------------------------------------------------------------------------------------------------- -subroutine parse_material() +function parse(fname,description) - character(len=:), allocatable :: & - fileContent, fname + character(len=*), intent(in) :: fname, description + type(tDict), pointer :: parse + + character(len=:), allocatable :: fileContent if (worldrank == 0) then - print'(/,1x,a)', 'reading material configuration'; flush(IO_STDOUT) -#if defined(MESH) || defined(GRID) - fname = CLI_materialFile -#else - fname = 'material.yaml' -#endif + print'(/,1x,a)', 'reading '//description; flush(IO_STDOUT) fileContent = IO_read(fname) - if (scan(fname,'/') /= 0) fname = fname(scan(fname,'/',.true.)+1:) call result_openJobFile(parallel=.false.) - call result_writeDataset_str(fileContent,'setup',fname,'material configuration') + call result_writeDataset_str(fileContent,'setup',fname(scan(fname,'/',.true.)+1:),description) call result_closeJobFile() end if call parallelization_bcast_str(fileContent) - config_material => YAML_parse_str_asDict(fileContent) + parse => YAML_parse_str_asDict(fileContent) -end subroutine parse_material - - -!-------------------------------------------------------------------------------------------------- -!> @brief Read numerics.yaml. -!-------------------------------------------------------------------------------------------------- -subroutine parse_numerics() - - character(len=:), allocatable :: & - fileContent, fname - logical :: parse - - - config_numerics => emptyDict - -#if defined(MESH) || defined(GRID) - fname = CLI_numericsFile - parse = len_trim(CLI_numericsFile) > 0 -#else - fname = 'numerics.yaml' - inquire(file=fname, exist=parse) -#endif - - if (parse) then - - if (worldrank == 0) then - print'(1x,a)', 'reading numerics configuration'; flush(IO_STDOUT) - fileContent = IO_read(fname) - if (scan(fname,'/') /= 0) fname = fname(scan(fname,'/',.true.)+1:) - call result_openJobFile(parallel=.false.) - call result_writeDataset_str(fileContent,'setup',fname,'numerics configuration') - call result_closeJobFile() - end if - call parallelization_bcast_str(fileContent) - - config_numerics => YAML_parse_str_asDict(fileContent) - - end if - -end subroutine parse_numerics +end function parse end module config From 162a009aa9b82408d92acd7437eb95530789992b Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 11 Jul 2023 15:11:17 +0200 Subject: [PATCH 3/8] helpful error messages --- src/CLI.f90 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/CLI.f90 b/src/CLI.f90 index 771d6da9f..587ae7949 100644 --- a/src/CLI.f90 +++ b/src/CLI.f90 @@ -155,18 +155,25 @@ subroutine CLI_init() print'(1x,a,/)',' Prints this message and exits' call quit(0) ! normal Termination case ('-g', '--geom', '--geometry') + if (i+1 > command_argument_count()) print'(/,1x,a)', 'ERROR: Missing argument for --geom' geomArg = getArg(i+1) case ('-l', '--load', '--loadcase') + if (i+1 > command_argument_count()) print'(/,1x,a)', 'ERROR: Missing argument for --load' loadArg = getArg(i+1) case ('-m', '--material', '--materialconfig') + if (i+1 > command_argument_count()) print'(/,1x,a)', 'ERROR: Missing argument for --material' materialArg = getArg(i+1) case ('-n', '--numerics', '--numericsconfig') + if (i+1 > command_argument_count()) print'(/,1x,a)', 'ERROR: Missing argument for --numerics' numericsArg = getArg(i+1) case ('-j', '--job', '--jobname') + if (i+1 > command_argument_count()) print'(/,1x,a)', 'ERROR: Missing argument for --jobname' solverJobname = getArg(i+1) case ('-w', '--wd', '--workingdir', '--workingdirectory') + if (i+1 > command_argument_count()) print'(/,1x,a)', 'ERROR: Missing argument for --workingdirectory' workingDirArg = getArg(i+1) case ('-r', '--rs', '--restart') + if (i+1 > command_argument_count()) print'(/,1x,a)', 'ERROR: Missing argument for --restart' arg = getArg(i+1) read(arg,*,iostat=stat) CLI_restartInc if (CLI_restartInc < 0 .or. stat /= 0) then From 295b5348f3637e4f412077f0261a5650b659be97 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 11 Jul 2023 17:32:04 +0200 Subject: [PATCH 4/8] update tests (could fail due to random input) --- PRIVATE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PRIVATE b/PRIVATE index 3c4052994..d61d62667 160000 --- a/PRIVATE +++ b/PRIVATE @@ -1 +1 @@ -Subproject commit 3c4052994318bf41620af2e4c8795f36cabc3645 +Subproject commit d61d62667fb683a61dcc41cd90194a2d9b279879 From 70817606db5bc3c95e7ff526cb229195efddea60 Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Tue, 11 Jul 2023 12:35:23 -0400 Subject: [PATCH 5/8] shorter logic for missing arguments --- src/CLI.f90 | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/CLI.f90 b/src/CLI.f90 index 587ae7949..f2575657c 100644 --- a/src/CLI.f90 +++ b/src/CLI.f90 @@ -59,6 +59,8 @@ subroutine CLI_init() i integer, dimension(8) :: & dateAndTime + logical :: & + hasArg external :: & quit @@ -109,6 +111,7 @@ subroutine CLI_init() print'(1x,a,1x,2(i2.2,a),i2.2)', 'Time:',dateAndTime(5),':',dateAndTime(6),':',dateAndTime(7) do i = 1, command_argument_count() + hasArg = i < command_argument_count() arg = getArg(i) select case(trim(arg)) ! extract key case ('-h','--help') @@ -155,25 +158,25 @@ subroutine CLI_init() print'(1x,a,/)',' Prints this message and exits' call quit(0) ! normal Termination case ('-g', '--geom', '--geometry') - if (i+1 > command_argument_count()) print'(/,1x,a)', 'ERROR: Missing argument for --geom' + if (.not. hasArg) print'(/,1x,a)', 'ERROR: Missing argument for --geom' geomArg = getArg(i+1) case ('-l', '--load', '--loadcase') - if (i+1 > command_argument_count()) print'(/,1x,a)', 'ERROR: Missing argument for --load' + if (.not. hasArg) print'(/,1x,a)', 'ERROR: Missing argument for --load' loadArg = getArg(i+1) case ('-m', '--material', '--materialconfig') - if (i+1 > command_argument_count()) print'(/,1x,a)', 'ERROR: Missing argument for --material' + if (.not. hasArg) print'(/,1x,a)', 'ERROR: Missing argument for --material' materialArg = getArg(i+1) case ('-n', '--numerics', '--numericsconfig') - if (i+1 > command_argument_count()) print'(/,1x,a)', 'ERROR: Missing argument for --numerics' + if (.not. hasArg) print'(/,1x,a)', 'ERROR: Missing argument for --numerics' numericsArg = getArg(i+1) case ('-j', '--job', '--jobname') - if (i+1 > command_argument_count()) print'(/,1x,a)', 'ERROR: Missing argument for --jobname' + if (.not. hasArg) print'(/,1x,a)', 'ERROR: Missing argument for --jobname' solverJobname = getArg(i+1) case ('-w', '--wd', '--workingdir', '--workingdirectory') - if (i+1 > command_argument_count()) print'(/,1x,a)', 'ERROR: Missing argument for --workingdirectory' + if (.not. hasArg) print'(/,1x,a)', 'ERROR: Missing argument for --workingdirectory' workingDirArg = getArg(i+1) case ('-r', '--rs', '--restart') - if (i+1 > command_argument_count()) print'(/,1x,a)', 'ERROR: Missing argument for --restart' + if (.not. hasArg) print'(/,1x,a)', 'ERROR: Missing argument for --restart' arg = getArg(i+1) read(arg,*,iostat=stat) CLI_restartInc if (CLI_restartInc < 0 .or. stat /= 0) then @@ -340,7 +343,7 @@ function getPathRelCWD(path,fileType) inquire(file=getPathRelCWD, exist=file_exists) if (.not. file_exists) then - print'(1x,a)', 'ERROR: '//fileType//' file does not exist: '//trim(getPathRelCWD) + print'(/,1x,a)', 'ERROR: '//fileType//' file does not exist: '//trim(getPathRelCWD) call quit(1) end if From 83db176e1b82c24d31f97cf68de038385d51973c Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Tue, 11 Jul 2023 13:19:31 -0400 Subject: [PATCH 6/8] specific error per missing mandatory argument --- src/CLI.f90 | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/CLI.f90 b/src/CLI.f90 index f2575657c..2774ee855 100644 --- a/src/CLI.f90 +++ b/src/CLI.f90 @@ -158,36 +158,46 @@ subroutine CLI_init() print'(1x,a,/)',' Prints this message and exits' call quit(0) ! normal Termination case ('-g', '--geom', '--geometry') - if (.not. hasArg) print'(/,1x,a)', 'ERROR: Missing argument for --geom' + if (.not. hasArg) print'(/,1x,a)', 'ERROR: missing argument for --geom' geomArg = getArg(i+1) case ('-l', '--load', '--loadcase') - if (.not. hasArg) print'(/,1x,a)', 'ERROR: Missing argument for --load' + if (.not. hasArg) print'(/,1x,a)', 'ERROR: missing argument for --load' loadArg = getArg(i+1) case ('-m', '--material', '--materialconfig') - if (.not. hasArg) print'(/,1x,a)', 'ERROR: Missing argument for --material' + if (.not. hasArg) print'(/,1x,a)', 'ERROR: missing argument for --material' materialArg = getArg(i+1) case ('-n', '--numerics', '--numericsconfig') - if (.not. hasArg) print'(/,1x,a)', 'ERROR: Missing argument for --numerics' + if (.not. hasArg) print'(/,1x,a)', 'ERROR: missing argument for --numerics' numericsArg = getArg(i+1) case ('-j', '--job', '--jobname') - if (.not. hasArg) print'(/,1x,a)', 'ERROR: Missing argument for --jobname' + if (.not. hasArg) print'(/,1x,a)', 'ERROR: missing argument for --jobname' solverJobname = getArg(i+1) case ('-w', '--wd', '--workingdir', '--workingdirectory') - if (.not. hasArg) print'(/,1x,a)', 'ERROR: Missing argument for --workingdirectory' + if (.not. hasArg) print'(/,1x,a)', 'ERROR: missing argument for --workingdirectory' workingDirArg = getArg(i+1) case ('-r', '--rs', '--restart') - if (.not. hasArg) print'(/,1x,a)', 'ERROR: Missing argument for --restart' + if (.not. hasArg) print'(/,1x,a)', 'ERROR: missing argument for --restart' arg = getArg(i+1) read(arg,*,iostat=stat) CLI_restartInc if (CLI_restartInc < 0 .or. stat /= 0) then - print'(/,1x,a)', 'ERROR: Could not parse restart increment: '//trim(arg) + print'(/,1x,a)', 'ERROR: could not parse restart increment: '//trim(arg) call quit(1) end if end select end do - if (.not. all([allocated(loadArg),allocated(geomArg),allocated(materialArg)])) then - print'(/,1x,a)', 'ERROR: Please specify geometry AND load case AND material configuration (-h for help)' + if (.not. allocated(loadArg)) then + print'(/,1x,a)', 'Error: no load case specified (-h for help)' + call quit(1) + end if + + if (.not. allocated(geomArg)) then + print'(/,1x,a)', 'Error: no geometry specified (-h for help)' + call quit(1) + end if + + if (.not. allocated(materialArg)) then + print'(/,1x,a)', 'Error: no material configuration specified (-h for help)' call quit(1) end if @@ -276,7 +286,7 @@ subroutine setWorkingDirectory(workingDirectoryArg) workingDirectory = trim(normpath(workingDirectory)) error = setCWD(trim(workingDirectory)) if (error) then - print'(1x,a)', 'ERROR: Invalid Working directory: '//trim(workingDirectory) + print'(1x,a)', 'ERROR: invalid working directory: '//trim(workingDirectory) call quit(1) end if From 0e7c9f101c85c98df2aa0cda80ed5182035458ba Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 11 Jul 2023 20:37:21 +0200 Subject: [PATCH 7/8] avoid file name clashes --- src/Marc/discretization_Marc.f90 | 6 ++--- src/config.f90 | 2 +- src/grid/DAMASK_grid.f90 | 2 +- src/grid/discretization_grid.f90 | 2 +- src/result.f90 | 41 ++++++++++++++++++++++++++++---- 5 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/Marc/discretization_Marc.f90 b/src/Marc/discretization_Marc.f90 index 63fe3f194..3d9778e0e 100644 --- a/src/Marc/discretization_Marc.f90 +++ b/src/Marc/discretization_Marc.f90 @@ -210,9 +210,9 @@ subroutine inputRead(elem,node0_elem,connectivity_elem,materialAt) call result_openJobFile() - call result_writeDataset_str(IO_read(trim(getSolverJobName())//InputFileExtension), 'setup', & - trim(getSolverJobName())//InputFileExtension, & - 'MSC.Marc input deck') + call result_addSetupFile(IO_read(trim(getSolverJobName())//InputFileExtension), & + trim(getSolverJobName())//InputFileExtension, & + 'MSC.Marc input deck') call result_closeJobFile() inputFile = IO_readlines(trim(getSolverJobName())//InputFileExtension) diff --git a/src/config.f90 b/src/config.f90 index edb72fbd3..0d7b9e385 100644 --- a/src/config.f90 +++ b/src/config.f90 @@ -121,7 +121,7 @@ function parse(fname,description) print'(/,1x,a)', 'reading '//description; flush(IO_STDOUT) fileContent = IO_read(fname) call result_openJobFile(parallel=.false.) - call result_writeDataset_str(fileContent,'setup',fname(scan(fname,'/',.true.)+1:),description) + call result_addSetupFile(fileContent,fname,description) call result_closeJobFile() end if call parallelization_bcast_str(fileContent) diff --git a/src/grid/DAMASK_grid.f90 b/src/grid/DAMASK_grid.f90 index 6015648b4..443f69f9c 100644 --- a/src/grid/DAMASK_grid.f90 +++ b/src/grid/DAMASK_grid.f90 @@ -146,7 +146,7 @@ program DAMASK_grid fname = CLI_loadFile if (scan(fname,'/') /= 0) fname = fname(scan(fname,'/',.true.)+1:) call result_openJobFile(parallel=.false.) - call result_writeDataset_str(fileContent,'setup',fname,'load case definition (grid solver)') + call result_addSetupFile(fileContent,fname,'load case definition (grid solver)') call result_closeJobFile() end if diff --git a/src/grid/discretization_grid.f90 b/src/grid/discretization_grid.f90 index f2f9ca126..e77a173e3 100644 --- a/src/grid/discretization_grid.f90 +++ b/src/grid/discretization_grid.f90 @@ -89,7 +89,7 @@ subroutine discretization_grid_init(restart) fname = CLI_geomFile if (scan(fname,'/') /= 0) fname = fname(scan(fname,'/',.true.)+1:) call result_openJobFile(parallel=.false.) - call result_writeDataset_str(fileContent,'setup',fname,'geometry definition (grid solver)') + call result_addSetupFile(fileContent,fname,'geometry definition (grid solver)') call result_closeJobFile() else allocate(materialAt_global(0)) ! needed for IntelMPI diff --git a/src/result.f90 b/src/result.f90 index b21429fa8..b8facc26a 100644 --- a/src/result.f90 +++ b/src/result.f90 @@ -62,6 +62,7 @@ module result result_writeDataset, & result_writeDataset_str, & result_setLink, & + result_addSetupFile, & result_addAttribute, & result_removeLink, & result_mapping_phase, & @@ -166,7 +167,7 @@ end subroutine result_finalizeIncrement !-------------------------------------------------------------------------------------------------- -!> @brief open a group from the result file +!> @brief Open a group from the result file. !-------------------------------------------------------------------------------------------------- integer(HID_T) function result_openGroup(groupName) @@ -179,7 +180,7 @@ end function result_openGroup !-------------------------------------------------------------------------------------------------- -!> @brief adds a new group to the result file +!> @brief Add a new group to the result file. !-------------------------------------------------------------------------------------------------- integer(HID_T) function result_addGroup(groupName) @@ -192,7 +193,7 @@ end function result_addGroup !-------------------------------------------------------------------------------------------------- -!> @brief close a group +!> @brief Close a group. !-------------------------------------------------------------------------------------------------- subroutine result_closeGroup(group_id) @@ -205,7 +206,7 @@ end subroutine result_closeGroup !-------------------------------------------------------------------------------------------------- -!> @brief set link to object in result file +!> @brief Set link to object in result file. !-------------------------------------------------------------------------------------------------- subroutine result_setLink(path,link) @@ -216,6 +217,38 @@ subroutine result_setLink(path,link) end subroutine result_setLink + +!-------------------------------------------------------------------------------------------------- +!> @brief Add file to setup folder and ensure unique name. +!-------------------------------------------------------------------------------------------------- +subroutine result_addSetupFile(content,fname,description) + + character(len=*), intent(in) :: content, fname, description + + integer(HID_T) :: groupHandle + character(len=:), allocatable :: fname_ + integer :: i + + groupHandle = result_openGroup('setup') + fname_ = fname(scan(fname,'/',.true.)+1:) + if (.not. HDF5_objectExists(groupHandle,fname_)) then + call result_writeDataset_str(content,'setup',fname_,description) + else + i = 1 + do + fname_ = fname(scan(fname,'/',.true.)+1:)//'.'//IO_intAsStr(i) + if (.not. HDF5_objectExists(groupHandle,fname_)) then + call result_writeDataset_str(content,'setup',fname_,description) + exit + i = i+1 + end if + end do + end if + call result_closeGroup(groupHandle) + +end subroutine result_addSetupFile + + !-------------------------------------------------------------------------------------------------- !> @brief Add a string attribute to an object in the result file. !-------------------------------------------------------------------------------------------------- From 4d8fc08a2f1971bab21f3ef9ff583eb866bfa222 Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Tue, 11 Jul 2023 16:11:59 -0400 Subject: [PATCH 8/8] shorter logic for addSetupFile --- src/result.f90 | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/result.f90 b/src/result.f90 index b8facc26a..de9db4091 100644 --- a/src/result.f90 +++ b/src/result.f90 @@ -226,24 +226,19 @@ subroutine result_addSetupFile(content,fname,description) character(len=*), intent(in) :: content, fname, description integer(HID_T) :: groupHandle - character(len=:), allocatable :: fname_ + character(len=:), allocatable :: name,suffix integer :: i groupHandle = result_openGroup('setup') - fname_ = fname(scan(fname,'/',.true.)+1:) - if (.not. HDF5_objectExists(groupHandle,fname_)) then - call result_writeDataset_str(content,'setup',fname_,description) - else - i = 1 - do - fname_ = fname(scan(fname,'/',.true.)+1:)//'.'//IO_intAsStr(i) - if (.not. HDF5_objectExists(groupHandle,fname_)) then - call result_writeDataset_str(content,'setup',fname_,description) - exit - i = i+1 - end if - end do - end if + name = fname(scan(fname,'/',.true.)+1:) + suffix = '' + i = 0 + + do while (HDF5_objectExists(groupHandle,name//suffix)) + i = i+1 + suffix = '.'//IO_intAsStr(i) + end do + call result_writeDataset_str(content,'setup',name//suffix,description) call result_closeGroup(groupHandle) end subroutine result_addSetupFile