onera / Cassiopee

CFD pre- and post-processing python modules
https://onera.github.io/Cassiopee/
GNU Lesser General Public License v3.0
15 stars 10 forks source link

Help with Paraview and CGNS files generated with Cassiopee #77

Open ricardofrantz opened 3 weeks ago

ricardofrantz commented 3 weeks ago

Hi,

I'm experiencing an issue, and I'm not sure where to post this question, so I'm trying here in the GitHub issues.

We are running simulations with Cassiopee, and I need to export snapshots to open them in ParaView for visualization, such as creating videos.

Issue 1: The contour option in ParaView is not available after opening the CGNS file. Is this a known issue? Are there additional steps or information we need to add to the file to support contour visualization?

Issue 2: How can I open a series of files and add time stamps to them in ParaView?

I am attempting the following, but ParaView does not recognize the time stamps:

This is what I am doing: initialize the time nodes on the tree...

import Converter.PyTree as C
import Converter.Internal as Int
t = C.convertFile2PyTree(input_file)
t = Int.renameNode(t, input_file, "Base")
# https://cgns.github.io/CGNS_docs_current/sids/timedep.html
n = Int.newBaseIterativeData(name="BaseIterativeData", nsteps=1, itype="IterationValues", parent=t)
Int.newDataArray("TimeValues", value=[0.0], parent=n)

and then upon runtime:

def write_snapshot(file_number: int, t: Any, mpi: bool, timestamp: float = 0.0, iteration: int = 0, restart_vars: List[str] = None):
    fname = f"snapshot{file_number:06d}.cgns" if file_number != 0 else "initial_condition.cgns"
    t_export_disk = extract_vars(t, restart_vars) if restart_vars else t
    print0(f'Writing file: {fname} at time: {timestamp:.6f}')

    BaseIterativeData = Int.getNodeFromName(t, "BaseIterativeData")
    IterationValues = Int.getNodeFromName(BaseIterativeData, "IterationValues")
    TimeValues = Int.getNodeFromName(BaseIterativeData, "TimeValues")
    Int.setValue(node=IterationValues, value=iteration)
    Int.setValue(node=TimeValues, value=round(timestamp, 8))

    if mpi:
        Cmpi.convertPyTree2File(t_export_disk, fname)
    else:
        C.convertPyTree2File(t_export_disk, fname)

Any assistance or guidance on these issues would be greatly appreciated.

Thank you!

benoit128 commented 3 weeks ago

Hi Ricardo,

Concerning the contour option, is your field located in centers or nodes in your cgns file? If your field is in centers, can you try : a = C.center2node(a, 'fieldName') before saving to cgns and see if you get the contour option in paraview?

Concerning iterative data, your cgns seems correct. I ll try to get more information.

Have a nice day

ricardofrantz commented 3 weeks ago

Hi Benoit,

Thanks for your time,

I updated my subroutines to move the outpost data to nodes, and it didn't change anything in ParaView. Maybe I am doing something wrong or removing some other info that may be necessary?

def extract_vars(t: Any, vars: List[str]) -> Any:
    new_vars = ["centers:" + var for var in vars] + ["CoordinateX", "CoordinateY", "CoordinateZ"]
    t_outpost = C.extractVars(t, new_vars) # extract variables
    t_outpost = Cmpi.center2Node(t_outpost, new_vars) # convert centers to nodes
    return C.rmGhostCells(t_outpost, t_outpost, hlo_rhs - 1, adaptBCs=1, modified=[]) # remove ghost cells

def write_snapshot(file_number: int, t: Any, mpi: bool, timestamp: float = 0.0, iteration: int = 0, restart_vars: List[str] = None):

    fname = f"snapshot{file_number:06d}.cgns" if file_number != 0 else "initial_condition.cgns"

    t_export_disk = extract_vars(t, restart_vars) if restart_vars else t # full tree if initial condition

    print0(f"Writing file: {fname} at time: {timestamp:.6f}")

    # Update the time and iteration values
    BaseIterativeData = Int.getNodeFromName(t, "BaseIterativeData")
    IterationValues = Int.getNodeFromName(BaseIterativeData, "IterationValues")
    TimeValues = Int.getNodeFromName(BaseIterativeData, "TimeValues")
    Int.setValue(node=IterationValues, value=iteration)
    Int.setValue(node=TimeValues, value=round(timestamp, 8))

    if mpi:
        Cmpi.convertPyTree2File(t_export_disk, fname)
    else:
        C.convertPyTree2File(t_export_disk, fname)

Cordialement, A+ R

benoit128 commented 3 weeks ago

Hard to say, but if you provide a small cgns file containing your t_outpost, i can try to look at it. a+

ricardofrantz commented 3 weeks ago

Hello,

After further inspection, I can now select Point Arrays alongside Cell Arrays in ParaView. Still, isocontours appear quite erratic, and I am unable to view the time stamps.

Here is a snapshot000008.cgns.zip](https://github.com/user-attachments/files/16128849/snapshot000008.cgns.zip) generated by the routines I shared previously.

Hopefully, your expert eyes can find any inconsistencies.

Thanks for your time, Ricardo

benoit128 commented 3 weeks ago

Hi Ricardo,

Here is a short example of BaseIterativeData for 2 zones with 2 times that load in paraview:

import Converter.PyTree as C
import Generator.PyTree as G
import Converter.Internal as Internal

a1 = G.cart((0,0,0), (1,1,1), (10,10,10)); a1[0] = 'cart1'
a2 = G.cart((9,0,0), (1,1,1), (10,10,10)); a2[0] = 'cart2'
t = C.newPyTree(['Base', a1, a2])

# instant must be in differents FlowSolutions
Internal.__FlowSolutionNodes__ = 'FlowSolution#001'
C._initVars(t, '{F}={CoordinateX}')
Internal.__FlowSolutionNodes__ = 'FlowSolution#002'
C._initVars(t, '{F}={CoordinateX}+1')

# add to base
b = Internal.getNodeFromName1(t, 'Base')
it = Internal.newBaseIterativeData(nsteps=2, parent=b)
Internal.createChild(it, 'TimeValues', 'DataArray_t', [0.1, 0.2])
Internal.createChild(it, 'NumberOfZones', 'DataArray_t', 2)
Internal.createChild(it, 'ZonePointers', 'DataArray_t', [['cart1'.ljust(65), 'cart2'.ljust(65)], ['cart1'.ljust(65), 'cart2'.ljust(65)]])

# add to zones
for a in [a1,a2]:
    zt = Internal.newZoneIterativeData(parent=a)
    Internal.createChild(zt, 'FlowSolutionPointers', 'DataArray_t', ['FlowSolution#001'.ljust(32), 'FlowSolution#002'.ljust(32)])

Internal.printTree(t)

C.convertPyTree2File(t, 'out.cgns')
ricardofrantz commented 2 weeks ago

Hello,

Thank you very much for your help. Indeed, it works as I expected. However, I believe it would be better to have each snapshot in a separate file rather than in a single file, especially for moving data around. Currently, I am unable to load the files as a group, such as a series of 100 snapshots each with a timestamp.

Best regards,
Ricardo

benoit128 commented 2 weeks ago

Hi, Maybe you can try to use links having one master file and different files that store the solution at different times. For example:

# - HDF write with links -
import Generator.PyTree as G
import Converter.PyTree as C
import Converter.Internal as Internal

a = G.cart((0,0,0),(1,1,1),(50,50,50))
C._initVars(a, 'Density=1.')
t = C.newPyTree(['Base',a])

# Save file with links
links=[['.','coord.hdf','/Base/cart/GridCoordinates','/Base/cart/GridCoordinates']]
C.convertPyTree2File(t, 'main.hdf', links=links)

# Write pointed file
Internal._rmNodeByPath(t, '/Base/cart/FlowSolution')
C.convertPyTree2File(t, 'coord.hdf')
vincentcasseau commented 1 week ago

Hi @ricardofrantz ,

Isn't your cgns file broken?

cgnsview reports the following errors:

* Checking pyTree [13:58:37]
 - Range of donor BC match3_1 is invalid for zone Zone5.2.
 - Range of donor BC match3_12 is invalid for zone Zone5.2.
 - Range of donor BC match5_24 is invalid for zone Zone4.1.
 - Range of donor BC match6_9 is invalid for zone Zone4.3.
 - Range of donor BC match6_30 is invalid for zone Zone4.3.
 - Range of donor BC match8_25 is invalid for zone zone.
 - Range of donor BC match8_40 is invalid for zone zone.
 - Range of donor BC match8_42 is invalid for zone zone.
 - Range of donor BC match1_0.0 is invalid for zone Zone2.
 - Range of donor BC match1_2.0 is invalid for zone Zone2.
 - Range of donor BC match1_4.0 is invalid for zone Zone2.
 - Range of donor BC match10_41 is invalid for zone Zone5.1.
 - Range of donor BC match10_48 is invalid for zone Zone5.1.
 - Range of donor BC match2_3 is invalid for zone Zone4.2.
 - Range of donor BC match2_8 is invalid for zone Zone4.2.
 - Range of donor BC match7_31 is invalid for zone Zone6.3.
 - Range of donor BC match7_34 is invalid for zone Zone6.3.
 - Range of donor BC match9_17 is invalid for zone zone.0.
 - Range of donor BC match9_43 is invalid for zone zone.0.
 - Range of donor BC match4_16 is invalid for zone Zone6.4.
 - Range of donor BC match11_13 is invalid for zone Zone5.3.
 - Range of donor BC match11_49 is invalid for zone Zone5.3.
 - Range of donor BC match12_5 is invalid for zone Zone6.5.
 - Range of donor BC match12_35 is invalid for zone Zone6.5.

while the mesh connectivity displayed in cassiopee is clearly wrong (see image attached). This could explain why contours in cassiopee and Paraview aren't drawn properly.

mesh