docs: def launch_cif_clean(cif_filter, cif_select, group_cif_raw, group_cif_clean, group_structure, group_workchain, node,
      max_entries, skip_check, parse_engine, daemon):
      """Run the `CifCleanWorkChain` on the entries in a group with raw imported CifData nodes.
  
      It will use the `cif_filter` and `cif_select` scripts of `cod-tools` to clean the input cif file. Additionally, if
      the `group-structure` option is passed, the workchain will also attempt to use the given parse engine to parse the
      cleaned `CifData` to obtain the structure and then use SeeKpath to find the primitive structure, which, if
      successful, will be added to the `group-structure` group.
      """
      # pylint: disable=too-many-arguments,too-many-locals,too-many-statements,too-many-branches
      import inspect
      from datetime import datetime
  
      from aiida import orm
      from aiida.engine import launch
      from aiida.plugins import DataFactory, WorkflowFactory
      from aiida_codtools.common.cli import echo_utc
      from aiida_codtools.common.resources import get_default_options
      from aiida_codtools.common.utils import get_input_node
  
      CifData = DataFactory('cif')  # pylint: disable=invalid-name
      CifCleanWorkChain = WorkflowFactory('codtools.cif_clean')  # pylint: disable=invalid-name
  
      # Collect the dictionary of not None parameters passed to the launch script and print to screen
      local_vars = locals()
      launch_paramaters = {}
      for arg in inspect.getargspec(launch_cif_clean.callback).args:  # pylint: disable=deprecated-method
          if arg in local_vars and local_vars[arg]:
              launch_paramaters[arg] = local_vars[arg]
  
      click.echo('=' * 80)
      click.echo('Starting on {}'.format(datetime.utcnow().isoformat()))
      click.echo('Launch parameters: {}'.format(launch_paramaters))
      click.echo('-' * 80)
  
      if group_cif_raw is not None:
  
          # Get CifData nodes that should actually be submitted according to the input filters
          builder = orm.QueryBuilder()
          builder.append(orm.Group, filters={'id': {'==': group_cif_raw.pk}}, tag='group')
  
          if skip_check:
              builder.append(CifData, with_group='group', project=['*'])
          else:
              # Get CifData nodes that already have an associated workchain node in the `group_workchain` group.
              submitted = orm.QueryBuilder()
              submitted.append(orm.WorkChainNode, tag='workchain')
              submitted.append(orm.Group, filters={'id': {'==': group_workchain.pk}}, with_node='workchain')
              submitted.append(orm.CifData, with_outgoing='workchain', tag='data', project=['id'])
              submitted_nodes = set(pk for entry in submitted.all() for pk in entry)
  
              if submitted_nodes:
                  filters = {'id': {'!in': submitted_nodes}}
              else:
                  filters = {}
  
              # Get all CifData nodes that are not included in the submitted node list
              builder.append(CifData, with_group='group', filters=filters, project=['*'])
  
          if max_entries is not None:
              builder.limit(int(max_entries))
  
          nodes = [entry[0] for entry in builder.all()]
  
      elif node is not None:
  
          nodes = [node]
  
      else:
          raise click.BadParameter('you have to specify either --group-cif-raw or --node')
  
      counter = 0
  
      node_cif_filter_parameters = get_input_node(orm.Dict, {
          'fix-syntax-errors': True,
          'use-c-parser': True,
          'use-datablocks-without-coordinates': True,
      })
  
      node_cif_select_parameters = get_input_node(orm.Dict, {
          'canonicalize-tag-names': True,
          'dont-treat-dots-as-underscores': True,
          'invert': True,
          'tags': '_publ_author_name,_citation_journal_abbrev',
          'use-c-parser': True,
      })
  
      node_options = get_input_node(orm.Dict, get_default_options())
      node_parse_engine = get_input_node(orm.Str, parse_engine)
      node_site_tolerance = get_input_node(orm.Float, 5E-4)
      node_symprec = get_input_node(orm.Float, 5E-3)
  
      for cif in nodes:
  
          inputs = {
              'cif': cif,
              'cif_filter': cif_filter,
              'cif_select': cif_select,
              'cif_filter_parameters': node_cif_filter_parameters,
              'cif_select_parameters': node_cif_select_parameters,
              'options': node_options,
              'parse_engine': node_parse_engine,
              'site_tolerance': node_site_tolerance,
              'symprec': node_symprec,
          }
  
          if group_cif_clean is not None:
              inputs['group_cif'] = group_cif_clean
  
          if group_structure is not None:
              inputs['group_structure'] = group_structure
  
          if daemon:
              workchain = launch.submit(CifCleanWorkChain, **inputs)
              echo_utc('CifData<{}> submitting: {}<{}>'.format(cif.pk, CifCleanWorkChain.__name__, workchain.pk))
          else:
              echo_utc('CifData<{}> running: {}'.format(cif.pk, CifCleanWorkChain.__name__))
              _, workchain = launch.run_get_node(CifCleanWorkChain, **inputs)
  
          if group_workchain is not None:
              group_workchain.add_nodes([workchain])
  
          counter += 1
  
          if max_entries is not None and counter >= max_entries:
              break
  
      click.echo('-' * 80)
      click.echo('Submitted {} new workchains'.format(counter))
      click.echo('Stopping on {}'.format(datetime.utcnow().isoformat()))
      click.echo('=' * 80)