# Buggy code
def network_run(
    self,
    net,
    duration,
    report=None,
    report_period=10 * second,
    namespace=None,
    profile=False,
    level=0,
    **kwds,
):
    if kwds:
        logger.warn(
            ("Unsupported keyword argument(s) provided for run: %s")
            % ", ".join(kwds.keys())
        )
    # We store this as an instance variable for later access by the
    # `code_object` method
    self.enable_profiling = profile
    all_objects = net.sorted_objects
    net._clocks = {obj.clock for obj in all_objects}
    t_end = net.t + duration
    for clock in net._clocks:
        clock.set_interval(net.t, t_end)

    # Get the local namespace
    if namespace is None:
        namespace = get_local_namespace(level=level + 2)

    net.before_run(namespace)

    self.clocks.update(net._clocks)
    net.t_ = float(t_end)

    # TODO: remove this horrible hack
    for clock in self.clocks:
        if clock.name == "clock":
            clock._name = "_clock"

    # Extract all the CodeObjects
    # Note that since we ran the Network object, these CodeObjects will be sorted into the right
    # running order, assuming that there is only one clock
    code_objects = []
    for obj in all_objects:
        if obj.active:
            for codeobj in obj._code_objects:
                code_objects.append((obj.clock, codeobj))

    # Code for a progress reporting function
    standard_code = """
        std::string _format_time(float time_in_s)
        {
            float divisors[] = {24*60*60, 60*60, 60, 1};
            char letters[] = {'d', 'h', 'm', 's'};
            float remaining = time_in_s;
            std::string text = "";
            int time_to_represent;
            for (int i =0; i < sizeof(divisors)/sizeof(float); i++)
            {
                time_to_represent = int(remaining / divisors[i]);
                remaining -= time_to_represent * divisors[i];
                if (time_to_represent > 0 || text.length())
                {
                    if(text.length() > 0)
                    {
                        text += " ";
                    }
                    text += (std::to_string(time_to_represent)+letters[i]);
                }
            }
            //less than one second
            if(text.length() == 0) 
            {
                text = "< 1s";
            }
            return text;
        }
        void report_progress(const double elapsed, const double completed, const double start, const double duration)
        {
            if (completed == 0.0)
            {
                %STREAMNAME% << "Starting simulation at t=" << start << " s for duration " << duration << " s";
            } else
            {
                %STREAMNAME% << completed*duration << " s (" << (int)(completed*100.) << "%) simulated in " << _format_time(elapsed);
                if (completed < 1.0)
                {
                    const int remaining = (int)((1-completed)/completed*elapsed+0.5);
                    %STREAMNAME% << ", estimated " << _format_time(remaining) << " remaining.";
                }
            }

            %STREAMNAME% << std::endl << std::flush;
        }
        """
    if report is None:
        report_func = ""
    elif report == "text" or report == "stdout":
        report_func = standard_code.replace("%STREAMNAME%", "std::cout")
    elif report == "stderr":
        report_func = standard_code.replace("%STREAMNAME%", "std::cerr")
    elif isinstance(report, str):
        report_func = """
            void report_progress(const double elapsed, const double completed, const double start, const double duration)
            {
            %REPORT%
            }
            """.replace("%REPORT%", report)
    else:
        raise TypeError(
            (
                'report argument has to be either "text", '
                '"stdout", "stderr", or the code for a report '
                "function"
            )
        )

    if report_func != "":
        if self.report_func != "" and report_func != self.report_func:
            raise NotImplementedError(
                "The C++ standalone device does not "
                "support multiple report functions, "
                "each run has to use the same (or "
                "none)."
            )
        self.report_func = report_func

    if report is not None:
        report_call = "report_progress"
    else:
        report_call = "NULL"

    # Generate the updaters
    run_lines = ["{net.name}.clear();".format(net=net)]
    all_clocks = set()
    for clock, codeobj in code_objects:
        run_lines.append(
            "{net.name}.add(&{clock.name}, _run_{codeobj.name});".format(
                clock=clock, net=net, codeobj=codeobj
            )
        )
        all_clocks.add(clock)

    # Under some rare circumstances (e.g. a NeuronGroup only defining a
    # subexpression that is used by other groups (via linking, or recorded
    # by a StateMonitor) *and* not calculating anything itself *and* using a
    # different clock than all other objects) a clock that is not used by
    # any code object should nevertheless advance during the run. We include
    # such clocks without a code function in the network.
    for clock in net._clocks:
        if clock not in all_clocks:
            run_lines.append(
                "{net.name}.add(&{clock.name}, NULL);".format(clock=clock, net=net)
            )

    run_lines.append(
        "{net.name}.run({duration!r}, {report_call}, {report_period!r});".format(
            net=net,
            duration=float(duration),
            report_call=report_call,
            report_period=float(report_period),
        )
    )
    self.main_queue.append(("run_network", (net, run_lines)))

    # Manually set the cache for the clocks, simulation scripts might
    # want to access the time (which has been set in code and is therefore
    # not accessible by the normal means until the code has been built and
    # run)
    for clock in net._clocks:
        self.array_cache[clock.variables["timestep"]] = np.array([clock._i_end])
        self.array_cache[clock.variables["t"]] = np.array([clock._i_end * clock.dt_])

    if self.build_on_run:
        if self.has_been_run:
            raise RuntimeError(
                "The network has already been built and run "
                "before. Use set_device with "
                "build_on_run=False and an explicit "
                "device.build call to use multiple run "
                "statements with this device."
            )
        self.build(direct_call=False, **self.build_options)


# Traceback (jinja2.exceptions.UndefinedError)
ERROR      Brian 2 encountered an unexpected error. If you think this is bug in Brian 2, please report this issue either to the mailing list at <http://groups.google.com/group/brian-development/>, or to the issue tracker at <https://github.com/brian-team/brian2/issues>. Please include this file with debug information in your report: /var/folders/_n/ml20bf7n0_g3sz165pd3nrjm0000gn/T/brian_debug_1uynejn5.log  Additionally, you can also include a copy of the script that was run, available at: /var/folders/_n/ml20bf7n0_g3sz165pd3nrjm0000gn/T/brian_script_m_84dmg4.py You can also include a copy of the redirected std stream outputs, available at /var/folders/_n/ml20bf7n0_g3sz165pd3nrjm0000gn/T/brian_stdout_d2yd1ugv.log and /var/folders/_n/ml20bf7n0_g3sz165pd3nrjm0000gn/T/brian_stderr_xkxqltw0.log Thanks! [brian2]
Traceback (most recent call last):
File "/Users/fpbatta/src/assembly_sequences/scripts/run_simulation_simple.py", line 69, in <module>
nn1 = network_sim()
File "/Users/fpbatta/src/assembly_sequences/scripts/run_simulation_simple.py", line 59, in network_sim
bb.get_device().build(directory='PETH_standalone', compile=True, run=True, debug=False)
File "/Users/fpbatta/.conda/envs/brian23/lib/python3.8/site-packages/brian2/devices/cpp_standalone/device.py", line 1265, in build
self.generate_objects_source(self.writer, self.arange_arrays,
File "/Users/fpbatta/.conda/envs/brian23/lib/python3.8/site-packages/brian2/devices/cpp_standalone/device.py", line 633, in generate_objects_source
arr_tmp = self.code_object_class().templater.objects(
File "/Users/fpbatta/.conda/envs/brian23/lib/python3.8/site-packages/brian2/codegen/templates.py", line 210, in __call__
return MultiTemplate(module)
File "/Users/fpbatta/.conda/envs/brian23/lib/python3.8/site-packages/brian2/codegen/templates.py", line 226, in __init__
s = autoindent_postfilter(str(f()))
File "/Users/fpbatta/.conda/envs/brian23/lib/python3.8/site-packages/jinja2/runtime.py", line 675, in __call__
return self._invoke(arguments, autoescape)
File "/Users/fpbatta/.conda/envs/brian23/lib/python3.8/site-packages/jinja2/runtime.py", line 679, in _invoke
rv = self._func(*arguments)
File "/Users/fpbatta/.conda/envs/brian23/lib/python3.8/site-packages/brian2/devices/cpp_standalone/templates/objects.cpp", line 122, in macro
if(f{{name}}.is_open())
File "/Users/fpbatta/.conda/envs/brian23/lib/python3.8/site-packages/jinja2/runtime.py", line 747, in _fail_with_undefined_error
raise self._undefined_exception(self._undefined_message)
jinja2.exceptions.UndefinedError: dict object has no element <DynamicArrayVariable(dimensions=Dimension(),  dtype=int32, scalar=False, constant=True, read_only=True)>

# Fixed code
def network_run(
    self,
    net,
    duration,
    report=None,
    report_period=10 * second,
    namespace=None,
    profile=False,
    level=0,
    **kwds,
):
    self.networks.add(net)
    if kwds:
        logger.warn(
            ("Unsupported keyword argument(s) provided for run: %s")
            % ", ".join(kwds.keys())
        )
    # We store this as an instance variable for later access by the
    # `code_object` method
    self.enable_profiling = profile
    all_objects = net.sorted_objects
    net._clocks = {obj.clock for obj in all_objects}
    t_end = net.t + duration
    for clock in net._clocks:
        clock.set_interval(net.t, t_end)

    # Get the local namespace
    if namespace is None:
        namespace = get_local_namespace(level=level + 2)

    net.before_run(namespace)

    self.clocks.update(net._clocks)
    net.t_ = float(t_end)

    # TODO: remove this horrible hack
    for clock in self.clocks:
        if clock.name == "clock":
            clock._name = "_clock"

    # Extract all the CodeObjects
    # Note that since we ran the Network object, these CodeObjects will be sorted into the right
    # running order, assuming that there is only one clock
    code_objects = []
    for obj in all_objects:
        if obj.active:
            for codeobj in obj._code_objects:
                code_objects.append((obj.clock, codeobj))

    # Code for a progress reporting function
    standard_code = """
        std::string _format_time(float time_in_s)
        {
            float divisors[] = {24*60*60, 60*60, 60, 1};
            char letters[] = {'d', 'h', 'm', 's'};
            float remaining = time_in_s;
            std::string text = "";
            int time_to_represent;
            for (int i =0; i < sizeof(divisors)/sizeof(float); i++)
            {
                time_to_represent = int(remaining / divisors[i]);
                remaining -= time_to_represent * divisors[i];
                if (time_to_represent > 0 || text.length())
                {
                    if(text.length() > 0)
                    {
                        text += " ";
                    }
                    text += (std::to_string(time_to_represent)+letters[i]);
                }
            }
            //less than one second
            if(text.length() == 0) 
            {
                text = "< 1s";
            }
            return text;
        }
        void report_progress(const double elapsed, const double completed, const double start, const double duration)
        {
            if (completed == 0.0)
            {
                %STREAMNAME% << "Starting simulation at t=" << start << " s for duration " << duration << " s";
            } else
            {
                %STREAMNAME% << completed*duration << " s (" << (int)(completed*100.) << "%) simulated in " << _format_time(elapsed);
                if (completed < 1.0)
                {
                    const int remaining = (int)((1-completed)/completed*elapsed+0.5);
                    %STREAMNAME% << ", estimated " << _format_time(remaining) << " remaining.";
                }
            }

            %STREAMNAME% << std::endl << std::flush;
        }
        """
    if report is None:
        report_func = ""
    elif report == "text" or report == "stdout":
        report_func = standard_code.replace("%STREAMNAME%", "std::cout")
    elif report == "stderr":
        report_func = standard_code.replace("%STREAMNAME%", "std::cerr")
    elif isinstance(report, str):
        report_func = """
            void report_progress(const double elapsed, const double completed, const double start, const double duration)
            {
            %REPORT%
            }
            """.replace("%REPORT%", report)
    else:
        raise TypeError(
            (
                'report argument has to be either "text", '
                '"stdout", "stderr", or the code for a report '
                "function"
            )
        )

    if report_func != "":
        if self.report_func != "" and report_func != self.report_func:
            raise NotImplementedError(
                "The C++ standalone device does not "
                "support multiple report functions, "
                "each run has to use the same (or "
                "none)."
            )
        self.report_func = report_func

    if report is not None:
        report_call = "report_progress"
    else:
        report_call = "NULL"

    # Generate the updaters
    run_lines = ["{net.name}.clear();".format(net=net)]
    all_clocks = set()
    for clock, codeobj in code_objects:
        run_lines.append(
            "{net.name}.add(&{clock.name}, _run_{codeobj.name});".format(
                clock=clock, net=net, codeobj=codeobj
            )
        )
        all_clocks.add(clock)

    # Under some rare circumstances (e.g. a NeuronGroup only defining a
    # subexpression that is used by other groups (via linking, or recorded
    # by a StateMonitor) *and* not calculating anything itself *and* using a
    # different clock than all other objects) a clock that is not used by
    # any code object should nevertheless advance during the run. We include
    # such clocks without a code function in the network.
    for clock in net._clocks:
        if clock not in all_clocks:
            run_lines.append(
                "{net.name}.add(&{clock.name}, NULL);".format(clock=clock, net=net)
            )

    run_lines.append(
        "{net.name}.run({duration!r}, {report_call}, {report_period!r});".format(
            net=net,
            duration=float(duration),
            report_call=report_call,
            report_period=float(report_period),
        )
    )
    self.main_queue.append(("run_network", (net, run_lines)))

    # Manually set the cache for the clocks, simulation scripts might
    # want to access the time (which has been set in code and is therefore
    # not accessible by the normal means until the code has been built and
    # run)
    for clock in net._clocks:
        self.array_cache[clock.variables["timestep"]] = np.array([clock._i_end])
        self.array_cache[clock.variables["t"]] = np.array([clock._i_end * clock.dt_])

    if self.build_on_run:
        if self.has_been_run:
            raise RuntimeError(
                "The network has already been built and run "
                "before. Use set_device with "
                "build_on_run=False and an explicit "
                "device.build call to use multiple run "
                "statements with this device."
            )
        self.build(direct_call=False, **self.build_options)