Simpatico
v1.10
|
4.4 Potential Energy Classes (Prev) 4.7 Modules (Next)
A Util::Factory may contain one or more subfactories. Creating a subfactories is an alternative way of adding new classes to the set that can be recognized by a Factory, without modifying the Factory implementation. Subfactories are useful for unit testing and for the construction of modules.
A subfactory may be added to a parent factory by calling the Util::Factory<Base>::addSubfactory() method of the Util::Factory class template. This has a signature:
Any number of subfactories can be added to a parent factory class.
Every subfactory of a Util::Factory<Base> object is another Util::Factory<Base> object. The implementation of a subfactory is thus very similar to that of the original default factory.
A factory and its subfactories (if any) form a tree that is searched in a depth first manner: The factory() method of the parent calls the factory method of each subfactory in a attempt to match a class name, before attempting to match it against its own explicit list of names. A recursive, depth-first search of subfactories is implemented by the trySubfactories() method. This has a signature:
The value of the "classname" parameter is the name of a subclass of Base. This method should be called by the factory() method of every factory class (including subfactories), near the beginning of the method. It calls the factory() method of every subfactory that has been added to that factory, passing the classname string as argument. The factory() method of each subfactory attempts to match this class name, and creates a new object of the desired subclass if it recognizes the name. If a match is found by any subfactory, trySubfactories() immediately stops the search and returns a Base* pointer to the new object. If no match is found by any subfactory, trySubfactories() returns a null pointer.
As an example, imagine that you have written an NvtLangevinIntegrator subclass of McMd::MdIntegrator, because no Langevin integrator is (thus far) distributed with Simpatico. You would then also define a subclass of Factory<MdIntegrator>, which we will called "MyMdIntegratorFactory", with a factory() method that can recognize the name "NvtLangevinIntegrator" and instantiate an object of this new class. Here is an example of the required class definition:
The factory method for this subclass returns a pointer to a new NvtLangevinIntegrator, if the subclassName string is "NvtLangevinIntegrator". It returns a null pointer otherwise.
After writing a custom factory, one must invoke the addSubfactory() method of the default factory to register the new Factory as a subfactory of the default Factory. This must be done in the main program, before the readParam() method is invoked.
Below, we show an example of a main program for an MdSimulation that adds a custom factory MyMdIntegratorFactory as a subfactory to the MdIntegratorFactory.
The addSubfactory() method must be invoked before readParam() in order for the subfactory to be available for use during processing of the parameter file.
When a factory is associated with a Manager object, the parent Manager class also provides an "addSubfactory()" method that has the same effect. This method simply calls the "addSubfactory() method of the associated Factory. For example, to add an analyzer subfactory named myFactory to a ddSim simulation in which the main object is named sim, one could invoke
Here, DdMd::Simulation::analyzerManager() is an accessor that returns the DdMd::AnalyzerManager by reference. This command is equivalent to the longer command sim.analyzerManager().factory().addSubfactory(myFactory), in which "factory()" is a member function of the Util::Manager<T> template that returns the associated Util::Factory<T> object by reference.
The modification of the main program described above requires that the user have access to the relevant factory or Manager object, in order to be able to invoke "addSubfactory()".
In ddSim simulations, access to Factory and Manager classes is provided by the following member functions of DdMd::Simulation:
To access some factories that are associated with Manager classes, such as the Analyzer and Modifier factories, one must call the DdMd::Simulation accessor for the Manager class (listed above), and then call the addSubfactory() method of the parent Manager.
In mcSim and mdSim simulations, access to different factories and managers is provided by member functions of the McMd::Simulation or McMd::System classes, or of the McSimulation, MdSimulation, McSystem or MdSystem subclasses. The required accessor methods are:
Member functions of the McMd::Simulation and McMd::System base classes are also available in subclasses of these classes, and so can be used in either MC or MD simulations. See the page about 4.4 Potential Energy Classes for a more detailed discussion of the peculiarities of the potential energy base and factory classes.
When a factory must be accessed via a member function McMd::System or one of its subclasesses, a reference to the required McSystem or MdSystem object can be obtained using the system() method of the parent McSimulation or MdSimulation object. For example, to add an MdIntegrator factory named myFactory to an mdSim simulation, one might invoke
Here, sim is an instance of MdSimulation. Here, the method McMd::MdSimulation::system() returns a reference to the associated McMd::MdSystem object.
4.4 Potential Energy Classes (Prev) 4 Extending Simpatico (Up) 4.7 Modules (Next)