From 89321c48053c49fba5acea941863309f5c7d3c8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20Iraz=C3=A1bal=20Gonz=C3=A1lez?= Date: Mon, 26 Oct 2026 17:08:09 +0100 Subject: [PATCH 1/3] Add VTK output options and configuration parameters to project settings --- .../apps/Dam/write/writeProjectParameters.tcl | 194 +++++++++++++++++- kratos.gid/apps/Dam/xml/Results.spd | 20 +- 2 files changed, 207 insertions(+), 7 deletions(-) diff --git a/kratos.gid/apps/Dam/write/writeProjectParameters.tcl b/kratos.gid/apps/Dam/write/writeProjectParameters.tcl index bdd25c622..5c1b2e1a0 100644 --- a/kratos.gid/apps/Dam/write/writeProjectParameters.tcl +++ b/kratos.gid/apps/Dam/write/writeProjectParameters.tcl @@ -17,7 +17,14 @@ proc ::Dam::write::getParametersDict { } { dict set projectParametersDict solver_settings [Dam::write::GetSolverSettingsDict] ### Output data - dict set projectParametersDict output_configuration [Dam::write::GetOutputDict] + # GiD output keeps using the legacy output_configuration block. VTK output + # uses the standard output_processes block supported by DamAnalysis. + if {[Dam::write::GetOutputGiDFlag]} { + dict set projectParametersDict output_configuration [Dam::write::GetOutputDict] + } + if {[Dam::write::GetOutputVTKFlag]} { + dict set projectParametersDict output_processes vtk_output [list [Dam::write::GetVTKOutputProcessDict]] + } ### Constraints processes dict set projectParametersDict constraints_process_list [Dam::write::ChangeFileNameforTableid [::write::getConditionsParametersDict DamNodalConditions "Nodal"]] @@ -462,6 +469,191 @@ proc ::Dam::write::GetOutputDict { {appid ""} } { return $outputDict } +# Returns whether the legacy GiD output must be written. Missing values (older +# projects) fall back to the historical behavior: GiD output enabled. +proc ::Dam::write::GetOutputGiDFlag { } { + set value [write::getValue Results OutputGiD] + if {$value eq ""} {return 1} + return [write::isBooleanTrue $value] +} + +# Returns whether the standard VTK output process must be written. +# Missing values (older projects) default to VTK output disabled. +proc ::Dam::write::GetOutputVTKFlag { } { + set value [write::getValue Results OutputVTK] + if {$value eq ""} {return 0} + return [write::isBooleanTrue $value] +} + +# Builds the standard VtkOutputProcess configuration. Only parameters accepted +# by the standard Kratos process are written here. +proc ::Dam::write::GetVTKOutputProcessDict { } { + + Dam::write::WarnAboutVTKGaussPointResults + Dam::write::WarnAboutVTKDelayedOutput + + set parametersDict [dict create] + dict set parametersDict model_part_name [Dam::write::GetVTKModelPartName] + dict set parametersDict file_format [Dam::write::GetVTKFileFormat] + dict set parametersDict output_precision [Dam::write::GetVTKOutputPrecision] + dict set parametersDict output_path [Dam::write::GetVTKOutputPath] + dict set parametersDict save_output_files_in_folder true + dict set parametersDict write_deformed_configuration [Dam::write::GetVTKWriteDeformedConfiguration] + dict set parametersDict output_control_type "time" + dict set parametersDict output_interval [Dam::write::GetVTKOutputIntervalInSeconds] + dict set parametersDict nodal_solution_step_data_variables [Dam::write::GetVTKNodalResultsList] + + set vtkProcessDict [dict create] + dict set vtkProcessDict python_module "vtk_output_process" + dict set vtkProcessDict kratos_module "KratosMultiphysics" + dict set vtkProcessDict process_name "VtkOutputProcess" + dict set vtkProcessDict Parameters $parametersDict + return $vtkProcessDict +} + +# Returns the full name of the model part used by the VtkOutputProcess. All +# mechanical solvers share "mechanical_computing_domain"; the acoustic solver +# computes on the root model part. +proc ::Dam::write::GetVTKModelPartName { } { + set rootModelPart [string trim [Dam::write::GetAttribute model_part_name]] + if {$rootModelPart eq ""} {set rootModelPart "MainModelPart"} + + set damTypeofProblem [write::getValue DamTypeofProblem] + if {$damTypeofProblem eq "Acoustic"} {return $rootModelPart} + return "${rootModelPart}.mechanical_computing_domain" +} + +proc ::Dam::write::GetVTKFileFormat { } { + set fileFormat [string trim [write::getValue DamVTKFileFormat]] + if {$fileFormat ni [list "binary" "ascii"]} { + W "Dam VTK output: unknown file format '$fileFormat'. Using 'binary'." + set fileFormat "binary" + } + return $fileFormat +} + +proc ::Dam::write::GetVTKOutputPrecision { } { + set precision [string trim [write::getValue DamVTKOutputPrecision]] + if {![string is integer -strict $precision] || $precision < 1} { + W "Dam VTK output: invalid output precision '$precision'. Using 7." + return 7 + } + return [expr {int($precision)}] +} + +proc ::Dam::write::GetVTKWriteDeformedConfiguration { } { + set value [write::getValue DamVTKWriteDeformedConfiguration] + if {$value eq ""} {return true} + if {[write::isBooleanTrue $value]} {return true} + return false +} + +# Converts the shared Dam output frequency to the seconds-based interval used +# by the standard VtkOutputProcess ("output_control_type": "time"). +proc ::Dam::write::GetVTKOutputIntervalInSeconds { } { + set outputCT [write::getValue Results OutputControlType] + + if {$outputCT eq "time_s"} { + set factor 1.0 + set delta [write::getValue Results OutputDeltaTime_s] + } elseif {$outputCT eq "time_h"} { + set factor 3600.0 + set delta [write::getValue Results OutputDeltaTime_h] + } elseif {$outputCT eq "time_d"} { + set factor 86400.0 + set delta [write::getValue Results OutputDeltaTime_d] + } elseif {$outputCT eq "time_w"} { + set factor 604800.0 + set delta [write::getValue Results OutputDeltaTime_w] + } else { + W "Dam VTK output: unknown output control type '$outputCT'. Using seconds." + set factor 1.0 + set delta [write::getValue Results OutputDeltaTime_s] + } + + if {![string is double -strict $delta] || $delta <= 0.0} { + W "Dam VTK output: invalid output interval '$delta'. Using 1.0 second." + set delta 1.0 + } + + return [expr {double($delta) * $factor}] +} + +# Returns a dedicated relative output folder, rejecting paths that could make +# the standard VtkOutputProcess delete unrelated contents. +proc ::Dam::write::GetVTKOutputPath { } { + set outputPath [string trim [write::getValue DamVTKOutputPath]] + if {$outputPath eq ""} {set outputPath "VTK_Output"} + + if {[Dam::write::IsUnsafeVTKOutputPath $outputPath]} { + W "Dam VTK output: output directory '$outputPath' is not a safe dedicated relative folder. Using 'VTK_Output' instead." + return "VTK_Output" + } + return $outputPath +} + +proc ::Dam::write::IsUnsafeVTKOutputPath { outputPath } { + set path [string trim $outputPath] + if {$path eq ""} {return 1} + + # Absolute Unix paths, home-relative paths, Windows drives and UNC paths. + if {[string index $path 0] eq "/" || [string index $path 0] eq "~"} {return 1} + if {[regexp {^[A-Za-z]:} $path] || [regexp {^\\\\} $path]} {return 1} + + # Normalize separators so parent traversal is detected on any platform. + set components [list] + foreach component [split [string map {"\\" "/"} $path] "/"] { + if {$component eq ".."} {return 1} + if {$component ne "" && $component ne "."} {lappend components $component} + } + + # Reject the working-directory root and equivalent path aliases. + if {[llength $components] == 0} {return 1} + + # Do not delete folders owned by other interface features. + set effectivePath [string tolower [join $components "/"]] + if {[lsearch -exact [list "monitoringdevices"] $effectivePath] >= 0} {return 1} + + return 0 +} + +# Reuses the existing GiD nodal result selection, keeping only variables that +# are safe for the standard VTK writer. +proc ::Dam::write::GetVTKNodalResultsList { } { + set supportedVariables [list \ + DISPLACEMENT REACTION VELOCITY ACCELERATION PRESSURE TEMPERATURE \ + NODAL_REFERENCE_TEMPERATURE HEAT_FLUX FACE_HEAT_FLUX VOLUME_ACCELERATION \ + POSITIVE_FACE_PRESSURE NODAL_JOINT_WIDTH Vi_POSITIVE Viii_POSITIVE] + + set vtkResults [list] + foreach result [write::GetResultsList Results OnNodes] { + if {[lsearch -exact $supportedVariables $result] >= 0} { + lappend vtkResults $result + } else { + W "Dam VTK output: result '$result' is not available for VTK output (unsupported variable type or not stored as a nodal solution-step variable) and will be omitted from the VTK file." + } + } + return $vtkResults +} + +proc ::Dam::write::WarnAboutVTKDelayedOutput { } { + set startOutput [write::getValue Results StartOutputResults] + if {$startOutput ne "" && [string is double -strict $startOutput] && $startOutput > 0.0} { + W "Dam VTK output: 'Start output results' is not supported by the standard VtkOutputProcess. VTK output will start at the first output interval boundary from time 0." + } +} + +proc ::Dam::write::WarnAboutVTKGaussPointResults { } { + set gaussPointResults [write::GetResultsList Results OnElement] + if {[llength $gaussPointResults] > 0} { + if {[Dam::write::GetOutputGiDFlag]} { + W "Dam VTK output: Gauss-point results selected in 'On element' ([join $gaussPointResults {, }]) are not written to VTK. They remain available in the GiD output." + } else { + W "Dam VTK output: Gauss-point results selected in 'On element' ([join $gaussPointResults {, }]) are not written to VTK, and GiD output is disabled. No field output will be written for them." + } + } +} + # This process is used for checking if the user is interested on streamlines proc ::Dam::write::StremalinesUtility {} { diff --git a/kratos.gid/apps/Dam/xml/Results.spd b/kratos.gid/apps/Dam/xml/Results.spd index 160308066..c0ff3baf7 100644 --- a/kratos.gid/apps/Dam/xml/Results.spd +++ b/kratos.gid/apps/Dam/xml/Results.spd @@ -1,16 +1,18 @@ - + + + - - - - + + + + @@ -33,13 +35,19 @@ - + + + + + + + From 5757016608823451e224a238295102bb9cb965ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20Iraz=C3=A1bal=20Gonz=C3=A1lez?= Date: Tue, 27 Oct 2026 07:54:04 +0100 Subject: [PATCH 2/3] Refactor VTK output options and improve configuration validation in project settings --- .../apps/Dam/write/writeProjectParameters.tcl | 232 ++++++++++++++---- kratos.gid/apps/Dam/xml/Results.spd | 16 +- 2 files changed, 192 insertions(+), 56 deletions(-) diff --git a/kratos.gid/apps/Dam/write/writeProjectParameters.tcl b/kratos.gid/apps/Dam/write/writeProjectParameters.tcl index 5c1b2e1a0..878174b67 100644 --- a/kratos.gid/apps/Dam/write/writeProjectParameters.tcl +++ b/kratos.gid/apps/Dam/write/writeProjectParameters.tcl @@ -469,20 +469,31 @@ proc ::Dam::write::GetOutputDict { {appid ""} } { return $outputDict } +# Safely reads an option by unique name (and optional child name). Missing or +# empty nodes fall back to the supplied default, which keeps older projects +# working when newly added XML nodes are absent from the stored project tree. +proc ::Dam::write::GetOptionValue { uniqueName {default ""} {childName ""} } { + set value "" + if {$childName eq ""} { + catch {set value [write::getValue $uniqueName]} + } else { + catch {set value [write::getValue $uniqueName $childName]} + } + set value [string trim $value] + if {$value eq ""} {return $default} + return $value +} + # Returns whether the legacy GiD output must be written. Missing values (older # projects) fall back to the historical behavior: GiD output enabled. proc ::Dam::write::GetOutputGiDFlag { } { - set value [write::getValue Results OutputGiD] - if {$value eq ""} {return 1} - return [write::isBooleanTrue $value] + return [write::isBooleanTrue [Dam::write::GetOptionValue DamOutputGiD "Yes"]] } # Returns whether the standard VTK output process must be written. # Missing values (older projects) default to VTK output disabled. proc ::Dam::write::GetOutputVTKFlag { } { - set value [write::getValue Results OutputVTK] - if {$value eq ""} {return 0} - return [write::isBooleanTrue $value] + return [write::isBooleanTrue [Dam::write::GetOptionValue DamOutputVTK "No"]] } # Builds the standard VtkOutputProcess configuration. Only parameters accepted @@ -490,7 +501,7 @@ proc ::Dam::write::GetOutputVTKFlag { } { proc ::Dam::write::GetVTKOutputProcessDict { } { Dam::write::WarnAboutVTKGaussPointResults - Dam::write::WarnAboutVTKDelayedOutput + Dam::write::WarnAboutVTKScheduling set parametersDict [dict create] dict set parametersDict model_part_name [Dam::write::GetVTKModelPartName] @@ -518,13 +529,13 @@ proc ::Dam::write::GetVTKModelPartName { } { set rootModelPart [string trim [Dam::write::GetAttribute model_part_name]] if {$rootModelPart eq ""} {set rootModelPart "MainModelPart"} - set damTypeofProblem [write::getValue DamTypeofProblem] + set damTypeofProblem [Dam::write::GetOptionValue DamTypeofProblem "Mechanical"] if {$damTypeofProblem eq "Acoustic"} {return $rootModelPart} return "${rootModelPart}.mechanical_computing_domain" } proc ::Dam::write::GetVTKFileFormat { } { - set fileFormat [string trim [write::getValue DamVTKFileFormat]] + set fileFormat [string trim [Dam::write::GetOptionValue DamVTKFileFormat "binary"]] if {$fileFormat ni [list "binary" "ascii"]} { W "Dam VTK output: unknown file format '$fileFormat'. Using 'binary'." set fileFormat "binary" @@ -533,7 +544,7 @@ proc ::Dam::write::GetVTKFileFormat { } { } proc ::Dam::write::GetVTKOutputPrecision { } { - set precision [string trim [write::getValue DamVTKOutputPrecision]] + set precision [string trim [Dam::write::GetOptionValue DamVTKOutputPrecision "7"]] if {![string is integer -strict $precision] || $precision < 1} { W "Dam VTK output: invalid output precision '$precision'. Using 7." return 7 @@ -542,8 +553,7 @@ proc ::Dam::write::GetVTKOutputPrecision { } { } proc ::Dam::write::GetVTKWriteDeformedConfiguration { } { - set value [write::getValue DamVTKWriteDeformedConfiguration] - if {$value eq ""} {return true} + set value [Dam::write::GetOptionValue DamVTKWriteDeformedConfiguration "Yes"] if {[write::isBooleanTrue $value]} {return true} return false } @@ -551,24 +561,24 @@ proc ::Dam::write::GetVTKWriteDeformedConfiguration { } { # Converts the shared Dam output frequency to the seconds-based interval used # by the standard VtkOutputProcess ("output_control_type": "time"). proc ::Dam::write::GetVTKOutputIntervalInSeconds { } { - set outputCT [write::getValue Results OutputControlType] + set outputCT [Dam::write::GetOptionValue DamOutputControlType "time_d"] if {$outputCT eq "time_s"} { set factor 1.0 - set delta [write::getValue Results OutputDeltaTime_s] + set delta [Dam::write::GetOptionValue Results "1.0" OutputDeltaTime_s] } elseif {$outputCT eq "time_h"} { set factor 3600.0 - set delta [write::getValue Results OutputDeltaTime_h] + set delta [Dam::write::GetOptionValue Results "1.0" OutputDeltaTime_h] } elseif {$outputCT eq "time_d"} { set factor 86400.0 - set delta [write::getValue Results OutputDeltaTime_d] + set delta [Dam::write::GetOptionValue Results "1.0" OutputDeltaTime_d] } elseif {$outputCT eq "time_w"} { set factor 604800.0 - set delta [write::getValue Results OutputDeltaTime_w] + set delta [Dam::write::GetOptionValue Results "1.0" OutputDeltaTime_w] } else { W "Dam VTK output: unknown output control type '$outputCT'. Using seconds." set factor 1.0 - set delta [write::getValue Results OutputDeltaTime_s] + set delta [Dam::write::GetOptionValue Results "1.0" OutputDeltaTime_s] } if {![string is double -strict $delta] || $delta <= 0.0} { @@ -579,44 +589,162 @@ proc ::Dam::write::GetVTKOutputIntervalInSeconds { } { return [expr {double($delta) * $factor}] } -# Returns a dedicated relative output folder, rejecting paths that could make -# the standard VtkOutputProcess delete unrelated contents. -proc ::Dam::write::GetVTKOutputPath { } { - set outputPath [string trim [write::getValue DamVTKOutputPath]] - if {$outputPath eq ""} {set outputPath "VTK_Output"} - - if {[Dam::write::IsUnsafeVTKOutputPath $outputPath]} { - W "Dam VTK output: output directory '$outputPath' is not a safe dedicated relative folder. Using 'VTK_Output' instead." - return "VTK_Output" +# Returns the resolved GiD project directory, which is the working directory +# used by the generated launch configuration. Validation is therefore done +# against that directory. If a user launches Kratos manually from a different +# directory, relative output paths resolve elsewhere and this check cannot +# guarantee containment. +proc ::Dam::write::GetVTKOutputBaseDir { } { + set baseDir "" + catch {set baseDir [write::GetConfigurationAttribute dir]} + if {$baseDir eq ""} {catch {set baseDir [pwd]}} + if {$baseDir eq "" || ![file isdirectory $baseDir]} {return ""} + + # file normalize does not resolve the final path component when it is a + # symbolic link. Normalizing a child and taking its dirname does. + if {[catch { + set resolvedBase [file dirname [file normalize [file join $baseDir "__dam_vtk_output_probe__"]]] + }]} { + return "" } - return $outputPath + return $resolvedBase } -proc ::Dam::write::IsUnsafeVTKOutputPath { outputPath } { +# Returns the normalized relative components of a VTK output path, or an empty +# list for absolute, home-relative, Windows drive/UNC, or parent-traversal paths. +proc ::Dam::write::GetVTKOutputComponents { outputPath } { set path [string trim $outputPath] - if {$path eq ""} {return 1} + if {$path eq ""} {return [list]} # Absolute Unix paths, home-relative paths, Windows drives and UNC paths. - if {[string index $path 0] eq "/" || [string index $path 0] eq "~"} {return 1} - if {[regexp {^[A-Za-z]:} $path] || [regexp {^\\\\} $path]} {return 1} + if {[string index $path 0] eq "/" || [string index $path 0] eq "~"} {return [list]} + if {[regexp {^[A-Za-z]:} $path] || [regexp {^\\\\} $path]} {return [list]} # Normalize separators so parent traversal is detected on any platform. + # Windows strips trailing spaces and trailing dots, so treat "." as a + # current-directory alias and reject any other all-dot/all-space component. set components [list] foreach component [split [string map {"\\" "/"} $path] "/"] { - if {$component eq ".."} {return 1} - if {$component ne "" && $component ne "."} {lappend components $component} + if {$component eq ""} {continue} + if {[regexp {^[. ]+$} $component]} { + if {$component eq "."} {continue} + return [list] + } + if {[regexp {^[A-Za-z]:} [string trimright $component ". "]]} {return [list]} + lappend components $component } + return $components +} + +proc ::Dam::write::PathsEqual { pathA pathB } { + if {$::tcl_platform(platform) eq "windows"} { + return [expr {[string tolower $pathA] eq [string tolower $pathB]}] + } + return [expr {$pathA eq $pathB}] +} + +proc ::Dam::write::IsPathInside { path parent } { + if {[catch { + set pathParts [file split [file normalize $path]] + set parentParts [file split [file normalize $parent]] + }]} { + return 0 + } + if {[llength $pathParts] <= [llength $parentParts]} {return 0} + + set pathPrefix [join [lrange $pathParts 0 [expr {[llength $parentParts]-1}]] "/"] + set parentPath [join $parentParts "/"] + return [Dam::write::PathsEqual $pathPrefix $parentPath] +} + +proc ::Dam::write::IsUnsafeVTKOutputPath { outputPath } { + set raw [string trim $outputPath] + if {$raw eq ""} {return 1} - # Reject the working-directory root and equivalent path aliases. + set components [Dam::write::GetVTKOutputComponents $raw] if {[llength $components] == 0} {return 1} - # Do not delete folders owned by other interface features. - set effectivePath [string tolower [join $components "/"]] - if {[lsearch -exact [list "monitoringdevices"] $effectivePath] >= 0} {return 1} + set baseDir [Dam::write::GetVTKOutputBaseDir] + if {$baseDir eq ""} {return 1} + + # Windows strips trailing dots and spaces, so account for them when + # comparing against reserved interface-owned folders. Reject the folder + # itself and anything below it. + set normalizedComponents [list] + foreach component $components { + lappend normalizedComponents [string trimright $component ". "] + } + set effectivePath [string tolower [join $normalizedComponents "/"]] + if {$effectivePath eq "monitoringdevices" || + [string first "monitoringdevices/" $effectivePath] == 0} { + return 1 + } + + # Reject symbolic-link components. Tcl reports broken links as "link" too. + # Windows junctions/reparse points are not always reported as links, so + # full containment cannot be guaranteed on every platform. + set nextPath $baseDir + foreach component $components { + set nextPath [file join $nextPath $component] + if {![catch {set nodeType [file type $nextPath]}] && $nodeType eq "link"} {return 1} + } + + # Resolve the final path and require strict containment in the project dir. + if {[catch { + set resolvedPath [file normalize [file join $baseDir {*}$components]] + }]} { + return 1 + } + if {![Dam::write::IsPathInside $resolvedPath $baseDir]} {return 1} + + # A symlink may resolve a differently named path into the reserved folder. + set reservedPath [file normalize [file join $baseDir "MonitoringDevices"]] + if {[Dam::write::PathsEqual $resolvedPath $reservedPath] || + [Dam::write::IsPathInside $resolvedPath $reservedPath]} { + return 1 + } return 0 } +# Returns a dedicated relative output folder, rejecting paths that could make +# the standard VtkOutputProcess delete unrelated contents. +proc ::Dam::write::GetVTKOutputPath { } { + set outputPath [string trim [Dam::write::GetOptionValue DamVTKOutputPath "VTK_Output"]] + if {$outputPath eq ""} {set outputPath "VTK_Output"} + + if {[Dam::write::IsUnsafeVTKOutputPath $outputPath]} { + set rawComponents [Dam::write::GetVTKOutputComponents $outputPath] + set cleanedPath "" + if {[llength $rawComponents] > 0} { + set cleanedPath [file join {*}$rawComponents] + } + + if {$cleanedPath eq "VTK_Output"} { + W "Dam VTK output: output directory '$outputPath' is not a safe dedicated relative folder (absolute paths, parent traversal, symbolic links, reserved folders and paths outside the project directory are not allowed). The default 'VTK_Output' also failed validation; review or remove that folder before running." + } else { + W "Dam VTK output: output directory '$outputPath' is not a safe dedicated relative folder (absolute paths, parent traversal, symbolic links, reserved folders and paths outside the project directory are not allowed). Using 'VTK_Output' instead." + } + # Do not re-run the check on the fallback. A final symlink named + # VTK_Output is refused by the standard process' rmtree; Windows + # junctions remain a residual platform risk. + return "VTK_Output" + } + + return [file join {*}[Dam::write::GetVTKOutputComponents $outputPath]] +} + +# Returns a short note explaining whether omitted results remain available +# through the legacy GiD output. +proc ::Dam::write::GetVTKGidAvailabilityNote { {plural 0} } { + if {[Dam::write::GetOutputGiDFlag]} { + if {$plural} {return "These results remain available in the GiD output."} + return "This result remains available in the GiD output." + } + if {$plural} {return "GiD output is disabled, so these results will not be written."} + return "GiD output is disabled, so this result will not be written." +} + # Reuses the existing GiD nodal result selection, keeping only variables that # are safe for the standard VTK writer. proc ::Dam::write::GetVTKNodalResultsList { } { @@ -625,32 +753,40 @@ proc ::Dam::write::GetVTKNodalResultsList { } { NODAL_REFERENCE_TEMPERATURE HEAT_FLUX FACE_HEAT_FLUX VOLUME_ACCELERATION \ POSITIVE_FACE_PRESSURE NODAL_JOINT_WIDTH Vi_POSITIVE Viii_POSITIVE] + set gidNote [Dam::write::GetVTKGidAvailabilityNote 0] set vtkResults [list] foreach result [write::GetResultsList Results OnNodes] { if {[lsearch -exact $supportedVariables $result] >= 0} { lappend vtkResults $result } else { - W "Dam VTK output: result '$result' is not available for VTK output (unsupported variable type or not stored as a nodal solution-step variable) and will be omitted from the VTK file." + W "Dam VTK output: nodal result '$result' is not available for VTK output and will be omitted. $gidNote" } } return $vtkResults } -proc ::Dam::write::WarnAboutVTKDelayedOutput { } { - set startOutput [write::getValue Results StartOutputResults] - if {$startOutput ne "" && [string is double -strict $startOutput] && $startOutput > 0.0} { - W "Dam VTK output: 'Start output results' is not supported by the standard VtkOutputProcess. VTK output will start at the first output interval boundary from time 0." +# Warnings comparing GiD and VTK schedules are only relevant when both formats +# are enabled. General VTK scheduling behavior is documented in the VTK options. +proc ::Dam::write::WarnAboutVTKScheduling { } { + if {![Dam::write::GetOutputGiDFlag]} {return} + + set startOutput [Dam::write::GetOptionValue DamStartOutputResults "0"] + if {[string is double -strict $startOutput] && $startOutput > 0.0} { + W "Dam VTK output: GiD has a delayed output start ('Start output results' = $startOutput), which the standard VTK process does not support. VTK frames follow the standard Kratos time controller and may differ from GiD frames." + return + } + + set startTime [Dam::write::GetOptionValue DamTimeParameters "0" StartTime] + if {$startTime ne "" && [string is double -strict $startTime] && $startTime > 0.0} { + W "Dam VTK output: the simulation starts at a nonzero time. VTK frames follow the standard Kratos time controller (absolute output interval boundaries, no initial frame), so they may differ from GiD frames." } } proc ::Dam::write::WarnAboutVTKGaussPointResults { } { set gaussPointResults [write::GetResultsList Results OnElement] if {[llength $gaussPointResults] > 0} { - if {[Dam::write::GetOutputGiDFlag]} { - W "Dam VTK output: Gauss-point results selected in 'On element' ([join $gaussPointResults {, }]) are not written to VTK. They remain available in the GiD output." - } else { - W "Dam VTK output: Gauss-point results selected in 'On element' ([join $gaussPointResults {, }]) are not written to VTK, and GiD output is disabled. No field output will be written for them." - } + set gidNote [Dam::write::GetVTKGidAvailabilityNote 1] + W "Dam VTK output: Gauss-point results selected in 'On element' ([join $gaussPointResults {, }]) are not available for VTK output and will be omitted. $gidNote" } } diff --git a/kratos.gid/apps/Dam/xml/Results.spd b/kratos.gid/apps/Dam/xml/Results.spd index c0ff3baf7..59ea0c32f 100644 --- a/kratos.gid/apps/Dam/xml/Results.spd +++ b/kratos.gid/apps/Dam/xml/Results.spd @@ -9,11 +9,11 @@ - - - - - + + + + + @@ -35,16 +35,16 @@ - + - + - + From bae183fcfb6be0d34a113c333de6b0cd6e95d741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20Iraz=C3=A1bal=20Gonz=C3=A1lez?= Date: Tue, 27 Oct 2026 08:12:16 +0100 Subject: [PATCH 3/3] Improve VTK output path validation and error handling in writeProjectParameters.tcl --- .../apps/Dam/write/writeProjectParameters.tcl | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/kratos.gid/apps/Dam/write/writeProjectParameters.tcl b/kratos.gid/apps/Dam/write/writeProjectParameters.tcl index 878174b67..630721b3f 100644 --- a/kratos.gid/apps/Dam/write/writeProjectParameters.tcl +++ b/kratos.gid/apps/Dam/write/writeProjectParameters.tcl @@ -714,20 +714,18 @@ proc ::Dam::write::GetVTKOutputPath { } { if {$outputPath eq ""} {set outputPath "VTK_Output"} if {[Dam::write::IsUnsafeVTKOutputPath $outputPath]} { - set rawComponents [Dam::write::GetVTKOutputComponents $outputPath] - set cleanedPath "" - if {[llength $rawComponents] > 0} { - set cleanedPath [file join {*}$rawComponents] - } - - if {$cleanedPath eq "VTK_Output"} { - W "Dam VTK output: output directory '$outputPath' is not a safe dedicated relative folder (absolute paths, parent traversal, symbolic links, reserved folders and paths outside the project directory are not allowed). The default 'VTK_Output' also failed validation; review or remove that folder before running." - } else { - W "Dam VTK output: output directory '$outputPath' is not a safe dedicated relative folder (absolute paths, parent traversal, symbolic links, reserved folders and paths outside the project directory are not allowed). Using 'VTK_Output' instead." + if {[Dam::write::IsUnsafeVTKOutputPath "VTK_Output"]} { + set rawComponents [Dam::write::GetVTKOutputComponents $outputPath] + set cleanedPath "" + if {[llength $rawComponents] > 0} { + set cleanedPath [file join {*}$rawComponents] + } + if {$cleanedPath eq "VTK_Output"} { + error "Dam VTK output: the output directory 'VTK_Output' is unsafe (for example, a symbolic link, a reserved folder, or a path outside the project directory). Remove or rename it, or configure a different safe relative output directory." + } + error "Dam VTK output: the configured output directory '$outputPath' is unsafe and the fallback directory 'VTK_Output' is also unsafe. Remove or rename the unsafe VTK_Output entry, or configure a different safe relative output directory." } - # Do not re-run the check on the fallback. A final symlink named - # VTK_Output is refused by the standard process' rmtree; Windows - # junctions remain a residual platform risk. + W "Dam VTK output: output directory '$outputPath' is not a safe dedicated relative folder (absolute paths, parent traversal, symbolic links, reserved folders and paths outside the project directory are not allowed). Using 'VTK_Output' instead." return "VTK_Output" }