Indian Ocean Skipjack
procedures.hpp
1 #pragma once
2 
3 #include <deque>
4 
5 #include "model.hpp"
6 #include "data.hpp"
7 
8 namespace IOSKJ {
9 
13 class Procedure {
14  public:
15  virtual void reset(uint time, Model& model) {
16 
17  };
18 
19  virtual void operate(uint time, Model& model) = 0;
20 
21  virtual double control(void) const {
22  return 1;
23  };
24 
25  virtual void read(std::istream& stream) {
26 
27  };
28 
29  virtual void write(std::ostream& stream) = 0;
30 };
31 
42 class Lagger : public std::deque<double> {
43  public:
44 
48  void set(int lag){
49  // Fill with NANs
50  clear();
51  resize(lag-1,NAN); // See not above for why minus one
52  }
53 
59  double push_pop(double current){
60  push_back(current);
61  auto lagged = front();
62  pop_front();
63  return lagged;
64  }
65 };
66 
67 
73 class DoNothing : public Procedure, public Structure<DoNothing> {
74 public:
75 
76  virtual void write(std::ostream& stream){
77  stream
78  <<"DoNothing"<<"\t\t\t\t\t\t\t\t\t\t\n";
79  }
80 
81  virtual void operate(uint time, Model& model){
82  }
83 };
84 
85 
91 class HistCatch : public Procedure, public Structure<HistCatch> {
92 public:
93 
94  Array<Variable<Fixed>,Year,Quarter,Region,Method> catches;
95 
96  HistCatch(void){
97  // Read in historical catches (borrowed from parameters)
98  catches.read("parameters/input/catches.tsv",true);
99  }
100 
101  virtual void write(std::ostream& stream){
102  stream
103  <<"HistCatch"<<"\t\t\t\t\t\t\t\t\t\t\n";
104  }
105 
106  virtual void operate(uint time, Model& model){
107  // Apply the actual quarterly catch history
108  // using 2012 catch distribution by quarter, region, method
109  // etc for years in the future
110  uint year = IOSKJ::year(time);
111  if(year>2014) year = 2014;
112  uint quarter = IOSKJ::quarter(time);
113  model.exploit = model.exploit_catch;
114  for(auto region : regions){
115  for(auto method : methods){
116  model.catches(region,method) = catches(year,quarter,region,method);
117  }
118  }
119  }
120 };
121 
122 
128 class ConstCatch : public Procedure, public Structure<ConstCatch> {
129 public:
130 
137  double tac = 429564.0;
138 
139  ConstCatch(double tac = 429564.0):
140  tac(tac) {}
141 
142  virtual void read(std::istream& stream){
143  stream
144  >>tac;
145  }
146 
147  virtual void write(std::ostream& stream){
148  stream
149  <<"ConstCatch\t"<<tac<<"\t\t\t\t\t\t\t\t\t\n";
150  }
151 
152  virtual void operate(uint time, Model& model){
153  model.catches_set(tac/4.0);
154  }
155 };
156 
162 class ConstEffort : public Procedure, public Structure<ConstEffort> {
163 public:
164 
170  double tae = 100;
171 
172  ConstEffort(double tae = 100):
173  tae(tae) {}
174 
175  virtual void write(std::ostream& stream){
176  stream
177  <<"ConstEffort\t"<<tae<<"\t\t\t\t\t\t\t\t\t\n";
178  }
179 
180  virtual void operate(uint time, Model& model){
181  model.effort_set(tae);
182  }
183 };
184 
185 
195 class Mald2016 : public Procedure, public Structure<Mald2016> {
196 public:
197 
198  // The following values for the control parameters are
199  // "reference case" only.
200 
204  int frequency = 3;
205 
209  double precision = 0.2;
210 
214  double imax = 1;
215 
219  double cmax = 700000;
220 
224  double dmax = 0.4;
225 
229  double thresh = 0.4;
230 
234  double closure = 0.1;
235 
239  std::string tag;
240 
244  int lag = 3;
245  Lagger lagger;
246 
250  template<class Mirror>
251  void reflect(Mirror& mirror){
252  mirror
253  .data(frequency,"frequency")
254  .data(precision,"precision")
255  .data(thresh,"thresh")
256  .data(closure,"closure")
257  .data(imax,"imax")
258  .data(cmax,"cmax")
259  .data(cmax,"dmax")
260  ;
261  }
262 
266  void read(std::istream& stream){
267  stream
268  >>frequency
269  >>precision
270  >>thresh
271  >>closure
272  >>imax
273  >>cmax
274  >>dmax;
275  }
276 
280  void write(std::ostream& stream){
281  stream
282  <<"Mald2016"<<"\t"
283  <<frequency<<"\t"
284  <<precision<<"\t"
285  <<thresh<<"\t"
286  <<closure<<"\t"
287  <<imax<<"\t"
288  <<cmax<<"\t"
289  <<dmax<<"\t"
290  <<"\t\t"
291  <<tag<<"\n";
292  }
293 
297  virtual void reset(uint time, Model& model){
298  lagger.set(lag);
299  year_last_ = -1;
300  // Starting catch which will be used as the basis against which maximal
301  // changed (dmax parameter)
302  // A 'round' number close to the 432,467t reported in Scientific Committe report for 2014
303  catches_last_ = (425000/4.0);
304  }
305 
309  virtual void operate(uint time, Model& model){
310  int year = IOSKJ::year(time);
311  int quarter = IOSKJ::quarter(time);
312  if(quarter==0){
313  if(year_last_<0 or year-year_last_>=frequency) {
314  // Get b_curr and b_0 (sum over all regions)
315  double bcurr = sum(model.biomass_spawners);
316  double b0 = sum(model.biomass_spawners_unfished);
317  double etarg = model.e_40;
318 
319  // Apply imprecision to simulate stock
320  // assessment estimation
321  Lognormal imprecision(1,precision);
322  bcurr *= imprecision.random();
323  b0 *= imprecision.random();
324  etarg *= imprecision.random();
325 
326  double status = bcurr/b0;
327 
328  // Calculate recommended exploitation rate
329  double exprate;
330  if(status<closure) exprate = 0;
331  else if(status>=thresh) exprate = imax * etarg;
332  else exprate = imax/(thresh-closure)*(status-closure) * etarg;
333 
334  // Calculate and apply catch limit ensure not
335  // above the annual limit
336  double catches = exprate * bcurr;
337  if (catches*4 > cmax) {
338  catches = cmax/4;
339  }
340 
341  // Apply maximum proportional changes in catch
342  auto change = catches/catches_last_;
343  if (change>(1+dmax)) catches = catches_last_ * (1 + dmax);
344  else if (change<(1-dmax)) catches = catches_last_ * (1 - dmax);
345 
346  // Store year so know when to do this again
347  year_last_ = year;
348  catches_last_ = catches;
349  }
350 
351  // Move along the lag queue every first quarter
352  catches_now_ = lagger.push_pop(catches_last_);
353  }
354 
355  // Apply catch limit with some implementation error
356  if (not std::isnan(catches_now_)) {
357  model.catches_set(catches_now_,0.2);
358  }
359  }
360 
361  virtual double control(void) const {
362  return catches_now_;
363  };
364 
365 private:
370  int year_last_ = -1;
371 
375  double catches_last_ = NAN;
376 
380  double catches_now_ = NAN;
381 
382 };
383 
384 
385 
389 class BRule : public Procedure, public Structure<BRule> {
390 public:
391 
395  int frequency = 2;
396 
400  double precision = 0.1;
401 
405  double target;
406 
410  double thresh;
411 
415  double limit;
416 
420  template<class Mirror>
421  void reflect(Mirror& mirror){
422  mirror
423  .data(frequency,"frequency")
424  .data(precision,"precision")
425  .data(target,"target")
426  .data(thresh,"thresh")
427  .data(limit,"limit")
428  ;
429  }
430 
431  void read(std::istream& stream){
432  stream
433  >>frequency
434  >>precision
435  >>target
436  >>thresh
437  >>limit;
438  }
439 
440  void write(std::ostream& stream){
441  stream
442  <<"BRule"<<"\t"
443  <<frequency<<"\t"
444  <<precision<<"\t"
445  <<target<<"\t"
446  <<thresh<<"\t"
447  <<limit<<"\t\t\t\t\t\n";
448  }
449 
450  virtual void reset(uint time, Model& model){
451  last_ = -1;
452  }
453 
454  virtual void operate(uint time, Model& model){
455  int year = IOSKJ::year(time);
456  int quarter = IOSKJ::quarter(time);
457  if(quarter==0 and (last_<0 or year-last_>=frequency)){
458  // Get stock status
459  double b = model.biomass_status();
460  // Add imprecision
461  Lognormal imprecision(1,precision);
462  b *= imprecision.random();
463  // Calculate F
464  double f;
465  if(b<limit) f = 0;
466  else if(b>thresh) f = target;
467  else f = target/(thresh-limit)*(b-limit);
468  // Apply F
469  model.fishing_mortality_set(f);
470  // Update last
471  last_ = year;
472  }
473  }
474 
475 private:
479  int last_ = -1;
480 };
481 
485 class FRange : public Procedure, public Structure<FRange> {
486 public:
487 
491  int frequency = 2;
492 
496  double precision = 0.1;
497 
501  double target;
502 
506  double buffer;
507 
512  double change_max = 0.3;
513 
517  template<class Mirror>
518  void reflect(Mirror& mirror){
519  mirror
520  .data(frequency,"frequency")
521  .data(precision,"precision")
522  .data(target,"target")
523  .data(buffer,"buffer")
524  .data(change_max,"change_max")
525  ;
526  }
527 
528  void write(std::ostream& stream){
529  stream
530  <<"FRange"<<"\t"
531  <<frequency<<"\t"
532  <<precision<<"\t"
533  <<target<<"\t"
534  <<buffer<<"\t"
535  <<change_max<<"\t\t\t\t\t\n";
536  }
537 
538  virtual void reset(uint time, Model& model){
539  last_ = -1;
540  effort_ = 100;
541  }
542 
543  virtual void operate(uint time, Model& model){
544  int year = IOSKJ::year(time);
545  int quarter = IOSKJ::quarter(time);
546  if(quarter==0 and (last_<0 or year-last_>=frequency)){
547  // Get an estimate of exploitation rate
548  double f = model.exploitation_rate_get();
549  // Add imprecision
550  Lognormal imprecision(1,precision);
551  f *= imprecision.random();
552  // Check to see if F is outside of range
553  if(f<target-buffer or f>target+buffer){
554  // Calculate ratio between current estimated F and target
555  double adjust = target/f;
556  if(adjust>(1+change_max)) adjust = 1+change_max;
557  else if(adjust<1/(1+change_max)) adjust = 1/(1+change_max);
558  // Adjust effort
559  effort_ *= adjust;
560  model.effort_set(effort_);
561  }
562  // Update last
563  last_ = year;
564  }
565  }
566 
567 private:
568 
572  int last_;
573 
577  double effort_;
578 };
579 
583 class IRate : public Procedure, public Structure<IRate> {
584 public:
585 
589  double precision = 0.2;
590 
594  double responsiveness = 1;
595 
599  double multiplier = 400;
600 
604  double threshold = 0.3;
605 
609  double limit = 0.1;
610 
614  double change_max = 0.3;
615 
619  double maximum = 600;
620 
624  template<class Mirror>
625  void reflect(Mirror& mirror){
626  mirror
627  .data(precision,"precision")
628  .data(responsiveness,"responsiveness")
629  .data(multiplier,"multiplier")
630  .data(threshold,"threshold")
631  .data(limit,"limit")
632  .data(change_max,"change_max")
633  .data(maximum,"maximum")
634  ;
635  }
636 
637  void read(std::istream& stream){
638  stream
639  >>precision
640  >>responsiveness
641  >>multiplier
642  >>threshold
643  >>limit
644  >>change_max
645  >>maximum;
646  }
647 
648  void write(std::ostream& stream){
649  stream
650  <<"IRate"<<"\t"
651  <<precision<<"\t"
652  <<responsiveness<<"\t"
653  <<multiplier<<"\t"
654  <<threshold<<"\t"
655  <<limit<<"\t"
656  <<change_max<<"\t"
657  <<maximum<<"\t\t\t\n";
658  }
659 
660  virtual void reset(uint time, Model& model){
661  last_ = -1;
662  index_ = -1;
663  }
664 
665  virtual void operate(uint time, Model& model){
666  int quarter = IOSKJ::quarter(time);
667  // Operate once per year in the third quarter
668  if(quarter==0){
669  // Get CPUE as a combination of WE/PS and MA/PL
670  GeometricMean combined;
671  combined.append(model.cpue(WE,PS));
672  combined.append(model.cpue(MA,PL));
673  double cpue = combined;
674  // Add observation error
675  Lognormal imprecision(1,precision);
676  cpue *= imprecision.random();
677  // Update smoothed index
678  if(index_==-1) index_ = cpue;
679  else index_ = responsiveness*cpue + (1-responsiveness)*index_;
680  // Calculate recommended harvest rate
681  double rate;
682  if(index_<limit) rate = 0;
683  else if(index_>threshold) rate = multiplier;
684  else rate = multiplier/(threshold-limit)*(index_-limit);
685  // Calculate recommended TAC
686  double tac = std::min(rate*cpue,maximum);
687  // Restrict changes in TAC
688  if(last_!=-1){
689  double change = tac/last_;
690  double max = 1 + change_max;
691  if(change>max) change = max;
692  else if(change<1/max) change = 1/max;
693  tac = last_*change;
694  }
695  last_ = tac;
696  // Apply recommended TAC
697  model.catches_set(tac*1000/4);
698  }
699  }
700 
701 private:
702 
706  double index_;
707 
711  double last_;
712 };
713 
714 
715 class Procedures : public Array<Procedure*> {
716 public:
717 
718  void populate(void){
719 
720  // First 10 MPs have full traces output
721 
722  append(new ConstCatch);
723  append(new ConstCatch(250000));
724  append(new ConstCatch(700000));
725 
726  append(new ConstEffort);
727  append(new ConstEffort(50));
728  append(new ConstEffort(200));
729 
730  // Mald2016 reference case
731  auto& ref = * new Mald2016;
732  ref.frequency = 3;
733  ref.precision = 0.1;
734  ref.thresh = 0.4;
735  ref.closure = 0.1;
736  ref.imax = 1;
737  ref.cmax = 900000;
738  ref.dmax = 0.3;
739  ref.tag = "ref";
740  append(&ref);
741 
742  // Alternative cases e.g. illustrating different
743  // shaped response curves
744  {
745  auto& proc = * new Mald2016(ref);
746  proc.dmax = 0.2;
747  append(&proc);
748  }
749  {
750  auto& proc = * new Mald2016(ref);
751  proc.dmax = 0.3;
752  append(&proc);
753  }
754  {
755  auto& proc = * new Mald2016(ref);
756  proc.dmax = 0.5;
757  append(&proc);
758  }
759  {
760  auto& proc = * new Mald2016(ref);
761  proc.dmax = 0.6;
762  append(&proc);
763  }
764 
765  // Alternative values of key Mald2016 control parameters
766  for(double imax=0.5; imax<=1.5; imax+=0.1){
767  auto& proc = * new Mald2016(ref);
768  proc.imax = imax;
769  proc.tag = "ref*imax";
770  append(&proc);
771  }
772  for(double thresh=0.2; thresh<=1; thresh+=0.1){
773  auto& proc = * new Mald2016(ref);
774  proc.thresh = thresh;
775  proc.tag = "ref*thresh";
776  append(&proc);
777  }
778  for(double closure=0; closure<=0.4; closure+=0.1){
779  auto& proc = * new Mald2016(ref);
780  proc.closure = closure;
781  proc.tag = "ref*closure";
782  append(&proc);
783  }
784  for(double dmax=0.1; dmax<=1.0; dmax+=0.1){
785  auto& proc = * new Mald2016(ref);
786  proc.dmax = dmax;
787  proc.tag = "ref*dmax";
788  append(&proc);
789  }
790 
791  // Grid of Mald2016 control parameters
792  for(auto frequency : {3}){
793  for(auto precision : {0.1}){
794  for(auto imax : {0.9, 1.0, 1.1}){
795  for(auto thresh : {0.3, 0.4, 0.5}){
796  for(auto closure : {0.0, 0.1, 0.2}){
797  for(auto cmax : {700000, 800000, 900000}){
798  auto& proc = * new Mald2016;
799  proc.frequency = frequency;
800  proc.precision = precision;
801  proc.thresh = thresh;
802  proc.closure = closure;
803  proc.imax = imax;
804  proc.cmax = cmax;
805  append(&proc);
806  }
807  }
808  }
809  }
810  }
811  }
812 
813  // Alternative values of constant catch
814  for(double catches=100; catches<=1000; catches+=100){
815  auto& proc = * new ConstCatch;
816  proc.tac = catches*1000;
817  append(&proc);
818  }
819 
820  // Alternative values of constant effort (%age of recent past)
821  for(double effort=50; effort<=600; effort+=10){
822  auto& proc = * new ConstEffort;
823  proc.tae = effort;
824  append(&proc);
825  }
826 
827  // BRule
828  {
829  auto& proc = * new BRule;
830  proc.frequency = 2;
831  proc.precision = 0.2;
832  proc.target = 0.25;
833  proc.thresh = 0.3;
834  proc.limit = 0.05;
835  append(&proc);
836  }
837  for(int frequency : {2}){
838  for(double precision : {0.2}){
839  for(auto target : {0.2,0.25,0.3}){
840  for(auto thresh : {0.4,0.5}){
841  for(auto limit : {0.1,0.2}){
842  auto& proc = * new BRule;
843  proc.frequency = frequency;
844  proc.precision = precision;
845  proc.target = target;
846  proc.thresh = thresh;
847  proc.limit = limit;
848  append(&proc);
849  }
850  }
851  }
852  }
853  }
854 
855  // FRange
856  {
857  auto& proc = * new FRange;
858  proc.frequency = 3;
859  proc.precision = 0.1;
860  proc.target = 0.25;
861  proc.buffer = 0.05;
862  proc.change_max = 0.3;
863  append(&proc);
864  }
865  for(int frequency : {5,7}){
866  for(double precision : {0.2}){
867  for(auto target : {0.2,0.25,0.3}){
868  for(auto buffer : {0.02,0.05}){
869  auto& proc = * new FRange;
870  proc.frequency = frequency;
871  proc.precision = precision;
872  proc.target = target;
873  proc.buffer = buffer;
874  proc.change_max = 0.4;
875  append(&proc);
876  }
877  }
878  }
879  }
880 
881  // IRate
882  {
883  auto& proc = * new IRate;
884  proc.responsiveness = 0.5;
885  proc.multiplier = 100000;
886  proc.threshold = 0.4;
887  proc.limit = 0.1;
888  proc.change_max = 0.3;
889  append(&proc);
890  }
891  for(double responsiveness : {0.5}){
892  for(double multiplier : {100000,120000,140000}){
893  for(auto threshold : {0.4, 0.5, 0.6}){
894  for(auto limit : {0.1,0.2}){
895  auto& proc = * new IRate;
896  proc.responsiveness = responsiveness;
897  proc.multiplier = multiplier;
898  proc.threshold = threshold;
899  proc.limit = limit;
900  proc.change_max = 0.4;
901  append(&proc);
902  }
903  }
904  }
905  }
906 
907  }
908 
909  void reset(int procedure, uint time, Model& model){
910  operator[](procedure)->reset(time,model);
911  }
912 
913  void operate(int procedure, uint time, Model& model){
914  operator[](procedure)->operate(time,model);
915  }
916 
917  void read(const std::string& path = "procedures/input/procedures.tsv"){
918  std::ifstream file(path);
919  std::string line;
920  std::getline(file,line);//header
921  while(std::getline(file,line)){
922  std::istringstream stream(line);
923  std::string clas;
924  stream>>clas;
925  if(clas=="HistCatch"){
926  auto proc = new HistCatch;
927  append(proc);
928  } else if(clas=="ConstCatch"){
929  auto proc = new ConstCatch;
930  proc->read(stream);
931  append(proc);
932  } else if(clas=="BRule"){
933  auto proc = new BRule;
934  proc->read(stream);
935  append(proc);
936  } else if(clas=="IRate"){
937  auto proc = new IRate;
938  proc->read(stream);
939  append(proc);
940  } else {
941  throw std::runtime_error("Unknown procedure class: "+clas);
942  }
943  }
944  }
945 
946  void write(const std::string& path = "procedures/output/procedures.tsv"){
947  std::ofstream file(path);
948  file<<"procedure\tclass\tp1\tp2\tp3\tp4\tp5\tp6\tp7\tp8\tp9\tp10\n";
949  int index = 0;
950  for(Procedure* procedure : *this) {
951  file<<index++<<"\t";
952  procedure->write(file);
953  }
954  }
955 };
956 
957 }
double tac
Definition: procedures.hpp:137
virtual void reset(uint time, Model &model)
Definition: procedures.hpp:297
Definition: data.hpp:6
Array< double, Region > biomass_spawners
Definition: model.hpp:29
Definition: procedures.hpp:91
int lag
Definition: procedures.hpp:244
double dmax
Definition: procedures.hpp:224
Definition: procedures.hpp:73
Definition: procedures.hpp:162
double target
Definition: procedures.hpp:405
Definition: model.hpp:13
double push_pop(double current)
Definition: procedures.hpp:59
double responsiveness
Definition: procedures.hpp:594
Array< double, Region > biomass_spawners_unfished
Definition: model.hpp:37
virtual void operate(uint time, Model &model)
Definition: procedures.hpp:309
double precision
Definition: procedures.hpp:400
void read(std::istream &stream)
Definition: procedures.hpp:266
Definition: dimensions.hpp:22
Definition: procedures.hpp:195
double tae
Definition: procedures.hpp:170
void catches_set(double catches_, double error=0.2)
Definition: model.hpp:493
Definition: procedures.hpp:42
double buffer
Definition: procedures.hpp:506
void write(std::ostream &stream)
Definition: procedures.hpp:280
Definition: procedures.hpp:715
void reflect(Mirror &mirror)
Definition: procedures.hpp:251
Definition: procedures.hpp:583
int frequency
Definition: procedures.hpp:491
int frequency
Definition: procedures.hpp:204
double closure
Definition: procedures.hpp:234
Definition: procedures.hpp:389
void reflect(Mirror &mirror)
Definition: procedures.hpp:421
int frequency
Definition: procedures.hpp:395
Definition: procedures.hpp:128
double thresh
Definition: procedures.hpp:229
double limit
Definition: procedures.hpp:609
Definition: procedures.hpp:13
void set(int lag)
Definition: procedures.hpp:48
double e_40
Definition: model.hpp:367
double maximum
Definition: procedures.hpp:619
double cmax
Definition: procedures.hpp:219
void reflect(Mirror &mirror)
Definition: procedures.hpp:518
double threshold
Definition: procedures.hpp:604
Definition: procedures.hpp:485
double limit
Definition: procedures.hpp:415
double change_max
Definition: procedures.hpp:614
double target
Definition: procedures.hpp:501
Array< double, Region, Method > catches
Definition: model.hpp:313
double change_max
Definition: procedures.hpp:512
double multiplier
Definition: procedures.hpp:599
double imax
Definition: procedures.hpp:214
Definition: distributions.hpp:262
double precision
Definition: procedures.hpp:209
double thresh
Definition: procedures.hpp:410
std::string tag
Definition: procedures.hpp:239
void reflect(Mirror &mirror)
Definition: procedures.hpp:625