From cd3aed11fa9709ec1500d6e70506577a7d7c8b4b Mon Sep 17 00:00:00 2001 From: Robert Chisholm Date: Fri, 29 Sep 2023 11:08:08 +0100 Subject: [PATCH] Improvements suggested by Bytetec (#161) * Remove redundant z variable from tutorial. * Add more context to enabling agent death. * Add more detail to clarify host fns are not launched by agent fns. * Moved environment macro property introduction. Left a shorter intro at the original location. * Add more submodel detail/example usage. * Add sphinxcontrib.mermaid dependency. The plugin was failing to include the JS automatically, so manually set static js to CDN. Enable mermaid's neutral theme * Add mermaid overview diagram with a quick summary of the components. * Change model diagram to top down (from left-right) Reordering message/agent seems to have fixed the overlap (or maybe its just page width). --- requirements.txt | 1 + src/conf.py.in | 14 ++++++-- .../agent-functions/agent-birth-death.rst | 8 +++-- src/guide/agent-functions/index.rst | 3 ++ src/guide/creating-a-model/index.rst | 33 +++++++++++++++++++ .../defining-execution-order/submodels.rst | 2 ++ src/guide/environment/index.rst | 5 +-- .../defining-host-functions.rst | 2 ++ src/guide/host-functions/index.rst | 2 ++ src/tutorial/index.rst | 5 --- 10 files changed, 64 insertions(+), 11 deletions(-) diff --git a/requirements.txt b/requirements.txt index 8f42da5d2..03c3cb5ae 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,3 +5,4 @@ exhale sphinx_rtd_theme sphinx_tabs sphinx-copybutton +sphinxcontrib-mermaid diff --git a/src/conf.py.in b/src/conf.py.in index 455b2eab2..7c1b3f272 100644 --- a/src/conf.py.in +++ b/src/conf.py.in @@ -38,7 +38,8 @@ html_logo = "@RELPATH_CONFIG_TO_STATIC@/img/flamegpu2-icon-notext-128.png" extensions = [ 'sphinx_tabs.tabs', 'sphinx_copybutton', - 'sphinx.ext.graphviz' + 'sphinx.ext.graphviz', + 'sphinxcontrib.mermaid' ] # If the @@ -49,7 +50,8 @@ if @USE_BREATHE_EXHALE@: 'exhale', 'sphinx_tabs.tabs', 'sphinx_copybutton', - 'sphinx.ext.graphviz' + 'sphinx.ext.graphviz', + 'sphinxcontrib.mermaid' ] # Setup the breathe extension @@ -138,3 +140,11 @@ html_static_path = ['@RELPATH_CONFIG_TO_STATIC@'] html_css_files = [ 'css/flamegpu.css', ] + +# Mermaid sphinx extension is failing to auto include mermaid.js +html_js_files = [ + 'https://unpkg.com/mermaid@10.4.0/dist/mermaid.js' +] + +# Config params passed to mermaid +mermaid_init_js = "mermaid.initialize({startOnLoad:true,theme: 'neutral'});" diff --git a/src/guide/agent-functions/agent-birth-death.rst b/src/guide/agent-functions/agent-birth-death.rst index 7e0e447a3..882f1d55e 100644 --- a/src/guide/agent-functions/agent-birth-death.rst +++ b/src/guide/agent-functions/agent-birth-death.rst @@ -14,20 +14,24 @@ Enabling Agent Death ==================== By default in FLAME GPU 2 agents do not die. To enable death for a particular agent function, use the :func:`setAllowAgentDeath()` method of -the :class:`AgentFunctionDescription` object: +the :class:`AgentFunctionDescription` that you would like to enable death for: .. tabs:: .. code-tab:: cpp C++ + flamegpu::AgentFunctionDescription agent_fn1_description = agent.newFunction("agent_fn1", agent_fn1); // Allow agent_fn1 to kill agents agent_fn1_description.setAllowAgentDeath(true); .. code-tab:: py Python - + + agent_fn1_description = agent.newRTCFunction("agent_fn1", agent_fn1_source); # Allow agent_fn1 to kill agents agent_fn1_description.setAllowAgentDeath(True) +When this agent function is then added to a layer or dependency graph, it will support agent death. + Killing Agents via Agent Functions ================================== diff --git a/src/guide/agent-functions/index.rst b/src/guide/agent-functions/index.rst index bf2c52285..dbf730d8f 100644 --- a/src/guide/agent-functions/index.rst +++ b/src/guide/agent-functions/index.rst @@ -28,3 +28,6 @@ This chapter has been broken up into several sections: random-numbers.rst conditional-behaviours.rst miscellaneous.rst + +.. note:: + If you require a function that operates at a population or global scope you should use :ref`Host Functions`, these are distinct from Agent Functions and cannot be launched from agent functions. diff --git a/src/guide/creating-a-model/index.rst b/src/guide/creating-a-model/index.rst index cf0c8184b..fdc635499 100644 --- a/src/guide/creating-a-model/index.rst +++ b/src/guide/creating-a-model/index.rst @@ -11,6 +11,39 @@ What is a Model? In FLAME GPU 2, a model is represented by a :class:`ModelDescription` object, this contains information specifying the agents, messages and environment properties within the model and how they interact. +The hierarchy of a :class:`ModelDescription` is shown below. + +.. mermaid:: + + graph TD; + %%Simulation-->Population; + %%Simulation-->Model; + Model-->Agent; + Model-->Message; + Model-->Environment; + Model-->Layer; + Model-->e["Init/Step/Exit Function"]; + Message-->Variable; + Agent-->a["Variable"]; + Agent-->b["Agent Function"]; + Agent-->State; + Environment-->Property; + Environment-->MacroProperty; + %%Environment-->StaticGraph; + Layer-->c[Agent Function]; + Layer-->d[Host Function]; + Layer-->SubModel; + +:ref:`Agents` are the executors of primary model behaviour. All agents of the same type and state execute in parallel, where they can update their internal variables based on messages from other agents and the environment's properties. + +:ref:`Messages` are what agents share to communicate with one another. Due to the parallel nature of a FLAME GPU model, they must be input in a separate agent function to the one they are output from. There are a wide range of message types supported, to enable the most efficient communication strategy for any purpose. + +:ref:`The Environment` holds global state information in the form of properties and macro properties. The environment is primarily mutated via :ref:`host functions`, which execute serially at the global level. New to FLAME GPU 2, :ref:`macro properties` support upto 4-dimensional arrays and provide a limited set of mutators so that they can be updated during agent functions. + +:ref:`Layers` are FLAME GPUs original method of defining the control flow of a model, layers are each executed in sequence and all functions within a layer may execute in parallel. FLAME GPU 2 alternatively provides a new intuitive :ref:`dependency graph API`, where instead dependencies between functions are defined, the layers are then automatically generated based on the dependencies. Additionally, FLAME GPU 2 introduces the concept of :ref:`submodels` which allow iterative algorithms (typically parallel conflict resolution) to be modelled within a single model step by nesting a model with shared agents. + +:ref:`Init, Step and Exit functions` are host functions which execute either at the start of the simulation, end of each step or after the simulation has finished. Otherwise, they are exactly the same as host functions attached to layers or the dependency graph. Additionally, FLAME GPU 2 provides a specialised :ref:`Exit Condition` host function, which can end a simulation early if a user-defined condition is met. + Once the :class:`ModelDescription` has been completely described, it is used to construct either a :class:`CUDASimulation` or :class:`CUDAEnsemble` to execute simulations of the model. diff --git a/src/guide/defining-execution-order/submodels.rst b/src/guide/defining-execution-order/submodels.rst index 192f20760..68092104f 100644 --- a/src/guide/defining-execution-order/submodels.rst +++ b/src/guide/defining-execution-order/submodels.rst @@ -2,6 +2,8 @@ Submodels ^^^^^^^^^ +Submodels allow FLAME GPU 2 models to contain nested models, this is particularly useful for models which contain iterative algorithms. Submodels were originally developed to enable a biological model to use an iterative cell-cell mechanical model, which would have otherwise have been difficult to implement with layers or a dependency graph. + A submodel acts as a full model nested inside a parent model, the only requirement is that the submodel contains atleast one :ref:`exit condition`. Agent variables can be mapped between the two models, with each model also having private agent variables (or even private agents). The agent ID of bound agents will always be mapped. Unbound agents which are recreated in each time the submodel is executed are not guaranteed to have the same ID between runs. Environment properties can also be shared with submodels, with the ability to mark them as constant within the submodel. Where an agent variable is mapped between model and submodel, the parent model's default value will always be used when creating new agents. diff --git a/src/guide/environment/index.rst b/src/guide/environment/index.rst index f4c2d7607..568dffee0 100644 --- a/src/guide/environment/index.rst +++ b/src/guide/environment/index.rst @@ -9,8 +9,7 @@ Environment properties are read-only to agents, but may be updated by host funct Although initial values must be specified for environment properties, they can be overridden at model runtime with :ref:`various techniques`. -FLAME GPU 2 introduces environment macro properties, these are intended for larger environment properties which may have upto four dimensions. Environment macro properties, unlike regular environment properties, can be updated by agents with a limited collection of atomic backed methods. However, they also have additional limitations; they always default to zero, cannot be logged, and cannot make use of experimental GLM support. - +Distinct from environment properties, FLAME GPU 2 introduces environment macro properties, these are intended for larger environment properties which may have upto four dimensions and can be updated by agents with a limited collection of atomic backed methods. Accessing the EnvironmentDescription Object ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,6 +79,8 @@ For a full list of supported types, see :ref:`Supported Types`. Defining Macro Properties ^^^^^^^^^^^^^^^^^^^^^^^^^ +FLAME GPU 2 introduces environment macro properties, these are intended for larger environment properties which may have upto four dimensions. Environment macro properties, unlike regular environment properties, can be updated by agents with a limited collection of atomic backed methods. However, they also have additional limitations; they always default to zero, cannot be logged, and cannot make use of experimental GLM support. + In contrast to regular environment properties, environment macro properties are declared using the :func:`newMacroProperty()` method. These may have upto 4 dimensions (unused dimensions if left unspecified, will default to length 1). diff --git a/src/guide/host-functions/defining-host-functions.rst b/src/guide/host-functions/defining-host-functions.rst index 31b018334..4f96fb9b4 100644 --- a/src/guide/host-functions/defining-host-functions.rst +++ b/src/guide/host-functions/defining-host-functions.rst @@ -57,6 +57,8 @@ In the Python API a host function is defined as a subclass of :class:`HostFuncti Although python Host functions and conditions are classes, the class should not utilise any additional stateful information (e.g. `self`). When executed via ensembles, Python host function instances are shared between concurrent simulation runs, which may lead to race conditions where stateful information is present. +.. _Types of Host Function: + Types of Host Function ---------------------- diff --git a/src/guide/host-functions/index.rst b/src/guide/host-functions/index.rst index caf31a7ea..50ae697eb 100644 --- a/src/guide/host-functions/index.rst +++ b/src/guide/host-functions/index.rst @@ -8,6 +8,8 @@ Host functions, as suggested by their name, execute on the host rather than the In prior versions of FLAME GPU, host functions were restricted to executing as initialisation functions (once before the simulation), exit functions (once after the simulation) or step functions (once at the end of each step). FLAME GPU 2 now additionally allows host functions to execute among agent functions during a step. +Host functions when not used as init, exit or step functions, are added to either :ref:`layers` or a :ref:`dependency graph` to control when they execute similar to :ref:`agent functions`. They cannot be dynamically started from agent functions, rather in this case the host function should execute each iteration and perform a reduction of an agent population to check whether a condition passes. + Host conditions are host functions with a return value. Currently, their usage is limited to a model's exit conditions, for example if a model can fully resolve before the number of time steps specified. All content that refers to host functions in this chapter applies to host conditions too. This chapter has been broken up into several sections: diff --git a/src/tutorial/index.rst b/src/tutorial/index.rst index 62228c999..4b84d1ba4 100644 --- a/src/tutorial/index.rst +++ b/src/tutorial/index.rst @@ -307,7 +307,6 @@ The Circles model requires a location, so we can add three ``float`` variables t // Assign the agent some variables (ID is implicit to agents, so we don't define it ourselves) agent.newVariable("x"); agent.newVariable("y"); - agent.newVariable("z"); agent.newVariable("drift", 0.0f); ... @@ -321,7 +320,6 @@ The Circles model requires a location, so we can add three ``float`` variables t # Assign the agent some variables (ID is implicit to agents, so we don't define it ourselves) agent.newVariableFloat("x") agent.newVariableFloat("y") - agent.newVariableFloat("z") agent.newVariableFloat("drift", 0) ... @@ -1047,7 +1045,6 @@ If you have followed the complete tutorial, you should now have the following co // Assign the agent some variables (ID is implicit to agents, so we don't define it ourselves) agent.newVariable("x"); agent.newVariable("y"); - agent.newVariable("z"); agent.newVariable("drift", 0.0f); // Setup the two agent functions flamegpu::AgentFunctionDescription out_fn = agent.newFunction("output_message", output_message); @@ -1211,7 +1208,6 @@ If you have followed the complete tutorial, you should now have the following co # Assign the agent some variables (ID is implicit to agents, so we don't define it ourselves) agent.newVariableFloat("x") agent.newVariableFloat("y") - agent.newVariableFloat("z") agent.newVariableFloat("drift", 0) # Setup the two agent functions out_fn = agent.newRTCFunction("output_message", output_message) @@ -1308,7 +1304,6 @@ If you have followed the complete tutorial, you should now have the following co # Assign the agent some variables (ID is implicit to agents, so we don't define it ourselves) agent.newVariableFloat("x") agent.newVariableFloat("y") - agent.newVariableFloat("z") agent.newVariableFloat("drift", 0) # Define environment properties