@@ -277,63 +277,80 @@ def compile(
277277 else :
278278 self ._compiler_options .add (compiler_options )
279279
280- compilation_failed = False
281- with TemporaryCopiedFile (self ._stan_file ) as (stan_file , is_copied ):
282- exe_file , _ = os .path .splitext (os .path .abspath (stan_file ))
283- exe_file = Path (exe_file ).as_posix () + EXTENSION
284- do_compile = True
285- if os .path .exists (exe_file ):
286- src_time = os .path .getmtime (self ._stan_file )
287- exe_time = os .path .getmtime (exe_file )
288- if exe_time > src_time and not force :
289- do_compile = False
290- self ._logger .info ('found newer exe file, not recompiling' )
291-
292- if do_compile :
293- self ._logger .info (
294- 'compiling stan program, exe file: %s' , exe_file
295- )
296- if self ._compiler_options is not None :
297- self ._compiler_options .validate ()
280+ # check if exe file exists in original location
281+ exe_file , _ = os .path .splitext (os .path .abspath (self ._stan_file ))
282+ exe_file = Path (exe_file ).as_posix () + EXTENSION
283+ do_compile = True
284+ if os .path .exists (exe_file ):
285+ src_time = os .path .getmtime (self ._stan_file )
286+ exe_time = os .path .getmtime (exe_file )
287+ if exe_time > src_time and not force :
288+ do_compile = False
289+ self ._logger .info ('found newer exe file, not recompiling' )
290+ self ._exe_file = exe_file
291+ self ._logger .info ('compiled model file: %s' , self ._exe_file )
292+ if do_compile :
293+ compilation_failed = False
294+ with TemporaryCopiedFile (self ._stan_file ) as (stan_file , is_copied ):
295+ exe_file , _ = os .path .splitext (os .path .abspath (stan_file ))
296+ exe_file = Path (exe_file ).as_posix () + EXTENSION
297+ do_compile = True
298+ if os .path .exists (exe_file ):
299+ src_time = os .path .getmtime (self ._stan_file )
300+ exe_time = os .path .getmtime (exe_file )
301+ if exe_time > src_time and not force :
302+ do_compile = False
303+ self ._logger .info (
304+ 'found newer exe file, not recompiling'
305+ )
306+
307+ if do_compile :
298308 self ._logger .info (
299- 'compiler options : %s' , self . _compiler_options
309+ 'compiling stan program, exe file : %s' , exe_file
300310 )
301- make = os .getenv (
302- 'MAKE' ,
303- 'make'
304- if platform .system () != 'Windows'
305- else 'mingw32-make' ,
306- )
307- cmd = [make ]
308- if self ._compiler_options is not None :
309- cmd .extend (self ._compiler_options .compose ())
310- cmd .append (Path (exe_file ).as_posix ())
311- try :
312- do_command (cmd , cmdstan_path (), logger = self ._logger )
313- except RuntimeError as e :
314- self ._logger .error (
315- 'file %s, exception %s' , stan_file , str (e )
311+ if self ._compiler_options is not None :
312+ self ._compiler_options .validate ()
313+ self ._logger .info (
314+ 'compiler options: %s' , self ._compiler_options
315+ )
316+ make = os .getenv (
317+ 'MAKE' ,
318+ 'make'
319+ if platform .system () != 'Windows'
320+ else 'mingw32-make' ,
316321 )
317- compilation_failed = True
322+ cmd = [make ]
323+ if self ._compiler_options is not None :
324+ cmd .extend (self ._compiler_options .compose ())
325+ cmd .append (Path (exe_file ).as_posix ())
326+ try :
327+ do_command (cmd , cmdstan_path (), logger = self ._logger )
328+ except RuntimeError as e :
329+ self ._logger .error (
330+ 'file %s, exception %s' , stan_file , str (e )
331+ )
332+ compilation_failed = True
318333
319- if not compilation_failed :
320- if is_copied :
321- original_target_dir = os .path .dirname (
322- os .path .abspath (self ._stan_file )
323- )
324- new_exec_name = (
325- os .path .basename (os .path .splitext (self ._stan_file )[0 ])
326- + EXTENSION
327- )
328- self ._exe_file = os .path .join (
329- original_target_dir , new_exec_name
330- )
331- shutil .copy (exe_file , self ._exe_file )
334+ if not compilation_failed :
335+ if is_copied :
336+ original_target_dir = os .path .dirname (
337+ os .path .abspath (self ._stan_file )
338+ )
339+ new_exec_name = (
340+ os .path .basename (
341+ os .path .splitext (self ._stan_file )[0 ]
342+ )
343+ + EXTENSION
344+ )
345+ self ._exe_file = os .path .join (
346+ original_target_dir , new_exec_name
347+ )
348+ shutil .copy (exe_file , self ._exe_file )
349+ else :
350+ self ._exe_file = exe_file
351+ self ._logger .info ('compiled model file: %s' , self ._exe_file )
332352 else :
333- self ._exe_file = exe_file
334- self ._logger .info ('compiled model file: %s' , self ._exe_file )
335- else :
336- self ._logger .error ('model compilation failed' )
353+ self ._logger .error ('model compilation failed' )
337354
338355 def optimize (
339356 self ,
@@ -473,7 +490,10 @@ def optimize(
473490 self ._run_cmdstan (runset , dummy_chain_id )
474491
475492 if not runset ._check_retcodes ():
476- msg = 'Error during optimization.\n {}' .format (runset .get_err_msgs ())
493+ msg = 'Error during optimization:\n {}' .format (runset .get_err_msgs ())
494+ msg = '{}Command and output files:\n {}' .format (
495+ msg , runset .__repr__ ()
496+ )
477497 raise RuntimeError (msg )
478498 mle = CmdStanMLE (runset )
479499 return mle
@@ -820,7 +840,6 @@ def sample(
820840 dynamic_ncols = False
821841 else :
822842 dynamic_ncols = True
823-
824843 pbar = tqdm_pbar (
825844 desc = 'Chain {} - warmup' .format (i + 1 ),
826845 position = i ,
@@ -838,7 +857,10 @@ def sample(
838857 self ._logger .propagate = True
839858
840859 if not runset ._check_retcodes ():
841- msg = 'Error during sampling.\n {}' .format (runset .get_err_msgs ())
860+ msg = 'Error during sampling:\n {}' .format (runset .get_err_msgs ())
861+ msg = '{}Command and output files:\n {}' .format (
862+ msg , runset .__repr__ ()
863+ )
842864 raise RuntimeError (msg )
843865
844866 mcmc = CmdStanMCMC (runset , validate_csv , logger = self ._logger )
@@ -990,9 +1012,12 @@ def generate_quantities(
9901012 executor .submit (self ._run_cmdstan , runset , i )
9911013
9921014 if not runset ._check_retcodes ():
993- msg = 'Error during generate_quantities. \n {}' .format (
1015+ msg = 'Error during generate_quantities: \n {}' .format (
9941016 runset .get_err_msgs ()
9951017 )
1018+ msg = '{}Command and output files:\n {}' .format (
1019+ msg , runset .__repr__ ()
1020+ )
9961021 raise RuntimeError (msg )
9971022 quantities = CmdStanGQ (runset = runset , mcmc_sample = sample_drawset )
9981023 return quantities
@@ -1149,9 +1174,12 @@ def variational(
11491174 if require_converged and not valid :
11501175 raise RuntimeError ('The algorithm may not have converged.' )
11511176 if not runset ._check_retcodes ():
1152- msg = 'Error during variational inference. \n {}' .format (
1177+ msg = 'Error during variational inference: \n {}' .format (
11531178 runset .get_err_msgs ()
11541179 )
1180+ msg = '{}Command and output files:\n {}' .format (
1181+ msg , runset .__repr__ ()
1182+ )
11551183 raise RuntimeError (msg )
11561184 # pylint: disable=invalid-name
11571185 vb = CmdStanVB (runset )
@@ -1170,26 +1198,48 @@ def _run_cmdstan(
11701198 'threads: %s' , str (os .environ .get ('STAN_NUM_THREADS' ))
11711199 )
11721200 self ._logger .debug ('sampling: %s' , cmd )
1173- proc = subprocess .Popen (
1174- cmd ,
1175- stdin = subprocess .DEVNULL ,
1176- stdout = subprocess .PIPE ,
1177- stderr = subprocess .PIPE ,
1178- env = os .environ ,
1179- )
1180- if pbar :
1181- stdout_pbar = self ._read_progress (proc , pbar , idx )
1182- stdout , stderr = proc .communicate ()
1183- if pbar :
1184- stdout = stdout_pbar + stdout
1185- self ._logger .info ('finish chain %u' , idx + 1 )
1186- if stdout :
1187- with open (runset .stdout_files [idx ], 'w+' ) as fd :
1188- fd .write (stdout .decode ('utf-8' ))
1189- if stderr :
1190- with open (runset .stderr_files [idx ], 'w+' ) as fd :
1191- fd .write (stderr .decode ('utf-8' ))
1192- runset ._set_retcode (idx , proc .returncode )
1201+ try :
1202+ proc = subprocess .Popen (
1203+ cmd ,
1204+ stdin = subprocess .DEVNULL ,
1205+ stdout = subprocess .PIPE ,
1206+ stderr = subprocess .PIPE ,
1207+ env = os .environ ,
1208+ )
1209+ if pbar :
1210+ stdout_pbar = self ._read_progress (proc , pbar , idx )
1211+ stdout , stderr = proc .communicate ()
1212+ if pbar :
1213+ stdout = stdout_pbar + stdout
1214+
1215+ self ._logger .info ('finish chain %u' , idx + 1 )
1216+ runset ._set_retcode (idx , proc .returncode )
1217+ if stdout :
1218+ with open (runset .stdout_files [idx ], 'w+' ) as fd :
1219+ fd .write (stdout .decode ('utf-8' ))
1220+ console_error = ''
1221+ if stderr :
1222+ console_error = stderr .decode ('utf-8' )
1223+ with open (runset .stderr_files [idx ], 'w+' ) as fd :
1224+ fd .write (console_error )
1225+
1226+ if proc .returncode != 0 :
1227+ if proc .returncode < 0 :
1228+ msg = 'Chain {} terminated by signal {}' .format (
1229+ idx + 1 , proc .returncode
1230+ )
1231+ else :
1232+ msg = 'Chain {} processing error' .format (idx + 1 )
1233+ msg = '{}, non-zero return code {}' .format (
1234+ msg , proc .returncode
1235+ )
1236+ if len (console_error ) > 0 :
1237+ msg = '{}\n error message:\n \t {}' .format (msg , console_error )
1238+ self ._logger .error (msg )
1239+
1240+ except OSError as e :
1241+ msg = 'Chain {} encounted error: {}\n ' .format (idx + 1 , str (e ))
1242+ raise RuntimeError (msg ) from e
11931243
11941244 def _read_progress (
11951245 self , proc : subprocess .Popen , pbar : Any , idx : int
0 commit comments