build method
Builds the Module and all subModules within it.
It is recommended not to override build nor put logic in build
unless you have good reason to do so. Aim to build up relevant logic in
the constructor.
All logic within this Module must be defined before the call to
super.build(). When overriding this method, you should call
super.build() as the last thing that you do, and you must always call
it.
This method traverses connectivity inwards from this Module's inputs
and outputs to determine which Modules are contained within it.
During this process, it will set a variety of additional information
within the hierarchy.
This function can be used to consume real wallclock time for things like starting up interactions with independent processes (e.g. cosimulation).
This function should only be called one time per Module.
The hierarchy is built "bottom-up", so leaf-level Modules are built
before the Modules which contain them.
Implementation
@mustCallSuper
Future<void> build() async {
if (hasBuilt) {
throw Exception(
'This Module has already been built, and can only be built once.');
}
// construct the list of modules within this module
// 1) trace from outputs of this module back to inputs of this module
for (final output in [..._outputs.values, ...inOuts.values]) {
await _traceOutputForModuleContents(output, dontAddSignal: true);
}
// 2) trace from inputs of all modules to inputs of this module
for (final input in [..._inputs.values, ...inOuts.values]) {
await _traceInputForModuleContents(input, dontAddSignal: true);
}
// set unique module instance names for submodules
final uniquifier = Uniquifier();
for (final module in _subModules) {
module._uniqueInstanceName = uniquifier.getUniqueName(
initialName: Sanitizer.sanitizeSV(module.name),
reserved: module.reserveName);
}
_checkValidHierarchy(visited: {});
_hasBuilt = true;
ModuleTree.rootModuleInstance = this;
}