11import os
2+ from warnings import warn
23
34from ansys .mapdl .core import __version__
45from ansys .mapdl .core .misc import is_float
@@ -61,21 +62,105 @@ def convert_script(
6162 >>> from ansys.mapdl.core import examples
6263 >>> clines = pymapdl.convert_script(examples.vmfiles['vm1'], 'vm1.py')
6364 """
65+ with open (filename_in , 'r' ) as fid :
66+ apdl_strings = fid .readlines ()
67+
68+ translator = _convert (apdl_strings = apdl_strings ,
69+ loglevel = loglevel ,
70+ auto_exit = auto_exit ,
71+ line_ending = line_ending ,
72+ exec_file = exec_file ,
73+ macros_as_functions = macros_as_functions ,
74+ use_function_names = use_function_names
75+ )
76+
77+ translator .save (filename_out )
78+ return translator .lines
79+
80+
81+ def convert_apdl_block (apdl_strings ,
82+ loglevel = "WARNING" ,
83+ auto_exit = True ,
84+ line_ending = None ,
85+ exec_file = None ,
86+ macros_as_functions = True ,
87+ use_function_names = True ,
88+ ):
89+ """Converts an ANSYS input string to a python PyMAPDL string.
90+
91+ Parameters
92+ ----------
93+ apdl_string : str
94+ APDL strings or list of strings to convert.
95+
96+ filename_out : str
97+ Filename of the python script to write a translation to.
98+
99+ loglevel : str, optional
100+ Logging level of the ansys object within the script.
101+
102+ auto_exit : bool, optional
103+ Adds a line to the end of the script to exit MAPDL. Default
104+ ``True``.
105+
106+ line_ending : str, optional
107+ When None, automatically determined by OS being used.
108+
109+ macros_as_functions : bool, optional
110+ Attempt to convert MAPDL macros to python functions.
111+
112+ use_function_names : bool, optional
113+ Convert MAPDL functions to ansys.mapdl.core.Mapdl class
114+ methods. When ``True``, the MAPDL command "K" will be
115+ converted to ``mapdl.k``. When ``False``, it will be
116+ converted to ``mapdl.run('k')``.
117+
118+ Returns
119+ -------
120+ list
121+ List of lines translated.
122+
123+ """
124+
125+ translator = _convert (apdl_strings ,
126+ loglevel = loglevel ,
127+ auto_exit = auto_exit ,
128+ line_ending = line_ending ,
129+ exec_file = exec_file ,
130+ macros_as_functions = macros_as_functions ,
131+ use_function_names = use_function_names )
132+
133+ if isinstance (apdl_strings , str ):
134+ return translator .line_ending .join (translator .lines )
135+ return translator .lines
136+
137+
138+ def _convert (apdl_strings ,
139+ loglevel = "WARNING" ,
140+ auto_exit = True ,
141+ line_ending = None ,
142+ exec_file = None ,
143+ macros_as_functions = True ,
144+ use_function_names = True ,
145+ ):
146+
64147 translator = FileTranslator (
65148 loglevel ,
66149 line_ending ,
67150 exec_file = exec_file ,
68151 macros_as_functions = macros_as_functions ,
69152 use_function_names = use_function_names ,
70153 )
71- with open (filename_in ) as file_in :
72- for line in file_in .readlines ():
73- translator .translate_line (line )
154+
155+ if isinstance (apdl_strings , str ):
156+ apdl_strings = apdl_strings .split (translator .line_ending )
157+
158+ for line in apdl_strings :
159+ translator .translate_line (line )
74160
75161 if auto_exit :
76162 translator .write_exit ()
77- translator .save (filename_out )
78- return translator .lines
163+ return translator
79164
80165
81166class FileTranslator :
@@ -107,7 +192,30 @@ def __init__(
107192 self .initialize_mapdl_object (loglevel , exec_file )
108193
109194 self ._valid_commands = dir (Commands )
110- self ._non_interactive_commands = ["*CRE" , "*VWR" ]
195+ self ._block_commands = {
196+ "NBLO" : "NBLOCK" ,
197+ "EBLO" : "EBLOCK" ,
198+ "BFBL" : "BFBLOCK" ,
199+ "BFEB" : "BFEBLOCK" ,
200+ "PREA" : "PREAD" ,
201+ "SFEB" : "SFEBLOCK" } #Way out: '-1' , 'END PREAD'
202+
203+ self ._enum_block_commands = {
204+ "CMBL" : "CMBLOCK" ,
205+ } # Commands where you need to count the number of lines.
206+
207+ _NON_INTERACTIVE_COMMANDS = {
208+ "*CRE" : "*CREATE" ,
209+ "*VWR" : "*VWRITE" ,
210+ "*VRE" : "*VREAD"
211+ }
212+
213+ self ._non_interactive_commands = list (_NON_INTERACTIVE_COMMANDS ) + list (self ._block_commands ) + list (self ._enum_block_commands )
214+
215+ self ._block_count = 0
216+ self ._block_count_target = 0
217+ self ._in_block = False
218+ self ._block_current_cmd = None
111219
112220 def write_header (self ):
113221 header = f'"""Script generated by ansys-mapdl-core version { __version__ } """'
@@ -152,6 +260,15 @@ def translate_line(self, line):
152260 line = line .strip ()
153261 line = line .replace ('"' , "'" )
154262
263+ if self ._in_block :
264+ self ._block_count += 1
265+
266+ if self ._in_block and self ._block_count >= self ._block_count_target and self ._block_count_target :
267+ self ._in_block = False
268+ self .end_non_interactive ()
269+ self ._block_count = 0
270+ self ._block_current_cmd = None
271+
155272 # check if line contains a comment
156273 if "!" in line :
157274 if "'!'" in line or '"!"' in line :
@@ -168,6 +285,34 @@ def translate_line(self, line):
168285
169286 if not line :
170287 return
288+ cmd_ = line .split (',' )[0 ].upper ()
289+
290+ if cmd_ == '*DO' :
291+ self .start_non_interactive ()
292+ self .store_run_command (line )
293+ return
294+
295+ if cmd_ == '*ENDDO' :
296+ self .store_run_command (line )
297+ self .end_non_interactive ()
298+ return
299+
300+ if self .output_to_file (line ):
301+ self .start_non_interactive ()
302+ self .store_run_command (line )
303+ return
304+
305+ if self .output_to_default (line ):
306+ self .end_non_interactive ()
307+ self .store_run_command (line )
308+ self .store_run_command ('/GOPR' )
309+ return
310+
311+ if cmd_ == '/VERIFY' :
312+ self .store_run_command ("FINISH" )
313+ self .store_run_command (line )
314+ self .store_run_command ("/PREP7" )
315+ return
171316
172317 if line [:4 ].upper () == "*REP" :
173318 if not self .non_interactive :
@@ -188,8 +333,17 @@ def translate_line(self, line):
188333 return self .store_command ("title" , ["" .join (parameters ).strip ()])
189334
190335 if line [:4 ].upper () == "*GET" :
191- parameters = line .split ("," )[1 :]
192- return self .store_command ("get" , parameters )
336+ if self .non_interactive : # gives error
337+ self .store_run_command (line )
338+ return
339+ else :
340+ parameters = line .split ("," )[1 :]
341+ return self .store_command ("get" , parameters )
342+
343+ if line [:4 ].upper () == "/NOP" :
344+ self .comment = "It is not recommended to use '/NOPR' in a normal PyMAPDL session."
345+ self .store_under_scored_run_command (line )
346+ return
193347
194348 if line [:6 ].upper () == "/PREP7" :
195349 return self .store_command ("prep7" , [])
@@ -200,11 +354,13 @@ def translate_line(self, line):
200354 self .store_empty_line ()
201355 self .indent = self .indent [4 :]
202356 self ._infunction = False
203- self .end_non_interactive ()
357+ if not self ._in_block :
358+ self .end_non_interactive ()
204359 return
205360 else :
206361 self .store_run_command (line )
207- self .end_non_interactive ()
362+ if not self ._in_block :
363+ self .end_non_interactive ()
208364 return
209365
210366 # check for if statement
@@ -216,12 +372,14 @@ def translate_line(self, line):
216372 # check if line ends non-interactive
217373 if line [0 ] == "(" :
218374 if not self .non_interactive :
219- print (
220- "Possible invalid line:\n %s\n " % line
221- + "This line requires a *VWRITE beforehand"
375+ warn (
376+ "\n Possible invalid line:\n %s\n " % line
377+ + "This line requires a *VWRITE beforehand."
378+ + "The previous line is: \n %s\n \n " % self .lines [- 1 ]
222379 )
223380 self .store_run_command (line )
224- self .end_non_interactive ()
381+ if not self ._in_block : # To escape cmds that require (XX) but they are not in block
382+ self .end_non_interactive ()
225383 return
226384 elif line [:4 ] == "*USE" and self .macros_as_functions :
227385 items = line .split ("," )
@@ -243,15 +401,36 @@ def translate_line(self, line):
243401 self .store_empty_line ()
244402 return
245403
404+ if line == '-1' or line == 'END PREAD' : # End of block commands
405+ self .store_run_command (line )
406+ self ._in_block = False
407+ self .end_non_interactive ()
408+ return
409+
246410 # check valid command
247411 if command not in self ._valid_commands :
248- if line [:4 ] == "*CRE" : # creating a function
412+ if line [:4 ]. upper () == "*CRE" : # creating a function
249413 if self .macros_as_functions :
250414 self .start_function (items [1 ].strip ())
251415 return
252416 else :
253417 self .start_non_interactive ()
254- elif line [:4 ] in self ._non_interactive_commands :
418+ elif line [:4 ].upper () in self ._non_interactive_commands :
419+ if line [:4 ].upper () in self ._block_commands :
420+ self ._in_block = True
421+ self ._block_count = 0
422+ self ._block_count_target = 0
423+
424+ elif line [:4 ].upper () in self ._enum_block_commands :
425+ self ._in_block = True
426+ self ._block_count = 0
427+ if line [:4 ].upper () == 'CMBL' : # In cmblock
428+ # CMBLOCK,Cname,Entity,NUMITEMS,,,,,KOPT
429+ numitems = int (line .split (',' )[3 ])
430+ _block_count_target = numitems // 8 + 1 if numitems % 8 != 0 else numitems // 8
431+ self ._block_count_target = _block_count_target + 2 # because the cmd line and option line.
432+
433+ self ._block_current_cmd = line [:4 ].upper ()
255434 self .start_non_interactive ()
256435 self .store_run_command (line )
257436 elif self .use_function_names :
@@ -274,10 +453,18 @@ def start_function(self, func_name):
274453 self .lines .append (line )
275454 self .indent = self .indent + " "
276455
277- def store_run_command (self , command ):
456+ def store_under_scored_run_command (self , command ):
457+ self .store_run_command (command , run_underscored = True )
458+
459+ def store_run_command (self , command , run_underscored = False ):
278460 """Stores pyansys.ANSYS command that cannot be broken down
279461 into a function and parameters.
280462 """
463+ if run_underscored :
464+ underscore = '_'
465+ else :
466+ underscore = ''
467+
281468 if self ._infunction and "ARG" in command :
282469 args = []
283470 for i in range (1 , 19 ):
@@ -288,22 +475,24 @@ def store_run_command(self, command):
288475 args .append (arg )
289476 c += 1
290477
291- line = '%s%s.run ("%s".format(%s))' % (
478+ line = '%s%s.%srun ("%s".format(%s))' % (
292479 self .indent ,
293480 self .obj_name ,
481+ underscore ,
294482 command ,
295483 ", " .join (args ),
296484 )
297485
298486 elif self .comment :
299- line = '%s%s.run ("%s") # %s' % (
487+ line = '%s%s.%srun ("%s") # %s' % (
300488 self .indent ,
301489 self .obj_name ,
490+ underscore ,
302491 command ,
303492 self .comment ,
304493 )
305494 else :
306- line = '%s%s.run ("%s")' % (self .indent , self .obj_name , command )
495+ line = '%s%s.%srun ("%s")' % (self .indent , self .obj_name , underscore , command )
307496 self .lines .append (line )
308497
309498 def store_comment (self ):
@@ -355,3 +544,41 @@ def end_non_interactive(self):
355544 if self ._non_interactive_level == 0 :
356545 self .non_interactive = False
357546 self .indent = self .indent [4 :]
547+
548+ def output_to_file (self , line ):
549+ """Return if an APDL line is redirecting to a file."""
550+ if line [:4 ].upper () == '/OUT' :
551+ # We are redirecting the output to somewhere, probably a file.
552+ # Because of the problem with the ansys output, we need to execute
553+ # this in non_interactive mode.
554+ output_cmd = line .strip ().upper ().split (',' )
555+ if len (output_cmd ) > 1 :
556+ opt1 = output_cmd [1 ].strip ().upper ()
557+ if opt1 != 'TERM' :
558+ # A file is supplied.
559+ return True
560+
561+ if line [:4 ].upper () == '*CFO' : # any([each[0:4] in '*CFOPEN' for each in dir(Commands)])
562+ # We might not need going into interactive mode for *CFOPEN/*CFCLOSE
563+ return True
564+
565+ return False
566+
567+ def output_to_default (self , line ):
568+ if line [:4 ].upper () == '/OUT' :
569+ # We are redirecting the output to somewhere, probably a file.
570+ # Because of the problem with the ansys output, we need to execute
571+ # this in non_interactive mode.
572+ output_cmd = line .strip ().upper ().split (',' )
573+ if len (output_cmd ) == 1 :
574+ return True
575+ elif len (output_cmd ) > 1 :
576+ opt1 = output_cmd [1 ].strip ().upper ()
577+ if opt1 == 'TERM' :
578+ # A file is supplied.
579+ return True
580+ if line [:4 ].upper () in '*CFCLOSE' :
581+ # We might not need going into interactive mode for *CFOPEN/*CFCLOSE
582+ return True
583+
584+ return False
0 commit comments