ansys / pymapdl

Pythonic interface to MAPDL
https://mapdl.docs.pyansys.com
MIT License
426 stars 120 forks source link

Bug in plot_nodal_values #1974

Closed Jrek98 closed 1 year ago

Jrek98 commented 1 year ago

Before submitting the issue

Description of the bug

Calling PostProcessing.plot_nodal_values results in an Error, which is produced by the function call self.nodal_values.

The "comp"-parameter in the function call self.nodal_values is always an empty string and is not set to the right value https://github.com/pyansys/pymapdl/blob/71d326fd31cfd80c858f6d9996944bbd86809213/src/ansys/mapdl/core/post.py#L509

Steps To Reproduce

Steps:

And I ran the following code:


from ansys.mapdl.core import launch_mapdl
mapdl = launch_mapdl()

# Insert your code here
mapdl.post1()
mapdl.post_processing.plot_nodal_values("B", "X")

Which Operating System are you using?

Windows

Which Python version are you using?

3.10

PyMAPDL Report

Show the Report! ```text # PASTE HERE THE OUTPUT OF `python -c "from ansys.mapdl import core as pymapdl; print(pymapdl.Report())"` here ```

Installed packages

Show the installed packages! ```text # PASTE HERE THE OUTPUT OF `python -m pip freeze` here ```

Logger output file

Show the logger output file. ```text # PASTE HERE THE CONTENT OF THE LOGGER OUTPUT FILE. ```
mikerife commented 1 year ago

@Jrek98 Hi, this is not a bug (or maybe it is, but...). The results have not been read into the MAPDL database yet for post processing. Try this instead:

mapdl.post1()
mapdl.set('last')
mapdl.post_processing.plot_nodal_values("B", "X")

Mike

Jrek98 commented 1 year ago

@mikerife Hey, thanks for your reply. Unfortunately this does not solve the problem. You are right, I missed the reading, but when you have a look at the mentioned line the comp(onent) will always be set to ""

This is the error that occurs after executing the code:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[4], line 3
      1 mapdl.post1()
      2 mapdl.set('last')
----> 3 mapdl.post_processing.plot_nodal_values("B", "X")

File [c:\Python310\lib\site-packages\ansys\mapdl\core\post.py:509](file:///C:/Python310/lib/site-packages/ansys/mapdl/core/post.py:509), in PostProcessing.plot_nodal_values(self, item, comp, show_node_numbering, **kwargs)
    458 def plot_nodal_values(self, item, comp, show_node_numbering=False, **kwargs):
    459     """Plot nodal values
    460 
    461     Displays solution results as continuous element contours.
   (...)
    506     ... )
    507     """
--> 509     values = self.nodal_values(self, item, comp="")
    510     kwargs.setdefault(
    511         "scalar_bar_args", {"title": f"item: {item}\nComponent: {comp}"}
    512     )
    513     return self._plot_point_scalars(
    514         values, show_node_numbering=show_node_numbering, **kwargs
    515     )

TypeError: PostProcessing.nodal_values() got multiple values for argument 'comp'
mikerife commented 1 year ago

Hi @Jrek98 @germa89 Adding germa89 for visibility as it does seem to be a bug. Jrek98: we can element plot Bx, or create native (mapdl) png files of nodal Bx plots; or dump the data and the grid out and use PyVista to plot the result.

The 'Normal' Power Graphics MAPDL PLNSOL plot will not average across the material boundaries so any non-MAPDL plot is kind of hard to replicate since the method used to retrieve the nodal values returns an average (of all attached elements of the node) value.

Attached is a Jupyter Notebook file of a MAPDL verification manual example model (2D solenoid actuator) to work with if Jrek98 cannot share their model. It contains the different plots of B. When run look in the working directory for file.png etc for the MAPDL native plots of nodal Bx.

I used MAPDL 2023R1, Python 3.9.9, PyMAPDL 0.64.1, and Windows 10.

Mike

BFluxPlot.zip

mikerife commented 1 year ago

Hi @Jrek98 @germa89 Jrek98 attached is a cleaned up version with a better PyVista plot of the Bx result for the model. By the way the model is not an verification manual model; rather is is the example from the Ansys MAPDL Help -> Low Frequency Electromagnetic Analysis Guide -> Section 2.5.1 Example: Basic 2D Static Magnetic Analysis.

To compare results first the following is done to create a Power Graphics, reversed video (white background, black element edges and text), Bx plot:

mapdl.graphics('power')
mapdl.rgb('INDEX',100,100,100, 0)   
mapdl.rgb('INDEX', 80, 80, 80,13)   
mapdl.rgb('INDEX', 60, 60, 60,14)  
mapdl.rgb('INDEX', 0, 0, 0,15)  

mapdl.edge(1,1)
mapdl.show('png')
mapdl.plnsol('b','x')
mapdl.show('')

Which results in this plot: image

Next we take advantage of both PyMAPDL mesh.grid and post_processing respecting element and node selections to gather the results on a body-by-body basis. Bodies here defined as element groups that share material ID numbers. We can get a list of unique material IDs (having imported numpy as np) and loop over each set gathering the mesh.grid and result for each element group:

elem_mats = mapdl.mesh.material_type
grids = []
scalars = []
for mat in np.unique(elem_mats):
    mapdl.esel('s','mat','',mat)
    mapdl.nsle()
    grids.append(mapdl.mesh.grid)
    scalars.append(mapdl.post_processing.nodal_values('b','x'))
mapdl.allsel()

I'm still learning PyVista (and am not a developer) so this may not be the best approach. But we can then loop over each element group in the grid list and add them to a PyVista plotter, along with some plot controls, to recreate the above plot. Matplotlib is imported as mpl and PyVista as pv.

cmap1 = (mpl.colors.ListedColormap(['blue','royalblue', 'cyan', '#00FA9A','#7CFC00', '#ADFF2F','yellow', 'orange','red'])
        .with_extremes())

plotter = pv.Plotter()

for i in range(0,4):
    _ = plotter.add_mesh(grids[i],scalars=scalars[i], show_edges = True, cmap=cmap1,n_colors=9,scalar_bar_args = {
    "color": "black",
    "title": "B Flux X",
    "vertical": False,
    "n_labels": 10,})

_ = plotter.set_background(color='white')
_ = plotter.camera_position = 'xy'
#_ = plotter.color_map = 'jet'
plotter.show()

Which results in this plot...pretty close!

image

Mike

BFluxPlot-Version2.zip

Jrek98 commented 1 year ago

Hey Mike, thanks for the very good example. It does exactly what I wanted to achieve. Maybe this can be included in the documentation to show how to plot results that are not directly available. So that some more people can profit from your work/example.

germa89 commented 1 year ago

Hey Mike, thanks for the very good example. It does exactly what I wanted to achieve. Maybe this can be included in the documentation to show how to plot results that are not directly available. So that some more people can profit from your work/example.

I think this is a good idea. If @mikerife can do a first approach to the example (like give it a title, objectives, document the sections, etc), I can work on it to upload it to the example database :)