import numpy as np
try:
from vbi.models.cpp._src.km_sde import KM_sde as _KM_sde
except ImportError as e:
print(f"Could not import modules: {e}, probably C++ code is not compiled or properly linked.")
[docs]
class KM_sde:
'''
Kuramoto model with noise (sde), C++ implementation.
Parameters
----------
par : dict
Dictionary of parameters.
'''
valid_parameters = [
"G", # global coupling strength
"dt", # time step
"noise_amp", # noise amplitude
"omega", # natural angular frequency
"weights", # weighted connection matrix
"noise_seed", # fix random seed for noise in Cpp code
"seed",
"alpha", # frustration matrix
"t_initial", # initial time
"t_transition", # transition time
"t_end", # end time
"output", # output directory
"num_threads", # number of threads using openmp
"initial_state",
"type" # output times series data type
]
[docs]
def __init__(self, par) -> None:
self.check_parameters(par)
self._par = self.get_default_parameters()
self._par.update(par)
for item in self._par.items():
name = item[0]
value = item[1]
setattr(self, name, value)
assert (self.omega is not None)
if self.seed is not None:
np.random.seed(self.seed)
self.num_nodes = len(self.omega)
if self.initial_state is None:
self.INITIAL_STATE_SET = False
[docs]
def set_initial_state(self):
self.INITIAL_STATE_SET = True
self.initial_state = set_initial_state(self.num_nodes, self.seed)
def __str__(self) -> str:
print("Kuramoto model with noise (sde), C++ implementation.")
print("----------------")
for item in self._par.items():
name = item[0]
value = item[1]
print(f"{name} = {value}")
return ""
def __call__(self):
return self._par
[docs]
def get_default_parameters(self):
return {
"G": 1.0, # global coupling strength
"dt": 0.01, # time step
"noise_amp": 0.1, # noise amplitude
"weights": None, # weighted connection matrix
"alpha": None, # frustration matrix
"omega": None, # natural angular frequency
"noise_seed": 0, # fix random seed for noise in Cpp code
"seed": None, # fix random seed for initial state
"t_initial": 0.0, # initial time
"t_transition": 0.0, # transition time
"t_end": 100.0, # end time
"num_threads": 1, # number of threads using openmp
"output": "output", # output directory
"initial_state": None, # initial state
"type": np.float32
}
[docs]
def check_parameters(self, par):
for key in par.keys():
if key not in self.valid_parameters:
raise ValueError(f"Invalid parameter: {key}")
[docs]
def run(self, par={}, x0=None, verbose=False):
'''
Simulate the model.
Parameters
----------
par : dict
Dictionary of parameters.
x0 : array
Initial state.
verbose : bool
Print simulation progress.
Returns
-------
dict
t : array
Time points.
x : array
State time series.
'''
if x0 is None:
if not self.INITIAL_STATE_SET:
self.set_initial_state()
if verbose:
print("initial state set by default")
else:
assert (len(x0) == self.num_nodes)
self.initial_state = x0
self.INITIAL_STATE_SET = True
for key in par.keys():
if key not in self.valid_parameters:
raise ValueError(f"Invalid parameter {key:s} provided.")
else:
setattr(self, key, par[key]['value'])
self.prepare_input()
obj = _KM_sde(self.dt,
self.t_initial,
self.t_transition,
self.t_end,
self.G,
self.noise_amp,
self.initial_state,
self.omega,
self.alpha,
self.weights,
self.noise_seed,
self.num_threads
)
obj.IntegrateHeun()
t = np.asarray(obj.get_times())
x = np.asarray(obj.get_theta()).T.astype(self.type)
return {"t": t, "x": x}
[docs]
def set_initial_state(num_nodes, seed=None):
if seed is not None:
np.random.seed(seed)
return np.random.uniform(0, 2*np.pi, num_nodes)