def _run(self, duration, logf, logt, log_interval, report_nan, progress, msg): # Simulation times if duration < 0: raise Exception('Simulation duration can\'t be negative.') tmin = self._time tmax = tmin + duration # Gather global variables in fiber model gf = [] gt = [] for label in self._global: v = self._modelf.binding(label) if v is not None: gf.append(v.qname()) v = self._modelt.binding(label) if v is not None: gt.append(v.qname()) # Parse logf argument logf = myokit.prepare_log(logf, self._modelf, dims=self._ncellsf, global_vars=gf, if_empty=myokit.LOG_STATE + myokit.LOG_BOUND, allowed_classes=myokit.LOG_STATE + myokit.LOG_BOUND + myokit.LOG_INTER, precision=self._precision) # Parse logt argument logt = myokit.prepare_log(logt, self._modelt, dims=self._ncellst, global_vars=gt, if_empty=myokit.LOG_STATE + myokit.LOG_BOUND, allowed_classes=myokit.LOG_STATE + myokit.LOG_BOUND + myokit.LOG_INTER, precision=self._precision) # Create list of intermediary fiber variables that need to be logged inter_logf = [] vars_checked = set() for var in logf.keys(): var = myokit.split_key(var)[1] if var in vars_checked: continue vars_checked.add(var) var = self._modelf.get(var) if var.is_intermediary() and not var.is_bound(): inter_logf.append(var) # Create list of intermediary tissue variables that need to be logged inter_logt = [] vars_checked = set() for var in logt.keys(): var = myokit.split_key(var)[1] if var in vars_checked: continue vars_checked.add(var) var = self._modelt.get(var) if var.is_intermediary() and not var.is_bound(): inter_logt.append(var) # Get preferred platform/device combo from configuration file platform, device = myokit.OpenCL.load_selection_bytes() # Generate kernels kernel_file = os.path.join(myokit.DIR_CFUNC, KERNEL_FILE) args = { 'precision': self._precision, 'native_math': self._native_math, 'diffusion': True, 'fields': [], 'rl_states': {}, } args['model'] = self._modelf args['vmvar'] = self._vmf args['bound_variables'] = self._bound_variablesf args['inter_log'] = inter_logf args['paced_cells'] = self._paced_cells if myokit.DEBUG: print('-' * 79) print( self._code(kernel_file, args, line_numbers=myokit.DEBUG_LINE_NUMBERS)) else: kernelf = self._export(kernel_file, args) args['model'] = self._modelt args['vmvar'] = self._vmt args['bound_variables'] = self._bound_variablest args['inter_log'] = inter_logt args['paced_cells'] = [] if myokit.DEBUG: print('-' * 79) print( self._code(kernel_file, args, line_numbers=myokit.DEBUG_LINE_NUMBERS)) import sys sys.exit(1) else: kernelt = self._export(kernel_file, args) # Logging period (0 = disabled) log_interval = 1e-9 if log_interval is None else float(log_interval) if log_interval <= 0: log_interval = 1e-9 # Get progress indication function (if any) if progress is None: progress = myokit._Simulation_progress if progress: if not isinstance(progress, myokit.ProgressReporter): raise ValueError( 'The argument "progress" must be either a subclass of' ' myokit.ProgressReporter or None.') # Run simulation if duration > 0: # Initialize state_inf = self._statef state_int = self._statet state_outf = list(state_inf) state_outt = list(state_int) self._sim.sim_init( platform, device, kernelf, kernelt, self._ncellsf[0], self._ncellsf[1], self._ncellst[0], self._ncellst[1], self._vmf.indice(), self._vmt.indice(), self._gf[0], self._gf[1], self._gt[0], self._gt[1], self._gft, self._cfx, self._ctx, self._cty, tmin, tmax, self._step_size, state_inf, state_int, state_outf, state_outt, self._protocol, logf, logt, log_interval, [x.qname().encode('ascii') for x in inter_logf], [x.qname().encode('ascii') for x in inter_logt], ) try: t = tmin if progress: # Loop with feedback with progress.job(msg): r = 1.0 / duration if duration != 0 else 1 while t < tmax: t = self._sim.sim_step() if t < tmin: # A numerical error has occurred. break if not progress.update(min((t - tmin) * r, 1)): raise myokit.SimulationCancelledError() else: # Loop without feedback while t < tmax: t = self._sim.sim_step() if t < tmin: # A numerical error has occurred. break finally: # Clean even after KeyboardInterrupt or other Exception self._sim.sim_clean() # Update states self._statef = state_outf self._statet = state_outt # Check for NaN's, print error output if report_nan and (logf.has_nan() or logt.has_nan()): txt = ['Numerical error found in simulation logs.'] try: # NaN encountered, show how it happened part, time, icell, var, value, states, bound = self.find_nan( logf, logt) model = self._modelt if part == 'tissue' else self._modelf txt.append('Encountered numerical error in ' + part + ' simulation at t=' + str(time) + ' in cell (' + ','.join([str(x) for x in icell]) + ') when ' + var + '=' + str(value) + '.') n_states = len(states) txt.append('Obtained ' + str(n_states) + ' previous state(s).') if n_states > 1: txt.append('State before:') txt.append(model.format_state(states[1])) txt.append('State during:') txt.append(model.format_state(states[0])) if n_states > 1: txt.append('Evaluating derivatives at state before...') try: derivs = model.eval_state_derivatives( states[1], precision=self._precision) txt.append( model.format_state_derivatives(states[1], derivs)) except myokit.NumericalError as ee: txt.append(str(ee)) except myokit.FindNanError as e: txt.append( 'Unable to pinpoint source of NaN, an error occurred:') txt.append(str(e)) raise myokit.SimulationError('\n'.join(txt)) # Return logs return logf, logt
def _run(self, duration, log, log_interval, report_nan, progress, msg): # Simulation times if duration < 0: raise Exception('Simulation time can\'t be negative.') tmin = self._time tmax = tmin + duration # Gather global variables in model g = [] for label in self._global: v = self._model.binding(label) if v is not None: g.append(v.qname()) # Parse log argument log = myokit.prepare_log(log, self._model, dims=self._dims, global_vars=g, if_empty=myokit.LOG_STATE + myokit.LOG_BOUND, allowed_classes=myokit.LOG_STATE + myokit.LOG_INTER + myokit.LOG_BOUND, precision=self._precision) # Create list of intermediary variables that need to be logged inter_log = [] vars_checked = set() for var in log.iterkeys(): var = myokit.split_key(var)[1] if var in vars_checked: continue vars_checked.add(var) var = self._model.get(var) if var.is_intermediary() and not var.is_bound(): inter_log.append(var) # Get preferred platform/device combo from configuration file platform, device = myokit.OpenCL.load_selection() # Compile template into string with kernel code kernel_file = os.path.join(myokit.DIR_CFUNC, KERNEL_FILE) args = { 'model': self._model, 'precision': self._precision, 'native_math': self._native_math, 'bound_variables': self._bound_variables, 'inter_log': inter_log, 'diffusion': self._diffusion_enabled, 'fields': self._fields.keys(), 'paced_cells': self._paced_cells, } if myokit.DEBUG: print('-' * 79) print( self._code(kernel_file, args, line_numbers=myokit.DEBUG_LINE_NUMBERS)) import sys sys.exit(1) kernel = self._export(kernel_file, args) # Logging period (0 = disabled) log_interval = 1e-9 if log_interval is None else float(log_interval) if log_interval <= 0: log_interval = 1e-9 # Create field values vector n = len(self._fields) * self._nx * self._ny if n: field_data = self._fields.itervalues() field_data = [np.array(x, copy=False) for x in field_data] field_data = np.vstack(field_data) field_data = list(field_data.reshape(n, order='F')) else: field_data = [] # Get progress indication function (if any) if progress is None: progress = myokit._Simulation_progress if progress: if not isinstance(progress, myokit.ProgressReporter): raise ValueError( 'The argument "progress" must be either a subclass of' ' myokit.ProgressReporter or None.') # Run simulation arithmetic_error = False if duration > 0: # Initialize state_in = self._state state_out = list(state_in) self._sim.sim_init( platform, device, kernel, self._nx, self._ny, self._diffusion_enabled, self._gx, self._gy, self._connections, tmin, tmax, self._step_size, state_in, state_out, self._protocol, log, log_interval, [x.qname() for x in inter_log], field_data, ) t = tmin try: if progress: # Loop with feedback with progress.job(msg): r = 1.0 / duration if duration != 0 else 1 while t < tmax: t = self._sim.sim_step() if not progress.update(min((t - tmin) * r, 1)): raise myokit.SimulationCancelledError() else: # Loop without feedback while t < tmax: t = self._sim.sim_step() except ArithmeticError: arithmetic_error = True finally: # Clean even after KeyboardInterrupt or other Exception self._sim.sim_clean() # Update state self._state = state_out # Check for NaN if report_nan and (arithmetic_error or log.has_nan()): txt = ['Numerical error found in simulation logs.'] try: # NaN encountered, show how it happened time, icell, var, value, states, bound = self.find_nan(log) txt.append('Encountered numerical error at t=' + str(time) + ' in cell (' + ','.join([str(x) for x in icell]) + ') when ' + var + '=' + str(value) + '.') n_states = len(states) txt.append('Obtained ' + str(n_states) + ' previous state(s).') if n_states > 1: txt.append('State before:') txt.append(self._model.format_state(states[1])) txt.append('State during:') txt.append(self._model.format_state(states[0])) if n_states > 1: txt.append('Evaluating derivatives at state before...') try: derivs = self._model.eval_state_derivatives( states[1], precision=self._precision) txt.append( self._model.format_state_derivs(states[1], derivs)) except myokit.NumericalError as ee: txt.append(ee.message) except myokit.FindNanError as e: txt.append( 'Unable to pinpoint source of NaN, an error occurred:') txt.append(e.message) raise myokit.SimulationError('\n'.join(txt)) # Return log return log