ansys / pymapdl

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

Unexpected MAPDL server disconnection while running a series of ``aplot()`` #1419

Open germa89 opened 1 year ago

germa89 commented 1 year ago

Discussed in https://github.com/pyansys/pymapdl/discussions/1411

Originally posted by **hawkoli1987** August 26, 2022 Dear All, I am trying to generating a random range of 2D shapes in series, there are 100 numbers of such shapes in total. For each shape generated, I ordered a printout of it via mapdl.aplot(). After a bunch of such shapes were successfully generated, there is always an automatic server disconnection which stops me from generating new shapes. However, if I simply change the aplot() to lplot(), it will complete the generation process successfully. Another issue I had was that on one side of the shape, it's a curve that was generated by fitting a spline through a series of keypoints. Among all the area plots, I can always spot a few that looks like straight line-segments rather than a spline. I would assume both issues are connected? and perhaps both was caused by insufficient memory? I attached my code here in a zip. Please enlighten me on this, thanks! ```py --------------------------------------------------------------------------- MapdlExitedError Traceback (most recent call last) Input In [5], in () 125 geo = Geometry(curve = line.tolist()) 126 mat = Material() --> 127 get_Ue(mat, geo) Input In [5], in get_Ue(mat, geo, c_r, force, disp, AESIZE, refine_lvl, detach_step) 114 else: 115 mapdl.rectng(0, geo.diameter/2, 0, geo.height) --> 116 mapdl.aplot('ALL',cpos="xy") 117 return File ~\anaconda3\envs\pyansys_env\lib\site-packages\ansys\mapdl\core\mapdl.py:1478, in _MapdlCore.aplot(self, na1, na2, ninc, degen, scale, vtk, quality, show_area_numbering, show_line_numbering, color_areas, show_lines, **kwargs) 1476 if quality < 1: 1477 quality = 1 -> 1478 surf = self.geometry.generate_surface(11 - quality, na1, na2, ninc) 1479 meshes = [] 1480 labels = [] File ~\anaconda3\envs\pyansys_env\lib\site-packages\ansys\mapdl\core\misc.py:324, in supress_logging..wrapper(*args, **kwargs) 321 if prior_log_level != "CRITICAL": 322 mapdl._set_log_level("CRITICAL") --> 324 out = func(*args, **kwargs) 326 if prior_log_level != "CRITICAL": 327 mapdl._set_log_level(prior_log_level) File ~\anaconda3\envs\pyansys_env\lib\site-packages\ansys\mapdl\core\misc.py:346, in run_as_prep7..wrapper(*args, **kwargs) 343 if prior_processor != "PREP7": 344 mapdl.prep7() --> 346 out = func(*args, **kwargs) 348 if prior_processor == "Begin level": 349 mapdl.finish() File ~\anaconda3\envs\pyansys_env\lib\site-packages\ansys\mapdl\core\mapdl_geometry.py:293, in Geometry.generate_surface(self, density, amin, amax, ninc) 290 self._mapdl.prep7(mute=True) 292 # Mesh and get the number of elements per area --> 293 resp = self._mapdl.amesh("all") 294 groups = get_elements_per_area(resp) 296 self._mapdl.esla("S") File ~\anaconda3\envs\pyansys_env\lib\site-packages\ansys\mapdl\core\_commands\preproc\meshing.py:182, in Meshing.amesh(self, na1, na2, ninc, **kwargs) 160 """Generates nodes and area elements within areas. 161 162 APDL Command: AMESH (...) 179 This command is also valid for rezoning. 180 """ 181 command = f"AMESH,{na1},{na2},{ninc}" --> 182 return self.run(command, **kwargs) File ~\anaconda3\envs\pyansys_env\lib\site-packages\ansys\mapdl\core\mapdl.py:2630, in _MapdlCore.run(self, command, write_to_log, mute, **kwargs) 2627 self._check_parameter_name(param_name) 2629 verbose = kwargs.get("verbose", False) -> 2630 text = self._run(command, verbose=verbose, mute=mute) 2632 if mute: 2633 return File ~\anaconda3\envs\pyansys_env\lib\site-packages\ansys\mapdl\core\mapdl_grpc.py:736, in MapdlGrpc._run(self, cmd, verbose, mute) 734 response = self._send_command_stream(cmd, True) 735 else: --> 736 response = self._send_command(cmd, mute=mute) 737 self._busy = False 739 return response.strip() File ~\anaconda3\envs\pyansys_env\lib\site-packages\ansys\mapdl\core\errors.py:138, in protect_grpc..wrapper(*args, **kwargs) 136 # Must close unfinished processes 137 mapdl._close_process() --> 138 raise MapdlExitedError("MAPDL server connection terminated") from None 140 if threading.current_thread().__class__.__name__ == "_MainThread": 141 received_interrupt = bool(SIGINT_TRACKER) MapdlExitedError: MAPDL server connection terminated --------------------------------------------------------------------------- ``` ## File: [Issue.zip](https://github.com/pyansys/pymapdl/files/9431863/Issue.zip) hawkoli1987
germa89 commented 1 year ago

Interesting...

After a while it doesn't seem to do the splines properly:

image

However, the MAPDL figure does show correct geometry:

image

Hence I believe the interpolation thing it is more an mapdl-pyvista mapping issue. I will open another issue about this.

germa89 commented 1 year ago

Sometimes I get weird lines:

image

germa89 commented 1 year ago

I'm using a slightly modified version of OP's code:

Show me ```py #!/usr/bin/env python # coding: utf-8 # In[5]: import numpy as np from numpy.lib.stride_tricks import sliding_window_view import matplotlib.pyplot as plt import math import random import matplotlib.pyplot as plt # from scipy.integrate import quad from math import* #import all function from math from ansys.mapdl.core import launch_mapdl exec_loc = 'C:/Program Files/ANSYS Inc/v222/ANSYS/bin/winx64/ANSYS222.exe' mapdl = launch_mapdl(exec_loc, port=50060, add_env_vars={'ANS_DEBUG_CRASH':1}) print(mapdl) print(mapdl.directory) mapdl.nerr(200, 99999999, -1) def Coefficient_Gen(pop_size, mode = 20, center_tolerance=1, max_amplitude=8): n = mode tol = center_tolerance Ans = np.empty(shape = (0,20)) Bns = np.empty(shape = (0,20)) while Ans[:,0].size < pop_size: An = np.expand_dims(np.array([random.uniform(-1, 1) for _ in range(n)]), axis = 0) Bn = np.expand_dims(np.array([random.uniform(-1, 1) for _ in range(n)]), axis = 0) line = to_Fourier(An, Bn) line_max = np.absolute(line).max() line_avg = np.average(line) if line_avg<-tol or line_avg>tol or line_max>max_amplitude: continue Ans = np.vstack((Ans, An)) Bns = np.vstack((Bns, Bn)) DNAs = np.hstack((Ans, Bns)) return DNAs def to_Fourier(An, Bn, segment = 20): if An.shape == Bn.shape: n = An[0,:].size else: print('Error: coefficients size mismatch') x=np.arange(-np.pi,np.pi,2*np.pi/segment) #x axis has been chosen from –π to +π, value x=np.expand_dims(x, 0) total = 0 for i in range(n): if i==0.0: total+=An[:,i]/2 # in case n=0 total=total[:,np.newaxis] else: total = total + An[:,i][:,np.newaxis]*np.cos(i*x)+Bn[:,i][:,np.newaxis]*np.sin(i*x) return total POP_SIZE = 100 DNA_SIZE = 40 class Material: """ elastic modulus (kPa), poisson ratio work of adhesion (mJ/m^2) """ def __init__(self, E_modulus = 500, nu=0.4, w_ad = 20): self.E_modulus = E_modulus*1e-3 # elasticu modulus: kPa -> uN/um^2 self.nu = nu # poisson ratio: dimensionless self.w_ad = w_ad *1e-3 # work of adhesion: mJ/m^2 -> uN/um class Geometry: """ unit (um) """ def __init__(self, height = 100, diameter=50, curve=[]): self.height = height # fiber height: um self.diameter = diameter # fiber average diameter: um self.curve = curve # curved side profile, either None (straight edge) or 1D array of radius def translateDNA(pop): # DNA samples to split into different gene groups, e.g. An, Bn An = pop[:,:int(DNA_SIZE/2)] Bn = pop[:,int(DNA_SIZE/2):] return An, Bn def get_Ue(mat, geo, c_r=None, force=None, disp=None, AESIZE=5, refine_lvl=3, detach_step=5): # reset mapdl mapdl.clear() mapdl.prep7() # Define element attributes # keyoption 3 = 1 (axis-symmetric formulation) mapdl.et(1, "PLANE182", kop3=1) # create cross-sectional area of fiber if geo.curve != []: line = geo.curve n = len(line) segment = geo.height/(n-1) for i, value in enumerate(line): mapdl.k(i+2, value+geo.diameter/2, i*segment) mapdl.ksel('all') mapdl.run("BSPLIN, 'all'") mapdl.cm("curved_edge", "LINE") mapdl.k(1,0,0) # starting at origin mapdl.k(n+2,0,geo.height) # ending at the top mapdl.lstr(1,2) mapdl.lstr(n+1,n+2) mapdl.lstr(n+2,1) try: mapdl.al('ALL') except: mapdl.lplot('ALL',cpos="xy") else: mapdl.rectng(0, geo.diameter/2, 0, geo.height) mapdl.aplot('ALL',cpos="xy") mapdl.aplot(vtk=False) return pop = Coefficient_Gen(pop_size = POP_SIZE) # initialize the pop DNA An, Bn = translateDNA(pop) lines = to_Fourier(An, Bn) print(lines) for ind, line in enumerate(lines): print(f"Line: {ind}/{len(lines)}") geo = Geometry(curve = line.tolist()) mat = Material() get_Ue(mat, geo) ```
germa89 commented 1 year ago

I get the same error as OP:


---------------------------------------------------------------------------
MapdlExitedError                          Traceback (most recent call last)
c:\ansys_jobs\aplot_failing\Issue.py in <module>
    138     geo = Geometry(curve = line.tolist())
    139     mat = Material()
--> 140     get_Ue(mat, geo)
    141
    142

c:\ansys_jobs\aplot_failing\Issue.py in get_Ue(mat, geo, c_r, force, disp, AESIZE, refine_lvl, detach_step)
    124             mapdl.aplot(vtk=False)
    125         except:
--> 126             mapdl.lplot('ALL',cpos="xy")
    127     else:
    128         mapdl.rectng(0, geo.diameter/2, 0, geo.height)

~\Others_pymapdls\pymapdl_1\pymapdl\src\ansys\mapdl\core\mapdl.py in lplot(self, nl1, nl2, ninc, vtk, show_line_numbering, show_keypoint_numbering, color_lines, **kwargs)
   1726             kwargs.setdefault("show_scalar_bar", False)
   1727             kwargs.setdefault("title", "MAPDL Line Plot")
-> 1728             if not self.geometry.n_line:
   1729                 warnings.warn(
   1730                     "Either no lines have been selected or there is nothing to plot."

~\Others_pymapdls\pymapdl_1\pymapdl\src\ansys\mapdl\core\mapdl_geometry.py in n_line(self)
    363         1
    364         """
--> 365         return self._item_count("LINE")
    366
    367     @property

~\Others_pymapdls\pymapdl_1\pymapdl\src\ansys\mapdl\core\misc.py in wrapper(*args, **kwargs)
    373             mapdl._set_log_level("CRITICAL")
    374
--> 375         out = func(*args, **kwargs)
    376
    377         if prior_log_level != "CRITICAL":

~\Others_pymapdls\pymapdl_1\pymapdl\src\ansys\mapdl\core\mapdl_geometry.py in _item_count(self, entity)
    380     def _item_count(self, entity):
    381         """Return item count for a given entity."""
--> 382         return int(self._mapdl.get(entity=entity, item1="COUNT"))
    383
    384     @property

~\Others_pymapdls\pymapdl_1\pymapdl\src\ansys\mapdl\core\mapdl.py in get(self, par, entity, entnum, item1, it1num, item2, it2num, item3, **kwargs)
   2240         # Checking printout is not suppressed by checking "wrinqr" flag.
   2241         flag = 0
-> 2242         if self.wrinqr(1) != 1:  # using wrinqr is more reliable than *get
   2243             flag = 1
   2244             self._run("/gopr")

~\Others_pymapdls\pymapdl_1\pymapdl\src\ansys\mapdl\core\mapdl_grpc.py in wrinqr(self, key, **kwargs)
   2513     def wrinqr(self, key, **kwargs):
   2514         """Wrap the ``wrinqr`` method to take advantage of the gRPC methods."""
-> 2515         super().wrinqr(key, pname=TMP_VAR, mute=True, **kwargs)
   2516         return self.scalar_param(TMP_VAR)
   2517

~\Others_pymapdls\pymapdl_1\pymapdl\src\ansys\mapdl\core\_commands\inq_func.py in wrinqr(self, key, pname, **kwargs)
   1404
   1405         """
-> 1406         return self.run(f"{pname} = wrinqr({key})", **kwargs)

~\Others_pymapdls\pymapdl_1\pymapdl\src\ansys\mapdl\core\mapdl.py in run(self, command, write_to_log, mute, **kwargs)
   2694
   2695         verbose = kwargs.get("verbose", False)
-> 2696         text = self._run(command, verbose=verbose, mute=mute)
   2697
   2698         if mute:

~\Others_pymapdls\pymapdl_1\pymapdl\src\ansys\mapdl\core\mapdl_grpc.py in _run(self, cmd, verbose, mute)
    744             response = self._send_command_stream(cmd, True)
    745         else:
--> 746             response = self._send_command(cmd, mute=mute)
    747         self._busy = False
    748

~\Others_pymapdls\pymapdl_1\pymapdl\src\ansys\mapdl\core\errors.py in wrapper(*args, **kwargs)
    143             # Must close unfinished processes
    144             mapdl._close_process()
--> 145             raise MapdlExitedError("MAPDL server connection terminated") from None
    146
    147         if threading.current_thread().__class__.__name__ == "_MainThread":

MapdlExitedError: MAPDL server connection terminated

And there is no generated ANS_DEBUG_CRASH file.

akaszynski commented 1 year ago

The fundamental issue is we're not transferring the underlying tessellated geometry from MAPDL to Python, but rather we have to generate a faux FEA mesh overlaid on top of the existing areas. This has always been a stopgap, waiting for an API to directly transfer the tessellated faces generated with the underlying APLOT command.

Whether or not we do this depends on how long we plan on using the internal MAPDL geometry kernel. Since we have nothing to replace it with, I think we should still support it.

germa89 commented 1 year ago

Whether or not we do this depends on how long we plan on using the internal MAPDL geometry kernel. Since we have nothing to replace it with, I think we should still support it.

I agree on this.

I cannot understand though how the crash is happening in the current implementation. The geometry kernel should be stable enough to support create, export and delete a faux FEA mesh.

I will propose then to leave this on hold until more progress is made on the gRPC implementation.

germa89 commented 10 months ago

I recheck this issue on the latest PyMAPDL version and 222, I still get the same MAPDL crash.