docs: def load_workflow(self, workflow_id):
          """
          Load workflow from the database and store in memory
          :param workflow_id: The workflow id
          :return: The workflow
          """
          with switch_db(WorkflowDefinitionModel, db_alias='hyperstream'):
              workflow_definition = WorkflowDefinitionModel.objects.get(workflow_id=workflow_id)
              if not workflow_definition:
                  logging.warn("Attempted to load workflow with id {}, but not found".format(workflow_id))
  
              workflow = Workflow(
                  workflow_id=workflow_id,
                  name=workflow_definition.name,
                  description=workflow_definition.description,
                  owner=workflow_definition.owner,
                  online=workflow_definition.online,
                  monitor=workflow_definition.monitor
              )
  
              for n in workflow_definition.nodes:
                  workflow.create_node(
                      stream_name=n.stream_name,
                      channel=self.channel_manager.get_channel(n.channel_id),
                      plates=[self.plate_manager.plates[p] for p in n.plate_ids])
  
              for f in workflow_definition.factors:
                  source_nodes = [workflow.nodes[node_id] for node_id in f.sources] if f.sources else []
                  sink_nodes = [workflow.nodes[node_id] for node_id in f.sinks] if f.sinks else []
                  alignment_node = workflow.nodes[f.alignment_node] if f.alignment_node else None
                  splitting_node = workflow.nodes[f.splitting_node] if f.splitting_node else None
                  output_plate = f.output_plate
  
                  parameters = Tool.parameters_from_model(f.tool.parameters)
                  # tool = dict(name=f.tool.name, parameters=parameters)
                  tool = self.channel_manager.get_tool(f.tool.name, parameters, version=None)
  
                  if f.factor_type == "Factor":
                      if len(sink_nodes) != 1:
                          raise ValueError(
                              "Standard factors should have a single sink node, received {}"
                              .format(len(sink_nodes)))
  
                      if splitting_node is not None:
                          raise ValueError(
                              "Standard factors do not support splitting nodes")
  
                      if output_plate is not None:
                          raise ValueError(
                              "Standard factors do not support output plates")
  
                      workflow.create_factor(
                          tool=tool,
                          sources=source_nodes,
                          sink=sink_nodes[0],
                          alignment_node=alignment_node
                      )
  
                  elif f.factor_type == "MultiOutputFactor":
                      if len(source_nodes) > 1:
                          raise ValueError(
                              "MultiOutputFactor factors should have at most one source node, received {}"
                              .format(len(source_nodes)))
  
                      if len(sink_nodes) != 1:
                          raise ValueError(
                              "MultiOutputFactor factors should have a single sink node, received {}"
                              .format(len(sink_nodes)))
  
                      if alignment_node is not None:
                          raise ValueError(
                              "MultiOutputFactor does not support alignment nodes")
  
                      if output_plate is not None:
                          raise ValueError(
                              "MultiOutputFactor does not support output plates")
  
                      workflow.create_multi_output_factor(
                          tool=tool,
                          source=source_nodes[0] if source_nodes else None,
                          splitting_node=splitting_node,
                          sink=sink_nodes[0]
                      )
  
                  elif f.factor_type == "NodeCreationFactor":
                      if len(source_nodes) > 1:
                          raise ValueError(
                              "NodeCreationFactor factors should no more than one source node, received {}"
                              .format(len(source_nodes)))
  
                      if len(sink_nodes) != 0:
                          raise ValueError(
                              "NodeCreationFactor factors should not have sink nodes"
                              .format(len(sink_nodes)))
  
                      if output_plate is None:
                          raise ValueError(
                              "NodeCreationFactor requires an output plate definition")
  
                      workflow.create_node_creation_factor(
                          tool=tool,
                          source=source_nodes[0] if source_nodes else None,
                          output_plate=output_plate.to_mongo().to_dict(),
                          plate_manager=self.plate_manager
                      )
  
                  else:
                      raise NotImplementedError("Unsupported factor type {}".format(f.factor_type))
  
              self.add_workflow(workflow, False)
              return workflow