diff --git a/applications/utilities/createScanPath/createFields.H b/applications/utilities/createScanPath/createFields.H index 8e63b77a..2cbab3ba 100644 --- a/applications/utilities/createScanPath/createFields.H +++ b/applications/utilities/createScanPath/createFields.H @@ -43,6 +43,8 @@ namespace Foam Struct Point Definition \*---------------------------------------------------------------------------*/ +const scalar tolerance = 1e-10; + struct Point { scalar x; @@ -171,8 +173,10 @@ struct BoundBox // Function to check if a point is inside the bounding box bool isInside( Point p ) { - return p.x >= minPoint.x && p.x <= maxPoint.x && p.y >= minPoint.y && - p.y <= maxPoint.y; + return p.x >= minPoint.x - tolerance && + p.x <= maxPoint.x + tolerance && + p.y >= minPoint.y - tolerance && + p.y <= maxPoint.y + tolerance; } Line cropLine( const Line& line ) @@ -231,7 +235,7 @@ struct BoundBox ( x1 - x2 ) * ( y3 - y4 ) - ( y1 - y2 ) * ( x3 - x4 ); // Lines are parallel or colinear, no intersection - if ( denominator == 0 ) + if ( std::abs(denominator) < tolerance ) { return intersection; } @@ -242,7 +246,11 @@ struct BoundBox scalar u = -( ( x1 - x2 ) * ( y1 - y3 ) - ( y1 - y2 ) * ( x1 - x3 ) ) / denominator; - if ( t >= 0 && t <= 1 && u >= 0 && u <= 1 ) + if + ( + ( t >= -tolerance && t <= 1.0 + tolerance ) + && ( u >= -tolerance && u <= 1.0 + tolerance ) + ) { intersection.x = x1 + t * ( x2 - x1 ); intersection.y = y1 + t * ( y2 - y1 ); @@ -342,6 +350,9 @@ struct Path { std::ofstream file( filename ); + int precision = static_cast(std::ceil(-std::log10(tolerance))); + file << std::fixed << std::setprecision(precision); + file << "Mode\tX(m)\tY(m)\tZ(m)\tPower(W)\ttParam" << std::endl; for ( size_t i = 0; i < lines.size(); ++i ) diff --git a/applications/utilities/multiLayer/runLayers b/applications/utilities/multiLayer/runLayers index 17552dd5..215772e9 100755 --- a/applications/utilities/multiLayer/runLayers +++ b/applications/utilities/multiLayer/runLayers @@ -88,22 +88,49 @@ done args_check $nLayers $layerThickness $nCellsPerLayer -# create case directories + +# 1. Find available scan path files +scanPathFiles=(constant/scanPath_*) + +# Check if the globbing found any actual files. +if [ -e "${scanPathFiles[0]}" ]; then + numScanPathFiles=${#scanPathFiles[@]} + echo "Found $numScanPathFiles numbered scanPath file(s) to cycle through." + +elif [ -f "constant/scanPath" ]; then + scanPathFiles=("constant/scanPath") + numScanPathFiles=1 + echo "Found single 'scanPath' file. This will be used for all layers." + +else + echo "Error: No 'scanPath_*' files or 'scanPath' file found." >&2 + exit 1 +fi + +# 2. Create case directories +shopt -s extglob baseDir=${PWD} caseList=() for (( layer=0; layer<$nLayers; layer++ )) do case="$baseDir/layer$layer" - caseList+=($case) - if [ -d $case ]; then rm -rf $case; fi - mkdir $case + caseList+=("$case") + if [ -d "$case" ]; then rm -rf "$case"; fi + mkdir -p "$case/constant" "$case/system" + + cp -r "$baseDir/0" "$case/" + cp -r "$baseDir/system"/* "$case/system/" + + cp -r "$baseDir/constant"/!(scanPath|scanPath_*) "$case/constant/" + scanPathIndex=$(( layer % numScanPathFiles )) + sourceScanPathFile=${scanPathFiles[$scanPathIndex]} - cp -r "$baseDir/0" $case - cp -r "$baseDir/constant" $case - cp -r "$baseDir/system" $case + echo "Layer $layer: using $sourceScanPathFile" + cp "$sourceScanPathFile" "$case/constant/scanPath" done +shopt -u extglob -# extrude mesh in each directory +# 3. Extrude mesh in case directories for (( layer=0; layer<$nLayers; layer++ )) do case=${caseList[$layer]} @@ -122,7 +149,7 @@ do fi done -# update simulation times and run layers sequentially +# 4. Run all layers layerTime="$(cd ${caseList[0]} && foamDictionary -entry endTime -value system/controlDict)" for (( layer=0; layer<$nLayers; layer++ )) @@ -142,7 +169,7 @@ do foamDictionary -entry startTime -set $time system/controlDict foamDictionary -entry endTime -set $endTime system/controlDict - # update wait time for scan path (assumes repeating scan) + # update wait time for scan path path=(`sed '2q;d' constant/scanPath`) path[5]=$time path=`echo $(echo ${path[@]}) | tr ' ' '\t\t'` diff --git a/tutorials/multiLayerPBF/0/T b/tutorials/multiLayerPBF/0/T index a3a1dc2a..e0f2489c 100644 --- a/tutorials/multiLayerPBF/0/T +++ b/tutorials/multiLayerPBF/0/T @@ -22,7 +22,7 @@ boundaryField { bottom { - type zeroGradient; + type fixedValue; value uniform 300; } top @@ -35,7 +35,7 @@ boundaryField } sides { - type zeroGradient; + type fixedValue; value uniform 300; } } diff --git a/tutorials/multiLayerPBF/Allclean b/tutorials/multiLayerPBF/Allclean index 98bbd51f..102cc751 100755 --- a/tutorials/multiLayerPBF/Allclean +++ b/tutorials/multiLayerPBF/Allclean @@ -7,6 +7,8 @@ cd ${0%/*} || exit 1 # Run from this directory cleanCase rm -rf layer* +rm -rf constant/scanPath_* + #------------------------------------------------------------------------------ rm -rf ExaCA/Output* rm -rf ExaCA/time-temperature.csv diff --git a/tutorials/multiLayerPBF/Allrun b/tutorials/multiLayerPBF/Allrun index 1503c12c..e962c986 100755 --- a/tutorials/multiLayerPBF/Allrun +++ b/tutorials/multiLayerPBF/Allrun @@ -26,10 +26,14 @@ fi # AdditiveFOAM runApplication blockMesh -# Change to AdditiveFOAM install path -path="$WM_PROJECT_INST_DIR/AdditiveFOAM/applications/utilities/multiLayer" +# Set $ADDITIVEFOAM_INST_DIR path: defaults to $WM_PROJECT_INST_DIR. +projectDir="${ADDITIVEFOAM_INST_DIR:-$WM_PROJECT_INST_DIR/AdditiveFOAM}" +path="$projectDir/applications/utilities/multiLayer" -$path/runLayers -nLayers 4 -nCellsPerLayer 4 -layerThickness 40e-6 +# Create scan paths from constant/createScanPathDict +createScanPath + +$path/runLayers -nLayers 2 -nCellsPerLayer 4 -layerThickness 40e-6 $path/reconstructLayers #------------------------------------------------------------------------------ diff --git a/tutorials/multiLayerPBF/constant/createScanPathDict b/tutorials/multiLayerPBF/constant/createScanPathDict new file mode 100644 index 00000000..8d14853a --- /dev/null +++ b/tutorials/multiLayerPBF/constant/createScanPathDict @@ -0,0 +1,36 @@ +/*--------------------------------*- C++ -*----------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | Website: https://openfoam.org + \\ / A nd | Version: 10 + \\/ M anipulation | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object createScanPathDict; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +minPoint (0.0 -1e-4); + +maxPoint (0.002 1e-4); + +angle 180; + +hatch 1e-4; + +nRotations 2; + +power 195; + +speed 0.8; + +dwellTime 5e-4; + +biDirection true; + +// ************************************************************************* // diff --git a/tutorials/multiLayerPBF/constant/heatSourceDict b/tutorials/multiLayerPBF/constant/heatSourceDict index 0c24aa03..24fa4770 100644 --- a/tutorials/multiLayerPBF/constant/heatSourceDict +++ b/tutorials/multiLayerPBF/constant/heatSourceDict @@ -14,15 +14,15 @@ FoamFile } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -sources (beam); - /*---------------------------------------------------------------------------*\ Citation: J. Coleman, G.L. Knapp, B. Stump, M. Rolchigo, K. Kincaid, A. Plotkowski, A dynamic volumetric heat source model for laser additive manufacturing, Additive Manufacturing (2024), https://doi.org/10.1016/j.addma.2024.104531. \*---------------------------------------------------------------------------*/ + +sources (beam); + beam { pathName scanPath; diff --git a/tutorials/multiLayerPBF/constant/scanPath b/tutorials/multiLayerPBF/constant/scanPath deleted file mode 100644 index 5fe3a9fb..00000000 --- a/tutorials/multiLayerPBF/constant/scanPath +++ /dev/null @@ -1,3 +0,0 @@ -Mode X Y Z Power Param -1 0.000 0.000 0 0 0 -0 0.002 0.000 0 195.0 0.8 diff --git a/tutorials/multiLayerPBF/system/controlDict b/tutorials/multiLayerPBF/system/controlDict index 7a3443c1..fe49c27e 100644 --- a/tutorials/multiLayerPBF/system/controlDict +++ b/tutorials/multiLayerPBF/system/controlDict @@ -23,13 +23,13 @@ startTime 0; stopAt endTime; -endTime 0.004; +endTime 0.015; deltaT 1e-07; writeControl adjustableRunTime; -writeInterval 0.001; +writeInterval 0.0025; purgeWrite 0; @@ -49,13 +49,12 @@ adjustTimeStep yes; maxCo 0.5; -maxDi 10; +maxDi 100; maxAlphaCo 1; functions { - #includeFunc ExaCA } diff --git a/tutorials/multiLayerPBF/system/fvSolution b/tutorials/multiLayerPBF/system/fvSolution index fa0ff1dd..f26a9ed0 100644 --- a/tutorials/multiLayerPBF/system/fvSolution +++ b/tutorials/multiLayerPBF/system/fvSolution @@ -54,6 +54,7 @@ PIMPLE nThermoCorrectors 20; thermoTolerance 1e-8; explicitSolve true; + Tmax 3300.0; } relaxationFactors