writeCTab2000()

in packages/ketcher-core/src/domain/serializers/mol/molfile.ts [291:532]


  writeCTab2000(rgroups?: Map<any, any>) {
    // eslint-disable-line max-statements
    /* saver */
    this.writeCTab2000Header();

    this.mapping = {};
    let i = 1;

    const atomsIds: number[] = [];
    const atomsProps: {
      id: number;
      value: string;
    }[] = [];
    this.molecule!.atoms.forEach((atom, id) => {
      let label = atom.label;
      if (atom.atomList != null) {
        label = 'L';
        atomsIds.push(id);
      } else if (atom.pseudo) {
        if (atom.pseudo.length > 3) {
          label = 'A';
          atomsProps.push({ id, value: `'${atom.pseudo}'` });
        }
      } else if (atom.alias) {
        atomsProps.push({ id, value: atom.alias });
      } else if (
        !Elements.get(atom.label) &&
        ['A', 'Q', 'X', '*', 'R#'].indexOf(atom.label) === -1
      ) {
        // search in generics?
        label = 'C';
        atomsProps.push({ id, value: atom.label });
      }

      this.writeAtom(atom, label);

      this.mapping[id] = i++;
    }, this);

    this.bondMapping = {};
    i = 1;
    this.molecule!.bonds.forEach((bond, id) => {
      this.bondMapping[id] = i++;
      this.writeBond(bond);
    }, this);

    while (atomsProps.length > 0) {
      this.writeAtomProps(atomsProps[0]);
      atomsProps.splice(0, 1);
    }

    const chargeList: NumberTuple[] = [];
    const isotopeList: NumberTuple[] = [];
    const radicalList: NumberTuple[] = [];
    const rglabelList: NumberTuple[] = [];
    const rglogicList: string[] = [];
    const aplabelList: NumberTuple[] = [];
    const rbcountList: NumberTuple[] = [];
    const unsaturatedList: NumberTuple[] = [];
    const substcountList: NumberTuple[] = [];

    this.molecule!.atoms.forEach((atom, id) => {
      if (atom.charge !== 0 && atom.charge !== null) {
        chargeList.push([id, atom.charge]);
      }
      if (atom.isotope !== 0 && atom.isotope !== null) {
        isotopeList.push([id, atom.isotope]);
      }
      if (atom.radical !== 0) {
        radicalList.push([id, atom.radical]);
      }
      if (atom.rglabel != null && atom.label === 'R#') {
        // TODO need to force rglabel=null when label is not 'R#'
        for (let rgi = 0; rgi < 32; rgi++) {
          if ((atom.rglabel as any) & (1 << rgi)) {
            rglabelList.push([id, rgi + 1]);
          }
        }
      }
      if (atom.attachmentPoints != null) {
        aplabelList.push([id, atom.attachmentPoints]);
      }
      if (atom.ringBondCount !== 0) {
        rbcountList.push([id, atom.ringBondCount]);
      }
      if (atom.substitutionCount !== 0) {
        substcountList.push([id, atom.substitutionCount]);
      }
      if (atom.unsaturatedAtom !== 0) {
        unsaturatedList.push([id, atom.unsaturatedAtom]);
      }
    });

    if (rgroups) {
      rgroups.forEach((rg, rgid) => {
        if (rg.resth || rg.ifthen > 0 || rg.range.length > 0) {
          const line =
            '  1 ' +
            utils.paddedNum(rgid, 3) +
            ' ' +
            utils.paddedNum(rg.ifthen, 3) +
            ' ' +
            utils.paddedNum(rg.resth ? 1 : 0, 3) +
            '   ' +
            rg.range;
          rglogicList.push(line);
        }
      });
    }

    this.writeAtomPropList('M  CHG', chargeList);
    this.writeAtomPropList('M  ISO', isotopeList);
    this.writeAtomPropList('M  RAD', radicalList);
    this.writeAtomPropList('M  RGP', rglabelList);
    for (let j = 0; j < rglogicList.length; ++j) {
      this.write('M  LOG' + rglogicList[j] + '\n');
    }

    this.writeAtomPropList('M  APO', aplabelList);
    this.writeAtomPropList('M  RBC', rbcountList);
    this.writeAtomPropList('M  SUB', substcountList);
    this.writeAtomPropList('M  UNS', unsaturatedList);

    if (atomsIds.length > 0) {
      for (let j = 0; j < atomsIds.length; ++j) {
        const atomId = atomsIds[j];
        const atomList = this.molecule!.atoms.get(atomId)!.atomList!;
        this.write('M  ALS');
        this.writePaddedNumber(atomId + 1, 4);
        this.writePaddedNumber(atomList.ids.length, 3);
        this.writeWhiteSpace();
        this.write(atomList.notList ? 'T' : 'F');

        const labelList = atomList.labelList();
        for (let k = 0; k < labelList.length; ++k) {
          this.writeWhiteSpace();
          this.writePadded(labelList[k], 3);
        }
        this.writeWhiteSpace();
        this.writeCR();
      }
    }

    const sgmap = {};
    let cnt = 1;
    const sgmapback = {};
    const sgorder = this.molecule!.sGroupForest.getSGroupsBFS();
    sgorder.forEach((id) => {
      sgmapback[cnt] = id;
      sgmap[id] = cnt++;
    });
    for (let sGroupIdInCTab = 1; sGroupIdInCTab < cnt; ++sGroupIdInCTab) {
      // each group on its own
      const id = sgmapback[sGroupIdInCTab];
      const sgroup = this.molecule!.sgroups.get(id)!;
      if (SGroup.isQuerySGroup(sgroup)) {
        console.warn('Query group does not support in mol format');
        continue;
      }
      this.write('M  STY');
      this.writePaddedNumber(1, 3);
      this.writeWhiteSpace(1);
      this.writePaddedNumber(sGroupIdInCTab, 3);
      this.writeWhiteSpace(1);
      this.writePadded(sgroup.type, 3);
      this.writeCR();

      // TODO: write subtype, M SST

      this.write('M  SLB');
      this.writePaddedNumber(1, 3);
      this.writeWhiteSpace(1);
      this.writePaddedNumber(sGroupIdInCTab, 3);
      this.writeWhiteSpace(1);
      this.writePaddedNumber(sGroupIdInCTab, 3);
      this.writeCR();

      const parentId = this.molecule!.sGroupForest.parent.get(id)!;
      if (parentId >= 0) {
        this.write('M  SPL');
        this.writePaddedNumber(1, 3);
        this.writeWhiteSpace(1);
        this.writePaddedNumber(sGroupIdInCTab, 3);
        this.writeWhiteSpace(1);
        this.writePaddedNumber(sgmap[parentId], 3);
        this.writeCR();
      }

      // connectivity
      if (sgroup.type === 'SRU' && sgroup.data.connectivity) {
        const connectivity = ` ${sGroupIdInCTab.toString().padStart(3)} ${(
          sgroup.data.connectivity || ''
        ).padEnd(3)}`;

        this.write('M  SCN');
        this.writePaddedNumber(1, 3);
        this.write(connectivity.toUpperCase());
        this.writeCR();
      }

      if (sgroup.type === 'SRU') {
        this.write('M  SMT ');
        this.writePaddedNumber(sGroupIdInCTab, 3);
        this.writeWhiteSpace();
        this.write(sgroup.data.subscript || 'n');
        this.writeCR();
      }
      sgroup.getAttachmentPoints().forEach((attachmentPoint) => {
        this.writeSGroupAttachmentPointLine(sGroupIdInCTab, attachmentPoint);
      });

      this.writeCR(
        common.saveToMolfile[sgroup.type](
          sgroup,
          this.molecule,
          sgmap,
          this.mapping,
          this.bondMapping,
        ),
      );
    }

    // TODO: write M  APO
    // TODO: write M  AAL
    // TODO: write M  RGP
    // TODO: write M  LOG

    const expandedGroups: number[] = [];
    this.molecule!.sgroups.forEach((sg) => {
      if (sg.isExpanded() && !SGroup.isQuerySGroup(sg))
        expandedGroups.push(sg.id + 1);
    });

    if (expandedGroups.length) {
      const expandedGroupsLine = `M  SDS EXP  ${
        expandedGroups.length
      }   ${expandedGroups.join('   ')}`;
      this.writeCR(expandedGroupsLine);
    }

    this.writeCR('M  END');
  }