LILAC
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
c_elegans.cpp
Go to the documentation of this file.
1 /*
2 Copyright (c) 2014, Sam Schetterer, Nathan Kutz, University of Washington
3 Authors: Sam Schetterer
4 All rights reserved.
5 
6 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
7 
8 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
9 
10 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
11 
12 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
13 
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15 
16 */
17 #include "c_elegans.h"
18 #include "engine/input.h"
19 #include "utils/comp_funcs.hpp"
20 #include "utils/item_heads.hpp"
21 #include "types/type_register.hpp"
22 #include <vector>
23 #include <fstream>
24 #include "gaba_list.hpp"
25 #include <eigen3/Eigen/Core>
26 #include "writer/writer.h"
27 #include "engine/engineimp.h"
28 #include "controller/controller.h"
29 bool next_comb(std::vector<size_t>& inval, size_t max_num){
30  class comb_helper{
31  public:
32  typedef std::vector<size_t>::iterator iter_t;
33  typedef std::vector<size_t>::const_iterator c_iter_t;
34  static bool do_next(iter_t cur, c_iter_t end, size_t max_num){
35  if(cur == end){
36  //test to ensure valid ptrs
37  //returns zero, since no ablations usually means something else is important
38  return false;
39  }
40  iter_t temp = cur;
41  temp++;
42  //increment current element;
43  (*cur)++;
44  if((*cur) >= max_num){
45  (*cur) = 0;
46  }
47  //if is at end
48  if(temp == end){
49  return (*cur) == 0;
50  }
51  //if the current value is now greater than
52  //or equal to the next, increment
53  //while loop allows bad inputs to reach valid combination states
54  //v[0] < v[1] < v[2] etc;
55  //also yes this has n^2 runtime. fortunately n is small, like around 4-5 at most
56  //and is called fairly rarely AND is simple
57  while(*cur >= *temp){
58  *cur = 0;
59  if(do_next(temp, end, max_num)){
60  return true;
61  }
62  }
63  return false;
64  }
65  };
66  return comb_helper::do_next(inval.begin(), inval.end(), max_num);
67 }
68 constexpr size_t c_elegans::num_neur;
69 constexpr size_t c_elegans::dim_v;
70 constexpr size_t c_elegans::dim_s;
71 template class type_register<c_elegans>;
72 int c_elegans::dxdt(ptr_passer x, ptr_passer dx, double dt){
73  has_gone=true;
74  double* restr v = x;
75  double* restr dv = dx;
76  double* restr ds = dv+dim_v;
77  double* restr s = v+dim_v;
78  //map eigen arrays over input pointers
79  Map<Array<double, dim_v, 1>> vmap(v);
80  Map<Array<double, dim_v, 1>> dvmap(dv);
81  Map<Array<double, dim_v, 1>> smap(s);
82  Map<Array<double, dim_v, 1>> dsmap(ds);
83  //calculations from matlab file
84  sig = 1.0 / (1.0 + (-1*beta*(vmap-vmean)).exp());
85  dsmap = ar*(sig * (1.0-smap)) - ad*smap;
86  /* Iohm = (memG*(vmap - memV));
87  Ielec = (gelec*laplacian*vmap.matrix()).array();
88  Ichem = (gchem *
89  (vmap*(AEchem_trans*smap.matrix()).array()
90  - (AEchem_trans*(smap*Echem).matrix()).array()));
91  dvmap = (-1.0/tau)*(Iohm + Ielec + Ichem);*/
92  dvmap = (-1.0/tau)*(
93  (memG*(vmap - memV)) +
94  (gchem * (vmap*(AEchem_trans*smap.matrix()).array()
95  - (AEchem_trans*(smap*Echem).matrix()).array())) +
96  (gelec*laplacian*vmap.matrix()).array()
97  );
98  //current injection-for now is hard coded below, inj_nodes is empty here
99  for(auto s : inj_nodes){
100  dv[s] += (-1.0/tau)*cur_inj;
101  }
102  double amp = 2e4;
103  dv[276]+= (1.0/tau)*amp;
104  dv[278]+= (1.0/tau)*amp;
105 
106  for(auto val : abl_neur){
107  dv[val] = 0;
108  ds[val] = 0;
109  }
110  return 0;
111 }
112 int c_elegans::dwdt(ptr_passer x, ptr_passer _dw, double dt){
113  double* dw = _dw;
114  std::fill(dw, dw+num_neur*2, 1);
115  //doesn't need to set abl_neur to zero, since that is done by mod_w
116  return 0;
117 }
118 void c_elegans::mod_w(ptr_passer _w, double t){
119  if(!abl_neur.empty()){
120  double *w = _w;
121  for(auto abl : abl_neur){
122  w[abl]= w[abl+num_neur] = 0;
123  }
124  }
125 }
127  return "c_elegans";
128 }
129 template<class sp_t>
130 void read_mat(std::string fname, sp_t& in_mat){
131  //intel compiler requries this...
132  std::ifstream in_f;
133  in_f.open(fname.c_str());
134  std::vector<Eigen::Triplet<double, int> > intr;
135  while(!in_f.eof()){
136  int row, col;
137  double val=0;
138  in_f >> row >> col >> val;
139  intr.push_back(Triplet<double, int>(row-1, col-1, val));
140  }
141  in_mat.setFromTriplets(intr.begin(), intr.end());
142 }
150  if(dimension != num_neur*2){
151  err("Dimension must be 558, which is double the number of neurons",
152  "", "", FATAL_ERROR);
153  }
154  in.retrieve(beta, "beta", this);
155  in.retrieve(tau, "tau", this);
156  in.retrieve(gelec, "gelec", this);
157  in.retrieve(gchem, "gchem", this);
158  in.retrieve(memV, "memV", this);
159  in.retrieve(memG, "memG", this);
160  in.retrieve(EchemEx, "EchemEx", this);
161  in.retrieve(EchemInh, "EchemInh", this);
162  in.retrieve(ar, "ar", this);
163  in.retrieve(ad, "ad", this);
164  std::string ag_fname, a_fname;
165  in.retrieve(ag_fname, "ag_mat", this);
166  in.retrieve(a_fname, "a_mat", this);
168  ag_full.resize(num_neur, num_neur);
169  laplacian.resize(num_neur, num_neur);
170  read_mat(ag_fname, ag_full);
171  read_mat(a_fname, a_m);
172  //create transposed sparse matrix AEchem
174  AEchem_trans_full = a_m.transpose();
175  AEchem_trans.resize(num_neur, num_neur);
176  //do any needed fake iterations, must make more general at some point
177  size_t num_comb;
178  int iterations;
179  in.retrieve(num_comb, "num_comb", this);
180  in.retrieve(iterations, "iterations", this);
181  in.retrieve(cur_ind, "!start_ind", this);
182  abl_neur.resize(num_comb);
183  for(auto& val : abl_neur){
184  val = 0;
185  }
186  if(abl_neur.size() != 1){
187  next_comb(abl_neur, num_neur);
188  }
189  for(int i = 0; i < cur_ind; i++){
190  for(int j = 0; j < iterations; j++){
191  if(next_comb(abl_neur, num_neur)){
192  char ind_str[20];//won't ever have a 20 digit index
193  //handy buffer to overflow for those hacking this.
194  sprintf(ind_str, "%d", (int)cur_ind);
195  err(std::string("Combinations exhausted in index ") + ind_str,
196  "c_elegans::postprocess","rhs/c_elegans.cpp", FATAL_ERROR);
197  }
198  }
199  }
200 /* if(cur_ind != 0){
201  if(next_comb(abl_neur, num_neur)){
202  char ind_str[20];//won't ever have a 20 digit index
203  //handy buffer to overflow for those hacking this.
204  sprintf(ind_str, "%d", (int)cur_ind);
205  err(std::string("Combinations exhausted in index ") + ind_str,
206  "c_elegans::postprocess","rhs/c_elegans.cpp", FATAL_ERROR);
207  }
208  }*/
209  auto dat_inds =
210  std::shared_ptr<writer>(new writer(true));
211  dat_inds->add_data(data::create("Ablations", abl_neur.data(), abl_neur.size()), writer::OTHER);
212  holder->add_writer(dat_inds);
213 
214  //write first ablation data
215 
216  //set up dummy connection to toroidal controller for now
217  controller* cont;
218  in.retrieve(cont, "controller", this);
219  auto val = std::make_shared<variable>();
220  val->setname("c_elegans_quickfix");
221  val->holder = holder;
222  val->parse("0.1");
223  in.insert_item(val);
224  cont->addvar(val);
225  in.retrieve(dummy, val->name(), this);
226  has_gone=true; //is true at first to allow update of zero index to occur
227  first_round=true;
228  update();
229 }
231  if(has_gone){
232  has_gone=false;//prevent more than one update happening without call to rhs
233  if(!first_round){
235  holder->write_dat();
236  char ind_str[20];//won't ever have a 20 digit index
237  //handy buffer to overflow for those hacking this.
238  sprintf(ind_str, "%d", cur_ind);
239  err(std::string("Combinations exhausted in index ") + ind_str,
240  "c_elegans::update","rhs/c_elegans.cpp", FATAL_ERROR);
241  }
242  auto dat_inds =
243  std::shared_ptr<writer>(new writer(true));
244  dat_inds->add_data(data::create("Ablations", abl_neur.data(), abl_neur.size()), writer::OTHER);
245  holder->add_writer(dat_inds);
246 
247  }
248  else{
249  first_round=false;
250  }
251 
252  Matrix<double, Dynamic, Dynamic> ag_dense(num_neur, num_neur);
253  //insert code to zero it out later
254 
255  auto ag_m = ag_full;
257  auto fncval = [this](int i, int j, double val)->bool{
258  for(int kk = 0; kk < (int)this->abl_neur.size(); kk++){
259  if((int)this->abl_neur[kk] == i || (int)this->abl_neur[kk] == j){
260  return false;
261  }
262  }
263  return true;
264  };
265  AEchem_trans.prune(fncval);
266  ag_m.prune(fncval);
267  ag_dense = ag_m * Matrix<double, num_neur, num_neur>::Identity();
268  auto sumvals = ag_dense.colwise().sum();
270  //generate the sparse diagonal matrix to build the lapacian
271  std::vector<Triplet<double, int> > temp_tr;
272  for(int i = 0; i < (int)num_neur; i++){
273  temp_tr.push_back(Triplet<double, int>(i, i, sumvals[i]));
274  }
275  temp.setFromTriplets(temp_tr.begin(), temp_tr.end());
276  laplacian = temp - ag_m;
277  //initialize the Echem array
278  for(size_t i = 0; i < num_neur; i++){
279  if(GABAergic[i]){
280  Echem[i] = EchemInh;
281  }
282  else{
283  Echem[i] = EchemEx;
284  }
285  }
286  //Initialize the sig array
287  for(size_t i = 0; i < num_neur; i++){
288  sig[i] = 0.5;
289  }
290 
291  eqS = sig * (ar/(ar*sig + ad));
292  //more initialization of temporary dense matrices
293  Matrix<double, Dynamic, Dynamic> ldense(num_neur,num_neur);
294  ldense = laplacian*Matrix<double, num_neur, num_neur>::Identity();
295  Matrix<double, Dynamic, Dynamic> aedense(num_neur, num_neur);
296  aedense= AEchem_trans*Matrix<double, num_neur, num_neur>::Identity();
297  Matrix<double, Dynamic, Dynamic> C(num_neur, num_neur);
298  //create the C matrix
299  C= memG*Matrix<double, num_neur, num_neur>::Identity() + gelec*ldense;
300  //initialize matrix to modify diagonal part of C
301  Matrix<double, num_neur, 1> tmp =(gchem * aedense * eqS.matrix());
302  for(size_t i = 0; i < num_neur; i++){
303  C(i, i) += tmp(i);
304  }
305  Matrix<double, num_neur, 1> Ivals;
306  Ivals.setZero();
307  double amp=2e4;
308  Ivals[276]=amp;
309  Ivals[278]=amp;
310  Matrix<double, num_neur, 1> b;
311  //create B vector
312  b= gchem*aedense*(eqS * Echem).matrix();
313  for(size_t i = 0; i < num_neur; i++){
314  b[i] += (memG*memV + Ivals[i]);
315  }
316  //calculate eqV
317  eqV.matrix() = C.inverse()*b;
318  vmean = eqV+(1.0/beta) * (1.0/sig - 1).log();
319  for(auto val : abl_neur){
320  eqV[val] = vmean [val] = eqS[val] = 0;
321  };
322  }
323 }
324 
325 std::vector<std::string> c_elegans::dependencies() const{
326  std::string deps[] = {"beta", "memV", "memG", "gchem", "gelec", "num_comb",
327  "tau", "EchemEx", "EchemInh", "ar", "ad", "ag_mat", "a_mat", "iterations",
328  "controller"};
329  return make_append(deps, rhs_type::dependencies());
330 }
331 
333  if(len != dimension){
335  }
336  double* vals = in;
337  for(size_t i = 0; i < num_neur; i++){
338  //vals[i] = eqV[i];
339  vals[i] = vmean[i];
340  vals[i+dim_v] = eqS[i];
341  }
342 }