The AHA Model  Revision: 12809
Reference implementation 04 (HEDG02_04)
m_neuro.f90
Go to the documentation of this file.
1 !> @file m_neuro.f90
2 !! The Neurobiological and behaviour architecture of the AHA Model.
3 !! @author Sergey Budaev <sergey.budaev@uib.no>
4 !! @author Jarl Giske <jarl.giske@uib.no>
5 !! @date 2016-2017
6 
7 !-------------------------------------------------------------------------------
8 ! $Id: m_neuro.f90 6951 2018-02-17 16:47:37Z sbu062 $
9 !-------------------------------------------------------------------------------
10 
11 !-------------------------------------------------------------------------------
12 !> @brief Definition of the decision making and behavioural the architecture
13 !> @section the_neurobio_module THE_NEUROBIO module
14 !> This module defines the neurobiological architecture of the agent, starting
15 !! from perception to representation, appraisal, motivation, emotion,
16 !! determination of the global organismic state, and behaviour.
18 
19  use commondata
20  use the_environment
21  use the_body
22 
23  implicit none
24 
25  character (len=*), parameter, private :: modname = "(THE_NEUROBIO)"
26 
27  !.............................................................................
28  ! Lower-order perception components and objects. These describe
29  ! the stimuli that the agent gets from the environment. These are of
30  ! two kinds: (1) spatial/environmental perception objects which get
31  ! objects from the outside world (e.g. food, conspecifics, predators)
32  ! and (2) internal perception objects that get objects of the self
33  ! organism (self stomach capacity available for food, energy reserve,
34  ! body mass etc).
35 
36  !.............................................................................
37  ! Spatial / environmental perception components: perception of objects in the
38  ! outer world
39 
40  !> This type defines how the agent perceives food items.
41  !! The food perception object the_neurobio::percept_food is basically an
42  !! array of food objects within the visual range of the agent plus
43  !! distances to the agent. This is the "objective" perception container,
44  !! reflecting the "real world". We introduce a perception error when
45  !! perception object is analysed by the agent's neurobiological system.
46  type, public :: percept_food
47  !> An array of food items found within the visual range, limited by
48  !! the maximum order of partial indexing
49  !! `commondata::food_select_items_index_partial`.
50  !! @note **Food perception** is quite complex to implement as it requires
51  !! determining individual food items within the current visual range
52  !! of the agent. There are, however, potentially thousands (or
53  !! millions) of food items in the food resource, each of the food
54  !! items is stochastic (e.g. they have different sizes), so visual
55  !! range differ for each item and each agent should determine
56  !! food items in its proximity at numerous time steps of the model.
57  !! This means repeating huge loops many times for each agent at
58  !! each time step. This is approached by array segmentation: the
59  !! perception object is obtained by *partial indexing* of a very
60  !! limited number (=`commondata::food_select_items_index_partial`) of
61  !! only the nearest food items, the agent's visual range is then
62  !! determined for each of this nearest neighbouring food items, and
63  !! finally those food items that individually fall within the
64  !! visual range
65  !! are included into the perception object.
66  ! @warning Tried to convert all perception types to allocatable
67  ! (at rev. 1651), food perception worked ok, but other objects were
68  ! broken. (1) pure/elemental procedures have problems with
69  ! allocatable within (allocatable is a side effect); (2) allocatable
70  ! from within user types have problems with whole array passage to
71  ! subroutines dummy parameters, issue error: [`Error: Component to
72  ! the right of a part reference with nonzero rank must not have the
73  ! ALLOCATABLE attribute at... `]. F2003 standard 6.1.2. prohibits
74  ! passing whole arrays of allocatable derived types. So far returned
75  ! to non-allocatable scalars and allocatable arrays, scalars would
76  ! not cause small memory expenditures.
77  type(food_item), allocatable, dimension(:) :: foods_seen
78  !> An array of distances towards each of the food items.
79  real(srp), allocatable, dimension(:) :: foods_distances
80  !> Total number of food items within the visual range of the agent.
81  !! must not exceed the `commondata::food_select_items_index_partial`
82  !! parameter.
83  integer :: food_seen_count
84  contains
85  !> Initiate an empty **food** perception object with known number of
86  !! components. See `the_neurobio::percept_food_create_init()`.
87  procedure, public :: init => percept_food_create_init
88  !! See `the_neurobio::percept_food_number_seen()`
89  procedure, public :: number => percept_food_number_seen
90  !> Set the total number of food items perceived (seen) in the food
91  !! perception object. Do not reallocate the perception object components
92  !! with respect to this new number yet.
93  !! See `the_neurobio::percept_food_make_fill_arrays()`.
94  procedure, public :: make => percept_food_make_fill_arrays
95  !> Get the number (count) of food items seen.
96  !! See `the_neurobio::percept_food_get_count_found()`.
97  procedure, public :: get_count => percept_food_get_count_found
98  !> Get the average size of food items seen.
99  !! See `the_neurobio::percept_food_get_meansize_found()`.
100  procedure, public :: get_meansize => percept_food_get_meansize_found
101  !> Get the average mass of food items seen.
102  !! See `the_neurobio::percept_food_get_meanmass_found()`.
103  procedure, public :: get_meanmass => percept_food_get_meanmass_found
104  !> Get the average distance tot the food items seen.
105  !! See `the_neurobio::percept_food_get_meandist_found()`.
106  procedure, public :: get_meandist => percept_food_get_meandist_found
107  !> Deallocate and delete a **food** perception object.
108  !! See `the_neurobio::percept_food_destroy_deallocate()`.
109  procedure, public :: destroy => percept_food_destroy_deallocate
110  end type percept_food
111 
112  !> This type defines a single spatial perception component, i.e. some single
113  !! elementary spatial object that can be perceived by the agent from a big
114  !! array of objects of the same type which are available in the agent's
115  !! environment. Different kinds of perception objects (e.g. conspecifics,
116  !! predators etc.) can be produced by extending this basic type.
117  !! @note Note that the **food items** the_neurobio::percept_food are
118  !! implemented separately and do not currently use the spatial
119  !! perception component objects. For example, individual food items
120  !! are indexed seperately witghin the food resource object by `iid`
121  !! data component.
122  type, public, extends(spatial) :: spatial_percept_component
123  !> Spatial perception component adds an unique component id (`cid`) number
124  !! to the basic `the_environment::spatial` so that individual objects
125  !! within the whole perception object array can be identified. As a
126  !! consequence, spatial perception component adds only two type-bound
127  !! procedures that do the \%cid.
128  integer :: cid
129  contains
130  !> Get the unique **id** of the food item object.
131  !! See `the_neurobio::spatial_percept_get_cid()`.
132  procedure, public :: get_cid => spatial_percept_get_cid
133  !> Set unique **id** for the conspecific perception component.
134  !! See `the_neurobio::spatial_percept_set_cid()`.
135  procedure, public :: set_cid => spatial_percept_set_cid
137 
138  !> This type defines a **single conspecific** perception component.
139  !! It is required for the `the_neurobio::percept_conspecifics` type that
140  !! defines the whole conspecifics perception object (array of conspecifics).
142  !> Body size. The body size of the perception conspecific.
143  !! @note We may need body size of the conspecifics as the decision
144  !! making rules may depend on the conspecific size (e.g.
145  !! approach big and repulse from small, also may affect
146  !! mating, e.g. mate with the biggest, etc.).
147  real(srp) :: consp_body_size
148  !> Body mass. The body mass of the perception conspecific.
149  real(srp) :: consp_body_mass
150  !> @note Any other characteristics of the perception conspecifics may
151  !! be added, e.g. sex etc. What is crucial for the decision making.
152  !> The distance towards this conspecific in the visual field.
153  real(srp) :: consp_distance
154  !> The sex of the conspecific in the perception object.
155  logical :: sex_is_male
156  contains
157  !> Create a single conspecific perception component at an undefined
158  !! position with default properties.
159  !! See `the_neurobio::consp_percept_comp_create()`.
160  procedure, public :: create => consp_percept_comp_create
161  !> Make a single conspecific perception component. This is a single
162  !! conspecific located within the visual range of the agent.
163  !! See `the_neurobio::consp_percept_make()`.
164  procedure, public :: make => consp_percept_make
165  !> Get the **conspecific** perception component body size.
166  !! See `the_neurobio::consp_percept_get_size()`.
167  procedure, public :: get_size => consp_percept_get_size
168  !> Get the **conspecific** perception component body mass.
169  !! See `the_neurobio::consp_percept_get_mass()`.
170  procedure, public :: get_mass => consp_percept_get_mass
171  !> Get the **conspecific** perception component distance.
172  !! See `the_neurobio::consp_percept_get_dist()`.
173  procedure, public :: get_dist => consp_percept_get_dist
174  !> Get the **conspecific** perception component sex flag (male).
175  !! See `the_neurobio::consp_percept_sex_is_male_get()`.
176  procedure, public :: is_male => consp_percept_sex_is_male_get
177  !> Get the **conspecific** perception component sex flag (female).
178  !! See `the_neurobio::consp_percept_sex_is_female_get()`.
179  procedure, public :: is_female => consp_percept_sex_is_female_get
180  end type conspec_percept_comp
181 
182  !> This type defines how the agent perceives conspecifics.
183  type, public :: percept_conspecifics
184  !> An array of conspecifics seen in proximity, within the visual range.
185  !! @note Perception of conspecifics is implemented similar to food items.
186  !! Conspecific perception object the_neurobio::percept_conspecifics
187  !! is a simple the_environment::spatial object.
188  type(conspec_percept_comp), allocatable, dimension(:) :: conspecifics_seen
189  !> The number of conspecifics seen.
190  integer :: conspecifics_seen_count
191  contains
192  !> Create conspecifics perception object, it is an array of
193  !! conspecific perception components.
194  !! See `the_neurobio::percept_consp_create_init()`.
195  procedure, public :: init => percept_consp_create_init
196  !> Set the total number of conspecifics perceived (seen) in the
197  !! conspecific perception object.
198  !! See `the_neurobio::percept_consp_number_seen()`.
199  procedure, public :: number => percept_consp_number_seen
200  !> Make the conspecifics perception object, fill it with the actual
201  !! arrays.
202  !! See `the_neurobio::percept_consp_make_fill_arrays()`.
203  procedure, public :: make => percept_consp_make_fill_arrays
204  !> Get the number (count) of conspecifics seen.
205  !! See `the_neurobio::percept_consp_get_count_seen()`.
206  procedure, public :: get_count => percept_consp_get_count_seen
207  !> Deallocate and delete a conspecific perception object.
208  !! See `the_neurobio::percept_consp_destroy_deallocate()`.
209  procedure, public :: destroy => percept_consp_destroy_deallocate
210  end type percept_conspecifics
211 
212  !> This type defines a **single** arbitrary spatial object perception
213  !! component. For example, a predator perception object is then an array of
214  !! such spatial object perception components.
216  !> Size. The size of the perception object.
217  real(srp) :: sobj_size
218  !> @note Any other characteristics of the perception conspecifics may
219  !! be added, e.g. sex etc. What is crucial for the decision making.
220  !> The distance towards this conspecific in the visual field.
221  real(srp) :: sobj_distance
222  contains
223  !> Create a single arbitrary spatial object perception component at an
224  !! undefined position with default properties.
225  !! See `the_neurobio::spatialobj_percept_comp_create()`.
226  procedure, public :: create => spatialobj_percept_comp_create
227  !> Make a single arbitrary **spatial** object perception component.
228  !! See `the_neurobio::spatialobj_percept_make()`.
229  procedure, public :: make => spatialobj_percept_make
230  !> Get an arbitrary spatial object perception component size.
231  !! See `the_neurobio::spatialobj_percept_get_size()`.
232  procedure, public :: get_size => spatialobj_percept_get_size
233  !> Get the distance to an arbitrary spatial object perception component.
234  !! See `the_neurobio::spatialobj_percept_get_dist()`.
235  procedure, public :: get_dist => spatialobj_percept_get_dist
236  !> Calculate the visibility range of this spatial object. Wrapper to the
237  !! `visual_range` function. This function calculates the distance from
238  !! which this object can be seen by a visual object (e.g. predator or
239  !! prey).
240  !! See `the_neurobio::spatialobj_percept_visibility_visual_range()`.
241  procedure, public :: visibility => &
243  end type spatialobj_percept_comp
244 
245  !> This type defines how the agent perceives a predator.
246  type, public :: percept_predator
247  !> An array of predators seen in proximity, within the visual range.
248  !! @note Perception of an array of predators uses the arbitrary spatial
249  !! object components type defined by `SPATIALOBJ_PERCEPT_COMP`.
250  type(spatialobj_percept_comp), allocatable, dimension(:) :: predators_seen
251  !> An array of the attack rates of the predators in the perception object.
252  real(srp), allocatable, dimension(:) :: predators_attack_rates
253  !> The number of conspecifics seen.
254  integer :: predators_seen_count
255  contains
256  !> Create **conspecifics** perception object, it is an array of
257  !! conspecific perception components.
258  !! See `the_neurobio::percept_predator_create_init()`.
259  procedure, public :: init => percept_predator_create_init
260  !> Set the total number of **predators** perceived (seen) in the predator
261  !! perception object.
262  !! See `the_neurobio::percept_predator_number_seen()`.
263  procedure, public :: number => percept_predator_number_seen
264  !> Make the **predator** perception object, fill it with the
265  !! actual arrays.
266  !! See `the_neurobio::percept_predator_make_fill_arrays()`.
267  procedure, public :: make => percept_predator_make_fill_arrays
268  !> Set an array of the attack rates for the predator perception object.
269  !! See `the_neurobio::percept_predator_set_attack_rate_vector()`.
270  procedure, public :: set_attack_rate_v => percept_predator_set_attack_rate_vector
271  !> Set an array of the attack rates for the predator perception object.
272  !! See `the_neurobio::percept_predator_set_attack_rate_scalar()`.
273  procedure, public :: set_attack_rate_s => percept_predator_set_attack_rate_scalar
274  !> A generic interface to set the attack rates for the predator
275  !! perception object.
276  !! See `the_neurobio::percept_predator_set_attack_rate_vector()` and
277  !! `the_neurobio::percept_predator_set_attack_rate_scalar()`.
278  generic, public :: set_attack_rate => set_attack_rate_v, set_attack_rate_s
279  !> Get the number (count) of predators seen.
280  !! See `the_neurobio:percept_predator_get_count_seen:()`.
281  procedure, public :: get_count => percept_predator_get_count_seen
282  !> Deallocate and delete a **predator** perception object.
283  !! See `the_neurobio::percept_predator_destroy_deallocate()`.
284  procedure, public :: destroy => percept_predator_destroy_deallocate
285  end type percept_predator
286 
287  !.............................................................................
288  ! Internal perception components: perception of objects within the
289  ! self organism.
290 
291  !> This type defines how the agent perceives its own stomach capacity.
292  type, public :: percept_stomach
293  !> Available stomach capacity as a proportion of the full stomach. So,
294  !! 0 is full stomach (no space for new food), 1 is empty stomach (full
295  !! capacity available).
296  real(srp) :: capacity
297  contains
298  !> Initiate an empty **stomach** capacity perception object.
299  !! See `the_neurobio::percept_stomach_create_init()`.
300  procedure, public :: init => percept_stomach_create_init
301  !> Get the currently available value of the available **stomach** volume.
302  !! See `the_neurobio::percept_stomach_get_avail_capacity()`.
303  procedure, public :: get_available => percept_stomach_get_avail_capacity
304  !> Set and update the currently available value of the available
305  !! **stomach** volume.
306  !! See `the_neurobio::percept_stomach_update_avail_capacity()`.
307  procedure, public :: set_available =>percept_stomach_update_avail_capacity
308  !> Destroy the **stomach** perception object and deallocate.
309  !! See `the_neurobio::percept_stomach_destroy_deallocate()`.
310  procedure, public :: destroy => percept_stomach_destroy_deallocate
311  end type percept_stomach
312 
313  !> This type defines how the agent perceives its own body mass
314  !> it can be important for state-dependency.
315  type, public :: percept_body_mass
316  !> The current body mass of the agent.
317  real(srp) :: body_mass
318  contains
319  !> Initiate an empty **body mass** perception object.
320  !! See `the_neurobio::percept_bodymass_create_init()`.
321  procedure, public :: init => percept_bodymass_create_init
322  !> Get the current value of the **body mass** perception.
323  !! See `the_neurobio::percept_bodymass_get_current()`.
324  procedure, public :: get_current => percept_bodymass_get_current
325  !> Set and update the current **body mass** perception value.
326  !! See `the_neurobio::percept_bodymass_update_current()`.
327  procedure, public :: set_current => percept_bodymass_update_current
328  !> Destroy the **body mass** perception object and deallocate.
329  !! See `the_neurobio::percept_bodymass_destroy_deallocate()`.
330  procedure, public :: destroy => percept_bodymass_destroy_deallocate
331  end type percept_body_mass
332 
333  !> This type defines how the agent perceives its own energy reserves
334  !> it can be important for state-dependency.
335  type, public :: percept_energy
336  !> The current energy reserves of the agent.
338  contains
339  !> Initiate an empty **energy** perception object.
340  !! See `the_neurobio::percept_energy_create_init()`.
341  procedure, public :: init => percept_energy_create_init
342  !> Get the current value of the **energy** reserves.
343  !! See `the_neurobio::percept_energy_get_current()`.
344  procedure, public :: get_current => percept_energy_get_current
345  !> Set and update the current **energy** perception value.
346  !! See `the_neurobio::percept_energy_update_current()`.
347  procedure, public :: set_current =>percept_energy_update_current
348  !> Destroy the **energy** perception object and deallocate.
349  !! See `the_neurobio::percept_energy_destroy_deallocate()`.
350  procedure, public :: destroy => percept_energy_destroy_deallocate
351  end type percept_energy
352 
353  !> This type defines how the agent perceives its own age in terms of
354  !! the model discrete time step.
355  type, public :: percept_age
356  integer :: age
357  contains
358  !> Initiate an empty **age** perception object.
359  !! See `the_neurobio::percept_age_create_init()`.
360  procedure, public :: init => percept_age_create_init
361  !> Get the current value of the **age** reserves.
362  !! See `the_neurobio::percept_age_get_current()`.
363  procedure, public :: get_current => percept_age_get_current
364  !> Set and update the current **age** perception value.
365  !! See `the_neurobio::percept_age_update_current()`.
366  procedure, public :: set_current =>percept_age_update_current
367  !> Destroy the **age** perception object and deallocate.
368  !! See `the_neurobio::percept_age_destroy_deallocate()`.
369  procedure, public :: destroy => percept_age_destroy_deallocate
370  end type percept_age
371 
372  !> Perception of the reproductive factor, reproductive factor depends
373  !! on the sex hormones differently in males and females.
374  type, public :: percept_reprfact
375  real(srp) :: reproduct_fact
376  contains
377  !> Make en empty reproductive factor perception component.
378  !! See `the_neurobio::percept_reprfac_create_init()`.
379  procedure, public :: init => percept_reprfac_create_init
380  !> Get the current perception of the **reproductive factor**.
381  !! See `the_neurobio::percept_reprfac_get_current()`.
382  procedure, public :: get_current => percept_reprfac_get_current
383  !> Set the current **reproductive factor** level into perception component.
384  !! See `the_neurobio::percept_reprfac_set_current()`.
385  procedure, public :: set_current => percept_reprfac_set_current
386  !> Destroy / deallocate **reproductive factor** perception component.
387  !! See `the_neurobio::percept_reprfac_destroy_deallocate()`.
388  procedure, public :: destroy => percept_reprfac_destroy_deallocate
389  end type percept_reprfact
390 
391  !.............................................................................
392  ! External **direct** non-spatial perception components: perception of the
393  ! general environmental factors like light and depth that are not localised
394  ! in the environment and can be perceived directly. The functions are almost
395  ! wholly trivial, but needed here to make perception structure consistent and
396  ! consisting of the same standardised units.
397 
398  !> Perception of the ambient illumination. This is a very simple
399  !! perception component, singular and static.
400  type, public :: percept_light
401  real(srp) :: illumination
402  contains
403  !> Make en empty light perception component.
404  !! See `the_neurobio::percept_light_create_init()`.
405  procedure, public :: init => percept_light_create_init
406  !> Get the current perception of the illumination.
407  !! See `the_neurobio::percept_light_get_current()`.
408  procedure, public :: get_current => percept_light_get_current
409  !> Set the current **light** level into the perception component.
410  !! See `the_neurobio::percept_light_set_current()`.
411  procedure, public :: set_current => percept_light_set_current
412  !> Destroy / deallocate **light** perception component.
413  !! See `the_neurobio::percept_light_destroy_deallocate()`.
414  procedure, public :: destroy => percept_light_destroy_deallocate
415  end type percept_light
416 
417  !> Perception of the current depth horizon.
418  type, public :: percept_depth
419  real(srp) :: depth
420  contains
421  !> Make en empty depth perception component.
422  !! See `the_neurobio::percept_depth_create_init()`.
423  procedure, public :: init => percept_depth_create_init
424  !> Get the current perception of the **depth**.
425  !! See `the_neurobio::percept_depth_get_current()`.
426  procedure, public :: get_current => percept_depth_get_current
427  !> Set the current **depth** level into the perception component.
428  !! See `the_neurobio::percept_depth_set_current()`.
429  procedure, public :: set_current => percept_depth_set_current
430  !> Destroy / deallocate **depth** perception component.
431  !! See `the_neurobio::percept_depth_destroy_deallocate()`.
432  procedure, public :: destroy => percept_depth_destroy_deallocate
433  end type percept_depth
434 
435  !.............................................................................
436  ! Here we collect all the above individual perception components into a
437  ! unitary individual-specific perception object.
438 
439  !> Individual perception memory(history) stack, a memory component that
440  !! saves perception values at previous time steps of the model. Not whole
441  !! perception objects are saved for simplicity, only the most important
442  !! parameters, integer and real types so commondata::add_to_history() can
443  !! be used in unmodified form. Decision making can make use of this memory
444  !! stack.
445  !! @note Note that age perception `the_neurobio::percept_age` is **not
446  !! saved** in memory stack as it is trivial to get/predict.
447  type, public :: memory_perceptual
448  !> Memory for **light**.
449  real(srp), dimension(HISTORY_SIZE_PERCEPTION) :: memory_light ! Light
450  !> Memory for **depth**.
451  real(srp), dimension(HISTORY_SIZE_PERCEPTION) :: memory_depth ! Depth
452  !> Memory for **number of food items** seen (in perception).
453  integer , dimension(HISTORY_SIZE_PERCEPTION) :: memory_food ! N foods
454  !> Memory for **mean size of food items** seen (in perception).
455  real(srp), dimension(HISTORY_SIZE_PERCEPTION) :: memory_foodsiz ! mean size
456  !> Memory for **mean distance to the food items** seen (in perception).
457  real(srp), dimension(HISTORY_SIZE_PERCEPTION) :: memory_foodist ! mean dist
458  !> Memory for **number of conspecifics** seen.
459  integer , dimension(HISTORY_SIZE_PERCEPTION) :: memory_consp ! N consp.
460  !> Memory for **number of predators**.
461  integer , dimension(HISTORY_SIZE_PERCEPTION) :: memory_pred ! N pred.
462  !> Memory for **stomach contents**.
463  real(srp), dimension(HISTORY_SIZE_PERCEPTION) :: memory_stom ! Stomach
464  !> Memory for **body mass**.
465  real(srp), dimension(HISTORY_SIZE_PERCEPTION) :: memory_bdmass ! Body mass
466  !> Memory for **energy reserves**.
467  real(srp), dimension(HISTORY_SIZE_PERCEPTION) :: memory_energ ! Energy
468  !> Memory for **reproductive factor** values.
469  real(srp), dimension(HISTORY_SIZE_PERCEPTION) :: memory_reprfac ! Repr.fact.
470  contains
471  !> Add perception components into the memory stack.
472  !! See `the_neurobio::percept_memory_add_to_stack()`.
473  procedure, public :: add_to_memory => percept_memory_add_to_stack
474  !> Cleanup and destroy the perceptual memory stack.
475  !! See `the_neurobio::percept_memory_cleanup_stack()`.
476  procedure, public :: memory_cleanup => percept_memory_cleanup_stack
477  !> Get the total number of food items within the whole perceptual memory
478  !! stack. See `the_neurobio::percept_memory_food_get_total()`.
479  procedure, public :: get_food_total => percept_memory_food_get_total
480  !> Get the average number of food items per single time step within the
481  !! whole perceptual memory stack.
482  !! See `the_neurobio::percept_memory_food_get_mean_n()`.
483  procedure, public :: get_food_mean_n => percept_memory_food_get_mean_n
484  !> Get the **average number** of food items per single time step within
485  !! the perceptual memory stack, split to the first (older) and second
486  !! (newer) parts. The whole memory stack ('sample') is split by the
487  !! `split_val` parameter and two means are calculated: before the
488  !! `split_val` and after it.
489  !! See `the_neurobio::percept_memory_food_mean_n_split()`.
490  procedure, public :: get_food_mean_n_split => &
492  !> Get the average size of food item per single time step within the
493  !! whole perceptual memory stack.
494  !! See `the_neurobio::percept_memory_food_get_mean_size()`.
495  procedure, public :: get_food_mean_size=>percept_memory_food_get_mean_size
496  !> Get the **average size** of food items per single time step within the
497  !! perceptual memory stack, split to the first (older) and second(newer)
498  !! parts. The whole memory stack 'sample' is split by the `split_val`
499  !! parameter and two means are calculated: before the `split_val` and
500  !! after it. See `the_neurobio::percept_memory_food_mean_size_split()`.
501  procedure, public :: get_food_mean_size_split => &
503  !> Get the **average distance** to food item per single time step within the
504  !! whole perceptual memory stack.
505  !! See `the_neurobio::percept_memory_food_get_mean_dist()`.
506  procedure, public :: get_food_mean_dist => &
508  !> Get the **average distance** to food items per single time step within the
509  !! perceptual memory stack, split to the first (older) and second(newer)
510  !! parts. The whole memory stack 'sample' is split by the `split_val`
511  !! parameter and two means are calculated: before the `split_val` and after
512  !! it. See `the_neurobio::percept_memory_food_mean_dist_split()`.
513  procedure, public :: get_food_mean_dist_split => &
515  !> Get the **average number** of conspecifics per single time step
516  !! within the whole perceptual memory stack.
517  !! See `the_neurobio::percept_memory_consp_get_mean_n()`.
518  procedure, public :: get_consp_mean_n => percept_memory_consp_get_mean_n
519  !> Get the total number of predators within the whole perceptual memory
520  !! stack. See `the_neurobio::percept_memory_predators_get_total()`.
521  procedure, public :: get_pred_total => percept_memory_predators_get_total
522  !> Get the average number of predators per single time step within the
523  !! whole perceptual memory stack.
524  !! See `the_neurobio::percept_memory_predators_get_mean()`.
525  procedure, public :: get_pred_mean => percept_memory_predators_get_mean
526  !> Get the **average number** of predators per single time step within the
527  !! perceptual memory stack, split to the first (older) and second(newer)
528  !! parts. The whole memory stack ('sample') is split by the `split_val`
529  !! parameter and two means are calculated: before the `split_val` and after
530  !! it. See `the_neurobio::percept_memory_predators_mean_split()`.
531  procedure, public :: get_pred_mean_split => &
533  end type memory_perceptual
534 
535  !. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
536  !> The perception architecture of the agent. See @ref aha_buildblocks_percept
537  !! "\"The perception mechanism\"" for a general overview.
538  !! At this level, lower order perception objects are combined into the
539  !! the_neurobio::perception class hierarchy level of the agent. The object
540  !! bound functions see_ and feel_ obtain (**set**) the specific perception
541  !! objects from the external or internal environments of the agent and put
542  !! them into the the_neurobio::perception data structure. Also, memory
543  !! component is updated with the perception data. Perception objects can
544  !! then be used as input into the individual decision-making procedures.
545  !! @note **Templates for outer environmental perceptions**:
546  !! @code
547  !! call proto_parents%individual(ind)%see_food( &
548  !! food_resource_available = habitat_safe%food, &
549  !! time_step_model = 1)
550  !!
551  !! call proto_parents%individual(ind)%see_consp( &
552  !! consp_agents = proto_parents%individual, &
553  !! time_step_model = 1 )
554  !!
555  !! call proto_parents%individual(ind)%see_pred( &
556  !! spatl_agents = predators, &
557  !! time_step_model = 1 )
558  !! call proto_parents%individual(ind)%feel_light(timestep)`
559  !! call proto_parents%individual(ind)%feel_depth()
560  !! @endcode
561  type, public, extends(reproduction) :: perception
562  type(percept_light) :: perceive_light !> perception of light
563  type(percept_depth) :: perceive_depth !> perception of depth
564  type(percept_food) :: perceive_food !> perception of food
565  type(percept_conspecifics) :: perceive_consp !> conspecifics perception
566  type(percept_predator) :: perceive_predator !> perceive predator
567  type(percept_stomach) :: perceive_stomach !> perception for stomach
568  type(percept_body_mass) :: perceive_body_mass !> perception for bodymass
569  type(percept_energy) :: perceive_energy !> percept. for energy
570  type(percept_age) :: perceive_age !> percept. of age
571  type(percept_reprfact) :: perceive_reprfac !> percept. of repr.factor
572  type(memory_perceptual) :: memory_stack !> @note Memory object.
573  contains
574  !> Get **light** perception objects into the individual
575  !! the_neurobio::perception object layer.
576  !! See `the_neurobio::light_perception_get_object()`.
577  procedure, public :: feel_light => light_perception_get_object
578  !> Get **depth** perception objects into the **individual**
579  !! the_neurobio::perception object layer.
580  !! See `the_neurobio::depth_perception_get_object()`.
581  procedure, public :: feel_depth => depth_perception_get_object
582  !> Get available food items within the visual range of the agent, which
583  !! the agent can perceive and therefore respond to. Food perception is
584  !! packaged into the food perception object `this%perceive_food` for
585  !! output. See `the_neurobio::food_perception_get_visrange_objects()`.
586  procedure, public :: see_food => food_perception_get_visrange_objects
587  !> Get available conspecific perception objects within the visual range
588  !! of the agent, which the agent can perceive and therefore respond to.
589  !! See `the_neurobio::consp_perception_get_visrange_objects()`.
590  procedure, public :: see_consp => consp_perception_get_visrange_objects
591  !> Get available predators perception objects within the visual range of
592  !! the agent, which the agent can perceive and therefore respond to.
593  !! See `the_neurobio::predator_perception_get_visrange_objects()`.
594  procedure, public :: see_pred => predator_perception_get_visrange_objects
595  !> Get the **stomach capacity** perception objects into the **individual**
596  !! the_neurobio::perception object layer.
597  !! See `the_neurobio::stomach_perception_get_object()`.
598  procedure, public :: feel_stomach => stomach_perception_get_object
599  !> Get the **body mass** perception objects into the **individual**
600  !! the_neurobio::perception object layer.
601  !! See `the_neurobio::bodymass_perception_get_object()`.
602  procedure, public :: feel_bodymass => bodymass_perception_get_object
603  !> Get the **energy reserves** perception objects into the **individual**
604  !! the_neurobio::perception object layer.
605  !! See `the_neurobio::energy_perception_get_object()`.
606  procedure, public :: feel_energy => energy_perception_get_object
607  !> Get the **age** perception objects into the **individual**
608  !! the_neurobio::perception object layer.
609  !! See `the_neurobio::age_perception_get_object()`.
610  procedure, public :: feel_age => age_perception_get_object
611  !> Get the **reproductive factor** perception objects into the
612  !! **individual** the_neurobio::perception object layer.
613  !! See `the_neurobio::repfac_perception_get_object()`.
614  procedure, public :: feel_repfac => repfac_perception_get_object
615 
616  !> Calculate the risk of **predation** as being **perceived / assessed**
617  !! by this agent.
618  !! See `the_neurobio::perception_predation_risk_objective()`.
619  procedure, public :: predation_risk => perception_predation_risk_objective
620  !> A single umbrella subroutine to get all **environmental** perceptions:
621  !! light, depth.
622  !! See `the_neurobio::perception_objects_get_all_environmental()`.
623  procedure, public :: perceptions_environ => perception_objects_get_all_environmental
624  !> A single umbrella subroutine wrapper to get all **inner** perceptions:
625  !! stomach, body mass, energy, age.
626  !! See `the_neurobio::perception_objects_get_all_inner()`.
627  procedure, public :: perceptions_inner => perception_objects_get_all_inner
628  !> Add the various perception objects to the memory stack object. This
629  !! procedure is called **after** all the perceptual components (light,
630  !! depth food, conspecifics, predators, etc.) are collected (using `set`
631  !! object-bound subroutines) into the perception bundle, so all the
632  !! values are known and ready to be used.
633  !! See `the_neurobio::perception_objects_add_memory_stack()`.
634  procedure, public :: perception_to_memory => perception_objects_add_memory_stack
635 
636  !> Initialise all the perception objects for the current agent. Do not
637  !! fill perception objects with the real data yet.
638  !! See `the_neurobio::perception_objects_init_agent()`.
639  procedure, public :: init_perception => perception_objects_init_agent
640  !> Destroy and deallocate all perception objects.
641  !! See `the_neurobio::perception_objects_destroy()`.
642  procedure, public :: destroy_perception => perception_objects_destroy
643 
644  ! Accessor methods (get).
645  !> Check if the agent sees any food items within its visual range.
646  !! See `the_neurobio::food_perception_is_seeing_food()`.
647  procedure, public :: has_food => food_perception_is_seeing_food
648  !> Check if the agent sees any conspecifics within the visual range.
649  !! See `the_neurobio::consp_perception_is_seeing_conspecifics()`.
650  procedure, public :: has_consp => consp_perception_is_seeing_conspecifics
651  !> Check if the agent sees any predators within the visual range.
652  !! See `the_neurobio::predator_perception_is_seeing_predators()`.
653  procedure, public :: has_pred => predator_perception_is_seeing_predators
654 
655  ! Relative location functions: Food items
656  !> Calculate the number of food items in the perception object that are
657  !! located **below** the actor agent.
658  !! See `the_neurobio::perception_food_items_below_calculate()`
659  procedure, public :: food_items_below_all => &
661  !> Calculate the number of food items in the perception object that are
662  !! located **below** the actor agent within a specific vertical horizon
663  !! [hz_lower,hz_upper]. The horizon limits are relative, in that they
664  !! start from the depth position of the `this` actor agent:
665  !! [z+hz_lower, z+hz_upper].
666  !! See `the_neurobio::perception_food_items_below_horiz_calculate()`.
667  procedure, public :: food_items_below_horiz => &
669  !> A generic interface for the two functions calculating the number of
670  !! food items in the perception object that are located **below** the
671  !! actor agent. See perception::food_items_below_all(),
672  !! perception::food_items_below_horiz().
673  generic, public :: food_items_below => &
674  food_items_below_all, food_items_below_horiz
675  !> Calculate the average mass of a food item from all the items in the
676  !! current perception object that are **below** the actor agent.
677  !! See `the_neurobio::perception_food_mass_below_calculate()`.
678  procedure, public :: food_mass_below_all => &
680  !> Calculate the average mass of a food item from all the items in the
681  !! current perception object that are **below** the actor agent within a
682  !! specific vertical horizon [hz_lower,hz_upper]. The horizon limits are
683  !! relative, in that they start from the depth position of the `this`
684  !! actor agent: [z+hz_lower, z+hz_upper].
685  !! See `the_neurobio::perception_food_mass_below_horiz_calculate()`.
686  procedure, public :: food_mass_below_horiz => &
688  !> A generic interface to the two functions that calculating the
689  !! average mass of food items in the perception object that are located
690  !! **below** the actor agent. See perception::food_mass_below_all(),
691  !! perception::food_mass_below_horiz().
692  generic, public :: food_mass_below => &
693  food_mass_below_all, food_mass_below_horiz
694  !> Calculate the number of food items in the perception object that are
695  !! located **above** the actor agent.
696  !! See `the_neurobio::perception_food_items_above_calculate()`
697  procedure, public :: food_items_above_all => &
699  !> Calculate the number of food items in the perception object that are
700  !! located **above** the actor agent within a specific vertical horizon
701  !! [hz_lower,hz_upper]. The horizon limits are relative, in that they
702  !! start from the depth position of the `this` actor agent:
703  !! [z-hz_upper, z-hz_upper].
704  !! See `the_neurobio::perception_food_items_above_horiz_calculate()`.
705  procedure, public :: food_items_above_horiz => &
707  !> A generic interface for the two functions calculating the number of
708  !! food itemsin the perception object that are located **below** the
709  !! actor agent. See perception::food_items_above_all(),
710  !! perception::food_items_above_horiz().
711  generic, public :: food_items_above => &
712  food_items_above_all, food_items_above_horiz
713  !> Calculate the average mass of a food item from all the items in the
714  !! current perception object that are **above** the actor agent.
715  !! See `the_neurobio::perception_food_mass_above_calculate()`.
716  procedure, public :: food_mass_above_all => &
718  !> Calculate the average mass of a food item from all the items in the
719  !! current perception object that are **above** the actor agent within a
720  !! specific vertical horizon [hz_lower,hz_upper]. The horizon limits are
721  !! relative, in that they start from the depth position of the `this`
722  !! actor agent: [z-hz_upper, z-hz_upper].
723  !! See `the_neurobio::perception_food_mass_above_horiz_calculate()`.
724  procedure, public :: food_mass_above_horiz => &
726  !> A generic interface to the two functions that calculating the
727  !! average mass of food items in the perception object that are located
728  !! **above** the actor agent. See perception::food_mass_above_all(),
729  !! perception::food_mass_above_horiz().
730  generic, public :: food_mass_above => &
731  food_mass_above_all, food_mass_above_horiz
732  !> Calculate the average distance to all food items in the current
733  !! perception object that are **below** the actor agent.
734  !! See `the_neurobio::perception_food_dist_below_calculate()`.
735  procedure, public :: food_dist_below => &
737  !> Calculate the average distance to all food items in the current
738  !! perception object that are **above** the actor agent.
739  !! See `the_neurobio::perception_food_dist_above_calculate()`.
740  procedure, public :: food_dist_above => &
742 
743  ! Relative location functions: conspecifics
744  !> Calculate the number of conspecifics in the perception object that are
745  !! located **below** the actor agent.
746  !! See `the_neurobio::perception_conspecifics_below_calculate()`.
747  procedure, public :: consp_below_all => &
749  !> Calculate the number of conspecifics in the perception object that are
750  !! located **above** the actor agent.
751  !! See `the_neurobio::perception_conspecifics_above_calculate()`.
752  procedure, public :: consp_above_all => &
754  !> Calculate the number of conspecifics in the perception object that are
755  !! located **below** the actor agent within a specific vertical horizon
756  !! [hz_lower,hz_upper].
757  !! See `the_neurobio::perception_conspecifics_below_horiz_calculate()`.
758  procedure, public :: consp_below_horiz => &
760  !> Calculate the number of conspecifics in the perception object that are
761  !! located **above** the actor agent within a specific vertical horizon
762  !! [hz_lower,hz_upper].
763  !! See `the_neurobio::perception_conspecifics_above_horiz_calculate()`.
764  procedure, public :: consp_above_horiz => &
766  !> A generic interface to the two functions that calculating the
767  !! number of conspecifics in the perception object that are located
768  !! **below** the actor agent. See perception::consp_below_all(),
769  !! perception::consp_below_horiz().
770  generic, public :: consp_below => consp_below_all, consp_below_horiz
771  !> A generic interface to the two functions that calculating the
772  !! number of conspecifics in the perception object that are located
773  !! **above** the actor agent. See perception::consp_above_all(),
774  !! perception::consp_above_horiz().
775  generic, public :: consp_above => consp_above_all, consp_above_horiz
776  !> Calculate the average distance to all conspecifics in the current
777  !! perception object that are **below** the actor agent.
778  !! See `the_neurobio::perception_consp_dist_below_calculate()`.
779  procedure, public :: consp_dist_below => &
781  !> Calculate the average distance to all conspecifics in the current
782  !! perception object that are **above** the actor agent.
783  !! See `the_neurobio::perception_consp_dist_above_calculate()`.
784  procedure, public :: consp_dist_above => &
786 
787  ! Relative location functions: predators
788  !> Calculate the number of predators in the perception object that are
789  !! located **below** the actor agent.
790  !! See `the_neurobio::perception_predator_below_calculate()`.
791  procedure, public :: pred_below_all => perception_predator_below_calculate
792  !> Calculate the number of predators in the perception object that are
793  !! located **above** the actor agent.
794  !! See `the_neurobio::perception_predator_above_calculate()`.
795  procedure, public :: pred_above_all => perception_predator_above_calculate
796  !> Calculate the number of predators in the perception object that are
797  !! located **below** the actor agent within a specific vertical horizon
798  !! [hz_lower,hz_upper].
799  !! See `the_neurobio::perception_predator_below_horiz_calculate`.
800  procedure, public :: pred_below_horiz => &
802  !> Calculate the number of predators in the perception object that are
803  !! located **above** the actor agent within a specific vertical horizon
804  !! [hz_lower,hz_upper].
805  !! See `the_neurobio::perception_predator_above_horiz_calculate`.
806  procedure, public :: pred_above_horiz => &
808  !> A generic interface to the two functions that calculating the
809  !! number of predators in the perception object that are located
810  !! **below** the actor agent. See perception::pred_below_all(),
811  !! perception::pred_below_horiz().
812  generic, public :: pred_below => pred_below_all, pred_below_horiz
813  !> A generic interface to the two functions that calculating the
814  !! number of predators in the perception object that are located
815  !! **above** the actor agent. See perception::pred_above_all(),
816  !! perception::pred_above_horiz().
817  generic, public :: pred_above => pred_above_all, pred_above_horiz
818  !> Calculate the average distance to all predators in the current
819  !! perception object that are **below** the actor agent.
820  !! See `the_neurobio::perception_predator_dist_below_calculate()`.
821  procedure, public :: pred_dist_below => &
823  !> Calculate the average distance to all predators in the current
824  !! perception object that are **above** the actor agent.
825  !! See `the_neurobio::perception_predator_dist_above_calculate()`.
826  procedure, public :: pred_dist_above => &
828  !> Calculate the probability of attack and capture of the `this` agent by
829  !! the predator `this_predator`. This probability is a function of the
830  !! distance between the predator and the agent and is calculated by the
831  !! predator-class-bound procedure the_environment::predator::risk_fish().
832  !! @note Note that this version of the procedure accepts `this_predator`
833  !! parameter as class the_neurobio::spatialobj_percept_comp that is
834  !! used for keeping the predator representations in the **perception
835  !! object**. This representation keeps two separate array for
836  !! the_neurobio::spatialobj_percept_comp spatial objects and the
837  !! attack rate.
838  !! See `the_neurobio::predator_capture_probability_calculate_spatobj()`.
839  procedure, public :: risk_pred_s => &
841  !> Calculate the probability of attack and capture of the `this` agent by
842  !! the predator `this_predator`. This probability is a function of the
843  !! distance between the predator and the agent and is calculated by the
844  !! predator-class-bound procedure the_environment::predator::risk_fish().
845  !! @note Note that this version of the procedure accepts `this_predator`
846  !! parameter as class the_neurobio::predator, i.e. for the
847  !! **objective predator object**.
848  !! See `the_neurobio::predator_capture_probability_calculate_pred()`.
849  procedure, public :: risk_pred_p => &
851  !> Calculate the overall direct predation risk for the agent, i.e.
852  !! the probability of attack and capture by the nearest predator.
853  !! See `the_neurobio::predation_capture_probability_risk_wrapper()`.
854  procedure, public :: risk_pred_w => &
856  !> A single generic interface for the calculation of the probability of
857  !! attack and capture of the `this` agent by a predator.
858  !! See `the_neurobio::predator_capture_probability_calculate_spatobj()`,
859  !! `the_neurobio::predator_capture_probability_calculate_pred()` and
860  !! `the_neurobio::predation_capture_probability_risk_wrapper()`.
861  generic, public :: risk_pred => risk_pred_s, risk_pred_p, risk_pred_w
862 
863  !> Calculate the probability of capture of a subjective representation of
864  !! food item based on the data from the perceptual memory stack. See
865  !! `the_neurobio::food_perception_probability_capture_memory_object()`.
866  procedure, public :: food_probability_capture_subjective => &
868 
869  end type perception
870 
871  !> Perceptual components of motivational states. Plugged into all `STATE_`,
872  !! attention etc. These components are linked to specific inner or outer
873  !! perception objects (stimuli). Their sum result(s) in the overall
874  !! value of the motivation component.
875  type, public :: percept_components_motiv
876  !> Light perception, direct environmental.
877  real(srp) :: light
878  !> Depth perception, direct environmental.
879  real(srp) :: depth
880  !> Perception of directly seen food items, spatial.
881  real(srp) :: food_dir
882  !> Perception of the food items in the memory stack.
883  real(srp) :: food_mem
884  !> Perception of conspecifics, spatial.
885  real(srp) :: conspec
886  !> Direct perception of predators, spatial. Based on the distance
887  !! to the nearest predator.
888  real(srp) :: pred_dir
889  !> General perception of predation risk, spatial. Based on a sum of the
890  !! number of predators in the perception object weighted by the number of
891  !! predators in the memory stack.
892  real(srp) :: predator
893  !> Perception of the stomach contents, direct, internal.
894  real(srp) :: stomach
895  !> Perception of the body mass, direct, internal.
896  real(srp) :: bodymass
897  !> Perception of the energy reserves, direct, internal.
898  real(srp) :: energy
899  !> Age perception, direct internal.
900  real(srp) :: age
901  !> Perception of the reproductive factor, based on the sex steroid
902  !! hormones, calculated differently in males and females.
903  real(srp) :: reprfac
904  contains
905  !> Initialise perception components for a motivation state object.
906  !! See `the_neurobio::perception_component_motivation_init_zero()`.
907  procedure, public :: init => perception_component_motivation_init_zero
908  !> Calculate the **maximum** value over all the perceptual components.
909  !! See `the_neurobio::perception_component_maxval()`.
910  procedure, public :: max_value => perception_component_maxval
911  !> Calculate individual perceptual components for **this** motivational
912  !! state using the **neuronal response** function, for an agent. This
913  !! agent has intent[in], so is **unchanged** in this procedure. Also
914  !! `motivation_components` can take optional arbitrary (fake) perception
915  !! values.
916  !! @note This procedure is used for normal calculations of motivation
917  !! components. A similar method with the agent intent[inout]
918  !! the_neurobio::percept_components_motiv::motivation_components_init()
919  !! is used to initialise an agent.
920  !! See
921  !! `the_neurobio::perception_components_neuronal_response_calculate()`.
922  procedure, public :: motivation_components => &
924  !> Calculate individual perceptual components for **this** motivational
925  !! state using the **neuronal response** function, for an agent. This
926  !! agent has intent[inout], so **is changed** (gene labels reset).
927  !> @warning This procedure is used only for initialisation of an agent.
928  !! For normal calculation of the motivational components use
929  !! the_neurobio::percept_components_motiv::motivation_components()
930  !! procedure that does not change the actor agent (intent[in]).
931  !! See `the_neurobio::perception_components_neuronal_response_init_set()`.
932  procedure, public :: motivation_components_init => &
934  !> Initialise the attention components of the emotional state to their
935  !! default parameter values. Attention sets weights to individual
936  !! perceptual components when the overall weighted sum is calculated.
937  !! The default weights are parameters defined in `COMMONDATA`.
938  !! See `the_neurobio::perception_components_attention_weights_init()`.
939  procedure, public :: attention_init => &
941  end type percept_components_motiv
942 
943  !> These types describe the **neurobiological states** of the agent.
944  !! (1) Each state may have several components that are related to specific
945  !! inner or outer perception objects (stimuli). (2) There is also a
946  !! `motivation` component that describes the global **motivation** value
947  !! for this state.
948  !!
949  !! This is the **base type** that serves as root for all other
950  !! motivation and emotion states, which are **extensions** of this
951  !! the_neurobio::state_motivation_base type.
952  type, abstract, public :: state_motivation_base
953  !> Label for the motivation state, fixed, **cannot be changed**.
954  !! @note Note that the label can be used as an **ID** for the motivational
955  !! state.
956  !! @note Note that we cannot use `protected` attribute within derived type,
957  !! so make it `private` and implement the accessor function
958  !! \%label_is. The label component is then set in each derived
959  !! motivation object in its respective `clean_init` procedure.
960  !! @note Note that the `clean_init` procedure is deferred (see abstract
961  !! interface) in this abstract type. Specific `clean_init` should
962  !! be implemented for each of the separate motivational/emotional
963  !! state type.
964  !! @note The procedure `motivation_components` does not seem to be necessary
965  !! at this level of class hierarchy as it would duplicate that in
966  !! the_neurobio::percept_components_motiv. Therefore just call the
967  !! upper procedure \%percept_component\%motivation_components().
968  character(len=LABEL_LENGTH), private :: label
969  !> **Perceptual components**.
970  type(percept_components_motiv) :: percept_component
971  !> **Attention** sets the weights given to the individual perceptual
972  !! components in the calculation of the motivation value.
973  type(percept_components_motiv) :: attention_weight
974  !> Overall **primary motivation values**.
975  real(srp) :: motivation_prim
976  !> Overall **final** motivation value after modulation is performed.
977  real(srp) :: motivation_finl
978  !> Overall GOS value, is this motivation state is dominant (TRUE/FALSE)?
979  !> @note Note that only one state can be dominant at a time (Or not?
980  logical :: dominant_state
981  contains
982  !> Abstract **init** function that has to be overridden by each object
983  !! that extends the basic motivational state type.
984  !! @warning Needs abstract interface, with import of the base object
985  !! type `the_neurobio::state_motivation_base`.
986  procedure(motivation_init_root), public, deferred :: clean_init
987  !> These are basically the accessor `get`-functions, the `set`-functions
988  !! are based on neural response from the perception object
989  !! the_neurobio::appraisal.
990  !> Get **light** perception component for this motivation state.
991  !! See `the_neurobio::state_motivation_light_get()`.
992  procedure, public :: get_light => state_motivation_light_get
993  !> Get **depth** perception component for this motivation state.
994  !! See `the_neurobio::state_motivation_depth_get()`.
995  procedure, public :: get_depth => state_motivation_depth_get
996  !> Get **directly perceived food** perception component for this
997  !! motivation state. See `the_neurobio::state_motivation_food_dir_get()`.
998  procedure, public :: get_food_dir => state_motivation_food_dir_get
999  !> Get **food in past memory** perception component for this motivation
1000  !! state. See `the_neurobio::state_motivation_food_mem_get()`.
1001  procedure, public :: get_food_mem => state_motivation_food_mem_get
1002  !> Get **conspecifics** perception component for this motivation state.
1003  !! See `the_neurobio::state_motivation_conspec_get()`.
1004  procedure, public :: get_conspec => state_motivation_conspec_get
1005  !> Standard "get" function for the state neuronal **direct predation**
1006  !! effect component.
1007  !! See `the_neurobio::state_motivation_pred_dir_get()`.
1008  procedure, public :: get_pred_dir => state_motivation_pred_dir_get
1009  !> Get **predator** perception component for this motivation state.
1010  !! See `the_neurobio::state_motivation_predator_get()`.
1011  procedure, public :: get_predator => state_motivation_predator_get
1012  !> Get **stomach contents** perception component for this motivation
1013  !! state. See `the_neurobio::state_motivation_stomach_get()`.
1014  procedure, public :: get_stomach => state_motivation_stomach_get
1015  !> Get **body mass** perception component for this motivation state.
1016  !! See `the_neurobio::state_motivation_bodymass_get()`.
1017  procedure, public :: get_bodymass => state_motivation_bodymass_get
1018  !> Get **energy reserves** perception component for this motivation
1019  !! state. See `the_neurobio::state_motivation_energy_get()`.
1020  procedure, public :: get_energy => state_motivation_energy_get
1021  !> Get **age** perception component for this motivation state.
1022  !! See `the_neurobio::state_motivation_age_get()`.
1023  procedure, public :: get_age => state_motivation_age_get
1024  !> Get **reproductive factor** perception component for this motivation
1025  !! state. See `the_neurobio::state_motivation_reprfac_get()`.
1026  procedure, public :: get_reprfac => state_motivation_reprfac_get
1027  !> Get the overall **primary motivation value** (before modulation).
1028  !! See `the_neurobio::state_motivation_motivation_prim_get()`.
1029  procedure, public :: motivation_value_prim => &
1031  !> Get the overall **final motivation value** (after modulation).
1032  !! See `the_neurobio::state_motivation_motivation_get()`.
1033  procedure, public :: motivation_value => state_motivation_motivation_get
1034  !> Check if the root state is the dominant state in GOS.
1035  !! See `the_neurobio::state_motivation_is_dominant_get()`.
1036  procedure, public :: is_dominant => state_motivation_is_dominant_get
1037  !> Get the fixed label for this motivational state. Note that the label
1038  !! is fixed and cannot be changed.
1039  !! See `the_neurobio::state_motivation_fixed_label_get()`.
1040  procedure, public :: label_is => state_motivation_fixed_label_get
1041  !> Transfer attention weights between two motivation state components.
1042  !! See `the_neurobio::state_motivation_attention_weights_transfer()`.
1043  procedure, public :: attention_copy => &
1045  !> Calculate the maximum value over all perceptual components.
1046  !! See `the_neurobio::state_motivation_percept_maxval()`.
1047  procedure, public :: max_perception => state_motivation_percept_maxval
1048  !> Calculate the level of the **primary motivation**.
1049  !! See `the_neurobio::state_motivation_calculate_prim()`.
1050  procedure, public :: motivation_calculate => &
1052  end type state_motivation_base
1053 
1054  !> Abstract interface for the deferred **init** function `clean_init` that
1055  !! has to be overridden by each object that extends the basic motivational
1056  !! state type.
1057  abstract interface
1058  elemental subroutine motivation_init_root(this)
1059  !> @warning Import base type. Without import gfortran issues this error:
1060  !! `Error: Derived type 'state_motivation_base' at (1) is being
1061  !! used before it is defined`.
1062  import :: state_motivation_base
1063  class(state_motivation_base), intent(inout) :: this
1064  end subroutine motivation_init_root
1065  end interface
1066 
1067  !> The motivational state of **hunger**. Evokes food seeking, eating, higher
1068  !! activity, emigrating and habitat switching.
1069  type, public, extends(state_motivation_base) :: state_hunger
1070  contains
1071  !> Init and cleanup **hunger** motivation object.
1072  !! See `the_neurobio::state_hunger_zero()`.
1073  procedure, public :: clean_init => state_hunger_zero
1074  end type state_hunger
1075 
1076  !> The state of **fear state**. Evokes active escape, fleeing,
1077  !! emigration and habitat switch.
1078  type, public, extends(state_motivation_base) :: state_fear_defence
1079  contains
1080  !> Init and cleanup **fear state** motivation object.
1081  !! See `the_neurobio::state_fear_defence_zero()`.
1082  procedure, public :: clean_init => state_fear_defence_zero
1083  end type state_fear_defence
1084 
1085  !> The state of **reproduction**. Evokes seeking conspecifics and
1086  !! mating during the reproductive phase.
1087  type, public, extends(state_motivation_base) :: state_reproduce
1088  contains
1089  !> Init and cleanup **reproductive** motivation object.
1090  !! See `the_neurobio::state_reproduce_zero()`.
1091  procedure, public :: clean_init => state_reproduce_zero
1092  end type state_reproduce
1093 
1094  !. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1095  ! Define the **motivational/affective system** of the agent.
1096  !. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1097 
1098  !> **Motivation** is a collection of all internal motivational states of
1099  !! the agent. This type is also used in defining *Expectancies* of
1100  !! motivations.
1101  type, public :: motivation
1102  !> - **hunger** is the state of the_neurobio::state_hunger.
1103  type(state_hunger) :: hunger
1104  !> - **fear state** is the state of the_neurobio::state_fear_defence;
1105  type(state_fear_defence) :: fear_defence
1106  !> - **reproduction** is the state of the_neurobio::state_reproduce;
1108  !> - `number_of_states` is a private value indicating the total number of
1109  !! motivational states. It is initialised to 4 in the
1110  !! the_neurobio::motivation_init_all_zero().
1111  !! .
1112  integer, private :: number_of_states
1113  contains
1114  !> Init the expectancy components to a zero state.
1115  !! See `the_neurobio::motivation_init_all_zero()`.
1116  procedure, public :: init => motivation_init_all_zero
1117  !> Calculate maximum value of the perception components across all
1118  !! motivations
1119  !! See `the_neurobio::motivation_max_perception_calc()`.
1120  procedure, public :: max_perception => motivation_max_perception_calc
1121  !> Return the vector of final motivation values for all motivational
1122  !! state components.
1123  !! See `the_neurobio::motivation_return_final_as_vector()`.
1124  procedure, public :: finals => motivation_return_final_as_vector
1125  !> Calculate the maximum value of the final motivations across all
1126  !! motivational state components.
1127  !! See `the_neurobio::motivation_maximum_value_motivation_finl()`.
1128  procedure, public :: max_final => motivation_maximum_value_motivation_finl
1129  !> Checks if the test value is the maximum **final** motivation value
1130  !! across all motivational state components.
1131  !! See `the_neurobio::motivation_val_is_maximum_value_motivation_finl()`.
1132  procedure, public :: is_max_final_val => &
1134  !> Checks if the test value is the maximum **final** motivation value
1135  !! across all motivational state components.
1136  !! See `the_neurobio::motivation_val_is_maximum_value_motivation_finl_o()`.
1137  procedure, public :: is_max_final_obj => &
1139  generic, public :: is_max_final => is_max_final_val, is_max_final_obj
1140  !> Reset all GOS indicators for this motivation object.
1141  !! See `the_neurobio::motivation_reset_gos_indicators()`.
1142  procedure, public :: gos_ind_reset => motivation_reset_gos_indicators
1143  !> Functions calculating the overall **motivation state values**.
1144  !! @important These functions calculate the **motivation state** of
1145  !! the agent. This is a kind of a summator for the many
1146  !! perception-specific state components into the unitary
1147  !! inner **motivation state**.
1148  !! See `the_neurobio::motivation_primary_sum_components()`.
1149  procedure, public :: motivation_primary_calc => &
1151  !> Functions re-calculating the overall motivation values after
1152  !! **modulation**.
1153  !! @note Modulation modifies the motivation value based on other
1154  !! properties of the agent with effect coefficients
1155  !! depending on the genome.
1156  !! See `the_neurobio::motivation_modulation_absent()`.
1157  procedure, public :: modulation_none => motivation_modulation_absent
1158 
1159  end type motivation
1160 
1161  !> Individual motivation/emotion memory stack, a memory component that
1162  !! saves the values of the **final motivations** at previous time
1163  !! steps of the model. Not whole state (`STATE_`) objects are saved for
1164  !! simplicity. `add_to_history` is used in unmodified form. Decision making
1165  !! can make use of this emotional memory stack.
1167  real(srp), dimension(HISTORY_SIZE_MOTIVATION) :: hunger
1168  real(srp), dimension(HISTORY_SIZE_MOTIVATION) :: defence_fear
1169  real(srp), dimension(HISTORY_SIZE_MOTIVATION) :: reproduction
1170  !> Memory also includes a component for the global organismic state (GOS).
1171  !! @note Note that GOS cannot be determined at the `APPRAISAL` level, is
1172  !! updated later, so we may need a separate add-to-memory function.
1173  character(len=LABEL_LENGTH), dimension(HISTORY_SIZE_MOTIVATION) :: gos_main
1174  !> Memory also includes the motivation level that has resulted in the
1175  !! current GOS. This is a memory for the arousal. Although doubles one of
1176  !! the basic motivations (hunger etc.), but here for convenience.
1177  real(srp), dimension(HISTORY_SIZE_MOTIVATION) :: gos_arousal
1178  !> Memory also includes the GOS repeat counter, this is the number of
1179  !! times that the same GOS state is repeated.
1180  !! See `the_neurobio::gos_global` for implementation details.
1181  integer, dimension(HISTORY_SIZE_MOTIVATION) :: gos_repeated
1182  contains
1183  !> Add emotional components into the memory stack.
1184  !! See `the_neurobio::emotional_memory_add_to_stack()`.
1185  procedure, public :: add_to_memory => emotional_memory_add_to_stack
1186  !> Add the current GOS label or/and arousal value and/or arousal repeat
1187  !! count into the emotional memory stack.
1188  !! See `the_neurobio::emotional_memory_add_gos_to_stack()`.
1189  procedure, public :: gos_to_memory => emotional_memory_add_gos_to_stack
1190  !> Cleanup and destroy the emotional memory stack.
1191  !! See `the_neurobio::emotional_memory_cleanup_stack()`.
1192  procedure, public :: memory_cleanup => emotional_memory_cleanup_stack
1193  !> Get the average value of the hunger motivation state within the
1194  !! whole emotional memory stack.
1195  !! See `the_neurobio::emotional_memory_hunger_get_mean()`.
1196  procedure, public :: get_hunger_mean => &
1198  !> Get the average value of the fear state motivation state within
1199  !! the whole emotional memory stack.
1200  !! See `the_neurobio::emotional_memory_actve_avoid_get_mean()`.
1201  procedure, public :: get_active_avoid_mean => &
1203  !> Get the average value of the reproductive motivation state within the
1204  !! whole emotional memory stack.
1205  !! See `the_neurobio::emotional_memory_reproduct_get_mean()`.
1206  procedure, public :: get_reproduction_mean => &
1208  !> Get the average value of the GOS arousal within the whole emotional
1209  !! memory stack.
1210  !! See `the_neurobio::emotional_memory_arousal_mean()`.
1211  procedure, public :: get_arousal => emotional_memory_arousal_mean
1212  end type memory_emotional
1213 
1214  !. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1215  !> The **appraisal** level. At this level, perception objects are feed into
1216  !! the commondata::gamma2gene() sigmoid function and the neuronal responses
1217  !! are obtained at the output. Neuronal responses for different perception
1218  !! objects are then summed up and the promary motivation values are obtained.
1219  !! Following this, modulation alters some of the primary motivation values
1220  !! resulting in the final motivation values. See @ref aha_neurobio_flow
1221  !! "\"From perception to GOS\"" for an overview.
1222  type, public, extends(perception) :: appraisal
1223  !> The appraisal component plugs-in the different motivational/emotional
1224  !! objects.
1225  type(motivation) :: motivations
1226  !> The emotional state memory stack object.
1227  type(memory_emotional) :: memory_motivations
1228  contains
1229  !> Initialise and cleanup all appraisal object components and sub-objects.
1230  !! See `the_neurobio::appraisal_init_zero_cleanup_all()`.
1231  procedure, public :: init_appraisal => appraisal_init_zero_cleanup_all
1232  !> Set the individual to be **dead**. This method overrides the
1233  !! the_genome::individual_genome::dies() method, nullifying all
1234  !! reproductive and neurobiological and behavioural objects.
1235  !! However, this function does not deallocate the individual
1236  !! agent object, this may be a separate destructor function.
1237  !! The `dies` method is implemented at the following levels
1238  !! of the agent object hierarchy (upper overrides the lower level):
1239  !! - the_genome::individual_genome::dies();
1240  !! - the_neurobio::appraisal::dies();
1241  !! - the_neurobio::gos_global::dies();
1242  !! - the_individual::individual_agent::dies().
1243  !! .
1244  !! See `the_individual::appraisal_agent_set_dead()`.
1245  procedure, public :: dies => appraisal_agent_set_dead
1246  !> Calculate **perception components** for each of the motivational state
1247  !! component.
1248  !! @brief Initialise motivational states from perception objects
1249  !! through the neuronal response function.
1250  !! @important We initialise here all the **perception components**
1251  !! (`the_neurobio::percept_components_motiv`) for every
1252  !! **motivational state** component.
1253  !! See `the_neurobio::appraisal_perceptual_comps_motiv_neur_response_calculate()`.
1254  procedure, public :: motivations_percept_components => &
1256  !> Calculate **primary motivation values** of the agent by summing up
1257  !! the perception components of each motivation state.
1258  !! @details Here it is just wrapper to the `the_neurobio::motivation`
1259  !! -bound procedure `motivation_primary_calc`.
1260  !! See `the_neurobio::appraisal_primary_motivations_calculate()`.
1261  procedure, public :: motivations_primary_calc => &
1263  !> Calculate the **final motivation values** after **modulation**.
1264  !! @details Perform developmental and/or genetic modulation of primary
1265  !! motivations that result in the final motivation values.
1266  !! @note Genetic modulation backend
1267  !! the_neurobio::appraisal_motivation_modulation_genetic() is
1268  !! bound to the agent rather than the_neurobio::motivation.
1269  !! See `the_neurobio::appraisal_motivation_modulation_non_genetic()`.
1270  procedure, public :: modulation => &
1272  !> Add individual final emotional state components into the emotional
1273  !! memory stack.
1274  !! See `the_neurobio::appraisal_add_final_motivations_memory()`.
1275  procedure, public :: motivations_to_memory => &
1277  !> Calculate the probability of successful reproduction for `this` agent
1278  !! in its current state.
1279  !! @note Note that this function is defined and bound to
1280  !! `the_neurobio::appraisal` but used in `the_neurobio::reproduce`
1281  !! behavioural component class.
1282  !! See `the_neurobio::reproduce_do_probability_reproduction_calc()`.
1283  procedure, public :: probability_reproduction => &
1285  !> Determine a stochastic outcome of **this** agent reproduction.
1286  !! Returns TRUE if the agent has reproduced successfully.
1287  !! See `the_neurobio::reproduction_success_stochast()`.
1288  procedure, public :: reproduction_success => reproduction_success_stochast
1289  end type appraisal
1290 
1291  !. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1292  ! Define the **Global Organismic State** of the agent.
1293  !. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1294 
1295  !> Global organismic state (GOS) level. GOS is defined by the dominant
1296  !! motivational state component (`STATE_`), namely, by the logical flag
1297  !! \%dominant_state. If this logical flag is TRUE for a particular
1298  !! motivational state component, this state is the GOS. Thus, there should
1299  !! be is no separate data component(s) e.g. "value" for GOS. The values
1300  !! the_neurobio::gos_global::gos_main and
1301  !! the_neurobio::gos_global::gos_arousal can be inferred from the
1302  !! motivations, here are doubled mainly for convenience. See @ref
1303  !! aha_neurobio_flow "\"From perception to GOS\"" for an overview.
1304  type, public, extends(appraisal) :: gos_global
1305  !> Current global organismic state (GOS). Obtained from the GOS-specific
1306  !! emotional state \%label data component.
1307  character(len=LABEL_LENGTH) :: gos_main
1308  !> This is the current value of the dominant motivation.
1309  real(srp) :: gos_arousal
1310  !> Integer number of the same GOS repetition, e.g. if GOS is the same the
1311  !! second time, gets 2 etc. Needed to asymptotically reduce GOS arousal
1312  !! when it is repeated, so smaller stimuli could overtake control.
1313  integer :: gos_repeated
1314  contains
1315  !> Initialise GOS engine components to a zero state.
1316  !! See `the_neurobio::gos_init_zero_state()`.
1317  procedure, public :: init_gos => gos_init_zero_state
1318  !> Set the individual to be **dead**. This method overrides the
1319  !! the_genome::individual_genome::dies() method, nullifying all
1320  !! reproductive and neurobiological and behavioural objects.
1321  !! However, this function does not deallocate the individual
1322  !! agent object, this may be a separate destructor function.
1323  !! The `dies` method is implemented at the following levels
1324  !! of the agent object hierarchy (upper overrides the lower level):
1325  !! - the_genome::individual_genome::dies();
1326  !! - the_neurobio::appraisal::dies();
1327  !! - the_neurobio::gos_global::dies();
1328  !! - the_individual::individual_agent::dies().
1329  !! .
1330  !! See `the_individual::gos_agent_set_dead()`.
1331  procedure, public :: dies => gos_agent_set_dead
1332  !> Find and set the global organismic state (GOS) based on the various
1333  !! available motivation values.
1334  !! See `the_neurobio::gos_find_global_state()`.
1335  procedure, public :: gos_find => gos_find_global_state
1336  !> Reset all motivation states as NOT dominant with respect to the GOS.
1337  !! See `the_neurobio::gos_reset_motivations_non_dominant()`.
1338  procedure, public :: gos_reset => gos_reset_motivations_non_dominant
1339  !> Get the current global organismic state (GOS).
1340  !! See `the_neurobio::gos_global_get_label()`.
1341  procedure, public :: gos_label => gos_global_get_label
1342  !> Get the overall level of arousal. Arousal is the current level
1343  !! of the dominant motivation that has brought about the current GOS
1344  !! at the previous time step.
1345  !! See `the_neurobio::gos_get_arousal_level()`.
1346  procedure, public :: arousal => gos_get_arousal_level
1347  !> Modulate the attention weights to suppress all perceptions alternative
1348  !! to the current GOS. This is done using the attention modulation
1349  !! interpolation curve.
1350  !! See `the_neurobio::gos_attention_modulate_weights()`.
1351  procedure, public :: attention_modulate => gos_attention_modulate_weights
1352  end type gos_global
1353 
1354  ! Implementation procedures for all "init" methods are private.
1357 
1358 contains ! ........ implementation of procedures for this level ................
1359 
1360  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1361  ! Functions linked with FOOD PERCEPTION
1362  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1363 
1364  !-----------------------------------------------------------------------------
1365  !> Initiate an empty **food** perception object with known number of
1366  !! components.
1367  elemental subroutine percept_food_create_init(this, maximum_number_food_items)
1368  class(percept_food), intent(inout) :: this
1369 
1370  !> @param[in] maximum_number_food_items Maximum number of food items in the
1371  !! food perception object, normally equal to the partial food
1372  !! resource indexing order
1373  !! `commondata::food_select_items_index_partial`.
1374  integer, intent(in) :: maximum_number_food_items
1375 
1376  ! Local counter, not needed in newer vector form, TODO: delete after
1377  ! speed test
1378  !integer :: i
1379 
1380  if (.not. allocated(this%foods_seen)) &
1381  allocate(this%foods_seen(maximum_number_food_items))
1382  if (.not. allocated(this%foods_distances)) &
1383  allocate(this%foods_distances(maximum_number_food_items))
1384 
1385  !> ### Implementation details ###
1386  ! Create every food item in the perception object array.
1387  ! do i = 1, maximum_number_food_items
1388  ! call this%foods_seen(i)%create()
1389  ! end do
1390  !> Create all food items in the perception array (`create` is elemental
1391  !! procedure).
1392  call this%foods_seen%create()
1393 
1394  !> Initialise all other components of the perception object.
1395  this%foods_distances = missing !> array
1396 
1397  !> Set the initial number of food items in the perception object to the
1398  !! maximum number using the function `percept_food_number_seen` below.
1399  ! @note Call outside of this module:
1400  !! `call this%number(maximum_number_food_items)`.
1401  this%food_seen_count = maximum_number_food_items
1402 
1403  end subroutine percept_food_create_init
1404 
1405  !-----------------------------------------------------------------------------
1406  !> Set the total number of food items perceived (seen) in the food
1407  !! perception object. Do not reallocate the perception object components
1408  !! with respect to this new number yet.
1409  subroutine percept_food_number_seen(this, number_set)
1410  class(percept_food), intent(inout) :: this
1411  !> @param[in] Set the number of food items in the perception object.
1412  integer, intent(in) :: number_set
1413 
1414  this%food_seen_count = number_set
1415 
1416  end subroutine percept_food_number_seen
1417 
1418  !-----------------------------------------------------------------------------
1419  !> Make the food perception object, fill it with the actual data arrays.
1420  !! @note Note that the size and allocation is set by the `init` method.
1421  subroutine percept_food_make_fill_arrays(this, items, dist)
1422  class(percept_food), intent(inout) :: this
1423 
1424  !> @param[in] items an array of food items that form the perception object.
1425  type(food_item), intent(in), dimension(:) :: items
1426 
1427  !> @param[in] dist an array of the distances between the agent and each of
1428  !! the food items in the perception object.
1429  real(SRP), intent(in), dimension(:) :: dist
1430 
1431  ! Local adjusted value of the number of food items seen
1432  ! @note Used in testing for non-conformant input arrays.
1433  integer :: n_adjusted
1434 
1435  ! PROCNAME is the procedure name for logging and debugging (with MODNAME).
1436  character(len=*), parameter :: PROCNAME = "(percept_food_make_fill_arrays)"
1437 
1438  !> ### Implementation details ###
1439  !> First we check for non-conforming input arrays and re-init and
1440  !! reallocate the perception object, if needed, to the minimum value.
1441  check_conforming: if (size(items) /= size(dist)) then
1442  n_adjusted = (min(size(items), size(dist)))
1443  call this%destroy()
1444  call this%init(n_adjusted)
1445  !> Report this issue to the log.
1446  call log_msg("WARNING: " // procname // &
1447  ": Non-conforming input arrays, re-initialised to " // &
1448  tostr(n_adjusted) // " food items.")
1449  end if check_conforming
1450 
1451  !> Second, fill the dynamic food perception object with the data
1452  !! from the input arrays. They should have conforming sizes now.
1453  this%foods_seen = items
1454  this%foods_distances = dist
1455 
1456  end subroutine percept_food_make_fill_arrays
1457 
1458  !-----------------------------------------------------------------------------
1459  !> Get the number (count) of food items seen. Trivial.
1460  elemental function percept_food_get_count_found (this) result (count_obj)
1461  class(percept_food), intent(in) :: this
1462  integer :: count_obj
1463 
1464  count_obj = this%food_seen_count
1465 
1466  end function percept_food_get_count_found
1467 
1468  !-----------------------------------------------------------------------------
1469  !> Get the average size of food items seen. Trivial.
1470  elemental function percept_food_get_meansize_found (this) result (size_obj)
1471  class(percept_food), intent(in) :: this
1472  real(srp) :: size_obj
1473 
1474  if (this%food_seen_count <1) then
1475  size_obj = 0.0_srp
1476  else
1477  size_obj = average(this%foods_seen%size)
1478  end if
1479 
1480  end function percept_food_get_meansize_found
1481 
1482  !-----------------------------------------------------------------------------
1483  !> Get the average mass of food items seen. Trivial.
1484  elemental function percept_food_get_meanmass_found (this) result (mass_obj)
1485  class(percept_food), intent(in) :: this
1486  real(srp) :: mass_obj
1487 
1488  if (this%food_seen_count < 1) then
1489  mass_obj = 0.0_srp
1490  else
1491  ! @note Alternatively can also use OO frontent for mass directly:
1492  ! mass_obj = average( this%foods_seen%get_mass() )
1493  mass_obj = average( size2mass_food(this%foods_seen%size) )
1494  end if
1495 
1496  end function percept_food_get_meanmass_found
1497 
1498  !-----------------------------------------------------------------------------
1499  !> Get the average distance to the food items seen. Trivial.
1500  elemental function percept_food_get_meandist_found (this) result (dist_obj)
1501  class(percept_food), intent(in) :: this
1502  real(srp) :: dist_obj
1503 
1504  if (this%food_seen_count <1) then
1505  dist_obj = missing !> If no food items seen, we have undefined distance.
1506  else
1507  dist_obj = average(this%foods_distances)
1508  end if
1509 
1510  end function percept_food_get_meandist_found
1511 
1512  !-----------------------------------------------------------------------------
1513  !> Deallocate and delete a **food** perception object.
1514  elemental subroutine percept_food_destroy_deallocate(this)
1515  class(percept_food), intent(inout) :: this
1516 
1517  if (allocated(this%foods_seen)) deallocate(this%foods_seen)
1518  if (allocated(this%foods_distances)) deallocate(this%foods_distances)
1519  this%food_seen_count = unknown
1520 
1521  end subroutine percept_food_destroy_deallocate
1522 
1523  !-----------------------------------------------------------------------------
1524  !> Get available food items within the visual range of the agent, which the
1525  !! agent can perceive and therefore respond to. Food perception is packaged
1526  !! into the food perception object this\%perceive_food for output.
1527  !!
1528  !! **Food perception** is quite complex to implement as it requires
1529  !! determining individual food items within the current visual range
1530  !! of the agent. There are, however, potentially thousands (or
1531  !! millions) of food items in the food resource, each of the food
1532  !! items is stochastic (e.g. they have different sizes), so visual
1533  !! range differ for each item and each agent should determine
1534  !! food items in its proximity at numerous time steps of the model.
1535  !! This means repeating huge loops many times for each agent at
1536  !! each time step. This is approached by array segmentation: the
1537  !! perception object is obtained by *partial indexing* of a very
1538  !! limited number (=`commondata::food_select_items_index_partial`) of
1539  !! only the nearest food items, the agent's visual range is then
1540  !! determined for each of this nearest neighbouring food items, and
1541  !! finally those food items that individually fall within the visual
1542  !! range are included into the perception object.
1543  !! @note Note that there are three similar procedures that detect spatial
1544  !! objects within the visual range of the agent:
1545  !! - the_neurobio::perception::see_food -- perception of food items;
1546  !! - the_neurobio::perception::see_consp -- perception of conspecifics:
1547  !! - the_neurobio::perception::see_pred -- perception of predators.
1548  !! .
1549  !! All these procedures were actually implemented using the first
1550  !! (the_neurobio::perception::see_food) as a template. All three
1551  !! implement partial indexing of the nearest spatial objects to
1552  !! accelerate computation of large arrays of spatial objects.
1554  food_resource_available, &
1555  time_step_model)
1556  class(perception), intent(inout) :: this
1557 
1558  !> @param[in] food_resource_available Global food resource object from
1559  !! which we select neighbouring item components that are
1560  !! present within the visual range of the agent.
1561  class(food_resource), intent(in) :: food_resource_available
1562 
1563  !> @param[in] time_step_model The current time step of the model.
1564  integer, optional, intent(in) :: time_step_model
1565 
1566  ! PROCNAME is the procedure name for logging and debugging (with MODNAME).
1567  character(len=*), parameter :: PROCNAME = &
1568  "(food_perception_get_visrange_objects)"
1569 
1570  !> ### Notable variables and parameters ###
1571  !> - **dist_foods** - temporary array of food items
1572  !! (`the_environment::food_item`) available to the agent.
1573  ! @note We cannot just place neighbours = food_resource_available\%food
1574  ! in the call to the this\%neighbours(). function and need
1575  ! a raw array of `the_environment::food_item`'s.
1576  ! @note This is a component of the input array of objects we search among.
1577  type(food_item), dimension(size(food_resource_available%food)) :: dist_foods
1578 
1579  !> - **dist_food_neighbours** - temporary array of the distances to the
1580  !! neighbouring food items.
1581  ! @note Note that we determine the size of the array the same as the
1582  ! whole input food resource size. We can use the number
1583  ! `number_food_items`, but determining from array is safer if
1584  ! `number_food_items` parameter goes un-updated for some reasons.
1585  real(SRP), dimension(size(food_resource_available%food)) :: &
1586  dist_food_neighbours
1587 
1588  !> - **dist_food_index** - temporary partial index vector for the
1589  !! distances to the neighbouring food items.
1590  integer, dimension(size(food_resource_available%food)) :: dist_food_index
1591 
1592  ! Temporary possible error status for sub-procedures
1593  logical :: dist_food_errflag
1594 
1595  !> - **irradiance_agent_depth** - local variable defining the irradiance
1596  !! (illumination) at the current depth of the agent. Needed to calculate
1597  !! the agent's visual range.
1598  real(SRP) :: irradiance_agent_depth
1599 
1600  !> - **food_item_area** - local variable defining the area of the food
1601  !! item. It is an array, area of each item in the
1602  !! `food_resource_available` and `dist_foods`. Needed to calculate
1603  !! the agent's visual range.
1604  real(SRP), dimension(size(food_resource_available%food)) :: food_item_area
1605 
1606  !> - **food_item_visual_range** - local variable defining the visual range
1607  !! of the agent for detecting each of the food items (with known areas)
1608  !! at the agent's current depth.
1609  real(SRP), dimension(size(food_resource_available%food)) :: &
1610  food_item_visual_range
1611 
1612  !> - **food_items_percept_in_visrange** - local sorted array of food
1613  !! objects that are within the visual range of the agent for output.
1614  !! The array should normally have the size of
1615  !! commondata::food_select_items_index_partial elements, but only the
1616  !! first `food_items_n_visrange` elements of it are actually within the
1617  !! visual range.
1618  type(food_item), dimension(FOOD_SELECT_ITEMS_INDEX_PARTIAL) :: &
1619  food_items_percept_in_visrange
1620 
1621  !> - **food_items_dist_sorted** - temporary local sorted array of
1622  !! distances between the agent and each of the nearest neighbouring food
1623  !! items, sorted for output.
1624  real(SRP), dimension(FOOD_SELECT_ITEMS_INDEX_PARTIAL) :: &
1625  food_items_dist_sorted
1626 
1627  !> - **food_items_n_visrange** - local number of elements of
1628  !! `food_items_percept_in_visrange` for output that are within he
1629  !! visual range of the agent.
1630  !! .
1631  integer :: food_items_n_visrange
1632 
1633  ! Local copy of the time step of the model.
1634  integer :: time_step_model_here
1635 
1636  ! Local counter
1637  integer :: i
1638 
1639  !> ### Implementation details ###
1640  !> #### Checks and preparations ####
1641  !> Check optional time step parameter. If unset, use global
1642  !! `commondata::global_time_step_model_current`.
1643  if (present(time_step_model)) then
1644  time_step_model_here = time_step_model
1645  else
1646  time_step_model_here = global_time_step_model_current
1647  end if
1648 
1649  !. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1650 
1651  !> Initialise index and rank values. Unititialised index arrays may result in
1652  !! invalid memory reference in `ARRAY_INDEX` (it is not safe by design).
1653  dist_food_neighbours = missing ; dist_food_index = unknown
1654  food_item_area = missing ; food_item_visual_range = missing
1655  food_items_dist_sorted = missing
1656 
1657  !> Copy food items array component from the `food_resource_available`
1658  !! class' the_environment::food_item's array.
1659  !! @warning Note that we cannot here call
1660  !! @verbatim
1661  !! call dist_foods%position( food_resource_available%food%location() )
1662  !! @endverbatim
1663  !! as the objects are `the_environment::food_item` higher level
1664  !! than `the_environment::spatial`.
1665  dist_foods = food_resource_available%food
1666 
1667  !. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1668  !> #### Step 1 ####
1669  !> First, we determine up to the maximum order (fast *partial indexing*)
1670  !! of `commondata::food_select_items_index_partial` neighbouring food
1671  !! items that are in proximity of the agent. This is done using the
1672  !! the_environment::spatial::neighbours() backend procedure.
1673  call this%neighbours( neighbours = dist_foods, &
1674  dist = dist_food_neighbours, &
1675  index_vector = dist_food_index, &
1676  rank_max = food_select_items_index_partial, &
1677  error_flag = dist_food_errflag )
1678 
1679  if (dist_food_errflag) call log_msg ( ltag_warn // procname // &
1680  ": Got error flag from food object neighbours procedure.")
1681 
1682  !. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1683  !> #### Step 2 ####
1684  !> Second, we select only those items within this set, which are within
1685  !! the visual range of the agent under the current conditions.
1686  !! To do this we, first, calculate the ambient illumination/irradiance
1687  !! level at the depth of the agent. Done using the
1688  !! the_environment::spatial::illumination() procedure.
1689  irradiance_agent_depth = this%illumination(time_step_model_here)
1690 
1691  !> Compute the array of "prey areas" for each of the food items (whole
1692  !! array or neighbouring food items only).
1693  food_item_area(dist_food_index(1:food_select_items_index_partial)) = &
1694  carea( cm2m( dist_foods( &
1695  dist_food_index(1:food_select_items_index_partial) )%size )&
1696  )
1697 
1698  !> Compute the vector of the visual ranges for detecting each of
1699  !! the food items by the agent.
1700  food_item_visual_range( &
1701  dist_food_index(1:food_select_items_index_partial) &
1702  ) &
1703  = m2cm( visual_range( &
1704  irradiance = irradiance_agent_depth, &
1705  prey_area = food_item_area( &
1706  dist_food_index(1:food_select_items_index_partial)&
1707  ) &
1708  ) &
1709  )
1710 
1711  !. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1712  !> #### Step 3 ####
1713  !> Now we can get the pre-output array `food_items_percept_in_visrange`
1714  !! that contains the food objects available within the visual range of
1715  !! the agent. Also, we count the number of such items for the output
1716  !! parameter `food_items_n_visrange`.
1717  food_items_n_visrange = 0
1719  if ( dist_food_neighbours(dist_food_index(i)) < &
1720  food_item_visual_range(dist_food_index(i)) ) then
1721  !> Also, check if the food item is available (not eaten).
1722  if (dist_foods(dist_food_index(i))%is_available()) then
1723  food_items_n_visrange = food_items_n_visrange + 1
1724  food_items_percept_in_visrange(food_items_n_visrange) = &
1725  dist_foods(dist_food_index(i))
1726  food_items_dist_sorted(food_items_n_visrange) = &
1727  dist_food_neighbours(dist_food_index(i))
1728  else
1729  call log_dbg ( ltag_info // procname // ": Food item within " // &
1730  "visual range but NOT available (eaten)." )
1731  end if
1732  end if
1733  end do
1734  !> Here we also log warning if no food items found, when debugging
1735  !! (see commondata::is_debug).
1736  if (food_items_n_visrange==0) call log_dbg( ltag_warn // procname // &
1737  ": No food items found within the visual range of the agent; " // &
1738  "The nearest food item distance=" // &
1739  tostr(dist_food_neighbours(dist_food_index(1))) // &
1740  ", with visual range=" // &
1741  tostr(food_item_visual_range(dist_food_index(1))) )
1742 
1743  !. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1744  !> #### Step 4 ####
1745  !> Finally, we can now create the output food perception object,
1746  !! including only food items that are within the current visual range
1747  !! of the agent.
1748  !! Init (create and allocate) the food perception object (at first empty)
1749  !! using the the_neurobio::percept_food::init().
1750  call this%perceive_food%init(food_items_n_visrange)
1751 
1752  !> Fill the output perception object with the values obtained at
1753  !! the step 3. This is done using the the_neurobio::percept_food::make()
1754  !! backend procedure.
1755  call this%perceive_food%make ( &
1756  food_items_percept_in_visrange(1:food_items_n_visrange), &
1757  food_items_dist_sorted(1:food_items_n_visrange) )
1758 
1760 
1761  !-----------------------------------------------------------------------------
1762  !> Check if the agent sees any food items within its visual range.
1763  !! @warning Should be called after the `see_food` method as it is only an
1764  !! accessor get-function.
1765  elemental function food_perception_is_seeing_food(this) result (sees_food)
1766  class(perception), intent(in) :: this
1767  !> @return Returns TRUE if the agent has any food items in its perception
1768  !! object and FALSE otherwise.
1769  logical :: sees_food
1770 
1771  sees_food = .false.
1772  if (this%perceive_food%get_count() > 0 ) sees_food = .true.
1773 
1774  end function food_perception_is_seeing_food
1775 
1776  !-----------------------------------------------------------------------------
1777  !> Calculate the probability of capture of a subjective representation of
1778  !! food item based on the data from the perceptual memory stack.
1780  time_step_model ) result (capture_prob)
1781  class(perception), intent(in) :: this
1782  !> @param last Limit to only this number of latest components in history.
1783  integer, optional, intent(in) :: last
1784  !> @param[in] time_step_model optional time step of the model, if absent,
1785  !! obtained from the global variable
1786  !! `commondata::global_time_step_model_current`.
1787  integer, optional, intent(in) :: time_step_model
1788  !> @return Capture probability of the "subjective" food item that has
1789  !! the size equal to the size of the average memorised food items
1790  !! (from the agent's perception memory stack) and located at an
1791  !! average distance of food items from the memory stack.
1792  real(srp) :: capture_prob
1793 
1794  ! Local copies of optionals
1795  integer :: time_step_model_here
1796 
1797  !> ### Implementation notes ###
1798  !> `subjective_food_item_average` of the type the_environment::food_item
1799  !! is a subjective representation of the food item object built from the
1800  !! memory stack data.
1801  type(food_item) :: subjective_food_item_average
1802 
1803  !> First, check optional time step parameter. If unset, use global
1804  !! commondata::global_time_step_model_current.
1805  if (present(time_step_model)) then
1806  time_step_model_here = time_step_model
1807  else
1808  time_step_model_here = global_time_step_model_current
1809  end if
1810 
1811  !> Second, build the subjective food item `subjective_food_item_average`
1812  !! using the the_environment:: food_item::make() method. The location of
1813  !! this subjective food item coincides with the location of the agent.
1814  !! This allows to calculate the visibility (visual range) of the food items
1815  !! bat the depth of the agent.
1816  !!
1817  !! Then the capture probability is calculated using the type-bound
1818  !! method the_environment::food_item::capture_probability(). Importantly,
1819  !! the distance towards towards the food item is explicitly provided
1820  !! as the average distance from the memory stack calculated by the
1821  !! the_neurobio::memory_perceptual::get_food_mean_dist().
1822  if (present(last)) then
1823  call subjective_food_item_average%make( &
1824  location = this%location(), &
1825  size = this%memory_stack%get_food_mean_size(last), &
1826  iid = unknown )
1827  capture_prob = subjective_food_item_average%capture_probability( &
1828  distance = this%memory_stack%get_food_mean_dist(last), &
1829  time_step_model = time_step_model_here )
1830  else
1831  call subjective_food_item_average%make( &
1832  location = this%location(), &
1833  size = this%memory_stack%get_food_mean_size(), &
1834  iid = unknown )
1835  capture_prob = subjective_food_item_average%capture_probability( &
1836  distance = this%memory_stack%get_food_mean_dist(), &
1837  time_step_model = time_step_model_here )
1838  end if
1839 
1840  !> Finally, we add a random Gaussian error to the above objective value.
1841  !! Now we have obtained the stochastic subjective value of the capture
1842  !! probability for this food item including a Gaussian error. There is
1843  !! also a strong limitation for the subjective probability to be within
1844  !! the range [0.0, 1.0]. See also ::subjective_capture_prob() for a
1845  !! similar Gaussian error in subjective probability.
1846  capture_prob = within( rnorm( capture_prob, cv2variance( &
1848  capture_prob) ), 0.0_srp, 1.0_srp )
1849 
1851 
1852  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1853  ! Functions linked with STOMACH PERCEPTION
1854  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1855 
1856  !-----------------------------------------------------------------------------
1857  !> Initiate an empty **stomach** capacity perception object.
1858  elemental subroutine percept_stomach_create_init(this)
1859  class(percept_stomach), intent(inout) :: this
1860 
1861  !> First, assign the current stomach capacity to `MISSING`.
1862  this%capacity = missing
1863 
1864  end subroutine percept_stomach_create_init
1865 
1866  !-----------------------------------------------------------------------------
1867  !> Get the currently available value of the available **stomach** volume.
1868  elemental function percept_stomach_get_avail_capacity (this) result(avail_capacity)
1869  class(percept_stomach), intent(in) :: this
1870 
1871  !> @returns the stomach capacity currently available for new food.
1872  real(srp) :: avail_capacity
1873 
1874  ! Return the current capacity.
1875  avail_capacity = this%capacity
1876 
1878 
1879  !-----------------------------------------------------------------------------
1880  !> Set and update the currently available value of the available **stomach**
1881  !! volume.
1882  subroutine percept_stomach_update_avail_capacity(this, current_volume)
1883  class(percept_stomach), intent(inout) :: this
1884 
1885  !> @param current_volume the new (updated) current volume of the
1886  !! stomach capacity.
1887  real(SRP), intent(in) ::current_volume
1888 
1889  ! And then place the parameter value to the updated object.
1890  this%capacity = current_volume
1891 
1893 
1894  !-----------------------------------------------------------------------------
1895  !> Destroy the **stomach** perception object and deallocate it.
1896  elemental subroutine percept_stomach_destroy_deallocate(this)
1897  class(percept_stomach), intent(inout) :: this
1898 
1899  !> Set the current value to commondata::missing.
1900  this%capacity = missing
1901 
1902  end subroutine percept_stomach_destroy_deallocate
1903 
1904  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1905  ! Functions linked with BODY MASS PERCEPTION
1906  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1907 
1908  !-----------------------------------------------------------------------------
1909  !> Initiate an empty **body mass** perception object.
1910  elemental subroutine percept_bodymass_create_init(this)
1911  class(percept_body_mass), intent(inout) :: this
1912 
1913  !> Assign the current body mass to `commondata::missing`.
1914  this%body_mass = missing
1915 
1916  end subroutine percept_bodymass_create_init
1917 
1918  !-----------------------------------------------------------------------------
1919  !> Get the current value of the **body mass** perception.
1920  elemental function percept_bodymass_get_current (this) result(current)
1921  class(percept_body_mass), intent(in) :: this
1922 
1923  !> @returns the current body mass value.
1924  real(srp) :: current
1925 
1926  ! Return the current mass.
1927  current = this%body_mass
1928 
1929  end function percept_bodymass_get_current
1930 
1931  !-----------------------------------------------------------------------------
1932  !> Set and update the current **body mass** perception value.
1933  subroutine percept_bodymass_update_current(this, current)
1934  class(percept_body_mass), intent(inout) :: this
1935 
1936  !> @param current the new (updated) current volume of the
1937  !! stomach capacity.
1938  real(SRP), intent(in) ::current
1939 
1940  ! And then place the parameter value to the updated object.
1941  this%body_mass = current
1942 
1943  end subroutine percept_bodymass_update_current
1944 
1945  !-----------------------------------------------------------------------------
1946  !> Destroy the **body mass** perception object and deallocate.
1947  elemental subroutine percept_bodymass_destroy_deallocate(this)
1948  class(percept_body_mass), intent(inout) :: this
1949 
1950  !> Set the current value to commondata::missing.
1951  this%body_mass = missing
1952 
1954 
1955  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1956  ! Functions linked with ENERGY PERCEPTION
1957  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1958 
1959  !-----------------------------------------------------------------------------
1960  !> Initiate an empty **energy** perception object.
1961  elemental subroutine percept_energy_create_init(this)
1962  class(percept_energy), intent(inout) :: this
1963 
1964  !> Assign the current energy to commondata::missing.
1965  this%energy_reserve = missing
1966 
1967  end subroutine percept_energy_create_init
1968 
1969  !-----------------------------------------------------------------------------
1970  !> Get the current value of the **energy** reserves.
1971  elemental function percept_energy_get_current (this) result(current)
1972  class(percept_energy), intent(in) :: this
1973 
1974  !> @returns the current energy reserve.
1975  real(srp) :: current
1976 
1977  ! Return the current capacity.
1978  current = this%energy_reserve
1979 
1980  end function percept_energy_get_current
1981 
1982  !-----------------------------------------------------------------------------
1983  !> Set and update the current **energy** perception value.
1984  subroutine percept_energy_update_current(this, current)
1985  class(percept_energy), intent(inout) :: this
1986 
1987  !> @param current the new (updated) current energy reserves.
1988  real(SRP), intent(in) ::current
1989 
1990  ! And then place the parameter value to the updated object.
1991  this%energy_reserve = current
1992 
1993  end subroutine percept_energy_update_current
1994 
1995  !-----------------------------------------------------------------------------
1996  !> Destroy the **energy** perception object and deallocate.
1997  elemental subroutine percept_energy_destroy_deallocate(this)
1998  class(percept_energy), intent(inout) :: this
1999 
2000  ! Set the current value to commondata::missing.
2001  this%energy_reserve = missing
2002 
2003  end subroutine percept_energy_destroy_deallocate
2004 
2005  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2006  ! Functions linked with AGE PERCEPTION
2007  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2008 
2009  !-----------------------------------------------------------------------------
2010  !> Initiate an empty **age** perception object.
2011  elemental subroutine percept_age_create_init(this)
2012  class(percept_age), intent(inout) :: this
2013 
2014  !> Assign the current age to commondata::unknown.
2015  this%age = unknown
2016 
2017  end subroutine percept_age_create_init
2018 
2019  !-----------------------------------------------------------------------------
2020  !> Get the current value of the **age** reserves.
2021  elemental function percept_age_get_current (this) result(current)
2022  class(percept_age), intent(in) :: this
2023 
2024  !> @returns the current age.
2025  integer :: current
2026 
2027  ! Return the current age.
2028  current = this%age
2029 
2030  end function percept_age_get_current
2031 
2032  !-----------------------------------------------------------------------------
2033  !> Set and update the current **age** perception value.
2034  subroutine percept_age_update_current(this, current)
2035  class(percept_age), intent(inout) :: this
2036 
2037  !> @param current the new (updated) current age.
2038  integer, intent(in) ::current
2039 
2040  ! And then place the parameter value to the updated object.
2041  this%age = current
2042 
2043  end subroutine percept_age_update_current
2044 
2045  !-----------------------------------------------------------------------------
2046  !> Destroy the **age** perception object and deallocate it.
2047  elemental subroutine percept_age_destroy_deallocate(this)
2048  class(percept_age), intent(inout) :: this
2049 
2050  !> Set the current value to commondata::unknown.
2051  this%age = unknown
2052 
2053  end subroutine percept_age_destroy_deallocate
2054 
2055  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2056  ! Functions linked with SPATIAL PERCEPTIONS
2057  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2058 
2059  !-----------------------------------------------------------------------------
2060  !> Set unique **id** for the conspecific perception component.
2061  subroutine spatial_percept_set_cid(this, id)
2062  class(spatial_percept_component), intent(inout) :: this
2063 
2064  !> @param iid optional individual id number for the food item.
2065  integer, optional, intent(in) :: id
2066 
2067  !> ### Implementation details ###
2068  !> **HUGE_ID** is a local parameter, the maximum unique id ever possible.
2069  integer, parameter :: HUGE_ID = huge(0)
2070 
2071  !> Check if conspecific cid is provided and if not, set random within the
2072  !! huge range.
2073  if (present(id)) then
2074  this%cid = id
2075  else
2076  this%cid = rand_i(1, huge_id)
2077  end if
2078 
2079  end subroutine spatial_percept_set_cid
2080 
2081  !-----------------------------------------------------------------------------
2082  !> Get the unique **id** of the food item object.
2083  elemental function spatial_percept_get_cid(this) result(id)
2084  class(spatial_percept_component), intent(in) :: this
2085 
2086  !> @returns cid the individual id number of this perception component.
2087  integer :: id
2088 
2089  id = this%cid
2090 
2091  end function spatial_percept_get_cid
2092 
2093  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2094  ! Functions linked with CONSPECIFIC PERCEPTION
2095  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2096 
2097  !-----------------------------------------------------------------------------
2098  !> Create a single conspecific perception component at an undefined
2099  !! position with default properties.
2100  elemental subroutine consp_percept_comp_create(this)
2101  class(conspec_percept_comp), intent(inout) :: this
2102 
2103  !> ### Implementation details ###
2104  !> We here just set an undefined location of the food object using
2105  !! standard interface function `missing`.
2106  call this%missing()
2107 
2108  !> Set cid to UNKNOWN.
2109  !> @warning random id on create is now disabled to allow elemental function,
2110  !! because random are never pure. So care to set cid's elsewhere.
2111  this%cid = unknown
2112 
2113  !> Then we set the conspecific size. Should it be MISSING or grand average?
2114  !! this%consp_body_size = MISSING
2115  this%consp_body_size = (body_length_max - body_length_min) / 2.0_srp
2116 
2117  !> Set the conspecific mass. The default mass of the conspecific is
2118  !! twice the minimum body mass. There is no upper limit on the body mass.
2119  !! @note These values are not very important as they are for default init
2120  !! only and will be overwritten by the actual values.
2121  this%consp_body_mass = body_mass_min * 2.0_srp
2122 
2123  !> Init distance towards the conspecific, now with MISSING value.
2124  this%consp_distance = missing
2125 
2126  !> Init the sex is male by default, it is arbitrary.
2127  this%sex_is_male = .true.
2128 
2129  end subroutine consp_percept_comp_create
2130 
2131  !-----------------------------------------------------------------------------
2132  !> Make a single conspecific perception component. This is a single
2133  !! conspecific located within the visual range of the agent.
2134  subroutine consp_percept_make(this, location, size, mass, dist, cid, is_male)
2135  class(conspec_percept_comp), intent(inout) :: this
2136 
2137  !> @param Location of the conspecific perception component, as a
2138  !! `SPATIAL` type container
2139  type(spatial), intent(in) :: location
2140 
2141  !> @param size This is the optional conspecific body size as guessed by
2142  !! the agent. May or may not reflect the "true" size of the
2143  !! conspecific.
2144  real(SRP), optional, intent(in) :: size
2145 
2146  !> @param mass This is the optional conspecific body mass as guessed by
2147  !! the agent. May or may not reflect the "true" mass of the
2148  !! conspecific.
2149  real(SRP), optional, intent(in) :: mass
2150 
2151  !> @param dist The distance towards this conspecific.
2152  real(SRP), optional, intent(in) :: dist
2153 
2154  !> @param iid Optional cid for the conspecific perception component.
2155  !! If not provided, set random.
2156  integer, optional, intent(in) :: cid
2157 
2158  !> @param is_male Optional flag that sex is male.
2159  logical, optional, intent(in) :: is_male
2160 
2161  !> ### Implementation details ###
2162  !> We here just set the location of the food object using
2163  !! standard interface function `position`.
2164  call this%position(location)
2165 
2166  !> If individual id is provided, set it. If not, set random.
2167  if (present(cid)) then
2168  call this%set_cid(cid)
2169  else
2170  call this%set_cid()
2171  end if
2172 
2173  !> Then we set the conspecific perception component body size.
2174  !! Check if optional size is provided and left untouched if not.
2175  if (present(size)) then
2176  this%consp_body_size = min( max(body_length_min, size), body_length_max )
2177  end if
2178 
2179  !> Then we set the conspecific perception component body mass.
2180  !! Check if optional size is provided and left untouched if not.
2181  if (present(mass)) then
2182  this%consp_body_mass = max(body_mass_min, mass)
2183  end if
2184 
2185  !> Also set the distance towards the conspecific if provided. If not
2186  !! provided, ignore.
2187  if (present(dist)) then
2188  this%consp_distance = dist
2189  end if
2190 
2191  if (present(is_male)) then
2192  this%sex_is_male = is_male
2193  end if
2194 
2195  end subroutine consp_percept_make
2196 
2197  !-----------------------------------------------------------------------------
2198  !> Get the **conspecific** perception component body size.
2199  elemental function consp_percept_get_size (this) result (body_size)
2200  class(conspec_percept_comp), intent(in) :: this
2201 
2202  real(srp) :: body_size
2203 
2204  body_size = this%consp_body_size
2205 
2206  end function consp_percept_get_size
2207  !-----------------------------------------------------------------------------
2208  !> Get the **conspecific** perception component body mass.
2209  elemental function consp_percept_get_mass (this) result (body_mass)
2210  class(conspec_percept_comp), intent(in) :: this
2211 
2212  real(srp) :: body_mass
2213 
2214  body_mass = this%consp_body_mass
2215 
2216  end function consp_percept_get_mass
2217 
2218  !-----------------------------------------------------------------------------
2219  !> Get the **conspecific** perception component distance.
2220  elemental function consp_percept_get_dist (this) result (dist_consp)
2221  class(conspec_percept_comp), intent(in) :: this
2222 
2223  real(srp) :: dist_consp
2224 
2225  dist_consp = this%consp_distance
2226 
2227  end function consp_percept_get_dist
2228 
2229  !-----------------------------------------------------------------------------
2230  !> Get the **conspecific** perception component sex flag (male).
2231  elemental function consp_percept_sex_is_male_get (this) result (sex_is_male)
2232  class(conspec_percept_comp), intent(in) :: this
2233  logical :: sex_is_male
2234 
2235  sex_is_male = this%sex_is_male
2236 
2237  end function consp_percept_sex_is_male_get
2238 
2239  !-----------------------------------------------------------------------------
2240  !> Get the **conspecific** perception component sex flag (female).
2241  elemental function consp_percept_sex_is_female_get (this) result (sex_is_female)
2242  class(conspec_percept_comp), intent(in) :: this
2243  logical :: sex_is_female
2244 
2245  if (this%sex_is_male) then
2246  sex_is_female = .false.
2247  else
2248  sex_is_female = .true.
2249  end if
2250 
2251  end function consp_percept_sex_is_female_get
2252 
2253  !-----------------------------------------------------------------------------
2254  !> Create conspecifics perception object, it is an array of
2255  !! conspecific perception components.
2256  elemental subroutine percept_consp_create_init (this, maximum_number_conspecifics)
2257  class(percept_conspecifics), intent(inout) :: this
2258 
2259  !> @param maximum_number_conspecifics The maximum number of conspecifics
2260  !! in the conspecifics perception object. Normally equal to the
2261  !! partial conspecific selection indexing order
2262  !! `CONSP_SELECT_ITEMS_INDEX_PARTIAL`.
2263  integer, intent(in) :: maximum_number_conspecifics
2264 
2265  !> ### Implementation details ###
2266  !> Allocate the array of the conspecific perception components
2267  if (.not. allocated(this%conspecifics_seen)) &
2268  allocate (this%conspecifics_seen(maximum_number_conspecifics))
2269 
2270  !> And create all perception components (create is `elemental`).
2271  call this%conspecifics_seen%create()
2272 
2273  !> Set the initial number of conspecifics within the visual range
2274  !! to the maximum number provided.
2275  call this%number(maximum_number_conspecifics)
2276 
2277  end subroutine percept_consp_create_init
2278 
2279  !-----------------------------------------------------------------------------
2280  !> Set the total number of conspecifics perceived (seen) in the conspecific
2281  !! perception object. But do **not** reallocate the conspecific perception
2282  !! components so far.
2283  elemental subroutine percept_consp_number_seen(this, number_set)
2284  class(percept_conspecifics), intent(inout) :: this
2285 
2286  !> @param[in] number_set Set the number of conspecifics in the perception
2287  !! object.
2288  integer, intent(in) :: number_set
2289 
2290  this%conspecifics_seen_count = number_set
2291 
2292  end subroutine percept_consp_number_seen
2293 
2294  !-----------------------------------------------------------------------------
2295  !> Make the conspecifics perception object, fill it with the actual arrays.
2296  !! @note Note that the size and allocation is set by the `init` method.
2297  pure subroutine percept_consp_make_fill_arrays(this, consps)
2298  class(percept_conspecifics), intent(inout) :: this
2299 
2300  !> @param[in] consps an array of conspecific perception components that
2301  !! form the perception object.
2302  type(conspec_percept_comp), intent(in), dimension(:) :: consps
2303 
2304  !> PROCNAME is the procedure name for logging and debugging (with MODNAME).
2305  character(len=*), parameter :: procname = "(percept_consp_make_fill_arrays)"
2306 
2307  !> ### Implementation details ###
2308  !> Fill the dynamic conspecific perception object with the data from
2309  !! the input array.
2310  this%conspecifics_seen = consps
2311 
2312  end subroutine percept_consp_make_fill_arrays
2313 
2314  !-----------------------------------------------------------------------------
2315  !> Get the number (count) of conspecifics seen. Trivial.
2316  elemental function percept_consp_get_count_seen (this) result (count_obj)
2317  class(percept_conspecifics), intent(in) :: this
2318  integer :: count_obj
2319 
2320  count_obj = this%conspecifics_seen_count
2321 
2322  end function percept_consp_get_count_seen
2323 
2324  !-----------------------------------------------------------------------------
2325  !> Deallocate and delete a conspecific perception object.
2326  elemental subroutine percept_consp_destroy_deallocate(this)
2327  class(percept_conspecifics), intent(inout) :: this
2328 
2329  if (allocated(this%conspecifics_seen)) deallocate(this%conspecifics_seen)
2330  this%conspecifics_seen_count = unknown
2331 
2332  end subroutine percept_consp_destroy_deallocate
2333 
2334  !-----------------------------------------------------------------------------
2335  !> Get available conspecific perception objects within the visual range of
2336  !! the agent, which the agent can perceive and therefore respond to.
2337  !! @note Note that there are three similar procedures that detect spatial
2338  !! objects within the visual range of the agent:
2339  !! - the_neurobio::perception::see_food -- perception of food items;
2340  !! - the_neurobio::perception::see_consp -- perception of conspecifics:
2341  !! - the_neurobio::perception::see_pred -- perception of predators.
2342  !! .
2343  !! All these procedures were actually implemented using the first
2344  !! (the_neurobio::perception::see_food) as a template. All three
2345  !! implement partial indexing of the nearest spatial objects to
2346  !! accelerate computation of large arrays of spatial objects.
2348  consp_agents, &
2349  time_step_model )
2350  class(perception), intent(inout) :: this
2351 
2352  !> @param[in] consp_agents An array of spatial objects where we are
2353  !! looking for the nearest available perception objects (array).
2354  class(condition), dimension(:), intent(in) :: consp_agents
2355 
2356  !> @param[in] time_step_model The current time step of the model.
2357  integer, optional, intent(in) :: time_step_model
2358 
2359  !> ### Notable variables and parameters ###
2360  !> - **consp_sizes** - local array for the body lengths of the agents.
2361  ! @note We now get this array from the `consp_agents` objects.
2362  real(SRP), dimension(size(consp_agents)) :: consp_sizes
2363 
2364  !> - **consp_masses** - local array for the body masses of the agents.
2365  ! @note We now get this array from the `consp_agents` objects.
2366  real(SRP), dimension(size(consp_agents)) :: consp_masses
2367 
2368  !> - **consp_alive** - local array of logical indicators if the agents
2369  !! are alive (TRUE).
2370  ! @note We now get this array from the `consp_agents` objects.
2371  logical, dimension(size(consp_agents)) :: consp_alive
2372 
2373  !> - **consp_sex_is_male** - local array of the sex of the conspecifics.
2374  ! @note We now get this array from the `consp_agents` objects.
2375  logical, dimension(size(consp_agents)) :: consp_sex_is_male
2376 
2377  ! Local copy of the time step of the model.
2378  integer :: time_step_model_here
2379 
2380  !. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2381 
2382  ! PROCNAME is the procedure name for logging and debugging (with MODNAME).
2383  character(len=*), parameter :: PROCNAME = &
2384  "(consp_perception_get_visrange_objects)"
2385 
2386  !> - **MIN_DIST_SELF** - exclude self from the neighbours. Because we
2387  !! cannot (easily) use
2388  !! recursive reference to the indvidal agent class from this lower-order
2389  !! perception class, we have to pass some parameters of the *this* agent
2390  !! as dummy parameters to the subroutine. E.g. individual ID, if ID is
2391  !! incorrect or not passed, the only way to distinguish self from other
2392  !! agents in the neighbourhood is by different location, i.e. the
2393  !! distance should be non-zero. This parameter sets the tolerance limit
2394  !! for the difference in the distance for considering the neighbour
2395  !! not-self. Possibly can be equal to the parameter `commondata::zero`,
2396  !! or we can allow a higher discrepancy (this also might correct some
2397  !! errors).
2398  real(SRP), parameter :: MIN_DIST_SELF = 2.0_srp * zero ! 0.001_SRP
2399 
2400  !> - **agents_near** - temporary array of nearby other conspecifics
2401  !! available to this agent.
2402  type(spatial), dimension(size(consp_agents)) :: agents_near
2403 
2404  !> - **dist_neighbours** - temporary array of the distances to the
2405  !! neighbouring food items.
2406  real(SRP), dimension(size(consp_agents)) :: dist_neighbours
2407 
2408  !> - **dist_index** - temporary partial index vector for the distances
2409  !! to the neighbouring conspecifics.
2410  integer, dimension(size(consp_agents)) :: dist_index
2411 
2412  ! Temporary possible error status for sub-procedures
2413  logical :: err_flag
2414 
2415  !> - **irradiance_agent_depth** - local variable defining the irradiance
2416  !! (illumination) at the current depth of the agent. Needed to calculate
2417  !! the agent's visual range.
2418  real(SRP) :: irradiance_agent_depth
2419 
2420  !> - **sobject_area** - local variable defining the conspecific area.
2421  !! Needed to calculate the agent's visual range.
2422  real(SRP), dimension(size(consp_agents)) :: sobject_area
2423 
2424  !> - **sobject_visual_range** - local variable defining the visual range
2425  !! of the agent for detecting each of the conspecifics (with known areas)
2426  !! at the agent's current depth.
2427  real(SRP), dimension(size(consp_agents)) :: sobject_visual_range
2428 
2429  !> - **sobjects_percept_in_visrange** - local sorted array of conspecific
2430  !! perception components that are within the visual range of the agent
2431  !! for output. The array should normally have the size of
2432  !! `commondata::consp_select_items_index_partial` elements, but only the
2433  !! first `sobjects_n_visrange` elements of it are actually within the
2434  !! visual range.
2435  type(conspec_percept_comp),dimension(CONSP_SELECT_ITEMS_INDEX_PARTIAL) :: &
2436  sobjects_percept_in_visrange
2437 
2438  !> - **sobjects_dist_sorted** - temporary local sorted array of distances
2439  !! between the agent and each of the nearest neighbouring conspecifics,
2440  !! sorted for output.
2441  real(SRP), dimension(CONSP_SELECT_ITEMS_INDEX_PARTIAL) :: &
2442  sobjects_dist_sorted
2443 
2444  !> - **consp_array_size** - the size of the input arrays of object
2445  !! properties, local. Initially set from the size of the objects (class)
2446  !! array, but `consp_sizes` and `consp_alive` must have identical sizes.
2447  integer :: consp_array_size
2448 
2449  !> - **sobjects_n_visrange** - local number of elements of
2450  !! `sobjects_percept_in_visrange` for output that are within he visual
2451  !! range of the agent.
2452  integer :: sobjects_n_visrange
2453 
2454  ! Local counter
2455  integer :: i
2456 
2457  !> - **self_idx** - local index of itself, needed to exclude self from
2458  !! debug messages and logs.
2459  !! .
2460  integer :: self_idx
2461 
2462  !. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2463 
2464  !> ### Implementation details ###
2465  !> #### Checks and preparations ####
2466  !> Initialise index and rank values. Uninitialised index arrays may result
2467  !! in invalid memory reference in `ARRAY_INDEX` (it is not safe by design).
2468  dist_neighbours = missing ; dist_index = unknown
2469  sobject_area = missing ; sobject_visual_range = missing
2470  sobjects_dist_sorted = missing
2471 
2472  self_idx = 0 !> Also zero-init self index.
2473 
2474  !> Check optional time step parameter. If unset, use global
2475  !! `commondata::global_time_step_model_current`.
2476  if (present(time_step_model)) then
2477  time_step_model_here = time_step_model
2478  else
2479  time_step_model_here = global_time_step_model_current
2480  end if
2481 
2482  !> Set the size for all the internal arrays, that is equal to the
2483  !! `consp_agents` objects array size.
2484  consp_array_size = size(consp_agents)
2485 
2486  !> Copy conspecifics array from the input `consp_agents` class into
2487  !! `agents_near`.
2488  call agents_near%position ( consp_agents%location() )
2489 
2490  !> Get local arrays for the conspecific sizes, alive status and sex using
2491  !! elemental array-based accessor functions.
2492  consp_sizes = consp_agents%get_length()
2493  consp_masses = consp_agents%get_mass()
2494  consp_alive = consp_agents%is_alive()
2495  consp_sex_is_male = consp_agents%is_male()
2496 
2497  !. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2498  !> #### Step 1 ####
2499  !> First, we get, up to the maximum order (fast *partial indexing*)
2500  !! of `commondata::consp_select_items_index_partial`, neighbouring
2501  !! conspecifics that are in proximity of this agent. here we get
2502  !! **partial index** vector for the input array of objects: `dist_index`.
2503  !! The calculation backend is the_environment::spatial::neighbours().
2504  call this%neighbours( neighbours = agents_near, &
2505  dist = dist_neighbours, &
2506  index_vector = dist_index, &
2507  rank_max = consp_select_items_index_partial, &
2508  error_flag = err_flag )
2509 
2510  if (err_flag) call log_msg ( ltag_warn // procname // ": Got error flag" &
2511  // " from conspecific objects neighbours procedure.")
2512 
2513  !. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2514  !> #### Step 2 ####
2515  !> Second, we select only those items within this set, which are within
2516  !! the visual range of the agent under the current conditions.
2517  !! To do this we, first, calculate the ambient illumination/irradiance
2518  !! level at the depth of the agent. Done using the
2519  !! the_environment::spatial::illumination() procedure.
2520  irradiance_agent_depth = this%illumination(time_step_model_here)
2521 
2522  !> Compute the array of "prey areas" for each conspecific.
2523  sobject_area(dist_index(1:consp_select_items_index_partial)) = &
2525  cm2m( consp_sizes(dist_index(1:consp_select_items_index_partial)) ) &
2526  )
2527 
2528  !> Compute the vector of the visual ranges for detecting each of
2529  !! the conspecifics by the agent.
2530  sobject_visual_range(dist_index(1:consp_select_items_index_partial)) &
2531  = m2cm( visual_range( &
2532  irradiance = irradiance_agent_depth, &
2533  prey_area = sobject_area( &
2534  dist_index(1:consp_select_items_index_partial) &
2535  ), &
2536  prey_contrast = individual_visual_contrast_default &
2537  ) &
2538  )
2539 
2540  !. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2541  !> #### Step 3 ####
2542  !> Now we can get the pre-output array `sobjects_percept_in_visrange`
2543  !! that contains the conspecifics available within the visual range of
2544  !! the agent. Also, we count their number for the output parameter
2545  !! `sobjects_n_visrange`.
2546  sobjects_n_visrange = 0
2548  if ( dist_neighbours(dist_index(i)) < &
2549  sobject_visual_range(dist_index(i)) ) then
2550  !> Include only agents non identical to oneself.
2551  !! TODO: Use individual ID, but have to pass as an additional
2552  !! dummy parameter.
2553  if ( this%distance( agents_near(dist_index(i)) ) > min_dist_self ) then
2554  !> Include only alive agents.
2555  if ( consp_alive(dist_index(i)) ) then
2556  sobjects_n_visrange = sobjects_n_visrange + 1
2557  call sobjects_percept_in_visrange(sobjects_n_visrange)%make( &
2558  location = agents_near(dist_index(i))%location(), &
2559  size = consp_sizes(dist_index(i)), &
2560  mass = consp_masses(dist_index(i)), &
2561  dist = dist_neighbours(dist_index(i)), &
2562  cid = dist_index(i), &
2563  is_male = consp_sex_is_male(dist_index(i)) )
2564  else
2565  call log_dbg( ltag_info // procname // &
2566  ": Dead neighbour excluded. Id:" // &
2567  tostr(dist_index(i)) )
2568  end if
2569  else
2570  self_idx = i !> Index of itself, will exclude from min. values.
2571  call log_dbg (ltag_info // procname // ": Found self within " // &
2572  "the visual range. Idx:" // tostr(dist_index(self_idx)))
2573  end if
2574  end if
2575  end do
2576  !> Here we also log warning if no conspecifics found, when debugging. If
2577  !! the self index self_idx is non-zero, will output next from self value,
2578  !! usually 2.
2579  if (sobjects_n_visrange==0) call log_dbg( ltag_warn // procname // &
2580  ": No conspecifics found within the visual range of the agent; " // &
2581  "The nearest conspecific distance=" // &
2582  tostr(dist_neighbours(dist_index(self_idx+1))) // &
2583  ", with visual range=" // &
2584  tostr(sobject_visual_range(dist_index(self_idx+1))) // &
2585  ", ID:" // tostr(dist_index(self_idx+1)) // &
2586  ", Idx:" // tostr(self_idx+1) )
2587 
2588  !. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2589  !> #### Step 4 ####
2590  !> Finally, we can now create the output conspecific perception object,
2591  !! including only conspecifics that are within the current visual range
2592  !! of the agent.
2593  !! Init (create and allocate) the conspecific perception object,
2594  !! at first empty, using the food perception object (at first empty)
2595  !! using the the_neurobio::percept_conspecifics::init().
2596  call this%perceive_consp%init(sobjects_n_visrange)
2597 
2598  !> Fill the output perception object with the values obtained at
2599  !! the step 3. This is done using the
2600  !! the_neurobio::percept_conspecifics::make() backend procedure.
2601  call this%perceive_consp%make ( &
2602  sobjects_percept_in_visrange(1:sobjects_n_visrange) )
2603 
2605 
2606  !-----------------------------------------------------------------------------
2607  !> Check if the agent sees any conspecifics within the visual range.
2608  !! @warning Should be called after the `see_consp` method as it is only an
2609  !! accessor get-function.
2610  !! @note There is little sense to implement this accessor procedure in the
2611  !! specific perception (up-level) class as every perception is not
2612  !! a derivative of a common class, perceptions independent, so we'll
2613  !! have to also implement agent-bound perception methods anyway.
2614  elemental function consp_perception_is_seeing_conspecifics(this) result (sees_consp)
2615  class(perception), intent(in) :: this
2616  logical :: sees_consp
2617 
2618  sees_consp = .false.
2619  if (this%perceive_consp%get_count() > 0 ) sees_consp = .true.
2620 
2622 
2623  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2624  ! Functions linked with SPATIAL PERCEPTION
2625  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2626 
2627  !-----------------------------------------------------------------------------
2628  !> Create a single arbitrary spatial object perception component at an
2629  !! undefined position with default properties.
2630  elemental subroutine spatialobj_percept_comp_create(this)
2631  class(spatialobj_percept_comp), intent(inout) :: this
2632 
2633  !> ### Implementation notes ###
2634  !> Just set an undefined location of the object using
2635  !! standard interface function `the_environment::spatial::missing()`.
2636  call this%missing()
2637 
2638  !> Set cid to commondata::unknown.
2639  !> @warning random id on create is now disabled to allow elemental function,
2640  !! because random are never pure. So care to set cid's elsewhere.
2641  this%cid = unknown
2642 
2643  !> Then we set the object size to commondata::missing.
2644  this%sobj_size = missing
2645 
2646  !> Init distance towards the object, initially also commondata::missing.
2647  this%sobj_distance = missing
2648 
2649  end subroutine spatialobj_percept_comp_create
2650 
2651  !-----------------------------------------------------------------------------
2652  !> Make a single arbitrary **spatial** object perception component.
2653  subroutine spatialobj_percept_make(this, location, size, dist, cid)
2654  class(spatialobj_percept_comp), intent(inout) :: this
2655 
2656  !> @param Location of the spatial object perception component, as a
2657  !! `the_environment::spatial` type container.
2658  type(spatial), intent(in) :: location
2659 
2660  !> @param size This is the optional object size.
2661  real(SRP), optional, intent(in) :: size
2662 
2663  !> @param dist The distance towards this object.
2664  real(SRP), optional, intent(in) :: dist
2665 
2666  !> @param iid Optional cid for the object, e.g. number within an array.
2667  integer, optional, intent(in) :: cid
2668 
2669  !> ### Implementation notes ###
2670  !> Set the location of the object using standard interface function
2671  !! `the_envirnoment::spatial::position()`.
2672  call this%position(location)
2673 
2674  !> If individual id is provided, set it. If not, set random.
2675  if (present(cid)) then
2676  call this%set_cid(cid)
2677  else
2678  call this%set_cid()
2679  end if
2680 
2681  !> Set the object perception component size. Only nonzero size is accepted.
2682  if (present(size)) then
2683  this%sobj_size = max(zero, size)
2684  end if
2685 
2686  !> Also set the distance towards the conspecific if provided. If not
2687  !! provided, ignore.
2688  if (present(dist)) then
2689  this%sobj_distance = dist
2690  end if
2691 
2692  end subroutine spatialobj_percept_make
2693 
2694  !-----------------------------------------------------------------------------
2695  !> Get an arbitrary spatial object perception component size.
2696  elemental function spatialobj_percept_get_size (this) result (obj_size)
2697  class(spatialobj_percept_comp), intent(in) :: this
2698 
2699  real(srp) :: obj_size
2700 
2701  obj_size = this%sobj_size
2702 
2703  end function spatialobj_percept_get_size
2704 
2705  !-----------------------------------------------------------------------------
2706  !> Get the distance to an arbitrary spatial object perception component.
2707  elemental function spatialobj_percept_get_dist (this) result (dist_object)
2708  class(spatialobj_percept_comp), intent(in) :: this
2709 
2710  real(srp) :: dist_object
2711 
2712  dist_object = this%sobj_distance
2713 
2714  end function spatialobj_percept_get_dist
2715 
2716  !-----------------------------------------------------------------------------
2717  !> Calculate the visibility range of this spatial object. Wrapper to the
2718  !! `visual_range` function. This function calculates the distance from
2719  !! which this object can be seen by a visual object (e.g. predator or
2720  !! prey).
2721  !! @warning The `visual_range` procedures use meter for units, this
2722  !! auto-converts to cm.
2723  !! @warning Cannot implement a generic function accepting also vectors of
2724  !! this objects as only elemental object-bound array functions are
2725  !! allowed by the standard. This function cannot be elemental, so
2726  !! passed-object dummy argument must always be scalar.
2727  function spatialobj_percept_visibility_visual_range(this, object_area, &
2728  contrast, time_step_model) result (visrange)
2729  class(spatialobj_percept_comp), intent(in) :: this
2730  !> @param[in] object_area is optional area of the spatial object. This
2731  !! parameter can be necessary because the area can be
2732  !! calculated differently for different types of objects, e.g.
2733  !! fish using commondata::length2sidearea_fish() or food
2734  !! items using commondata::carea(). The default object area
2735  !! if the parameter is absent, uses the fish backend.
2736  real(srp), optional, intent(in) :: object_area
2737  !> @param[in] contrast is an optional inherent visual contrast of the
2738  !! spatial object. The default contrast of all objects is
2739  !! defined by the commondata::preycontrast_default parameter.
2740  real(srp), optional, intent(in) :: contrast
2741  !> @param[in] optional time step of the model, if absent gets the current
2742  !! time step as defined by the value of
2743  !! `commondata::global_time_step_model_current`.
2744  integer, optional, intent(in) :: time_step_model
2745  !> @return The maximum distance from which this object can be seen.
2746  real(srp) :: visrange
2747 
2748  ! Local copies of optionals
2749  integer :: time_step_model_here
2750  real(srp) :: object_area_here, contrast_here
2751 
2752  ! Local variables
2753  real(srp) :: irradiance_agent_depth
2754 
2755  !> ### Implementation details ###
2756  !> Check optional `contrast` parameter. If unset, use global
2757  !! `commondata::preycontrast_default`.
2758  if (present(contrast)) then
2759  contrast_here = contrast
2760  else
2761  contrast_here = preycontrast_default
2762  end if
2763  !> Check optional time step parameter. If unset, use global
2764  !! `commondata::global_time_step_model_current`.
2765  if (present(time_step_model)) then
2766  time_step_model_here = time_step_model
2767  else
2768  time_step_model_here = global_time_step_model_current
2769  end if
2770 
2771  !> Second, check if the object area (`object_area`) parameter is provided.
2772  !! If not, calculate area from the `sobj_size` component assuming it is
2773  !! a fish. This is logical because the_neurobio::spatialobj_percept_comp
2774  !! class is mainly used in the perception of conspecifics and predators.
2775  if (present(object_area)) then
2776  object_area_here = object_area
2777  else
2778  object_area_here = length2sidearea_fish( cm2m( this%sobj_size ) )
2779  end if
2780 
2781  !> Calculate ambient illumination / irradiance at the depth of
2782  !! this object at the given time step.
2783  irradiance_agent_depth = this%illumination(time_step_model_here)
2784 
2785  !> Return visual range to see this spatial object: its visibility range.
2786  visrange = m2cm( visual_range( irradiance = irradiance_agent_depth, &
2787  prey_area = object_area_here, &
2788  prey_contrast = contrast_here ) )
2789 
2791 
2792  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2793  ! Functions linked with PREDATOR PERCEPTION
2794  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2795 
2796  !-----------------------------------------------------------------------------
2797  !> Create **predator** perception object, it is an array of
2798  !! spatial perception components.
2799  elemental subroutine percept_predator_create_init (this, maximum_number_predators)
2800  class(percept_predator), intent(inout) :: this
2801 
2802  !> @param maximum_number_predators The maximum number of predators
2803  !! in the perception object. Normally equal to the partial
2804  !! predator selection indexing order
2805  !! `PREDATOR_SELECT_ITEMS_INDEX_PARTIAL`.
2806  integer, intent(in) :: maximum_number_predators
2807 
2808  !> ### Implementation notes ###
2809  !> Allocate the array of the predator's spatial perception components.
2810  if (.not. allocated(this%predators_seen)) &
2811  allocate(this%predators_seen(maximum_number_predators))
2812 
2813  !> Allocate the array of the predator attack rates.
2814  if (.not. allocated(this%predators_attack_rates)) &
2815  allocate(this%predators_attack_rates(maximum_number_predators))
2816 
2817  !> And create all perception components (create is `elemental`).
2818  call this%predators_seen%create()
2819 
2820  !> Fill the predator's attack rates arrays with commondata::missing
2821  !! values.
2822  this%predators_attack_rates = missing
2823 
2824  !> Set the initial number of predators within the visual range
2825  !! to the maximum number provided.
2826  call this%number(maximum_number_predators)
2827 
2828  end subroutine percept_predator_create_init
2829 
2830  !-----------------------------------------------------------------------------
2831  !> Set the total number of **predators** perceived (seen) in the predator
2832  !! perception object. But do not reallocate the predator perception
2833  !! components so far.
2834  elemental subroutine percept_predator_number_seen(this, number_set)
2835  class(percept_predator), intent(inout) :: this
2836 
2837  !> @param[in] number_set Set the number of predators in the perception
2838  !! object.
2839  integer, intent(in) :: number_set
2840 
2841  this%predators_seen_count = number_set
2842 
2843  end subroutine percept_predator_number_seen
2844 
2845  !-----------------------------------------------------------------------------
2846  !> Make the **predator** perception object, fill it with the actual arrays.
2847  !! @note Note that the size and allocation is set by the
2848  !! `the_neurobio::percept_predator::init()` method.
2849  pure subroutine percept_predator_make_fill_arrays(this, preds, attack_rate)
2850  class(percept_predator), intent(inout) :: this
2851  !> @param[in] preds an array of predator (spatial,
2852  !! `the_neurobio::spatialobj_percept_comp`) perception
2853  !! components that form the perception object.
2854  type(spatialobj_percept_comp), intent(in), dimension(:) :: preds
2855 
2856  real(srp), optional, intent(in), dimension(:) :: attack_rate
2857 
2858  ! PROCNAME is the procedure name for logging and debugging (with MODNAME).
2859  character(len=*), parameter :: procname = &
2860  "(percept_predator_make_fill_arrays)"
2861 
2862  !> ### Implementation notes ###
2863  !> Fill the dynamic conspecific perception object with the data from
2864  !! the input array.
2865  this%predators_seen = preds
2866 
2867  !> The arrays for the body sizes and attack rates of the predators are
2868  !! set only if these arrays are present in the dummy arguments to this
2869  !! procedure. If they are not provided, default values are used as defined
2870  !! by commondata::predator_attack_rate_default parameter.
2871  if (present(attack_rate)) then
2872  this%predators_attack_rates = attack_rate
2873  else
2874  this%predators_attack_rates = predator_attack_rate_default
2875  end if
2876 
2877  end subroutine percept_predator_make_fill_arrays
2878 
2879  !-----------------------------------------------------------------------------
2880  !> Set an array of the attack rates for the predator perception object.
2881  pure subroutine percept_predator_set_attack_rate_vector(this, attack_rate)
2882  class(percept_predator), intent(inout) :: this
2883 
2884  real(srp), intent(in), dimension(:) :: attack_rate
2885 
2886  this%predators_attack_rates = attack_rate
2887 
2889 
2890  !-----------------------------------------------------------------------------
2891  !> Set an array of the attack rates for the predator perception object.
2892  pure subroutine percept_predator_set_attack_rate_scalar(this, attack_rate)
2893  class(percept_predator), intent(inout) :: this
2894 
2895  real(srp), intent(in) :: attack_rate
2896 
2897  this%predators_attack_rates = attack_rate
2898 
2900 
2901  !-----------------------------------------------------------------------------
2902  !> Get the number (count) of predators seen. Trivial.
2903  elemental function percept_predator_get_count_seen (this) result (count_obj)
2904  class(percept_predator), intent(in) :: this
2905  integer :: count_obj
2906 
2907  count_obj = this%predators_seen_count
2908 
2909  end function percept_predator_get_count_seen
2910 
2911  !-----------------------------------------------------------------------------
2912  !> Deallocate and delete a **predator** perception object.
2913  elemental subroutine percept_predator_destroy_deallocate(this)
2914  class(percept_predator), intent(inout) :: this
2915 
2916  if (allocated(this%predators_seen)) deallocate(this%predators_seen)
2917  if (allocated(this%predators_attack_rates)) deallocate(this%predators_attack_rates)
2918  this%predators_seen_count = unknown
2919 
2921 
2922  !-----------------------------------------------------------------------------
2923  !> Get available predators perception objects within the visual range of
2924  !! the agent, which the agent can perceive and therefore respond to.
2925  !! @note Note that there are three similar procedures that detect spatial
2926  !! objects within the visual range of the agent:
2927  !! - the_neurobio::perception::see_food -- perception of food items;
2928  !! - the_neurobio::perception::see_consp -- perception of conspecifics:
2929  !! - the_neurobio::perception::see_pred -- perception of predators.
2930  !! .
2931  !! All these procedures were actually implemented using the first
2932  !! (the_neurobio::perception::see_food) as a template. All three
2933  !! implement partial indexing of the nearest spatial objects to
2934  !! accelerate computation of large arrays of spatial objects.
2935  !! @note This procedure also used the conspecific perception as a template,
2936  !! but removed extra tests for "self".
2938  spatl_agents, &
2939  time_step_model )
2940  class(perception), intent(inout) :: this
2941 
2942  !> @param[in] spatl_agents An array of spatial objects where we are
2943  !! looking for the nearest available perception objects (array).
2944  class(predator), dimension(:), intent(in) :: spatl_agents
2945 
2946  !> @param[in] time_step_model The current time step of the model.
2947  integer, optional, intent(in) :: time_step_model
2948 
2949  ! Local copy of the time step of the model.
2950  integer :: time_step_model_here
2951 
2952  !. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2953 
2954  ! PROCNAME is the procedure name for logging and debugging (with MODNAME).
2955  character(len=*), parameter :: PROCNAME = &
2956  "(predator_perception_get_visrange_objects)"
2957 
2958  !> ### Notable variables and parameters ###
2959  !> - **MIN_DIST_SELF** - exclude self from the neighbours. Because we
2960  !! cannot (easily) use recursive reference to the individual agent class
2961  !! from this lower-order perception class, we have to pass some
2962  !! parameters of the *this* agent as dummy parameters to the subroutine.
2963  !! E.g. individual ID, if ID is incorrect or not passed, the only way to
2964  !! distinguish self from other agents in the neighbourhood is by
2965  !! different location, i.e. the distance should be non-zero. This
2966  !! parameter sets the tolerance limit for the difference in the distance
2967  !! for considering the neighbour not-self. Possibly can be equal to the
2968  !! parameter `commondata::zero`, or one can allow a higher discrepancy
2969  !! (this also might correct some errors).
2970  real(SRP), parameter :: MIN_DIST_SELF = 0.001_srp
2971 
2972  !> - **agents_near** - temporary array of predators in proximity to this
2973  !! agent.
2974  type(spatial), dimension(size(spatl_agents)) :: agents_near
2975 
2976  !> - **dist_neighbours** - temporary array of the distances to the
2977  !! neighbouring predators.
2978  real(SRP), dimension(size(spatl_agents)) :: dist_neighbours
2979 
2980  !> - **dist_index** - temporary partial index vector for the distances
2981  !! to the neighbouring predators.
2982  integer, dimension(size(spatl_agents)) :: dist_index
2983 
2984  ! Temporary possible error status for sub-procedures
2985  logical :: err_flag
2986 
2987  !> - **irradiance_agent_depth** - local variable defining the irradiance
2988  !! (illumination) at the current depth of the agent. Needed to
2989  !! calculate the agent's visual range.
2990  real(SRP) :: irradiance_agent_depth
2991 
2992  !> - **spatl_sizes** -local copy of the body lengths of the predators.
2993  real(SRP), dimension(size(spatl_agents)) :: spatl_sizes
2994 
2995  ! Local copy of the attack rates of the predators
2996  real(SRP), dimension(size(spatl_agents)) :: pred_attack_rates
2997 
2998  !> - **sobject_area** - local variable defining the conspecific area.
2999  !! Needed to calculate the agent's visual range.
3000  ! It is the `prey_area` parameter in the equation.
3001  real(SRP), dimension(size(spatl_agents)) :: sobject_area
3002 
3003  !> - **sobject_visual_range** - local variable defining the visual range
3004  !! of the agent for detecting each of the predators (with known areas)
3005  !! at the agent's current depth.
3006  real(SRP), dimension(size(spatl_agents)) :: sobject_visual_range
3007 
3008  !> - **sobjects_percept_in_visrange** - local sorted array of the
3009  !! perception components that are within the visual range of the agent
3010  !! for output. The array should normally have the size of
3011  !! `commondata::pred_select_items_index_partial` elements, but only
3012  !! the first `sobjects_n_visrange` elements of it are actually within
3013  !! the visual range.
3014  type(spatialobj_percept_comp), dimension( & PRED_SELECT_ITEMS_INDEX_PARTIAL) :: sobjects_percept_in_visrange
3015 
3016  !> - **pred_attack_rates_in_visrange** - local variable containing the
3017  !! attack rates of the predators that are within the visual range of
3018  !! the agent. The array should normally have the size of
3019  !! `commondata::pred_select_items_index_partial` elements, but only
3020  !! the first `sobjects_n_visrange` elements of it are actually within
3021  !! the visual range.
3022  real(SRP) , dimension( & PRED_SELECT_ITEMS_INDEX_PARTIAL) :: pred_attack_rates_in_visrange
3023 
3024  !> - **index_max_size** - the size of the input arrays of object
3025  !! properties, local. Initially set from the size of the objects (class)
3026  !! array, but `spatl_sizes` must have identical size.
3027  integer :: index_max_size
3028 
3029  !> - **sobjects_n_visrange** - local number of elements of
3030  !! `food_items_percept_in_visrange` for output that are within he visual
3031  !! range of the agent.
3032  !! .
3033  integer :: sobjects_n_visrange
3034 
3035  ! Local counter
3036  integer :: i
3037 
3038  !. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3039 
3040  !> ### Implementation details ###
3041  !> #### Checks and preparations ####
3042  !> Initialise index and rank values. Uninitialised index arrays may result
3043  !! in invalid memory reference in `ARRAY_INDEX` (it is not safe by design).
3044  dist_neighbours = missing ; dist_index = unknown
3045  sobject_area = missing ; sobject_visual_range = missing
3046 
3047  !> Check optional time step parameter. If unset, use global
3048  !! `commondata::global_time_step_model_current`.
3049  if (present(time_step_model)) then
3050  time_step_model_here = time_step_model
3051  else
3052  time_step_model_here = global_time_step_model_current
3053  end if
3054 
3055  !> This is the maximum size of the index. If the number of spatial objects
3056  !! is huge, we use partial indexing of the neighbours array. Then it is
3057  !! equal to the partial indexing
3058  !! `commondata::pred_select_items_index_partial`. However, if the number
3059  !! of potential neighbouring objects is smaller than the partial index
3060  !! size, we use full indexing. In the later case `index_max_size` is
3061  !! equal to the actual size of the neighbouring objects array.
3062  !! @note Distinguishing between the partial indexing parameter and the
3063  !! max size of the index makes sense only in cases where small
3064  !! number of neighbours can be expected. We normally have large
3065  !! populations of agents and huge number of food items, well
3066  !! exceeding the partial indexing parameter
3067  !! `commondata::pred_select_items_index_partial`. However, the
3068  !! number of predators can be smaller than this.
3069  index_max_size = min( size(spatl_agents), pred_select_items_index_partial )
3070 
3071  !> Copy predators array from the input `spatl_agents` class into
3072  !! `agents_near`.
3073  call agents_near%position ( spatl_agents%location() )
3074 
3075  !> Get an array of the body sizes of the predators using array-based
3076  !! elemental function (This now works ok in Intel Fortran 17).
3077  spatl_sizes = spatl_agents%get_size()
3078 
3079  !> Get an array of the attack rates of the predators using array-based
3080  !! elemental function.
3081  pred_attack_rates = spatl_agents%get_attack_rate()
3082 
3083  !. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3084  !> #### Step 1 ####
3085  !> First, we get, up to the maximum order (fast *partial indexing*)
3086  !! of `commondata::pred_select_items_index_partial`, neighbouring
3087  !! predators that are in proximity of this agent. here we get partial
3088  !! index vector for the input array of objects: `dist_index`.
3089  !! **Partial indexing** is the most typical case as we have normally
3090  !! quite large number of agents within the population and food
3091  !! items within the habitat. However, this might be important for
3092  !! **predators**. Predators can be quite infrequent within the
3093  !! habitat, their number can be smaller than the maximum indexing
3094  !! parameter `commondata::pred_select_items_index_partial`. Hence
3095  !! the check is much more important here than in similar
3096  !! procedures for food items and conspecifics. The neighbours are
3097  !! computed using the the_environment::spatial::neighbours() procedure.
3098  if ( size(spatl_agents) < pred_select_items_index_partial ) then
3099  !> Here we check if the number of neighbouring agents is smaller than
3100  !! the partial indexing parameter
3101  !! commondata::pred_select_items_index_partial and if yes, do **full
3102  !! indexing**.
3103  call this%neighbours( neighbours = agents_near, &
3104  dist = dist_neighbours, &
3105  index_vector = dist_index, &
3106  error_flag = err_flag )
3107  else
3108  !> However, if the number of potential neighbouring objects is big, do
3109  !! **partial indexing**.
3110  call this%neighbours( neighbours = agents_near, &
3111  dist = dist_neighbours, &
3112  index_vector = dist_index, &
3113  rank_max = pred_select_items_index_partial, &
3114  error_flag = err_flag )
3115  end if
3116  if (err_flag) call log_msg ( ltag_warn // procname // ": Got error flag" &
3117  // " from conspecific objects neighbours procedure.")
3118 
3119  !. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3120  !> #### Step 2 ####
3121  !> Second, we select only those items within this set, which are within
3122  !! the visual range of the agent under the current conditions.
3123  !! To do this we, first, calculate the ambient illumination/irradiance
3124  !! level at the depth of the agent. Done using the
3125  !! the_environment::spatial::illumination() procedure.
3126  irradiance_agent_depth = this%illumination(time_step_model_here)
3127 
3128  !> Compute the array of "prey areas" for each conspecific.
3129  !! So far `prey_contrast` is not set, use default value
3130  !! `commondata::individual_visual_contrast_default`.
3131  sobject_area(dist_index(1:index_max_size)) = &
3133  cm2m( spatl_sizes(dist_index(1:index_max_size)) ) &
3134  )
3135 
3136  !> Compute the vector of the visual ranges for detecting each of
3137  !! the predators by the agent.
3138  sobject_visual_range(dist_index(1:index_max_size)) &
3139  = m2cm( visual_range( &
3140  irradiance = irradiance_agent_depth, &
3141  prey_area = sobject_area( &
3142  dist_index(1:index_max_size) &
3143  ), &
3144  prey_contrast = individual_visual_contrast_default &
3145  ) &
3146  )
3147 
3148  !. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3149  !> #### Step 3 ####
3150  !> Now we can get the pre-output array `sobjects_percept_in_visrange`
3151  !! that contains the predators available within the visual range of
3152  !! the agent. Also, we count their number for the output parameter
3153  !! `sobjects_n_visrange`.
3154  sobjects_n_visrange = 0
3155  do i=1, index_max_size
3156  if ( dist_neighbours(dist_index(i)) < &
3157  sobject_visual_range(dist_index(i)) ) then
3158  sobjects_n_visrange = sobjects_n_visrange + 1
3159  call sobjects_percept_in_visrange(sobjects_n_visrange)%make( &
3160  location = agents_near(dist_index(i))%location(), &
3161  size = spatl_sizes(dist_index(i)), &
3162  dist = dist_neighbours(dist_index(i)), &
3163  cid = dist_index(i) )
3164  !> The inherent attack rates of each of the predators within the
3165  !! visual range is also collected here into the
3166  !! `pred_attack_rates_in_visrange` array.
3167  pred_attack_rates_in_visrange(sobjects_n_visrange) = &
3168  pred_attack_rates(dist_index(i))
3169  end if
3170  end do
3171  !> Here we also log warning if no objects found, when debugging.
3172  !! (see commondata::is_debug).
3173  if (sobjects_n_visrange==0) call log_dbg( ltag_warn // procname // &
3174  ": No objects found within the visual range of the agent; " // &
3175  "The nearest object distance=" // &
3176  tostr(dist_neighbours(dist_index(1))) // &
3177  ", with visual range=" // &
3178  tostr(sobject_visual_range(dist_index(1))) // &
3179  ", ID:" // tostr(dist_index(1)) )
3180 
3181  !. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3182  !> #### Step 4 ####
3183  !> Finally, we can now create the output conspecific perception object,
3184  !! including only predators that are within the current visual range
3185  !! of the agent.
3186  !! Init (create and allocate) the predator perception object,
3187  !! at first empty, with the_neurobio::percept_predator::init().
3188  call this%perceive_predator%init(sobjects_n_visrange)
3189 
3190  !> Fill the output perception object with the values obtained at
3191  !! the step 3 using the the_neurobio::percept_predator::make() method.
3193  !> Note that if the commondata::agent_can_assess_predator_attack_rate
3194  !! parameter is set to TRUE, the agents can access and assess the
3195  !! inherent attack rate of the predator. This can be for example
3196  !! possible if the agent can assess the hunger level of the predator.
3197  !! The attack rate is then set from the array of the inherent attack
3198  !! rates of the predators `pred_attack_rates_in_visrange`. May need to
3199  !! add a predator perception error to this value, but it is not
3200  !! implemented yet.
3201  call this%perceive_predator%make ( &
3202  sobjects_percept_in_visrange(1:sobjects_n_visrange), &
3203  pred_attack_rates_in_visrange(1:sobjects_n_visrange) )
3204  else
3205  !> Note that if the commondata::agent_can_assess_predator_attack_rate
3206  !! parameter is set to FALSE, the agents cannot access the
3207  !! inherent attack rate of the predator. The attack rate is then fixed
3208  !! from the default parameter commondata::predator_attack_rate_default
3209  !! value.
3210  call this%perceive_predator%make ( &
3211  sobjects_percept_in_visrange(1:sobjects_n_visrange) )
3212  end if
3213 
3215 
3216  !-----------------------------------------------------------------------------
3217  !> Check if the agent sees any predators within the visual range.
3218  !! @warning Should be called after the `the_neurobio::perception::see_food()`
3219  !! method as it is just an accessor function.
3220  ! @note There is little sense to implement this accessor procedure in the
3221  ! specific perception (up-level) class as every perception is not
3222  ! a derivative of a common class, perceptions independent, so we'll
3223  ! have to also implement agent-bound perception methods anyway.
3224  elemental function predator_perception_is_seeing_predators(this) &
3225  result(sees_pred)
3226  class(perception), intent(in) :: this
3227  logical :: sees_pred
3228 
3229  sees_pred = .false.
3230  if (this%perceive_predator%get_count() > 0 ) sees_pred = .true.
3231 
3233 
3234  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3235  ! Functions linked with LIGHT PERCEPTION
3236  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3237 
3238  !-----------------------------------------------------------------------------
3239  !> Make en empty light perception component. Really necessary only when
3240  !! perception objects are all allocatable.
3241  elemental subroutine percept_light_create_init(this)
3242  class(percept_light), intent(inout) :: this
3244  this%illumination = missing
3245 
3246  end subroutine percept_light_create_init
3247 
3248  !-----------------------------------------------------------------------------
3249  !> Get the current perception of the illumination.
3250  elemental function percept_light_get_current(this) result (illumination_here)
3251  class(percept_light), intent(in) :: this
3252  real(srp) :: illumination_here
3253 
3254  illumination_here = this%illumination
3255 
3256  end function percept_light_get_current
3257 
3258  !-----------------------------------------------------------------------------
3259  !> Set the current **light** level into the perception component.
3260  subroutine percept_light_set_current(this, timestep, depth)
3261  class(percept_light), intent(inout) :: this
3262  integer, intent(in) :: timestep
3263  real(SRP), intent(in) :: depth
3264 
3265  !> Here we, calculate the ambient illumination/irradiance level at the
3266  !! current depth of the agent.
3267  !> @note `is_stochastic` logical parameter is TRUE in `light_surface`, that
3268  !! sets a stochastic illumination level at the surface and therefore
3269  !! also at the agent's current depth.
3270  this%illumination = light_depth( depth=depth, &
3271  surface_light = &
3272  light_surface(tstep=timestep, &
3273  is_stochastic=daylight_stochastic)&
3274  )
3275 
3276  end subroutine percept_light_set_current
3277 
3278  !-----------------------------------------------------------------------------
3279  !> Destroy / deallocate **light** perception component. Really necessary only when
3280  !! perception objects are all allocatable.
3281  elemental subroutine percept_light_destroy_deallocate(this)
3282  class(percept_light), intent(inout) :: this
3284  this%illumination = missing
3285 
3286  end subroutine percept_light_destroy_deallocate
3287 
3288  !-----------------------------------------------------------------------------
3289  !> Get **light** perception objects into the individual PERCEPTION
3290  !! object layer.
3291  subroutine light_perception_get_object(this, time_step_model)
3292  class(perception), intent(inout) :: this
3294  !> @param[in] time_step_model The current time step of the model.
3295  integer, optional, intent(in) :: time_step_model
3296 
3297  !> Local copy of the time step of the model.
3298  integer :: time_step_model_here
3299 
3300  !> Check optional time step parameter. If unset, use global
3301  !! `commondata::global_time_step_model_current`.
3302  if (present(time_step_model)) then
3303  time_step_model_here = time_step_model
3304  else
3305  time_step_model_here = global_time_step_model_current
3306  end if
3307 
3308  !> Allocate and init the perception object (needed only when it is
3309  !! allocatable)
3310  call this%perceive_light%init()
3311 
3312  call this%perceive_light%set_current( time_step_model_here, this%dpos() )
3313 
3314  end subroutine light_perception_get_object
3315 
3316  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3317  ! Functions linked with DEPTH PERCEPTION
3318  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3319 
3320  !-----------------------------------------------------------------------------
3321  !> Make en empty depth perception component. Really necessary only when
3322  !! perception objects are all allocatable.
3323  elemental subroutine percept_depth_create_init(this)
3324  class(percept_depth), intent(inout) :: this
3326  this%depth = missing
3327 
3328  end subroutine percept_depth_create_init
3329 
3330  !-----------------------------------------------------------------------------
3331  !> Get the current perception of the **depth**.
3332  elemental function percept_depth_get_current(this) result (depth_now)
3333  class(percept_depth), intent(in) :: this
3334  real(srp) :: depth_now
3335 
3336  depth_now = this%depth
3337 
3338  end function percept_depth_get_current
3339 
3340  !-----------------------------------------------------------------------------
3341  !> Set the current **depth** level into the perception component.
3342  subroutine percept_depth_set_current(this, cdepth)
3343  class(percept_depth), intent(inout) :: this
3344  real(SRP), intent(in) :: cdepth
3345 
3346  this%depth = cdepth
3347 
3348  end subroutine percept_depth_set_current
3349 
3350  !-----------------------------------------------------------------------------
3351  !> Destroy / deallocate **depth** perception component. Really necessary
3352  !! only when perception objects are all allocatable.
3353  elemental subroutine percept_depth_destroy_deallocate(this)
3354  class(percept_depth), intent(inout) :: this
3356  this%depth = missing
3357 
3358  end subroutine percept_depth_destroy_deallocate
3359 
3360  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3361  ! Functions linked with REPRODUCTIVE FACTOR PERCEPTION
3362  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3363 
3364  !-----------------------------------------------------------------------------
3365  !> Make en empty reproductive factor perception component. Really necessary
3366  !! only when perception objects are all allocatable.
3367  elemental subroutine percept_reprfac_create_init(this)
3368  class(percept_reprfact), intent(inout) :: this
3370  this%reproduct_fact = missing
3371 
3372  end subroutine percept_reprfac_create_init
3373 
3374  !-----------------------------------------------------------------------------
3375  !> Get the current perception of the **reproductive factor**.
3376  elemental function percept_reprfac_get_current(this) result (rf_now)
3377  class(percept_reprfact), intent(in) :: this
3378  real(srp) :: rf_now
3379 
3380  rf_now = this%reproduct_fact
3381 
3382  end function percept_reprfac_get_current
3383 
3384  !-----------------------------------------------------------------------------
3385  !> Set the current **reproductive factor** level into perception component.
3386  subroutine percept_reprfac_set_current(this, reprfac)
3387  class(percept_reprfact), intent(inout) :: this
3388  real(SRP), intent(in) :: reprfac
3389 
3390  this%reproduct_fact = reprfac
3391 
3392  end subroutine percept_reprfac_set_current
3393 
3394  !-----------------------------------------------------------------------------
3395  !> Destroy / deallocate **reproductive factor** perception component. Really
3396  !! necessary only when perception objects are all allocatable.
3397  elemental subroutine percept_reprfac_destroy_deallocate(this)
3398  class(percept_reprfact), intent(inout) :: this
3400  this%reproduct_fact = missing
3401 
3402  end subroutine percept_reprfac_destroy_deallocate
3403 
3404  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3405  ! Functions linked with GET OBJECTS PERCEPTION
3406  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3407 
3408  !-----------------------------------------------------------------------------
3409  !> Get **depth** perception objects into the **individual** PERCEPTION
3410  !! object layer.
3411  subroutine depth_perception_get_object(this)
3412  class(perception), intent(inout) :: this
3414  !> Allocate and init the perception object (needed only when it is
3415  !! allocatable)
3416  call this%perceive_depth%init()
3417 
3418  call this%perceive_depth%set_current( this%dpos() )
3419 
3420  end subroutine depth_perception_get_object
3421 
3422  !-----------------------------------------------------------------------------
3423  !> Get the **stomach capacity** perception objects into the **individual**
3424  !! PERCEPTION object layer.
3425  subroutine stomach_perception_get_object(this)
3426  class(perception), intent(inout) :: this
3428  !> Allocate and init the perception object (needed only when it is
3429  !! allocatable)
3430  call this%perceive_stomach%init()
3431 
3432  !> Calculate the available stomach capacity, i.e. maximum stomach mass
3433  !! minus current stomach content, and set the value into the stomach
3434  !! perception object. Body mass and maxstomcap are from the `CONDITION`
3435  !! layer.
3436  call this%perceive_stomach%set_available( this%body_mass * this%maxstomcap &
3437  - this%get_stom_content() )
3438 
3439  end subroutine stomach_perception_get_object
3440 
3441  !-----------------------------------------------------------------------------
3442  !> Get the **body mass** perception objects into the **individual**
3443  !! PERCEPTION object layer.
3444  subroutine bodymass_perception_get_object(this)
3445  class(perception), intent(inout) :: this
3447  !> Allocate and init the perception object (needed only when it is
3448  !! allocatable)
3449  call this%perceive_body_mass%init()
3450 
3451  !> Get the body mass from the individual, put it to the perception object.
3452  call this%perceive_body_mass%set_current( this%mass() )
3453 
3454  end subroutine bodymass_perception_get_object
3455 
3456  !-----------------------------------------------------------------------------
3457  !> Get the **energy reserves** perception objects into the **individual**
3458  !! PERCEPTION object layer.
3459  subroutine energy_perception_get_object(this)
3460  class(perception), intent(inout) :: this
3462  !> Allocate and init the perception object (needed only when it is
3463  !! allocatable)
3464  call this%perceive_energy%init()
3465 
3466  !> Get the energy reserves from the individual, put it to the perception
3467  !! object.
3468  call this%perceive_energy%set_current( this%get_energy() )
3469 
3470  end subroutine energy_perception_get_object
3471 
3472  !-----------------------------------------------------------------------------
3473  !> Get the **age** perception objects into the **individual**
3474  !! PERCEPTION object layer.
3475  subroutine age_perception_get_object(this)
3476  class(perception), intent(inout) :: this
3478  !> Allocate and init the perception object (needed only when it is
3479  !! allocatable).
3480  call this%perceive_age%init()
3481 
3482  !> Get the age from the individual, put it to the perception
3483  !! object.
3484  call this%perceive_age%set_current( this%get_age() )
3485 
3486  end subroutine age_perception_get_object
3487 
3488  !-----------------------------------------------------------------------------
3489  !> Get the **reproductive factor** perception objects into the **individual**
3490  !! PERCEPTION object layer.
3491  subroutine repfac_perception_get_object(this)
3492  class(perception), intent(inout) :: this
3494  !> Allocate and init the perception object (needed only when it is
3495  !! allocatable).
3496  call this%perceive_reprfac%init()
3497 
3498  !> Get the the_hormones::hormones::reproductive_factor() from the
3499  !! individual, put it to the perception object.
3500  call this%perceive_reprfac%set_current( this%reproductive_factor() )
3501 
3502  end subroutine repfac_perception_get_object
3503 
3504 
3505  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3506  ! Functions linked with PERCEPTION MEMORY STACK
3507  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3508 
3509  !-----------------------------------------------------------------------------
3510  !> Add perception components into the memory stack.
3511  elemental subroutine percept_memory_add_to_stack(this, light, depth, food, &
3512  foodsize, fooddist, consp, pred, stom, bdmass, energ, reprfac )
3514  class(memory_perceptual), intent(inout) :: this !> This memory object.
3515 
3516  !> The parameters of the subroutine are the actual values that are added
3517  !! to the perceptual memory stack arrays.
3518  real(srp), intent(in) :: light !> illuimination
3519  real(srp), intent(in) :: depth !> depth
3520  integer , intent(in) :: food !> number of food items
3521  real(srp), intent(in) :: foodsize !> average size of food items
3522  real(srp), intent(in) :: fooddist !> average distance to food items
3523  integer , intent(in) :: consp !> number of conspecifics
3524  integer , intent(in) :: pred !> number of predators
3525  real(srp), intent(in) :: stom !> stomach capacity
3526  real(srp), intent(in) :: bdmass !> body mass
3527  real(srp), intent(in) :: energ !> energy
3528  real(srp), intent(in) :: reprfac !> reproductive factor
3529 
3530  !> Each of the memory stack components corresponds to the respective
3531  !! dummy parameter. So arrays are updated at each step.
3532  call add_to_history( this%memory_light, light )
3533  call add_to_history( this%memory_depth, depth )
3534  call add_to_history( this%memory_food , food )
3535  call add_to_history( this%memory_foodsiz, foodsize )
3536  call add_to_history( this%memory_foodist, fooddist )
3537  call add_to_history( this%memory_consp, consp )
3538  call add_to_history( this%memory_pred , pred )
3539  call add_to_history( this%memory_stom , stom )
3540  call add_to_history( this%memory_bdmass, bdmass )
3541  call add_to_history( this%memory_energ , energ )
3542  call add_to_history( this%memory_reprfac, reprfac )
3543 
3544  end subroutine percept_memory_add_to_stack
3545 
3546  !-----------------------------------------------------------------------------
3547  !> Cleanup and destroy the perceptual memory stack.
3548  elemental subroutine percept_memory_cleanup_stack(this)
3549 
3550  class(memory_perceptual), intent(inout) :: this !> This memory object.
3551 
3552  !> cleanup procedure uses whole array assignment.
3553  this%memory_light = missing
3554  this%memory_depth = missing
3555  this%memory_food = unknown
3556  this%memory_foodsiz = missing
3557  this%memory_foodist = missing
3558  this%memory_consp = unknown
3559  this%memory_pred = unknown
3560  this%memory_stom = missing
3561  this%memory_bdmass = missing
3562  this%memory_energ = missing
3563  this%memory_reprfac = missing
3564 
3565  end subroutine percept_memory_cleanup_stack
3566 
3567  !-----------------------------------------------------------------------------
3568  !> Get the total number of food items within the whole perceptual memory
3569  !! stack.
3570  elemental function percept_memory_food_get_total (this) &
3571  result(total_count)
3572  class(memory_perceptual), intent(in) :: this
3573  !> @returns Total count of predators in the memory stack.
3574  integer :: total_count
3575 
3576  !> Calculate the overall sum excluding missing values (masked).
3577  total_count = sum(this%memory_food, this%memory_food /= unknown)
3578 
3579  end function percept_memory_food_get_total
3580 
3581  !-----------------------------------------------------------------------------
3582  !> Get the **average number** of food items per single time step within the
3583  !! whole perceptual memory stack.
3584  !! @note There are several similar procedures with very similar
3585  !! implementation:
3586  !! - the_neurobio::percept_memory_food_get_mean_n() - get mean
3587  !! **number** of food items from the memory;
3588  !! - the_neurobio::percept_memory_food_get_mean_size() - get
3589  !! mean **size** of food items from the memory.
3590  !! - the_neurobio::percept_memory_predators_get_mean() - get
3591  !! average number of predators from the memory.
3592  !! .
3593  elemental function percept_memory_food_get_mean_n (this, last) &
3594  result(mean_count)
3595  class(memory_perceptual), intent(in) :: this
3596 
3597  !> @param last Limit to only this number of latest components in history.
3598  integer, optional, intent(in) :: last
3599 
3600  !> @returns Mean count of food items in the memory stack.
3601  real(srp) :: mean_count
3602 
3603  !> Local copy of optional last
3604  integer :: last_here
3605 
3606  ! History stack size. We determine it from the size of the actual array
3607  ! rather than `commondata::history_size_perception` for further safety.
3608  integer, parameter :: hist_size = size(this%memory_food)
3609 
3610  !> ### Implementation notes ###
3611  !> Check if we are given the parameter requesting the latest history size.
3612  !! if parameter `last` absent or bigger than the array size, get whole
3613  !! stack array.
3614  if (present(last)) then
3615  if ( last < hist_size ) then
3616  last_here = last
3617  else
3618  last_here = hist_size - 1
3619  end if
3620  else
3621  last_here = hist_size - 1
3622  end if
3623 
3624  !> Calculate the average excluding missing values (masked) using
3625  !! commondata::average().
3626  mean_count=average( this%memory_food( hist_size-last_here+1:hist_size ), &
3627  undef_ret_null=.true. )
3628 
3629  end function percept_memory_food_get_mean_n
3630 
3631  !-----------------------------------------------------------------------------
3632  !> Get the **average number** of food items per single time step within the
3633  !! perceptual memory stack, split to the first (older) and second (newer)
3634  !! parts. The whole memory stack ('sample') is split by the `split_val`
3635  !! parameter and two means are calculated: before the `split_val` and after
3636  !! it.
3637  !! @note There are several similar procedures with very similar
3638  !! implementation:
3639  !! - the_neurobio::percept_memory_food_mean_n_split() - get mean
3640  !! **number** of food items from the memory;
3641  !! - the_neurobio::percept_memory_food_mean_size_split() - get
3642  !! mean **size** of food items from the memory;
3643  !! - the_neurobio::percept_memory_predators_mean_split() - get
3644  !! average number of predators.
3645  !! .
3646  elemental subroutine percept_memory_food_mean_n_split( this, window, &
3647  split_val, older, newer )
3648  class(memory_perceptual), intent(in) :: this
3649  !> @param[in] window is the whole memory window which is analysed, if
3650  !! not present, the whole memory stack is used.
3651  integer, optional, intent(in) :: window
3652  !> @param[in] split_val is the split value for the separation of the
3653  !! older and newer averages. If not present, just splits the
3654  !! memory window evenly in two halves.
3655  integer, optional, intent(in) :: split_val
3656  !> @param[out] older is the output average number of the food items in the
3657  !! first (older) part of the memory window.
3658  real(srp), intent(out) :: older
3659  !> @param[out] newer is the output average number of the food items in the
3660  !! second (newer) part of the memory window.
3661  real(srp), intent(out) :: newer
3662 
3663  ! Local copies of optionals.
3664  integer :: window_loc, split_val_loc
3665 
3666  integer, parameter :: hist_size = size(this%memory_food)
3667 
3668  !> ### Implementation details ###
3669  !> First, check optional parameters: the memory window `window` and the
3670  !> split value `split_val`. If either is not provided, defaults are used.
3671  if (present(window)) then
3672  window_loc = window
3673  !> (Also, a check is made so that a window exceeding the history stack
3674  !! length is reduced accordingly to the whole memory size).
3675  if (window_loc >= hist_size) window_loc = hist_size
3676  else
3677  !> - whole size of the perceptual memory stack
3678  !! commondata::history_size_perception for the memory window
3679  window_loc = hist_size
3680  end if
3681 
3682  if (present(split_val)) then
3683  split_val_loc = split_val
3684  else
3685  !> - half of the memory window for the `split_val`.
3686  !! .
3687  split_val_loc = floor( real( window_loc, srp ) / 2.0 )
3688  end if
3689 
3690  !> A sanity check is also done, if the split value happen to exceed the
3691  !! `window` parameter, it is reduced to the default 1/2 of the `window`.
3692  if (split_val_loc >= window_loc) &
3693  split_val_loc = floor( real( window_loc, srp ) / 2.0 )
3694 
3695  !> Second, the `older` and the `newer` output average values are calculated.
3696  !! Here is the illustration of the calculation:
3697  !! @verbatim
3698  !! Such 'window' and 'split_val'
3699  !! values...
3700  !!
3701  !! |<----- window ----->|
3702  !! +--------+--------------------+
3703  !! + | :|: +
3704  !! +--------+--------------------+
3705  !! ^ split_val
3706  !!
3707  !!
3708  !! ... result in these means:
3709  !!
3710  !! +--------+---------------------+
3711  !! + | mean for | mean for +
3712  !! + | 'older' | 'newer' +
3713  !! +--------+---------------------+
3714  !! @endverbatim
3715  older=average( this%memory_food(hist_size-window_loc+1 : &
3716  hist_size-window_loc+split_val_loc), &
3717  undef_ret_null=.true. )
3718 
3719  newer=average( this%memory_food(hist_size-window_loc+split_val_loc+1 : &
3720  hist_size), &
3721  undef_ret_null=.true. )
3722 
3723  end subroutine percept_memory_food_mean_n_split
3724 
3725  !-----------------------------------------------------------------------------
3726  !> Get the **average size** of food item per single time step within the
3727  !! whole perceptual memory stack.
3728  !! @note There are several similar procedures with very similar
3729  !! implementation:
3730  !! - the_neurobio::percept_memory_food_get_mean_n() - get mean
3731  !! **number** of food items from the memory;
3732  !! - the_neurobio::percept_memory_food_get_mean_size() - get
3733  !! mean **size** of food items from the memory.
3734  !! - the_neurobio::percept_memory_predators_get_mean() - get
3735  !! average number of predators from the memory.
3736  !! .
3737  elemental function percept_memory_food_get_mean_size (this, last) &
3738  result(mean_val)
3739  class(memory_perceptual), intent(in) :: this
3740 
3741  !> @param last Limit to only this number of latest components in history.
3742  integer, optional, intent(in) :: last
3743 
3744  !> @returns Mean size of food items in the memory stack.
3745  real(srp) :: mean_val
3746 
3747  !> Local copy of optional last
3748  integer :: last_here
3749 
3750  ! History stack size. We determine it from the size of the actual array
3751  ! rather than `commondata::history_size_perception` for further safety.
3752  integer, parameter :: hist_size = size(this%memory_foodsiz)
3753 
3754  !> ### Implementation notes ###
3755  !> Check if we are given the parameter requesting the latest history size.
3756  !! if parameter `last` absent or bigger than the array size, get whole
3757  !! stack array.
3758  if (present(last)) then
3759  if ( last < hist_size ) then
3760  last_here = last
3761  else
3762  last_here = hist_size
3763  end if
3764  else
3765  last_here = hist_size
3766  end if
3767 
3768  !> Calculate the average excluding missing values (masked) using
3769  !! commondata::average().
3770  mean_val = average(this%memory_foodsiz(hist_size-last_here+1:hist_size), &
3771  undef_ret_null=.true.)
3772 
3774 
3775  !-----------------------------------------------------------------------------
3776  !> Get the **average size** of food items per single time step within the
3777  !! perceptual memory stack, split to the first (older) and second(newer)
3778  !! parts. The whole memory stack 'sample' is split by the `split_val`
3779  !! parameter and two means are calculated: before the `split_val` and after
3780  !! it.
3781  !! @note There are several similar procedures with very similar
3782  !! implementation:
3783  !! - the_neurobio::percept_memory_food_mean_n_split() - get mean
3784  !! **number** of food items from the memory;
3785  !! - the_neurobio::percept_memory_food_mean_size_split() - get
3786  !! mean **size** of food items from the memory;
3787  !! - the_neurobio::percept_memory_predators_mean_split() - get
3788  !! average number of predators.
3789  !! .
3790  elemental subroutine percept_memory_food_mean_size_split( this, window, &
3791  split_val, older, newer )
3792  class(memory_perceptual), intent(in) :: this
3793  !> @param[in] window is the whole memory window which is analysed, if
3794  !! not present, the whole memory stack is used.
3795  integer, optional, intent(in) :: window
3796  !> @param[in] split_val is the split value for the separation of the
3797  !! older and newer averages. If not present, just splits the
3798  !! memory window evenly in two halves.
3799  integer, optional, intent(in) :: split_val
3800  !> @param[out] older is the output average sizes of the food items in the
3801  !! first (older) part of the memory window.
3802  real(srp), intent(out) :: older
3803  !> @param[out] newer is the output average sizes of the food items in the
3804  !! second (newer) part of the memory window.
3805  real(srp), intent(out) :: newer
3806 
3807  ! Local copies of optionals.
3808  integer :: window_loc, split_val_loc
3809 
3810  integer, parameter :: hist_size = size(this%memory_foodsiz)
3811 
3812  !> ### Implementation details ###
3813  !> First, check optional parameters: the memory window `window` and the
3814  !> split value `split_val`. If either is not provided, defaults are used.
3815  if (present(window)) then
3816  window_loc = window
3817  !> (Also, a check is made so that a window exceeding the history stack
3818  !! length is reduced accordingly to the whole memory size).
3819  if (window_loc >= hist_size) window_loc = hist_size
3820  else
3821  !> - whole size of the perceptual memory stack
3822  !! commondata::history_size_perception for the memory window
3823  window_loc = hist_size
3824  end if
3825 
3826  if (present(split_val)) then
3827  split_val_loc = split_val
3828  else
3829  !> - half of the memory window for the `split_val`.
3830  !! .
3831  split_val_loc = floor( real( window_loc, srp ) / 2.0 )
3832  end if
3833 
3834  !> A sanity check is also done, if the split value happen to exceed the
3835  !! `window` parameter, it is reduced to the default 1/2 of the `window`.
3836  if (split_val_loc >= window_loc) &
3837  split_val_loc = floor( real( window_loc, srp ) / 2.0 )
3838 
3839  !> Second, the `older` and the `newer` output average values are calculated.
3840  !! Here is the illustration of the calculation:
3841  !! @verbatim
3842  !! Such 'window' and 'split_val'
3843  !! values...
3844  !!
3845  !! |<----- window ----->|
3846  !! +--------+--------------------+
3847  !! + | :|: +
3848  !! +--------+--------------------+
3849  !! ^ split_val
3850  !!
3851  !!
3852  !! ... result in these means:
3853  !!
3854  !! +--------+---------------------+
3855  !! + | mean for | mean for +
3856  !! + | 'older' | 'newer' +
3857  !! +--------+---------------------+
3858  !! @endverbatim
3859  older=average( this%memory_foodsiz(hist_size-window_loc+1 : &
3860  hist_size-window_loc+split_val_loc), &
3861  undef_ret_null=.true. )
3862 
3863  newer=average( this%memory_foodsiz(hist_size-window_loc+split_val_loc+1 : &
3864  hist_size), &
3865  undef_ret_null=.true. )
3866 
3868 
3869  !-----------------------------------------------------------------------------
3870  !> Get the **average distance** to food item per single time step within the
3871  !! whole perceptual memory stack.
3872  !! @note There are several similar procedures with very similar
3873  !! implementation:
3874  !! - the_neurobio::percept_memory_food_get_mean_n() - get mean
3875  !! **number** of food items from the memory;
3876  !! - the_neurobio::percept_memory_food_get_mean_size() - get
3877  !! mean **size** of food items from the memory.
3878  !! - the_neurobio::percept_memory_predators_get_mean() - get
3879  !! average number of predators from the memory.
3880  !! .
3881  elemental function percept_memory_food_get_mean_dist (this, last, &
3882  undef_ret_null) result (mean_val)
3883  class(memory_perceptual), intent(in) :: this
3884  !> @param last Limit to only this number of latest components in history.
3885  integer, optional, intent(in) :: last
3886  !> @param undef_ret_null Optional flag if undefined value with sample size
3887  !! should return zero mean value; if absent is set to TRUE and zero
3888  !! mean is returned. Note that this behaviour is the opposite of the
3889  !! standard commondata::average(). It is because this function is
3890  !! mainly for perception memory, where zero value is appropriate in
3891  !! absence of any food items.
3892  logical, optional, intent(in) :: undef_ret_null
3893  !> @returns Mean distance to food items in the memory stack.
3894  real(srp) :: mean_val
3895 
3896  !> Local copies of optionals
3897  logical :: undef_ret_null_loc
3898  integer :: last_here
3899 
3900  ! History stack size. We determine it from the size of the actual array
3901  ! rather than `commondata::history_size_perception` for further safety.
3902  integer, parameter :: hist_size = size(this%memory_foodist)
3903 
3904  !> ### Implementation notes ###
3905  !> Check if we are given the parameter requesting the latest history size.
3906  !! if parameter `last` absent or bigger than the array size, get whole
3907  !! stack array.
3908  if (present(last)) then
3909  if ( last < hist_size ) then
3910  last_here = last
3911  else
3912  last_here = hist_size
3913  end if
3914  else
3915  last_here = hist_size
3916  end if
3917 
3918  if (present(undef_ret_null)) then
3919  undef_ret_null_loc = undef_ret_null
3920  else
3921  undef_ret_null_loc = .true.
3922  end if
3923 
3924  !> Calculate the average excluding missing values (masked) using
3925  !! commondata::average().
3926  mean_val = average(this%memory_foodist(hist_size-last_here+1:hist_size), &
3927  undef_ret_null=undef_ret_null_loc)
3928 
3930 
3931  !-----------------------------------------------------------------------------
3932  !> Get the **average distance** to food items per single time step within the
3933  !! perceptual memory stack, split to the first (older) and second(newer)
3934  !! parts. The whole memory stack 'sample' is split by the `split_val`
3935  !! parameter and two means are calculated: before the `split_val` and after
3936  !! it.
3937  !! @note There are several similar procedures with very similar
3938  !! implementation:
3939  !! - the_neurobio::percept_memory_food_mean_n_split() - get mean
3940  !! **number** of food items from the memory;
3941  !! - the_neurobio::percept_memory_food_mean_size_split() - get
3942  !! mean **size** of food items from the memory;
3943  !! - the_neurobio::percept_memory_predators_mean_split() - get
3944  !! average number of predators.
3945  !! .
3946  elemental subroutine percept_memory_food_mean_dist_split(this, window, &
3947  split_val, older, newer )
3948  class(memory_perceptual), intent(in) :: this
3949  !> @param[in] window is the whole memory window which is analysed, if
3950  !! not present, the whole memory stack is used.
3951  integer, optional, intent(in) :: window
3952  !> @param[in] split_val is the split value for the separation of the
3953  !! older and newer averages. If not present, just splits the
3954  !! memory window evenly in two halves.
3955  integer, optional, intent(in) :: split_val
3956  !> @param[out] older is the output average distance to the food items in the
3957  !! first (older) part of the memory window.
3958  real(srp), intent(out) :: older
3959  !> @param[out] newer is the output average distance to the food items in the
3960  !! second (newer) part of the memory window.
3961  real(srp), intent(out) :: newer
3962 
3963  ! Local copies of optionals.
3964  integer :: window_loc, split_val_loc
3965 
3966  integer, parameter :: hist_size = size(this%memory_foodist)
3967 
3968  !> ### Implementation details ###
3969  !> First, check optional parameters: the memory window `window` and the
3970  !> split value `split_val`. If either is not provided, defaults are used.
3971  if (present(window)) then
3972  window_loc = window
3973  !> (Also, a check is made so that a window exceeding the history stack
3974  !! length is reduced accordingly to the whole memory size).
3975  if (window_loc >= hist_size) window_loc = hist_size
3976  else
3977  !> - whole size of the perceptual memory stack
3978  !! commondata::history_size_perception for the memory window
3979  window_loc = hist_size
3980  end if
3981 
3982  if (present(split_val)) then
3983  split_val_loc = split_val
3984  else
3985  !> - half of the memory window for the `split_val`.
3986  !! .
3987  split_val_loc = floor( real( window_loc, srp ) / 2.0 )
3988  end if
3989 
3990  !> A sanity check is also done, if the split value happen to exceed the
3991  !! `window` parameter, it is reduced to the default 1/2 of the `window`.
3992  if (split_val_loc >= window_loc) &
3993  split_val_loc = floor( real( window_loc, srp ) / 2.0 )
3994 
3995  !> Second, the `older` and the `newer` output average values are calculated.
3996  !! Here is the illustration of the calculation:
3997  !! @verbatim
3998  !! Such 'window' and 'split_val'
3999  !! values...
4000  !!
4001  !! |<----- window ----->|
4002  !! +--------+--------------------+
4003  !! + | :|: +
4004  !! +--------+--------------------+
4005  !! ^ split_val
4006  !!
4007  !!
4008  !! ... result in these means:
4009  !!
4010  !! +--------+---------------------+
4011  !! + | mean for | mean for +
4012  !! + | 'older' | 'newer' +
4013  !! +--------+---------------------+
4014  !! @endverbatim
4015  older=average( this%memory_foodist(hist_size-window_loc+1 : &
4016  hist_size-window_loc+split_val_loc), &
4017  undef_ret_null=.true. )
4018 
4019  newer=average( this%memory_foodist(hist_size-window_loc+split_val_loc+1 : &
4020  hist_size), &
4021  undef_ret_null=.true. )
4022 
4024 
4025  !-----------------------------------------------------------------------------
4026  !> Get the **average number** of conspecifics per single time step within the
4027  !! whole perceptual memory stack.
4028  elemental function percept_memory_consp_get_mean_n (this, last) &
4029  result(mean_count)
4030  class(memory_perceptual), intent(in) :: this
4031 
4032  !> @param last Limit to only this number of latest components in history.
4033  integer, optional, intent(in) :: last
4034 
4035  !> @returns Mean count of conspecifics in the memory stack.
4036  real(srp) :: mean_count
4037 
4038  !> Local copy of optional last
4039  integer :: last_here
4040 
4041  ! History stack size. We determine it from the size of the actual array
4042  ! rather than `commondata::history_size_perception` for further safety.
4043  integer, parameter :: hist_size = size(this%memory_consp)
4044 
4045  !> ### Implementation notes ###
4046  !> Check if we are given the parameter requesting the latest history size.
4047  !! if parameter `last` absent or bigger than the array size, get whole
4048  !! stack array.
4049  if (present(last)) then
4050  if ( last < hist_size ) then
4051  last_here = last
4052  else
4053  last_here = hist_size - 1
4054  end if
4055  else
4056  last_here = hist_size - 1
4057  end if
4058 
4059  !> Calculate the average excluding missing values (masked) using
4060  !! commondata::average().
4061  mean_count=average( this%memory_consp( hist_size-last_here+1:hist_size ), &
4062  undef_ret_null=.true. )
4063 
4064  end function percept_memory_consp_get_mean_n
4065 
4066  !-----------------------------------------------------------------------------
4067  !> Get the total number of predators within the whole perceptual memory stack.
4068  elemental function percept_memory_predators_get_total (this) &
4069  result(total_count)
4070  class(memory_perceptual), intent(in) :: this
4071  !> @returns Total count of predators in the memory stack.
4072  integer :: total_count
4073 
4074  !> Calculate the overall sum excluding missing values (masked).
4075  total_count = sum(this%memory_pred, this%memory_pred /= unknown)
4076 
4078 
4079  !-----------------------------------------------------------------------------
4080  !> Get the average number of predators per single time step within the
4081  !! whole perceptual memory stack.
4082  !! @note There are several similar procedures with very similar
4083  !! implementation:
4084  !! - the_neurobio::percept_memory_food_get_mean_n() - get mean
4085  !! **number** of food items from the memory;
4086  !! - the_neurobio::percept_memory_food_get_mean_size() - get
4087  !! mean **size** of food items from the memory.
4088  !! - the_neurobio::percept_memory_predators_get_mean() - get
4089  !! average number of predators from the memory.
4090  !! .
4091  elemental function percept_memory_predators_get_mean (this, last) &
4092  result(mean_count)
4093  class(memory_perceptual), intent(in) :: this
4094 
4095  !> @param last Limit to only this number of latest components in the
4096  !! history.
4097  integer, optional, intent(in) :: last
4098 
4099  !> @returns Mean count of predators in the memory stack.
4100  real(srp) :: mean_count
4101 
4102  !> Local copy of optional last
4103  integer :: last_here
4104 
4105  !> History stack size. We determine it from the size of the actual array
4106  !! rather than `HISTORY_SIZE_PERCEPTION` for further safety.
4107  integer, parameter :: hist_size = size(this%memory_pred)
4108 
4109  !> Check if we are given the parameter requesting the latest history size.
4110  !! if parameter `last` absent or bigger than the array size, get whole
4111  !! stack array.
4112  if (present(last)) then
4113  if ( last < hist_size ) then
4114  last_here = last
4115  else
4116  last_here = hist_size
4117  end if
4118  else
4119  last_here = hist_size
4120  end if
4121 
4122  !> Calculate the average excluding missing values (masked).
4123  mean_count=average(this%memory_pred( hist_size-last_here+1:hist_size ), &
4124  undef_ret_null=.true. )
4125 
4127 
4128  !-----------------------------------------------------------------------------
4129  !> Get the **average number** of predators per single time step within the
4130  !! perceptual memory stack, split to the first (older) and second(newer)
4131  !! parts. The whole memory stack ('sample') is split by the `split_val`
4132  !! parameter and two means are calculated: before the `split_val` and after
4133  !! it.
4134  !! @note There are several similar procedures with very similar
4135  !! implementation:
4136  !! - the_neurobio::percept_memory_food_mean_n_split() - get mean
4137  !! **number** of food items from the memory;
4138  !! - the_neurobio::percept_memory_food_mean_size_split() - get
4139  !! mean **size** of food items from the memory;
4140  !! - the_neurobio::percept_memory_predators_mean_split() - get
4141  !! average number of predators.
4142  !! .
4143  elemental subroutine percept_memory_predators_mean_split(this, window, &
4144  split_val, older, newer)
4145  class(memory_perceptual), intent(in) :: this
4146  !> @param[in] window is the whole memory window which is analysed, if
4147  !! not present, the whole memory stack is used.
4148  integer, optional, intent(in) :: window
4149  !> @param[in] split_val is the split value for the separation of the
4150  !! older and newer averages. If not present, just splits the
4151  !! memory window evenly in two halves.
4152  integer, optional, intent(in) :: split_val
4153  !> @param[out] older is the output average number of predators in the
4154  !! first (older) part of the memory window.
4155  real(srp), intent(out) :: older
4156  !> @param[out] newer is the output average number of predators in the
4157  !! second (newer) part of the memory window.
4158  real(srp), intent(out) :: newer
4159 
4160  ! Local copies of optionals.
4161  integer :: window_loc, split_val_loc
4162 
4163  integer, parameter :: hist_size = size(this%memory_pred)
4164 
4165  !> ### Implementation details ###
4166  !> First, check optional parameters: the memory window `window` and the
4167  !> split value `split_val`. If either is not provided, defaults are used.
4168  if (present(window)) then
4169  window_loc = window
4170  !> (Also, a check is made so that a window exceeding the history stack
4171  !! length is reduced accordingly to the whole memory size).
4172  if (window_loc >= hist_size) window_loc = hist_size
4173  else
4174  !> - whole size of the perceptual memory stack
4175  !! commondata::history_size_perception for the memory window
4176  window_loc = hist_size
4177  end if
4178 
4179  if (present(split_val)) then
4180  split_val_loc = split_val
4181  else
4182  !> - half of the memory window for the `split_val`.
4183  !! .
4184  split_val_loc = floor( real( window_loc, srp ) / 2.0 )
4185  end if
4186 
4187  !> A sanity check is also done, if the split value happen to exceed the
4188  !! `window` parameter, it is reduced to the default 1/2 of the `window`.
4189  if (split_val_loc >= window_loc) &
4190  split_val_loc = floor( real( window_loc, srp ) / 2.0 )
4191 
4192  !> Second, the `older` and the `newer` output average values are calculated.
4193  !! Here is the illustration of the calculation:
4194  !! @verbatim
4195  !! Such 'window' and 'split_val'
4196  !! values...
4197  !!
4198  !! |<----- window ----->|
4199  !! +--------+--------------------+
4200  !! + | :|: +
4201  !! +--------+--------------------+
4202  !! ^ split_val
4203  !!
4204  !!
4205  !! ... result in these means:
4206  !!
4207  !! +--------+---------------------+
4208  !! + | mean for | mean for +
4209  !! + | 'older' | 'newer' +
4210  !! +--------+---------------------+
4211  !! @endverbatim
4212  older=average( this%memory_pred(hist_size-window_loc+1 : &
4213  hist_size-window_loc+split_val_loc), &
4214  undef_ret_null=.true. )
4215 
4216  newer=average( this%memory_pred(hist_size-window_loc+split_val_loc+1 : &
4217  hist_size), &
4218  undef_ret_null=.true. )
4219 
4221 
4222  !-----------------------------------------------------------------------------
4223  !> Add the various perception objects to the memory stack object. This
4224  !! procedure is called **after** all the perceptual components (light, depth
4225  !! food, conspecifics, predators, etc.) are collected (using `set`
4226  !! object-bound subroutines) into the perception bundle, so all the values
4227  !! are known and ready to be used.
4228  elemental subroutine perception_objects_add_memory_stack(this)
4229  class(perception), intent(inout) :: this
4231  !> Now collect all perception variables into the whole memory stack object.
4232  call this%memory_stack%add_to_memory( &
4233  light = this%perceive_light%get_current(), &
4234  depth = this%perceive_depth%get_current(), &
4235  food = this%perceive_food%get_count(), &
4236  foodsize = this%perceive_food%get_meansize(), &
4237  fooddist = this%perceive_food%get_meandist(), &
4238  consp = this%perceive_consp%get_count(), &
4239  pred = this%perceive_predator%get_count(), &
4240  stom = this%perceive_stomach%get_available(), &
4241  bdmass = this%perceive_body_mass%get_current(), &
4242  energ = this%perceive_energy%get_current(), &
4243  reprfac= this%perceive_reprfac%get_current() &
4244  )
4245 
4247 
4248  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4249  ! Functions linked with PERCEPTION INITS
4250  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4251 
4252  !> A single umbrella subroutine to get all **environmental** perceptions:
4253  !! light, depth. This procedure invokes these calls:
4254  !! - the_neurobio::perception::feel_light()
4255  !! - the_neurobio::perception::feel_depth()
4256  !! .
4257  !! See also the_neurobio::perception::perceptions_inner().
4259  class(perception), intent(inout) :: this
4261  call this%feel_light()
4262  call this%feel_depth()
4263 
4265 
4266  !-----------------------------------------------------------------------------
4267  !> A single umbrella subroutine wrapper to get all **inner** perceptions:
4268  !! stomach, body mass, energy, age. Invokes all these procedures:
4269  !! - the_neurobio::perception::feel_stomach()
4270  !! - the_neurobio::perception::feel_bodymass()
4271  !! - the_neurobio::perception::feel_energy()
4272  !! - the_neurobio::perception::feel_age()
4273  !! - the_neurobio::perception::feel_repfac()
4274  !! .
4275  !! See also the_neurobio::perception::perceptions_environ().
4276  !!
4277  !! Splitting between the procedures for getting the inner and outer
4278  !! perceptions is for convenience only, this inner perceptions
4279  !! subroutine has no other parameters.
4280  !! @warning It would **not** be easy to implement such a wrapper for the
4281  !! **outer** perceptions because the population and various
4282  !! environmental objects are not yet available at this object level.
4283  !! @note **Templates for outer environmental perceptions**:
4284  !! `call proto_parents%individual(ind)%see_food( &
4285  !! food_resource_available = habitat_safe%food, &
4286  !! time_step_model = 1)`
4287  !!
4288  !! `call proto_parents%individual(ind)%see_consp( &
4289  !! consp_agents = proto_parents%individual, &
4290  !! time_step_model = 1 )`
4291  !!
4292  !! `call proto_parents%individual(ind)%see_pred( &
4293  !! spatl_agents = predators, &
4294  !! time_step_model = 1 )`
4295  !! `call proto_parents%individual(ind)%feel_light(timestep)`
4296  !! `call proto_parents%individual(ind)%feel_depth()`
4297  subroutine perception_objects_get_all_inner(this)
4298  class(perception), intent(inout) :: this
4300  call this%feel_stomach()
4301  call this%feel_bodymass()
4302  call this%feel_energy()
4303  call this%feel_age()
4304  call this%feel_repfac()
4305 
4306  end subroutine perception_objects_get_all_inner
4307 
4308  !-----------------------------------------------------------------------------
4309  !> Initialise all the perception objects for the current agent. Do not fill
4310  !! perception objects with the real data yet.
4311  elemental subroutine perception_objects_init_agent(this)
4312  class(perception), intent(inout) :: this
4314  !> Init all perception objects within the agent.
4315  call this%perceive_light%init()
4316  call this%perceive_depth%init()
4317  call this%perceive_food%init(0) ! food 0
4318  call this%perceive_consp%init(0) ! conspecifics 0
4319  call this%perceive_predator%init(0) ! predators 0
4320  call this%perceive_stomach%init()
4321  call this%perceive_body_mass%init()
4322  call this%perceive_energy%init()
4323  call this%perceive_age%init()
4324  call this%perceive_reprfac%init()
4325 
4326  !> Init and cleanup perceptual memory stack at start.
4327  call this%memory_stack%memory_cleanup()
4328 
4329  end subroutine perception_objects_init_agent
4330 
4331  !-----------------------------------------------------------------------------
4332  !> Destroy and deallocate all perception objects.
4333  elemental subroutine perception_objects_destroy(this, clean_memory)
4334  class(perception), intent(inout) :: this
4335  !> @param[in] clean_memory Logical flag to cleanup perceptual memory stack.
4336  logical, optional, intent(in) :: clean_memory
4337 
4338  !> Use the `destroy` method for all perception objects within the agent.
4339  call this%perceive_light%destroy()
4340  call this%perceive_depth%destroy()
4341  call this%perceive_food%destroy()
4342  call this%perceive_consp%destroy()
4343  call this%perceive_predator%destroy()
4344  call this%perceive_stomach%destroy()
4345  call this%perceive_body_mass%destroy()
4346  call this%perceive_energy%destroy()
4347  call this%perceive_age%destroy()
4348  call this%perceive_reprfac%destroy()
4349 
4350  !> Init and cleanup perceptual memory stack if clean_memory is set to TRUE.
4351  if (present(clean_memory)) then
4352  if (clean_memory) call this%memory_stack%memory_cleanup()
4353  end if
4354 
4355  end subroutine perception_objects_destroy
4356 
4357  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4358  ! Other functions linked with PERCEPTION sub-objects
4359  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4360 
4361  !-----------------------------------------------------------------------------
4362  !> Calculate the risk of **predation** as being **perceived / assessed**
4363  !! by this agent.
4364  !! @note It can be placed either to `PERCEPTION` (which might seem more
4365  !! logical as it is basically the *perception* of predation risk by
4366  !! the agent) or `APPRAISAL` level class. Here it is in the
4367  !! `APPRAISAL` because it is actually used here. It may also be safer
4368  !! here as we need completed perception objects and perception memory
4369  !! stack to assess the objective predation risk.
4370  elemental function perception_predation_risk_objective(this) &
4371  result(predation_risk)
4372  class(perception), intent(in) :: this !> @param[in] this Self.
4373  !> @returns assessment of the predation risk based on both the
4374  !! perception object and its linked perceptual memory component.
4375  real(srp) :: predation_risk
4376 
4377  !> ### Notable parameters ###
4378  !> **WEIGHT_DIRECT** is the relative weight given to the immediate
4379  !! perception of predators over the predators counts in the memory stack.
4380  !! Obtained from global parameters
4381  !! (`commondata::predation_risk_weight_immediate`).
4382  real(srp), parameter :: weight_direct = predation_risk_weight_immediate
4383 
4384  !> **MEM_WIND** is the size of the memory window when assessing the
4385  !! predator risk, only this number of the latest elements from the memory
4386  !! stack is taken into account. So we further weight the direct threat
4387  !! over the background risk when making the decision.
4388  !! @note Note that we take into account the whole memory size
4389  !! (commondata::history_size_perception).
4390  integer, parameter :: mem_wind = history_size_perception
4391 
4392  !> ### Implementation details ###
4393  !> Here we analyse the predator perception object and memory stack to get
4394  !! the **predation risk** perception value, that will be fed into the
4395  !! sigmoid function via `neuro_resp` at the next step.
4396  !! Perception of the predation risk is the weighted sum of the **total
4397  !! number of predators in the memory stack** and the **current count**
4398  !! of predators within the visual range of the agent. The actual
4399  !! calculatio is done by the comon backend that is used for objective and
4400  !! subjective assessment of risk: the_neurobio::predation_risk_backend().
4401  predation_risk = predation_risk_backend( &
4402  this%perceive_predator%get_count(), &
4403  this%memory_stack%get_pred_mean(mem_wind), &
4404  weight_direct )
4405 
4407 
4408  !-----------------------------------------------------------------------------
4409  !> Simple computational backend for the risk of predation that is used in
4410  !! objective risk function the_neurobio::perception_predation_risk_objective()
4411  !! and the subjective risk function.
4412  elemental function predation_risk_backend(pred_count, pred_memory_mean, &
4413  weight_direct) &
4414  result(risk)
4415  !> @param[in] pred_count The number of predators in the current perception
4416  !! object. This is an estimate of the direct risk of predation
4417  !! @f$ r_{d} @f$.
4418  integer, intent(in) :: pred_count
4419  !> @param[in] pred_memory_mean The mean number of predators in the memory
4420  !! window. The size of the memory window is not set here.
4421  !! It is an estimate of the indirect risk of predation
4422  !! @f$ r_{id} @f$.
4423  real(srp), intent(in) :: pred_memory_mean
4424  !> @param[in] weight_direct an optional weighting factor for the immediate
4425  !! risk (the number of predators in the current perception
4426  !! object), @f$ \omega @f$. If not provided, the default value
4427  !! is set by the commondata::predation_risk_weight_immediate
4428  !! parameter.
4429  real(srp), optional, intent(in) :: weight_direct
4430  real(srp) :: risk
4431 
4432  ! Local copies of optionals
4433  real(srp) :: weight_direct_loc
4434 
4435  !> ### Implementation details ###
4436  !> First, check if the optional direct risk weighting factor
4437  !! @f$ \omega @f$) is provided as a dummy parameter. If not provided,
4438  !! use the default value that is set by the
4439  !! commondata::predation_risk_weight_immediate parameter.
4440  if (present(weight_direct)) then
4441  weight_direct_loc = weight_direct
4442  else
4443  weight_direct_loc = predation_risk_weight_immediate
4444  end if
4445 
4446  !> Second, calculate the predation risk as a weighted sum of the direct
4447  !! risk (number of immediately perceived predators, @f$ r_{d} @f$) and
4448  !! indirect risk (average number of predators in the memory,
4449  !! @f$ r_{id} @f$):
4450  !! @f[ R = r_{d} \cdot \omega + r_{id} \cdot (1 - \omega) @f]
4451  risk = real(pred_count, srp) * weight_direct + &
4452  pred_memory_mean * (1.0_srp - weight_direct)
4453 
4454  end function predation_risk_backend
4455 
4456  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4457  ! Functions linked with NEUROBIOLOGICAL STATE sub-objects
4458  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4459 
4460  !-----------------------------------------------------------------------------
4461  !> Initialise the attention components of the emotional state to their
4462  !! default parameter values. Attention sets weights to individual perceptual
4463  !! components when the overall weighted sum is calculated. The default
4464  !! weights are parameters defined in `COMMONDATA`.
4465  !! @warning The number and nature of the attention components is equal
4466  !! to the number of perceptual components, they agree 1 to 1.
4467  !! @note The perception weights `weight_` parameters are not passed
4468  !! as an array to (a) allow for elemental function, (b) allow
4469  !! disabling attention components at init when weights are not
4470  !! provided = set to zero.
4471  !! @note The **precedence** order of the parameters `all_vals_fix`,
4472  !! `all_one` and then `weight_`s, i.e. if `all_vals_fix` is
4473  !! provided, all other are ignored (see `return` in if-present-test
4474  !! blocks).
4475  elemental subroutine perception_components_attention_weights_init( this, &
4476  all_vals_fix, &
4477  all_one, &
4478  weight_light, &
4479  weight_depth, &
4480  weight_food_dir, &
4481  weight_food_mem, &
4482  weight_conspec, &
4483  weight_pred_dir, &
4484  weight_predator, &
4485  weight_stomach, &
4486  weight_bodymass, &
4487  weight_energy, &
4488  weight_age, &
4489  weight_reprfac )
4490  class(percept_components_motiv), intent(inout) :: this
4491  !> @param[in] all_vals_fix Optional parameter setting all weights equal to
4492  !! a specific fixed value.
4493  real(srp), optional, intent(in) :: all_vals_fix
4494 
4495  !> @param[in] all_one Optional logical parameter setting all weights to 1.0,
4496  !! so the perceptual components go into unchanged form (weight=1)
4497  !! into the weighted sum (overall primary motivation value).
4498  logical, optional, intent(in) :: all_one
4499 
4500  !> Optional attention weights for specific perception components.
4501  !! @note If absent, set to **zero**.
4502  real(srp), optional, intent(in) :: &
4503  weight_light, weight_depth, &
4504  weight_food_dir, weight_food_mem, &
4505  weight_conspec, weight_pred_dir, weight_predator, &
4506  weight_stomach, weight_bodymass, &
4507  weight_energy, weight_age, &
4508  weight_reprfac
4509 
4510  !> Local copies of the optional parameters.
4511  real(srp) :: &
4512  here_weight_light, here_weight_depth, &
4513  here_weight_food_dir, here_weight_food_mem, &
4514  here_weight_conspec, here_weight_pred_dir, here_weight_predator, &
4515  here_weight_stomach, here_weight_bodymass, &
4516  here_weight_energy, here_weight_age, &
4517  here_weight_reprfac
4518 
4519  real(srp), parameter :: p1 = 1.0_srp !> **Unity weight** for unchanged vals.
4520  real(srp), parameter :: p0 = 0.0_srp !> **Zero weight** for unchanged vals.
4521 
4522  !> If `all_vals_fix` is set, set all weights to this fixed value.
4523  !! @note We do not have option to set all values to an **array**
4524  !! to be able to have this procedure **elemental**.
4525  if (present(all_vals_fix)) then
4526  this%light = all_vals_fix
4527  this%depth = all_vals_fix
4528  this%food_dir = all_vals_fix
4529  this%food_mem = all_vals_fix
4530  this%conspec = all_vals_fix
4531  this%pred_dir = all_vals_fix
4532  this%predator = all_vals_fix
4533  this%stomach = all_vals_fix
4534  this%bodymass = all_vals_fix
4535  this%energy = all_vals_fix
4536  this%age = all_vals_fix
4537  this%reprfac = all_vals_fix
4538  return !> Return after setting values.
4539  end if
4540 
4541  !> If `all_one` is present and set to TRUE, init all
4542  !! attention weights to 1.0
4543  if (present(all_one)) then
4544  if (all_one) then
4545  this%light = p1
4546  this%depth = p1
4547  this%food_dir = p1
4548  this%food_mem = p1
4549  this%conspec = p1
4550  this%pred_dir = p1
4551  this%predator = p1
4552  this%stomach = p1
4553  this%bodymass = p1
4554  this%energy = p1
4555  this%age = p1
4556  this%reprfac = p1
4557  return !> Return after setting values.
4558  end if
4559  end if
4560 
4561  ! - - - - - - - - - - - - - - - - - - - - - - - - -
4562  !> Set individual attention weights
4563  if ( present(weight_light) ) then
4564  here_weight_light = weight_light
4565  else
4566  here_weight_light = p0
4567  end if
4568 
4569  if ( present(weight_depth) ) then
4570  here_weight_depth = weight_depth
4571  else
4572  here_weight_depth = p0
4573  end if
4574 
4575  if ( present(weight_food_dir) ) then
4576  here_weight_food_dir = weight_food_dir
4577  else
4578  here_weight_food_dir = p0
4579  end if
4580 
4581  if ( present(weight_food_mem) ) then
4582  here_weight_food_mem = weight_food_mem
4583  else
4584  here_weight_food_mem = p0
4585  end if
4586 
4587  if ( present(weight_conspec) ) then
4588  here_weight_conspec = weight_conspec
4589  else
4590  here_weight_conspec = p0
4591  end if
4592 
4593  if ( present(weight_pred_dir) ) then
4594  here_weight_pred_dir = weight_pred_dir
4595  else
4596  here_weight_pred_dir = p0
4597  end if
4598 
4599  if ( present(weight_predator) ) then
4600  here_weight_predator = weight_predator
4601  else
4602  here_weight_predator = p0
4603  end if
4604 
4605  if ( present(weight_stomach) ) then
4606  here_weight_stomach = weight_stomach
4607  else
4608  here_weight_stomach = p0
4609  end if
4610 
4611  if ( present(weight_bodymass) ) then
4612  here_weight_bodymass = weight_bodymass
4613  else
4614  here_weight_bodymass = p0
4615  end if
4616 
4617  if ( present(weight_energy) ) then
4618  here_weight_energy = weight_energy
4619  else
4620  here_weight_energy = p0
4621  end if
4622 
4623  if ( present(weight_age) ) then
4624  here_weight_age = weight_age
4625  else
4626  here_weight_age = p0
4627  end if
4628 
4629  if ( present(weight_reprfac) ) then
4630  here_weight_reprfac = weight_reprfac
4631  else
4632  here_weight_reprfac = p0
4633  end if
4634  ! - - - - - - - - - - - - - - - - - - - - - - - - -
4635 
4636  !> If nothing is provided, set attention weights
4637  !! from the dummy parameters of this procedure.
4638  this%light = here_weight_light
4639  this%depth = here_weight_depth
4640  this%food_dir = here_weight_food_dir
4641  this%food_mem = here_weight_food_mem
4642  this%conspec = here_weight_conspec
4643  this%pred_dir = here_weight_pred_dir
4644  this%predator = here_weight_predator
4645  this%stomach = here_weight_stomach
4646  this%bodymass = here_weight_bodymass
4647  this%energy = here_weight_energy
4648  this%age = here_weight_age
4649  this%reprfac = here_weight_reprfac
4650 
4652 
4653  !-----------------------------------------------------------------------------
4654  !> Set and calculate individual perceptual components for **this**
4655  !! motivational state using the **neuronal response** function, for
4656  !! **this_agent**.
4657  !! @note The **this_agent** has intent [inout], so can be changed as a result
4658  !! of this procedure, gene labels are set for genes involved in the
4659  !! neuronal response.
4660  !! @note TODO: huge parameter list- ugly coding, try to fix.
4661  !! @note This procedure uses labelled if constructs with inline call of
4662  !! the neuronal response function `neuro_resp`, unlike this, the intent
4663  !! [in] procedure `perception_components_neuronal_response_calculate`
4664  !! uses inner subroutines.
4665  ! TODO: change the intent[in] removing inner subroutines? Or leave as is?
4667  this, this_agent, &
4668  ! Boolean G x P matrices:
4669  param_gp_matrix_light, &
4670  param_gp_matrix_depth, &
4671  param_gp_matrix_food_dir, &
4672  param_gp_matrix_food_mem, &
4673  param_gp_matrix_conspec, &
4674  param_gp_matrix_pred_dir, &
4675  param_gp_matrix_predator, &
4676  param_gp_matrix_stomach, &
4677  param_gp_matrix_bodymass, &
4678  param_gp_matrix_energy, &
4679  param_gp_matrix_age, &
4680  param_gp_matrix_reprfac, &
4681  ! G x P variances:
4682  param_gerror_cv_light, &
4683  param_gerror_cv_depth, &
4684  param_gerror_cv_food_dir, &
4685  param_gerror_cv_food_mem, &
4686  param_gerror_cv_conspec, &
4687  param_gerror_cv_pred_dir, &
4688  param_gerror_cv_predator, &
4689  param_gerror_cv_stomach, &
4690  param_gerror_cv_bodymass, &
4691  param_gerror_cv_energy, &
4692  param_gerror_cv_age, &
4693  param_gerror_cv_reprfac, &
4694  ! labels for genes:
4695  param_gene_label_light, &
4696  param_gene_label_depth, &
4697  param_gene_label_food_dir, &
4698  param_gene_label_food_mem, &
4699  param_gene_label_conspec, &
4700  param_gene_label_pred_dir, &
4701  param_gene_label_predator, &
4702  param_gene_label_stomach, &
4703  param_gene_label_bodymass, &
4704  param_gene_label_energy, &
4705  param_gene_label_age, &
4706  param_gene_label_reprfac )
4707 
4708  class(percept_components_motiv), intent(inout) :: this
4709  !> @param[inout] this_agent The actor agent.
4710  class(appraisal), intent(inout) :: this_agent
4711 
4712  !- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
4713  ! Pass boolean G x P parameter matrices from `COMMONDATA` :
4714 
4715  !> ### Boolean G x P matrices ###
4716  !> Input structure of the fixed parameters that define the boolean
4717  !! @ref aha_buildblocks_gp_matrix_intro "genotype x phenotype matrices"
4718  !! for each perceptual component of motivational state defined in
4719  !! @ref commondata.
4720  !! @warning There should be **exactly** as many `param_g_p_matrix`
4721  !! parameters as perceptual components for this motivation
4722  !! (`the_neurobio::percept_components_motiv`).
4723  !! @warning The dimensionality of the parameter arrays must be **exactly**
4724  !! the same as in @ref commondata. This is why **assumed shape
4725  !! arrays** (:,:) are **not used** here.
4726  !> @param[in] param_gp_matrix_light boolean *G* x *P* matrix for
4727  !! light;
4728  !! @param[in] param_gp_matrix_depth boolean *G* x *P* matrix for
4729  !! depth;
4730  !! @param[in] param_gp_matrix_food_dir boolean *G* x *P* matrix for
4731  !! direct food
4732  !! @param[in] param_gp_matrix_food_mem boolean *G* x *P* matrix for
4733  !! number of food items in memory;
4734  !! @param[in] param_gp_matrix_conspec boolean *G* x *P* matrix for
4735  !! number of conspecifics;
4736  !! @param[in] param_gp_matrix_pred_dir boolean *G* x *P* matrix for
4737  !! direct predation risk;
4738  !! @param[in] param_gp_matrix_predator boolean *G* x *P* matrix for
4739  !! number of predators;
4740  !! @param[in] param_gp_matrix_stomach boolean *G* x *P* matrix for
4741  !! stomach contents;
4742  !! @param[in] param_gp_matrix_bodymass boolean *G* x *P* matrix for
4743  !! body mass;
4744  !! @param[in] param_gp_matrix_energy boolean *G* x *P* matrix for
4745  !! energy reserves;
4746  !! @param[in] param_gp_matrix_age boolean *G* x *P* matrix for
4747  !! age;
4748  !! @param[in] param_gp_matrix_reprfac boolean *G* x *P* matrix for
4749  !! reproductive factor.
4750  logical, dimension(MAX_NALLELES,N_CHROMOSOMES), optional, intent(in) :: &
4751  param_gp_matrix_light, &
4752  param_gp_matrix_depth, &
4753  param_gp_matrix_food_dir, &
4754  param_gp_matrix_food_mem, &
4755  param_gp_matrix_conspec, &
4756  param_gp_matrix_pred_dir, &
4757  param_gp_matrix_predator, &
4758  param_gp_matrix_stomach, &
4759  param_gp_matrix_bodymass, &
4760  param_gp_matrix_energy, &
4761  param_gp_matrix_age, &
4762  param_gp_matrix_reprfac
4763 
4764  !- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
4765  ! Pass Gaussian error parameters from `COMMONDATA`:
4766 
4767  !> ### Coefficients of variation parameters ###
4768  !> Input structures that define the coefficient of variation for the
4769  !! Gaussian perception error parameters for each of the perceptual
4770  !! components. Normally they are also defined in @ref commondata.
4771  !! @param[in] param_gerror_cv_light coefficient of variation for
4772  !! light
4773  !! @param[in] param_gerror_cv_depth coefficient of variation for
4774  !! depth
4775  !! @param[in] param_gerror_cv_food_dir coefficient of variation for
4776  !! direct food;
4777  !! @param[in] param_gerror_cv_food_mem coefficient of variation for
4778  !! number of food items in memory;
4779  !! @param[in] param_gerror_cv_conspec coefficient of variation for
4780  !! number of conspecific;
4781  !! @param[in] param_gerror_cv_pred_dir coefficient of variation for
4782  !! direct predation risk;
4783  !! @param[in] param_gerror_cv_predator coefficient of variation for
4784  !! number of predators;
4785  !! @param[in] param_gerror_cv_stomach coefficient of variation for
4786  !! stomach contents;
4787  !! @param[in] param_gerror_cv_bodymass coefficient of variation for
4788  !! body mass;
4789  !! @param[in] param_gerror_cv_energy coefficient of variation for
4790  !! energy reserves;
4791  !! @param[in] param_gerror_cv_age coefficient of variation for
4792  !! age;
4793  !! @param[in] param_gerror_cv_reprfac coefficient of variation for
4794  !! reproductive factor.
4795  real(SRP), optional, intent(in) :: param_gerror_cv_light, &
4796  param_gerror_cv_depth, &
4797  param_gerror_cv_food_dir, &
4798  param_gerror_cv_food_mem, &
4799  param_gerror_cv_conspec, &
4800  param_gerror_cv_pred_dir, &
4801  param_gerror_cv_predator, &
4802  param_gerror_cv_stomach, &
4803  param_gerror_cv_bodymass, &
4804  param_gerror_cv_energy, &
4805  param_gerror_cv_age, &
4806  param_gerror_cv_reprfac
4807 
4808  !> ### Perception component labels ###
4809  !> Input parameters for the gene labels that code specific neuronal
4810  !! response genes.
4811  ! @note Do not need local copies of the label parameters as they are
4812  ! not present in the neuronal response function call.
4813  !> @param[in] param_gene_label_light label for light;
4814  !! @param[in] param_gene_label_depth label for depth;
4815  !! @param[in] param_gene_label_food_dir label for direct food;
4816  !! @param[in] param_gene_label_food_mem label for number of food items
4817  !! in memory;
4818  !! @param[in] param_gene_label_conspec label for number of conspecific;
4819  !! @param[in] param_gene_label_pred_dir label for direct predation risk;
4820  !! @param[in] param_gene_label_predator label for number of predators;
4821  !! @param[in] param_gene_label_stomach label for stomach contents;
4822  !! @param[in] param_gene_label_bodymass label for body mass;
4823  !! @param[in] param_gene_label_energy label for energy reserves;
4824  !! @param[in] param_gene_label_age label for age;
4825  !! @param[in] param_gene_label_reprfac label for reproductive factor;
4826  character(len=*), optional, intent(in) :: param_gene_label_light, &
4827  param_gene_label_depth, &
4828  param_gene_label_food_dir, &
4829  param_gene_label_food_mem, &
4830  param_gene_label_conspec, &
4831  param_gene_label_pred_dir, &
4832  param_gene_label_predator, &
4833  param_gene_label_stomach, &
4834  param_gene_label_bodymass, &
4835  param_gene_label_energy, &
4836  param_gene_label_age, &
4837  param_gene_label_reprfac
4838 
4839  !- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
4840  ! Local variables
4841 
4842  !> Local copies of **genotype x phenotype** boolean matrices.
4843  logical, dimension(MAX_NALLELES,N_CHROMOSOMES) :: &
4844  here_param_gp_matrix_light, &
4845  here_param_gp_matrix_depth, &
4846  here_param_gp_matrix_food_dir, &
4847  here_param_gp_matrix_food_mem, &
4848  here_param_gp_matrix_conspec, &
4849  here_param_gp_matrix_pred_dir, &
4850  here_param_gp_matrix_predator, &
4851  here_param_gp_matrix_stomach, &
4852  here_param_gp_matrix_bodymass, &
4853  here_param_gp_matrix_energy, &
4854  here_param_gp_matrix_age, &
4855  here_param_gp_matrix_reprfac
4856 
4857  !> Local copies of the Gaussian perception error coefficients of variation.
4858  real(SRP) :: here_param_gerror_cv_light, &
4859  here_param_gerror_cv_depth, &
4860  here_param_gerror_cv_food_dir, &
4861  here_param_gerror_cv_food_mem, &
4862  here_param_gerror_cv_conspec, &
4863  here_param_gerror_cv_pred_dir, &
4864  here_param_gerror_cv_predator, &
4865  here_param_gerror_cv_stomach, &
4866  here_param_gerror_cv_bodymass, &
4867  here_param_gerror_cv_energy, &
4868  here_param_gerror_cv_age, &
4869  here_param_gerror_cv_reprfac
4870 
4871  !- - - - - - - - - - - - - - - - - - -- - - - - - - - - - - - - - - - - - -
4872  !> ### Implementation notes ###
4873  !> We check input boolean G x P matrices and calculate the perceptual
4874  !! components of **this** motivation state only when the boolean matrix
4875  !! is provided as a parameter. Also check the corresponding variance/CV
4876  !! and reset to deterministic (variance zero) is not provided as a dummy
4877  !! parameter parameter.
4878  !! @warning There should be **exactly** as many `param_g_p_matrix` and
4879  !! `param_gerror_cv_light` parameters as perceptual components
4880  !! for this motivation (`the_neurobio::percept_components_motiv`).
4881  light: if (present(param_gp_matrix_light)) then
4882  here_param_gp_matrix_light = param_gp_matrix_light
4883  if (present(param_gerror_cv_light)) then
4884  here_param_gerror_cv_light = param_gerror_cv_light
4885  else
4886  here_param_gerror_cv_light = 0.0_srp
4887  end if
4888  !> - calculate the perceptual component for **light**.
4889  if (present(param_gene_label_light)) then
4890  !> @note The function is almost the same as in
4891  !! `the_neurobio::appraisal` but
4892  !! **does** set the label so `the_agent` has
4893  !! **intent[inout]**.
4894  call this_agent%neuro_resp( &
4895  this_trait = this%light, &
4896  g_p_matrix = here_param_gp_matrix_light, &
4897  init_val = this_agent%perceive_light%get_current(), &
4898  gerror_cv = here_param_gerror_cv_light, &
4899  label = param_gene_label_light )
4900  else
4901  ! @note The function is almost the same as in `APPRAISAL` but does
4902  ! **not** set the label so `the_agent` has the **intent[in]**.
4903  call this_agent%neuro_resp( &
4904  this_trait = this%light, &
4905  g_p_matrix = here_param_gp_matrix_light, &
4906  init_val = this_agent%perceive_light%get_current(), &
4907  gerror_cv = here_param_gerror_cv_light )
4908  end if
4909  end if light
4910 
4911  depth: if (present(param_gp_matrix_depth)) then
4912  here_param_gp_matrix_depth = param_gp_matrix_depth
4913  if (present(param_gerror_cv_depth)) then
4914  here_param_gerror_cv_depth = param_gerror_cv_depth
4915  else
4916  here_param_gerror_cv_depth = 0.0_srp
4917  end if
4918  !> - calculate the perceptual component for **depth**.
4919  if (present(param_gene_label_depth)) then
4920  ! @note The function is almost the same as in `APPRAISAL` but
4921  ! **does** set the label so `the_agent` has **intent[inout]**.
4922  call this_agent%neuro_resp( &
4923  this_trait = this%depth, &
4924  g_p_matrix = here_param_gp_matrix_depth, &
4925  init_val = this_agent%perceive_depth%get_current(), &
4926  gerror_cv = here_param_gerror_cv_depth, &
4927  label = param_gene_label_depth )
4928  else
4929  ! @note The function is almost the same as in `APPRAISAL` but does
4930  ! **not** set the label so `the_agent` has the **intent[in]**.
4931  call this_agent%neuro_resp( &
4932  this_trait = this%depth, &
4933  g_p_matrix = here_param_gp_matrix_depth, &
4934  init_val = this_agent%perceive_depth%get_current(), &
4935  gerror_cv = here_param_gerror_cv_depth )
4936  end if
4937  end if depth
4938 
4939  food_dir: if (present(param_gp_matrix_food_dir)) then
4940  here_param_gp_matrix_food_dir = param_gp_matrix_food_dir
4941  if (present(param_gerror_cv_food_dir)) then
4942  here_param_gerror_cv_food_dir = param_gerror_cv_food_dir
4943  else
4944  here_param_gerror_cv_food_dir = 0.0_srp
4945  end if
4946  !> - calculate the perceptual component for **food_dir**.
4947  if (present(param_gene_label_food_dir)) then
4948  ! @note The function is almost the same as in `APPRAISAL` but
4949  ! **does** set the label so `the_agent` has **intent[inout]**.
4950  call this_agent%neuro_resp( &
4951  this_trait = this%food_dir, &
4952  g_p_matrix = here_param_gp_matrix_food_dir, &
4953  init_val = real(this_agent%perceive_food%get_count(), srp), &
4954  gerror_cv = here_param_gerror_cv_food_dir, &
4955  label = param_gene_label_food_dir )
4956  else
4957  ! @note The function is almost the same as in `APPRAISAL` but does
4958  ! **not** set the label so `the_agent` has the **intent[in]**.
4959  call this_agent%neuro_resp( &
4960  this_trait = this%food_dir, &
4961  g_p_matrix = here_param_gp_matrix_food_dir, &
4962  init_val = real(this_agent%perceive_food%get_count(), srp), &
4963  gerror_cv = here_param_gerror_cv_food_dir )
4964  end if
4965  end if food_dir
4966 
4967  food_mem: if (present(param_gp_matrix_food_mem)) then
4968  here_param_gp_matrix_food_mem = param_gp_matrix_food_mem
4969  if (present(param_gerror_cv_food_mem)) then
4970  here_param_gerror_cv_food_mem = param_gerror_cv_food_mem
4971  else
4972  here_param_gerror_cv_food_mem = 0.0_srp
4973  end if
4974  !> - calculate the perceptual component for **food_mem**.
4975  if (present(param_gene_label_food_mem)) then
4976  ! @note The function is almost the same as in `APPRAISAL` but
4977  ! **does** set the label so `the_agent` has **intent[inout]**.
4978  call this_agent%neuro_resp( &
4979  this_trait = this%food_mem, &
4980  g_p_matrix = here_param_gp_matrix_food_mem, &
4981  init_val = this_agent%memory_stack%get_food_mean_n(), &
4982  gerror_cv = here_param_gerror_cv_food_mem, &
4983  label = param_gene_label_food_mem )
4984  else
4985  ! @note The function is almost the same as in `APPRAISAL` but does
4986  ! **not** set the label so `the_agent` has the **intent[in]**.
4987  call this_agent%neuro_resp( &
4988  this_trait = this%food_mem, &
4989  g_p_matrix = here_param_gp_matrix_food_mem, &
4990  init_val = this_agent%memory_stack%get_food_mean_n(), &
4991  gerror_cv = here_param_gerror_cv_food_mem )
4992  end if
4993  end if food_mem
4994 
4995  conspec: if (present(param_gp_matrix_conspec)) then
4996  here_param_gp_matrix_conspec = param_gp_matrix_conspec
4997  if (present(param_gerror_cv_conspec)) then
4998  here_param_gerror_cv_conspec = param_gerror_cv_conspec
4999  else
5000  here_param_gerror_cv_conspec = 0.0_srp
5001  end if
5002  !> - calculate the perceptual component for **conspec**.
5003  if (present(param_gene_label_conspec)) then
5004  ! @note The function is almost the same as in `APPRAISAL` but
5005  ! **does** set the label so `the_agent` has **intent[inout]**.
5006  call this_agent%neuro_resp( &
5007  this_trait = this%conspec, &
5008  g_p_matrix = here_param_gp_matrix_conspec, &
5009  init_val = real(this_agent%perceive_consp%get_count(), srp), &
5010  gerror_cv = here_param_gerror_cv_conspec, &
5011  label = param_gene_label_conspec )
5012  else
5013  ! @note The function is almost the same as in `APPRAISAL` but does
5014  ! **not** set the label so `the_agent` has the **intent[in]**.
5015  call this_agent%neuro_resp( &
5016  this_trait = this%conspec, &
5017  g_p_matrix = here_param_gp_matrix_conspec, &
5018  init_val = real(this_agent%perceive_consp%get_count(), srp), &
5019  gerror_cv = here_param_gerror_cv_conspec )
5020  end if
5021  end if conspec
5022 
5023  pred_dir: if (present(param_gp_matrix_pred_dir)) then
5024  here_param_gp_matrix_pred_dir = param_gp_matrix_pred_dir
5025  if (present(param_gerror_cv_pred_dir)) then
5026  here_param_gerror_cv_pred_dir = param_gerror_cv_pred_dir
5027  else
5028  here_param_gerror_cv_pred_dir = 0.0_srp
5029  end if
5030  !> - calculate the perceptual component for **direct predation**.
5031  if (present(param_gene_label_pred_dir)) then
5032  ! @note The function is almost the same as in `APPRAISAL` but
5033  ! **does** set the label so `the_agent` has **intent[inout]**.
5034  call this_agent%neuro_resp( &
5035  this_trait = this%pred_dir, &
5036  g_p_matrix = here_param_gp_matrix_pred_dir, &
5037  init_val = this_agent%risk_pred(), &
5038  gerror_cv = here_param_gerror_cv_pred_dir, &
5039  label = param_gene_label_pred_dir )
5040  else
5041  ! @note The function is almost the same as in `APPRAISAL` but does
5042  ! **not** set the label so `the_agent` has the **intent[in]**.
5043  call this_agent%neuro_resp( &
5044  this_trait = this%pred_dir, &
5045  g_p_matrix = here_param_gp_matrix_pred_dir, &
5046  init_val = this_agent%risk_pred(), &
5047  gerror_cv = here_param_gerror_cv_pred_dir )
5048  end if
5049  end if pred_dir
5050 
5051  predator: if (present(param_gp_matrix_predator)) then
5052  here_param_gp_matrix_predator = param_gp_matrix_predator
5053  if (present(param_gerror_cv_predator)) then
5054  here_param_gerror_cv_predator = param_gerror_cv_predator
5055  else
5056  here_param_gerror_cv_predator = 0.0_srp
5057  end if
5058  !> - calculate the perceptual component for **predator**.
5059  if (present(param_gene_label_predator)) then
5060  ! @note The function is almost the same as in `APPRAISAL` but
5061  ! **does** set the label so `the_agent` has **intent[inout]**.
5062  call this_agent%neuro_resp( &
5063  this_trait = this%predator, &
5064  g_p_matrix = here_param_gp_matrix_predator, &
5065  init_val = this_agent%predation_risk(), &
5066  gerror_cv = here_param_gerror_cv_predator, &
5067  label = param_gene_label_predator )
5068  else
5069  ! @note The function is almost the same as in `APPRAISAL` but does
5070  ! **not** set the label so `the_agent` has the **intent[in]**.
5071  call this_agent%neuro_resp( &
5072  this_trait = this%predator, &
5073  g_p_matrix = here_param_gp_matrix_predator, &
5074  init_val = this_agent%predation_risk(), &
5075  gerror_cv = here_param_gerror_cv_predator )
5076  end if
5077  end if predator
5078 
5079  stomach: if (present(param_gp_matrix_stomach)) then
5080  here_param_gp_matrix_stomach = param_gp_matrix_stomach
5081  if (present(param_gerror_cv_stomach)) then
5082  here_param_gerror_cv_stomach = param_gerror_cv_stomach
5083  else
5084  here_param_gerror_cv_stomach = 0.0_srp
5085  end if
5086  !> - calculate the perceptual component for **stomach**.
5087  if (present(param_gene_label_stomach)) then
5088  ! @note The function is almost the same as in `APPRAISAL` but
5089  ! **does** set the label so `the_agent` has **intent[inout]**.
5090  call this_agent%neuro_resp( &
5091  this_trait = this%stomach, &
5092  g_p_matrix = here_param_gp_matrix_stomach, &
5093  init_val = this_agent%perceive_stomach%get_available(), &
5094  gerror_cv = here_param_gerror_cv_stomach, &
5095  label = param_gene_label_stomach )
5096  else
5097  ! @note The function is almost the same as in `APPRAISAL` but does
5098  ! **not** set the label so `the_agent` has the **intent[in]**.
5099  call this_agent%neuro_resp( &
5100  this_trait = this%stomach, &
5101  g_p_matrix = here_param_gp_matrix_stomach, &
5102  init_val = this_agent%perceive_stomach%get_available(), &
5103  gerror_cv = here_param_gerror_cv_stomach )
5104  end if
5105  end if stomach
5106 
5107  bodymass: if (present(param_gp_matrix_bodymass)) then
5108  here_param_gp_matrix_bodymass = param_gp_matrix_bodymass
5109  if (present(param_gerror_cv_bodymass)) then
5110  here_param_gerror_cv_bodymass = param_gerror_cv_bodymass
5111  else
5112  here_param_gerror_cv_bodymass = 0.0_srp
5113  end if
5114  !> - calculate the perceptual component for **bodymass**.
5115  if (present(param_gene_label_bodymass)) then
5116  ! @note The function is almost the same as in `APPRAISAL` but
5117  ! **does** set the label so `the_agent` has **intent[inout]**.
5118  call this_agent%neuro_resp( &
5119  this_trait = this%bodymass, &
5120  g_p_matrix = here_param_gp_matrix_bodymass, &
5121  init_val = this_agent%perceive_body_mass%get_current(), &
5122  gerror_cv = here_param_gerror_cv_bodymass, &
5123  label = param_gene_label_bodymass )
5124  else
5125  ! @note The function is almost the same as in `APPRAISAL` but does
5126  ! **not** set the label so `the_agent` has the **intent[in]**.
5127  call this_agent%neuro_resp( &
5128  this_trait = this%bodymass, &
5129  g_p_matrix = here_param_gp_matrix_bodymass, &
5130  init_val = this_agent%perceive_body_mass%get_current(), &
5131  gerror_cv = here_param_gerror_cv_bodymass )
5132  end if
5133  end if bodymass
5134 
5135  energy: if (present(param_gp_matrix_energy)) then
5136  here_param_gp_matrix_energy = param_gp_matrix_energy
5137  if (present(param_gerror_cv_energy)) then
5138  here_param_gerror_cv_energy = param_gerror_cv_energy
5139  else
5140  here_param_gerror_cv_energy = 0.0_srp
5141  end if
5142  !> - calculate the perceptual component for **energy**.
5143  if (present(param_gene_label_energy)) then
5144  ! @note The function is almost the same as in `APPRAISAL` but
5145  ! **does** set the label so `the_agent` has **intent[inout]**.
5146  call this_agent%neuro_resp( &
5147  this_trait = this%energy, &
5148  g_p_matrix = here_param_gp_matrix_energy, &
5149  init_val = this_agent%perceive_energy%get_current(), &
5150  gerror_cv = here_param_gerror_cv_energy, &
5151  label = param_gene_label_energy )
5152  else
5153  ! @note The function is almost the same as in `APPRAISAL` but does
5154  ! **not** set the label so `the_agent` has the **intent[in]**.
5155  call this_agent%neuro_resp( &
5156  this_trait = this%energy, &
5157  g_p_matrix = here_param_gp_matrix_energy, &
5158  init_val = this_agent%perceive_energy%get_current(), &
5159  gerror_cv = here_param_gerror_cv_energy )
5160  end if
5161  end if energy
5162 
5163  age: if (present(param_gp_matrix_age)) then
5164  here_param_gp_matrix_age = param_gp_matrix_age
5165  if (present(param_gerror_cv_age)) then
5166  here_param_gerror_cv_age = param_gerror_cv_age
5167  else
5168  here_param_gerror_cv_age = 0.0_srp
5169  end if
5170  !> - calculate the perceptual component for **age**.
5171  if (present(param_gene_label_age)) then
5172  ! @note The function is almost the same as in `APPRAISAL` but
5173  ! **does** set the label so `the_agent` has **intent[inout]**.
5174  call this_agent%neuro_resp( &
5175  this_trait = this%age, &
5176  g_p_matrix = here_param_gp_matrix_age, &
5177  init_val = real(this_agent%perceive_age%get_current(), srp), &
5178  gerror_cv = here_param_gerror_cv_age, &
5179  label = param_gene_label_age )
5180  else
5181  ! @note The function is almost the same as in `APPRAISAL` but does
5182  ! **not** set the label so `the_agent` has the **intent[in]**.
5183  call this_agent%neuro_resp( &
5184  this_trait = this%age, &
5185  g_p_matrix = here_param_gp_matrix_age, &
5186  init_val = real(this_agent%perceive_age%get_current(), srp), &
5187  gerror_cv = here_param_gerror_cv_age )
5188  end if
5189  end if age
5190 
5191  reprfac: if (present(param_gp_matrix_reprfac)) then
5192  here_param_gp_matrix_reprfac = param_gp_matrix_reprfac
5193  if (present(param_gerror_cv_reprfac)) then
5194  here_param_gerror_cv_reprfac = param_gerror_cv_reprfac
5195  else
5196  here_param_gerror_cv_reprfac = 0.0_srp
5197  end if
5198  !> - calculate the perceptual component for **reproduct. factor**.
5199  if (present(param_gene_label_reprfac)) then
5200  ! @note The function is almost the same as in `APPRAISAL` but
5201  ! **does** set the label so `the_agent` has **intent[inout]**.
5202  call this_agent%neuro_resp( &
5203  this_trait = this%reprfac, &
5204  g_p_matrix = here_param_gp_matrix_reprfac, &
5205  init_val = this_agent%perceive_reprfac%get_current(), &
5206  gerror_cv = here_param_gerror_cv_reprfac, &
5207  label = param_gene_label_reprfac )
5208  else
5209  ! @note The function is almost the same as in `APPRAISAL` but does
5210  ! **not** set the label so `the_agent` has the **intent[in]**.
5211  call this_agent%neuro_resp( &
5212  this_trait = this%reprfac, &
5213  g_p_matrix = here_param_gp_matrix_reprfac, &
5214  init_val = this_agent%perceive_reprfac%get_current(), &
5215  gerror_cv = here_param_gerror_cv_reprfac )
5216  end if
5217  end if reprfac
5218 
5220 
5221  !-----------------------------------------------------------------------------
5222  !> Calculate individual perceptual components for **this** motivational
5223  !! state using the **neuronal response** function, for an **this_agent**.
5224  !! @note The **this_agent** has intent [in], so is unchanged as a result
5225  !! of this procedure. Unlike the above intent [inout] procedure,
5226  !! this accepts optional perception parameters that override those
5227  !! stored in `this_agent` data structure. This is done for calculating
5228  !! representation **expectancies** from possible behaviour.
5229  !!
5230  ! @note TODO: huge parameter list- ugly coding, try to fix.
5232  this, this_agent, &
5233  ! Boolean G x P matrices:
5234  param_gp_matrix_light, &
5235  param_gp_matrix_depth, &
5236  param_gp_matrix_food_dir, &
5237  param_gp_matrix_food_mem, &
5238  param_gp_matrix_conspec, &
5239  param_gp_matrix_pred_dir, &
5240  param_gp_matrix_predator, &
5241  param_gp_matrix_stomach, &
5242  param_gp_matrix_bodymass, &
5243  param_gp_matrix_energy, &
5244  param_gp_matrix_age, &
5245  param_gp_matrix_reprfac, &
5246  ! G x P variances:
5247  param_gerror_cv_light, &
5248  param_gerror_cv_depth, &
5249  param_gerror_cv_food_dir, &
5250  param_gerror_cv_food_mem, &
5251  param_gerror_cv_conspec, &
5252  param_gerror_cv_pred_dir, &
5253  param_gerror_cv_predator, &
5254  param_gerror_cv_stomach, &
5255  param_gerror_cv_bodymass, &
5256  param_gerror_cv_energy, &
5257  param_gerror_cv_age, &
5258  param_gerror_cv_reprfac, &
5259  ! Override raw perceptions
5260  perception_override_light, &
5261  perception_override_depth, &
5262  perception_override_food_dir, &
5263  perception_override_food_mem, &
5264  perception_override_conspec, &
5265  perception_override_pred_dir, &
5266  perception_override_predator, &
5267  perception_override_stomach, &
5268  perception_override_bodymass, &
5269  perception_override_energy, &
5270  perception_override_age, &
5271  perception_override_reprfac &
5272  )
5273 
5274  class(percept_components_motiv), intent(inout) :: this
5275  !> @param[inout] this_agent The actor agent.
5276  class(appraisal), intent(in) :: this_agent
5277 
5278  !- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
5279  ! Pass boolean G x P parameter matrices from `COMMONDATA` :
5280 
5281  !> ### Boolean G x P matrices ###
5282  !> Input structure of the fixed parameters that define the boolean
5283  !! @ref aha_buildblocks_gp_matrix_intro "genotype x phenotype matrices"
5284  !! for each perceptual component of motivational state defined in
5285  !! @ref commondata.
5286  !! @warning There should be **exactly** as many `param_g_p_matrix`
5287  !! parameters as perceptual components for this motivation
5288  !! (`the_neurobio::percept_components_motiv`).
5289  !! @warning The dimensionality of the parameter arrays must be **exactly**
5290  !! the same as in @ref commondata. This is why **assumed shape
5291  !! arrays** (:,:) are **not used** here.
5292  !> @param[in] param_gp_matrix_light boolean *G* x *P* matrix
5293  !! for light;
5294  !! @param[in] param_gp_matrix_depth boolean *G* x *P* matrix
5295  !! for depth;
5296  !! @param[in] param_gp_matrix_food_dir boolean *G* x *P* matrix
5297  !! for direct food;
5298  !! @param[in] param_gp_matrix_food_mem boolean *G* x *P* matrix
5299  !! for number of food items in memory;
5300  !! @param[in] param_gp_matrix_conspec boolean *G* x *P* matrix
5301  !! for number of conspecifics;
5302  !! @param[in] param_gp_matrix_pred_dir boolean *G* x *P* matrix
5303  !! for direct predation risk;
5304  !! @param[in] param_gp_matrix_predator boolean *G* x *P* matrix
5305  !! for number of predators;
5306  !! @param[in] param_gp_matrix_stomach boolean *G* x *P* matrix
5307  !! for stomach contents;
5308  !! @param[in] param_gp_matrix_bodymass boolean *G* x *P* matrix
5309  !! for body mass;
5310  !! @param[in] param_gp_matrix_energy boolean *G* x *P* matrix
5311  !! for energy reserves;
5312  !! @param[in] param_gp_matrix_age boolean *G* x *P* matrix
5313  !! for age;
5314  !! @param[in] param_gp_matrix_reprfac boolean *G* x *P* matrix
5315  !! for reproductive factor.
5316  logical, dimension(MAX_NALLELES,N_CHROMOSOMES), optional, intent(in) :: &
5317  param_gp_matrix_light, &
5318  param_gp_matrix_depth, &
5319  param_gp_matrix_food_dir, &
5320  param_gp_matrix_food_mem, &
5321  param_gp_matrix_conspec, &
5322  param_gp_matrix_pred_dir, &
5323  param_gp_matrix_predator, &
5324  param_gp_matrix_stomach, &
5325  param_gp_matrix_bodymass, &
5326  param_gp_matrix_energy, &
5327  param_gp_matrix_age, &
5328  param_gp_matrix_reprfac
5329 
5330  !- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
5331  ! Pass Gaussian error parameters from `COMMONDATA`:
5332 
5333  !> ### Coefficients of variation parameters ###
5334  !> Input structures that define the coefficient of variation for the
5335  !! Gaussian perception error parameters for each of the perceptual
5336  !! components. Normally they are also defined in @ref commondata.
5337  !> @param[in] param_gerror_cv_light coefficient of variation
5338  !! for light;
5339  !! @param[in] param_gerror_cv_depth coefficient of variation
5340  !! for depth;
5341  !! @param[in] param_gerror_cv_food_dir coefficient of variation
5342  !! for direct food;
5343  !! @param[in] param_gerror_cv_food_mem coefficient of variation
5344  !! for number of food items in memory;
5345  !! @param[in] param_gerror_cv_conspec coefficient of variation
5346  !! for number of conspecific;
5347  !! @param[in] param_gerror_cv_pred_dir coefficient of variation
5348  !! for direct predation risk;
5349  !! @param[in] param_gerror_cv_predator coefficient of variation
5350  !! for number of predators;
5351  !! @param[in] param_gerror_cv_stomach coefficient of variation
5352  !! for stomach contents;
5353  !! @param[in] param_gerror_cv_bodymass coefficient of variation
5354  !! for body mass;
5355  !! @param[in] param_gerror_cv_energy coefficient of variation
5356  !! for energy reserves;
5357  !! @param[in] param_gerror_cv_age coefficient of variation
5358  !! for age;
5359  !! @param[in] param_gerror_cv_reprfac coefficient of variation
5360  !! for reproductive factor.
5361  real(SRP), optional, intent(in) :: param_gerror_cv_light, &
5362  param_gerror_cv_depth, &
5363  param_gerror_cv_food_dir, &
5364  param_gerror_cv_food_mem, &
5365  param_gerror_cv_conspec, &
5366  param_gerror_cv_pred_dir, &
5367  param_gerror_cv_predator, &
5368  param_gerror_cv_stomach, &
5369  param_gerror_cv_bodymass, &
5370  param_gerror_cv_energy, &
5371  param_gerror_cv_age, &
5372  param_gerror_cv_reprfac
5373 
5374  !> ### Perception overrides (fake perceptions) ###
5375  !> @anchor percept_overrides_lst
5376  !> Optional parameters to override the perception value of `this_agent`
5377  !! that will be passed through the neuronal response function.
5378  !! We need to be able to pass arbitrary perception values to neuronal
5379  !! response to assess expectancies of different behaviours for this agent.
5380  !! @warning Note that the data types of the perception override values
5381  !! **must** agree with the `init_val` parameter of the neuronal
5382  !! response function, i.e. be **real**. But the perception
5383  !! object accessor (get) function of the respective perception
5384  !! object (`PERCEPT_`) sometimes have integer type. In such cases
5385  !! use inline real conversion function **when calling this**
5386  !! procedure.
5387  !> @param[in] perception_override_light perception override
5388  !! for light;
5389  !! @param[in] perception_override_depth perception override
5390  !! for depth;
5391  !! @param[in] perception_override_food_dir perception override
5392  !! for direct food (convert from integer);
5393  !! @param[in] perception_override_food_mem perception override
5394  !! for number of food items in memory;
5395  !! @param[in] perception_override_conspec perception override
5396  !! for number of conspecific (convert from integer);
5397  !! @param[in] perception_override_pred_dir perception override
5398  !! for direct predation risk;
5399  !! @param[in] perception_override_predator perception override
5400  !! for number of predators;
5401  !! @param[in] perception_override_stomach perception override
5402  !! for stomach contents;
5403  !! @param[in] perception_override_bodymass perception override
5404  !! for body mass;
5405  !! @param[in] perception_override_energy perception override
5406  !! for energy reserves;
5407  !! @param[in] perception_override_age perception override
5408  !! for age (convert from integer);
5409  !! @param[in] perception_override_reprfac perception override
5410  !! for reproductive factor.
5411  real(SRP), optional, intent(in) :: perception_override_light, &
5412  perception_override_depth, &
5413  perception_override_food_dir, & ! integer
5414  perception_override_food_mem, &
5415  perception_override_conspec, & ! integer
5416  perception_override_pred_dir, &
5417  perception_override_predator, &
5418  perception_override_stomach, &
5419  perception_override_bodymass, &
5420  perception_override_energy, &
5421  perception_override_age, & ! integer
5422  perception_override_reprfac
5423 
5424  !- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
5425  ! Local variables
5426 
5427  ! Local copies of **genotype x phenotype** boolean matrices.
5428  logical, dimension(MAX_NALLELES,N_CHROMOSOMES) :: &
5429  here_param_gp_matrix_light, &
5430  here_param_gp_matrix_depth, &
5431  here_param_gp_matrix_food_dir, &
5432  here_param_gp_matrix_food_mem, &
5433  here_param_gp_matrix_conspec, &
5434  here_param_gp_matrix_pred_dir, &
5435  here_param_gp_matrix_predator, &
5436  here_param_gp_matrix_stomach, &
5437  here_param_gp_matrix_bodymass, &
5438  here_param_gp_matrix_energy, &
5439  here_param_gp_matrix_age, &
5440  here_param_gp_matrix_reprfac
5441 
5442  ! Local copies of the Gaussian perception error coefficients of variation.
5443  real(SRP) :: here_param_gerror_cv_light, &
5444  here_param_gerror_cv_depth, &
5445  here_param_gerror_cv_food_dir, &
5446  here_param_gerror_cv_food_mem, &
5447  here_param_gerror_cv_conspec, &
5448  here_param_gerror_cv_pred_dir, &
5449  here_param_gerror_cv_predator, &
5450  here_param_gerror_cv_stomach, &
5451  here_param_gerror_cv_bodymass, &
5452  here_param_gerror_cv_energy, &
5453  here_param_gerror_cv_age, &
5454  here_param_gerror_cv_reprfac
5455 
5456  !- - - - - - - - - - - - - - - - - - -- - - - - - - - - - - - - - - - - - -
5457  !> ### Implementation notes ###
5458  !> We check input boolean G x P matrices and calculate the perceptual
5459  !! components of **this** motivation state only when the boolean matrix
5460  !! is provided as a parameter. Also check the corresponding variance/CV
5461  !! and reset to deterministic (variance zero) is not provided as a dummy
5462  !! parameter parameter.
5463  !! @warning There should be **exactly** as many `param_g_p_matrix_` and
5464  !! `param_gerror_cv_` parameters as perceptual components
5465  !! for this motivation (the_neurobio::percept_components_motiv).
5466  light: if (present(param_gp_matrix_light)) then
5467  here_param_gp_matrix_light = param_gp_matrix_light
5468  if (present(param_gerror_cv_light)) then
5469  here_param_gerror_cv_light = param_gerror_cv_light
5470  else
5471  here_param_gerror_cv_light = 0.0_srp
5472  end if
5473  !> - calculate the perceptual component for **light**.
5474  if (present(perception_override_light)) then
5475  call this_agent%neuro_resp( &
5476  this_trait = this%light, &
5477  g_p_matrix = here_param_gp_matrix_light, &
5478  init_val = perception_override_light, &
5479  gerror_cv = here_param_gerror_cv_light )
5480  else
5481  call this_agent%neuro_resp( &
5482  this_trait = this%light, &
5483  g_p_matrix = here_param_gp_matrix_light, &
5484  init_val = this_agent%perceive_light%get_current(), &
5485  gerror_cv = here_param_gerror_cv_light )
5486  end if
5487  end if light
5488 
5489  depth: if (present(param_gp_matrix_depth)) then
5490  here_param_gp_matrix_depth = param_gp_matrix_depth
5491  if (present(param_gerror_cv_depth)) then
5492  here_param_gerror_cv_depth = param_gerror_cv_depth
5493  else
5494  here_param_gerror_cv_depth = 0.0_srp
5495  end if
5496  !> - calculate the perceptual component for **depth**.
5497  if (present(perception_override_depth)) then
5498  call this_agent%neuro_resp( &
5499  this_trait = this%depth, &
5500  g_p_matrix = here_param_gp_matrix_depth, &
5501  init_val = perception_override_depth, &
5502  gerror_cv = here_param_gerror_cv_depth )
5503  else
5504  call this_agent%neuro_resp( &
5505  this_trait = this%depth, &
5506  g_p_matrix = here_param_gp_matrix_depth, &
5507  init_val = this_agent%perceive_depth%get_current(), &
5508  gerror_cv = here_param_gerror_cv_depth )
5509 
5510  end if
5511  end if depth
5512 
5513  food_dir: if (present(param_gp_matrix_food_dir)) then
5514  here_param_gp_matrix_food_dir = param_gp_matrix_food_dir
5515  if (present(param_gerror_cv_food_dir)) then
5516  here_param_gerror_cv_food_dir = param_gerror_cv_food_dir
5517  else
5518  here_param_gerror_cv_food_dir = 0.0_srp
5519  end if
5520  !> - calculate the perceptual component for **food_dir**.
5521  if (present(perception_override_food_dir)) then
5522  call this_agent%neuro_resp( &
5523  this_trait = this%food_dir, &
5524  g_p_matrix = here_param_gp_matrix_food_dir, &
5525  init_val = perception_override_food_dir, &
5526  gerror_cv = here_param_gerror_cv_food_dir )
5527  else
5528  call this_agent%neuro_resp( &
5529  this_trait = this%food_dir, &
5530  g_p_matrix = here_param_gp_matrix_food_dir, &
5531  init_val = real(this_agent%perceive_food%get_count(), srp), &
5532  gerror_cv = here_param_gerror_cv_food_dir )
5533  end if
5534  end if food_dir
5535 
5536  food_mem: if (present(param_gp_matrix_food_mem)) then
5537  here_param_gp_matrix_food_mem = param_gp_matrix_food_mem
5538  if (present(param_gerror_cv_food_mem)) then
5539  here_param_gerror_cv_food_mem = param_gerror_cv_food_mem
5540  else
5541  here_param_gerror_cv_food_mem = 0.0_srp
5542  end if
5543  !> - calculate the perceptual component for **food_mem**.
5544  if (present(perception_override_food_mem)) then
5545  call this_agent%neuro_resp( &
5546  this_trait = this%food_mem, &
5547  g_p_matrix = here_param_gp_matrix_food_mem, &
5548  init_val = perception_override_food_mem, &
5549  gerror_cv = here_param_gerror_cv_food_mem )
5550  else
5551  call this_agent%neuro_resp( &
5552  this_trait = this%food_mem, &
5553  g_p_matrix = here_param_gp_matrix_food_mem, &
5554  init_val = this_agent%memory_stack%get_food_mean_n(), &
5555  gerror_cv = here_param_gerror_cv_food_mem )
5556  end if
5557  end if food_mem
5558 
5559  conspec: if (present(param_gp_matrix_conspec)) then
5560  here_param_gp_matrix_conspec = param_gp_matrix_conspec
5561  if (present(param_gerror_cv_conspec)) then
5562  here_param_gerror_cv_conspec = param_gerror_cv_conspec
5563  else
5564  here_param_gerror_cv_conspec = 0.0_srp
5565  end if
5566  !> - calculate the perceptual component for **conspec**.
5567  if (present(perception_override_conspec)) then
5568  call this_agent%neuro_resp( &
5569  this_trait = this%conspec, &
5570  g_p_matrix = here_param_gp_matrix_conspec, &
5571  init_val = perception_override_conspec, &
5572  gerror_cv = here_param_gerror_cv_conspec )
5573  else
5574  call this_agent%neuro_resp( &
5575  this_trait = this%conspec, &
5576  g_p_matrix = here_param_gp_matrix_conspec, &
5577  init_val = real(this_agent%perceive_consp%get_count(), srp),&
5578  gerror_cv = here_param_gerror_cv_conspec )
5579 
5580  end if
5581  end if conspec
5582 
5583  pred_dir: if (present(param_gp_matrix_pred_dir)) then
5584  here_param_gp_matrix_pred_dir = param_gp_matrix_pred_dir
5585  if (present(param_gerror_cv_pred_dir)) then
5586  here_param_gerror_cv_pred_dir = param_gerror_cv_pred_dir
5587  else
5588  here_param_gerror_cv_pred_dir = 0.0_srp
5589  end if
5590  !> - calculate the perceptual component for **direct predation**.
5591  if (present(perception_override_pred_dir)) then
5592  call this_agent%neuro_resp( &
5593  this_trait = this%pred_dir, &
5594  g_p_matrix = here_param_gp_matrix_pred_dir, &
5595  init_val = perception_override_pred_dir, &
5596  gerror_cv = here_param_gerror_cv_pred_dir )
5597  else
5598  call this_agent%neuro_resp( &
5599  this_trait = this%pred_dir, &
5600  g_p_matrix = here_param_gp_matrix_pred_dir, &
5601  init_val = this_agent%risk_pred(), &
5602  gerror_cv = here_param_gerror_cv_pred_dir )
5603  end if
5604  end if pred_dir
5605 
5606  predator: if (present(param_gp_matrix_predator)) then
5607  here_param_gp_matrix_predator = param_gp_matrix_predator
5608  if (present(param_gerror_cv_predator)) then
5609  here_param_gerror_cv_predator = param_gerror_cv_predator
5610  else
5611  here_param_gerror_cv_predator = 0.0_srp
5612  end if
5613  !> - calculate the perceptual component for **predator**.
5614  if (present(perception_override_predator)) then
5615  call this_agent%neuro_resp( &
5616  this_trait = this%predator, &
5617  g_p_matrix = here_param_gp_matrix_predator, &
5618  init_val = perception_override_predator, &
5619  gerror_cv = here_param_gerror_cv_predator )
5620  else
5621  call this_agent%neuro_resp( &
5622  this_trait = this%predator, &
5623  g_p_matrix = here_param_gp_matrix_predator, &
5624  init_val = this_agent%predation_risk(), &
5625  gerror_cv = here_param_gerror_cv_predator )
5626  end if
5627  end if predator
5628 
5629  stomach: if (present(param_gp_matrix_stomach)) then
5630  here_param_gp_matrix_stomach = param_gp_matrix_stomach
5631  if (present(param_gerror_cv_stomach)) then
5632  here_param_gerror_cv_stomach = param_gerror_cv_stomach
5633  else
5634  here_param_gerror_cv_stomach = 0.0_srp
5635  end if
5636  !> - calculate the perceptual component for **stomach**.
5637  if (present(perception_override_stomach)) then
5638  call this_agent%neuro_resp( &
5639  this_trait = this%stomach, &
5640  g_p_matrix = here_param_gp_matrix_stomach, &
5641  init_val = perception_override_stomach, &
5642  gerror_cv = here_param_gerror_cv_stomach )
5643  else
5644  call this_agent%neuro_resp( &
5645  this_trait = this%stomach, &
5646  g_p_matrix = here_param_gp_matrix_stomach, &
5647  init_val = this_agent%perceive_stomach%get_available(), &
5648  gerror_cv = here_param_gerror_cv_stomach )
5649  end if
5650  end if stomach
5651 
5652  bodymass: if (present(param_gp_matrix_bodymass)) then
5653  here_param_gp_matrix_bodymass = param_gp_matrix_bodymass
5654  if (present(param_gerror_cv_bodymass)) then
5655  here_param_gerror_cv_bodymass = param_gerror_cv_bodymass
5656  else
5657  here_param_gerror_cv_bodymass = 0.0_srp
5658  end if
5659  !> - calculate the perceptual component for **bodymass**.
5660  if (present(perception_override_bodymass)) then
5661  call this_agent%neuro_resp( &
5662  this_trait = this%bodymass, &
5663  g_p_matrix = here_param_gp_matrix_bodymass, &
5664  init_val = perception_override_bodymass, &
5665  gerror_cv = here_param_gerror_cv_bodymass )
5666  else
5667  call this_agent%neuro_resp( &
5668  this_trait = this%bodymass, &
5669  g_p_matrix = here_param_gp_matrix_bodymass, &
5670  init_val = this_agent%perceive_body_mass%get_current(), &
5671  gerror_cv = here_param_gerror_cv_bodymass )
5672  end if
5673  end if bodymass
5674 
5675  energy: if (present(param_gp_matrix_energy)) then
5676  here_param_gp_matrix_energy = param_gp_matrix_energy
5677  if (present(param_gerror_cv_energy)) then
5678  here_param_gerror_cv_energy = param_gerror_cv_energy
5679  else
5680  here_param_gerror_cv_energy = 0.0_srp
5681  end if
5682  !> - calculate the perceptual component for **energy**.
5683  if (present(perception_override_energy)) then
5684  call this_agent%neuro_resp( &
5685  this_trait = this%energy, &
5686  g_p_matrix = here_param_gp_matrix_energy, &
5687  init_val = perception_override_energy, &
5688  gerror_cv = here_param_gerror_cv_energy )
5689  else
5690  call this_agent%neuro_resp( &
5691  this_trait = this%energy, &
5692  g_p_matrix = here_param_gp_matrix_energy, &
5693  init_val = this_agent%perceive_energy%get_current(), &
5694  gerror_cv = here_param_gerror_cv_energy )
5695  end if
5696  end if energy
5697 
5698  age: if (present(param_gp_matrix_age)) then
5699  here_param_gp_matrix_age = param_gp_matrix_age
5700  if (present(param_gerror_cv_age)) then
5701  here_param_gerror_cv_age = param_gerror_cv_age
5702  else
5703  here_param_gerror_cv_age = 0.0_srp
5704  end if
5705  !> - calculate the perceptual component for **age**.
5706  if (present(perception_override_age)) then
5707  call this_agent%neuro_resp( &
5708  this_trait = this%age, &
5709  g_p_matrix = here_param_gp_matrix_age, &
5710  init_val = perception_override_age, &
5711  gerror_cv = here_param_gerror_cv_age )
5712  else
5713  call this_agent%neuro_resp( &
5714  this_trait = this%age, &
5715  g_p_matrix = here_param_gp_matrix_age, &
5716  init_val = real(this_agent%perceive_age%get_current(), srp),&
5717  gerror_cv = here_param_gerror_cv_age )
5718  end if
5719  end if age
5720 
5721  reprfac: if (present(param_gp_matrix_reprfac)) then
5722  here_param_gp_matrix_reprfac = param_gp_matrix_reprfac
5723  if (present(param_gerror_cv_reprfac)) then
5724  here_param_gerror_cv_reprfac = param_gerror_cv_reprfac
5725  else
5726  here_param_gerror_cv_reprfac = 0.0_srp
5727  end if
5728  !> - calculate the perceptual component for **reproductive factor**.
5729  !! .
5730  if (present(perception_override_reprfac)) then
5731  call this_agent%neuro_resp( &
5732  this_trait = this%reprfac, &
5733  g_p_matrix = here_param_gp_matrix_reprfac, &
5734  init_val = perception_override_reprfac, &
5735  gerror_cv = here_param_gerror_cv_reprfac )
5736  else
5737  call this_agent%neuro_resp( &
5738  this_trait = this%reprfac, &
5739  g_p_matrix = here_param_gp_matrix_reprfac, &
5740  init_val = this_agent%perceive_reprfac%get_current(), &
5741  gerror_cv = here_param_gerror_cv_reprfac )
5742  end if
5743  end if reprfac
5744 
5745 
5747 
5748  !-----------------------------------------------------------------------------
5749  !> Standard "get" function for the state neuronal **light** effect
5750  !! component.
5751  elemental function state_motivation_light_get(this) result (value_get)
5752  class(state_motivation_base), intent(in) :: this
5753  !> @returns function value: light
5754  real(srp) :: value_get
5755 
5756  value_get = this%percept_component%light
5757 
5758  end function state_motivation_light_get
5759 
5760  !-----------------------------------------------------------------------------
5761  !> Standard "get" function for the state neuronal **depth** effect
5762  !! component.
5763  elemental function state_motivation_depth_get(this) result (value_get)
5764  class(state_motivation_base), intent(in) :: this
5765  !> @returns function value: depth
5766  real(srp) :: value_get
5767 
5768  value_get = this%percept_component%depth
5769 
5770  end function state_motivation_depth_get
5771 
5772  !-----------------------------------------------------------------------------
5773  !> Standard "get" function for the state neuronal **directly seen
5774  !! food** effect component.
5775  elemental function state_motivation_food_dir_get(this) result (value_get)
5776  class(state_motivation_base), intent(in) :: this
5777  !> @returns function value: food
5778  real(srp) :: value_get
5779 
5780  value_get = this%percept_component%food_dir
5781 
5782  end function state_motivation_food_dir_get
5783 
5784  !-----------------------------------------------------------------------------
5785  !> Standard "get" function for the state neuronal **food items from
5786  !! past memory** effect component.
5787  elemental function state_motivation_food_mem_get(this) result (value_get)
5788  class(state_motivation_base), intent(in) :: this
5789  !> @returns function value: food
5790  real(srp) :: value_get
5791 
5792  value_get = this%percept_component%food_mem
5793 
5794  end function state_motivation_food_mem_get
5795 
5796  !-----------------------------------------------------------------------------
5797  !> Standard "get" function for the state neuronal **conspecifics**
5798  !! effect component.
5799  elemental function state_motivation_conspec_get(this) result (value_get)
5800  class(state_motivation_base), intent(in) :: this
5801  !> @returns function value: conspecifics
5802  real(srp) :: value_get
5803 
5804  value_get = this%percept_component%conspec
5805 
5806  end function state_motivation_conspec_get
5807 
5808  !-----------------------------------------------------------------------------
5809  !> Standard "get" function for the state neuronal **direct predation**
5810  !! effect component.
5811  elemental function state_motivation_pred_dir_get(this) result (value_get)
5812  class(state_motivation_base), intent(in) :: this
5813  !> @returns function value: predators
5814  real(srp) :: value_get
5815 
5816  value_get = this%percept_component%pred_dir
5817 
5818  end function state_motivation_pred_dir_get
5819 
5820  !-----------------------------------------------------------------------------
5821  !> Standard "get" function for the state neuronal **predators**
5822  !! effect component.
5823  elemental function state_motivation_predator_get(this) result (value_get)
5824  class(state_motivation_base), intent(in) :: this
5825  !> @returns function value: predators
5826  real(srp) :: value_get
5827 
5828  value_get = this%percept_component%predator
5829 
5830  end function state_motivation_predator_get
5831 
5832  !-----------------------------------------------------------------------------
5833  !> Standard "get" function for the state neuronal **stomach**
5834  !! effect component.
5835  elemental function state_motivation_stomach_get(this) result (value_get)
5836  class(state_motivation_base), intent(in) :: this
5837  !> @returns function value: stomach
5838  real(srp) :: value_get
5839 
5840  value_get = this%percept_component%stomach
5841 
5842  end function state_motivation_stomach_get
5843 
5844  !-----------------------------------------------------------------------------
5845  !> Standard "get" function for the state neuronal **body mass**
5846  !! effect component.
5847  elemental function state_motivation_bodymass_get(this) result (value_get)
5848  class(state_motivation_base), intent(in) :: this
5849  !> @returns function value: body mass
5850  real(srp) :: value_get
5851 
5852  value_get = this%percept_component%bodymass
5853 
5854  end function state_motivation_bodymass_get
5855 
5856  !-----------------------------------------------------------------------------
5857  !> Standard "get" function for the state neuronal **energy reserves**
5858  !! effect component.
5859  elemental function state_motivation_energy_get(this) result (value_get)
5860  class(state_motivation_base), intent(in) :: this
5861  !> @returns function value: energy reserves
5862  real(srp) :: value_get
5863 
5864  value_get = this%percept_component%energy
5865 
5866  end function state_motivation_energy_get
5867 
5868  !-----------------------------------------------------------------------------
5869  !> Standard "get" function for the state neuronal **age**
5870  !! effect component.
5871  elemental function state_motivation_age_get(this) result (value_get)
5872  class(state_motivation_base), intent(in) :: this
5873  !> @returns function value: age
5874  real(srp) :: value_get
5875 
5876  value_get = this%percept_component%age
5877 
5878  end function state_motivation_age_get
5879 
5880  !-----------------------------------------------------------------------------
5881  !> Standard "get" function for the state neuronal **reproductive factor**
5882  !! effect component.
5883  elemental function state_motivation_reprfac_get(this) result (value_get)
5884  class(state_motivation_base), intent(in) :: this
5885  !> @returns function value: age
5886  real(srp) :: value_get
5887 
5888  value_get = this%percept_component%reprfac
5889 
5890  end function state_motivation_reprfac_get
5891 
5892  !-----------------------------------------------------------------------------
5893  !> Standard "get" function for the root state, get the overall
5894  !! **primary motivation value** (before modulation).
5895  elemental function state_motivation_motivation_prim_get(this) result (value_get)
5896  class(state_motivation_base), intent(in) :: this
5897  !> @returns function value: age
5898  real(srp) :: value_get
5899 
5900  value_get = this%motivation_prim
5901 
5903 
5904  !-----------------------------------------------------------------------------
5905  !> Standard "get" function for the root state, get the overall
5906  !! **final motivation value** (after modulation).
5907  elemental function state_motivation_motivation_get(this) result (value_get)
5908  class(state_motivation_base), intent(in) :: this
5909  !> @returns function value: age
5910  real(srp) :: value_get
5911 
5912  value_get = this%motivation_finl
5913 
5914  end function state_motivation_motivation_get
5915 
5916  !-----------------------------------------------------------------------------
5917  !> Check if the root state is the dominant state in GOS.
5918  elemental function state_motivation_is_dominant_get(this) result (gos_dominant)
5919  class(state_motivation_base), intent(in) :: this
5921  !> @returns TRUE if this motivational state is **dominant** in the GOS,
5922  !! and FALSE otherwise.
5923  logical :: gos_dominant
5924 
5925  gos_dominant = this%dominant_state
5926 
5928 
5929  !-----------------------------------------------------------------------------
5930  !> Get the fixed label for this motivational state. Note that the label
5931  !! is fixed and cannot be changed.
5932  elemental function state_motivation_fixed_label_get(this) result (label_get)
5933  class(state_motivation_base), intent(in) :: this
5935  !> @returns Returns the fixed label for this motivation state.
5936  character(len=LABEL_LENGTH) :: label_get
5937 
5938  label_get = this%label
5939 
5941 
5942  !-----------------------------------------------------------------------------
5943  !> Transfer attention weights between two motivation state components.
5944  !! The main use of this subroutine would be to transfer attention from the
5945  !! actor agent's main motivation's attention component to the behaviour's GOS
5946  !! expectancy object.
5947  !! @note Note that the procedure `behaviour_root_attention_weights_transfer`
5948  !! which does this is not using this procedure and transfers objects
5949  !! directly.
5950  pure subroutine state_motivation_attention_weights_transfer (this, copy_from)
5951  class(state_motivation_base), intent(inout) :: this
5952  class(state_motivation_base), intent(in) :: copy_from
5953 
5954  associate( to_this => this%attention_weight, &
5955  from_this => copy_from%attention_weight )
5956  to_this%light = from_this%light
5957  to_this%depth = from_this%depth
5958  to_this%food_dir = from_this%food_dir
5959  to_this%food_mem = from_this%food_mem
5960  to_this%conspec = from_this%conspec
5961  to_this%pred_dir = from_this%pred_dir
5962  to_this%predator = from_this%predator
5963  to_this%stomach = from_this%stomach
5964  to_this%bodymass = from_this%bodymass
5965  to_this%energy = from_this%energy
5966  to_this%age = from_this%age
5967  to_this%reprfac = from_this%reprfac
5968  end associate
5969 
5971 
5972  !-----------------------------------------------------------------------------
5973  !> Calculate the **maximum** value over all the perceptual components.
5974  elemental function perception_component_maxval(this) result (maxvalue)
5975  class(percept_components_motiv), intent(in) :: this
5977  !> @return the maximum value among all the perceptual components.
5978  real(srp) :: maxvalue
5979 
5980  maxvalue = maxval( [ &
5981  this%light, &
5982  this%depth, &
5983  this%food_dir, &
5984  this%food_mem, &
5985  this%conspec, &
5986  this%pred_dir, &
5987  this%predator, &
5988  this%stomach, &
5989  this%bodymass, &
5990  this%energy, &
5991  this%age, &
5992  this%reprfac ] )
5993 
5994  end function perception_component_maxval
5995 
5996  !-----------------------------------------------------------------------------
5997  !> Calculate the **maximum** value over all the perceptual components of
5998  !! this motivational state component.
5999  !! @note Used in `motivation_primary_calc` procedure.
6000  elemental function state_motivation_percept_maxval(this) result (maxvalue)
6001  class(state_motivation_base), intent(in) :: this
6003  !> @return the maximum value among all the perceptual components.
6004  real(srp) :: maxvalue
6005 
6006  maxvalue = this%percept_component%max_value()
6007 
6008  end function state_motivation_percept_maxval
6009 
6010  !-----------------------------------------------------------------------------
6011  !> Calculate the level of **primary motivation** for this **specific**
6012  !! emotional state **component**.
6013  !! @note Used in `motivation_primary_calc` procedure.
6014  elemental function state_motivation_calculate_prim(this, maxvalue) &
6015  result(motivation_prim)
6016  class(state_motivation_base), intent(in) :: this
6017 
6018  !> The maximum value across all appraisal perception components, needed
6019  !! to standardise and rescale the latter to the range 0:1 before they
6020  !! are summed up.
6021  real(srp), optional, intent(in) :: maxvalue
6022 
6023  !> @return The value of the primary motivation for this
6024  !! motivation component.
6025  real(srp) :: motivation_prim
6026 
6027  !> Local parameters defining 0.0 and 1.0 for rescale.
6028  real(srp), parameter :: p0 = 0.0_srp, p1 = 1.0_srp
6029 
6030  !> Local copy of optional `maxvalue`.
6031  real(srp) :: maxvalue_here
6032 
6033  check_max_optnl: if (present(maxvalue)) then
6034  maxvalue_here = maxvalue
6035  else check_max_optnl
6036  !> Normally we **rescale** all values within the perceptual motivation
6037  !! components coming from the appraisal level into a [0..1] range within
6038  !! the agent, so that they are comparable across the motivations. To do
6039  !! this we need the maximum perception value **over all perception
6040  !! objects**: `maxvalue`. Normally `maxvalue` is an input parameter
6041  !! taking account of all motivation all state components. But if it is
6042  !! not provided, we calculate local maximum for **this** motivational
6043  !! component only.
6044  maxvalue_here = this%max_perception()
6045  end if check_max_optnl
6046 
6047  !> Calculate the primary motivation for this motivational state by summing
6048  !! up (**averaging**) all the perceptual components for this motivation
6049  !! weighted by their respective attention weights; components are
6050  !! **rescaled* from the potential global range 0:maxvalue to the range 0:1.
6051  !! @note `maxvalue` should normally be the maximum value for **all**
6052  !! available motivation states, not just this.
6053  !! TODO: make maxvalue a structure reflecting motivational components.
6054  motivation_prim = average( [ &
6055  rescale(this%percept_component%light, p0, maxvalue_here, p0, p1) * &
6056  this%attention_weight%light, &
6057 
6058  rescale(this%percept_component%depth, p0, maxvalue_here, p0, p1) * &
6059  this%attention_weight%depth, &
6060 
6061  rescale(this%percept_component%food_dir, p0, maxvalue_here, p0, p1) * &
6062  this%attention_weight%food_dir, &
6063 
6064  rescale(this%percept_component%food_mem, p0, maxvalue_here, p0, p1) * &
6065  this%attention_weight%food_mem, &
6066 
6067  rescale(this%percept_component%conspec, p0, maxvalue_here, p0, p1) * &
6068  this%attention_weight%conspec, &
6069 
6070  rescale(this%percept_component%pred_dir, p0, maxvalue_here, p0, p1) * &
6071  this%attention_weight%pred_dir, &
6072 
6073  rescale(this%percept_component%predator, p0, maxvalue_here, p0, p1) * &
6074  this%attention_weight%predator, &
6075 
6076  rescale(this%percept_component%stomach, p0, maxvalue_here, p0, p1) * &
6077  this%attention_weight%stomach, &
6078 
6079  rescale(this%percept_component%bodymass, p0, maxvalue_here, p0, p1) * &
6080  this%attention_weight%bodymass, &
6081 
6082  rescale(this%percept_component%energy, p0, maxvalue_here, p0, p1) * &
6083  this%attention_weight%energy, &
6084 
6085  rescale(this%percept_component%age, p0, maxvalue_here, p0, p1) * &
6086  this%attention_weight%age, &
6087 
6088  rescale(this%percept_component%reprfac, p0, maxvalue_here, p0, p1) * &
6089  this%attention_weight%reprfac ] )
6090 
6091  end function state_motivation_calculate_prim
6092 
6093  !.............................................................................
6094 
6095  !-----------------------------------------------------------------------------
6096  !> Initialise perception components for a motivation state object.
6097  elemental subroutine perception_component_motivation_init_zero(this)
6098  class(percept_components_motiv), intent(inout) :: this
6100  this%light = missing
6101  this%depth = missing
6102  this%food_dir = missing
6103  this%food_mem = missing
6104  this%conspec = missing
6105  this%pred_dir = missing
6106  this%predator = missing
6107  this%stomach = missing
6108  this%bodymass = missing
6109  this%energy = missing
6110  this%age = missing
6111  this%reprfac = missing
6112 
6114 
6115  !-----------------------------------------------------------------------------
6116  !> Init and cleanup **hunger** motivation object. The only difference from
6117  !! the base root STATE_MOTIVATION_BASE is that it sets unique label.
6118  elemental subroutine state_hunger_zero(this)
6119  class(state_hunger), intent(inout) :: this
6121  this%label = "HUNGER"
6122 
6123  call this%percept_component%init()
6124 
6125  call this%attention_weight%attention_init( &
6126  weight_light = attention_switch_hunger_light, &
6127  weight_depth = attention_switch_hunger_depth, &
6128  weight_food_dir = attention_switch_hunger_food_dir, &
6129  weight_food_mem = attention_switch_hunger_food_mem, &
6130  weight_conspec = attention_switch_hunger_conspec, &
6131  weight_pred_dir = attention_switch_hunger_pred_dir, &
6132  weight_predator = attention_switch_hunger_predator, &
6133  weight_stomach = attention_switch_hunger_stomach, &
6134  weight_bodymass = attention_switch_hunger_bodymass, &
6135  weight_energy = attention_switch_hunger_energy, &
6136  weight_age = attention_switch_hunger_age, &
6137  weight_reprfac = attention_switch_hunger_reprfac )
6138 
6139  this%motivation_prim = missing
6140  this%motivation_finl = missing
6141 
6142  this%dominant_state = .false.
6143 
6144  end subroutine state_hunger_zero
6145 
6146  !-----------------------------------------------------------------------------
6147  !> Init and cleanup **fear state** motivation object. The only
6148  !! difference from the base root STATE_MOTIVATION_BASE is that it sets
6149  !! unique label.
6150  elemental subroutine state_fear_defence_zero(this)
6151  class(state_fear_defence), intent(inout) :: this
6153  this%label = "ACTIVE_AVOID"
6154 
6155  call this%percept_component%init()
6156 
6157  call this%attention_weight%attention_init( &
6158  weight_light = attention_switch_avoid_act_light, &
6159  weight_depth = attention_switch_avoid_act_depth, &
6160  weight_food_dir = attention_switch_avoid_act_food_dir, &
6161  weight_food_mem = attention_switch_avoid_act_food_mem, &
6162  weight_conspec = attention_switch_avoid_act_conspec, &
6163  weight_pred_dir = attention_switch_avoid_act_pred_dir, &
6164  weight_predator = attention_switch_avoid_act_predator, &
6165  weight_stomach = attention_switch_avoid_act_stomach, &
6166  weight_bodymass = attention_switch_avoid_act_bodymass, &
6167  weight_energy = attention_switch_avoid_act_energy, &
6168  weight_age = attention_switch_avoid_act_age, &
6169  weight_reprfac = attention_switch_avoid_act_reprfac )
6170 
6171  this%motivation_prim = missing
6172  this%motivation_finl = missing
6173 
6174  this%dominant_state = .false.
6175 
6176  end subroutine state_fear_defence_zero
6177 
6178  !-----------------------------------------------------------------------------
6179  !> Init and cleanup **reproductive** motivation object. The only
6180  !! difference from the base root STATE_MOTIVATION_BASE is that it sets
6181  !! unique label.
6182  elemental subroutine state_reproduce_zero(this)
6183  class(state_reproduce), intent(inout) :: this
6185  this%label = "REPRODUCTION"
6186 
6187  call this%percept_component%init()
6188 
6189  call this%attention_weight%attention_init( &
6190  weight_light = attention_switch_reproduce_light, &
6191  weight_depth = attention_switch_reproduce_depth, &
6192  weight_food_dir = attention_switch_reproduce_food_dir, &
6193  weight_food_mem = attention_switch_reproduce_food_mem, &
6194  weight_conspec = attention_switch_reproduce_conspec, &
6195  weight_pred_dir = attention_switch_reproduce_pred_dir, &
6196  weight_predator = attention_switch_reproduce_predator, &
6197  weight_stomach = attention_switch_reproduce_stomach, &
6198  weight_bodymass = attention_switch_reproduce_bodymass, &
6199  weight_energy = attention_switch_reproduce_energy, &
6200  weight_age = attention_switch_reproduce_age, &
6201  weight_reprfac = attention_switch_reproduce_reprfac )
6202 
6203  this%motivation_prim = missing
6204  this%motivation_finl = missing
6205 
6206  this%dominant_state = .false.
6207 
6208  end subroutine state_reproduce_zero
6209 
6210  !-----------------------------------------------------------------------------
6211  !> Init the expectancy components to a zero state.
6212  elemental subroutine motivation_init_all_zero(this)
6213  class(motivation), intent(inout) :: this
6215  !> Expectancy components.
6216  call this%hunger%clean_init()
6217  call this%fear_defence%clean_init()
6218  call this%reproduction%clean_init()
6219 
6220  !> Also set the private and fixed "number of motivational states"
6221  !! constant, we obviously have 3 motivations.
6222  this%number_of_states = 3
6223 
6224  end subroutine motivation_init_all_zero
6225 
6226  !-----------------------------------------------------------------------------
6227  !> Reset all GOS indicators for this motivation object.
6228  elemental subroutine motivation_reset_gos_indicators(this)
6229  class(motivation), intent(inout) :: this
6231  !> Reset dominant status to FALSE for all motivational states.
6232  this%hunger%dominant_state = .false.
6233  this%fear_defence%dominant_state = .false.
6234  this%reproduction%dominant_state = .false.
6235 
6236  end subroutine motivation_reset_gos_indicators
6237 
6238  !-----------------------------------------------------------------------------
6239  !> Calculate maximum value of the perception components across all
6240  !! motivations.
6241  elemental function motivation_max_perception_calc(this) &
6242  result(max_motivation)
6243  class(motivation), intent(in) :: this
6244 
6245  !> @returns Returns the maximum value of the perception components
6246  !! across all motivations.
6247  real(srp) :: max_motivation
6248 
6249  max_motivation = maxval([ this%hunger%max_perception(), &
6250  this%fear_defence%max_perception(), &
6251  this%reproduction%max_perception() ])
6252 
6253  end function motivation_max_perception_calc
6254 
6255  !-----------------------------------------------------------------------------
6256  !> Return the vector of final motivation values for all motivational
6257  !! state components.
6258  pure function motivation_return_final_as_vector(this) &
6259  result(final_vals_vector)
6260  class(motivation), intent(in) :: this
6261  real(srp), allocatable, dimension(:) :: final_vals_vector
6262 
6263  final_vals_vector = [ this%hunger%motivation_finl, &
6264  this%fear_defence%motivation_finl, &
6265  this%reproduction%motivation_finl ]
6266 
6268 
6269  !-----------------------------------------------------------------------------
6270  !> Calculate the maximum value of the final motivations across all
6271  !! motivational state components.
6272  elemental function motivation_maximum_value_motivation_finl(this) &
6273  result(maxvalue)
6274  class(motivation), intent(in) :: this !< @param[in] this self
6275  real(srp) :: maxvalue !< @returns Maximum final motivation.
6276  !> An equivalent "manual" form not using `finals` function :
6277  !! maxvalue = maxval( [ this%hunger%motivation_finl, &
6278  !! this%fear_defence%motivation_finl, &
6279  !! this%reproduction%motivation_finl ] )
6280  maxvalue = maxval( this%finals() )
6281 
6283 
6284  !-----------------------------------------------------------------------------
6285  !> Checks if the test value is the maximum **final** motivation value
6286  !! across all motivational state components.
6287  !! @note This is a scalar form, inputs a single scalar value for testing.
6289  this, test_value) result(is_maximum)
6290  class(motivation), intent(in) :: this
6291  real(srp), intent(in) :: test_value
6292  logical :: is_maximum
6293 
6294  ! An equivalent "manual" form not using `finals` function :
6295  ! if ( is_maxval(test_value, [ this%hunger%motivation_finl, &
6296  ! this%fear_defence%motivation_finl, &
6297  ! this%reproduction%motivation_finl ]) ) &
6298  ! is_maximum = .TRUE.
6299  if ( is_maxval( test_value, this%finals() ) ) is_maximum = .true.
6300 
6302 
6303  !-----------------------------------------------------------------------------
6304  !> Checks if the test value is the maximum **final** motivation value
6305  !! across all motivational state components.
6306  !! @note This is object form, inputs a whole motivation state object
6308  this, test_motivation) result(is_maximum)
6309  class(motivation), intent(in) :: this
6310  class(state_motivation_base), intent(in) :: test_motivation
6311  logical :: is_maximum
6312 
6313  is_maximum = .false.
6314 
6315  if ( is_maxval( test_motivation%motivation_value(), this%finals() ) ) &
6316  is_maximum = .true.
6317 
6319 
6320  !-----------------------------------------------------------------------------
6321  !> Calculate the **primary motivations** from motivation-specific perception
6322  !! appraisal components. The **primary motivations** are motivation values
6323  !! before the modulation takes place.
6324  ! @note Note that we use array intrinsic functions `maxval` and `sum` here,
6325  ! combining arrays by array constructors using square brackets.
6326  elemental subroutine motivation_primary_sum_components(this, max_val)
6327  class(motivation), intent(inout) :: this
6329  !> @param[in] max_val optional parameter that sets the maximum perception
6330  !! value for rescaling all perceptions to a common currency.
6331  !! @note Needed to standardise and rescale the appraisal
6332  !! perception components to the range 0:1 before they
6333  !! are summed up.
6334  ! TODO: set from maximum perceptual memory
6335  real(srp), optional, intent(in) :: max_val
6336 
6337  ! Local copy of `max_val`, if the latter is absent, set to the maximum
6338  ! value across all appraisal perception components, needed to standardise
6339  ! and rescale the latter to the range 0:1 before they are summed up.
6340  real(srp) :: appmaxval
6341 
6342  !> ### Implementation notes ###
6343  !> - Rescale all values within the perceptual motivation components coming
6344  !! from the appraisal level into a [0..1] range within the agent, so
6345  !! that they are comparable across the motivations. To do this we need
6346  !! the maximum perception value overall perception objects: `appmaxval`.
6347  if (present(max_val)) then
6348  !> - If the maximum rescale perception is provided as a parameter,
6349  !! use it.
6350  appmaxval = max_val
6351  else
6352  !> - If the parameter value is not provided, calculate maximum rescale
6353  !! perceptions from the currently available perception components
6354  !! of each specific motivational state.
6355  !! .
6356  appmaxval = this%max_perception()
6357  end if
6358 
6359  !> - Calculate each of the motivations by summing up all state
6360  !! perceptual components for a particular motivation that are
6361  !! rescaled from the potential global range 0:appmaxval to the
6362  !! range 0:1. This is done calling the
6363  !! the_neurobio::state_motivation_base::motivation_calculate() method
6364  !! for each of the @ref aha_buildblocks_gp_motivations
6365  !! "motivational states".
6366  !! .
6367  this%hunger%motivation_prim = &
6368  this%hunger%motivation_calculate(appmaxval)
6369 
6370  this%fear_defence%motivation_prim = &
6371  this%fear_defence%motivation_calculate(appmaxval)
6372 
6373  this%reproduction%motivation_prim = &
6374  this%reproduction%motivation_calculate(appmaxval)
6375 
6376  end subroutine motivation_primary_sum_components
6377 
6378  !-----------------------------------------------------------------------------
6379  !> Produce **modulation** of the primary motivations, that result in
6380  !! the **final motivation** values (`_finl`). In this subroutine,
6381  !! **modulation is absent**, so the final motivation values are equal
6382  !! to the primary motivations.
6383  elemental subroutine motivation_modulation_absent(this)
6384  class(motivation), intent(inout) :: this
6386  !> Here the final motivations are just equal to their primary values
6387  this%hunger%motivation_finl = &
6388  this%hunger%motivation_prim
6389 
6390  this%fear_defence%motivation_finl = &
6391  this%fear_defence%motivation_prim
6392 
6393  this%reproduction%motivation_finl = &
6394  this%reproduction%motivation_prim
6395 
6396  end subroutine motivation_modulation_absent
6397 
6398 
6399 
6400 
6401 
6402 
6403 
6404 
6405 
6406 
6407 
6408 
6409 
6410 
6411 
6412 
6413 
6414 
6415 
6416 
6417 
6418 
6419  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6420  ! Functions linked with APPRAISAL
6421  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6422  !! @note We do not use **set** function for the `STATE_....` component
6423  !! (e.g. use `this%hunger%light` directly instead of
6424  !! `call this%hunger%set_light`) for brevity and simplicity.
6425  !! Otherwise, a temporal object may be needed with the second
6426  !! assignment in `this%hunger%set_...` procedure after the main
6427  !! `this%trait_init`. It is reasonable because the state component
6428  !! is within the same module so access granted. Unlike this neuronal
6429  !! response procedure requiring `set`, `get`-functions may be used
6430  !! in other, upwards, modules, so raw data components might be
6431  !! unaccessible there if declared `private`.
6432  !! @note `trait_init` function takes care of the neural response
6433  !! calculation from perception as well as the perception error
6434  !! and genome.
6435  !! @note Local rename `trait_init` to `neuro_resp`. May use different
6436  !! `trait_init` procedures, e.g. direct rescale-like gene to phenotype
6437  !! effects.
6438 
6439  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6440  ! Functions linked with APPRAISAL - generating
6441  ! PERCEPTUAL MOTIVATION COMPONENTS
6442  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6443 
6444  !-----------------------------------------------------------------------------
6445  !> Initialise and cleanup all appraisal object components and sub-objects.
6446  elemental subroutine appraisal_init_zero_cleanup_all(this)
6447  class(appraisal), intent(inout) :: this
6449  !> Init and clean all motivational components.
6450  call this%motivations%init()
6451 
6452  !> Also cleanup the emotional memory stack.
6453  call this%memory_motivations%memory_cleanup()
6454 
6455  end subroutine appraisal_init_zero_cleanup_all
6456 
6457  !-----------------------------------------------------------------------------
6458  !> Set the individual to be **dead**. Note that this function does not
6459  !! deallocate the individual agent object, this may be a separate destructor
6460  !! function.
6461  !!
6462  !! The `dies` method is implemented at the following levels
6463  !! of the agent object hierarchy (upper overrides the lower level):
6464  !! - the_genome::individual_genome::dies();
6465  !! - the_neurobio::appraisal::dies();
6466  !! - the_neurobio::gos_global::dies();
6467  !! - the_individual::individual_agent::dies().
6468  !! .
6469  !! @note This method overrides the the_genome::individual_genome::dies()
6470  !! method, nullifying all reproductive and neurobiological and
6471  !! behavioural objects.
6472  !! @note The `dies` method is implemented at the @ref gos_global to allow
6473  !! "cleaning" of all neurobiological objects when `dies` is called
6474  !! when performing the behaviours upwards in the object hierarchy.
6475  elemental subroutine appraisal_agent_set_dead(this)
6476  class(appraisal), intent(inout) :: this
6478  call this%set_dead() !> - Set the agent "dead";
6479  call this%init_reproduction() !> - emptify reproduction objects;
6480  call this%init_perception() !> - emptify all neurobiological objects.
6481  call this%init_appraisal() !> .
6482 
6483  end subroutine appraisal_agent_set_dead
6484 
6485  !-----------------------------------------------------------------------------
6486  !> Get the perceptual components of all motivational states by passing
6487  !! perceptions via the neuronal response function.
6488  !! @warning Here we use the intent[inout] procedure that **does change** the
6489  !! actor agent: sets the labels for the genes. This procedure,
6490  !! therefore is used only for initialisation and not in prediction.
6492  class(appraisal), intent(inout) :: this
6494  !> ### Implementation notes ###
6495  !! Call the neuronal response initialisation procedure
6496  !! the_neurobio::percept_components_motiv::motivation_components_init()
6497  !! for all the motivation states:
6498  !! - the_neurobio::state_hunger
6499  !! - the_neurobio::state_fear_defence
6500  !! - the_neurobio::state_reproduce
6501  !! .
6502  ! @note **Appraisal** assessment for **hunger** motivation, using
6503  ! `PERCEPT_COMPONENTS_MOTIV`-bound procedure with **intent[inout]**
6504  ! for `this_agent` now.
6505  call this%motivations%hunger%percept_component%motivation_components_init &
6506  (this, &
6507  ! Parameters:: Boolean G x P matrices:
6508  param_gp_matrix_light = light_hunger_genotype_neuronal, &
6509  param_gp_matrix_depth = depth_hunger_genotype_neuronal, &
6510  param_gp_matrix_food_dir = foodcount_hunger_genotype_neuronal, &
6511  param_gp_matrix_food_mem = food_mem_hunger_genotype_neuronal, &
6512  param_gp_matrix_conspec = conspcount_hunger_genotype_neuronal, &
6513  param_gp_matrix_pred_dir = pred_direct_hunger_genotype_neuronal, &
6514  param_gp_matrix_predator = pred_meancount_hunger_genotype_neuronal, &
6515  param_gp_matrix_stomach = stom_hunger_genotype_neuronal, &
6516  param_gp_matrix_bodymass = bodymass_hunger_genotype_neuronal, &
6517  param_gp_matrix_energy = energy_hunger_genotype_neuronal, &
6518  param_gp_matrix_age = age_hunger_genotype_neuronal, &
6519  param_gp_matrix_reprfac = reprfac_hunger_genotype_neuronal, &
6520  ! Parameters :: G x P variances:
6521  param_gerror_cv_light = light_hunger_genotype_neuronal_gerror_cv, &
6522  param_gerror_cv_depth = depth_hunger_genotype_neuronal_gerror_cv, &
6523  param_gerror_cv_food_dir = foodcount_hunger_genotype_neuronal_gerror_cv,&
6524  param_gerror_cv_food_mem = food_mem_hunger_genotype_neuronal_gerror_cv, &
6525  param_gerror_cv_conspec = conspcount_hunger_genotype_neuronal_gerror_cv,&
6526  param_gerror_cv_pred_dir = pred_direct_hunger_genotype_neuronal_gerror_cv,&
6527  param_gerror_cv_predator = pred_meancount_hunger_genotype_neuronal_gerror_cv,&
6528  param_gerror_cv_stomach = stom_hunger_genotype_neuronal_gerror_cv, &
6529  param_gerror_cv_bodymass = bodymass_hunger_genotype_neuronal_gerror_cv, &
6530  param_gerror_cv_energy = energy_hunger_genotype_neuronal_gerror_cv, &
6531  param_gerror_cv_age = age_hunger_genotype_neuronal_gerror_cv, &
6532  param_gerror_cv_reprfac = reprfac_hunger_genotype_neuronal_gerror_cv, &
6533  ! Parameters :: labels for genes:
6534  param_gene_label_light = "HUNGER_LIGHT", &
6535  param_gene_label_depth = "HUNGER_DEPTH", &
6536  param_gene_label_food_dir= "HUNGER_FOODMEM", &
6537  param_gene_label_food_mem= "HUNGER_FOODMEM", &
6538  param_gene_label_conspec = "HUNGER_CONSP_N", &
6539  param_gene_label_pred_dir= "HUNGER_PREDDIR", &
6540  param_gene_label_predator= "HUNGER_PRED", &
6541  param_gene_label_stomach = "HUNGER_STOM", &
6542  param_gene_label_bodymass= "HUNGER_BODYMAS", &
6543  param_gene_label_energy = "HUNGER_ENERGY", &
6544  param_gene_label_age = "HUNGER_AGE", &
6545  param_gene_label_reprfac = "HUNGER_REPRFAC" )
6546 
6547  ! @note **Appraisal** assessment for **fear_defence** motivation,
6548  ! using `PERCEPT_COMPONENTS_MOTIV`-bound procedure with intent[inout]
6549  ! for `this_agent` now.
6550  call this%motivations%fear_defence%percept_component%motivation_components_init &
6551  (this, &
6552  ! Parameters:: Boolean G x P matrices:
6553  param_gp_matrix_light = light_actv_avoid_genotype_neuronal, &
6554  param_gp_matrix_depth = depth_actv_avoid_genotype_neuronal, &
6555  param_gp_matrix_food_dir = foodcount_actv_avoid_genotype_neuronal, &
6556  param_gp_matrix_food_mem = food_mem_actv_avoid_genotype_neuronal, &
6557  param_gp_matrix_conspec = conspcount_actv_avoid_genotype_neuronal, &
6558  param_gp_matrix_pred_dir = pred_direct_actv_avoid_genotype_neuronal, &
6559  param_gp_matrix_predator = pred_meancount_actv_avoid_genotype_neuronal, &
6560  param_gp_matrix_stomach = stom_actv_avoid_genotype_neuronal, &
6561  param_gp_matrix_bodymass = bodymass_actv_avoid_genotype_neuronal, &
6562  param_gp_matrix_energy = energy_actv_avoid_genotype_neuronal, &
6563  param_gp_matrix_age = age_actv_avoid_genotype_neuronal, &
6564  param_gp_matrix_reprfac = reprfac_actv_avoid_genotype_neuronal, &
6565  ! Parameters :: G x P variances:
6566  param_gerror_cv_light = light_actv_avoid_genotype_neuronal_gerror_cv, &
6567  param_gerror_cv_depth = depth_actv_avoid_genotype_neuronal_gerror_cv, &
6568  param_gerror_cv_food_dir = foodcount_actv_avoid_genotype_neuronal_gerror_cv,&
6569  param_gerror_cv_food_mem = food_mem_actv_avoid_genotype_neuronal_gerror_cv, &
6570  param_gerror_cv_conspec = conspcount_actv_avoid_genotype_neuronal_gerror_cv,&
6571  param_gerror_cv_pred_dir = pred_direct_actv_avoid_genotype_neuronal_gerror_cv,&
6572  param_gerror_cv_predator = pred_meancount_actv_avoid_genotype_neuronal_gerror_cv,&
6573  param_gerror_cv_stomach = stom_actv_avoid_genotype_neuronal_gerror_cv, &
6574  param_gerror_cv_bodymass = bodymass_actv_avoid_genotype_neuronal_gerror_cv,&
6575  param_gerror_cv_energy = energy_actv_avoid_genotype_neuronal_gerror_cv,&
6576  param_gerror_cv_age = age_actv_avoid_genotype_neuronal_gerror_cv, &
6577  param_gerror_cv_reprfac = reprfac_actv_avoid_genotype_neuronal_gerror_cv,&
6578  ! Parameters :: labels for genes:
6579  param_gene_label_light = "AAVOID_LIGHT", &
6580  param_gene_label_depth = "AAVOID_DEPTH", &
6581  param_gene_label_food_dir= "AAVOID_FOODMEM", &
6582  param_gene_label_food_mem= "AAVOID_FOODMEM", &
6583  param_gene_label_conspec = "AAVOID_CONSP_N", &
6584  param_gene_label_pred_dir= "AAVOID_PREDDIR", &
6585  param_gene_label_predator= "AAVOID_PRED", &
6586  param_gene_label_stomach = "AAVOID_STOM", &
6587  param_gene_label_bodymass= "AAVOID_BODYMAS", &
6588  param_gene_label_energy = "AAVOID_ENERGY", &
6589  param_gene_label_age = "AAVOID_AGE", &
6590  param_gene_label_reprfac = "AAVOID_REPRFAC" )
6591 
6592  ! @note **Appraisal** assessment for **reproduction** motivation, using
6593  ! `PERCEPT_COMPONENTS_MOTIV`-bound procedure with intent[inout] for
6594  ! `this_agent` now.
6595  call this%motivations%reproduction%percept_component%motivation_components_init &
6596  (this, &
6597  ! Parameters:: Boolean G x P matrices:
6598  param_gp_matrix_light = light_reproduce_genotype_neuronal, &
6599  param_gp_matrix_depth = depth_reproduce_genotype_neuronal, &
6600  param_gp_matrix_food_dir = foodcount_reproduce_genotype_neuronal, &
6601  param_gp_matrix_food_mem = food_mem_reproduce_genotype_neuronal, &
6602  param_gp_matrix_conspec = conspcount_reproduce_genotype_neuronal, &
6603  param_gp_matrix_pred_dir = pred_direct_reproduce_genotype_neuronal, &
6604  param_gp_matrix_predator = pred_meancount_reproduce_genotype_neuronal, &
6605  param_gp_matrix_stomach = stom_reproduce_genotype_neuronal, &
6606  param_gp_matrix_bodymass = bodymass_reproduce_genotype_neuronal, &
6607  param_gp_matrix_energy = energy_reproduce_genotype_neuronal, &
6608  param_gp_matrix_age = age_reproduce_genotype_neuronal, &
6609  param_gp_matrix_reprfac = reprfac_reproduce_genotype_neuronal, &
6610  ! Parameters :: G x P variances:
6611  param_gerror_cv_light = light_reproduce_genotype_neuronal_gerror_cv, &
6612  param_gerror_cv_depth = depth_reproduce_genotype_neuronal_gerror_cv, &
6613  param_gerror_cv_food_dir = foodcount_reproduce_genotype_neuronal_gerror_cv,&
6614  param_gerror_cv_food_mem = food_mem_reproduce_genotype_neuronal_gerror_cv, &
6615  param_gerror_cv_conspec = conspcount_reproduce_genotype_neuronal_gerror_cv,&
6616  param_gerror_cv_pred_dir = pred_direct_reproduce_genotype_neuronal_gerror_cv,&
6617  param_gerror_cv_predator = pred_meancount_reproduce_genotype_neuronal_gerror_cv,&
6618  param_gerror_cv_stomach = stom_reproduce_genotype_neuronal_gerror_cv, &
6619  param_gerror_cv_bodymass = bodymass_reproduce_genotype_neuronal_gerror_cv,&
6620  param_gerror_cv_energy = energy_reproduce_genotype_neuronal_gerror_cv,&
6621  param_gerror_cv_age = age_reproduce_genotype_neuronal_gerror_cv, &
6622  param_gerror_cv_reprfac = reprfac_reproduce_genotype_neuronal_gerror_cv,&
6623  ! Parameters :: labels for genes:
6624  param_gene_label_light = "REPROD_LIGHT", &
6625  param_gene_label_depth = "REPROD_DEPTH", &
6626  param_gene_label_food_dir= "REPROD_FOODMEM", &
6627  param_gene_label_food_mem= "REPROD_FOODMEM", &
6628  param_gene_label_conspec = "REPROD_CONSP_N", &
6629  param_gene_label_pred_dir= "REPROD_PREDDIR", &
6630  param_gene_label_predator= "REPROD_PRED", &
6631  param_gene_label_stomach = "REPROD_STOM", &
6632  param_gene_label_bodymass= "REPROD_BODYMAS", &
6633  param_gene_label_energy = "REPROD_ENERGY", &
6634  param_gene_label_age = "REPROD_AGE", &
6635  param_gene_label_reprfac = "REPROD_REPRFAC" )
6636 
6638 
6639  !-----------------------------------------------------------------------------
6640  !> Calculate primary motivations from perceptual components of each
6641  !! motivation state.
6642  elemental subroutine appraisal_primary_motivations_calculate(this, &
6643  rescale_max_motivation)
6644  class(appraisal), intent(inout) :: this
6645 
6646  !> @param[in] rescale_max_motivation maximum motivation value for
6647  !! rescaling all motivational components for comparison
6648  !! across all motivation and perceptual components and behaviour
6649  !! units.
6650  real(srp), optional, intent(in) :: rescale_max_motivation
6651 
6652  ! Local variables
6653  real(srp) :: max_motivation !< Local max. over all motivation components.
6654 
6655 
6656  !> ### Implementation notes ###
6657  !> - Check if the maximum motivation value for rescale is provided as
6658  !! a parameter.
6659  if (present(rescale_max_motivation)) then
6660  !> - Check if global maximum motivation across all behaviours
6661  !! and perceptual components is provided for rescaling.
6662  max_motivation = rescale_max_motivation
6663  else
6664  !> - If not, use local maximum value for this behaviour only.
6665  !! .
6666  !! .
6667  max_motivation = this%motivations%max_perception()
6668  end if
6669 
6670  !> Finally, the primary motivation values are calculated using the
6671  !! the_neurobio::motivation::motivation_primary_calc() method.
6672  call this%motivations%motivation_primary_calc(max_motivation)
6673 
6675 
6676  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6677  ! Functions linked with generation of the MOTIVATION states (SUMMATOR).
6678  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6679 
6680  !-----------------------------------------------------------------------------
6681  !> Produce **modulation** of the primary motivations, that result in
6682  !! the **final motivation** values (`_finl`). Modulation here is non-genetic
6683  !! and involves a fixed transformation of the primary motivation values.
6685  no_modulation)
6686  class(appraisal), intent(inout) :: this
6687  !> @param[in] no_genetic_modulation chooses if genetic modulation is
6688  !! calculated at all, if set to TRUE, then genetic modulation
6689  !! is **not** calculated and the final motivational values
6690  !! are just equal to the primary motivations.
6691  logical, optional, intent(in) :: no_modulation
6692 
6693  ! PROCNAME is the procedure name for logging and debugging
6694  character(len=*), parameter :: &
6695  PROCNAME = "(appraisal_motivation_modulation_non_genetic)"
6696 
6697  real(SRP) :: weight_reprfac
6698 
6699  !> ### Notable variables and parameters ###
6700  !> - `AGE_ARRAY_ABSCISSA` is the interpolation grid abscissa for the
6701  !! weighting factor applied to reproductive motivation. It is defined
6702  !! by the parameter commondata::reprod_modulation_devel_abscissa.
6703  real(SRP), parameter, dimension(*) :: AGE_ARRAY_ABSCISSA = &
6704  reprod_modulation_devel_abscissa
6705 
6706  !> - `AGE_ARRAY_ORDINATE` is the interpolation grid ordinate. Its first
6707  !! and last values are set as 0.0 and 1.0, and the middle is defined by
6708  !! the parameter commondata::reprod_modulation_devel_w2.
6709  !! @verbatim
6710  !! htintrpl.exe [ 7000, 8555, 11666 ] [ 0, 0.10, 1.0 ]
6711  !! @endverbatim
6712  !! .
6713  real(SRP), parameter, dimension(*) :: AGE_ARRAY_ORDINATE = &
6714  [ zero, reprod_modulation_devel_w2, 1.0_srp ]
6715 
6716  !> ### Implementation notes ###
6717  !> First, *initialise* the **final motivation** values from the
6718  !! **no modulation** method the_neurobio::motivation::modulation_none().
6719  call this%motivations%modulation_none()
6720 
6721  !> Then check if developmental or genetic (or any other) modulation is
6722  !! disabled by the parameters commondata::modulation_appraisal_disable_all.
6723  if ( modulation_appraisal_disable_all ) return
6724 
6725  !> Check if `no_genetic_modulation` parameter is set to TRUE and if
6726  !! yes, return without no further processing.
6727  if (present(no_modulation)) then
6728  if ( no_modulation ) return ! no further processing.
6729  end if
6730 
6731  !+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
6732  ! Explicit non-genetic modulation starts below:
6733 
6734  !> #### Developmental modulation of reproductive factor ####
6735  !> Reproductive factor the_hormones::hormones::reproductive_factor() is
6736  !! accumulated by the sex hormone level whenever the agent is growing.
6737  !! Such accumulation can increase motivation for reproduction. However,
6738  !! reproduction is not possible in young and small agents. Therefore,
6739  !! this procedure implements a developmental modulation of the
6740  !! reproductive factor: reproductive motivation
6741  !! the_neurobio::state_reproduce is weighted out while the agent does
6742  !! not reach a target body length and age. This weighting is defined by
6743  !! nonlinear interpolation using the abscissa array `AGE_ARRAY_ABSCISSA`
6744  !! and ordinate `AGE_ARRAY_ORDINATE`. Such weighting, thus, allows
6745  !! non-zero reproductive motivation only when the agent reaches the age
6746  !! exceeding the first abscissa value `AGE_ARRAY_ABSCISSA`, age > *L/2*,
6747  !! as here the weighting factor exceeds zero. Furthermore, when the
6748  !! age of the agent exceeds the last value of `AGE_ARRAY_ABSCISSA`,
6749  !! the weighting factor is equal to 1.0, so reproductive motivation is
6750  !! not limited any more.
6751  weight_reprfac &
6752  = within( ddpinterpol( age_array_abscissa, age_array_ordinate, &
6753  real(this%get_age(), SRP) ), &
6754  ZERO, 1.0_SRP )
6755 
6756  !> Interpolation plots can be saved in the @ref intro_debug_mode
6757  !! "debug mode" using this plotting command:
6758  !! commondata::debug_interpolate_plot_save().
6759  ! @warning Calling `debug_interpolate_plot_save` here precludes making
6760  ! this function **pure** and **elemental**. Comment-out upon
6761  ! full testing and debugging!
6762  call debug_interpolate_plot_save( &
6763  grid_xx=age_array_abscissa, grid_yy=age_array_ordinate, &
6764  ipol_value=weight_reprfac, &
6765  algstr="DDPINTERPOL", &
6766  output_file="plot_debug_reproduction_modulal_ageweight_" // &
6767  tostr(global_time_step_model_current) // &
6768  mmdd // "_a_"// trim(this%individ_label()) // "_" // &
6769  rand_string(label_length, label_cst,label_cen) // ps )
6770 
6771  this%motivations%reproduction%motivation_finl = &
6772  this%motivations%reproduction%motivation_prim * weight_reprfac
6773 
6775 
6776  !-----------------------------------------------------------------------------
6777  !> Produce **modulation** of the primary motivations, that result in
6778  !! the **final motivation** values (`_finl`). Modulation involves
6779  !! effects of such characteristics of the agent as body mass and age on
6780  !! the primary motivations (hunger, active and passive avoidance and
6781  !! reproduction) mediated by the genome effects. Here the genome determines
6782  !! the coefficients that set the degree of the influence of the agent's
6783  !! characteristics on the motivations.
6784  subroutine appraisal_motivation_modulation_genetic (this, &
6785  no_genetic_modulation)
6786  class(appraisal), intent(inout) :: this
6787  !> @param[in] no_genetic_modulation chooses if genetic modulation is
6788  !! calculated at all, if set to TRUE, then genetic modulation
6789  !! is **not** calculated and the final motivational values
6790  !! are just equal to the primary motivations.
6791  logical, optional, intent(in) :: no_genetic_modulation
6792 
6793  ! Genetically determined **gamma** modulation coefficient that mediates
6794  ! the effect of sex on reproductive motivation.
6795  real(SRP) :: modulation_gamma
6796 
6797  ! PROCNAME is the procedure name for logging and debugging
6798  character(len=*), parameter :: PROCNAME = &
6799  "(appraisal_motivation_modulation_genetic)"
6800 
6801  !> ### Implementation notes ###
6802  !> First, *initialise* the **final motivation** values from the
6803  !! **no modulation** method the_neurobio::motivation::modulation_none().
6804  call this%motivations%modulation_none()
6805 
6806  !> Then check if developmental or genetic (or any other) modulation is
6807  !! disabled by the parameters commondata::modulation_appraisal_disable_all.
6808  if ( modulation_appraisal_disable_all ) return
6809 
6810  !> Check if `no_genetic_modulation` parameter is set to TRUE and if
6811  !! yes, return without no further processing.
6812  if (present(no_genetic_modulation)) then
6813  if ( no_genetic_modulation ) return ! no further processing.
6814  end if
6815 
6816  !+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
6817  ! Explicit modulation starts below:
6818 
6819  !+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
6820  !> Sex modulation of the **reproduction** motivation state for **male**.
6821  ! @warning This code uses the `block` construct from the F2008 standard,
6822  ! which may not be supported by all compilers (e.g. ifort v 13
6823  ! doesn't support it). It is here only for convenience and can be
6824  ! commented-out if unsupported (but don't forget to disable the
6825  ! `end block` too).
6826  male_reprod: block
6827 
6828  !> - First, use the sigmoid function and genome to set the phenotypic
6829  !! value of the **gamma** modulation coefficient that mediates the
6830  !! effect of the agent's sex on reproductive motivation.
6831  call this%trait_init( &
6832  this_trait = modulation_gamma, &
6833  g_p_matrix = sex_male_modulation_reproduce_genotype, &
6834  init_val = this%motivations%reproduction%motivation_prim, &
6835  gerror_cv = sex_male_modulation_reproduce_gerror_cv, &
6836  label = "M_MALE_REPRO" )
6837 
6838  !> - Second, add the modulation factor to the actual motivation value.
6839  !! If the agent is male, then its reproductive motivation is increased
6840  !! by an additive component that is an ::asymptotic() function of the
6841  !! genome based `modulation_gamma` parameter. The maximum modulatory
6842  !! increase ever possible is the double value of the raw primary
6843  !! motivation.
6844  !! .
6845  if ( this%is_male() ) then
6846  this%motivations%reproduction%motivation_finl = &
6847  this%motivations%reproduction%motivation_prim + &
6848  this%motivations%reproduction%motivation_prim * &
6849  asymptotic(this%motivations%reproduction%motivation_prim, &
6850  modulation_gamma)
6851  end if
6852 
6853  end block male_reprod
6854 
6855  !+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
6856  !> Sex modulation of the **reproduction** motivation state for **female**.
6857  ! @warning See warning on `block`-construct in `MALE_REPROD` above.
6858  female_reprod: block
6859 
6860  !> - First, use the sigmoid function and genome to set the phenotypic
6861  !! value of the **gamma** modulation coefficient that mediates the
6862  !! effect of the agent's sex on reproductive motivation.
6863  call this%trait_init( &
6864  this_trait = modulation_gamma, &
6865  g_p_matrix = sex_female_modulation_reproduce_genotype, &
6866  init_val = this%motivations%reproduction%motivation_prim, &
6867  gerror_cv = sex_female_modulation_reproduce_gerror_cv, &
6868  label = "M_FEMALE_REPRO" )
6869 
6870  !> - Second, add the modulation factor to the actual motivation value.
6871  !! If the agent is male, then its reproductive motivation is increased
6872  !! by an additive component that is an ::asymptotic() function of the
6873  !! genome based `modulation_gamma` parameter. The maximum modulatory
6874  !! increase ever possible is the double value of the raw primary
6875  !! motivation.
6876  !! .
6877  if ( this%is_female() ) then
6878  this%motivations%reproduction%motivation_finl = &
6879  this%motivations%reproduction%motivation_prim + &
6880  this%motivations%reproduction%motivation_prim * &
6881  asymptotic(this%motivations%reproduction%motivation_prim, &
6882  modulation_gamma)
6883  end if
6884 
6885  end block female_reprod
6886 
6887  !> The values are logged in the@ref intro_debug_mode "debug mode".
6888  call log_dbg( ltag_info // "Modulation REPRODUCTION " // &
6889  "gamma: " // tostr(modulation_gamma) // &
6890  ", primary: " // &
6891  tostr(this%motivations%reproduction%motivation_prim) // &
6892  ", final: " // &
6893  tostr(this%motivations%reproduction%motivation_finl), &
6894  procname, modname )
6895 
6896  contains
6897  !- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
6898  !> Definition of the asymptotic function for converting the primary
6899  !! genotype-based modulation coefficient *gamma* to the actual additive
6900  !! multiplication value:
6901  !! @f$ y = \frac{M\cdot x}{1 + x} @f$, where @f$ M @f$ is the asymptotic
6902  !! value (maximum)
6903  !! @note wxMaxima quick code:
6904  !! @code
6905  !! wxplot2d(0.7*x/(1+x), [x, 0, 10]);
6906  !! @endcode
6907  elemental function asymptotic(max_level, x) result (out_value)
6908 
6909  real(srp) :: out_value
6910  real(srp), intent(in) :: max_level, x
6911 
6912  ! We do not accept zero asymptotic maximum value.
6913  if (max_level <= zero) then
6914  out_value = 0.0_srp
6915  return
6916  end if
6917  ! We also do not accept negative x-argument values, set to zero.
6918  if (x < zero) then
6919  out_value = 0.0_srp
6920  else
6921  out_value = (max_level * x) / (1 + x)
6922  end if
6923 
6924  end function asymptotic
6925 
6927 
6928  !-----------------------------------------------------------------------------
6929  !> Add individual final emotional state components into the emotional
6930  !! memory stack. This is a wrapper to the
6931  !! the_neurobio::memory_emotional::add_to_memory method.
6932  elemental subroutine appraisal_add_final_motivations_memory(this)
6933  class(appraisal), intent(inout) :: this
6935  call this%memory_motivations%add_to_memory( &
6936  this%motivations%hunger%motivation_finl, &
6937  this%motivations%fear_defence%motivation_finl, &
6938  this%motivations%reproduction%motivation_finl )
6939 
6941 
6942  !-----------------------------------------------------------------------------
6943  !> Calculate the instantaneous probability of successful reproduction.
6944  !! @note Note that this function is bound to class the_neurobio::appraisal
6945  !! rather than the_neurobio::reproduce. Probability of successful
6946  !! reproduction is a dynamic property of this agent that depends on
6947  !! the nearby conspecifics and their sex and size/mass.
6948  function reproduce_do_probability_reproduction_calc(this, weight_baseline, &
6949  allow_immature ) result (p_reproduction)
6950  class(appraisal), intent(in) :: this
6951  !> @param[in] weight_baseline is the weighting factor for the baseline
6952  !! probability of successful reproduction @f$ \varphi @f$ (see
6953  !! details below).
6954  real(srp), optional, intent(in) :: weight_baseline
6955 
6956  !> @param[in] allow_immature a logical switch that allows calculation
6957  !! (non-zero probability) if the agent is not ready to
6958  !! reproduction as determined by the
6959  !! the_body::reproduction::is_ready_reproduce() method.
6960  !! Normally, immature agents (for which this method returns
6961  !! FALSE) have zero probability of reproduction.
6962  !! The default is FALSE, i.e. not to allow reproduction to
6963  !! immature agents.
6964  logical, optional, intent(in) :: allow_immature
6965  !> @returns instantaneous probability of successful reproduction.
6966  real(srp) :: p_reproduction
6967 
6968  ! Local copies of the optionals.
6969  real(srp) :: weight_baseline_here
6970  logical :: allow_immature_loc
6971 
6972  ! PROCNAME is the procedure name for logging and debugging
6973  character(len=*), parameter :: &
6974  procname = "(reproduce_do_probability_reproduction_calc)"
6975 
6976  !> ### Implementation details ###
6977  !> The probability of successful reproduction depends on the number of
6978  !! conspecifics of the same and the opposite sex within the `this` agent's
6979  !! visual range. So the starting point here is the number of conspecifics
6980  !! within the current conspecifics perception object.
6981  integer :: n_conspecifics_perception
6982  integer :: n_same_sex_perception, n_opposite_sex_perception
6983 
6984  ! Intermediate probabilities.
6985  real(srp) :: p_reproduction_baseline
6986 
6987  ! Difference in mass with the other same-sex agents.
6988  real(srp) :: delta_mass
6989 
6990  ! Sum of the same sex conspecifics mass, used in calculation of delta_mass.
6991  real(srp) :: sum_mass_samesex
6992 
6993  ! Local counters.
6994  integer :: i
6995 
6996  !> **First,** determine if the hormonal system of the agent is ready for
6997  !! reproduction using the_body::reproduction::is_ready_reproduce().
6998  if (present(allow_immature)) then
6999  allow_immature_loc = allow_immature
7000  else
7001  allow_immature_loc = .false.
7002  end if
7003  !> If this agent is not ready to reproduce, a zero probability of
7004  !! reproduction returned. However, if the optional parameter
7005  !! `allow_immature` is explicitly set to TRUE, this check is not done
7006  !! and the probability of reproduction is calculated as follows.
7007  check_mature: if ( .not. allow_immature_loc ) then
7008  if ( .not. this%is_ready_reproduce() ) then
7009  p_reproduction = 0.0
7010  ! @warning Calling LOG_DBG precludes making this function **pure**.
7011  call log_dbg( ltag_info // "Not ready to reproduce (steroids).", &
7012  procname, modname)
7013  return
7014  end if
7015  end if check_mature
7016 
7017  !> **Second,** determine if there are any conspecifics in the perception,
7018  !! if there are no, reproduction is impossible. Return straight away zero
7019  !! probability in such a case.
7020  check_is_alone: if ( .NOT. this%has_consp() ) then
7021  p_reproduction = 0.0_srp
7022  ! @warning Calling LOG_DBG precludes making this function **pure**.
7023  call log_dbg( ltag_info // "No conspecifics in perception", &
7024  procname, modname)
7025  return
7026  end if check_is_alone
7027 
7028  ! Check optional baseline probability weighting factor @f$ \varphi @f$.
7029  if (present(weight_baseline)) then
7030  weight_baseline_here = weight_baseline
7031  else
7032  weight_baseline_here = probability_reproduction_base_factor
7033  end if
7034 
7035  !> **Second,** extract the number of conspecifics `n_conspecifics_perception`
7036  !! from the perception object.
7037  n_conspecifics_perception = this%perceive_consp%get_count()
7038 
7039  !> Also, initialise the number of same- and opposite-sex conspecifics
7040  !! (integer counters) as well as the total mass of same-sex conspecifics
7041  !! (real) to zero.
7042  n_same_sex_perception = 0
7043  n_opposite_sex_perception = 0
7044  sum_mass_samesex = 0.0_srp
7045 
7046  !> **Third,** determine how many of the conspecifics in perception
7047  !! have the same and the opposite sex. Calculate total mass of same sex
7048  !! conspecifics.
7049  check_sex: if ( this%is_male() ) then
7050  do concurrent(i=1:n_conspecifics_perception)
7051  if ( this%perceive_consp%conspecifics_seen(i)%is_male() ) then
7052  n_same_sex_perception = n_same_sex_perception + 1
7053  sum_mass_samesex = sum_mass_samesex + &
7054  this%perceive_consp%conspecifics_seen(i)%get_mass()
7055  else
7056  n_opposite_sex_perception = n_opposite_sex_perception + 1
7057  end if
7058  end do
7059  else check_sex
7060  do concurrent(i=1:n_conspecifics_perception)
7061  if ( this%perceive_consp%conspecifics_seen(i)%is_female() ) then
7062  n_same_sex_perception = n_same_sex_perception + 1
7063  sum_mass_samesex = sum_mass_samesex + &
7064  this%perceive_consp%conspecifics_seen(i)%get_mass()
7065  else
7066  n_opposite_sex_perception = n_opposite_sex_perception + 1
7067  end if
7068  end do
7069  end if check_sex
7070 
7071  !> Additionally, check if the number of opposite sex agents is zero.
7072  !! in such a case zero probability of reproduction is obviously returned.
7073  if (n_opposite_sex_perception == 0) then
7074  p_reproduction = 0.0_srp
7075  ! @warning Calling LOG_DBG precludes making this function **pure**.
7076  call log_dbg(ltag_info // " No oposite-sex conspecifics in " // &
7077  "perception, return zero probability.", procname, modname)
7078  return
7079  end if
7080 
7081  !> **Fourth,** calculate the **baseline probability** of reproduction.
7082  !! This probability is proportional to the proportions of the same- and
7083  !! opposite-sex agents within the visual range.
7084  !! @f[ p_{0} = \frac{N_{os}}{1+N_{ss}} ; 0 \leq p_{0}\leq 1, @f] where
7085  !! @f$ N_{os} @f$ is the number of the opposite-sex agents,
7086  !! @f$ N_{ss} @f$ is the number of same-sex agents.
7087  !! We also adjust the baseline probability of successful reproduction by
7088  !! a parameter factor @f$ \varphi @f$, so that this probability never
7089  !! reaches 1:
7090  !! @f[ p_{0} = \frac{N_{os}}{1+N_{ss}} \cdot \varphi @f]
7091  !! For example, if there is only one agent of the opposite sex and no
7092  !! same-sex in proximity the baseline probability of reproduction is
7093  !! 1/(1+0) = 1.0 (note that the this agent also adds to the same-sex count,
7094  !! hence "1+..."). If there are 3 opposite-sex agents and 3 same-sex
7095  !! agents, the baseline probability is calculated as 3/(1+3) = 0.75. This
7096  !! doesn't take account of the @f$ \varphi @f$ multiplier factor.
7097  p_reproduction_baseline = &
7098  within( real(n_opposite_sex_perception, srp) / &
7099  (1.0_srp + real(n_same_sex_perception, srp)), &
7100  0.0_srp, 1.0_srp ) * weight_baseline_here
7101 
7102  !> **Fifth,** to get the final successful reproduction probability,
7103  !! the baseline value @f$ p_{0} @f$ is multiplied by a function
7104  !! @f$ \Phi @f$ that depends on the relative body mass of the `this` agent
7105  !! with respect to all the *same-sex* agents in proximity.
7106  !! @f[ p_{rep} = p_{0} \cdot \Phi(\Delta \overline{m_{i}}),
7107  !! 0 \leq p_{rep} \leq 1 , @f] where
7108  !! @f$ p_{rep} @f$ is the final probability of successful reproduction.
7109  !! This is done to model direct within-sex competition for mates.
7110  !! Therefore, if the `this` agent is smaller than all the other same-sex
7111  !! agents here, the probability of successful reproduction significantly
7112  !! reduces. On the other hand, if the agent is larger than all the others,
7113  !! this probability would increase. The form of the @f$ \Phi @f$
7114  !! function is calculated on the bases of the *ratio* of the `this`
7115  !! agent body mass to the average body mass of all same sex agents within
7116  !! the visual range:
7117  !! @f[ \Delta \overline{m_{i}} = \frac{ M }{ \overline{m_{i}} } . @f]
7118  check_calcp: if (n_same_sex_perception == 0) then
7119  !> Note that if there are *no same sex agents* (i.e. intra-sexual
7120  !! competition is absent) the probability of
7121  !! reproduction takes the baseline value @f$ p_{0} @f$ :
7122  !! @f[ p_{rep} = p_{0} . @f]
7123  !! No debug interpolation plot is produced in such a degenerate case.
7124  p_reproduction = p_reproduction_baseline
7125  ! @warning Calling LOG_DBG precludes making this function **pure**.
7126  call log_dbg(ltag_info // " No same-sex conspecifics in " // &
7127  "perception, return baseline: " // &
7128  tostr(p_reproduction), procname, modname)
7129  else check_calcp
7130  delta_mass = &
7131  within( this%get_mass() / &
7132  (sum_mass_samesex / real(n_same_sex_perception, srp)), &
7133  minval(probability_reproduction_delta_mass_abscissa), &
7134  maxval(probability_reproduction_delta_mass_abscissa) &
7135  )
7136  !> The @f$ \Phi(\Delta \overline{m_{i}}) @f$ function itself is obtained
7137  !! from a nonlinear interpolation of grid values defined by the parameter
7138  !! arrays `commondata::probability_reproduction_delta_mass_abscissa` and
7139  !! `commondata::probability_reproduction_delta_mass_ordinate`.
7140  !! @image html img_doxy_reprod_prob.svg
7141  !! @image latex img_doxy_reprod_prob.eps "Relationship between body mass ratio and probability of reproduction" width=14cm
7142  !! So the **final reproduction probability** value is obtained by
7143  !! multiplication of the baseline value by the @f$ \Phi @f$ function.
7144  !! The final probability of reproduction value is limited to lie
7145  !! within the range @f$ 0 \leq p_{rep} \leq 1 \cdot \varphi @f$.
7146  p_reproduction &
7147  = within( &
7148  p_reproduction_baseline * &
7149  ddpinterpol(probability_reproduction_delta_mass_abscissa, &
7150  probability_reproduction_delta_mass_ordinate, &
7151  delta_mass), &
7152  0.0_srp, weight_baseline_here )
7153  ! @warning Calling LOG_DBG precludes making this function **pure**.
7154  call log_dbg(ltag_info // &
7155  " P reproduction: " // tostr(p_reproduction) // &
7156  ", average mass ratio of same sex " // &
7157  "conspecifics in percept: " // tostr(delta_mass) // &
7158  ", N of same-sex conspecifics: " // &
7159  tostr(n_same_sex_perception) // &
7160  ", N of opposite-sex conspecifics: " // &
7161  tostr(n_opposite_sex_perception) // &
7162  ", baseline P reproduction: " // &
7163  tostr(p_reproduction_baseline), procname, modname)
7164 
7165  !> Interpolation plots can be saved in the @ref intro_debug_mode
7166  !! "debug mode" using this plotting command:
7167  !! commondata::debug_interpolate_plot_save().
7168  ! @warning Calling `debug_interpolate_plot_save` here precludes making
7169  ! this function **pure** and **elemental**. Comment-out upon
7170  ! full testing and debugging!
7171  call debug_interpolate_plot_save( &
7172  grid_xx=probability_reproduction_delta_mass_abscissa, &
7173  grid_yy=probability_reproduction_delta_mass_ordinate, &
7174  ipol_value=delta_mass, &
7175  algstr="DDPINTERPOL", &
7176  output_file="plot_debug_reproduction_probability_" // &
7177  tostr(global_time_step_model_current) // &
7178  mmdd // "_a_"// trim(this%individ_label()) // "_" // &
7179  rand_string(label_length, label_cst,label_cen) // ps )
7180 
7181  end if check_calcp
7182 
7184 
7185  !-----------------------------------------------------------------------------
7186  !> @brief Determine a stochastic outcome of **this** agent reproduction.
7187  !! Returns TRUE if the agent has reproduced successfully.
7188  !! @param[in] prob optional fixed probability of reproduction to override.
7189  !! @return TRUE if reproduction is successful.
7190  !! @warning This function cannot be made elemental/pure due to random
7191  !! number call.
7192  function reproduction_success_stochast(this, prob) result (success)
7193  class(appraisal), intent(in) :: this ! This actor agent.
7194  ! @param[in] prob fixed probability of reproduction.
7195  real(srp), optional, intent(in) :: prob
7196  ! return@ TRUE if reproduction is actually successful.
7197  logical :: success
7198 
7199  ! Local copy of `prob` parameter.
7200  real(srp) :: prob_here
7201 
7202  ! PROCNAME is the procedure name for logging and debugging (with MODNAME).
7203  character(len=*), parameter :: procname="(reproduction_success_stochast)"
7204 
7205  success = .false. ! Init to FALSE.
7206 
7207  !> ### Implementation details ###
7208  !> Check if `prob` is present, if not, the probability of reproduction is
7209  !! calculated based on the perception objects of the actor agent `this`
7210  !! using the `probability_reproduction()` method.
7211  if (present(prob)) then
7212  prob_here = prob
7213  else
7214  prob_here = this%probability_reproduction()
7215  end if
7216 
7217  !> Determine the reproduction success stochastically based on the
7218  !! probability of repriduction (`prob_here`) value.
7219  if ( rand_r4() < prob_here ) success = .true.
7220 
7221  end function reproduction_success_stochast
7222 
7223  !-----------------------------------------------------------------------------
7224  !> Add emotional components into the memory stack.
7225  elemental subroutine emotional_memory_add_to_stack(this, &
7226  v_hunger, v_defence_fear, v_reproduction, &
7227  v_gos_label, v_gos_arousal, v_gos_repeated )
7228 
7229  class(memory_emotional), intent(inout) :: this !> This memory object.
7230 
7231  !> The parameters of the subroutine are the actual values that are added
7232  !! to the emotional memory stack arrays.
7233  !! @param[in] v_hunger value for hunger;
7234  !! @param[in] v_defence_fear value for fear state;
7235  !! @param[in] v_reproduction value for reproduction;
7236  !! @param[in] v_gos_label value for GOS label;
7237  !! @param[in] v_gos_arousal value for GOS arousal value;
7238  !! @param[in] v_gos_repeated value for repeated counter for GOS.
7239  real(srp), intent(in) :: v_hunger
7240  real(srp), intent(in) :: v_defence_fear
7241  real(srp), intent(in) :: v_reproduction
7242  character(*), optional, intent(in) :: v_gos_label
7243  real(srp), optional, intent(in) :: v_gos_arousal
7244  integer, optional, intent(in) :: v_gos_repeated
7245 
7246  !> Each of the memory stack components corresponds to the respective
7247  !! dummy parameter. These arrays are updated at each step (mandatory
7248  !! procedure arguments):
7249  !! - v_hunger
7250  !! - v_defence_fear
7251  !! - v_reproduction
7252  call add_to_history( this%hunger, v_hunger )
7253  call add_to_history( this%defence_fear, v_defence_fear )
7254  call add_to_history( this%reproduction, v_reproduction )
7255 
7256  !> However, GOS parameters are optional and updated only if provided for
7257  !! invocation of this method (optional arguments):
7258  !! - v_gos_label;
7259  !! - v_gos_arousal;
7260  !! - v_gos_repeated.
7261  if (present(v_gos_label)) &
7262  call add_to_history( this%gos_main, v_gos_label )
7263  if (present(v_gos_arousal)) &
7264  call add_to_history( this%gos_arousal, v_gos_arousal )
7265  if (present(v_gos_repeated)) &
7266  call add_to_history( this%gos_repeated, v_gos_repeated )
7267 
7268  end subroutine emotional_memory_add_to_stack
7269 
7270  !-----------------------------------------------------------------------------
7271  !> Add the current GOS label or/and arousal value and/or arousal repeat
7272  !! count into the emotional memory stack.
7273  elemental subroutine emotional_memory_add_gos_to_stack(this, v_gos_label, &
7274  v_gos_arousal, v_gos_repeated )
7275  class(memory_emotional), intent(inout) :: this
7276  !> @param[in] v_gos_label Text label for the current GOS.
7277  character(*), optional, intent(in) :: v_gos_label
7278  !> @param[in] v_gos_arousal The maximum motivation (arousal) value for the
7279  !! current GOS.
7280  real(srp), optional, intent(in) :: v_gos_arousal
7281  !> @param[in] v_gos_repeated
7282  integer, optional, intent(in) :: v_gos_repeated
7283 
7284  !> ### Implementation notes ###
7285  !> GOS label is added to the memory stack.
7286  if (present(v_gos_label)) call add_to_history( this%gos_main, v_gos_label )
7287 
7288  !> GOS arousal is added to the memory stack.
7289  if (present(v_gos_arousal)) &
7290  call add_to_history( this%gos_arousal, v_gos_arousal )
7291 
7292  !> The GOS repeated counter (gos_repeated) is added to the memory stack.
7293  if (present(v_gos_repeated)) &
7294  call add_to_history( this%gos_repeated, v_gos_repeated )
7295 
7296  end subroutine emotional_memory_add_gos_to_stack
7297 
7298  !-----------------------------------------------------------------------------
7299  !> Cleanup and destroy the emotional memory stack.
7300  elemental subroutine emotional_memory_cleanup_stack(this)
7301 
7302  class(memory_emotional), intent(inout) :: this !> This memory object.
7303 
7304  !> cleanup procedure uses whole array assignment to the
7305  !! commondata::missing values.
7306  this%hunger = missing
7307  this%defence_fear = missing
7308  this%reproduction = missing
7309  this%gos_main = ""
7310  this%gos_arousal = missing
7311  this%gos_repeated = unknown
7312 
7313  end subroutine emotional_memory_cleanup_stack
7314 
7315  !-----------------------------------------------------------------------------
7316  !> Get the average value of the hunger motivation state within the
7317  !! whole emotional memory stack.
7318  elemental function emotional_memory_hunger_get_mean (this, last) &
7319  result(mean_value)
7320  class(memory_emotional), intent(in) :: this
7321  !> @returns Total count of predators in the memory stack.
7322  real(srp) :: mean_value
7323  !> @param last Limit to only this number of latest components in the
7324  !! history.
7325  integer, optional, intent(in) :: last
7326 
7327  ! Local copy of optional last
7328  integer :: last_here
7329 
7330  ! History stack size. We determine it from the size of the actual array
7331  ! rather than `HISTORY_SIZE_MOTIVATION` for further safety.
7332  integer, parameter :: hist_size = size(this%hunger)
7333 
7334  !> ### Implementation notes ###
7335  !> - Check if we are given the parameter requesting the latest history size.
7336  !! If the `last` parameter is absent or bigger than the array size,
7337  !! get the whole stack array.
7338  if (present(last)) then
7339  if ( last < hist_size ) then
7340  last_here = last
7341  else
7342  last_here = hist_size
7343  end if
7344  else
7345  last_here = hist_size
7346  end if
7347 
7348  !> - Calculate the average excluding missing values (masked) within the
7349  !! subarray of interest.
7350  !! .
7351  mean_value = average( this%hunger( hist_size-last_here+1:hist_size ), &
7352  undef_ret_null=.true. )
7353 
7355 
7356  !-----------------------------------------------------------------------------
7357  !> Get the average value of the fear state motivation state within the
7358  !! whole emotional memory stack.
7359  elemental function emotional_memory_actve_avoid_get_mean (this, last) &
7360  result(mean_value)
7361  class(memory_emotional), intent(in) :: this
7362  !> @returns Total count of predators in the memory stack.
7363  real(srp) :: mean_value
7364  !> @param last Limit to only this number of latest components in the
7365  !! history.
7366  integer, optional, intent(in) :: last
7367 
7368  ! Local copy of optional last
7369  integer :: last_here
7370 
7371  ! History stack size. We determine it from the size of the actual array
7372  ! rather than `HISTORY_SIZE_MOTIVATION` for further safety.
7373  integer, parameter :: hist_size = size(this%defence_fear)
7374 
7375  !> ### Implementation notes ###
7376  !> - Check if we are given the parameter requesting the latest history size.
7377  !! if the `last` parameter is absent or bigger than the array size, get
7378  !! the whole stack array.
7379  if (present(last)) then
7380  if ( last < hist_size ) then
7381  last_here = last
7382  else
7383  last_here = hist_size
7384  end if
7385  else
7386  last_here = hist_size
7387  end if
7388 
7389  !> - Calculate the average excluding missing values (masked) within the
7390  !! subarray of interest.
7391  !! .
7392  mean_value = average( &
7393  this%defence_fear( hist_size-last_here+1:hist_size ), &
7394  undef_ret_null=.true. )
7395 
7397 
7398  !-----------------------------------------------------------------------------
7399  !> Get the average value of the reproductive motivation state within the
7400  !! whole emotional memory stack.
7401  elemental function emotional_memory_reproduct_get_mean (this, last) &
7402  result(mean_value)
7403  class(memory_emotional), intent(in) :: this
7404  !> @returns Total count of predators in the memory stack.
7405  real(srp) :: mean_value
7406  !> @param last Limit to only this number of latest components in the
7407  !! history.
7408  integer, optional, intent(in) :: last
7409 
7410  ! Local copy of optional last
7411  integer :: last_here
7412 
7413  ! History stack size. We determine it from the size of the actual array
7414  ! rather than `HISTORY_SIZE_MOTIVATION` for further safety.
7415  integer, parameter :: hist_size = size(this%reproduction)
7416 
7417  !> ### Implementation notes ###
7418  !> - Check if we are given the parameter requesting the latest history size.
7419  !! if the `last` parameter is absent or bigger than the array size, get
7420  !! the whole stack array.
7421  if (present(last)) then
7422  if ( last < hist_size ) then
7423  last_here = last
7424  else
7425  last_here = hist_size
7426  end if
7427  else
7428  last_here = hist_size
7429  end if
7430 
7431  !> - Calculate the average excluding missing values (masked) within the
7432  !! subarray of interest.
7433  !! .
7434  mean_value = average( &
7435  this%reproduction( hist_size-last_here+1:hist_size ), &
7436  undef_ret_null=.true. )
7437 
7439 
7440  !-----------------------------------------------------------------------------
7441  !> Get the average value of the GOS arousal within the whole emotional
7442  !! memory stack.
7443  elemental function emotional_memory_arousal_mean (this, last) &
7444  result(mean_value)
7445  class(memory_emotional), intent(in) :: this
7446  !> @returns Total count of predators in the memory stack.
7447  real(srp) :: mean_value
7448  !> @param last Limit to only this number of latest components in the
7449  !! history.
7450  integer, optional, intent(in) :: last
7451 
7452  ! Local copy of optional last
7453  integer :: last_here
7454 
7455  ! History stack size. We determine it from the size of the actual array
7456  ! rather than `HISTORY_SIZE_MOTIVATION` for further safety.
7457  integer, parameter :: hist_size = size(this%gos_arousal)
7458 
7459  !> ### Implementation notes ###
7460  !> - Check if we are given the parameter requesting the latest history size.
7461  !! If the `last` parameter is absent or bigger than the array size, get
7462  !! the whole stack array.
7463  if (present(last)) then
7464  if ( last < hist_size ) then
7465  last_here = last
7466  else
7467  last_here = hist_size
7468  end if
7469  else
7470  last_here = hist_size
7471  end if
7472 
7473  !> - Calculate the average excluding missing values (masked) within the
7474  !! subarray of interest.
7475  !! .
7476  mean_value = average( &
7477  this%gos_arousal( hist_size-last_here+1:hist_size ), &
7478  undef_ret_null=.true. )
7479 
7480  end function emotional_memory_arousal_mean
7481 
7482  !-----------------------------------------------------------------------------
7483  !> Find and set the **Global Organismic State (GOS)** of the agent based on
7484  !! the various available motivation values. The motivation values linked with
7485  !! the different stimuli compete with the current GOS and among themselves.
7486  !! ### General principle ###
7487  !! The GOS competition threshold is a function of the current GOS arousal
7488  !! level: if it is very low, it would be very difficult to switch to a
7489  !! different GOS. However, if the current GOS has a high arousal, then
7490  !! switching to a competing motivation is relatively easy: a very small
7491  !! motivational surplus is enough for winning the competition with the
7492  !! current GOS.
7493  !! @image html img_doxy_aha2-gos-threshold.svg
7494  !! @image latex img_doxy_aha2-gos-threshold.eps "Global organismcs state" width=14cm
7495  !! @note GOS generation is a little changed in the new generation model.
7496  !! 1. We try to avoid constant switching of the GOS by requiring that
7497  !! the difference between motivational components should exceed
7498  !! some threshold value, if it does not, retain old GOS. So minor
7499  !! fluctuations in the stimulus field are ignored. Threshold is
7500  !! a dynamic parameter, so can also be zero.
7501  !! 2. The threshold is inversely related to the absolute value of the
7502  !! motivations compared, when the motivations are low, the
7503  !! threshold is big, when their values are approaching 1, the
7504  !! threshold approaches zero. So motivations have relatively little
7505  !! effects.
7506  subroutine gos_find_global_state(this)
7507  class(gos_global), intent(inout) :: this
7509  !> ### Implementation details ###
7510  !! #### Notable class data members ####
7511  !! **Public attribute of the `GOS_GLOBAL` class: `gos_arousal`** keeps the
7512  !! current level of the GOS arousal (*A*, see below). If GOS does
7513  !! switch as a result of competition with the other motivational states,
7514  !! it gets the value of its *winning* (maximum) motivation, if GOS does
7515  !! not switch as a result of competition, the `gos_arousal` value
7516  !! dissipates spontaneously to a lower value and the `gos_repeated`
7517  !! attribute of `GOS_GLOBAL` gets the successive number of repetitions
7518  !! of the same out of competition GOS state.
7519  !! #### Notable local variables ####
7520  !! **Local variable: `arousal_new`** is the maximum level of motivation
7521  !! among all new incoming motivations *A*. It is this motivation
7522  !! value that competes with the current GOS arousal value (*G*
7523  !! the `gos_arousal` public attribute of the `GOS_GLOBAL` class).
7524  real(SRP) :: arousal_new
7525 
7526  !> **Local variable `gos_dthreshold`** is a dynamic threshold
7527  !! factor for GOS change @f$ \Delta @f$ (see below). It determines the
7528  !! threshold that a new competing motivation has to exceed to win the
7529  !! competition with the previous (and still current up to this point)
7530  !! motivation.
7531  real(SRP) :: gos_dthreshold
7532 
7533  ! PROCNAME is the procedure name for logging and debugging (with MODNAME).
7534  character(len=*), parameter :: PROCNAME = "(gos_find_global_state)"
7535 
7536  ! *Arousal* is the maximum level among all available motivations (**final**
7537  ! motivational components). This is the **new** state depending on all
7538  ! the currently incoming perceptions.
7539  arousal_new = this%motivations%max_final()
7540 
7541  call log_dbg( ltag_info // "Current GOS arousal: " // &
7542  tostr(this%gos_arousal), procname, modname )
7543  call log_dbg( ltag_info // "Motivations (final) array: " // &
7544  tostr([ this%motivations%hunger%motivation_finl, &
7545  this%motivations%fear_defence%motivation_finl, &
7546  this%motivations%reproduction%motivation_finl ]), &
7547  procname, modname )
7548  call log_dbg( ltag_info // "Arousal max (compet): " // tostr(arousal_new),&
7549  procname, modname )
7550 
7551  !> #### GOS competition ####
7552  !> The GOS competition threshold is a function of the current GOS arousal
7553  !! level @f$ G @f$: if it is very low, we need a relatively high competing
7554  !! motivation to win competition, if it is high then very small difference
7555  !! is enough. The global organismic state will switch to a competing state
7556  !! only if its maximum motivation @f$ A @f$ exceeds the current GOS's
7557  !! arousal level @f$ G @f$ by more than @f$ \Delta @f$ units of @f$ G @f$:
7558  !! @f[ A - G > \Delta \cdot G . @f]
7559  !! Here the @f$ \Delta @f$ threshold factor is set by a nonparametric
7560  !! function that is calculated from nonlinear interpolation of the grid
7561  !! values:
7562  !! @image html img_doxy_aha-gos-delta.svg
7563  !! @image latex img_doxy_aha-gos-delta.eps "GOS competition threshold factor" width=14cm
7564  !! So if the agent currently has a low GOS arousal *G*=0.1, it requires a
7565  !! competing state to be at least *A*=0.155 to win (with @f$ \Delta @f$
7566  !! =0.55, 0.155 = 0.1 + 0.1 * 0.55). However, if the agent has a high GOS
7567  !! motivation *G*=0.8, almost any exceeding motivation (>0.808) will win.
7568  !! The actual value of the nonparametric interpolation function are
7569  !! obtained by nonlinear interpolation of the grid values
7570  !! defined by the `MOTIVATION_COMPET_THRESHOLD_CURVE_` parameter arrays.
7571  !! @note In this implementation, the exact **type** of the competing
7572  !! motivation is not considered in the GOS competition procedure.
7573  !! For example, The current hunger GOS competes with all motivations,
7574  !! including itself. Consider an agent that is starving and has
7575  !! a high level of hunger GOS. At each step this hunger competes
7576  !! with all other motivations, including hunger. If hunger continues
7577  !! to increase, still, at many time steps, the new level of hunger
7578  !! can outcompete the current hunger and GOS switches from hunger
7579  !! to ... hunger. There can also be situations when current GOS
7580  !! hunger wins competition from all other motivations several times,
7581  !! dissipates and then is outcompeted by hunger again, that would
7582  !! lead to a relatively long streak of the same GOS. This mechanism
7583  !! would preclude switching out of (and losing) a continuously high
7584  !! but still appropriate motivational state.
7585  gos_dthreshold = ddpinterpol( motivation_compet_threshold_curve_abscissa, &
7586  motivation_compet_threshold_curve_ordinate, &
7587  this%gos_arousal )
7588 
7589  call log_dbg( ltag_info // "GOS threshold from interpolation: " // &
7590  tostr(gos_dthreshold), procname, modname )
7591 
7592  !> The interpolation plots are saved in the @ref intro_debug_mode
7593  !! "debug mode" to a disk file using an external command by the
7594  !! `commondata::debug_interpolate_plot_save()` procedure.
7595  !! @warning Enabling plotting can produce a **huge** number of plots and
7596  !! should normally be disabled.
7597  call debug_interpolate_plot_save( &
7598  grid_xx=motivation_compet_threshold_curve_abscissa, &
7599  grid_yy=motivation_compet_threshold_curve_ordinate, &
7600  ipol_value=this%gos_arousal, algstr="DDPINTERPOL", &
7601  output_file="plot_debug_arousal_gos_threshold_" // &
7602  tostr(global_time_step_model_current) // &
7603  mmdd // "_a_"// trim(this%individ_label()) // &
7604  "_" // rand_string(label_length, label_cst,label_cen) &
7605  // ps )
7606 
7607  !> Once the dynamic threshold is calculated, we can compare each of the
7608  !! competing motivation levels with the current arousal. If the maximum
7609  !! value of these motivations exceeds the current arousal by more than the
7610  !! threshold @f$ \Delta @f$ factor, the GOS switches to the new motivation.
7611  !! If not, we are still left with the previous GOS.
7612  arousal_threshold: if (arousal_new - this%gos_arousal < &
7613  gos_dthreshold * this%gos_arousal) then
7614  !> ##### Threshold not exceeded #####
7615  !> If the maximum competing motivation does not exceed the threshold,
7616  !! we are left with the old GOS. However, we reduce the current arousal
7617  !! spontaneously using a simple linear or some non-linear dissipation
7618  !! pattern using the \%gos_repeated parameter that sets the number of
7619  !! repeated occurrences of the same (current) GOS.
7620  !! First, increment GOS repeat counter.
7621  this%gos_repeated = this%gos_repeated + 1
7622  !> And spontaneously decrease, **dissipate**, the current arousal level.
7623  !! Spontaneous dissipation of arousal is implemented by multiplying the
7624  !! current level by a factor within the range [0.0..1.0] that can depend
7625  !! on the number of times this GOS is repeated.
7626  !! @note Note that the dissipation function is local to this procedure.
7627  !! `arousal_decrease_factor_fixed` = fixed value
7628  !! `arousal_decrease_factor_nonpar` = nonlinear, nonparametric,
7629  !! based on nonlinear interpolation.
7630  !! @plot `aha_gos_arousal_dissipation.svg`
7631  !! @note Can use either `arousal_decrease_factor_fixed` or
7632  !! `arousal_decrease_factor_nonpar`.
7633  this%gos_arousal = this%gos_arousal * &
7634  arousal_decrease_factor_fixed(this%gos_repeated)
7635  call log_dbg( ltag_info // "Threshold not exceeded, " // &
7636  "GOS repeated incremented to: " // &
7637  tostr(this%gos_repeated), procname, modname )
7638  else arousal_threshold
7639  !> ##### Threshold is exceeded #####
7640  !> If the maximum competing motivation exceeds the threshold, we get to a
7641  !! **new GOS**. That is, the **highest** among the competing
7642  !! motivations defines the new GOS.
7643  ! @note Use `associate` construct to set alias for long object hierarchy.
7644  !> @note Note that `gos_repeated` is initialised to 1.0 at
7645  !! `gos_reset`.
7646  associate( mot => this%motivations )
7647  !> ### Check **hunger** ###
7648  gos_is_max: if (mot%is_max_final(mot%hunger)) then
7649  !> Reset all motivations to *non-dominant*.
7650  call this%gos_reset()
7651  !> Set new GOS for hunger...
7652  mot%hunger%dominant_state = .true.
7653  this%gos_main = mot%hunger%label
7654  this%gos_arousal = mot%hunger%motivation_finl
7655  !> ### Check **fear_defence** ###
7656  else if (mot%is_max_final(mot%fear_defence)) then gos_is_max
7657  !> Reset all motivations to *non-dominant*.
7658  call this%gos_reset()
7659  !> Set new GOS for fear_defence...
7660  mot%fear_defence%dominant_state = .true.
7661  this%gos_main = mot%fear_defence%label
7662  this%gos_arousal = mot%fear_defence%motivation_finl
7663  !> ### Check **reproduction** ###
7664  else if (mot%is_max_final(mot%reproduction)) then gos_is_max
7665  !> Reset all motivations to *non-dominant*.
7666  call this%gos_reset()
7667  !> Set new GOS for reproduction...
7668  mot%reproduction%dominant_state = .true.
7669  this%gos_main = mot%reproduction%label
7670  this%gos_arousal = mot%reproduction%motivation_finl
7671  end if gos_is_max
7672  end associate
7673  call log_dbg( ltag_info // "Threshold exceeded, arousal: " // &
7674  tostr(this%gos_arousal) // ", label: " // &
7675  this%gos_main, procname, modname )
7676  end if arousal_threshold
7677 
7678  !> #### Other finalising procedures ####
7679  !! Add the current GOS parameters to the emotional memory stack
7680  !! @note Note that the memory stack arrays are defined in
7681  !! APPRAISAL and cleaned/init in `init_appraisal`
7682  ! @note We can use the dedicated procedures. Here disabled so far to avoid
7683  ! a small speed overhead.
7684  ! @code{.unparsed}
7685  ! call this%memory_motivations%gos_to_memory( &
7686  ! v_gos_label=this%gos_main, &
7687  ! v_gos_arousal= this%gos_arousal, &
7688  ! v_gos_repeated=this%gos_repeated )
7689  ! @endcode
7690  call add_to_history(this%memory_motivations%gos_main, this%gos_main)
7691  call add_to_history(this%memory_motivations%gos_arousal, this%gos_arousal)
7692  call add_to_history(this%memory_motivations%gos_repeated, this%gos_repeated)
7693 
7694  !> Finally recalculate the attention weights for all the states' perception
7695  !! components using attention_modulate(). The dominant GOS state will now
7696  !! get its default attention weights whereas all non-dominant states will
7697  !! get modulated values, i.e. values recalculated from a non-linear
7698  !! interpolation based **attention modulation curve**.
7699  call this%attention_modulate()
7700 
7701  contains ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
7702 
7703  !- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
7704  !> ### Fixed spontaneous arousal dissipation factor ###
7705  !! At each step, `gos_arousal` is reduced by a constant factor,
7706  !! `AROUSAL_GOS_DISSIPATION_FACTOR` (e.g. reduced by 0.5)
7707  !! independently on the current GOS time step.
7708  !! TODO: make dependent on the genome.
7709  pure function arousal_decrease_factor_fixed (time_step) &
7710  result(arousal_factor)
7711  !> @param[in] time_step The number of repetitions of the same GOS.
7712  !! @note Note that the `time_step` dummy parameter is **not used** in
7713  !! calculations here. But it is still present as an optional
7714  !! parameter for compatibility with the other possible dissipation
7715  !! pattern functions that can really depend on the time GOS repeat
7716  !! step.
7717  integer, optional, intent(in) :: time_step
7718  !> @returns Arousal dissipation factor.
7719  real(srp) :: arousal_factor
7720 
7721  !> At each GOS step the `gos_arousal` is reduced by the factor
7722  !! `AROUSAL_GOS_DISSIPATION_FACTOR` that is **independent** of
7723  !! the `time_step`.
7724  arousal_factor = arousal_gos_dissipation_factor
7725 
7726  end function arousal_decrease_factor_fixed
7727 
7728  !- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
7729  !> ### Nonparametric spontaneous arousal dissipation pattern ###
7730  !! @details Here the arousal dissipation factor is defined by a
7731  !! function of the GOS repeated time step based on polynomial
7732  !! or linear interpolation over a grid defined by
7733  !! `AROUSAL_GOS_DISSIPATION_NONPAR_ABSCISSA` (X) and
7734  !! `AROUSAL_GOS_DISSIPATION_NONPAR_ORDINATE` (Y).
7735  !! For example, multiplied by 0.9 at the first time step,
7736  !! 0.5 at the 10s step, 0.7 at 20s step.
7737  !! TODO: make dependent on the genome.
7738  !! @param[in] time_step The number of repetitions of the same GOS.
7739  !! @returns Arousal dissipation factor. In this version, arousal
7740  !! dissipation factor is determined by a nonlinear
7741  !! interpolation-based function.
7742  !! @image html img_doxygen_dissipate_nonpar.svg
7743  !! @image latex img_doxygen_dissipate_nonpar.eps "Nonparametric spontaneous arousal dissipation function" width=14cm
7744  !! @n
7745  !! Save Interpolation plot:
7746  !! @code
7747  !! htintrpl.exe [ 1.0, 2.00, 5.00, 10.0, 15.0, 18.0, 20.0 ] \
7748  !! [ 1.0, 0.98, 0.80, 0.40, 0.22, 0.18, 0.17 ] [2] \
7749  !! [img_doxygen_dissipate_nonpar.ps]
7750  !! @endcode
7751  function arousal_decrease_factor_nonpar(time_step) &
7752  result(arousal_factor)
7753  ! @param[in] time_step The number of repetitions of the same GOS.
7754  integer, intent(in) :: time_step
7755  ! @returns Arousal dissipation factor. In this version, arousal
7756  ! dissipation factor is determined by a nonlinear
7757  ! interpolation-based function.
7758  real(srp) :: arousal_factor
7759 
7760  arousal_factor = ddpinterpol( &
7761  arousal_gos_dissipation_nonpar_abscissa, &
7762  arousal_gos_dissipation_nonpar_ordinate, &
7763  real(time_step, srp) )
7764 
7765  !> Interpolation plots can be saved in the @ref intro_debug_mode
7766  !! "debug mode" using this plotting command:
7767  !! commondata::debug_interpolate_plot_save().
7768  !! @warning Disabling the plot output allows the function to be declared
7769  !! as **pure** with all the benefits.
7770  call debug_interpolate_plot_save( &
7771  grid_xx=arousal_gos_dissipation_nonpar_abscissa, &
7772  grid_yy=arousal_gos_dissipation_nonpar_ordinate, &
7773  ipol_value=real(time_step, srp), algstr="DDPINTERPOL", &
7774  output_file="plot_debug_arousal_dissipation_factor_" // &
7775  tostr(global_time_step_model_current) // &
7776  mmdd // "_a_"// trim(this%individ_label()) // "_" // &
7777  rand_string(label_length, label_cst,label_cen) // ps )
7778 
7779  end function arousal_decrease_factor_nonpar
7780 
7781  end subroutine gos_find_global_state
7782 
7783  !> Initialise GOS engine components to a zero state. The values are set to
7784  !! commondata::missing, commondata::unknown, string to "undefined".
7785  elemental subroutine gos_init_zero_state(this)
7786  class(gos_global), intent(inout) :: this
7788  this%gos_main = "undefined"
7789  !> @note the GOS arousal value is initialised to commondata::missing,
7790  !! which is a big negative value. Therefore, any competing motivation
7791  !! initially wins in the the_neurobio::gos_find_global_state()
7792  !! procedure. There seems to be no sense initialising arousal to 0.0.
7793  this%gos_arousal = missing
7794  this%gos_repeated = unknown
7795 
7796  end subroutine gos_init_zero_state
7797 
7798  !-----------------------------------------------------------------------------
7799  !> Set the individual to be **dead**. Note that this function does not
7800  !! deallocate the individual agent object, this may be a separate destructor
7801  !! function.
7802  !!
7803  !! The `dies` method is implemented at the following levels
7804  !! of the agent object hierarchy (upper overrides the lower level):
7805  !! - the_genome::individual_genome::dies();
7806  !! - the_neurobio::appraisal::dies();
7807  !! - the_neurobio::gos_global::dies();
7808  !! - the_individual::individual_agent::dies().
7809  !! .
7810  !! @note This method overrides the the_genome::individual_genome::dies()
7811  !! method, nullifying all reproductive and neurobiological and
7812  !! behavioural objects.
7813  !! @note The `dies` method is implemented at the @ref gos_global to allow
7814  !! "cleaning" of all neurobiological objects when `dies` is called
7815  !! when performing the behaviours upwards in the object hierarchy.
7816  elemental subroutine gos_agent_set_dead(this)
7817  class(gos_global), intent(inout) :: this
7819  call this%set_dead() !> - Set the agent "dead";
7820  call this%init_reproduction() !> - emptify reproduction objects;
7821  call this%init_perception() !> - emptify all neurobiological objects.
7822  call this%init_appraisal() !> .
7823  call this%init_gos()
7824 
7825  end subroutine gos_agent_set_dead
7826 
7827  !-----------------------------------------------------------------------------
7828  !> Reset all motivation states as *not* dominant with respect to the GOS.
7829  !! @note This subroutine is used in the_neurobio::gos_find_global_state().
7830  elemental subroutine gos_reset_motivations_non_dominant(this)
7831  class(gos_global), intent(inout) :: this
7833  !> ### Implementation notes ###
7834  !> Reset dominant status to FALSE for all motivational states calling
7835  !! the the_neurobio::motivation::gos_ind_reset().
7836  call this%motivations%gos_ind_reset()
7837 
7838  !> Also reset the number of GOS repeated occurrences to 1.
7839  this%gos_repeated = 1
7840 
7841  end subroutine gos_reset_motivations_non_dominant
7842 
7843  !-----------------------------------------------------------------------------
7844  !> Get the current global organismic state (GOS).
7845  elemental function gos_global_get_label(this) result (return_gos)
7846  class(gos_global), intent(in) :: this
7848  !> @returns Global organismic state label.
7849  character(len=LABEL_LENGTH) :: return_gos
7850 
7851  !> Check which of the currently implemented motivational state
7852  !! components (`STATE_`) has the **dominant** flag. Can call
7853  !! motivation-type-bound function \%is_dominant().
7854  !! @note Only one component can be "dominant".
7855  ! TODO: consider several simultaneously overlapping GOSs. In
7856  ! such a case the function should return an array-based
7857  ! object.
7858  ! @note Note that type-bound functions can be used (although this makes
7859  ! sense only outside of this module to avoid a small function-call
7860  ! overhead): `if ( this%motivations%hunger%is_dominant() ) then`.
7861  ! For the motivational state label we can use the accessor
7862  ! function \%label_is :
7863  ! `return_gos = this%motivations%hunger%label_is()` (it is
7864  ! **mandatory** outside of this module as label is declared
7865  ! `private`).
7866  if (this%motivations%hunger%dominant_state) then
7867  return_gos = this%motivations%hunger%label
7868  else if (this%motivations%fear_defence%dominant_state) then
7869  return_gos = this%motivations%fear_defence%label
7870  else if (this%motivations%reproduction%dominant_state) then
7871  return_gos = this%motivations%reproduction%label
7872  end if
7873 
7874  end function gos_global_get_label
7875 
7876  !-----------------------------------------------------------------------------
7877  !> Get the overall level of arousal. Arousal is the current level
7878  !! of the dominant motivation that has brought about the current GOS at the
7879  !! previous time step.
7880  elemental function gos_get_arousal_level(this) result (arousal_out)
7881  class(gos_global), intent(in) :: this
7883  ! Arousal is the current level of motivation that has brought about GOS.
7884  real(srp) :: arousal_out
7885 
7886  ! It is saved in this GOS-object component.
7887  arousal_out = this%gos_arousal
7888 
7889  end function gos_get_arousal_level
7890 
7891  !-----------------------------------------------------------------------------
7892  !> Modulate the attention weights to suppress all perceptions alternative
7893  !! to the current GOS. This is done using the attention modulation
7894  !! interpolation curve.
7895  !! @warning This subroutine is called from within `gos_find()` and should
7896  !! normally **not** be called separately.
7897  subroutine gos_attention_modulate_weights(this)
7898  class(gos_global), intent(inout) :: this
7900  ! Local variable, the weight given to the attention weight components
7901  ! of all the non-dominant motivation states. Based on nonlinear
7902  ! interpolation.
7903  real(SRP) :: percept_w
7904 
7905  !- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
7906 
7907  !> ### Implementation details ###
7908  !> #### Overview ####
7909  !> Each of the perceptions is weighted by an attention factor. The
7910  !! attention factor is in turn modulated (weighted) by the current
7911  !! Global Organismic State (GOS). When the current arousal is relatively
7912  !! high, all irrelevant perceptions are effectively filtered out
7913  !! (weighted by near-zero) and do not (largely) contribute to the GOS
7914  !! at the *next* time step. For example, the agent just does not "see"
7915  !! food items when it is in a high fear state.
7916  !! @image html img_doxy_aha2-attention-modulation.svg
7917  !! @image latex img_doxy_aha2-attention-modulation.eps "Perception weights" width=14cm
7918  !!
7919  !! Thus, perception is weighted by the attention suppression factor
7920  !! separately for each motivational (emotional) state according to the
7921  !! scheme below:
7922  !! @image html aha_attention_modulate_weights.svg "Attention suppression"
7923  !! @image latex aha_attention_modulate_weights.eps "Attention suppression" width=10cm
7924  !! Also see @ref aha_buildblocks_cogn_arch "Cognitive architecture" section.
7925 
7926  !> #### Specific details ####
7927  !> **First**, we calculate the attention weight given to all non-dominant
7928  !! perceptions via nonlinear interpolation. Interpolation is based on the
7929  !! grid defined by two parameters: `ATTENTION_MODULATION_CURVE_ABSCISSA`
7930  !! and `ATTENTION_MODULATION_CURVE_ORDINATE`.
7931  !! @note Interpolation plot can be produced using this command, assuming
7932  !! the plotting tools are installed on the system.
7933  !! @verbatim
7934  !! htintrpl.exe [0.0, 0.3, 0.5, 1.0] [1.0, 0.98, 0.9, 0.0] [2]
7935  !! @endverbatim
7936  !>
7937  percept_w = ddpinterpol( attention_modulation_curve_abscissa, &
7938  attention_modulation_curve_ordinate, &
7939  this%gos_arousal )
7940 
7941  !> Interpolation plots can be saved in the @ref intro_debug_mode
7942  !! "debug mode" using this plotting command:
7943  !! commondata::debug_interpolate_plot_save().
7944  !! @warning Involves **huge** number of plots, should normally be
7945  !! disabled.
7946  call debug_interpolate_plot_save( &
7947  grid_xx=attention_modulation_curve_abscissa, &
7948  grid_yy=attention_modulation_curve_ordinate, &
7949  ipol_value=this%gos_arousal, algstr="DDPINTERPOL", &
7950  output_file="plot_debug_attention_modulation_" // &
7951  tostr(global_time_step_model_current) // &
7952  mmdd // "_a_"// trim(this%individ_label()) // &
7953  "_" // rand_string(label_length, label_cst,label_cen) &
7954  // ps )
7955 
7956  !- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
7957  !> **Second**, we reset the attention weights for the **dominant GOS
7958  !! state** to their **default** parameter values whereas for all other
7959  !! states, to the **recalculated** `percept_w` modulated/weighted
7960  !! value. The the_neurobio::percept_components_motiv::attention_init()
7961  !! method is used to adjust the attention weights.
7962  !- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
7963  ! The *dominant* state is **hunger**:
7964  reset_dominant: if ( this%motivations%hunger%is_dominant() ) then
7965 
7966  ! @note Dominant is **hunger**.
7967  call this%motivations%hunger%attention_weight%attention_init &
7968  (weight_light = attention_switch_hunger_light, &
7969  weight_depth = attention_switch_hunger_depth, &
7970  weight_food_dir = attention_switch_hunger_food_dir, &
7971  weight_food_mem = attention_switch_hunger_food_mem, &
7972  weight_conspec = attention_switch_hunger_conspec, &
7973  weight_pred_dir = attention_switch_hunger_pred_dir, &
7974  weight_predator = attention_switch_hunger_predator, &
7975  weight_stomach = attention_switch_hunger_stomach, &
7976  weight_bodymass = attention_switch_hunger_bodymass, &
7977  weight_energy = attention_switch_hunger_energy, &
7978  weight_age = attention_switch_hunger_age, &
7979  weight_reprfac = attention_switch_hunger_reprfac )
7980 
7981  call this%motivations%fear_defence%attention_weight%attention_init &
7982  (weight_light = attention_switch_avoid_act_light * percept_w, &
7983  weight_depth = attention_switch_avoid_act_depth * percept_w, &
7984  weight_food_dir = attention_switch_avoid_act_food_dir * percept_w, &
7985  weight_food_mem = attention_switch_avoid_act_food_mem * percept_w, &
7986  weight_conspec = attention_switch_avoid_act_conspec * percept_w, &
7987  weight_pred_dir = attention_switch_avoid_act_pred_dir * percept_w, &
7988  weight_predator = attention_switch_avoid_act_predator * percept_w, &
7989  weight_stomach = attention_switch_avoid_act_stomach * percept_w, &
7990  weight_bodymass = attention_switch_avoid_act_bodymass * percept_w, &
7991  weight_energy = attention_switch_avoid_act_energy * percept_w, &
7992  weight_age = attention_switch_avoid_act_age * percept_w, &
7993  weight_reprfac = attention_switch_avoid_act_reprfac * percept_w )
7994 
7995  call this%motivations%reproduction%attention_weight%attention_init &
7996  (weight_light = attention_switch_reproduce_light * percept_w, &
7997  weight_depth = attention_switch_reproduce_depth * percept_w, &
7998  weight_food_dir = attention_switch_reproduce_food_dir * percept_w, &
7999  weight_food_mem = attention_switch_reproduce_food_mem * percept_w, &
8000  weight_conspec = attention_switch_reproduce_conspec * percept_w, &
8001  weight_pred_dir = attention_switch_reproduce_pred_dir * percept_w, &
8002  weight_predator = attention_switch_reproduce_predator * percept_w, &
8003  weight_stomach = attention_switch_reproduce_stomach * percept_w, &
8004  weight_bodymass = attention_switch_reproduce_bodymass * percept_w, &
8005  weight_energy = attention_switch_reproduce_energy * percept_w, &
8006  weight_age = attention_switch_reproduce_age * percept_w, &
8007  weight_reprfac = attention_switch_reproduce_reprfac * percept_w )
8008 
8009  !- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
8010  ! The *dominant* state is **fear_defence**:
8011  else if ( this%motivations%fear_defence%is_dominant() ) then reset_dominant
8012 
8013  call this%motivations%hunger%attention_weight%attention_init &
8014  (weight_light = attention_switch_hunger_light * percept_w, &
8015  weight_depth = attention_switch_hunger_depth * percept_w, &
8016  weight_food_dir = attention_switch_hunger_food_dir * percept_w, &
8017  weight_food_mem = attention_switch_hunger_food_mem * percept_w, &
8018  weight_conspec = attention_switch_hunger_conspec * percept_w, &
8019  weight_pred_dir = attention_switch_hunger_pred_dir * percept_w, &
8020  weight_predator = attention_switch_hunger_predator * percept_w, &
8021  weight_stomach = attention_switch_hunger_stomach * percept_w, &
8022  weight_bodymass = attention_switch_hunger_bodymass * percept_w, &
8023  weight_energy = attention_switch_hunger_energy * percept_w, &
8024  weight_age = attention_switch_hunger_age * percept_w, &
8025  weight_reprfac = attention_switch_hunger_reprfac * percept_w )
8026 
8027  ! @note Dominant is **fear_defence**.
8028  call this%motivations%fear_defence%attention_weight%attention_init &
8029  (weight_light = attention_switch_avoid_act_light, &
8030  weight_depth = attention_switch_avoid_act_depth, &
8031  weight_food_dir = attention_switch_avoid_act_food_dir, &
8032  weight_food_mem = attention_switch_avoid_act_food_mem, &
8033  weight_conspec = attention_switch_avoid_act_conspec, &
8034  weight_pred_dir = attention_switch_avoid_act_pred_dir, &
8035  weight_predator = attention_switch_avoid_act_predator, &
8036  weight_stomach = attention_switch_avoid_act_stomach, &
8037  weight_bodymass = attention_switch_avoid_act_bodymass, &
8038  weight_energy = attention_switch_avoid_act_energy, &
8039  weight_age = attention_switch_avoid_act_age, &
8040  weight_reprfac = attention_switch_avoid_act_reprfac )
8041 
8042  call this%motivations%reproduction%attention_weight%attention_init &
8043  (weight_light = attention_switch_reproduce_light * percept_w, &
8044  weight_depth = attention_switch_reproduce_depth * percept_w, &
8045  weight_food_dir = attention_switch_reproduce_food_dir * percept_w, &
8046  weight_food_mem = attention_switch_reproduce_food_mem * percept_w, &
8047  weight_conspec = attention_switch_reproduce_conspec * percept_w, &
8048  weight_pred_dir = attention_switch_reproduce_pred_dir * percept_w, &
8049  weight_predator = attention_switch_reproduce_predator * percept_w, &
8050  weight_stomach = attention_switch_reproduce_stomach * percept_w, &
8051  weight_bodymass = attention_switch_reproduce_bodymass * percept_w, &
8052  weight_energy = attention_switch_reproduce_energy * percept_w, &
8053  weight_age = attention_switch_reproduce_age * percept_w, &
8054  weight_reprfac = attention_switch_reproduce_reprfac * percept_w )
8055 
8056  !- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
8057  ! The *dominant* state is **reproduction**:
8058  else if ( this%motivations%reproduction%is_dominant() ) then reset_dominant
8059 
8060  call this%motivations%hunger%attention_weight%attention_init &
8061  (weight_light = attention_switch_hunger_light * percept_w, &
8062  weight_depth = attention_switch_hunger_depth * percept_w, &
8063  weight_food_dir = attention_switch_hunger_food_dir * percept_w, &
8064  weight_food_mem = attention_switch_hunger_food_mem * percept_w, &
8065  weight_conspec = attention_switch_hunger_conspec * percept_w, &
8066  weight_pred_dir = attention_switch_hunger_pred_dir * percept_w, &
8067  weight_predator = attention_switch_hunger_predator * percept_w, &
8068  weight_stomach = attention_switch_hunger_stomach * percept_w, &
8069  weight_bodymass = attention_switch_hunger_bodymass * percept_w, &
8070  weight_energy = attention_switch_hunger_energy * percept_w, &
8071  weight_age = attention_switch_hunger_age * percept_w, &
8072  weight_reprfac = attention_switch_hunger_reprfac * percept_w )
8073 
8074  call this%motivations%fear_defence%attention_weight%attention_init &
8075  (weight_light = attention_switch_avoid_act_light * percept_w, &
8076  weight_depth = attention_switch_avoid_act_depth * percept_w, &
8077  weight_food_dir = attention_switch_avoid_act_food_dir * percept_w, &
8078  weight_food_mem = attention_switch_avoid_act_food_mem * percept_w, &
8079  weight_conspec = attention_switch_avoid_act_conspec * percept_w, &
8080  weight_pred_dir = attention_switch_avoid_act_pred_dir * percept_w, &
8081  weight_predator = attention_switch_avoid_act_predator * percept_w, &
8082  weight_stomach = attention_switch_avoid_act_stomach * percept_w, &
8083  weight_bodymass = attention_switch_avoid_act_bodymass * percept_w, &
8084  weight_energy = attention_switch_avoid_act_energy * percept_w, &
8085  weight_age = attention_switch_avoid_act_age * percept_w, &
8086  weight_reprfac = attention_switch_avoid_act_reprfac * percept_w )
8087 
8088  ! @note Dominant **reproduction**.
8089  call this%motivations%reproduction%attention_weight%attention_init &
8090  (weight_light = attention_switch_reproduce_light, &
8091  weight_depth = attention_switch_reproduce_depth, &
8092  weight_food_dir = attention_switch_reproduce_food_dir, &
8093  weight_food_mem = attention_switch_reproduce_food_mem, &
8094  weight_conspec = attention_switch_reproduce_conspec, &
8095  weight_pred_dir = attention_switch_reproduce_pred_dir, &
8096  weight_predator = attention_switch_reproduce_predator, &
8097  weight_stomach = attention_switch_reproduce_stomach, &
8098  weight_bodymass = attention_switch_reproduce_bodymass, &
8099  weight_energy = attention_switch_reproduce_energy, &
8100  weight_age = attention_switch_reproduce_age, &
8101  weight_reprfac = attention_switch_reproduce_reprfac )
8102 
8103  end if reset_dominant
8104 
8105  end subroutine gos_attention_modulate_weights
8106 
8107  !-----------------------------------------------------------------------------
8108  !> Calculate the number of food items in the perception object that are
8109  !! located **below** the actor agent.
8110  elemental function perception_food_items_below_calculate(this) &
8111  result(number_below)
8112  class(perception), intent(in) :: this
8113  !> @return The number of food items within the perception object that are
8114  !! located below (under) the actor agent.
8115  integer :: number_below
8116 
8117  !> ### Implementation details ###
8118  !> First, initialise the counter to zero.
8119  number_below = 0
8120 
8121  !> Then, check if the agent has any food items in the perception;
8122  !! if not, return zero straight away.
8123  if (.not. this%has_food()) then
8124  return
8125  end if
8126 
8127  !> From now on it is assumed that the agent has at least one food item
8128  !! in the perception object. Calculate food items within the
8129  !! perception that are *below* the agent.
8130  number_below = count( this%perceive_food%foods_seen .below. this )
8131 
8133 
8134  !-----------------------------------------------------------------------------
8135  !> Calculate the number of food items in the perception object that are
8136  !! located **below** the actor agent within a specific vertical horizon
8137  !! [hz_lower,hz_upper]. The horizon limits are relative, in that they start
8138  !! from the depth position of the `this` actor agent:
8139  !! [z+hz_lower, z+hz_upper].
8140  !! @image html aha_percept_food_up_lower.svg
8141  !! @image latex aha_percept_food_up_lower.eps "Calculation of food items above and below" width=8cm
8142  elemental function perception_food_items_below_horiz_calculate( this, &
8143  hz_lower, &
8144  hz_upper ) &
8145  result(number_below)
8146  class(perception), intent(in) :: this
8147  !> @param[in] hz_lower The upper limit for the vertical horizon
8148  real(srp), intent(in) :: hz_lower
8149  !> @param[in] hz_upper The lower limit for the vertical horizon
8150  real(srp), intent(in) :: hz_upper
8151  !> @return The number of food items within the perception object that are
8152  !! located below (under) the actor agent.
8153  integer :: number_below
8154 
8155  ! Local counter
8156  integer :: i
8157 
8158  !> ### Implementation details ###
8159  !> First, initialise the counter to zero.
8160  number_below = 0
8161 
8162  !> Then, check if the agent has any food items in the perception;
8163  !! if not, return zero straight away.
8164  if (.not. this%has_food()) then
8165  return
8166  end if
8167 
8168  !> From now on it is assumed that the agent has at least one food item
8169  !! in the perception object. Loop through the food items within the later
8170  !! and calculate the total number.
8171  do concurrent(i=1:this%perceive_food%get_count())
8172  ! Can use the operator .within.
8173  ! if ( this%perceive_food%foods_seen(i)%dpos() .within. &
8174  ! [this%dpos()+hz_lower, this%dpos()+hz_upper] ) then
8175  if ( is_within( this%perceive_food%foods_seen(i)%dpos(), &
8176  this%dpos() + hz_lower, &
8177  this%dpos() + hz_upper ) ) then
8178  number_below = number_below + 1
8179  end if
8180  end do
8181 
8183 
8184  !-----------------------------------------------------------------------------
8185  !> Calculate the average mass of a food item from all the items in the
8186  !! current perception object that are **below** the actor agent.
8187  elemental function perception_food_mass_below_calculate(this) &
8188  result(mean_mass_below)
8189  class(perception), intent(in) :: this
8190  !> @return Average mass of food items within the perception object that are
8191  !! located below (under) the actor agent.
8192  real(srp) ::mean_mass_below
8193 
8194  ! Local counters
8195  integer :: i, n_counter
8196 
8197  !> ### Implementation details ###
8198  !> First, initialise the return average mass and the counter
8199  !! for calculating the average both to zero.
8200  mean_mass_below = 0.0_srp
8201  n_counter = 0
8202 
8203  !> Then, check if the agent has any food items in the perception;
8204  !! if not, return zero straight away.
8205  if (.not. this%has_food()) then
8206  return
8207  end if
8208 
8209  !> From now on it is assumed that the agent has at least one food item
8210  !! in the perception object. Calculation of the average mass of the food
8211  !! items **below** is done by concurrent looping through the food items
8212  !! within the perception object.
8213  do concurrent(i=1:this%perceive_food%get_count())
8214  !> This is done by checking the condition:
8215  !! @verbatim
8216  !! if ( food_item .below. this ) ...
8217  !! @endverbatim
8218  !! @note This uses the user defined operator `.below.` that is
8219  !! implemented in `the_environment` module.
8220  if ( this%perceive_food%foods_seen(i) .below. this ) then
8221  !> The average mass of the food items is calculated using the food
8222  !! items mass values returned by the function `get_mass`
8223  !! (`the_environment::food_item::get_mass()`) .
8224  mean_mass_below = &
8225  mean_mass_below + this%perceive_food%foods_seen(i)%get_mass()
8226  n_counter = n_counter + 1
8227  end if
8228  end do
8229 
8230  !> Final average value is calculated, obviously, by division of the
8231  !! total mass by the total count. In case the count is zero, also
8232  !! return zero mean.
8233  if ( n_counter > 0 ) then
8234  mean_mass_below = mean_mass_below / real(n_counter, srp)
8235  else
8236  mean_mass_below = 0.0_srp
8237  end if
8238 
8240 
8241  !-----------------------------------------------------------------------------
8242  !> Calculate the average mass of a food item from all the items in the
8243  !! current perception object that are **below** the actor agent within a
8244  !! specific vertical horizon [hz_lower,hz_upper]. The horizon limits are
8245  !! relative, in that they start from the depth position of the `this` actor
8246  !! agent: [z+hz_lower, z+hz_upper].
8247  !! @image html aha_percept_food_up_lower.svg
8248  !! @image latex aha_percept_food_up_lower.eps "Calculation of food items above and below" width=8cm
8249  elemental function perception_food_mass_below_horiz_calculate(this, &
8250  hz_lower, &
8251  hz_upper ) &
8252  result(mean_mass_below)
8253  class(perception), intent(in) :: this
8254  !> @param[in] hz_lower The upper limit for the vertical horizon
8255  real(srp), intent(in) :: hz_lower
8256  !> @param[in] hz_upper The lower limit for the vertical horizon
8257  real(srp), intent(in) :: hz_upper
8258  !> @return Average mass of food items within the perception object that are
8259  !! located below (under) the actor agent.
8260  real(srp) ::mean_mass_below
8261 
8262  ! Local counters
8263  integer :: i, n_counter
8264 
8265  !> ### Implementation details ###
8266  !> First, initialise the return average mass and the counter
8267  !! for calculating the average both to zero.
8268  mean_mass_below = 0.0_srp
8269  n_counter = 0
8270 
8271  !> Then, check if the agent has any food items in the perception;
8272  !! if not, return zero straight away.
8273  if (.not. this%has_food()) then
8274  return
8275  end if
8276 
8277  !> From now on it is assumed that the agent has at least one food item
8278  !! in the perception object. Calculation of the average mass of the food
8279  !! items **below** is done by concurrent looping through the food items
8280  !! within the perception object.
8281  do concurrent(i=1:this%perceive_food%get_count())
8282  ! Can use the operator .within.
8283  ! if ( this%perceive_food%foods_seen(i)%dpos() .within. &
8284  ! [this%dpos()+hz_lower, this%dpos()+hz_upper] ) then
8285  if ( is_within( this%perceive_food%foods_seen(i)%dpos(), &
8286  this%dpos() + hz_lower, &
8287  this%dpos() + hz_upper ) ) then
8288  !> The average mass of the food items is calculated using the food
8289  !! items mass values returned by the function `get_mass`
8290  !! (`the_environment::food_item::get_mass()`) .
8291  mean_mass_below = &
8292  mean_mass_below + this%perceive_food%foods_seen(i)%get_mass()
8293  n_counter = n_counter + 1
8294  end if
8295  end do
8296 
8297  !> Final average value is calculated, obviously, by division of the
8298  !! total mass by the total count. In case the count is zero, also
8299  !! return zero mean.
8300  if ( n_counter > 0 ) then
8301  mean_mass_below = mean_mass_below / real(n_counter, srp)
8302  else
8303  mean_mass_below = 0.0_srp
8304  end if
8305 
8307 
8308  !-----------------------------------------------------------------------------
8309  !> Calculate the number of food items in the perception object that are
8310  !! located **above** the actor agent.
8311  elemental function perception_food_items_above_calculate(this) &
8312  result(number_above)
8313  class(perception), intent(in) :: this
8314  !> @return The number of food items within the perception object that are
8315  !! located above (over) the actor agent.
8316  integer :: number_above
8317 
8318  !> ### Implementation details ###
8319  !> First, initialise the counter to zero.
8320  number_above = 0
8321 
8322  !> Then, check if the agent has any food items in the perception;
8323  !! if not, return zero straight away.
8324  if (.not. this%has_food()) then
8325  return
8326  end if
8327 
8328  !> From now on it is assumed that the agent has at least one food item
8329  !! in the perception object. Calculate food items within the
8330  !! perception that are *above* the agent.
8331  number_above = count( this%perceive_food%foods_seen .above. this )
8332 
8334 
8335  !-----------------------------------------------------------------------------
8336  !> Calculate the number of food items in the perception object that are
8337  !! located **above** the actor agent within a specific vertical horizon
8338  !! [hz_lower,hz_upper]. The horizon limits are relative, in that they start
8339  !! from the depth position of the `this` actor agent:
8340  !! [z-hz_upper, z-hz_upper].
8341  !! @image html aha_percept_food_up_lower.svg
8342  !! @image latex aha_percept_food_up_lower.eps "Calculation of food items above and below" width=8cm
8343  elemental function perception_food_items_above_horiz_calculate( this, &
8344  hz_lower, &
8345  hz_upper ) &
8346  result(number_above)
8347  class(perception), intent(in) :: this
8348  !> @param[in] hz_lower The upper limit for the vertical horizon
8349  real(srp), intent(in) :: hz_lower
8350  !> @param[in] hz_upper The lower limit for the vertical horizon
8351  real(srp), intent(in) :: hz_upper
8352  !> @return The number of food items within the perception object that are
8353  !! located above (over) the actor agent.
8354  integer :: number_above
8355 
8356  ! Local counter
8357  integer :: i
8358 
8359  !> ### Implementation details ###
8360  !> First, initialise the counter to zero.
8361  number_above = 0
8362 
8363  !> Then, check if the agent has any food items in the perception;
8364  !! if not, return zero straight away.
8365  if (.not. this%has_food()) then
8366  return
8367  end if
8368 
8369  !> From now on it is assumed that the agent has at least one food item
8370  !! in the perception object. Loop through the food items within the later
8371  !! and calculate the total number.
8372  do concurrent(i=1:this%perceive_food%get_count())
8373  ! Can use the operator .within.
8374  ! if ( this%perceive_food%foods_seen(i)%dpos() .within. &
8375  ! [this%dpos()-hz_upper, this%dpos()-hz_lower] ) then
8376  if ( is_within( this%perceive_food%foods_seen(i)%dpos(), &
8377  this%dpos() - hz_upper, &
8378  this%dpos() - hz_lower ) ) then
8379  number_above = number_above + 1
8380  end if
8381  end do
8382 
8384 
8385  !-----------------------------------------------------------------------------
8386  !> Calculate the average mass of a food item from all the items in the
8387  !! current perception object that are **above** the actor agent.
8388  elemental function perception_food_mass_above_calculate(this) &
8389  result(mean_mass_above)
8390  class(perception), intent(in) :: this
8391  real(srp) ::mean_mass_above
8392 
8393  ! Local counters
8394  integer :: i, n_counter
8395 
8396  !> ### Implementation details ###
8397  !> First, initialise the return average mass and the counter
8398  !! for calculating the average both to zero.
8399  mean_mass_above = 0.0_srp
8400  n_counter = 0
8401 
8402  !> Then, check if the agent has any food items in the perception;
8403  !! if not, return zero straight away.
8404  if (.not. this%has_food()) then
8405  return
8406  end if
8407 
8408  !> From now on it is assumed that the agent has at least one food item
8409  !! in the perception object. Calculation of the average mass of the food
8410  !! items **above** is done by concurrent looping through the food items
8411  !! within the perception object.
8412  do concurrent(i=1:this%perceive_food%get_count())
8413  !> This is done by checking the condition:
8414  !! @verbatim
8415  !! if ( food_item .above. this ) ...
8416  !! @endverbatim
8417  !! @note This uses the user defined operator `.above.` that is
8418  !! implemented in `the_environment` module.
8419  if ( this%perceive_food%foods_seen(i) .above. this ) then
8420  !> The average mass of the food items is calculated using the food
8421  !! items mass values returned by the function `get_mass`
8422  !! (`the_environment::food_item::get_mass()`) .
8423  mean_mass_above = &
8424  mean_mass_above + this%perceive_food%foods_seen(i)%get_mass()
8425  n_counter = n_counter + 1
8426  end if
8427  end do
8428 
8429  !> Final average value is calculated, obviously, by division of the
8430  !! total mass by the total count. In case the count is zero, also
8431  !! return zero mean.
8432  if ( n_counter > 0 ) then
8433  mean_mass_above = mean_mass_above / real(n_counter, srp)
8434  else
8435  mean_mass_above = 0.0_srp
8436  end if
8437 
8439 
8440  !-----------------------------------------------------------------------------
8441  !> Calculate the average mass of a food item from all the items in the
8442  !! current perception object that are **above** the actor agent within a
8443  !! specific vertical horizon [hz_lower,hz_upper]. The horizon limits are
8444  !! relative, in that they start from the depth position of the `this` actor
8445  !! agent: [z-hz_upper, z-hz_upper].
8446  !! @image html aha_percept_food_up_lower.svg
8447  !! @image latex aha_percept_food_up_lower.eps "Calculation of food items above and below" width=8cm
8448  elemental function perception_food_mass_above_horiz_calculate(this, &
8449  hz_lower, &
8450  hz_upper ) &
8451  result(mean_mass_above)
8452  class(perception), intent(in) :: this
8453  !> @param[in] hz_lower The upper limit for the vertical horizon
8454  real(srp), intent(in) :: hz_lower
8455  !> @param[in] hz_upper The lower limit for the vertical horizon
8456  real(srp), intent(in) :: hz_upper
8457  !> @return Average mass of food items within the perception object that are
8458  !! located above (over) the actor agent.
8459  real(srp) ::mean_mass_above
8460 
8461  ! Local counters
8462  integer :: i, n_counter
8463 
8464  !> ### Implementation details ###
8465  !> First, initialise the return average mass and the counter
8466  !! for calculating the average both to zero.
8467  mean_mass_above = 0.0_srp
8468  n_counter = 0
8469 
8470  !> Then, check if the agent has any food items in the perception;
8471  !! if not, return zero straight away.
8472  if (.not. this%has_food()) then
8473  return
8474  end if
8475 
8476  !> From now on it is assumed that the agent has at least one food item
8477  !! in the perception object. Calculation of the average mass of the food
8478  !! items **above** is done by concurrent looping through the food items
8479  !! within the perception object.
8480  do concurrent(i=1:this%perceive_food%get_count())
8481  ! Can use the operator .within.
8482  ! if ( this%perceive_food%foods_seen(i)%dpos() .within. &
8483  ! [this%dpos()-hz_upper, this%dpos()-hz_lower] ) then
8484  if ( is_within( this%perceive_food%foods_seen(i)%dpos(), &
8485  this%dpos() - hz_upper, &
8486  this%dpos() - hz_lower ) ) then
8487  !> The average mass of the food items is calculated using the food
8488  !! items mass values returned by the function `get_mass`
8489  !! (`the_environment::food_item::get_mass()`) .
8490  mean_mass_above = &
8491  mean_mass_above + this%perceive_food%foods_seen(i)%get_mass()
8492  n_counter = n_counter + 1
8493  end if
8494  end do
8495 
8496  !> Final average value is calculated, obviously, by division of the
8497  !! total mass by the total count. In case the count is zero, also
8498  !! return zero mean.
8499  if ( n_counter > 0 ) then
8500  mean_mass_above = mean_mass_above / real(n_counter, srp)
8501  else
8502  mean_mass_above = 0.0_srp
8503  end if
8504 
8506 
8507  !-----------------------------------------------------------------------------
8508  !> Calculate the number of conspecifics in the perception object that are
8509  !! located **below** the actor agent.
8510  elemental function perception_conspecifics_below_calculate(this) &
8511  result(number_below)
8512  class(perception), intent(in) :: this
8513  !> @return The number of conspecifics within the perception object that are
8514  !! located below (under) the actor agent.
8515  integer :: number_below
8516 
8517  !> ### Implementation details ###
8518  !> First, initialise the counter to zero.
8519  number_below = 0
8520 
8521  !> Then, check if the agent has any conspecifics in the perception;
8522  !! if not, return zero straight away.
8523  if (.not. this%has_consp()) then
8524  return
8525  end if
8526 
8527  !> From now on it is assumed that the agent has at least one conspecific
8528  !! in the perception object. Loop through the conspecifics and count
8529  !! their total number.
8530  number_below = count( this%perceive_consp%conspecifics_seen .below. this )
8531 
8533 
8534  !-----------------------------------------------------------------------------
8535  !> Calculate the number of conspecifics in the perception object that are
8536  !! located **above** the actor agent.
8537  elemental function perception_conspecifics_above_calculate(this) &
8538  result(number_above)
8539  class(perception), intent(in) :: this
8540  !> @return The number of conspecifics within the perception object that are
8541  !! located above (over) the actor agent.
8542  integer :: number_above
8543 
8544  !> ### Implementation details ###
8545  !> First, initialise the counter to zero.
8546  number_above = 0
8547 
8548  !> Then, check if the agent has any conspecifics in the perception;
8549  !! if not, return zero straight away.
8550  if (.not. this%has_consp()) then
8551  return
8552  end if
8553 
8554  !> From now on it is assumed that the agent has at least one conspecific
8555  !! in the perception object. Loop through the conspecifics and count
8556  !! their total number.
8557  number_above = count( this%perceive_consp%conspecifics_seen .above. this )
8558 
8560 
8561  !-----------------------------------------------------------------------------
8562  !> Calculate the number of conspecifics in the perception object that are
8563  !! located **below** the actor agent within a specific vertical horizon
8564  !! [hz_lower,hz_upper]. The horizon limits are relative, in that they start
8565  !! from the depth position of the `this` actor agent:
8566  !! [z+hz_lower, z+hz_upper].
8567  elemental function perception_conspecifics_below_horiz_calculate( this, &
8568  hz_lower, &
8569  hz_upper )&
8570  result(number_below)
8571  class(perception), intent(in) :: this
8572  !> @param[in] hz_lower The upper limit for the vertical horizon
8573  real(srp), intent(in) :: hz_lower
8574  !> @param[in] hz_upper The lower limit for the vertical horizon
8575  real(srp), intent(in) :: hz_upper
8576  !> @return The number of conspecifics within the perception object that are
8577  !! located below (under) the actor agent.
8578  integer :: number_below
8579 
8580  ! Local counter
8581  integer :: i
8582 
8583  !> ### Implementation details ###
8584  !> First, initialise the counter to zero.
8585  number_below = 0
8586 
8587  !> Then, check if the agent has any conspecifics in the perception;
8588  !! if not, return zero straight away.
8589  if (.not. this%has_consp()) then
8590  return
8591  end if
8592 
8593  !> From now on it is assumed that the agent has at least one conspecific
8594  !! in the perception object. Loop through the conspecifics within the later
8595  !! and calculate their number.
8596  do concurrent(i=1:this%perceive_consp%get_count())
8597  if ( this%perceive_consp%conspecifics_seen(i)%dpos() .within. &
8598  [this%dpos()+hz_lower, this%dpos()+hz_upper] ) then
8599  number_below = number_below + 1
8600  end if
8601  end do
8602 
8604 
8605  !-----------------------------------------------------------------------------
8606  !> Calculate the number of conspecifics in the perception object that are
8607  !! located **above** the actor agent within a specific vertical horizon
8608  !! [hz_lower,hz_upper]. The horizon limits are relative, in that they start
8609  !! from the depth position of the `this` actor agent:
8610  !! [z-hz_upper, z-hz_upper].
8611  elemental function perception_conspecifics_above_horiz_calculate( this, &
8612  hz_lower, &
8613  hz_upper )&
8614  result(number_above)
8615  class(perception), intent(in) :: this
8616  !> @param[in] hz_lower The upper limit for the vertical horizon
8617  real(srp), intent(in) :: hz_lower
8618  !> @param[in] hz_upper The lower limit for the vertical horizon
8619  real(srp), intent(in) :: hz_upper
8620  !> @return The number of conspecifics within the perception object that are
8621  !! located above (over) the actor agent.
8622  integer :: number_above
8623 
8624  ! Local counter
8625  integer :: i
8626 
8627  !> ### Implementation details ###
8628  !> First, initialise the counter to zero.
8629  number_above = 0
8630 
8631  !> Then, check if the agent has any conspecifics in the perception;
8632  !! if not, return zero straight away.
8633  if (.not. this%has_food()) then
8634  return
8635  end if
8636 
8637  !> From now on it is assumed that the agent has at least one conspecific
8638  !! in the perception object. Loop through the conspecifics within and
8639  !! calculate their number.
8640  do concurrent(i=1:this%perceive_consp%get_count())
8641  if ( this%perceive_consp%conspecifics_seen(i)%dpos() .within. &
8642  [this%dpos()-hz_upper, this%dpos()-hz_lower] ) then
8643  number_above = number_above + 1
8644  end if
8645  end do
8646 
8648 
8649  !-----------------------------------------------------------------------------
8650  !> Calculate the number of predators in the perception object that are
8651  !! located **below** the actor agent.
8652  elemental function perception_predator_below_calculate(this) &
8653  result(number_below)
8654  class(perception), intent(in) :: this
8655  !> @return The number of predators within the perception object that are
8656  !! located below (under) the actor agent.
8657  integer :: number_below
8658 
8659  !> ### Implementation details ###
8660  !> First, initialise the counter to zero.
8661  number_below = 0
8662 
8663  !> Then, check if the agent has any predators in the perception;
8664  !! if not, return zero straight away.
8665  if (.not. this%has_pred()) then
8666  return
8667  end if
8668 
8669  !> From now on it is assumed that the agent has at least one conspecific
8670  !! in the perception object. Loop through the predators and count
8671  !! their total number.
8672  number_below = count( this%perceive_predator%predators_seen .below. this )
8673 
8675 
8676  !-----------------------------------------------------------------------------
8677  !> Calculate the number of predators in the perception object that are
8678  !! located **above** the actor agent.
8679  elemental function perception_predator_above_calculate(this) &
8680  result(number_above)
8681  class(perception), intent(in) :: this
8682  !> @return The number of predators within the perception object that are
8683  !! located above (over) the actor agent.
8684  integer :: number_above
8685 
8686  !> ### Implementation details ###
8687  !> First, initialise the counter to zero.
8688  number_above = 0
8689 
8690  !> Then, check if the agent has any predators in the perception;
8691  !! if not, return zero straight away.
8692  if (.not. this%has_pred()) then
8693  return
8694  end if
8695 
8696  !> From now on it is assumed that the agent has at least one conspecific
8697  !! in the perception object. Loop through the predators and count
8698  !! their total number.
8699  number_above = count( this%perceive_predator%predators_seen .above. this )
8700 
8702 
8703  !-----------------------------------------------------------------------------
8704  !> Calculate the number of predators in the perception object that are
8705  !! located **below** the actor agent within a specific vertical horizon
8706  !! [hz_lower,hz_upper]. The horizon limits are relative, in that they start
8707  !! from the depth position of the `this` actor agent:
8708  !! [z+hz_lower, z+hz_upper].
8709  elemental function perception_predator_below_horiz_calculate( this, &
8710  hz_lower, &
8711  hz_upper )&
8712  result(number_below)
8713  class(perception), intent(in) :: this
8714  !> @param[in] hz_lower The upper limit for the vertical horizon
8715  real(srp), intent(in) :: hz_lower
8716  !> @param[in] hz_upper The lower limit for the vertical horizon
8717  real(srp), intent(in) :: hz_upper
8718  !> @return The number of predators within the perception object that are
8719  !! located below (under) the actor agent.
8720  integer :: number_below
8721 
8722  ! Local counter
8723  integer :: i
8724 
8725  !> ### Implementation details ###
8726  !> First, initialise the counter to zero.
8727  number_below = 0
8728 
8729  !> Then, check if the agent has any predators in the perception;
8730  !! if not, return zero straight away.
8731  if (.not. this%has_pred()) then
8732  return
8733  end if
8734 
8735  !> From now on it is assumed that the agent has at least one conspecific
8736  !! in the perception object. Loop through the predators within the later
8737  !! and calculate their number.
8738  do concurrent(i=1:this%perceive_predator%get_count())
8739  if ( this%perceive_predator%predators_seen(i)%dpos() .within. &
8740  [this%dpos()+hz_lower, this%dpos()+hz_upper] ) then
8741  number_below = number_below + 1
8742  end if
8743  end do
8744 
8746 
8747  !-----------------------------------------------------------------------------
8748  !> Calculate the number of predators in the perception object that are
8749  !! located **above** the actor agent within a specific vertical horizon
8750  !! [hz_lower,hz_upper]. The horizon limits are relative, in that they start
8751  !! from the depth position of the `this` actor agent:
8752  !! [z-hz_upper, z-hz_upper].
8753  elemental function perception_predator_above_horiz_calculate( this, &
8754  hz_lower, &
8755  hz_upper )&
8756  result(number_above)
8757  class(perception), intent(in) :: this
8758  !> @param[in] hz_lower The upper limit for the vertical horizon
8759  real(srp), intent(in) :: hz_lower
8760  !> @param[in] hz_upper The lower limit for the vertical horizon
8761  real(srp), intent(in) :: hz_upper
8762  !> @return The number of predators within the perception object that are
8763  !! located above (over) the actor agent.
8764  integer :: number_above
8765 
8766  ! Local counter
8767  integer :: i
8768 
8769  !> ### Implementation details ###
8770  !> First, initialise the counter to zero.
8771  number_above = 0
8772 
8773  !> Then, check if the agent has any predators in the perception;
8774  !! if not, return zero straight away.
8775  if (.not. this%has_pred()) then
8776  return
8777  end if
8778 
8779  !> From now on it is assumed that the agent has at least one conspecific
8780  !! in the perception object. Loop through the predators within and
8781  !! calculate their number.
8782  do concurrent(i=1:this%perceive_predator%get_count())
8783  if ( this%perceive_predator%predators_seen(i)%dpos() .within. &
8784  [this%dpos()-hz_upper, this%dpos()-hz_lower] ) then
8785  number_above = number_above + 1
8786  end if
8787  end do
8788 
8790 
8791  !-----------------------------------------------------------------------------
8792  !> Calculate the average distance to all food items in the current
8793  !! perception object that are **below** the actor agent.
8794  elemental function perception_food_dist_below_calculate(this) &
8795  result(mean_dist)
8796  class(perception), intent(in) :: this
8797  !> @return The average distance to food items within the perception
8798  !! object that are located below (under) the actor agent.
8799  real(srp) ::mean_dist
8800 
8801  ! Local counters
8802  integer :: i, n_counter
8803 
8804  !> ### Implementation details ###
8805  !> First, initialise the return average and the counter to zero.
8806  mean_dist = 0.0_srp
8807  n_counter = 0
8808 
8809  !> Then, check if the agent has any food items in the perception;
8810  !! if not, return zero straight away.
8811  if (.not. this%has_food()) then
8812  return
8813  end if
8814 
8815  !> From now on it is assumed that the agent has at least one food item
8816  !! in the perception object. Calculation of the average distance to the
8817  !! food items **below** is done by concurrent looping through the food
8818  !! items within the perception object and calculating the distance from
8819  !! the agent.
8820  do concurrent(i=1:this%perceive_food%get_count())
8821  !> This is done by checking the condition:
8822  !! @verbatim
8823  !! if ( food_item .below. this ) ...
8824  !! @endverbatim
8825  if ( this%perceive_food%foods_seen(i) .below. this ) then
8826  mean_dist = &
8827  !mean_dist + this%perceive_food%foods_seen(i)%distance( this )
8828  mean_dist + this%distance( this%perceive_food%foods_seen(i) )
8829  n_counter = n_counter + 1
8830  end if
8831  end do
8832 
8833  !> Final average value is calculated, obviously, by division of the
8834  !! total distance by the count. In case the count is zero, also
8835  !! return commondata::missing mean. Note that zero is not returned here
8836  !! because zero distance to food item would result in the highest
8837  !! probability of capture which is not what is intended (zero probability
8838  !! should be invoked for null food items).
8839  if ( n_counter > 0 ) then
8840  mean_dist = mean_dist / real(n_counter, srp)
8841  else
8842  mean_dist = missing
8843  end if
8844 
8846 
8847  !-----------------------------------------------------------------------------
8848  !> Calculate the average distance to all food items in the current
8849  !! perception object that are **above** the actor agent.
8850  elemental function perception_food_dist_above_calculate(this) &
8851  result(mean_dist)
8852  class(perception), intent(in) :: this
8853  !> @return The average distance to food items within the perception
8854  !! object that are located above (over) the actor agent.
8855  real(srp) ::mean_dist
8856 
8857  ! Local counters
8858  integer :: i, n_counter
8859 
8860  !> ### Implementation details ###
8861  !> First, initialise the return average and the counter to zero.
8862  mean_dist = 0.0_srp
8863  n_counter = 0
8864 
8865  !> Then, check if the agent has any food items in the perception;
8866  !! if not, return zero straight away.
8867  if (.not. this%has_food()) then
8868  return
8869  end if
8870 
8871  !> From now on it is assumed that the agent has at least one food item
8872  !! in the perception object. Calculation of the average distance to the
8873  !! food items **above** is done by concurrent looping through the food
8874  !! items within the perception object and calculating the distance from
8875  !! the agent.
8876  do concurrent(i=1:this%perceive_food%get_count())
8877  !> This is done by checking the condition:
8878  !! @verbatim
8879  !! if ( food_item .above. this ) ...
8880  !! @endverbatim
8881  if ( this%perceive_food%foods_seen(i) .above. this ) then
8882  mean_dist = &
8883  !mean_dist + this%perceive_food%foods_seen(i)%distance( this )
8884  mean_dist + this%distance( this%perceive_food%foods_seen(i) )
8885  n_counter = n_counter + 1
8886  end if
8887  end do
8888 
8889  !> Final average value is calculated, obviously, by division of the
8890  !! total distance by the count. In case the count is zero, also
8891  !! return commondata::missing mean. Note that zero is not returned here
8892  !! because zero distance to food item would result in the highest
8893  !! probability of capture which is not what is intended (zero probability
8894  !! should be invoked for null food items).
8895  if ( n_counter > 0 ) then
8896  mean_dist = mean_dist / real(n_counter, srp)
8897  else
8898  mean_dist = missing
8899  end if
8900 
8902 
8903  !-----------------------------------------------------------------------------
8904  !> Calculate the average distance to all conspecifics in the current
8905  !! perception object that are **below** the actor agent.
8906  elemental function perception_consp_dist_below_calculate(this) &
8907  result(mean_dist)
8908  class(perception), intent(in) :: this
8909  !> @return The average distance to conspecifics within the perception
8910  !! object that are located below (under) the actor agent.
8911  real(srp) ::mean_dist
8912 
8913  ! Local counters
8914  integer :: i, n_counter
8915 
8916  !> ### Implementation details ###
8917  !> First, initialise the return average and the counter to zero.
8918  mean_dist = 0.0_srp
8919  n_counter = 0
8920 
8921  !> Then, check if the agent has any conspecifics in the perception;
8922  !! if not, return zero straight away.
8923  if (.not. this%has_consp()) then
8924  return
8925  end if
8926 
8927  !> From now on it is assumed that the agent has at least one conspecific
8928  !! in the perception object. Calculation of the average distance to the
8929  !! conspecifics **below** is done by concurrent looping through the
8930  !! conspecifics within the perception object and calculating the distance
8931  !! from the agent.
8932  do concurrent(i=1:this%perceive_consp%get_count())
8933  !> This is done by checking the condition:
8934  !! @verbatim
8935  !! if ( food_item .below. this ) ...
8936  !! @endverbatim
8937  if ( this%perceive_consp%conspecifics_seen(i) .below. this ) then
8938  mean_dist = &
8939  mean_dist + this%distance( &
8940  this%perceive_consp%conspecifics_seen(i) )
8941  n_counter = n_counter + 1
8942  end if
8943  end do
8944 
8945  !> Final average value is calculated, obviously, by division of the
8946  !! total distance by the count. In case the count is zero, also
8947  !! return commondata::missing mean.
8948  if ( n_counter > 0 ) then
8949  mean_dist = mean_dist / real(n_counter, srp)
8950  else
8951  mean_dist = missing
8952  end if
8953 
8955 
8956  !-----------------------------------------------------------------------------
8957  !> Calculate the average distance to all conspecifics in the current
8958  !! perception object that are **above** the actor agent.
8959  elemental function perception_consp_dist_above_calculate(this) &
8960  result(mean_dist)
8961  class(perception), intent(in) :: this
8962  !> @return The average distance to conspecifics within the perception
8963  !! object that are located above (over) the actor agent.
8964  real(srp) ::mean_dist
8965 
8966  ! Local counters
8967  integer :: i, n_counter
8968 
8969  !> ### Implementation details ###
8970  !> First, initialise the return average and the counter to zero.
8971  mean_dist = 0.0_srp
8972  n_counter = 0
8973 
8974  !> Then, check if the agent has any conspecifics in the perception;
8975  !! if not, return zero straight away.
8976  if (.not. this%has_consp()) then
8977  return
8978  end if
8979 
8980  !> From now on it is assumed that the agent has at least one conspecific
8981  !! in the perception object. Calculation of the average distance to the
8982  !! conspecifics **above** is done by concurrent looping through the
8983  !! conspecifics within the perception object and calculating the distance
8984  !! from the agent.
8985  do concurrent(i=1:this%perceive_consp%get_count())
8986  !> This is done by checking the condition:
8987  !! @verbatim
8988  !! if ( food_item .above. this ) ...
8989  !! @endverbatim
8990  if ( this%perceive_consp%conspecifics_seen(i) .above. this ) then
8991  mean_dist = &
8992  mean_dist + this%distance( &
8993  this%perceive_consp%conspecifics_seen(i) )
8994  n_counter = n_counter + 1
8995  end if
8996  end do
8997 
8998  !> Final average value is calculated, obviously, by division of the
8999  !! total distance by the count. In case the count is zero, also
9000  !! return commondata::missing mean.
9001  if ( n_counter > 0 ) then
9002  mean_dist = mean_dist / real(n_counter, srp)
9003  else
9004  mean_dist = missing
9005  end if
9006 
9008 
9009  !-----------------------------------------------------------------------------
9010  !> Calculate the average distance to all predators in the current
9011  !! perception object that are **below** the actor agent.
9012  elemental function perception_predator_dist_below_calculate(this) &
9013  result(mean_dist)
9014  class(perception), intent(in) :: this
9015  !> @return The average distance to predators within the perception
9016  !! object that are located below (under) the actor agent.
9017  real(srp) ::mean_dist
9018 
9019  ! Local counters
9020  integer :: i, n_counter
9021 
9022  !> ### Implementation details ###
9023  !> First, initialise the return average and the counter to zero.
9024  mean_dist = 0.0_srp
9025  n_counter = 0
9026 
9027  !> Then, check if the agent has any predators in the perception;
9028  !! if not, return zero straight away.
9029  if (.not. this%has_pred()) then
9030  return
9031  end if
9032 
9033  !> From now on it is assumed that the agent has at least one conspecific
9034  !! in the perception object. Calculation of the average distance to the
9035  !! predators **below** is done by concurrent looping through the
9036  !! predators within the perception object and calculating the distance
9037  !! from the agent.
9038  do concurrent(i=1:this%perceive_predator%get_count())
9039  !> This is done by checking the condition:
9040  !! @verbatim
9041  !! if ( food_item .below. this ) ...
9042  !! @endverbatim
9043  if ( this%perceive_predator%predators_seen(i) .below. this ) then
9044  mean_dist = &
9045  mean_dist + this%distance( &
9046  this%perceive_predator%predators_seen(i) )
9047  n_counter = n_counter + 1
9048  end if
9049  end do
9050 
9051  !> Final average value is calculated, obviously, by division of the
9052  !! total distance by the count. In case the count is zero, also
9053  !! return commondata::missing mean.
9054  if ( n_counter > 0 ) then
9055  mean_dist = mean_dist / real(n_counter, srp)
9056  else
9057  mean_dist = missing
9058  end if
9059 
9061 
9062  !-----------------------------------------------------------------------------
9063  !> Calculate the average distance to all predators in the current
9064  !! perception object that are **above** the actor agent.
9065  elemental function perception_predator_dist_above_calculate(this) &
9066  result(mean_dist)
9067  class(perception), intent(in) :: this
9068  !> @return The average distance to predators within the perception
9069  !! object that are located above (over) the actor agent.
9070  real(srp) ::mean_dist
9071 
9072  ! Local counters
9073  integer :: i, n_counter
9074 
9075  !> ### Implementation details ###
9076  !> First, initialise the return average and the counter to zero.
9077  mean_dist = 0.0_srp
9078  n_counter = 0
9079 
9080  !> Then, check if the agent has any predators in the perception;
9081  !! if not, return zero straight away.
9082  if (.not. this%has_pred()) then
9083  return
9084  end if
9085 
9086  !> From now on it is assumed that the agent has at least one conspecific
9087  !! in the perception object. Calculation of the average distance to the
9088  !! predators **above** is done by concurrent looping through the
9089  !! predators within the perception object and calculating the distance
9090  !! from the agent.
9091  do concurrent(i=1:this%perceive_predator%get_count())
9092  !> This is done by checking the condition:
9093  !! @verbatim
9094  !! if ( food_item .above. this ) ...
9095  !! @endverbatim
9096  if ( this%perceive_predator%predators_seen(i) .above. this ) then
9097  mean_dist = &
9098  mean_dist + this%distance( &
9099  this%perceive_predator%predators_seen(i) )
9100  n_counter = n_counter + 1
9101  end if
9102  end do
9103 
9104  !> Final average value is calculated, obviously, by division of the
9105  !! total distance by the count. In case the count is zero, also
9106  !! return commondata::missing mean.
9107  if ( n_counter > 0 ) then
9108  mean_dist = mean_dist / real(n_counter, srp)
9109  else
9110  mean_dist = missing
9111  end if
9112 
9114 
9115  !-----------------------------------------------------------------------------
9116  !> Calculate the probability of attack and capture of the `this` agent by
9117  !! the predator `this_predator`. This probability is a function of the
9118  !! distance between the predator and the agent and is calculated by the
9119  !! predator-class-bound procedure the_environment::predator::risk_fish().
9120  !! Example call:
9121  !! @verbatim
9122  !! risk=proto_parents%individual(ind)%risk_pred( &
9123  !! proto_parents%individual(ind)%perceive_predator%predators_seen(i), &
9124  !! proto_parents%individual(ind)%perceive_predator%predators_attack_rates(i))
9125  !! @endverbatim
9126  !! @note Note that this version of the procedure accepts `this_predator`
9127  !! parameter as class the_neurobio::spatialobj_percept_comp that is
9128  !! used for keeping the predator representations in the **perception
9129  !! object**. This representation keeps two separate array for
9130  !! the_neurobio::spatialobj_percept_comp spatial objects and the
9131  !! attack rate.
9133  this_predator, attack_rate, &
9134  is_freezing, time_step_model) &
9135  result(risk_pred)
9136  class(perception), intent(in) :: this
9137  !> @param[in] this_predator the predator that is about to attack the agent.
9138  !! @note Note that the predator has the SPATIALOBJ_PERCEPT_COMP
9139  !! type that is used in the predator perception object
9140  class(spatialobj_percept_comp), intent(in) :: this_predator
9141  !> @param[in] attack_rate attack rate of the predator.
9142  !! @note Note that the predator perception object keeps a
9143  !! separate array of the attack rate.
9144  real(srp), intent(in) :: attack_rate
9145  !> @param[in] is_freezing optional logical flag indicating that the fish
9146  !! prey agent is immobile (freezing) that would result in
9147  !! reduced predation risk. Default value is FALSE.
9148  logical, optional, intent(in) :: is_freezing
9149  !> @param[in] time_step_model optional time step of the model, if absent,
9150  !! set from the current time step
9151  !! commondata::global_time_step_model_current.
9152  integer, optional, intent(in) :: time_step_model
9153 
9154  real(srp) :: risk_pred
9155 
9156  ! Temporary predator object
9157  type(predator) :: tmp_predator
9158 
9159  ! Local copies of optionals.
9160  integer :: time_step_model_here
9161  logical :: is_freezing_loc
9162 
9163  ! Distance to the predator
9164  real(srp) :: distance_pred
9165  ! Postscript file name for the debug plot
9166  character(FILENAME_LENGTH) :: debug_plot_file
9167 
9168  !> ### Checks ###
9169  !> First, check if the agent has any predators and return zero
9170  !! and exit if there are no predators in the agent's perception
9171  !! object.
9172  !! @note This assumes that the predator is much larger than the agent,
9173  !! so the visual range the agent has for detecting the predator is
9174  !! longer than the visual range of the predator for detecting the
9175  !! prey agent.
9176  !! @warning The version working with the agent's perception component
9177  !! the_neurobio::predator_capture_probability_calculate_pred()
9178  !! returns a small non-zero probability of capture in contrast to
9179  !! this version accepting `this_predator` object as a class
9180  !! SPATIALOBJ_PERCEPT_COMP. This is because the former normally
9181  !! calculated the objective predation risk whereas this version,
9182  !! subjective risk in the agent's perception. The agent cannot be
9183  !! aware of a predator that is outside of its perception.
9184  if (.not. this%has_pred()) then
9185  risk_pred = 0.0_srp
9186  return
9187  end if
9188 
9189  !> Second, Check optional time step parameter. If unset, use global
9190  !! variable `commondata::global_time_step_model_current`.
9191  if (present(time_step_model)) then
9192  time_step_model_here = time_step_model
9193  else
9194  time_step_model_here = global_time_step_model_current
9195  end if
9196 
9197  ! Check is_freezing dummy parameter.
9198  if (present(is_freezing)) then
9199  is_freezing_loc = is_freezing
9200  else
9201  is_freezing_loc = .false.
9202  end if
9203 
9204  !> Third, create a temporary PREDATOR type object using the standard method
9205  !! `make`. The body size and the spatial position are obtained directly
9206  !! from the `this_predator` object. However, the attack rate is obtained
9207  !! from the second dummy argument `attack_rate` to this procedure.
9208  ! @note Note that the `select type` construct used in the initial version
9209  ! that allows implementation of a single procedure for both
9210  ! PREDATOR and SPATIALOBJ_PERCEPT_COMP types requires attack rate
9211  ! as an optional parameter which is not safe: if not provided when
9212  ! required, it could lead to non-initialised attack rate in
9213  ! calculations.
9214  call tmp_predator%make( body_size=this_predator%get_size(), &
9215  attack_rate=attack_rate, &
9216  position=this_predator%location(), &
9217  label="tmp_object" )
9218 
9219  !> ### Implementation ###
9220  !> Calculate the distance between the agent and predator.
9221  distance_pred = this%distance( this_predator )
9222 
9223  !> Set the debug plot file name that will be passed to the
9224  !! predator-class-bound function the_environment::predator::risk_fish().
9225  debug_plot_file = "plot_debug_predation_risk_" &
9226  // tostr(global_time_step_model_current) // "_" // &
9227  mmdd // "_a_" // trim(this%individ_label()) &
9228  // "_" // &
9229  rand_string(label_length, label_cst,label_cen) // ps
9230 
9231  !> Calculate the probability of capture of the `this` prey agent by the
9232  !! predator. See the_environment::predator::risk_fish() for the details of
9233  !! the calculation.
9234  risk_pred = tmp_predator%risk_fish(prey_spatial=this%location(), &
9235  prey_length=this%get_length(), &
9236  prey_distance=distance_pred, &
9237  is_freezing=is_freezing_loc, &
9238  time_step_model=time_step_model_here, &
9239  debug_plot_file=debug_plot_file )
9240 
9242 
9243  !-----------------------------------------------------------------------------
9244  !> Calculate the probability of attack and capture of the `this` agent by
9245  !! the predator `this_predator`. This probability is a function of the
9246  !! distance between the predator and the agent and is calculated by the
9247  !! predator-class-bound procedure the_environment::predator::risk_fish().
9248  !! @note Note that this version of the procedure accepts `this_predator`
9249  !! parameter as class the_neurobio::predator, i.e. for the **objective
9250  !! predator object**.
9251  function predator_capture_probability_calculate_pred(this, this_predator, &
9252  is_freezing, time_step_model) &
9253  result(risk_pred)
9254  class(perception), intent(in) :: this
9255  !> @param[in] this_predator the predator that is about to attack the agent.
9256  class(predator), intent(in) :: this_predator
9257  !> @param[in] is_freezing optional logical flag indicating that the fish
9258  !! prey agent is immobile (freezing) that would result in
9259  !! reduced predation risk. Default value is FALSE.
9260  logical, optional, intent(in) :: is_freezing
9261  !> @param[in] time_step_model optional time step of the model, if absent,
9262  !! set from the current time step
9263  !! commondata::global_time_step_model_current.
9264  integer, optional, intent(in) :: time_step_model
9265 
9266  real(srp) :: risk_pred
9267 
9268  ! Local copies of optionals
9269  integer :: time_step_model_here
9270  logical :: is_freezing_loc
9271 
9272  ! Distance to the predator
9273  real(srp) :: distance_pred
9274  ! Postscript file name for the debug plot
9275  character(FILENAME_LENGTH) :: debug_plot_file
9276 
9277  !> ### Checks ###
9278  !> First, check if the agent has any predators in the perception object.
9279  !! Return a near-zero value defined by the
9280  !! commondata::predator_attack_capture_probability_min parameter
9281  !! constant, and exit if there are no predators in the agent's perception
9282  !! object.
9283  !! @note This assumes that the predator is much larger than the agent,
9284  !! so the visual range the agent has for detecting the predator is
9285  !! longer than the visual range of the predator for detecting the
9286  !! prey agent.
9287  !! @warning The version working with the agent's **perception** component
9288  !! the_neurobio::predator_capture_probability_calculate_spatobj()
9289  !! returns **zero** probability in contrast to this version
9290  !! accepting `this_predator` object as a type PREDATOR. This is
9291  !! because the former normally calculated the subjective
9292  !! assessment of the predation risk whereas this version,
9293  !! objective risk.
9294  if (.not. this%has_pred()) then
9295  risk_pred = this_predator%attack_rate * &
9296  predator_attack_capture_probability_min
9297  return
9298  end if
9299 
9300  !> Second, Check optional time step parameter. If unset, use global
9301  !! variable `commondata::global_time_step_model_current`.
9302  if (present(time_step_model)) then
9303  time_step_model_here = time_step_model
9304  else
9305  time_step_model_here = global_time_step_model_current
9306  end if
9307 
9308  ! Check is_freezing dummy parameter.
9309  if (present(is_freezing)) then
9310  is_freezing_loc = is_freezing
9311  else
9312  is_freezing_loc = .false.
9313  end if
9314 
9315  !> ### Implementation ###
9316  !> Calculate the distance between the agent and predator.
9317  distance_pred = this%distance( this_predator )
9318 
9319  !> Set the debug plot file name that will be passed to the
9320  !! predator-class-bound function the_environment::predator::risk_fish().
9321  debug_plot_file = "plot_debug_predation_risk_" &
9322  // tostr(global_time_step_model_current) // "_" // &
9323  mmdd // "_a_" // trim(this%individ_label()) &
9324  // "_" // &
9325  rand_string(label_length, label_cst,label_cen) // ps
9326 
9327  !> Calculate the probability of capture of the `this` prey agent by the
9328  !! predator. See the_environment::predator::risk_fish() for the details of
9329  !! the calculation.
9330  risk_pred = this_predator%risk_fish(prey_spatial=this%location(), &
9331  prey_length=this%get_length(), &
9332  prey_distance=distance_pred, &
9333  is_freezing=is_freezing_loc, &
9334  time_step_model=time_step_model_here, &
9335  debug_plot_file=debug_plot_file )
9336 
9338 
9339  !-----------------------------------------------------------------------------
9340  !> Calculate the overall direct predation risk for the agent, i.e.
9341  !! the probability of attack and capture by the nearest predator.
9342  function predation_capture_probability_risk_wrapper(this, is_freezing) &
9343  result(risk)
9344  class(perception), intent(in) :: this
9345  !> @param[in] is_freezing optional logical flag indicating that the fish
9346  !! prey agent is immobile (freezing) that would result in
9347  !! reduced predation risk. Default value is FALSE.
9348  logical, optional, intent(in) :: is_freezing
9349  !> @return Returns the probability of capture by the nearest predator.
9350  real(srp) :: risk
9351 
9352  ! Local copies of optionals
9353  logical :: is_freezing_loc
9354 
9355  ! Check is_freezing dummy parameter.
9356  if (present(is_freezing)) then
9357  is_freezing_loc = is_freezing
9358  else
9359  is_freezing_loc = .false.
9360  end if
9361 
9362  if (this%has_pred()) then
9363  risk = this%risk_pred( this%perceive_predator%predators_seen(1), &
9364  this%perceive_predator%predators_attack_rates(1),&
9365  is_freezing=is_freezing_loc )
9366  else
9367  risk= 0.0_srp
9368  end if
9369 
9371 
9372  !-----------------------------------------------------------------------------
9373  !> Get the body size property of a polymorphic object. The object can be
9374  !! of the following extension of the basic the_environment::spatial class:
9375  !! - the_neurobio::conspec_percept_comp - perception object
9376  !! - the_body::condition - real conspecific.
9377  !! .
9378  !! @note Other specific classes can be similarly implemented.
9379  !! @warning This is not a type-bound function because the base class
9380  !! the_environment::spatial is defined in a different down-level
9381  !! module. Usage: `M = get_props_size(object)`.
9382  elemental function get_prop_size(this) result (size)
9383  class(spatial), intent(in) :: this
9384  !> @return the body size of the input the_environment::spatial class object.
9385  real(srp) :: size
9386 
9387  !> #### Implementation notes ####
9388  !> Get the properties of the conspecific from the perception object
9389  !! or real physical conspecific data. This is done by determining the
9390  !! `this` data type with "select type" construct.
9391  !!
9392  select type (this)
9393  !> - if the `this` is a conspecific from the perception object,
9394  !! its body length is obtained from the respective
9395  !! data components of the_neurobio::conspec_percept_comp.
9396  class is (conspec_percept_comp)
9397  size = this%get_size()
9398  !> - if the `this` is real conspecific (the_neurobio::condition
9399  !! class), its body length is obtained from the
9400  !! the_body::condition::get_length() and
9401  !! the_body::condition::get_mass() methods.
9402  class is (condition)
9403  size = this%get_length()
9404  !> - in the case construct "default" case, the class is undefined,
9405  !! return commondata::missing value.
9406  !> .
9407  class default
9408  size = missing
9409  end select
9410 
9411  end function get_prop_size
9412 
9413  !-----------------------------------------------------------------------------
9414  !> Get the body mass property of a polymorphic object. The object can be
9415  !! of the following extension of the basic the_environment::spatial class:
9416  !! - the_neurobio::conspec_percept_comp - perception object
9417  !! - the_body::condition - real conspecific.
9418  !! .
9419  !! @note Other specific classes can be similarly implemented.
9420  !! @warning This is not a type-bound function because the base class
9421  !! the_environment::spatial is defined in a different down-level
9422  !! module. Usage: `M = get_props_mass(object)`.
9423  elemental function get_prop_mass(this) result (mass)
9424  class(spatial), intent(in) :: this
9425  !> @return the body mass of the input the_environment::spatial class object.
9426  real(srp) :: mass
9427 
9428  !> #### Implementation notes ####
9429  !> Get the properties of the conspecific from the perception object
9430  !! or real physical conspecific data. This is done by determining the
9431  !! `this` data type with "select type" construct.
9432  !!
9433  select type (this)
9434  !> - if the `this` is a conspecific from the perception object,
9435  !! its body length is obtained from the respective
9436  !! data components of the_neurobio::conspec_percept_comp.
9437  class is (conspec_percept_comp)
9438  mass = this%get_mass()
9439  !> - if the `this` is real conspecific (the_neurobio::condition
9440  !! class), its body length is obtained from the
9441  !! the_body::condition::get_length() and
9442  !! the_body::condition::get_mass() methods.
9443  class is (condition)
9444  mass = this%get_mass()
9445  !> - in the case construct "default" case, the class is undefined,
9446  !! return commondata::missing value.
9447  !> .
9448  class default
9449  mass = missing
9450  end select
9451 
9452  end function get_prop_mass
9453 
9454  !-----------------------------------------------------------------------------
9455 
9456 end module the_neurobio
9457 
Simple history stack function, add to the end of the stack. We need only to add components on top (en...
Definition: m_common.f90:5292
Calculate an average of an array excluding missing code values.
Definition: m_common.f90:5491
Convert cm to m.
Definition: m_common.f90:5306
Convert m to cm.
Definition: m_common.f90:5319
Force a value within the range set by the vmin and vmax dummy parameter values.
Definition: m_common.f90:5350
Internal distance calculation backend engine.
Definition: m_env.f90:757
Calculate underwater background irradiance at specific depth.
Definition: m_env.f90:715
Calculate surface light intensity (that is subject to diel variation) for specific time step of the m...
Definition: m_env.f90:702
Calculate visual range of predator using Dag Aksnes's procedures srgetr(), easyr() and deriv().
Definition: m_env.f90:738
Abstract interface for the deferred init function clean_init that has to be overridden by each object...
Definition: m_neuro.f90:1058
elemental real(srp) function asymptotic(max_level, x)
Definition of the asymptotic function for converting the primary genotype-based modulation coefficien...
Definition: m_neuro.f90:6910
pure real(srp) function arousal_decrease_factor_fixed(time_step)
Definition: m_neuro.f90:7713
real(srp) function arousal_decrease_factor_nonpar(time_step)
Definition: m_neuro.f90:7755
COMMONDATA – definitions of global constants and procedures.
Definition: m_common.f90:1497
logical, parameter, public agent_can_assess_predator_attack_rate
A logical flag of whether the agents can assess the individual inherent attack rates of the predators...
Definition: m_common.f90:2395
integer, parameter, public pred_select_items_index_partial
Sets the limit for partial indexing and ranking of predators in the visual range of the agent.
Definition: m_common.f90:3368
real(srp), parameter, public body_length_max
Maximum body length.
Definition: m_common.f90:2121
integer, parameter, public srp
Definition of the standard real type precision (SRP).
Definition: m_common.f90:1551
elemental real(srp) function cv2variance(cv, mean)
Calculate the variance from the coefficient of variation.
Definition: m_common.f90:6956
integer, parameter, public unknown
Numerical code for invalid or missing integer counts.
Definition: m_common.f90:1704
integer, parameter, public history_size_perception
Sets the size of the perception memory stack.
Definition: m_common.f90:3377
integer, parameter, public food_select_items_index_partial
Sets the limit for partial indexing and ranking of food items in the visual range of the agents.
Definition: m_common.f90:3360
real(srp), parameter, public predation_risk_weight_immediate
The weight of the immediately seen predators over those in the perceptual memory stack....
Definition: m_common.f90:3621
real(srp), parameter, public missing
Numerical code for missing and invalid real type values.
Definition: m_common.f90:1699
logical, parameter, public daylight_stochastic
Flag for stochastic daylight pattern (if TRUE) or deterministic sinusoidal (when FALSE)....
Definition: m_common.f90:2513
subroutine log_dbg(message_string, procname, modname)
LOG_DBG: debug message to the log. The message goes to the logger only when running in the DEBUG mode...
Definition: m_common.f90:9171
real(srp), parameter, public body_mass_min
Minimum possible body mass, hard limit.
Definition: m_common.f90:2126
logical, parameter, public true
Safety parameter avoid errors in logical values, so we can now refer to standard Fortran ....
Definition: m_common.f90:1632
real(srp), parameter, public predator_attack_rate_default
Mean rate of a single predator attack.
Definition: m_common.f90:2360
real(srp), parameter, public zero
Some parameters should never be zero or below. In such cases they could be set to some smallest disti...
Definition: m_common.f90:1644
real(srp), parameter, public preycontrast_default
Inherent contrast of prey, CONTRAST =1.0.
Definition: m_common.f90:2527
real(srp), parameter, public food_item_capture_probability_subjective_errorr_cv
Subjective error assessing the food item capture probability when assessing the subjective GOS expect...
Definition: m_common.f90:2473
elemental real(srp) function carea(R)
Calculate a circle area.
Definition: m_common.f90:5665
character(len= *), parameter, public ltag_warn
Definition: m_common.f90:1822
real(srp), parameter, public body_length_min
Minimum body length possible.
Definition: m_common.f90:2118
integer, public global_time_step_model_current
The current global time step of the model. This is a global non fixed-parameter variable that is upda...
Definition: m_common.f90:2095
character(len= *), parameter, private procname
PROCNAME is the procedure name for logging and debugging (with commondata::modname).
Definition: m_common.f90:1605
elemental real(srp) function length2sidearea_fish(body_length)
A function linking body length with the body area in fish.
Definition: m_common.f90:5682
integer, parameter, public consp_select_items_index_partial
Sets the limit for partial indexing and ranking of conspecifics in the visual range of the agent.
Definition: m_common.f90:3364
real(srp), parameter, public individual_visual_contrast_default
Inherent contrast of the agent, It is used in determining the visual range of an agent in perception ...
Definition: m_common.f90:3374
logical, parameter, public false
Definition: m_common.f90:1632
character(len= *), parameter, public ltag_info
Definition: m_common.f90:1821
Definition the physical properties and condition of the agent.
Definition: m_body.f90:19
character(len= *), parameter, private modname
Definition: m_body.f90:26
elemental real(srp) function energy_reserve(m, l)
Calculate the current energy reserves (Fulton condition factor) from body mass and length.
Definition: m_body.f90:332
Definition of environmental objects.
Definition: m_env.f90:19
elemental real(srp) function size2mass_food(radius)
Calculate the mass of a food item, the non-OO backend.
Definition: m_env.f90:6323
Definition of the decision making and behavioural the architecture.
Definition: m_neuro.f90:17
elemental real(srp) function state_motivation_food_dir_get(this)
Standard "get" function for the state neuronal directly seen food effect component.
Definition: m_neuro.f90:5778
subroutine perception_objects_get_all_inner(this)
A single umbrella subroutine wrapper to get all inner perceptions: stomach, body mass,...
Definition: m_neuro.f90:4300
subroutine percept_energy_update_current(this, current)
Set and update the current energy perception value.
Definition: m_neuro.f90:1985
elemental subroutine appraisal_agent_set_dead(this)
Set the individual to be dead. Note that this function does not deallocate the individual agent objec...
Definition: m_neuro.f90:6478
elemental real(srp) function percept_memory_consp_get_mean_n(this, last)
Get the average number of conspecifics per single time step within the whole perceptual memory stack.
Definition: m_neuro.f90:4032
elemental subroutine percept_reprfac_create_init(this)
Make en empty reproductive factor perception component. Really necessary only when perception objects...
Definition: m_neuro.f90:3370
elemental real(srp) function emotional_memory_actve_avoid_get_mean(this, last)
Get the average value of the fear state motivation state within the whole emotional memory stack.
Definition: m_neuro.f90:7363
elemental subroutine percept_light_create_init(this)
Make en empty light perception component. Really necessary only when perception objects are all alloc...
Definition: m_neuro.f90:3244
elemental real(srp) function perception_food_dist_below_calculate(this)
Calculate the average distance to all food items in the current perception object that are below the ...
Definition: m_neuro.f90:8798
elemental subroutine percept_age_destroy_deallocate(this)
Destroy the age perception object and deallocate it.
Definition: m_neuro.f90:2048
elemental real(srp) function state_motivation_age_get(this)
Standard "get" function for the state neuronal age effect component.
Definition: m_neuro.f90:5874
subroutine depth_perception_get_object(this)
Get depth perception objects into the individual PERCEPTION object layer.
Definition: m_neuro.f90:3414
subroutine percept_bodymass_update_current(this, current)
Set and update the current body mass perception value.
Definition: m_neuro.f90:1934
elemental real(srp) function perception_predator_dist_below_calculate(this)
Calculate the average distance to all predators in the current perception object that are below the a...
Definition: m_neuro.f90:9016
elemental integer function perception_predator_below_horiz_calculate(this, hz_lower, hz_upper)
Calculate the number of predators in the perception object that are located below the actor agent wit...
Definition: m_neuro.f90:8715
elemental subroutine appraisal_primary_motivations_calculate(this, rescale_max_motivation)
Calculate primary motivations from perceptual components of each motivation state.
Definition: m_neuro.f90:6646
elemental integer function percept_age_get_current(this)
Get the current value of the age reserves.
Definition: m_neuro.f90:2022
subroutine perception_components_neuronal_response_init_set(this, this_agent, param_gp_matrix_light, param_gp_matrix_depth, param_gp_matrix_food_dir, param_gp_matrix_food_mem, param_gp_matrix_conspec, param_gp_matrix_pred_dir, param_gp_matrix_predator, param_gp_matrix_stomach, param_gp_matrix_bodymass, param_gp_matrix_energy, param_gp_matrix_age, param_gp_matrix_reprfac, param_gerror_cv_light, param_gerror_cv_depth, param_gerror_cv_food_dir, param_gerror_cv_food_mem, param_gerror_cv_conspec, param_gerror_cv_pred_dir, param_gerror_cv_predator, param_gerror_cv_stomach, param_gerror_cv_bodymass, param_gerror_cv_energy, param_gerror_cv_age, param_gerror_cv_reprfac, param_gene_label_light, param_gene_label_depth, param_gene_label_food_dir, param_gene_label_food_mem, param_gene_label_conspec, param_gene_label_pred_dir, param_gene_label_predator, param_gene_label_stomach, param_gene_label_bodymass, param_gene_label_energy, param_gene_label_age, param_gene_label_reprfac)
Set and calculate individual perceptual components for this motivational state using the neuronal res...
Definition: m_neuro.f90:4709
elemental real(srp) function percept_energy_get_current(this)
Get the current value of the energy reserves.
Definition: m_neuro.f90:1972
elemental real(srp) function consp_percept_get_size(this)
Get the conspecific perception component body size.
Definition: m_neuro.f90:2200
elemental subroutine gos_agent_set_dead(this)
Set the individual to be dead. Note that this function does not deallocate the individual agent objec...
Definition: m_neuro.f90:7819
elemental real(srp) function percept_memory_food_get_mean_size(this, last)
Get the average size of food item per single time step within the whole perceptual memory stack.
Definition: m_neuro.f90:3741
elemental subroutine percept_depth_destroy_deallocate(this)
Destroy / deallocate depth perception component. Really necessary only when perception objects are al...
Definition: m_neuro.f90:3356
real(srp) function predator_capture_probability_calculate_pred(this, this_predator, is_freezing, time_step_model)
Calculate the probability of attack and capture of the this agent by the predator this_predator....
Definition: m_neuro.f90:9256
elemental subroutine percept_consp_create_init(this, maximum_number_conspecifics)
Create conspecifics perception object, it is an array of conspecific perception components.
Definition: m_neuro.f90:2257
elemental real(srp) function state_motivation_stomach_get(this)
Standard "get" function for the state neuronal stomach effect component.
Definition: m_neuro.f90:5838
elemental real(srp) function percept_food_get_meandist_found(this)
Get the average distance to the food items seen. Trivial.
Definition: m_neuro.f90:1501
subroutine appraisal_perceptual_comps_motiv_neur_response_calculate(this)
Get the perceptual components of all motivational states by passing perceptions via the neuronal resp...
Definition: m_neuro.f90:6494
elemental real(srp) function motivation_maximum_value_motivation_finl(this)
Calculate the maximum value of the final motivations across all motivational state components.
Definition: m_neuro.f90:6276
elemental real(srp) function state_motivation_predator_get(this)
Standard "get" function for the state neuronal predators effect component.
Definition: m_neuro.f90:5826
elemental real(srp) function state_motivation_percept_maxval(this)
Calculate the maximum value over all the perceptual components of this motivational state component.
Definition: m_neuro.f90:6003
subroutine consp_percept_make(this, location, size, mass, dist, cid, is_male)
Make a single conspecific perception component. This is a single conspecific located within the visua...
Definition: m_neuro.f90:2135
logical function reproduction_success_stochast(this, prob)
Determine a stochastic outcome of this agent reproduction. Returns TRUE if the agent has reproduced s...
Definition: m_neuro.f90:7195
elemental subroutine percept_predator_create_init(this, maximum_number_predators)
Create predator perception object, it is an array of spatial perception components.
Definition: m_neuro.f90:2800
elemental real(srp) function spatialobj_percept_get_dist(this)
Get the distance to an arbitrary spatial object perception component.
Definition: m_neuro.f90:2708
elemental subroutine consp_percept_comp_create(this)
Create a single conspecific perception component at an undefined position with default properties.
Definition: m_neuro.f90:2101
elemental subroutine percept_consp_destroy_deallocate(this)
Deallocate and delete a conspecific perception object.
Definition: m_neuro.f90:2327
elemental subroutine percept_bodymass_create_init(this)
Initiate an empty body mass perception object.
Definition: m_neuro.f90:1911
elemental logical function food_perception_is_seeing_food(this)
Check if the agent sees any food items within its visual range.
Definition: m_neuro.f90:1766
elemental subroutine percept_stomach_create_init(this)
Initiate an empty stomach capacity perception object.
Definition: m_neuro.f90:1859
elemental integer function percept_consp_get_count_seen(this)
Get the number (count) of conspecifics seen. Trivial.
Definition: m_neuro.f90:2317
subroutine food_perception_get_visrange_objects(this, food_resource_available, time_step_model)
Get available food items within the visual range of the agent, which the agent can perceive and there...
Definition: m_neuro.f90:1556
elemental subroutine percept_food_create_init(this, maximum_number_food_items)
Initiate an empty food perception object with known number of components.
Definition: m_neuro.f90:1368
elemental real(srp) function predation_risk_backend(pred_count, pred_memory_mean, weight_direct)
Simple computational backend for the risk of predation that is used in objective risk function the_ne...
Definition: m_neuro.f90:4417
elemental subroutine, private gos_init_zero_state(this)
Initialise GOS engine components to a zero state. The values are set to commondata::missing,...
Definition: m_neuro.f90:7788
elemental logical function motivation_val_is_maximum_value_motivation_finl(this, test_value)
Checks if the test value is the maximum final motivation value across all motivational state componen...
Definition: m_neuro.f90:6292
elemental integer function perception_predator_above_calculate(this)
Calculate the number of predators in the perception object that are located above the actor agent.
Definition: m_neuro.f90:8683
elemental subroutine percept_memory_predators_mean_split(this, window, split_val, older, newer)
Get the average number of predators per single time step within the perceptual memory stack,...
Definition: m_neuro.f90:4147
elemental real(srp) function state_motivation_motivation_prim_get(this)
Standard "get" function for the root state, get the overall primary motivation value (before modulati...
Definition: m_neuro.f90:5898
elemental subroutine motivation_reset_gos_indicators(this)
Reset all GOS indicators for this motivation object.
Definition: m_neuro.f90:6231
elemental subroutine, private perception_objects_init_agent(this)
Initialise all the perception objects for the current agent. Do not fill perception objects with the ...
Definition: m_neuro.f90:4314
elemental integer function perception_predator_below_calculate(this)
Calculate the number of predators in the perception object that are located below the actor agent.
Definition: m_neuro.f90:8656
real(srp) function predator_capture_probability_calculate_spatobj(this, this_predator, attack_rate, is_freezing, time_step_model)
Calculate the probability of attack and capture of the this agent by the predator this_predator....
Definition: m_neuro.f90:9138
elemental real(srp) function perception_predator_dist_above_calculate(this)
Calculate the average distance to all predators in the current perception object that are above the a...
Definition: m_neuro.f90:9069
elemental subroutine gos_reset_motivations_non_dominant(this)
Reset all motivation states as not dominant with respect to the GOS.
Definition: m_neuro.f90:7833
subroutine spatial_percept_set_cid(this, id)
Set unique id for the conspecific perception component.
Definition: m_neuro.f90:2062
pure subroutine percept_consp_make_fill_arrays(this, consps)
Make the conspecifics perception object, fill it with the actual arrays.
Definition: m_neuro.f90:2298
elemental integer function perception_predator_above_horiz_calculate(this, hz_lower, hz_upper)
Calculate the number of predators in the perception object that are located above the actor agent wit...
Definition: m_neuro.f90:8759
subroutine perception_components_neuronal_response_calculate(this, this_agent, param_gp_matrix_light, param_gp_matrix_depth, param_gp_matrix_food_dir, param_gp_matrix_food_mem, param_gp_matrix_conspec, param_gp_matrix_pred_dir, param_gp_matrix_predator, param_gp_matrix_stomach, param_gp_matrix_bodymass, param_gp_matrix_energy, param_gp_matrix_age, param_gp_matrix_reprfac, param_gerror_cv_light, param_gerror_cv_depth, param_gerror_cv_food_dir, param_gerror_cv_food_mem, param_gerror_cv_conspec, param_gerror_cv_pred_dir, param_gerror_cv_predator, param_gerror_cv_stomach, param_gerror_cv_bodymass, param_gerror_cv_energy, param_gerror_cv_age, param_gerror_cv_reprfac, perception_override_light, perception_override_depth, perception_override_food_dir, perception_override_food_mem, perception_override_conspec, perception_override_pred_dir, perception_override_predator, perception_override_stomach, perception_override_bodymass, perception_override_energy, perception_override_age, perception_override_reprfac)
Calculate individual perceptual components for this motivational state using the neuronal response fu...
Definition: m_neuro.f90:5275
elemental real(srp) function get_prop_mass(this)
Get the body mass property of a polymorphic object. The object can be of the following extension of t...
Definition: m_neuro.f90:9426
elemental subroutine percept_memory_food_mean_size_split(this, window, split_val, older, newer)
Get the average size of food items per single time step within the perceptual memory stack,...
Definition: m_neuro.f90:3794
elemental real(srp) function percept_memory_food_get_mean_n(this, last)
Get the average number of food items per single time step within the whole perceptual memory stack.
Definition: m_neuro.f90:3597
elemental character(len=label_length) function state_motivation_fixed_label_get(this)
Get the fixed label for this motivational state. Note that the label is fixed and cannot be changed.
Definition: m_neuro.f90:5935
real(srp) function food_perception_probability_capture_memory_object(this, last, time_step_model)
Calculate the probability of capture of a subjective representation of food item based on the data fr...
Definition: m_neuro.f90:1781
elemental real(srp) function consp_percept_get_dist(this)
Get the conspecific perception component distance.
Definition: m_neuro.f90:2221
elemental integer function perception_food_items_above_horiz_calculate(this, hz_lower, hz_upper)
Calculate the number of food items in the perception object that are located above the actor agent wi...
Definition: m_neuro.f90:8349
subroutine percept_light_set_current(this, timestep, depth)
Set the current light level into the perception component.
Definition: m_neuro.f90:3263
subroutine age_perception_get_object(this)
Get the age perception objects into the individual PERCEPTION object layer.
Definition: m_neuro.f90:3478
elemental subroutine state_reproduce_zero(this)
Init and cleanup reproductive motivation object. The only difference from the base root STATE_MOTIVAT...
Definition: m_neuro.f90:6185
elemental subroutine motivation_primary_sum_components(this, max_val)
Calculate the primary motivations from motivation-specific perception appraisal components....
Definition: m_neuro.f90:6329
elemental real(srp) function state_motivation_conspec_get(this)
Standard "get" function for the state neuronal conspecifics effect component.
Definition: m_neuro.f90:5802
elemental subroutine percept_consp_number_seen(this, number_set)
Set the total number of conspecifics perceived (seen) in the conspecific perception object....
Definition: m_neuro.f90:2284
elemental real(srp) function emotional_memory_hunger_get_mean(this, last)
Get the average value of the hunger motivation state within the whole emotional memory stack.
Definition: m_neuro.f90:7322
elemental subroutine percept_reprfac_destroy_deallocate(this)
Destroy / deallocate reproductive factor perception component. Really necessary only when perception ...
Definition: m_neuro.f90:3400
character(len= *), parameter, private modname
Definition: m_neuro.f90:25
pure real(srp) function, dimension(:), allocatable motivation_return_final_as_vector(this)
Return the vector of final motivation values for all motivational state components.
Definition: m_neuro.f90:6262
elemental real(srp) function get_prop_size(this)
Get the body size property of a polymorphic object. The object can be of the following extension of t...
Definition: m_neuro.f90:9385
elemental subroutine percept_light_destroy_deallocate(this)
Destroy / deallocate light perception component. Really necessary only when perception objects are al...
Definition: m_neuro.f90:3284
elemental subroutine percept_food_destroy_deallocate(this)
Deallocate and delete a food perception object.
Definition: m_neuro.f90:1515
subroutine energy_perception_get_object(this)
Get the energy reserves perception objects into the individual PERCEPTION object layer.
Definition: m_neuro.f90:3462
subroutine spatialobj_percept_make(this, location, size, dist, cid)
Make a single arbitrary spatial object perception component.
Definition: m_neuro.f90:2654
elemental real(srp) function consp_percept_get_mass(this)
Get the conspecific perception component body mass.
Definition: m_neuro.f90:2210
real(srp) function spatialobj_percept_visibility_visual_range(this, object_area, contrast, time_step_model)
Calculate the visibility range of this spatial object. Wrapper to the visual_range function....
Definition: m_neuro.f90:2729
elemental subroutine, private appraisal_init_zero_cleanup_all(this)
Initialise and cleanup all appraisal object components and sub-objects.
Definition: m_neuro.f90:6449
elemental real(srp) function perception_food_mass_below_calculate(this)
Calculate the average mass of a food item from all the items in the current perception object that ar...
Definition: m_neuro.f90:8191
elemental subroutine percept_predator_number_seen(this, number_set)
Set the total number of predators perceived (seen) in the predator perception object....
Definition: m_neuro.f90:2835
elemental real(srp) function perception_food_mass_above_horiz_calculate(this, hz_lower, hz_upper)
Calculate the average mass of a food item from all the items in the current perception object that ar...
Definition: m_neuro.f90:8454
elemental real(srp) function percept_depth_get_current(this)
Get the current perception of the depth.
Definition: m_neuro.f90:3335
elemental real(srp) function perception_food_mass_below_horiz_calculate(this, hz_lower, hz_upper)
Calculate the average mass of a food item from all the items in the current perception object that ar...
Definition: m_neuro.f90:8255
elemental real(srp) function state_motivation_food_mem_get(this)
Standard "get" function for the state neuronal food items from past memory effect component.
Definition: m_neuro.f90:5790
elemental real(srp) function percept_food_get_meansize_found(this)
Get the average size of food items seen. Trivial.
Definition: m_neuro.f90:1471
elemental real(srp) function percept_reprfac_get_current(this)
Get the current perception of the reproductive factor.
Definition: m_neuro.f90:3379
subroutine consp_perception_get_visrange_objects(this, consp_agents, time_step_model)
Get available conspecific perception objects within the visual range of the agent,...
Definition: m_neuro.f90:2350
subroutine percept_food_number_seen(this, number_set)
Set the total number of food items perceived (seen) in the food perception object....
Definition: m_neuro.f90:1410
elemental integer function perception_food_items_below_calculate(this)
Calculate the number of food items in the perception object that are located below the actor agent.
Definition: m_neuro.f90:8114
elemental integer function perception_conspecifics_above_horiz_calculate(this, hz_lower, hz_upper)
Calculate the number of conspecifics in the perception object that are located above the actor agent ...
Definition: m_neuro.f90:8617
subroutine light_perception_get_object(this, time_step_model)
Get light perception objects into the individual PERCEPTION object layer.
Definition: m_neuro.f90:3294
subroutine predator_perception_get_visrange_objects(this, spatl_agents, time_step_model)
Get available predators perception objects within the visual range of the agent, which the agent can ...
Definition: m_neuro.f90:2940
elemental logical function state_motivation_is_dominant_get(this)
Check if the root state is the dominant state in GOS.
Definition: m_neuro.f90:5921
real(srp) function reproduce_do_probability_reproduction_calc(this, weight_baseline, allow_immature)
Calculate the instantaneous probability of successful reproduction.
Definition: m_neuro.f90:6952
elemental real(srp) function perception_food_mass_above_calculate(this)
Calculate the average mass of a food item from all the items in the current perception object that ar...
Definition: m_neuro.f90:8392
elemental logical function consp_perception_is_seeing_conspecifics(this)
Check if the agent sees any conspecifics within the visual range.
Definition: m_neuro.f90:2615
elemental real(srp) function perception_consp_dist_above_calculate(this)
Calculate the average distance to all conspecifics in the current perception object that are above th...
Definition: m_neuro.f90:8963
elemental subroutine percept_energy_create_init(this)
Initiate an empty energy perception object.
Definition: m_neuro.f90:1962
subroutine bodymass_perception_get_object(this)
Get the body mass perception objects into the individual PERCEPTION object layer.
Definition: m_neuro.f90:3447
pure subroutine percept_predator_make_fill_arrays(this, preds, attack_rate)
Make the predator perception object, fill it with the actual arrays.
Definition: m_neuro.f90:2850
subroutine percept_food_make_fill_arrays(this, items, dist)
Make the food perception object, fill it with the actual data arrays.
Definition: m_neuro.f90:1422
elemental integer function spatial_percept_get_cid(this)
Get the unique id of the food item object.
Definition: m_neuro.f90:2084
elemental integer function perception_food_items_above_calculate(this)
Calculate the number of food items in the perception object that are located above the actor agent.
Definition: m_neuro.f90:8315
elemental subroutine percept_depth_create_init(this)
Make en empty depth perception component. Really necessary only when perception objects are all alloc...
Definition: m_neuro.f90:3326
elemental logical function predator_perception_is_seeing_predators(this)
Check if the agent sees any predators within the visual range.
Definition: m_neuro.f90:3228
elemental integer function perception_conspecifics_below_horiz_calculate(this, hz_lower, hz_upper)
Calculate the number of conspecifics in the perception object that are located below the actor agent ...
Definition: m_neuro.f90:8573
elemental subroutine percept_memory_cleanup_stack(this)
Cleanup and destroy the perceptual memory stack.
Definition: m_neuro.f90:3551
elemental logical function consp_percept_sex_is_female_get(this)
Get the conspecific perception component sex flag (female).
Definition: m_neuro.f90:2242
elemental subroutine spatialobj_percept_comp_create(this)
Create a single arbitrary spatial object perception component at an undefined position with default p...
Definition: m_neuro.f90:2631
elemental subroutine perception_components_attention_weights_init(this, all_vals_fix, all_one, weight_light, weight_depth, weight_food_dir, weight_food_mem, weight_conspec, weight_pred_dir, weight_predator, weight_stomach, weight_bodymass, weight_energy, weight_age, weight_reprfac)
Initialise the attention components of the emotional state to their default parameter values....
Definition: m_neuro.f90:4492
elemental subroutine percept_predator_destroy_deallocate(this)
Deallocate and delete a predator perception object.
Definition: m_neuro.f90:2914
elemental real(srp) function percept_light_get_current(this)
Get the current perception of the illumination.
Definition: m_neuro.f90:3253
elemental subroutine emotional_memory_cleanup_stack(this)
Cleanup and destroy the emotional memory stack.
Definition: m_neuro.f90:7303
subroutine perception_objects_get_all_environmental(this)
A single umbrella subroutine to get all environmental perceptions: light, depth. This procedure invok...
Definition: m_neuro.f90:4261
elemental real(srp) function state_motivation_reprfac_get(this)
Standard "get" function for the state neuronal reproductive factor effect component.
Definition: m_neuro.f90:5886
elemental real(srp) function spatialobj_percept_get_size(this)
Get an arbitrary spatial object perception component size.
Definition: m_neuro.f90:2697
subroutine gos_find_global_state(this)
Find and set the Global Organismic State (GOS) of the agent based on the various available motivation...
Definition: m_neuro.f90:7509
elemental subroutine percept_memory_food_mean_n_split(this, window, split_val, older, newer)
Get the average number of food items per single time step within the perceptual memory stack,...
Definition: m_neuro.f90:3650
elemental logical function motivation_val_is_maximum_value_motivation_finl_o(this, test_motivation)
Checks if the test value is the maximum final motivation value across all motivational state componen...
Definition: m_neuro.f90:6311
elemental subroutine emotional_memory_add_gos_to_stack(this, v_gos_label, v_gos_arousal, v_gos_repeated)
Add the current GOS label or/and arousal value and/or arousal repeat count into the emotional memory ...
Definition: m_neuro.f90:7277
elemental subroutine percept_bodymass_destroy_deallocate(this)
Destroy the body mass perception object and deallocate.
Definition: m_neuro.f90:1948
elemental integer function percept_memory_predators_get_total(this)
Get the total number of predators within the whole perceptual memory stack.
Definition: m_neuro.f90:4072
elemental real(srp) function gos_get_arousal_level(this)
Get the overall level of arousal. Arousal is the current level of the dominant motivation that has br...
Definition: m_neuro.f90:7883
elemental integer function perception_conspecifics_above_calculate(this)
Calculate the number of conspecifics in the perception object that are located above the actor agent.
Definition: m_neuro.f90:8541
elemental real(srp) function percept_memory_predators_get_mean(this, last)
Get the average number of predators per single time step within the whole perceptual memory stack.
Definition: m_neuro.f90:4095
elemental real(srp) function percept_memory_food_get_mean_dist(this, last, undef_ret_null)
Get the average distance to food item per single time step within the whole perceptual memory stack.
Definition: m_neuro.f90:3885
subroutine gos_attention_modulate_weights(this)
Modulate the attention weights to suppress all perceptions alternative to the current GOS....
Definition: m_neuro.f90:7900
subroutine appraisal_motivation_modulation_non_genetic(this, no_modulation)
Produce modulation of the primary motivations, that result in the final motivation values (_finl)....
Definition: m_neuro.f90:6688
subroutine repfac_perception_get_object(this)
Get the reproductive factor perception objects into the individual PERCEPTION object layer.
Definition: m_neuro.f90:3494
elemental real(srp) function percept_stomach_get_avail_capacity(this)
Get the currently available value of the available stomach volume.
Definition: m_neuro.f90:1869
elemental real(srp) function state_motivation_pred_dir_get(this)
Standard "get" function for the state neuronal direct predation effect component.
Definition: m_neuro.f90:5814
elemental integer function percept_predator_get_count_seen(this)
Get the number (count) of predators seen. Trivial.
Definition: m_neuro.f90:2904
elemental subroutine perception_objects_destroy(this, clean_memory)
Destroy and deallocate all perception objects.
Definition: m_neuro.f90:4336
elemental real(srp) function percept_food_get_meanmass_found(this)
Get the average mass of food items seen. Trivial.
Definition: m_neuro.f90:1485
elemental character(len=label_length) function gos_global_get_label(this)
Get the current global organismic state (GOS).
Definition: m_neuro.f90:7848
elemental real(srp) function perception_predation_risk_objective(this)
Calculate the risk of predation as being perceived / assessed by this agent.
Definition: m_neuro.f90:4374
pure subroutine state_motivation_attention_weights_transfer(this, copy_from)
Transfer attention weights between two motivation state components. The main use of this subroutine w...
Definition: m_neuro.f90:5953
elemental subroutine emotional_memory_add_to_stack(this, v_hunger, v_defence_fear, v_reproduction, v_gos_label, v_gos_arousal, v_gos_repeated)
Add emotional components into the memory stack.
Definition: m_neuro.f90:7230
subroutine percept_reprfac_set_current(this, reprfac)
Set the current reproductive factor level into perception component.
Definition: m_neuro.f90:3389
elemental real(srp) function perception_consp_dist_below_calculate(this)
Calculate the average distance to all conspecifics in the current perception object that are below th...
Definition: m_neuro.f90:8910
elemental subroutine percept_memory_add_to_stack(this, light, depth, food, foodsize, fooddist, consp, pred, stom, bdmass, energ, reprfac)
Add perception components into the memory stack.
Definition: m_neuro.f90:3515
elemental subroutine motivation_init_all_zero(this)
Init the expectancy components to a zero state.
Definition: m_neuro.f90:6215
elemental logical function consp_percept_sex_is_male_get(this)
Get the conspecific perception component sex flag (male).
Definition: m_neuro.f90:2232
elemental real(srp) function percept_bodymass_get_current(this)
Get the current value of the body mass perception.
Definition: m_neuro.f90:1921
elemental subroutine percept_energy_destroy_deallocate(this)
Destroy the energy perception object and deallocate.
Definition: m_neuro.f90:1998
elemental subroutine percept_age_create_init(this)
Initiate an empty age perception object.
Definition: m_neuro.f90:2012
elemental integer function percept_memory_food_get_total(this)
Get the total number of food items within the whole perceptual memory stack.
Definition: m_neuro.f90:3574
elemental subroutine perception_objects_add_memory_stack(this)
Add the various perception objects to the memory stack object. This procedure is called after all the...
Definition: m_neuro.f90:4231
elemental real(srp) function state_motivation_calculate_prim(this, maxvalue)
Calculate the level of primary motivation for this specific emotional state component.
Definition: m_neuro.f90:6018
elemental real(srp) function state_motivation_bodymass_get(this)
Standard "get" function for the state neuronal body mass effect component.
Definition: m_neuro.f90:5850
elemental real(srp) function state_motivation_light_get(this)
Standard "get" function for the state neuronal light effect component.
Definition: m_neuro.f90:5754
subroutine percept_stomach_update_avail_capacity(this, current_volume)
Set and update the currently available value of the available stomach volume.
Definition: m_neuro.f90:1883
pure subroutine percept_predator_set_attack_rate_scalar(this, attack_rate)
Set an array of the attack rates for the predator perception object.
Definition: m_neuro.f90:2893
elemental real(srp) function perception_component_maxval(this)
Calculate the maximum value over all the perceptual components.
Definition: m_neuro.f90:5977
elemental subroutine percept_stomach_destroy_deallocate(this)
Destroy the stomach perception object and deallocate it.
Definition: m_neuro.f90:1897
elemental integer function percept_food_get_count_found(this)
Get the number (count) of food items seen. Trivial.
Definition: m_neuro.f90:1461
elemental real(srp) function state_motivation_depth_get(this)
Standard "get" function for the state neuronal depth effect component.
Definition: m_neuro.f90:5766
elemental subroutine appraisal_add_final_motivations_memory(this)
Add individual final emotional state components into the emotional memory stack. This is a wrapper to...
Definition: m_neuro.f90:6935
elemental subroutine state_hunger_zero(this)
Init and cleanup hunger motivation object. The only difference from the base root STATE_MOTIVATION_BA...
Definition: m_neuro.f90:6121
elemental real(srp) function state_motivation_energy_get(this)
Standard "get" function for the state neuronal energy reserves effect component.
Definition: m_neuro.f90:5862
elemental real(srp) function emotional_memory_reproduct_get_mean(this, last)
Get the average value of the reproductive motivation state within the whole emotional memory stack.
Definition: m_neuro.f90:7405
subroutine percept_depth_set_current(this, cdepth)
Set the current depth level into the perception component.
Definition: m_neuro.f90:3345
elemental integer function perception_food_items_below_horiz_calculate(this, hz_lower, hz_upper)
Calculate the number of food items in the perception object that are located below the actor agent wi...
Definition: m_neuro.f90:8148
subroutine appraisal_motivation_modulation_genetic(this, no_genetic_modulation)
Produce modulation of the primary motivations, that result in the final motivation values (_finl)....
Definition: m_neuro.f90:6788
elemental subroutine motivation_modulation_absent(this)
Produce modulation of the primary motivations, that result in the final motivation values (_finl)....
Definition: m_neuro.f90:6386
elemental subroutine perception_component_motivation_init_zero(this)
Initialise perception components for a motivation state object.
Definition: m_neuro.f90:6100
elemental subroutine state_fear_defence_zero(this)
Init and cleanup fear state motivation object. The only difference from the base root STATE_MOTIVATIO...
Definition: m_neuro.f90:6153
real(srp) function predation_capture_probability_risk_wrapper(this, is_freezing)
Calculate the overall direct predation risk for the agent, i.e. the probability of attack and capture...
Definition: m_neuro.f90:9346
pure subroutine percept_predator_set_attack_rate_vector(this, attack_rate)
Set an array of the attack rates for the predator perception object.
Definition: m_neuro.f90:2882
elemental subroutine percept_memory_food_mean_dist_split(this, window, split_val, older, newer)
Get the average distance to food items per single time step within the perceptual memory stack,...
Definition: m_neuro.f90:3950
elemental real(srp) function motivation_max_perception_calc(this)
Calculate maximum value of the perception components across all motivations.
Definition: m_neuro.f90:6245
elemental real(srp) function state_motivation_motivation_get(this)
Standard "get" function for the root state, get the overall final motivation value (after modulation)...
Definition: m_neuro.f90:5910
subroutine percept_age_update_current(this, current)
Set and update the current age perception value.
Definition: m_neuro.f90:2035
elemental real(srp) function emotional_memory_arousal_mean(this, last)
Get the average value of the GOS arousal within the whole emotional memory stack.
Definition: m_neuro.f90:7447
elemental integer function perception_conspecifics_below_calculate(this)
Calculate the number of conspecifics in the perception object that are located below the actor agent.
Definition: m_neuro.f90:8514
elemental real(srp) function perception_food_dist_above_calculate(this)
Calculate the average distance to all food items in the current perception object that are above the ...
Definition: m_neuro.f90:8854
subroutine stomach_perception_get_object(this)
Get the stomach capacity perception objects into the individual PERCEPTION object layer.
Definition: m_neuro.f90:3428
CONDITION defines the physical condition of the agent
Definition: m_body.f90:29
REPRODUCTION type defines parameters of the reproduction system.
Definition: m_body.f90:252
Definition of a single food item. Food item is a spatial object that has specific location in space....
Definition: m_env.f90:371
Definition of the super-type FOOD resource type. This is a superclass, several sub-classes can be def...
Definition: m_env.f90:434
Definition of the PREDATOR objects. Predator is a moving agent that hunts on the evolving AHA agents ...
Definition: m_env.f90:506
Definition of a spatial object. Spatial object determines the position of the agent,...
Definition: m_env.f90:50
The appraisal level. At this level, perception objects are feed into the commondata::gamma2gene() sig...
Definition: m_neuro.f90:1222
This type defines a single conspecific perception component. It is required for the the_neurobio::per...
Definition: m_neuro.f90:141
Global organismic state (GOS) level. GOS is defined by the dominant motivational state component (STA...
Definition: m_neuro.f90:1304
Individual motivation/emotion memory stack, a memory component that saves the values of the final mot...
Definition: m_neuro.f90:1166
Individual perception memory(history) stack, a memory component that saves perception values at previ...
Definition: m_neuro.f90:447
Motivation is a collection of all internal motivational states of the agent. This type is also used i...
Definition: m_neuro.f90:1101
This type defines how the agent perceives its own age in terms of the model discrete time step.
Definition: m_neuro.f90:355
This type defines how the agent perceives its own body mass it can be important for state-dependency.
Definition: m_neuro.f90:315
Perceptual components of motivational states. Plugged into all STATE_, attention etc....
Definition: m_neuro.f90:875
This type defines how the agent perceives conspecifics.
Definition: m_neuro.f90:183
Perception of the current depth horizon.
Definition: m_neuro.f90:418
This type defines how the agent perceives its own energy reserves it can be important for state-depen...
Definition: m_neuro.f90:335
This type defines how the agent perceives food items. The food perception object the_neurobio::percep...
Definition: m_neuro.f90:46
Perception of the ambient illumination. This is a very simple perception component,...
Definition: m_neuro.f90:400
This type defines how the agent perceives a predator.
Definition: m_neuro.f90:246
Perception of the reproductive factor, reproductive factor depends on the sex hormones differently in...
Definition: m_neuro.f90:374
This type defines how the agent perceives its own stomach capacity.
Definition: m_neuro.f90:292
The perception architecture of the agent. See "The perception mechanism" for a general overview....
Definition: m_neuro.f90:561
This type defines a single spatial perception component, i.e. some single elementary spatial object t...
Definition: m_neuro.f90:122
This type defines a single arbitrary spatial object perception component. For example,...
Definition: m_neuro.f90:215
The state of fear state. Evokes active escape, fleeing, emigration and habitat switch.
Definition: m_neuro.f90:1078
The motivational state of hunger. Evokes food seeking, eating, higher activity, emigrating and habita...
Definition: m_neuro.f90:1069
These types describe the neurobiological states of the agent. (1) Each state may have several compone...
Definition: m_neuro.f90:952
The state of reproduction. Evokes seeking conspecifics and mating during the reproductive phase.
Definition: m_neuro.f90:1087