├── requirements.txt ├── screenshots ├── U_field_probes-0-1.png └── p_field_probes-0-1.png ├── LICENSE ├── README.md ├── runCases.py ├── residuals.py ├── plot_probes.py └── mplfoam.py /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | scipy 3 | paraview 4 | vtk 5 | -------------------------------------------------------------------------------- /screenshots/U_field_probes-0-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbob/mplFOAM/HEAD/screenshots/U_field_probes-0-1.png -------------------------------------------------------------------------------- /screenshots/p_field_probes-0-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbob/mplFOAM/HEAD/screenshots/p_field_probes-0-1.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 François Beaubert 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This repository contains some Python functions to plot OpenFOAM data with Matplotlib. 2 | 3 | mplFOAM 4 | ======= 5 | 6 | This module contains functions to plot OpenFOAM data with Matplotlib using paraview.simple and numpy_support from vtk.util. 7 | 8 | At present time it only support: 9 | * surface plot in slice 10 | * plot along line 11 | 12 | plot_probes 13 | =========== 14 | 15 | This command line utility plots the probes signals written in the postProcessing/probes/0 directory 16 | It computes the number of probe(s) and plot the field(s) signal(s) at the probes. 17 | 18 | ```bash 19 | Usage: plot_probes.py [-h] [-p PROBES [PROBES ...]] [-f FIELDS [FIELDS ...]] 20 | 21 | Plot fields signals versus Time/Iteration at choosen probes. 22 | If no probe and field are given all the probes will be plotted for all the fields. 23 | 24 | optional arguments: 25 | -h, --help show this help message and exit 26 | -p PROBES [PROBES ...], --probes PROBES [PROBES ...] 27 | list of integers corresponding to the probes numbers 28 | -f FIELDS [FIELDS ...], --fields FIELDS [FIELDS ...] 29 | list of string corresponding to the fields names 30 | ``` 31 | 32 | For example, the command line invocation: 33 | ```bash 34 | plot_probes.py -f U p -p 0 1 35 | ``` 36 | will produce 37 | 38 | ![U field signals](/screenshots/U_field_probes-0-1.png) 39 | ![p field signals](/screenshots/p_field_probes-0-1.png) 40 | -------------------------------------------------------------------------------- /runCases.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import subprocess 5 | import sys 6 | 7 | # Cases names (list of directories): 8 | cases_names = ["pitzDaily1","pitzDaily2","pitzDaily3"] 9 | 10 | # Run in parallel 11 | parallel = True # Or False for one proc 12 | 13 | # Redirect the output of the Python script to a file 14 | log_filename ="runCases.log" 15 | log_file = open(log_filename, 'w') 16 | sys.stdout = log_file 17 | 18 | # Ensure that all cases (directories) exist and remove the non-existent ones from the list. 19 | cases_names_exist = cases_names.copy() 20 | for case_name in cases_names: 21 | if not os.path.isdir(case_name): 22 | print("Warning: The case directory " + case_name + " does not exist.") 23 | cases_names_exist.remove(case_name) 24 | if len(cases_names_exist) == 0: 25 | print("Error: No case found") 26 | sys.exit() 27 | 28 | # Start the main loop on case directory 29 | # If you don't want to wait for the end of the foamJob process 30 | # please remove the '-wait' option 31 | for case_name in cases_names_exist: 32 | # Change to the case directory. 33 | os.chdir("./" + case_name) 34 | print("===========================", flush=True) 35 | print("Working in case directory: " + case_name, flush=True) 36 | print("===========================", flush=True) 37 | if parallel: 38 | # Decompose the case: output in 'log.decomposePar' file 39 | subprocess.call("decomposePar 2>&1 | tee -a log.decomposePar", 40 | shell=True, 41 | stdout=log_file, 42 | stderr=subprocess.STDOUT) 43 | # Run the OpenFoam case in parallel: output in 'log' file 44 | subprocess.call("foamJob -wait -p simpleFoam", 45 | shell=True, 46 | stdout=log_file, 47 | stderr=subprocess.STDOUT) 48 | # Reconstruct the case: output in 'log.reconstructPar' file 49 | subprocess.call("reconstructPar -latestTime 2>&1 | tee -a log.reconstructPar", 50 | shell=True, 51 | stdout=log_file, 52 | stderr=subprocess.STDOUT) 53 | else: 54 | # Run the OpenFoam case 55 | subprocess.call("foamJob -wait simpleFoam", 56 | shell=True, 57 | stdout=log_file, 58 | stderr=subprocess.STDOUT) 59 | # Revert to the root directory. 60 | os.chdir("../") 61 | -------------------------------------------------------------------------------- /residuals.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | 4 | import sys 5 | import getopt 6 | import re 7 | import os 8 | import pylab as plt 9 | import numpy as np 10 | 11 | # Define the variables for which the residuals will be plotted 12 | variables = ["Ux", "Uy", "T", "p_rgh", "k", "epsilon"] 13 | 14 | # Get the arguments of the script 15 | def usage(): 16 | print("Usage: residuals.py -l logfile\nPlot the residuals versus Time/Iteration") 17 | 18 | try: 19 | options, args = getopt.getopt(sys.argv[1:], 'l:h', ['help', 'logfile=']) 20 | except getopt.GetoptError: 21 | usage() 22 | sys.exit(2) 23 | 24 | for opt, arg in options: 25 | if opt in ("-l", "--logfile"): 26 | log_file = arg 27 | elif opt in ("-h", "--help"): 28 | usage() 29 | sys.exit(1) 30 | 31 | # Get the lines of the logfile 'log_file' 32 | lines = open(log_file, "r" ).readlines() 33 | 34 | # Get the time and continuity values 35 | time = [] # Time(s) or iterations counter 36 | continuity = [] # Continuity values 37 | for line in lines: 38 | if re.search(r"^Time = ", line): # Search for string 'Time' at the begining of the line in file 39 | start = 'Time = ' 40 | value = line.split(start)[1] # Take the Time value as the string just after start 41 | time.append(np.float(value)) # Transform the string in a float value 42 | elif re.search(r"continuity errors :", line): # Search for string 'continuity' in the lines of file 'log_file' 43 | start = 'sum local = ' 44 | end = ', global' 45 | value = line.split(start)[1].split(end)[0] # Take the continuity value as string between start and end 46 | continuity.append(np.float(value)) # Transform the string in a float value 47 | 48 | # Get the residual values for each variable 49 | for variable in variables: 50 | data = [] 51 | for line in lines: 52 | if re.search(r"Solving for " + variable, line):# Search for string variable in line of file 'log_file' 53 | start = 'Final residual = ' 54 | end = ', No Iterations' 55 | value = line.split(start)[1].split(end)[0] 56 | data.append(np.float(value)) 57 | plt.plot(np.array(time),np.array(data), label=variable) # Plot the residual values of variable 58 | 59 | plt.plot(np.array(time),np.array(continuity), label="Continuity") # Plot the continuity values 60 | 61 | # Plot 62 | plt.title("Residuals plot:\n * logfile: " + log_file + "\n * case dir: " + os.getcwd().split('/')[-1], loc='left') 63 | plt.xlabel("Time(s)/Iterations") 64 | plt.ylabel("Residuals (Log Scale)") 65 | plt.yscale('log') 66 | plt.legend() 67 | plt.grid() 68 | plt.show() 69 | -------------------------------------------------------------------------------- /plot_probes.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # ************************************************ 5 | # Plot the probes signal written in the postProcessing/probes/0 directory 6 | # It computes the number of probes and plot the signal(s) of field(s) at the probes. 7 | # ************************************************ 8 | 9 | import os 10 | import argparse 11 | import numpy as np 12 | import matplotlib.pyplot as plt 13 | 14 | def probes_nb(probes_path, field="U"): 15 | """Return the number of probes for each data field""" 16 | # Open the field probe file 17 | probe_file = open(probes_path + field, 'r') 18 | # Compute the number of probes nbProbes 19 | nb_probes = 0 20 | while probe_file.readline()[2] == "P" : 21 | nb_probes = nb_probes + 1 22 | # Close the probe file 23 | probe_file.close 24 | return nb_probes 25 | 26 | def probes_fields(probes_path): 27 | """Give a list of all the fields present in the probes directory""" 28 | # WARNING: Add a test to check if the file is indeed a probe data file 29 | fields = [] 30 | for (dirpath, dirnames, filenames) in os.walk(probes_path): 31 | fields.extend(filenames) 32 | return fields 33 | 34 | def probes_coordinates(probes_path, nb_probes, field="U"): 35 | """Return the probes coordinates arrays""" 36 | # Open the field probe file 37 | probe_file=open(probes_path + field,'r') 38 | # Define the probes coordinates arrays 39 | xProbe = np.zeros(nb_probes) # Array of the x coordinates of all the probes 40 | yProbe = np.zeros(nb_probes) # Array of the y coordinates of all the probes 41 | zProbe = np.zeros(nb_probes) # Array of the z coordinates of all the probes 42 | for iProbe in range(0,nb_probes): 43 | lineStrings = probe_file.readline().split() 44 | xProbe[iProbe] = float(lineStrings[3][1:]) # Skip the first character which is '(' 45 | yProbe[iProbe] = float(lineStrings[4]) 46 | zProbe[iProbe] = float(lineStrings[5][:-1]) # Skip the last character which is ')' 47 | # Close the probe file 48 | probe_file.close 49 | return xProbe, yProbe, zProbe 50 | 51 | def probes_data(probe_file, nb_probes, nb_components): 52 | """Return the probes data array""" 53 | # Distinguish the volVectorField and the volScalarField 54 | if nb_components==3: 55 | # Define the converters in order to convert string to float 56 | converters = {} 57 | k = 0 58 | for iProbe in range(0, nb_probes): 59 | converters[k+1] = lambda s: float(s[1:]) # Skip the first character which is '(' 60 | converters[k+3] = lambda s: float(s[:-1]) # Skip the last character which is ') 61 | k = k + 3 62 | # Load the vector field values with loadtxt() 63 | data = np.loadtxt(probe_file, comments='#', delimiter=None ,converters=converters, unpack=True) 64 | 65 | elif nb_components==1: 66 | # Load scalar field values with loadtxt() 67 | data = np.loadtxt(probe_file, comments='#', delimiter=None ,converters=None, unpack=True) 68 | return data 69 | 70 | # Path of the probes data 71 | probes_path = "postProcessing/probes/0/" 72 | 73 | # By default get all the fields present in the probe directory and set the nbProbes to its max 74 | fields = probes_fields(probes_path) 75 | nb_probes = probes_nb(probes_path) 76 | 77 | # Create the parser 78 | parser = argparse.ArgumentParser( 79 | description = "Plot fields signals versus Time/Iteration at choosen probes. If no probe and field are given all the probes will be plotted for all the fields.", 80 | epilog = "Happy Foaming ...") 81 | 82 | parser.add_argument("-p", "--probes", 83 | type = int, 84 | nargs = "+", 85 | default = range(nb_probes), 86 | help="list of integers corresponding to the probes numbers") 87 | 88 | parser.add_argument("-f", "--fields", 89 | type = str, 90 | nargs = "+", 91 | default = fields, 92 | help="list of string corresponding to the fields names") 93 | 94 | # Get the args 95 | args = parser.parse_args() 96 | fields = args.fields # list of string: fields names 97 | probes = args.probes # list of int: probes numbers 98 | 99 | # Define the fields type and the ones to plot 100 | fieldsType={"U" : "volVectorField", "p" : "volScalarField", "T" : "volScalarField"} 101 | 102 | # Get the coordinates of the probes 103 | xProbe, yProbe, zProbe = probes_coordinates(probes_path,nb_probes) 104 | 105 | # Loop over of the fields to plot 106 | for iField in range(np.size(fields)): 107 | try: 108 | if fieldsType[fields[iField]] == "volVectorField": 109 | nb_components = 3 110 | elif fieldsType[fields[iField]] == "volScalarField": 111 | nb_components = 1 112 | except: 113 | print "Error: One of the field to plot has a unknown fieldType" 114 | exit 115 | 116 | # Open the probe file 117 | probe_file=open(probes_path + fields[iField],'r') 118 | 119 | # Get the probes data 120 | data = probes_data(probe_file, nb_probes, nb_components) 121 | 122 | # Creation of the different figures 123 | f1 = plt.figure() 124 | nb_probes_to_plot = np.size(probes) 125 | for i in range(nb_probes_to_plot): 126 | iProbe = probes[i] 127 | for j in range(nb_components): 128 | ax = f1.add_subplot(nb_probes_to_plot,nb_components,nb_components*i + j + 1) 129 | ax.set_title(r'Point '+ str(iProbe) + str(" (%.3f %.3f %.3f)"% (xProbe[iProbe],yProbe[iProbe],zProbe[iProbe])),fontsize=12) 130 | x = data[0,:] 131 | y = data[nb_components*i + j + 1,:] 132 | # Change the labels of the axes according to the number of components 133 | if nb_components == 3: 134 | label = r'$'+fields[iField]+'_'+str(j)+'$' 135 | ax.set_ylabel(r'$'+fields[iField]+'_'+str(j)+'$') 136 | elif nb_components == 1: 137 | label = r'$'+fields[iField]+'$' 138 | ax.set_ylabel(r'$'+fields[iField]+'$') 139 | ax.set_xlabel(r'Time$(\Delta t)$') 140 | ax.plot(x,y,lw=2, ms=5,label= label) 141 | ax.xaxis.grid(True) 142 | ax.yaxis.grid(True) 143 | ax.legend(loc='best') 144 | plt.tight_layout(pad=0.01) 145 | 146 | # Draw the figures 147 | plt.show() 148 | -------------------------------------------------------------------------------- /mplfoam.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # mplFOAM module 3 | # some useful functions to import, plot OpenFoam data with matplotlib 4 | 5 | import os 6 | import numpy as np 7 | 8 | try: paraview.simple 9 | except: from paraview.simple import * 10 | paraview.simple._DisableFirstRenderCameraReset() 11 | 12 | from vtk.util import numpy_support as npvtk 13 | 14 | def read_openfoam_case(verbose=False,**kwargs): 15 | """ 16 | Read the OpenFOAM case 17 | 18 | Parameters 19 | ---------- 20 | directory : str, optional 21 | Directory path of the OpenFOAM case 22 | 23 | filename : str, optional 24 | Filename of the .OpenfOAM case for Paraview 25 | 26 | mesh_parts : list of str 27 | List of the different parts of the mesh to be loaded 28 | 29 | volume_fields : list of str 30 | List of the different fields to be loaded 31 | 32 | times : list of str 33 | List of the different timestep to be loaded 34 | 35 | Return 36 | ------ 37 | openfoam_case_merged : paraview object 38 | """ 39 | 40 | # Create the OpenFOAM file case 41 | if kwargs.get('directory') is None: 42 | directory = os.getcwd().split('/')[-1] 43 | 44 | if kwargs.get('filename') is None: 45 | filename = directory +'.OpenFOAM' 46 | 47 | case_file = open(filename, 'w') 48 | case_file.close() 49 | 50 | # Define the OpenFOAM data source 51 | openfoam_case = OpenDataFile(filename) 52 | 53 | # Import all the mesh parts if none are specified 54 | if kwargs.get('mesh_parts') is None: 55 | mesh_parts = openfoam_case.MeshParts.Available 56 | openfoam_case.MeshParts = mesh_parts 57 | 58 | # Import all the volume fields if none are specified 59 | if kwargs.get('volume_fields') is None: 60 | volume_fields = openfoam_case.VolumeFields.Available 61 | openfoam_case.VolumeFields = volume_fields 62 | 63 | # Read the specified time steps 64 | if kwargs.get('times') is None: 65 | # Get the latest timestep if none is specified 66 | openfoam_case.TimestepValues = openfoam_case.TimestepValues[-1] 67 | else: 68 | openfoam_case.TimestepValues = times 69 | 70 | # Print some basic informations on the loaded case 71 | if verbose: 72 | print "Case filename: ", filename 73 | print "Mesh parts: ", mesh_parts 74 | print "Volume fields: ", volume_fields 75 | print "Timestep values: ", openfoam_case.TimestepValues 76 | 77 | openfoam_case_merged = MergeBlocks(openfoam_case) 78 | openfoam_data = servermanager.Fetch(openfoam_case_merged) 79 | 80 | return openfoam_case_merged 81 | 82 | def extractDataInPatch(case, verbose=False): 83 | "Extract the data from a patch and" 84 | 85 | # Select the active source 86 | #SetActiveSource(case) 87 | 88 | # Define the data 89 | Tetrahedralize1 = Tetrahedralize() 90 | data = servermanager.Fetch(Tetrahedralize1) 91 | 92 | # Define the number of points, cells and arrays 93 | nb_points = case.GetNumberOfPoints() 94 | nb_cells = case.GetNumberOfCells() 95 | nb_arrays = case.GetPointData().GetNumberOfArrays() 96 | 97 | # Get Paraview's own triangulation 98 | #cells = data.GetPolys() 99 | #triangles = cells.GetData() 100 | #nb_triangles = triangles.GetNumberOfTuples()/4 101 | 102 | nb_triangles = nb_cells 103 | tri = np.zeros((nb_triangles, 3)) 104 | 105 | #for i in xrange(0, nb_triangles): 106 | # tri[i, 0] = triangles.GetTuple(4*i + 1)[0] 107 | # tri[i, 1] = triangles.GetTuple(4*i + 2)[0] 108 | # tri[i, 2] = triangles.GetTuple(4*i + 3)[0] 109 | 110 | # Display some informations on the slice 111 | if verbose: 112 | 113 | #print 'Patch name :', patchName 114 | print "Number of cells:",nb_cells 115 | print "Number of triangles:",nb_triangles 116 | print "Number of points:",nb_points 117 | print "Number of arrays:",nb_arrays 118 | 119 | for i in range(nb_arrays): 120 | print 'Array [',i,'] name:', case.GetPointData().GetArrayName(i) 121 | 122 | # Put the points coordinates in x, y and z arrays 123 | x=[] 124 | y=[] 125 | z=[] 126 | #points=zeros((nb_points,3)) 127 | 128 | for i in range(nb_points): 129 | coord = case.GetPoint(i) 130 | xx, yy, zz = coord[:3] 131 | x.append(xx) 132 | y.append(yy) 133 | z.append(zz) 134 | 135 | #points[i,0] = xx 136 | #points[i,1] = yy 137 | #points[i,2] = zz 138 | 139 | x=np.array(x) 140 | y=np.array(y) 141 | z=np.array(z) 142 | 143 | #print 'Points',points 144 | 145 | # Define the velocity components U=(u,v,w) 146 | U = npvtk.vtk_to_numpy(case.GetPointData().GetArray('U')) 147 | u = U[:,0] 148 | v = U[:,1] 149 | w = U[:,2] 150 | 151 | # Define the cinematique pressure p => p/\rho 152 | p = npvtk.vtk_to_numpy(case.GetPointData().GetArray('p')) 153 | 154 | # Return the values extracted from the slice 155 | return x,y,z,u,v,w,p,tri 156 | 157 | def extract_plane(case, slice_origin=[0,0,0],slice_normal=[0,0,1], verbose=False): 158 | """ 159 | Extract Paraview slice object from OpenFOAM case `case` 160 | 161 | Parameters 162 | ---------- 163 | case : Paraview object 164 | OpenFOAM case 165 | 166 | slice_origin : list of float 167 | Slice point origin [x, y, z] in cartesian coordinates 168 | 169 | slice_normal : list of float 170 | Slice point normal [nx, ny, nz] in cartesian coordinates 171 | 172 | Return 173 | ------ 174 | plane_data: paraview slice object 175 | 176 | """ 177 | # Select the active source 178 | SetActiveSource(case) 179 | 180 | # Define the plane 181 | Slice1 = Slice(SliceType="Plane") 182 | Slice1.SliceType = 'Plane' 183 | Slice1.SliceType.Origin = slice_origin 184 | Slice1.SliceType.Normal = slice_normal 185 | #Slice1.UpdatePipeline() 186 | 187 | plane_data = servermanager.Fetch(Slice1) 188 | 189 | # Define the number of points, cells and arrays 190 | nb_points = plane_data.GetNumberOfPoints() 191 | nb_cells = plane_data.GetNumberOfCells() 192 | nb_arrays = plane_data.GetPointData().GetNumberOfArrays() 193 | 194 | # Display some informations on the slice 195 | if verbose: 196 | print 'Slice origin:', slice_origin 197 | print 'Slice normal:', slice_normal 198 | print "Number of cells:", nb_cells 199 | print "Number of triangles:", nb_triangles 200 | print "Number of points:", nb_points 201 | print "Number of arrays:", nb_arrays 202 | 203 | for i in range(nb_arrays): 204 | print 'Array [',i,'] name:', plane_data.GetPointData().GetArrayName(i) 205 | 206 | return plane_data 207 | 208 | def extract_plane_triangulation(plane_data, verbose=False): 209 | """Extract the triangulation of the plane""" 210 | 211 | # Get Paraview's own triangulation 212 | cells = plane_data.GetPolys() 213 | triangles = cells.GetData() 214 | nb_triangles = triangles.GetNumberOfTuples()/4 215 | 216 | tri = np.zeros((nb_triangles, 3)) 217 | 218 | for i in xrange(0, nb_triangles): 219 | tri[i, 0] = triangles.GetTuple(4*i + 1)[0] 220 | tri[i, 1] = triangles.GetTuple(4*i + 2)[0] 221 | tri[i, 2] = triangles.GetTuple(4*i + 3)[0] 222 | 223 | # Display some informations on the triangulation 224 | if verbose: 225 | print "Number of triangles:", nb_triangles 226 | 227 | # Return the triangulation of the plane 228 | return tri, triangles 229 | 230 | def extract_plane_points(plane_data, verbose=False): 231 | """Extract the points of the plane""" 232 | 233 | # Get the number of points 234 | nb_points = plane_data.GetNumberOfPoints() 235 | 236 | # Put the points coordinates in x, y and z arrays 237 | x = [] 238 | y = [] 239 | z = [] 240 | 241 | for i in range(nb_points): 242 | coord = plane_data.GetPoint(i) 243 | xx, yy, zz = coord[:3] 244 | x.append(xx) 245 | y.append(yy) 246 | z.append(zz) 247 | 248 | x = np.array(x) 249 | y = np.array(y) 250 | z = np.array(z) 251 | 252 | # Display some informations on the triangulation points 253 | if verbose: 254 | print "Number of points:", nb_points 255 | print "xrange: [%5.3f, %5.3f]" %(x.min(), x.max()) 256 | print "yrange: [%5.3f, %5.3f]" %(y.min(), y.max()) 257 | print "zrange: [%5.3f, %5.3f]" %(z.min(), z.max()) 258 | 259 | # Return the cartesian coordinates of the triangulation points 260 | return x,y,z 261 | 262 | def extract_plane_vector_field(plane_data, field_name, verbose=False): 263 | """Extract the vector field components in the plane""" 264 | 265 | # Define the velocity components U=(u,v,w) 266 | U = npvtk.vtk_to_numpy(plane_data.GetPointData().GetArray(field_name)) 267 | u = U[:,0] 268 | v = U[:,1] 269 | w = U[:,2] 270 | 271 | # Return the vector field components 272 | return u,v,w 273 | 274 | def extract_plane_scalar_field(plane_data, field_name, verbose=False): 275 | """Extract the scalar field `field_name` in the plane `plane_data`""" 276 | 277 | # Put the scalar field field_name in array scalar 278 | scalar = npvtk.vtk_to_numpy(plane_data.GetPointData().GetArray(field_name)) 279 | 280 | # Return the scalar field values extracted from the plane 281 | return scalar 282 | --------------------------------------------------------------------------------