:py:mod:`cubnm.sim.rww`
######################

.. py:module:: cubnm.sim.rww


.. autoapisummary::

   cubnm.sim.rww.rWWSimGroup




.. py:class:: rWWSimGroup(*args, do_fic=True, max_fic_trials=0, I_SAMPLING_START=1000, I_SAMPLING_END=10000, init_delta=0.02, fic_penalty_scale=0.5, **kwargs)


   Bases: :py:obj:`cubnm.sim.base.SimGroup`

   Group of reduced Wong-Wang (excitatory-inhibitory) simulations that are executed in parallel.

   Parameters
   ---------
   do_fic: :obj:`bool`
       whether to apply feedback inhibition control. If provided wIE parameters will be ignored
   max_fic_trials: :obj:`int`
       maximum number of numerical FIC trials. If set to 0, FIC will be done only analytically
   I_SAMPLING_START: :obj:`int`
       starting time of numerical FIC I_E sampling (msec)
   I_SAMPLING_END: :obj:`int`
       end time of numerical FIC I_E sampling (msec)
   init_delta: :obj:`float`
       initial delta for numerical FIC adjustment
   fic_penalty_scale: :obj:`float`
       how much deviation from FIC target mean rE of 3 Hz is penalized. Set to 0 to disable FIC penalty.
   *args, **kwargs:
       see :class:`cubnm.sim.SimGroup` for details

   Attributes
   ----------
   param_lists: :obj:`dict` of :obj:`np.ndarray`
       dictionary of parameter lists, including
           - ``'G'``: global coupling strength. Shape: (N_SIMS,)
           - ``'w_p'``: local excitatory recurrence. Shape: (N_SIMS, nodes)
           - ``'J_N'``: synaptic coupling strength. Shape: (N_SIMS, nodes)
           - ``'wIE'``: inhibitory to excitatory weight. Shape: (N_SIMS, nodes)
           - ``'sigma'``: noise amplitude. Shape: (N_SIMS, nodes)
           - ``'v'``: conduction velocity. Shape: (N_SIMS,)

   Equations
   ---------
   .. math::

       \begin{gather}
       I_i^E=W^EI_b+w_i^{p} J_i^{N} S_i^E+GJ_i^{N}\sum_{j}{C_{ij}S_j^E}-w_i^{IE}S_i^I \\
       I_i^I=W^II_b+J_i^{N}S_i^E-w^{II}S_i^I \\
       r_i^E=H^E(I_i^E)\ =\frac{a^EI_i^E-b^E}{1\ -\ e^{-d^E(a^EI_i^E-b^E)}} \\
       r_i^I=H^I(I_i^I)\ =\frac{a^II_i^I-b^I}{1\ -\ e^{-d^I(a^II_i^I-b^I)}} \\
       \dot{S_i^E}=-\frac{S_i^E}{\tau_E}+(1\ -\ S_i^E)\gamma r_i^E(t)+\sigma_i\epsilon_i^E \\
       \dot{S_i^I}=-\frac{S_i^I}{\tau_I}+r_i^I+\sigma_i\epsilon_i^I \\
       \end{gather}

   References
   ----------        
   * Deco et al. 2014 Journal of Neuroscience (10.1523/JNEUROSCI.5068-13.2014)
   * Demirtas et al. 2019 Neuron (10.1016/j.neuron.2019.01.017)
   * Deco et al. 2018 Current Biology (10.1016/j.cub.2018.07.083)

   .. py:attribute:: model_name
      :value: 'rWW'

      

   .. py:attribute:: global_param_names
      :value: ['G']

      

   .. py:attribute:: regional_param_names
      :value: ['w_p', 'J_N', 'wIE', 'sigma']

      

   .. py:attribute:: state_names
      :value: ['I_E', 'I_I', 'r_E', 'r_I', 'S_E', 'S_I']

      

   .. py:attribute:: sel_state_var
      :value: 'r_E'

      

   .. py:attribute:: n_noise
      :value: 2

      

   .. py:attribute:: default_params

      

   .. py:method:: get_config(*args, **kwargs)

      Get the configuration of the simulation group

      Parameters
      ----------
      include_N: :obj:`bool`
          include N in the output config
          is ignored when for_reinit is True
      for_reinit: :obj:`bool`
          include the parameters that need reinitialization of the
          simulation core session if changed

      Returns
      -------
      config: :obj:`dict`
          dictionary of simulation group configuration


   .. py:method:: _process_out(out)

      Assigns model outputs (as arrays) to object attributes
      with correct shapes, names and types.

      Parameters
      ----------
      out: :obj:`tuple`
          output of ``cubnm._core.run_simulations`` function

      Notes
      -----
      The simulation outputs are assigned to the following object attributes:

      - init_time: :obj:`float`
          initialization time of the simulations
      - run_time: :obj:`float`
          run time of the simulations
      - sim_bold: :obj:`np.ndarray`
          simulated BOLD time series. Shape: (N_SIMS, duration/TR, nodes)
      - sim_states: :obj:`dict` of :obj:`np.ndarray`
          simulated state variables with keys as state names
          and values as arrays with the shape (N_SIMS, nodes)
          when ``states_ts`` is False, and (N_SIMS, duration/TR, nodes)
          when ``states_ts`` is True

      If ``do_fc`` is ``True``, additionally includes:

      - sim_fc_trils: :obj:`np.ndarray`
          simulated FC lower triangle. Shape: (N_SIMS, n_pairs)

      If ``do_fcd`` is ``True``, additionally includes:

      - sim_fcd_trils: :obj:`np.ndarray`
          simulated FCD lower triangle. Shape: (N_SIMS, n_window_pairs)


   .. py:method:: score(emp_fc_tril=None, emp_fcd_tril=None, emp_bold=None, **kwargs)

      Calculates individual goodness-of-fit terms and aggregates them.
      In FIC models also calculates fic_penalty. Note that while 
      FIC penalty is included in the cost function of optimizer, 
      it is not included in the aggregate GOF.

      Parameters
      --------
      emp_fc_tril: :obj:`np.ndarray`
          1D array of empirical FC lower triangle. Shape: (edges,)
      emp_fcd_tril: :obj:`np.ndarray`
          1D array of empirical FCD lower triangle. Shape: (window_pairs,)
      emp_bold: :obj:`np.ndarray` or None
          cleaned and parcellated empirical BOLD time series. Shape: (nodes, volumes)
          Motion outliers should either be excluded (not recommended as it disrupts
          the temporal structure) or replaced with zeros.
          If provided emp_fc_tril and emp_fcd_tril will be ignored.
      **kwargs:
          keyword arguments passed to `cubnm.sim.SimGroup.score`

      Returns
      -------
      scores: :obj:`pd.DataFrame`
          The goodness of fit measures (columns) of each simulation (rows)


   .. py:method:: _get_save_data()

      Get the simulation outputs and parameters to be saved to disk

      Returns
      -------
      out_data: :obj:`dict`
          dictionary of simulation outputs and parameters


   .. py:method:: _problem_init(problem)

      Extends BNMProblem initialization and includes FIC penalty
      if indicated.

      Parameters
      ----------
      problem: :obj:`cubnm.optimize.BNMProblem`
          optimization problem object


   .. py:method:: _problem_evaluate(problem, X, out, *args, **kwargs)

      Extends BNMProblem evaluation and includes FIC penalty
      in the cost function if indicated.

      Parameters
      ----------
      X: :obj:`np.ndarray`
          the normalized parameters of current population in range [0, 1]. 
          Shape: (N, ndim)
      out: :obj:`dict`
          the output dictionary to store the results with keys ``'F'`` and ``'G'``.
          Currently only ``'F'`` (cost) is used.
      *args, **kwargs


   .. py:method:: _get_test_configs(cpu_gpu_identity=False)
      :classmethod:

      Get configs for testing the simulations

      Parameters
      ----------
      cpu_gpu_identity: :obj:`bool`
          indicates whether configs are for CPU/GPU identity tests
          in which case force_cpu is not included in the configs
          since tests will be done on both CPU and GPU

      Returns
      -------
      configs: :obj:`dict` of :obj:`list`


   .. py:method:: _get_test_instance(opts)
      :classmethod:

      Initializes an instance that is used in tests

      Parameters
      ----------
      opts: :obj:`dict`
          dictionary of test options

      Returns
      -------
      sim_group: :obj:`cubnm.sim.rWWSimGroup`
          simulation group object of the test simulation
          which is not run yet


   .. py:method:: post_init()

      Post-initilaization hook that normally does nothing, but
      can be overridden in derived classes to add custom
      post-initialization steps.


   .. py:method:: _check_dt()

      Check if integrations steps are valid


   .. py:method:: _set_default_params(missing=True)

      Set default parameters for the simulations.

      Parameters
      ----------
      missing: :obj:`bool`, optional
          If True (default), only sets parameters that are currently None
          or have an incorrect length in self.param_lists. 
          If False, always overwrites all listed defaults.


   .. py:method:: run(force_reinit=False)

      Run the simulations in parallel (as possible) on GPU/CPU
      through the :func:`cubnm._core.run_simulations` function which runs
      compiled C++/CUDA code.

      Parameters
      ----------
      force_reinit: :obj:`bool`
          force reinitialization of the session.
          At the beginning of each session (when `cubnm` is imported)
          some variables are initialized on CPU/GPU and reused in
          every run. Set this to True if you want to reinitialize
          these variables. This is rarely needed.


   .. py:method:: get_state_averages()

      Get the averages of state variables across time and nodes
      for each simulation.

      Returns
      -------
      state_averages: :obj:`pd.DataFrame`
          DataFrame of state averages with columns as state names
          and rows as simulations


   .. py:method:: get_noise()

      Get the (recreated) noise time series. This requires recreation
      of the noise array if noise segmenting is on. Noise will be
      recreated based on shuffling indices of nodes and time steps,
      similar to how it is done in the core code.

      Returns
      -------
      noise: :obj:`np.ndarray`
          Noise segment array. Shape: (n_noise, nodes, bw_it, inner_it)


   .. py:method:: get_sim_fc(idx)

      Get the simulated FC of a given simulation ``idx``
      as a square matrix.

      Parameters
      ----------
      idx: :obj:`int`
          index of the simulation to get the FC for

      Returns
      -------
      fc: :obj:`np.ndarray`
          simulated FC matrix of shape (nodes, nodes)
          for the simulation with index ``idx``


   .. py:method:: get_sim_fcd(idx)

      Get the simulated FCD of a given simulation ``idx``
      as a square matrix.

      Parameters
      ----------
      idx: :obj:`int`
          index of the simulation to get the FC for

      Returns
      -------
      fcd: :obj:`np.ndarray`
          simulated FC matrix of shape (n_windows, n_windows)
          for the simulation with index ``idx``


   .. py:method:: slice(key, inplace=False)

      Slice the simulation group to a single simulation

      Parameters
      ----------
      key: :obj:`int`
          index of the simulation to slice
      inplace: :obj:`bool`
          the object will be sliced in place
          and therefore the data of other simulations
          will be removed. Otherwise a new object
          copied from the current object will be returned.

      Returns
      -------
      obj: :obj:`cubnm.sim.SimGroup`
          sliced simulation group


   .. py:method:: clear()

      Clear the simulation outputs


   .. py:method:: save()

      Save simulation outputs to disk as an npz file.



