1515from collections import defaultdict
1616import logging
1717import math
18+ import os
1819from typing import (
1920 Any , Collection , Dict , Iterable , List , Optional , Sequence , Tuple , Union ,
2021 cast , TYPE_CHECKING )
@@ -486,6 +487,73 @@ def set_max_atoms_per_dimension_per_core(
486487 def set_structure (self , structure : BaseStructure ) -> None :
487488 self .__structure = structure
488489
490+ @property
491+ def combined_binary_file_name (self ) -> str :
492+ """
493+ The name of the combined binary file for the vertex.
494+ """
495+ # Split binary name into title and extension
496+ name , ext = os .path .splitext (self .__neuron_impl .binary_name )
497+
498+ # Reunite title and extension and return
499+ return name + self .synapse_executable_suffix + ext
500+
501+ @property
502+ def neuron_core_binary_file_name (self ) -> str :
503+ """
504+ The name of the neuron core binary file for the vertex.
505+ """
506+ # Split binary name into title and extension
507+ name , ext = os .path .splitext (self .__neuron_impl .binary_name )
508+
509+ # Reunite title and extension and return
510+ return name + "_neuron" + ext
511+
512+ @property
513+ def synapse_core_binary_file_name (self ) -> str :
514+ """
515+ The name of the synapse core binary file for the vertex.
516+ """
517+ return "synapses" + self .synapse_executable_suffix + ".aplx"
518+
519+ @property
520+ def combined_binary_exists (self ) -> bool :
521+ """
522+ Whether the combined binary file exists.
523+
524+ :rtype: bool
525+ """
526+ # If we are in virtual machine mode, we can work without binaries
527+ # so easier to assume they exist
528+ if get_config_bool ("Machine" , "virtual_board" ):
529+ return True
530+ try :
531+ SpynnakerDataView ().get_executable_path (
532+ self .combined_binary_file_name )
533+ return True
534+ except KeyError :
535+ return False
536+
537+ @property
538+ def split_binaries_exist (self ) -> bool :
539+ """
540+ Whether the split binary files exist.
541+
542+ :rtype: bool
543+ """
544+ # If we are in virtual machine mode, we can work without binaries
545+ # so easier to assume they exist
546+ if get_config_bool ("Machine" , "virtual_board" ):
547+ return True
548+ try :
549+ SpynnakerDataView ().get_executable_path (
550+ self .neuron_core_binary_file_name )
551+ SpynnakerDataView ().get_executable_path (
552+ self .synapse_core_binary_file_name )
553+ return True
554+ except KeyError :
555+ return False
556+
489557 @property
490558 def use_combined_core (self ) -> bool :
491559 """
@@ -495,6 +563,15 @@ def use_combined_core(self) -> bool:
495563
496564 :rtype: bool
497565 """
566+ # If there are no binaries at all, complain!
567+ if not self .combined_binary_exists and not self .split_binaries_exist :
568+ raise SynapticConfigurationException (
569+ "This model has no binaries! Please compile the binaries"
570+ f" { self .combined_binary_file_name } and/or"
571+ f" ({ self .synapse_core_binary_file_name } and"
572+ f" { self .neuron_core_binary_file_name } )"
573+ " before running the simulation." )
574+
498575 # If we can't use a combined core, use a split core
499576 if not self .__synapse_dynamics .is_combined_core_capable :
500577 if not self .__synapse_dynamics .is_split_core_capable :
@@ -508,6 +585,13 @@ def use_combined_core(self) -> bool:
508585 f"The synapse dynamics { self .__synapse_dynamics } must be"
509586 " run using a synapse core separate from a neuron core."
510587 " Please set the number of synapse cores to 1 or greater." )
588+ if not self .split_binaries_exist :
589+ raise SynapticConfigurationException (
590+ "This model requires split binaries"
591+ f" { self .neuron_core_binary_file_name } and"
592+ f" { self .synapse_core_binary_file_name } but they do not "
593+ "exist. Please compile the split binaries before "
594+ "running the simulation." )
511595 return False
512596
513597 # If we can't use a split core, use a combined core
@@ -518,21 +602,67 @@ def use_combined_core(self) -> bool:
518602 f"The synapse dynamics { self .__synapse_dynamics } must be"
519603 " run using a combined synapse-neuron core."
520604 " Please set the number of synapse cores to 0." )
605+ if not self .combined_binary_exists :
606+ raise SynapticConfigurationException (
607+ "This model requires a combined binary"
608+ f" { self .combined_binary_file_name } , but it does not "
609+ "exist. Please compile the combined binary before "
610+ "running the simulation." )
521611 return True
522612
523613 # If the user has chosen to have a synapse core, add one
524614 if self .__n_synapse_cores is not None and self .__n_synapse_cores > 0 :
615+ if not self .split_binaries_exist :
616+ raise SynapticConfigurationException (
617+ "This model is configured to use split binaries"
618+ f" { self .neuron_core_binary_file_name } and"
619+ f" { self .synapse_core_binary_file_name } but they do not "
620+ "exist. Please compile the split binaries before "
621+ "running the simulation." )
525622 return False
526623
624+ # If the user has chosen to have no synapse cores, use a combined core
625+ if self .__n_synapse_cores is not None and self .__n_synapse_cores == 0 :
626+ if not self .combined_binary_exists :
627+ raise SynapticConfigurationException (
628+ "This model is configured to use a combined binary"
629+ f" { self .combined_binary_file_name } , but it does not "
630+ "exist. Please compile the combined binary before "
631+ "running the simulation." )
632+ return True
633+
527634 # If the time-step is less than 1, use combined core if no synapse
528635 # cores are needed, otherwise use split core
529636 # TODO: Look at if it is possible to include neurons in a combined
530637 # core calculation and update to allow a choice of combined core if
531638 # neurons and synapses fit on a single core
532639 if SpynnakerDataView ().get_simulation_time_step_ms () < 1.0 :
533- return self .n_synapse_cores_required == 0
640+ use_combined = (self .n_synapse_cores_required == 0 )
641+
642+ # We want combined, but it doesn't exist, so use split
643+ # (which is fine)
644+ if use_combined and not self .combined_binary_exists :
645+ return False
534646
535- # If the timestep is 1 or greater, use a combined core generally
647+ # We want split, but it doesn't exist, so use combined, which needs
648+ # a warning as it might not work at this time-step!
649+ if not use_combined and not self .split_binaries_exist :
650+ logger .warning (
651+ "The synapse dynamics are set to use a split core, but "
652+ "the split binaries do not exist. Using the combined "
653+ "core instead, but this may not work at this time-step. "
654+ "To avoid this warning please build the split binaries "
655+ f"{ self .neuron_core_binary_file_name } and "
656+ f"{ self .synapse_core_binary_file_name } ." )
657+ return True
658+
659+ # Use the recommended mode
660+ return use_combined
661+
662+ # If the timestep is 1 or greater, use a combined core generally,
663+ # unless only a split core exists!
664+ if not self .combined_binary_exists :
665+ return False
536666 return True
537667
538668 @property
@@ -616,7 +746,16 @@ def __update_n_synapse_cores(self) -> int:
616746
617747 # If the number of cores needed is more than the maximum, use the
618748 # maximum
619- self .__n_synapse_cores = min (max_n_cores , n_synapse_cores )
749+ if n_synapse_cores > max_n_cores :
750+ logger .warning (
751+ f"Ideally this execution would need { n_synapse_cores } synapse "
752+ f"cores, but only { max_n_cores } cores are available. This may "
753+ "mean that the simulation does not work correctly. Potential "
754+ "solutions include increasing the time_scale_factor, or "
755+ "reducing the number of synapses incoming into each "
756+ "population" )
757+ n_synapse_cores = max_n_cores
758+ self .__n_synapse_cores = n_synapse_cores
620759 assert self .__n_synapse_cores is not None
621760 return self .__n_synapse_cores
622761
0 commit comments