@@ -37,14 +37,14 @@ SIMoutput::SIMoutput (IntegrandBase* itg) : SIMinput(itg)
3737 myPtSize = 0.0 ;
3838 myGeomID = myGeofs1 = myGeofs2 = 0 ;
3939 myVtf = nullptr ;
40- logRpMap = false;
40+ mergeVtf = logRpMap = false;
4141 idxGrid = -1 ;
4242}
4343
4444
4545SIMoutput ::~SIMoutput ()
4646{
47- if ( myVtf ) delete myVtf ;
47+ delete myVtf ;
4848
4949 for (std ::pair < const std ::string ,RealFunc * > & func : myAddScalars )
5050 delete func .second ;
@@ -106,6 +106,7 @@ bool SIMoutput::parseOutputTag (const tinyxml2::XMLElement* elem)
106106{
107107 IFEM ::cout <<" Parsing <" << elem -> Value () <<">" << std ::endl ;
108108
109+ bool newGroup = false;
109110 if (const char * funcval = utl ::getValue (elem ,"function" ); funcval )
110111 {
111112 std ::string name ;
@@ -122,10 +123,14 @@ bool SIMoutput::parseOutputTag (const tinyxml2::XMLElement* elem)
122123 myAddScalars [name ] = f ;
123124 return true;
124125 }
125- else if (strcasecmp (elem -> Value (),"resultpoints" ))
126+ else if (!strcasecmp (elem -> Value (),"resultpoints" ))
127+ newGroup = true; // we are parsing result points, below
128+ else if (!strcasecmp (elem -> Value (),"vtfformat" ))
129+ utl ::getAttribute (elem ,"merge" ,mergeVtf );
130+
131+ if (!newGroup )
126132 return this -> SIMinput ::parseOutputTag (elem );
127133
128- bool newGroup = true;
129134 // Lambda function for adding a new result point to the myPoints container.
130135 auto&& addPoint = [& newGroup ,& points = myPoints ](const ResultPoint & newPoint )
131136 {
@@ -711,12 +716,18 @@ bool SIMoutput::writeGlvG (int& nBlock, double time)
711716 // Get the ID list of current node blocks, if any
712717 IntVec nodeBlocks ;
713718 int i , nodeBlock ;
719+ size_t nNodeLast = 0 ;
714720 if (time > 0.0 )
721+ {
715722 for (i = 1 ; (nodeBlock = myVtf -> getNodeBlock (i )); i ++ )
716723 nodeBlocks .push_back (nodeBlock );
724+ if (mergeVtf ) // Get the size of the last node block written
725+ nNodeLast = myVtf -> getBlock (i - 1 )-> getNoNodes ();
726+ }
717727 if (time >= 0.0 )
718728 myVtf -> clearGeometryBlocks ();
719729
730+ ElementBlock * singlePart = nullptr ;
720731 ElementBlock * lvb ;
721732 char pname [64 ];
722733
@@ -737,14 +748,40 @@ bool SIMoutput::writeGlvG (int& nBlock, double time)
737748 if (!pch -> isElementActive (iel - 1 ,time ))
738749 lvb -> removeElement (iel );
739750
751+ if (mergeVtf && myModel .size () > 1 )
752+ {
753+ // Merge all element blocks into a single part
754+ if (!singlePart )
755+ singlePart = lvb ;
756+ else
757+ {
758+ singlePart -> merge (* lvb ,false);
759+ delete lvb ;
760+ }
761+ }
762+ else
763+ {
764+ if (msgLevel > 1 )
765+ IFEM ::cout <<"Writing geometry for patch "
766+ << pch -> idx + 1 <<" (" << lvb -> getNoNodes () <<")" << std ::endl ;
767+
768+ sprintf (pname ,"Patch %zu" ,pch -> idx + 1 );
769+ // Reuse the existing node block when time > 0.0
770+ nodeBlock = i < static_cast < int > (nodeBlocks .size ()) ? nodeBlocks [i ++ ] : 0 ;
771+ if (!myVtf -> writeGrid (lvb ,pname ,++ nBlock ,nodeBlock ))
772+ return false;
773+ }
774+ }
775+
776+ if (singlePart )
777+ {
740778 if (msgLevel > 1 )
741- IFEM ::cout <<"Writing geometry for patch "
742- << pch -> idx + 1 << " (" << lvb -> getNoNodes () <<")" << std ::endl ;
779+ IFEM ::cout <<"Writing new geometry ( "
780+ << singlePart -> getNoNodes () <<")" << std ::endl ;
743781
744- sprintf (pname ,"Patch %zu" ,pch -> idx + 1 );
745- // Reuse the existing node block when time > 0.0
746- nodeBlock = i < static_cast < int > (nodeBlocks .size ()) ? nodeBlocks [i ++ ] : 0 ;
747- if (!myVtf -> writeGrid (lvb ,pname ,++ nBlock ,nodeBlock ))
782+ // Reuse the last node block when time > 0.0 unless increased size
783+ nodeBlock = singlePart -> getNoNodes () > nNodeLast ? 0 : nodeBlocks .back ();
784+ if (!myVtf -> writeGrid (singlePart ,"FE model" ,++ nBlock ,nodeBlock ))
748785 return false;
749786 }
750787
@@ -795,6 +832,8 @@ bool SIMoutput::writeGlvBC (int& nBlock, int iStep) const
795832{
796833 if (!myVtf )
797834 return true;
835+ if (mergeVtf && myModel .size () > 1 )
836+ return true; // not implemented for merged patches, ignore
798837
799838 Matrix field ;
800839 std ::array < IntVec ,6 > dID ;
@@ -933,6 +972,8 @@ bool SIMoutput::writeGlvV (const RealArray& vec, const char* fieldName,
933972{
934973 if (vec .empty () || !myVtf )
935974 return true;
975+ if (mergeVtf && myModel .size () > 1 )
976+ return true; // not implemented for merged patches, ignore
936977
937978 Matrix field ;
938979 Vector lovec ;
@@ -973,6 +1014,8 @@ bool SIMoutput::writeGlvS (const Vector& scl, const char* fieldName,
9731014{
9741015 if (scl .empty () || !myVtf )
9751016 return true;
1017+ if (mergeVtf && myModel .size () > 1 )
1018+ return false; // not implemented for merged patches, abort..
9761019
9771020 const bool piolaMapping = myProblem ?
9781021 myProblem -> getIntegrandType () & Integrand ::PIOLA_MAPPING : false;
@@ -1086,6 +1129,14 @@ int SIMoutput::writeGlvS1 (const Vector& psol, int iStep, int& nBlock,
10861129 if (myVtf -> getBlock (geo ))
10871130 vID [0 ].push_back (dis );
10881131
1132+ // Find the last active patch at current time
1133+ size_t lastActive = 0 ;
1134+ if (mergeVtf )
1135+ for (const ASMbase * pch : myModel )
1136+ if (!pch -> empty () && !pch -> inActive (time ))
1137+ lastActive = pch -> idx ;
1138+
1139+ Matrix singleField ;
10891140 Matrix field ;
10901141 Vector lovec ;
10911142
@@ -1109,6 +1160,19 @@ int SIMoutput::writeGlvS1 (const Vector& psol, int iStep, int& nBlock,
11091160 if (!pch -> evalSolution (field ,lovec ,opt .nViz ,0 ,piolaMapping ))
11101161 return -1 ;
11111162
1163+ if (lastActive > 0 )
1164+ {
1165+ // We need to merge the results for all patches before writing them
1166+ if (singleField .empty ())
1167+ std ::swap (singleField ,field );
1168+ else
1169+ singleField .augmentCols (field );
1170+ if (lastActive == pch -> idx )
1171+ std ::swap (field ,singleField );
1172+ else
1173+ continue ;
1174+ }
1175+
11121176 const ElementBlock * grid = myVtf -> getBlock (++ geomID );
11131177 pch -> filterResults (field ,grid );
11141178
@@ -1280,6 +1344,14 @@ int SIMoutput::writeGlvS2 (const Vector& psol, int iStep, int& nBlock,
12801344 std ::vector < IntVec > sID ;
12811345 sID .reserve ((haveAsol ? 2 * nf : nf ) + nProj );
12821346
1347+ // Find the last active patch at current time
1348+ size_t lastActive = 0 ;
1349+ if (mergeVtf )
1350+ for (const ASMbase * pch : myModel )
1351+ if (!pch -> empty () && !pch -> inActive (time ))
1352+ lastActive = pch -> idx ;
1353+
1354+ Matrix singleField , projField ;
12831355 Matrix field , pdir ;
12841356 Vector lovec ;
12851357
@@ -1294,7 +1366,7 @@ int SIMoutput::writeGlvS2 (const Vector& psol, int iStep, int& nBlock,
12941366 else if (pch -> empty () || pch -> inActive (time ))
12951367 continue ; // skip empty and inactive patches
12961368
1297- myProblem -> initResultPoints (time ,true ); // include principal stresses
1369+ myProblem -> initResultPoints (time ,! lastActive ); // include principal stresses
12981370 if (!this -> initPatchForEvaluation (pch -> idx + 1 ))
12991371 return -2 ;
13001372
@@ -1307,12 +1379,29 @@ int SIMoutput::writeGlvS2 (const Vector& psol, int iStep, int& nBlock,
13071379 if (!pch -> evalSolution (field ,* myProblem ,opt .nViz ))
13081380 return -1 ;
13091381
1310- const ElementBlock * grid = myVtf -> getBlock (++ geomID );
1311- pch -> filterResults (field ,grid );
1312-
13131382 size_t k = 0 ;
1314- if (!this -> writeScalarFields (field ,geomID ,nBlock ,sID ,& k ,ASM ::SECONDARY ))
1315- return -4 ;
1383+ bool writeNow = true;
1384+ if (lastActive > 0 )
1385+ {
1386+ // We need to merge the results for all patches before writing them
1387+ if (singleField .empty ())
1388+ std ::swap (singleField ,field );
1389+ else
1390+ singleField .augmentCols (field );
1391+ if (lastActive == pch -> idx )
1392+ std ::swap (field ,singleField );
1393+ else
1394+ writeNow = false;
1395+ }
1396+
1397+ const ElementBlock * grid = writeNow ? myVtf -> getBlock (++ geomID ) : nullptr ;
1398+
1399+ if (writeNow )
1400+ {
1401+ pch -> filterResults (field ,grid );
1402+ if (!this -> writeScalarFields (field ,geomID ,nBlock ,sID ,& k ,ASM ::SECONDARY ))
1403+ return -4 ;
1404+ }
13161405
13171406 // Write principal directions, if any, as vector fields
13181407
@@ -1334,9 +1423,23 @@ int SIMoutput::writeGlvS2 (const Vector& psol, int iStep, int& nBlock,
13341423 if (!pch -> evalSolution (field ,* myProblem ,opt .nViz ,'D' ))
13351424 return -1 ;
13361425
1337- pch -> filterResults (field ,grid );
1338- if (!this -> writeScalarFields (field ,geomID ,nBlock ,sID ,& k ,ASM ::PROJECTED ))
1339- return -4 ;
1426+ if (lastActive > 0 )
1427+ {
1428+ // We need to merge the results for all patches before writing them
1429+ if (projField .empty ())
1430+ std ::swap (projField ,field );
1431+ else
1432+ projField .augmentCols (field );
1433+ if (lastActive == pch -> idx )
1434+ std ::swap (field ,projField );
1435+ }
1436+
1437+ if (writeNow )
1438+ {
1439+ pch -> filterResults (field ,grid );
1440+ if (!this -> writeScalarFields (field ,geomID ,nBlock ,sID ,& k ,ASM ::PROJECTED ))
1441+ return -4 ;
1442+ }
13401443 }
13411444
13421445 if (haveAsol && grid )
@@ -1445,6 +1548,8 @@ bool SIMoutput::writeGlvP (const RealArray& ssol, int iStep, int& nBlock,
14451548{
14461549 if (ssol .empty () || !myVtf )
14471550 return true ; // no projected solution
1551+ if (mergeVtf && myModel .size () > 1 )
1552+ return true ; // not implemented for merged patches, ignore
14481553
14491554 // Lambda function for updating (patch-wise) maximum result values.
14501555 auto && updateMaxVal = [](PointValues & maxVal , double res ,
@@ -1547,6 +1652,8 @@ bool SIMoutput::writeGlvF (const RealFunc& f, const char* fname,
15471652{
15481653 if (!myVtf )
15491654 return true;
1655+ if (mergeVtf && myModel .size () > 1 )
1656+ return true; // not implemented for merged patches, ignore
15501657
15511658 const bool piolaMapping = state && myProblem ?
15521659 myProblem -> getIntegrandType () & Integrand ::PIOLA_MAPPING : false;
@@ -1607,6 +1714,8 @@ bool SIMoutput::writeGlvM (const Mode& mode, bool freq, int& nBlock)
16071714{
16081715 if (mode .eigVec .empty () || !myVtf )
16091716 return true; // no eigen modes
1717+ if (mergeVtf && myModel .size () > 1 )
1718+ return true; // not implemented for merged patches, ignore
16101719
16111720 if (msgLevel > 1 )
16121721 IFEM ::cout <<"Writing eigenvector for Mode " << mode .eigNo << std ::endl ;
@@ -1683,6 +1792,8 @@ bool SIMoutput::writeGlvN (const Matrix& norms, int iStep, int& nBlock,
16831792{
16841793 if (norms .empty () || !myVtf )
16851794 return true; // no element norms
1795+ if (mergeVtf && myModel .size () > 1 )
1796+ return true; // not implemented for merged patches, ignore
16861797
16871798 NormBase * norm = myProblem -> getNormIntegrand (mySol );
16881799
@@ -1781,6 +1892,8 @@ bool SIMoutput::writeGlvE (const Vector& field, int iStep, int& nBlock,
17811892{
17821893 if (!myVtf )
17831894 return true;
1895+ if (mergeVtf && myModel .size () > 1 )
1896+ return true; // not implemented for merged patches, ignore
17841897
17851898 Vector lVec ;
17861899 IntVec sID ;
0 commit comments