"""
Additional FeatureCoordinators specific to cortical modelling work,
supplementing the general-purpose ones in imagen.patterncoordinator.
"""
import copy
import param
from param.parameterized import ParamOverrides
from imagen.patterncoordinator import FeatureCoordinator
from imagen import Sweeper
import numbergen
[docs]class DisparityCoordinator(FeatureCoordinator):
"""
Coordinates the disparity (difference of pattern locations) of two
pattern generators. The pattern_label of the generators must
contain 'Left' or 'Right'
"""
disparity_bound = param.Number(default=4.0*0.041665/2.0,doc="""
Maximum difference of the pattern locations between the two
eyes (on the x axis).""")
def __call__(self, pattern, pattern_label, pattern_number, master_seed, **params):
p = ParamOverrides(self,params,allow_extra_keywords=True)
new_pattern=copy.copy(pattern)
if(pattern_label.count('Left')):
new_pattern.x = pattern.get_value_generator('x')-\
numbergen.UniformRandom(lbound=-p.disparity_bound,
ubound=p.disparity_bound,
seed=master_seed+45+pattern_number,
name="DisparityCoordinator"+str(pattern_number))
elif(pattern_label.count('Right')):
new_pattern.x = pattern.get_value_generator('x')+\
numbergen.UniformRandom(lbound=-p.disparity_bound,
ubound=p.disparity_bound,
seed=master_seed+45+pattern_number,
name="DisparityCoordinator"+str(pattern_number))
else:
self.warning('Skipping region %s; Disparity is defined '
'only for Left and Right retinas.' % pattern)
return new_pattern
[docs]class OcularityCoordinator(FeatureCoordinator):
"""
Coordinates the ocularity (brightness difference) of two pattern
generators. The pattern_label of the generators must contain
'Left' or 'Right'
"""
dim_fraction = param.Number(default=0.7,bounds=(0.0,1.0),doc="""
Fraction by which the pattern brightness varies between the two eyes.""")
def __call__(self, pattern, pattern_label, pattern_number, master_seed, **params):
p = ParamOverrides(self,params,allow_extra_keywords=True)
new_pattern=copy.copy(pattern)
if(pattern_label.count('Left')):
new_pattern.scale = (1-p.dim_fraction) + p.dim_fraction * \
(2.0-numbergen.UniformRandom(lbound=0,
ubound=2,
seed=master_seed+55+pattern_number,
name="OcularityCoordinator"+str(pattern_number)))
elif(pattern_label.count('Right')):
new_pattern.scale = (1-p.dim_fraction) + p.dim_fraction * \
numbergen.UniformRandom(lbound=0,
ubound=2,
seed=master_seed+55+pattern_number,
name="OcularityCoordinator"+str(pattern_number))
else:
self.warning('Skipping region %s; Ocularity is defined'
' only for Left and Right retinas.' % pattern)
return new_pattern
[docs]class SpatialFrequencyCoordinator(FeatureCoordinator):
"""
Coordinates the size of pattern generators. This is useful when
multiple spatial frequency channels are used, to cover a wide
range of sizes of pattern generators.
"""
sf_spacing = param.Number(default=2.0,bounds=(0.0,None),doc="""
Determines the factor by which successive SF channels increase
in size. Together with sf_max_channel, this is used to compute
the upper bound of the size of the supplied pattern
generator.""")
sf_max_channel = param.Integer(default=2,bounds=(2,None),
softbounds=(1,4), doc="""
Highest spatial frequency channel. Together with sf_spacing,
this is used to compute the upper bound of the size of the
supplied pattern generator.""")
def __call__(self, pattern, pattern_label, pattern_number, master_seed, **params):
p = ParamOverrides(self,params,allow_extra_keywords=True)
new_pattern=copy.copy(pattern)
new_pattern.size=pattern.get_value_generator('size')*\
numbergen.UniformRandom(lbound=1,
ubound=p.sf_spacing**(p.sf_max_channel-1),
seed=master_seed+77+pattern_number,
name="SpatialFrequencyCoordinator"+str(pattern_number))
return new_pattern
[docs]class MotionCoordinator(FeatureCoordinator):
"""
Coordinates the motion of patterns.
"""
reset_period = param.Number(default=4,bounds=(0.0,None),doc="""
Period between generating each new translation episode.""")
speed = param.Number(default=2.0/24.0,bounds=(0.0,None),doc="""
The speed with which the pattern should move,
in sheet coordinates per time_fn unit.""")
time_fn = param.Callable(default=param.Dynamic.time_fn,doc="""
Function to generate the time used as a base for translation.""")
def __call__(self, pattern, pattern_label, pattern_number, master_seed, **params):
p = ParamOverrides(self,params,allow_extra_keywords=True)
err_msg = "%s must be enabled for motion"
if not param.Dynamic.time_dependent:
raise RuntimeError(err_msg % "param.Dynamic.time_dependent")
if not numbergen.RandomDistribution.time_dependent:
raise RuntimeError(err_msg % "numbergen.RandomDistribution.time_dependent")
moved_pattern = Sweeper(generator=copy.deepcopy(pattern),
speed=p.speed,
reset_period=p.reset_period,
time_fn=p.time_fn)
return moved_pattern
feature_coordinators=[('od',OcularityCoordinator),
('dy',DisparityCoordinator),
('sf',SpatialFrequencyCoordinator),
('dr',MotionCoordinator)]