sagesim 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
sagesim-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Oak Ridge National Laboratory
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
sagesim-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,77 @@
1
+ Metadata-Version: 2.2
2
+ Name: sagesim
3
+ Version: 0.1.0
4
+ Summary: Scalable Agent-based GPU Enabled Simulator.
5
+ Author-email: Chathika Gunaratne <chathikagunaratne@gmail.com>
6
+ Maintainer-email: Chathika Gunaratne <chathikagunaratne@gmail.com>
7
+ License: MIT License
8
+
9
+ Copyright (c) 2024 Oak Ridge National Laboratory
10
+
11
+ Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ of this software and associated documentation files (the "Software"), to deal
13
+ in the Software without restriction, including without limitation the rights
14
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ copies of the Software, and to permit persons to whom the Software is
16
+ furnished to do so, subject to the following conditions:
17
+
18
+ The above copyright notice and this permission notice shall be included in all
19
+ copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ SOFTWARE.
28
+
29
+ Project-URL: Repository, https://github.com/ornl/sagesim.git
30
+ Keywords: agent-based,hpc,gpu
31
+ Requires-Python: >=3.11
32
+ Description-Content-Type: text/markdown
33
+ License-File: LICENSE
34
+ Requires-Dist: awkward==2.7.4
35
+ Requires-Dist: cupy_cuda12x==13.3.0
36
+ Requires-Dist: mpi4py==4.0.3
37
+ Requires-Dist: networkx==3.4.2
38
+ Requires-Dist: numpy==2.2.3
39
+ Requires-Dist: ragged==0.2.0
40
+ Requires-Dist: setuptools==75.8.0
41
+
42
+ # SAGESim
43
+
44
+ Scalable Agent-based GPU Enabled Simulator
45
+
46
+ # Requirements
47
+
48
+ - Python 3.7+
49
+ - `conda create -n sagesimenv python=3.9`
50
+ - `conda activate sagesimenv`
51
+ - Install CUDA toolkit
52
+ - - https://developer.nvidia.com/cuda-toolkit
53
+ - - https://rocm.docs.amd.com/projects/install-on-linux/en/docs-6.0.2/
54
+ - - [Install using Anaconda](`conda install -c anaconda cudatoolkit`)
55
+ - install mpi4py (Recommend using conda): https://mpi4py.readthedocs.io/en/stable/install.html#using-conda
56
+ - [Follow the instructions here to install CuPy](https://docs.cupy.dev/en/stable/install.html)
57
+ - `pip install -r requirements.txt`
58
+
59
+ # Run Example
60
+
61
+ - `git clone https://code.ornl.gov/sagesim/sagesim`
62
+ - `export PYTHONPATH=/path/to/clone_repo`
63
+ - `cd /path/to/clone_repo/examples/sir`
64
+ - `mpiexec -n 4 python run.py`
65
+
66
+
67
+ # There are some unfortunate quirks to using CuPyx `jit.rawkernel`:
68
+ - nan checked by inequality to self. Unfortunate limitation of cupyx.
69
+ - Dicts and objects are unsupported.
70
+ - *args and **kwargs are unsupported.
71
+ - nested functions are unsupported.
72
+ - Be sure to use `cupy` data types and array routines in favor of `numpy`: [https://docs.cupy.dev/en/stable/reference/routines.html]
73
+ - `for` loops must use range iterator only. No 'for each' style loops.
74
+ - `return` does not seem to work well either
75
+ - `break` and `continue` are unsupported!
76
+ - Cannot reassign variables within `if` or `for` statements. Must be assigned at top level of function or new variable declared under subscope.
77
+ - `-1` indexing does not necessarily work as expected, as it will access the last element of the memory block of the array instead of the logical array. Use `len(my_array) - 1` instead
@@ -0,0 +1,36 @@
1
+ # SAGESim
2
+
3
+ Scalable Agent-based GPU Enabled Simulator
4
+
5
+ # Requirements
6
+
7
+ - Python 3.7+
8
+ - `conda create -n sagesimenv python=3.9`
9
+ - `conda activate sagesimenv`
10
+ - Install CUDA toolkit
11
+ - - https://developer.nvidia.com/cuda-toolkit
12
+ - - https://rocm.docs.amd.com/projects/install-on-linux/en/docs-6.0.2/
13
+ - - [Install using Anaconda](`conda install -c anaconda cudatoolkit`)
14
+ - install mpi4py (Recommend using conda): https://mpi4py.readthedocs.io/en/stable/install.html#using-conda
15
+ - [Follow the instructions here to install CuPy](https://docs.cupy.dev/en/stable/install.html)
16
+ - `pip install -r requirements.txt`
17
+
18
+ # Run Example
19
+
20
+ - `git clone https://code.ornl.gov/sagesim/sagesim`
21
+ - `export PYTHONPATH=/path/to/clone_repo`
22
+ - `cd /path/to/clone_repo/examples/sir`
23
+ - `mpiexec -n 4 python run.py`
24
+
25
+
26
+ # There are some unfortunate quirks to using CuPyx `jit.rawkernel`:
27
+ - nan checked by inequality to self. Unfortunate limitation of cupyx.
28
+ - Dicts and objects are unsupported.
29
+ - *args and **kwargs are unsupported.
30
+ - nested functions are unsupported.
31
+ - Be sure to use `cupy` data types and array routines in favor of `numpy`: [https://docs.cupy.dev/en/stable/reference/routines.html]
32
+ - `for` loops must use range iterator only. No 'for each' style loops.
33
+ - `return` does not seem to work well either
34
+ - `break` and `continue` are unsupported!
35
+ - Cannot reassign variables within `if` or `for` statements. Must be assigned at top level of function or new variable declared under subscope.
36
+ - `-1` indexing does not necessarily work as expected, as it will access the last element of the memory block of the array instead of the logical array. Use `len(my_array) - 1` instead
File without changes
File without changes
@@ -0,0 +1,120 @@
1
+ from time import time
2
+ import argparse
3
+ from sir_model import SIRModel
4
+ from state import SIRState
5
+ from mpi4py import MPI
6
+
7
+ from random import sample
8
+
9
+ import networkx as nx
10
+
11
+ comm = MPI.COMM_WORLD
12
+ num_workers = comm.Get_size()
13
+ worker = comm.Get_rank()
14
+
15
+
16
+ def generate_small_world_network(n, k, p):
17
+ """
18
+ Generate a small world network using the Watts-Strogatz model.
19
+
20
+ Parameters:
21
+ - n (int): The number of nodes in the network.
22
+ - k (int): Each node is connected to its k nearest neighbors in a ring topology.
23
+ - p (float): The probability of rewiring each edge.
24
+
25
+ Returns:
26
+ - networkx.Graph: The generated small world network.
27
+ """
28
+ return nx.watts_strogatz_graph(n, k, p)
29
+
30
+
31
+ def test_network():
32
+ network = nx.Graph()
33
+ network.add_nodes_from(range(8))
34
+ network.add_edges_from(
35
+ [(0, 1), (0, 4), (2, 3), (3, 4), (4, 5), (4, 7), (6, 5), (7, 6)]
36
+ )
37
+
38
+ for n in network.nodes:
39
+ if n == 0:
40
+ model.create_agent(SIRState.INFECTED.value)
41
+ else:
42
+ model.create_agent(SIRState.SUSCEPTIBLE.value)
43
+
44
+ for edge in network.edges:
45
+ model.connect_agents(edge[0], edge[1])
46
+ print(edge[0], "->", edge[1])
47
+ return model
48
+
49
+
50
+ def generate_small_world_of_agents(
51
+ model, num_agents: int, num_init_connections: int, num_infected: int
52
+ ) -> SIRModel:
53
+ network = generate_small_world_network(num_agents, num_init_connections, 0.2)
54
+ for n in network.nodes:
55
+ model.create_agent(SIRState.SUSCEPTIBLE.value)
56
+
57
+ for n in sample(sorted(network.nodes), num_infected):
58
+ model.set_agent_property_value(n, "state", SIRState.INFECTED.value)
59
+
60
+ for edge in network.edges:
61
+ model.connect_agents(edge[0], edge[1])
62
+ return model
63
+
64
+
65
+ if __name__ == "__main__":
66
+
67
+ parser = argparse.ArgumentParser()
68
+ parser.add_argument(
69
+ "--num_agents",
70
+ type=int,
71
+ )
72
+ parser.add_argument(
73
+ "--percent_init_connections",
74
+ type=float,
75
+ )
76
+ parser.add_argument(
77
+ "--num_nodes",
78
+ type=int,
79
+ )
80
+ args = parser.parse_args()
81
+
82
+ model = SIRModel()
83
+ model.setup(use_gpu=True)
84
+ num_agents = args.num_agents
85
+ num_init_connections = int(args.percent_init_connections * num_agents)
86
+ num_nodes = args.num_nodes
87
+
88
+ model_creation_start = time()
89
+ model = generate_small_world_of_agents(
90
+ model, num_agents, num_init_connections, int(0.1 * num_agents)
91
+ ) # test_network() #
92
+ model_creation_end = time()
93
+ model_creation_duration = model_creation_end - model_creation_start
94
+ """print(
95
+ [
96
+ SIRState(model.get_agent_property_value(agent_id, property_name="state"))
97
+ for agent_id in range(n_agents)
98
+ ]
99
+ )"""
100
+
101
+ simulate_start = time()
102
+ model.simulate(10, sync_workers_every_n_ticks=2)
103
+ simulate_end = time()
104
+ simulate_duration = simulate_end - simulate_start
105
+
106
+ if worker == 0:
107
+ with open("execution_times.csv", "a") as f:
108
+ f.write(
109
+ f"{num_agents}, {num_init_connections}, {num_nodes}, {num_workers}, {model_creation_duration}, {simulate_duration}\n"
110
+ )
111
+
112
+ if worker == 0:
113
+ print(
114
+ [
115
+ SIRState(
116
+ model.get_agent_property_value(agent_id, property_name="state")
117
+ )
118
+ for agent_id in range(num_agents)
119
+ ]
120
+ )
@@ -0,0 +1,42 @@
1
+ from random import random
2
+
3
+ from sagesim.breed import Breed
4
+ from state import SIRState
5
+ from cupyx import jit
6
+
7
+ global INFECTED
8
+ INFECTED = SIRState.INFECTED.value
9
+ global SUSCEPTIBLE
10
+ SUSCEPTIBLE = SIRState.SUSCEPTIBLE.value
11
+
12
+
13
+ class SIRBreed(Breed):
14
+
15
+ def __init__(self) -> None:
16
+ name = "SIR"
17
+ super().__init__(name)
18
+ self.register_property("state", SIRState.SUSCEPTIBLE.value)
19
+ self.register_step_func(step_func)
20
+
21
+
22
+ def step_func(id, id2index, globals, breeds, locations, states):
23
+ # agent_index = step_func_helper_get_agent_index(id, id2index)
24
+ # nan checked by inequality to self. Unfortunate limitation of cupyx
25
+ if (id == id) and (id2index[int(id)] == id2index[int(id)]):
26
+ agent_index = int(id2index[int(id)])
27
+
28
+ neighbors = locations[agent_index] # network location is defined by neighbors
29
+ rand = random() # 0.1#step_func_helper_get_random_float(rng_states, id)
30
+
31
+ p_infection = globals[1]
32
+
33
+ for i in range(len(neighbors)):
34
+ neighbor_id = neighbors[i]
35
+ # neighbor_index = step_func_helper_get_agent_index(neighbor_id, id2index)
36
+ if (neighbor_id == neighbor_id) and (
37
+ id2index[int(neighbor_id)] == id2index[int(neighbor_id)]
38
+ ):
39
+ neighbor_index = int(id2index[int(neighbor_id)])
40
+ neighbor_state = states[neighbor_index]
41
+ if neighbor_state == 2 and rand < p_infection:
42
+ states[agent_index] = 2
@@ -0,0 +1,22 @@
1
+ from sagesim.model import Model
2
+ from sagesim.space import NetworkSpace
3
+ from sir_breed import SIRBreed
4
+ from state import SIRState
5
+
6
+
7
+ class SIRModel(Model):
8
+
9
+ def __init__(self, p_infection=0.5) -> None:
10
+ space = NetworkSpace()
11
+ super().__init__(space)
12
+ self._sir_breed = SIRBreed()
13
+ self.register_breed(breed=self._sir_breed)
14
+ self.register_global_property("p_infection", p_infection)
15
+
16
+ def create_agent(self, state):
17
+ agent_id = self.create_agent_of_breed(self._sir_breed, state=state)
18
+ self.get_space().add_agent(agent_id)
19
+ return agent_id
20
+
21
+ def connect_agents(self, agent_0, agent_1):
22
+ self.get_space().connect_agents(agent_0, agent_1)
@@ -0,0 +1,7 @@
1
+ from enum import Enum
2
+
3
+
4
+ class SIRState(Enum):
5
+ SUSCEPTIBLE = 1
6
+ INFECTED = 2
7
+ RECOVERED = 3
@@ -0,0 +1,66 @@
1
+
2
+
3
+ from random import random
4
+
5
+ from cupyx import jit
6
+
7
+
8
+
9
+
10
+ import cupy as cp
11
+ import math
12
+
13
+ @jit.rawkernel(device='cuda')
14
+ def step_func(id, id2index, globals, breeds, locations, states):
15
+ # agent_index = step_func_helper_get_agent_index(id, id2index)
16
+ # nan checked by inequality to self. Unfortunate limitation of cupyx
17
+ if (id == id) and (id2index[int(id)] == id2index[int(id)]):
18
+ agent_index = int(id2index[int(id)])
19
+
20
+ neighbors = locations[agent_index] # network location is defined by neighbors
21
+ rand = random() # 0.1#step_func_helper_get_random_float(rng_states, id)
22
+
23
+ p_infection = globals[1]
24
+
25
+ for i in range(len(neighbors)):
26
+ neighbor_id = neighbors[i]
27
+ # neighbor_index = step_func_helper_get_agent_index(neighbor_id, id2index)
28
+ if (neighbor_id == neighbor_id) and (
29
+ id2index[int(neighbor_id)] == id2index[int(neighbor_id)]
30
+ ):
31
+ neighbor_index = int(id2index[int(neighbor_id)])
32
+ neighbor_state = states[neighbor_index]
33
+ if neighbor_state == 2 and rand < p_infection:
34
+ states[agent_index] = 2
35
+
36
+
37
+
38
+ @jit.rawkernel()
39
+ def stepfunc(
40
+ device_global_data_vector,
41
+ a0,a1,a2,
42
+ sync_workers_every_n_ticks,
43
+ agent_ids,
44
+ agents_index_in_subcontext,
45
+ ):
46
+ thread_id = jit.blockIdx.x * jit.blockDim.x + jit.threadIdx.x
47
+ #g = cuda.cg.this_grid()
48
+ agent_id = thread_id
49
+ if agent_id < agent_ids.shape[0]:
50
+ breed_id = a0[agent_id]
51
+ for tick in range(sync_workers_every_n_ticks):
52
+
53
+
54
+ if breed_id == 0:
55
+ step_func(
56
+ agent_id,
57
+ agents_index_in_subcontext,
58
+ device_global_data_vector,
59
+ a0,a1,a2,
60
+ )
61
+ #cuda.syncthreads()
62
+
63
+
64
+ if thread_id == 0:
65
+ device_global_data_vector[0] += 1
66
+
@@ -0,0 +1,36 @@
1
+ [build-system]
2
+ requires = ["setuptools >= 75.8.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "sagesim"
7
+ version = "0.1.0"
8
+ dependencies = [
9
+ "awkward==2.7.4",
10
+ "cupy_cuda12x==13.3.0",
11
+ "mpi4py==4.0.3",
12
+ "networkx==3.4.2",
13
+ "numpy==2.2.3",
14
+ "ragged==0.2.0",
15
+ "setuptools==75.8.0",
16
+ ]
17
+ requires-python = ">=3.11"
18
+ authors = [
19
+ {name = "Chathika Gunaratne", email = "chathikagunaratne@gmail.com"}
20
+ ]
21
+ maintainers = [
22
+ {name = "Chathika Gunaratne", email = "chathikagunaratne@gmail.com"}
23
+ ]
24
+
25
+ description = "Scalable Agent-based GPU Enabled Simulator."
26
+
27
+ readme = "README.md"
28
+ license = {file = "LICENSE", type = "text/plain"}
29
+
30
+ keywords = ["agent-based", "hpc", "gpu"]
31
+
32
+ [tool.setuptools.packages.find]
33
+ where = ["."]
34
+
35
+ [project.urls]
36
+ Repository = "https://github.com/ornl/sagesim.git"
File without changes