Adding route descriptors¶
The route_descriptors module stores all the classes and functions to calculate
route descriptors, so if you would like to add a new one, this is the module you will need to modify.
Below, we firstly give a brief description of the module architecture and then we show a practical example
for including a route descriptor.
route_descriptors overview¶
The module is composed by a factory structure in which the subclasses of the abstract class
RouteDescriptor implement the concrete
calculators of the various descriptors, so that, for example, there is a
NrBranches, a NrReactionSteps etc…
For each subclass the concrete implementation the abstract method
compute_descriptor() is developed.
The DescriptorsCalculatorFactory class handles the calls to
the correct RouteDescriptor
subclass based on the user’s input.
The factory is wrapped by the facade function descriptor_calculator().
It takes a graph object and the ‘name’ of the descriptor that should be computed
and returns the value of the descriptor. Currently, all the descriptors are
computed on SynGraph instances, however this is not mandatory and you can implement
your compute_descriptor() method so that it takes a different type
of graph.
Implementing a new descriptor¶
In order to include a new descriptor among those available in LinChemIn, you
firstly need to create a new subclass of the abstract class
RouteDescriptor in the route_descriptors module and
implement its concrete compute_descriptor() method.
class CustomMetric(RouteDescriptor)
""" Subclass of RouteDescriptor representing the CustomMetric. """
def compute_descriptor(self, graph)
# some super cool code
return new_descriptor
The last step is to add the ‘name’ of your descriptor to the route_descriptors dictionary,
to make it available to the factory.
route_descriptors = {
'longest_seq': {'value': LongestSequence,
'info': 'Computes the longest linear sequence in the input SynGraph'},
'nr_steps': {'value': NrReactionSteps,
'info': 'Computes the number of chemical reactions in the input SynGraph'},
'all_paths': {'value': PathFinder,
'info': 'Computes all the paths between the SynRoots and the SynLeaves in the input SynGraph'},
'nr_branches': {'value': NrBranches,
'info': 'Computes the number of branches in the input SynGraph'},
'branchedness': {'value': Branchedness,
'info': 'Computes the "branchedness" of the input SynGraph, weighting the number of '
'branching nodes with their distance from the root'},
'branching_factor': {'value': AvgBranchingFactor,
'info': 'Computes the average branching factor of the input SynGraph'},
'convergence': {'value': Convergence,
'info': 'Computes the "convergence" of the input SynGraph, as the ratio between the '
'longest linear sequence and the number of steps'},
'cdscore': {'value': CDScore,
'info': 'Computes the Convergent Disconnection Score of the input SynGraph'},
'new_desc': {'value': CustomMetric,
'info': 'Brief description that will appear in the helper function'}
}
You can now compute your newly developed descriptor by calling the
descriptor_calculator() function:
from linchemin.rem.route_descriptors import descriptor_calculator
descriptor_value = descriptor_calculator(graph, 'new_desc')
or use it through the facade() function with a list of routes.
from linchemin.interfaces.facade import facade
descriptors, metadata = facade('routes_descriptors', routes_list, descriptors=['new_desc'])