react-cheminfo 0.22.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -28
- package/lib/chrome/ui/HeaderToggle.d.ts +52 -0
- package/lib/chrome/ui/HeaderToggle.d.ts.map +1 -0
- package/lib/chrome/ui/HeaderToggle.js +31 -0
- package/lib/chrome/ui/HeaderToggle.js.map +1 -0
- package/lib/chrome/ui/index.d.ts +2 -0
- package/lib/chrome/ui/index.d.ts.map +1 -1
- package/lib/chrome/ui/index.js +1 -0
- package/lib/chrome/ui/index.js.map +1 -1
- package/lib/citation/core/gfn2Paper.d.ts +10 -0
- package/lib/citation/core/gfn2Paper.d.ts.map +1 -0
- package/lib/citation/core/gfn2Paper.js +28 -0
- package/lib/citation/core/gfn2Paper.js.map +1 -0
- package/lib/citation/core/index.d.ts +1 -0
- package/lib/citation/core/index.d.ts.map +1 -1
- package/lib/citation/core/index.js +1 -0
- package/lib/citation/core/index.js.map +1 -1
- package/lib/clipboard/ui/ClickToCopy.d.ts +8 -7
- package/lib/clipboard/ui/ClickToCopy.d.ts.map +1 -1
- package/lib/clipboard/ui/ClickToCopy.js +3 -3
- package/lib/clipboard/ui/ClickToCopy.js.map +1 -1
- package/lib/conformers.d.ts +27 -0
- package/lib/conformers.d.ts.map +1 -0
- package/lib/conformers.js +19 -0
- package/lib/conformers.js.map +1 -0
- package/lib/core.d.ts +1 -0
- package/lib/core.d.ts.map +1 -1
- package/lib/core.js +1 -0
- package/lib/core.js.map +1 -1
- package/lib/credits/core/credits.d.ts +12 -0
- package/lib/credits/core/credits.d.ts.map +1 -1
- package/lib/credits/core/credits.js +14 -0
- package/lib/credits/core/credits.js.map +1 -1
- package/lib/ecosystem/core/index.d.ts +1 -1
- package/lib/ecosystem/core/index.d.ts.map +1 -1
- package/lib/ecosystem/core/index.js.map +1 -1
- package/lib/ecosystem/core/sites.d.ts +11 -1
- package/lib/ecosystem/core/sites.d.ts.map +1 -1
- package/lib/ecosystem/core/sites.js +7 -2
- package/lib/ecosystem/core/sites.js.map +1 -1
- package/lib/ecosystem/ui/EcosystemLinks.d.ts.map +1 -1
- package/lib/ecosystem/ui/EcosystemLinks.js +3 -1
- package/lib/ecosystem/ui/EcosystemLinks.js.map +1 -1
- package/lib/ecosystem/ui/SiteTile.d.ts.map +1 -1
- package/lib/ecosystem/ui/SiteTile.js +3 -1
- package/lib/ecosystem/ui/SiteTile.js.map +1 -1
- package/lib/format/core/index.d.ts +1 -1
- package/lib/format/core/index.d.ts.map +1 -1
- package/lib/format/core/index.js +1 -1
- package/lib/format/core/index.js.map +1 -1
- package/lib/format/core/words.d.ts +9 -0
- package/lib/format/core/words.d.ts.map +1 -1
- package/lib/format/core/words.js +16 -0
- package/lib/format/core/words.js.map +1 -1
- package/lib/language/core/index.d.ts +3 -0
- package/lib/language/core/index.d.ts.map +1 -0
- package/lib/language/core/index.js +3 -0
- package/lib/language/core/index.js.map +1 -0
- package/lib/language/core/languageName.d.ts +8 -0
- package/lib/language/core/languageName.d.ts.map +1 -0
- package/lib/language/core/languageName.js +16 -0
- package/lib/language/core/languageName.js.map +1 -0
- package/lib/language/core/languageParam.d.ts +35 -0
- package/lib/language/core/languageParam.d.ts.map +1 -0
- package/lib/language/core/languageParam.js +67 -0
- package/lib/language/core/languageParam.js.map +1 -0
- package/lib/language/ui/SiteLanguage.d.ts +20 -0
- package/lib/language/ui/SiteLanguage.d.ts.map +1 -0
- package/lib/language/ui/SiteLanguage.js +14 -0
- package/lib/language/ui/SiteLanguage.js.map +1 -0
- package/lib/language/ui/index.d.ts +4 -0
- package/lib/language/ui/index.d.ts.map +1 -0
- package/lib/language/ui/index.js +3 -0
- package/lib/language/ui/index.js.map +1 -0
- package/lib/language/ui/siteLanguageContext.d.ts +12 -0
- package/lib/language/ui/siteLanguageContext.d.ts.map +1 -0
- package/lib/language/ui/siteLanguageContext.js +19 -0
- package/lib/language/ui/siteLanguageContext.js.map +1 -0
- package/lib/orbital/core/atomicOrbitals.d.ts +9 -1
- package/lib/orbital/core/atomicOrbitals.d.ts.map +1 -1
- package/lib/orbital/core/atomicOrbitals.js +7 -0
- package/lib/orbital/core/atomicOrbitals.js.map +1 -1
- package/lib/orbital/core/hydrogenic.d.ts +2 -1
- package/lib/orbital/core/hydrogenic.d.ts.map +1 -1
- package/lib/orbital/core/hydrogenic.js +2 -1
- package/lib/orbital/core/hydrogenic.js.map +1 -1
- package/lib/orbital/core/index.d.ts +1 -0
- package/lib/orbital/core/index.d.ts.map +1 -1
- package/lib/orbital/core/index.js +1 -0
- package/lib/orbital/core/index.js.map +1 -1
- package/lib/orbital/core/slaterEnergy.d.ts +35 -0
- package/lib/orbital/core/slaterEnergy.d.ts.map +1 -0
- package/lib/orbital/core/slaterEnergy.js +66 -0
- package/lib/orbital/core/slaterEnergy.js.map +1 -0
- package/lib/overlay/core/index.d.ts +2 -2
- package/lib/overlay/core/index.d.ts.map +1 -1
- package/lib/overlay/core/index.js +1 -1
- package/lib/overlay/core/index.js.map +1 -1
- package/lib/overlay/core/overlayMarks.d.ts +20 -5
- package/lib/overlay/core/overlayMarks.d.ts.map +1 -1
- package/lib/overlay/core/overlayMarks.js +31 -5
- package/lib/overlay/core/overlayMarks.js.map +1 -1
- package/lib/overlay/ui/OverlayLegendMark.js +5 -0
- package/lib/overlay/ui/OverlayLegendMark.js.map +1 -1
- package/lib/projection/core/index.d.ts +4 -4
- package/lib/projection/core/index.d.ts.map +1 -1
- package/lib/projection/core/index.js +2 -2
- package/lib/projection/core/index.js.map +1 -1
- package/lib/projection/core/projectionCopy.d.ts +2 -0
- package/lib/projection/core/projectionCopy.d.ts.map +1 -1
- package/lib/projection/core/projectionCopy.js +1 -0
- package/lib/projection/core/projectionCopy.js.map +1 -1
- package/lib/projection/core/projectionGroupings.d.ts +44 -0
- package/lib/projection/core/projectionGroupings.d.ts.map +1 -0
- package/lib/projection/core/projectionGroupings.js +132 -0
- package/lib/projection/core/projectionGroupings.js.map +1 -0
- package/lib/projection/core/projectionOptions.d.ts +16 -6
- package/lib/projection/core/projectionOptions.d.ts.map +1 -1
- package/lib/projection/core/projectionOptions.js +7 -1
- package/lib/projection/core/projectionOptions.js.map +1 -1
- package/lib/projection/core/projectionPanelWords.d.ts +6 -0
- package/lib/projection/core/projectionPanelWords.d.ts.map +1 -1
- package/lib/projection/core/projectionPanelWords.js +4 -0
- package/lib/projection/core/projectionPanelWords.js.map +1 -1
- package/lib/projection/core/projectionSamples.d.ts +63 -32
- package/lib/projection/core/projectionSamples.d.ts.map +1 -1
- package/lib/projection/core/projectionSamples.js +1 -80
- package/lib/projection/core/projectionSamples.js.map +1 -1
- package/lib/projection/core/projectionStrings.d.ts +2 -0
- package/lib/projection/core/projectionStrings.d.ts.map +1 -1
- package/lib/projection/core/projectionStrings.js +10 -1
- package/lib/projection/core/projectionStrings.js.map +1 -1
- package/lib/projection/core/resolveProjectionOptions.d.ts +8 -3
- package/lib/projection/core/resolveProjectionOptions.d.ts.map +1 -1
- package/lib/projection/core/resolveProjectionOptions.js +58 -5
- package/lib/projection/core/resolveProjectionOptions.js.map +1 -1
- package/lib/projection/ui/ProjectionBar.d.ts +1 -1
- package/lib/projection/ui/ProjectionBar.d.ts.map +1 -1
- package/lib/projection/ui/ProjectionBar.js +3 -1
- package/lib/projection/ui/ProjectionBar.js.map +1 -1
- package/lib/projection/ui/ProjectionGroupingPickers.d.ts +38 -0
- package/lib/projection/ui/ProjectionGroupingPickers.d.ts.map +1 -0
- package/lib/projection/ui/ProjectionGroupingPickers.js +33 -0
- package/lib/projection/ui/ProjectionGroupingPickers.js.map +1 -0
- package/lib/projection/ui/ProjectionMapControls.d.ts +6 -7
- package/lib/projection/ui/ProjectionMapControls.d.ts.map +1 -1
- package/lib/projection/ui/ProjectionMapControls.js +11 -9
- package/lib/projection/ui/ProjectionMapControls.js.map +1 -1
- package/lib/projection/ui/ProjectionMapLegend.d.ts.map +1 -1
- package/lib/projection/ui/ProjectionMapLegend.js +1 -1
- package/lib/projection/ui/ProjectionMapLegend.js.map +1 -1
- package/lib/projection/ui/ProjectionMapMore.d.ts +2 -2
- package/lib/projection/ui/ProjectionMapMore.d.ts.map +1 -1
- package/lib/projection/ui/ProjectionMapMore.js +7 -5
- package/lib/projection/ui/ProjectionMapMore.js.map +1 -1
- package/lib/projection/ui/ProjectionMapTab.d.ts +15 -6
- package/lib/projection/ui/ProjectionMapTab.d.ts.map +1 -1
- package/lib/projection/ui/ProjectionMapTab.js +11 -7
- package/lib/projection/ui/ProjectionMapTab.js.map +1 -1
- package/lib/projection/ui/ProjectionPairsMore.d.ts +3 -7
- package/lib/projection/ui/ProjectionPairsMore.d.ts.map +1 -1
- package/lib/projection/ui/ProjectionPairsMore.js +4 -5
- package/lib/projection/ui/ProjectionPairsMore.js.map +1 -1
- package/lib/projection/ui/ProjectionPairsTab.d.ts.map +1 -1
- package/lib/projection/ui/ProjectionPairsTab.js +2 -2
- package/lib/projection/ui/ProjectionPairsTab.js.map +1 -1
- package/lib/projection/ui/ProjectionPanel.d.ts +1 -1
- package/lib/projection/ui/ProjectionPanel.d.ts.map +1 -1
- package/lib/projection/ui/ProjectionPanel.js +1 -1
- package/lib/projection/ui/ProjectionPanel.js.map +1 -1
- package/lib/projection/ui/ProjectionReadout.d.ts +7 -1
- package/lib/projection/ui/ProjectionReadout.d.ts.map +1 -1
- package/lib/projection/ui/ProjectionReadout.js +19 -7
- package/lib/projection/ui/ProjectionReadout.js.map +1 -1
- package/lib/projection/ui/ProjectionSpaceControls.d.ts +3 -5
- package/lib/projection/ui/ProjectionSpaceControls.d.ts.map +1 -1
- package/lib/projection/ui/ProjectionSpaceControls.js +9 -7
- package/lib/projection/ui/ProjectionSpaceControls.js.map +1 -1
- package/lib/projection/ui/ProjectionSpaceMore.d.ts +2 -2
- package/lib/projection/ui/ProjectionSpaceMore.d.ts.map +1 -1
- package/lib/projection/ui/ProjectionSpaceMore.js +5 -4
- package/lib/projection/ui/ProjectionSpaceMore.js.map +1 -1
- package/lib/projection/ui/ProjectionSpaceTab.d.ts +11 -3
- package/lib/projection/ui/ProjectionSpaceTab.d.ts.map +1 -1
- package/lib/projection/ui/ProjectionSpaceTab.js +7 -4
- package/lib/projection/ui/ProjectionSpaceTab.js.map +1 -1
- package/lib/projection/ui/ProjectionViewer.d.ts.map +1 -1
- package/lib/projection/ui/ProjectionViewer.js +1 -0
- package/lib/projection/ui/ProjectionViewer.js.map +1 -1
- package/lib/projection/ui/projectionBarReadings.d.ts +4 -1
- package/lib/projection/ui/projectionBarReadings.d.ts.map +1 -1
- package/lib/projection/ui/projectionBarReadings.js +14 -4
- package/lib/projection/ui/projectionBarReadings.js.map +1 -1
- package/lib/projection/ui/projectionBarSlots.d.ts +4 -2
- package/lib/projection/ui/projectionBarSlots.d.ts.map +1 -1
- package/lib/projection/ui/projectionBarSlots.js +3 -7
- package/lib/projection/ui/projectionBarSlots.js.map +1 -1
- package/lib/projection/ui/projectionMapChoices.d.ts +31 -6
- package/lib/projection/ui/projectionMapChoices.d.ts.map +1 -1
- package/lib/projection/ui/projectionMapChoices.js +58 -9
- package/lib/projection/ui/projectionMapChoices.js.map +1 -1
- package/lib/projection/ui/projectionMapChrome.d.ts +3 -9
- package/lib/projection/ui/projectionMapChrome.d.ts.map +1 -1
- package/lib/projection/ui/projectionMapChrome.js +41 -27
- package/lib/projection/ui/projectionMapChrome.js.map +1 -1
- package/lib/projection/ui/projectionMapCorner.d.ts +25 -0
- package/lib/projection/ui/projectionMapCorner.d.ts.map +1 -0
- package/lib/projection/ui/projectionMapCorner.js +46 -0
- package/lib/projection/ui/projectionMapCorner.js.map +1 -0
- package/lib/projection/ui/projectionMapModel.d.ts +9 -18
- package/lib/projection/ui/projectionMapModel.d.ts.map +1 -1
- package/lib/projection/ui/projectionMapModel.js +14 -39
- package/lib/projection/ui/projectionMapModel.js.map +1 -1
- package/lib/projection/ui/projectionMapView.d.ts +3 -1
- package/lib/projection/ui/projectionMapView.d.ts.map +1 -1
- package/lib/projection/ui/projectionMapView.js +9 -4
- package/lib/projection/ui/projectionMapView.js.map +1 -1
- package/lib/projection/ui/projectionSelectionSentence.d.ts +10 -0
- package/lib/projection/ui/projectionSelectionSentence.d.ts.map +1 -0
- package/lib/projection/ui/projectionSelectionSentence.js +18 -0
- package/lib/projection/ui/projectionSelectionSentence.js.map +1 -0
- package/lib/projection/ui/projectionStateApi.d.ts +47 -0
- package/lib/projection/ui/projectionStateApi.d.ts.map +1 -0
- package/lib/projection/ui/projectionStateApi.js +9 -0
- package/lib/projection/ui/projectionStateApi.js.map +1 -0
- package/lib/projection/ui/projectionTabModels.js +1 -1
- package/lib/projection/ui/projectionTabModels.js.map +1 -1
- package/lib/projection/ui/useProjectionState.d.ts +1 -29
- package/lib/projection/ui/useProjectionState.d.ts.map +1 -1
- package/lib/projection/ui/useProjectionState.js +13 -5
- package/lib/projection/ui/useProjectionState.js.map +1 -1
- package/lib/scatter/core/index.d.ts +1 -0
- package/lib/scatter/core/index.d.ts.map +1 -1
- package/lib/scatter/core/index.js +1 -0
- package/lib/scatter/core/index.js.map +1 -1
- package/lib/scatter/core/pointShape.d.ts +18 -0
- package/lib/scatter/core/pointShape.d.ts.map +1 -0
- package/lib/scatter/core/pointShape.js +70 -0
- package/lib/scatter/core/pointShape.js.map +1 -0
- package/lib/scatter/ui/ScatterPlot.d.ts.map +1 -1
- package/lib/scatter/ui/ScatterPlot.js +3 -2
- package/lib/scatter/ui/ScatterPlot.js.map +1 -1
- package/lib/scatter/ui/ScatterPointLayer.d.ts +14 -1
- package/lib/scatter/ui/ScatterPointLayer.d.ts.map +1 -1
- package/lib/scatter/ui/ScatterPointLayer.js +15 -3
- package/lib/scatter/ui/ScatterPointLayer.js.map +1 -1
- package/lib/scatter/ui/scatterFigureProps.d.ts +13 -0
- package/lib/scatter/ui/scatterFigureProps.d.ts.map +1 -1
- package/lib/scatter/ui/scatterMarkGlyph.d.ts +2 -1
- package/lib/scatter/ui/scatterMarkGlyph.d.ts.map +1 -1
- package/lib/scatter/ui/scatterMarkGlyph.js +7 -1
- package/lib/scatter/ui/scatterMarkGlyph.js.map +1 -1
- package/lib/scatter3d/ui/ScatterCloud.d.ts.map +1 -1
- package/lib/scatter3d/ui/ScatterCloud.js +2 -1
- package/lib/scatter3d/ui/ScatterCloud.js.map +1 -1
- package/lib/shared/ui/MenuButton.d.ts +3 -2
- package/lib/shared/ui/MenuButton.d.ts.map +1 -1
- package/lib/shared/ui/MenuButton.js +1 -1
- package/lib/shared/ui/MenuButton.js.map +1 -1
- package/lib/structure/core/conformerMinimise.d.ts +36 -0
- package/lib/structure/core/conformerMinimise.d.ts.map +1 -0
- package/lib/structure/core/conformerMinimise.js +81 -0
- package/lib/structure/core/conformerMinimise.js.map +1 -0
- package/lib/structure/core/conformerMinimum.d.ts +62 -0
- package/lib/structure/core/conformerMinimum.d.ts.map +1 -0
- package/lib/structure/core/conformerMinimum.js +90 -0
- package/lib/structure/core/conformerMinimum.js.map +1 -0
- package/lib/structure/core/conformerOptions.d.ts +62 -0
- package/lib/structure/core/conformerOptions.d.ts.map +1 -0
- package/lib/structure/core/conformerOptions.js +83 -0
- package/lib/structure/core/conformerOptions.js.map +1 -0
- package/lib/structure/core/conformerRefine.d.ts +104 -0
- package/lib/structure/core/conformerRefine.d.ts.map +1 -0
- package/lib/structure/core/conformerRefine.js +130 -0
- package/lib/structure/core/conformerRefine.js.map +1 -0
- package/lib/structure/core/conformerRefineRank.d.ts +36 -0
- package/lib/structure/core/conformerRefineRank.d.ts.map +1 -0
- package/lib/structure/core/conformerRefineRank.js +69 -0
- package/lib/structure/core/conformerRefineRank.js.map +1 -0
- package/lib/structure/core/conformerSession.d.ts +50 -0
- package/lib/structure/core/conformerSession.d.ts.map +1 -0
- package/lib/structure/core/conformerSession.js +88 -0
- package/lib/structure/core/conformerSession.js.map +1 -0
- package/lib/structure/core/conformerShape.d.ts +36 -0
- package/lib/structure/core/conformerShape.d.ts.map +1 -0
- package/lib/structure/core/conformerShape.js +150 -0
- package/lib/structure/core/conformerShape.js.map +1 -0
- package/lib/structure/core/conformers.d.ts +107 -0
- package/lib/structure/core/conformers.d.ts.map +1 -0
- package/lib/structure/core/conformers.js +149 -0
- package/lib/structure/core/conformers.js.map +1 -0
- package/lib/structure/core/geometryRelaxer.d.ts +66 -0
- package/lib/structure/core/geometryRelaxer.d.ts.map +1 -0
- package/lib/structure/core/geometryRelaxer.js +2 -0
- package/lib/structure/core/geometryRelaxer.js.map +1 -0
- package/lib/structure/core/index.d.ts +4 -0
- package/lib/structure/core/index.d.ts.map +1 -1
- package/lib/structure/core/index.js +2 -0
- package/lib/structure/core/index.js.map +1 -1
- package/lib/structure/core/moleculeCoordinates.d.ts +31 -0
- package/lib/structure/core/moleculeCoordinates.d.ts.map +1 -0
- package/lib/structure/core/moleculeCoordinates.js +80 -0
- package/lib/structure/core/moleculeCoordinates.js.map +1 -0
- package/lib/structure/core/molfileExport.d.ts +42 -0
- package/lib/structure/core/molfileExport.d.ts.map +1 -0
- package/lib/structure/core/molfileExport.js +47 -0
- package/lib/structure/core/molfileExport.js.map +1 -0
- package/lib/structure/core/oclResources.d.ts +12 -0
- package/lib/structure/core/oclResources.d.ts.map +1 -0
- package/lib/structure/core/oclResources.js +35 -0
- package/lib/structure/core/oclResources.js.map +1 -0
- package/lib/translate/core/catalog.d.ts +61 -0
- package/lib/translate/core/catalog.d.ts.map +1 -0
- package/lib/translate/core/catalog.js +49 -0
- package/lib/translate/core/catalog.js.map +1 -0
- package/lib/translate/core/checkTranslation.d.ts +32 -0
- package/lib/translate/core/checkTranslation.d.ts.map +1 -0
- package/lib/translate/core/checkTranslation.js +98 -0
- package/lib/translate/core/checkTranslation.js.map +1 -0
- package/lib/translate/core/contribution.d.ts +88 -0
- package/lib/translate/core/contribution.d.ts.map +1 -0
- package/lib/translate/core/contribution.js +14 -0
- package/lib/translate/core/contribution.js.map +1 -0
- package/lib/translate/core/index.d.ts +19 -0
- package/lib/translate/core/index.d.ts.map +1 -0
- package/lib/translate/core/index.js +15 -0
- package/lib/translate/core/index.js.map +1 -0
- package/lib/translate/core/marker.d.ts +45 -0
- package/lib/translate/core/marker.d.ts.map +1 -0
- package/lib/translate/core/marker.js +79 -0
- package/lib/translate/core/marker.js.map +1 -0
- package/lib/translate/core/mergeMessages.d.ts +35 -0
- package/lib/translate/core/mergeMessages.d.ts.map +1 -0
- package/lib/translate/core/mergeMessages.js +69 -0
- package/lib/translate/core/mergeMessages.js.map +1 -0
- package/lib/translate/core/session.d.ts +102 -0
- package/lib/translate/core/session.d.ts.map +1 -0
- package/lib/translate/core/session.js +162 -0
- package/lib/translate/core/session.js.map +1 -0
- package/lib/translate/core/start.d.ts +70 -0
- package/lib/translate/core/start.d.ts.map +1 -0
- package/lib/translate/core/start.js +73 -0
- package/lib/translate/core/start.js.map +1 -0
- package/lib/translate/core/suggestions.d.ts +77 -0
- package/lib/translate/core/suggestions.d.ts.map +1 -0
- package/lib/translate/core/suggestions.js +143 -0
- package/lib/translate/core/suggestions.js.map +1 -0
- package/lib/translate/core/tables.d.ts +100 -0
- package/lib/translate/core/tables.d.ts.map +1 -0
- package/lib/translate/core/tables.js +51 -0
- package/lib/translate/core/tables.js.map +1 -0
- package/lib/translate.d.ts +2 -0
- package/lib/translate.d.ts.map +1 -0
- package/lib/translate.js +6 -0
- package/lib/translate.js.map +1 -0
- package/lib/ui.d.ts +1 -0
- package/lib/ui.d.ts.map +1 -1
- package/lib/ui.js +1 -0
- package/lib/ui.js.map +1 -1
- package/lib/xtb/core/xtbRelaxer.d.ts +61 -0
- package/lib/xtb/core/xtbRelaxer.d.ts.map +1 -0
- package/lib/xtb/core/xtbRelaxer.js +108 -0
- package/lib/xtb/core/xtbRelaxer.js.map +1 -0
- package/lib/xtb.d.ts +11 -0
- package/lib/xtb.d.ts.map +1 -0
- package/lib/xtb.js +10 -0
- package/lib/xtb.js.map +1 -0
- package/package.json +18 -11
- package/src/chrome/ui/HeaderToggle.tsx +100 -0
- package/src/chrome/ui/index.ts +2 -0
- package/src/citation/core/gfn2Paper.ts +32 -0
- package/src/citation/core/index.ts +1 -0
- package/src/clipboard/ui/ClickToCopy.tsx +8 -7
- package/src/conformers.ts +87 -0
- package/src/core.ts +1 -0
- package/src/credits/core/credits.ts +16 -0
- package/src/ecosystem/core/index.ts +1 -0
- package/src/ecosystem/core/sites.ts +20 -2
- package/src/ecosystem/ui/EcosystemLinks.tsx +3 -1
- package/src/ecosystem/ui/SiteTile.tsx +3 -1
- package/src/format/core/index.ts +1 -1
- package/src/format/core/words.ts +19 -0
- package/src/language/core/index.ts +7 -0
- package/src/language/core/languageName.ts +16 -0
- package/src/language/core/languageParam.ts +70 -0
- package/src/language/ui/SiteLanguage.tsx +26 -0
- package/src/language/ui/index.ts +3 -0
- package/src/language/ui/siteLanguageContext.ts +20 -0
- package/src/orbital/core/atomicOrbitals.ts +17 -1
- package/src/orbital/core/hydrogenic.ts +2 -1
- package/src/orbital/core/index.ts +1 -0
- package/src/orbital/core/slaterEnergy.ts +83 -0
- package/src/overlay/core/index.ts +6 -2
- package/src/overlay/core/overlayMarks.ts +51 -6
- package/src/overlay/ui/OverlayLegendMark.tsx +5 -0
- package/src/projection/core/index.ts +11 -3
- package/src/projection/core/projectionCopy.ts +3 -0
- package/src/projection/core/projectionGroupings.ts +174 -0
- package/src/projection/core/projectionOptions.ts +18 -7
- package/src/projection/core/projectionPanelWords.ts +10 -0
- package/src/projection/core/projectionSamples.ts +62 -120
- package/src/projection/core/projectionStrings.ts +12 -1
- package/src/projection/core/resolveProjectionOptions.ts +66 -4
- package/src/projection/ui/ProjectionBar.tsx +4 -2
- package/src/projection/ui/ProjectionGroupingPickers.tsx +91 -0
- package/src/projection/ui/ProjectionMapControls.tsx +29 -32
- package/src/projection/ui/ProjectionMapLegend.tsx +1 -1
- package/src/projection/ui/ProjectionMapMore.tsx +14 -4
- package/src/projection/ui/ProjectionMapTab.tsx +27 -9
- package/src/projection/ui/ProjectionPairsMore.tsx +12 -21
- package/src/projection/ui/ProjectionPairsTab.tsx +5 -2
- package/src/projection/ui/ProjectionPanel.tsx +7 -3
- package/src/projection/ui/ProjectionReadout.tsx +28 -8
- package/src/projection/ui/ProjectionSpaceControls.tsx +20 -27
- package/src/projection/ui/ProjectionSpaceMore.tsx +12 -3
- package/src/projection/ui/ProjectionSpaceTab.tsx +23 -6
- package/src/projection/ui/ProjectionViewer.tsx +1 -0
- package/src/projection/ui/projectionBarReadings.ts +24 -8
- package/src/projection/ui/projectionBarSlots.tsx +10 -9
- package/src/projection/ui/projectionMapChoices.ts +71 -14
- package/src/projection/ui/projectionMapChrome.ts +55 -30
- package/src/projection/ui/projectionMapCorner.ts +67 -0
- package/src/projection/ui/projectionMapModel.ts +20 -59
- package/src/projection/ui/projectionMapView.ts +15 -8
- package/src/projection/ui/projectionSelectionSentence.ts +22 -0
- package/src/projection/ui/projectionStateApi.ts +57 -0
- package/src/projection/ui/projectionTabModels.ts +1 -1
- package/src/projection/ui/useProjectionState.ts +33 -37
- package/src/scatter/core/index.ts +1 -0
- package/src/scatter/core/pointShape.ts +80 -0
- package/src/scatter/ui/ScatterPlot.tsx +4 -1
- package/src/scatter/ui/ScatterPointLayer.tsx +39 -11
- package/src/scatter/ui/scatterFigureProps.ts +13 -0
- package/src/scatter/ui/scatterMarkGlyph.tsx +9 -1
- package/src/scatter3d/ui/ScatterCloud.tsx +3 -0
- package/src/shared/ui/MenuButton.tsx +4 -3
- package/src/structure/core/conformerMinimise.ts +99 -0
- package/src/structure/core/conformerMinimum.ts +125 -0
- package/src/structure/core/conformerOptions.ts +125 -0
- package/src/structure/core/conformerRefine.ts +234 -0
- package/src/structure/core/conformerRefineRank.ts +89 -0
- package/src/structure/core/conformerSession.ts +123 -0
- package/src/structure/core/conformerShape.ts +181 -0
- package/src/structure/core/conformers.ts +282 -0
- package/src/structure/core/geometryRelaxer.ts +71 -0
- package/src/structure/core/index.ts +13 -0
- package/src/structure/core/moleculeCoordinates.ts +93 -0
- package/src/structure/core/molfileExport.ts +62 -0
- package/src/structure/core/oclResources.ts +41 -0
- package/src/translate/core/catalog.ts +83 -0
- package/src/translate/core/checkTranslation.ts +128 -0
- package/src/translate/core/contribution.ts +99 -0
- package/src/translate/core/index.ts +72 -0
- package/src/translate/core/marker.ts +85 -0
- package/src/translate/core/mergeMessages.ts +74 -0
- package/src/translate/core/session.ts +250 -0
- package/src/translate/core/start.ts +121 -0
- package/src/translate/core/suggestions.ts +211 -0
- package/src/translate/core/tables.ts +120 -0
- package/src/translate.ts +5 -0
- package/src/ui.ts +1 -0
- package/src/xtb/core/xtbRelaxer.ts +160 -0
- package/src/xtb.ts +16 -0
- package/styles/chrome.css +61 -30
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { Molecule } from 'openchemlib';
|
|
2
|
+
|
|
3
|
+
import { ordinal } from '../../format/core/words.ts';
|
|
4
|
+
|
|
5
|
+
import type { RefinedMinimum } from './conformerRefineRank.ts';
|
|
6
|
+
import {
|
|
7
|
+
isRefinedDuplicate,
|
|
8
|
+
rankByRefinedEnergy,
|
|
9
|
+
} from './conformerRefineRank.ts';
|
|
10
|
+
import { conformerShape } from './conformerShape.ts';
|
|
11
|
+
import type { Conformer, ConformerSet } from './conformers.ts';
|
|
12
|
+
import type {
|
|
13
|
+
GeometryRelaxer,
|
|
14
|
+
RelaxableGeometry,
|
|
15
|
+
RelaxerOptions,
|
|
16
|
+
} from './geometryRelaxer.ts';
|
|
17
|
+
import {
|
|
18
|
+
centredRmsd,
|
|
19
|
+
readRelaxableGeometry,
|
|
20
|
+
writeRelaxedCoordinates,
|
|
21
|
+
} from './moleculeCoordinates.ts';
|
|
22
|
+
import { toMolfileExport } from './molfileExport.ts';
|
|
23
|
+
|
|
24
|
+
/** What refining one conformer produced, on top of its force-field numbers. */
|
|
25
|
+
export interface ConformerRefinement {
|
|
26
|
+
/**
|
|
27
|
+
* The rank this conformer held before the refinement, which is the `id` it
|
|
28
|
+
* carried in the force-field set. Refinement hands the ids out again, so this
|
|
29
|
+
* is what a reader compares the new rank against and what a caller uses to
|
|
30
|
+
* find again the conformer that was on screen.
|
|
31
|
+
*/
|
|
32
|
+
forceFieldId: number;
|
|
33
|
+
/** Total energy at the relaxed geometry, kcal/mol. */
|
|
34
|
+
energy: number;
|
|
35
|
+
/** Energy above the most stable refined conformer of the set, kcal/mol. */
|
|
36
|
+
relativeEnergy: number;
|
|
37
|
+
/**
|
|
38
|
+
* The dispersion term of {@link ConformerRefinement.energy}, kcal/mol, or
|
|
39
|
+
* `null` from a method that has none.
|
|
40
|
+
*/
|
|
41
|
+
dispersionEnergy: number | null;
|
|
42
|
+
/**
|
|
43
|
+
* The force-field energy this conformer had before, kcal/mol, `null` when it
|
|
44
|
+
* had none. Kept so the two rankings can be read against each other, which is
|
|
45
|
+
* the whole reason to refine.
|
|
46
|
+
*/
|
|
47
|
+
forceFieldEnergy: number | null;
|
|
48
|
+
/** How far the atoms moved from the force-field geometry, RMSD in ångström. */
|
|
49
|
+
rmsd: number;
|
|
50
|
+
/** Optimizer cycles spent. */
|
|
51
|
+
cycles: number;
|
|
52
|
+
/** Whether the optimizer met its convergence criteria. */
|
|
53
|
+
converged: boolean;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** What a whole refinement pass produced, recorded on the set. */
|
|
57
|
+
export interface ConformerSetRefinement {
|
|
58
|
+
/** The method, as it is shown to a reader, e.g. `GFN2-xTB`. */
|
|
59
|
+
method: string;
|
|
60
|
+
/** Wall-clock duration of the pass, in milliseconds. */
|
|
61
|
+
elapsedMilliseconds: number;
|
|
62
|
+
/** How many conformers were dropped as duplicates of a kept minimum. */
|
|
63
|
+
merged: number;
|
|
64
|
+
/**
|
|
65
|
+
* How many conformers the refined ranking put at a different position,
|
|
66
|
+
* degenerate conformers swapping places included — so it is a fact about the
|
|
67
|
+
* two orders, not a measure of how much the methods disagree. The two relative
|
|
68
|
+
* energies are what a reader should be shown.
|
|
69
|
+
*/
|
|
70
|
+
reordered: number;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** How a refinement pass is tuned, watched and cancelled. */
|
|
74
|
+
export interface RefineConformersOptions extends RelaxerOptions {
|
|
75
|
+
/**
|
|
76
|
+
* Name of the method, for the label the UI shows.
|
|
77
|
+
* @default 'GFN2-xTB'
|
|
78
|
+
*/
|
|
79
|
+
method?: string;
|
|
80
|
+
/**
|
|
81
|
+
* Energy gap in kcal/mol under which two refined conformers are taken to be
|
|
82
|
+
* one minimum.
|
|
83
|
+
* @default REFINED_SAME_ENERGY_TOLERANCE
|
|
84
|
+
*/
|
|
85
|
+
sameEnergyTolerance?: number;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Energy gap in kcal/mol under which two relaxed conformers can be one minimum.
|
|
90
|
+
*
|
|
91
|
+
* Measured with `benchmark/conformerRefine.js scatter`: one butane minimum
|
|
92
|
+
* reached from six geometries perturbed by up to 0.02 Å lands within 4.9e-6
|
|
93
|
+
* kcal/mol, in 8 to 20 optimizer cycles. So 1e-4 is twenty times the scatter of
|
|
94
|
+
* one minimum, and ten times below the closest gap between two real minima seen
|
|
95
|
+
* on a flexible molecule — ibuprofen has distinct conformers 1e-3 kcal/mol
|
|
96
|
+
* apart. The energy is only the cheap half of the test in any case: what decides
|
|
97
|
+
* that two conformers are one minimum is the shape.
|
|
98
|
+
*/
|
|
99
|
+
export const REFINED_SAME_ENERGY_TOLERANCE = 1e-4;
|
|
100
|
+
|
|
101
|
+
/** What is shown when a conformer set is ranked by the refined energies. */
|
|
102
|
+
export const REFINED_RANKING = 'refined';
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Relax every conformer of a set with a better method and rank the set by what
|
|
106
|
+
* that method says.
|
|
107
|
+
*
|
|
108
|
+
* This is the opt-in second stage of a conformer search, opt-in because it costs
|
|
109
|
+
* seconds where the force field costs milliseconds. MMFF94 places the atoms well
|
|
110
|
+
* but ranks conformers badly — it has no dispersion and no electronic structure,
|
|
111
|
+
* and those are what decide which conformer is lowest. So both numbers are kept:
|
|
112
|
+
* `conformer.energy` stays the force field's, `conformer.refinement.energy` is
|
|
113
|
+
* the new one, and `set.rankedBy` says which of the two the order follows.
|
|
114
|
+
*
|
|
115
|
+
* Refinement changes the set, not only its order: conformers the force field
|
|
116
|
+
* held apart can relax into one minimum, and the first of them is the one that
|
|
117
|
+
* survives. Ids are handed out again over the ranked result, so a caller holding
|
|
118
|
+
* an id must look its conformer up again.
|
|
119
|
+
*
|
|
120
|
+
* A conformer without a force-field energy is refined like any other; its
|
|
121
|
+
* `forceFieldEnergy` is `null` and it takes its place by the refined energy.
|
|
122
|
+
* @param set - The set to refine. Not modified.
|
|
123
|
+
* @param relax - The engine, e.g. `xtbRelaxer` from `react-cheminfo/xtb`.
|
|
124
|
+
* @param options - Method name, duplicate tolerance, progress and cancellation.
|
|
125
|
+
* @returns A new set, ranked by the refined energies.
|
|
126
|
+
* @throws {Error} When the relaxer fails or is cancelled, or answers with the
|
|
127
|
+
* wrong number of geometries.
|
|
128
|
+
*/
|
|
129
|
+
export async function refineConformers(
|
|
130
|
+
set: ConformerSet,
|
|
131
|
+
relax: GeometryRelaxer,
|
|
132
|
+
options: RefineConformersOptions = {},
|
|
133
|
+
): Promise<ConformerSet> {
|
|
134
|
+
const startedAt = performance.now();
|
|
135
|
+
const method = options.method ?? 'GFN2-xTB';
|
|
136
|
+
if (set.conformers.length === 0) {
|
|
137
|
+
return {
|
|
138
|
+
...set,
|
|
139
|
+
rankedBy: REFINED_RANKING,
|
|
140
|
+
refinement: { method, elapsedMilliseconds: 0, merged: 0, reordered: 0 },
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const prepared: Array<{
|
|
145
|
+
conformer: Conformer;
|
|
146
|
+
molecule: Molecule;
|
|
147
|
+
geometry: RelaxableGeometry;
|
|
148
|
+
}> = [];
|
|
149
|
+
for (const conformer of set.conformers) {
|
|
150
|
+
const molecule = Molecule.fromMolfile(conformer.molfile.data);
|
|
151
|
+
prepared.push({
|
|
152
|
+
conformer,
|
|
153
|
+
molecule,
|
|
154
|
+
geometry: readRelaxableGeometry(molecule),
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const relaxed = await relax(
|
|
159
|
+
prepared.map((entry) => entry.geometry),
|
|
160
|
+
{
|
|
161
|
+
onSettled: options.onSettled,
|
|
162
|
+
signal: options.signal,
|
|
163
|
+
},
|
|
164
|
+
);
|
|
165
|
+
if (relaxed.length !== set.conformers.length) {
|
|
166
|
+
throw new Error(
|
|
167
|
+
`The relaxer answered with ${relaxed.length} geometries for ${set.conformers.length} conformers.`,
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const tolerance =
|
|
172
|
+
options.sameEnergyTolerance ?? REFINED_SAME_ENERGY_TOLERANCE;
|
|
173
|
+
const warnings = [...set.warnings];
|
|
174
|
+
const kept: Conformer[] = [];
|
|
175
|
+
const minima: RefinedMinimum[] = [];
|
|
176
|
+
let merged = 0;
|
|
177
|
+
|
|
178
|
+
for (const [index, entry] of prepared.entries()) {
|
|
179
|
+
const result = relaxed[index];
|
|
180
|
+
if (result === undefined) continue;
|
|
181
|
+
const { conformer, molecule, geometry } = entry;
|
|
182
|
+
writeRelaxedCoordinates(molecule, result.coordinates);
|
|
183
|
+
const candidate: RefinedMinimum = {
|
|
184
|
+
energy: result.energy,
|
|
185
|
+
shape: conformerShape(molecule),
|
|
186
|
+
};
|
|
187
|
+
if (isRefinedDuplicate(candidate, minima, tolerance)) {
|
|
188
|
+
merged++;
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
for (const warning of result.warnings) {
|
|
192
|
+
warnings.push(`The ${ordinal(conformer.id)} conformer: ${warning}`);
|
|
193
|
+
}
|
|
194
|
+
if (!result.converged) {
|
|
195
|
+
warnings.push(
|
|
196
|
+
`The ${ordinal(conformer.id)} conformer did not reach a ${method} minimum in ${result.cycles} cycles, so its refined energy is an upper bound.`,
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
kept.push({
|
|
200
|
+
...conformer,
|
|
201
|
+
molfile: toMolfileExport(molecule),
|
|
202
|
+
refinement: {
|
|
203
|
+
forceFieldId: conformer.id,
|
|
204
|
+
energy: result.energy,
|
|
205
|
+
relativeEnergy: 0,
|
|
206
|
+
dispersionEnergy: result.dispersionEnergy,
|
|
207
|
+
forceFieldEnergy: conformer.energy,
|
|
208
|
+
rmsd: centredRmsd(geometry.coordinates, result.coordinates),
|
|
209
|
+
cycles: result.cycles,
|
|
210
|
+
converged: result.converged,
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
minima.push(candidate);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (merged > 0) {
|
|
217
|
+
warnings.push(
|
|
218
|
+
`${merged} conformer(s) relaxed into a ${method} minimum the set already held, so they were dropped.`,
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
const ranked = rankByRefinedEnergy(kept);
|
|
222
|
+
return {
|
|
223
|
+
...set,
|
|
224
|
+
conformers: ranked.conformers,
|
|
225
|
+
warnings,
|
|
226
|
+
rankedBy: REFINED_RANKING,
|
|
227
|
+
refinement: {
|
|
228
|
+
method,
|
|
229
|
+
elapsedMilliseconds: performance.now() - startedAt,
|
|
230
|
+
merged,
|
|
231
|
+
reordered: ranked.reordered,
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { isSameShape } from './conformerMinimum.ts';
|
|
2
|
+
import type { ConformerShape } from './conformerShape.ts';
|
|
3
|
+
import type { Conformer } from './conformers.ts';
|
|
4
|
+
|
|
5
|
+
/** A refined conformer's energy and shape, which is what tells two minima apart. */
|
|
6
|
+
export interface RefinedMinimum {
|
|
7
|
+
/** Refined total energy, kcal/mol. */
|
|
8
|
+
energy: number;
|
|
9
|
+
shape: ConformerShape;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** A ranked set, and how far it moved from the order it came in. */
|
|
13
|
+
export interface RefinedRanking {
|
|
14
|
+
/** The conformers, most stable first, renumbered from one in that order. */
|
|
15
|
+
conformers: Conformer[];
|
|
16
|
+
/** How many conformers ended up at a different position than they came in at. */
|
|
17
|
+
reordered: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Order refined conformers from the most stable down, number them from one in
|
|
22
|
+
* that order, and measure every refined energy from the lowest.
|
|
23
|
+
*
|
|
24
|
+
* `reordered` counts the conformers whose position changed, which is the number
|
|
25
|
+
* worth showing: it says how much the better method disagreed with the force
|
|
26
|
+
* field.
|
|
27
|
+
* @param conformers - The refined conformers, in the force field's own order.
|
|
28
|
+
* @returns The ranked conformers and the disagreement count.
|
|
29
|
+
*/
|
|
30
|
+
export function rankByRefinedEnergy(
|
|
31
|
+
conformers: readonly Conformer[],
|
|
32
|
+
): RefinedRanking {
|
|
33
|
+
let lowest = Number.POSITIVE_INFINITY;
|
|
34
|
+
for (const conformer of conformers) {
|
|
35
|
+
const energy = conformer.refinement?.energy;
|
|
36
|
+
if (energy !== undefined && energy < lowest) lowest = energy;
|
|
37
|
+
}
|
|
38
|
+
const ranked = conformers.toSorted(compareRefined);
|
|
39
|
+
const result: Conformer[] = [];
|
|
40
|
+
let reordered = 0;
|
|
41
|
+
for (const [index, conformer] of ranked.entries()) {
|
|
42
|
+
if (conformer.id !== index + 1) reordered++;
|
|
43
|
+
const refinement = conformer.refinement;
|
|
44
|
+
result.push({
|
|
45
|
+
...conformer,
|
|
46
|
+
id: index + 1,
|
|
47
|
+
refinement:
|
|
48
|
+
refinement === null
|
|
49
|
+
? null
|
|
50
|
+
: { ...refinement, relativeEnergy: refinement.energy - lowest },
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
return { conformers: result, reordered };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Whether a refined conformer landed in a minimum one of `kept` already holds:
|
|
58
|
+
* the same energy within `tolerance`, and the same shape.
|
|
59
|
+
* @param candidate - The refined conformer's energy and shape.
|
|
60
|
+
* @param kept - The minima kept so far.
|
|
61
|
+
* @param tolerance - Energy gap in kcal/mol under which two energies are one.
|
|
62
|
+
* @returns `true` when one of them is the same minimum.
|
|
63
|
+
*/
|
|
64
|
+
export function isRefinedDuplicate(
|
|
65
|
+
candidate: RefinedMinimum,
|
|
66
|
+
kept: readonly RefinedMinimum[],
|
|
67
|
+
tolerance: number,
|
|
68
|
+
): boolean {
|
|
69
|
+
for (const entry of kept) {
|
|
70
|
+
if (Math.abs(candidate.energy - entry.energy) > tolerance) continue;
|
|
71
|
+
if (isSameShape(candidate.shape, entry.shape)) return true;
|
|
72
|
+
}
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Order two conformers by refined energy; one without a refinement ranks after
|
|
78
|
+
* every one that has one.
|
|
79
|
+
* @param a - One conformer.
|
|
80
|
+
* @param b - The other.
|
|
81
|
+
* @returns Negative when `a` is the more stable, positive when `b` is.
|
|
82
|
+
*/
|
|
83
|
+
function compareRefined(a: Conformer, b: Conformer): number {
|
|
84
|
+
const energyA = a.refinement?.energy;
|
|
85
|
+
const energyB = b.refinement?.energy;
|
|
86
|
+
if (energyA === undefined) return energyB === undefined ? 0 : 1;
|
|
87
|
+
if (energyB === undefined) return -1;
|
|
88
|
+
return energyA - energyB;
|
|
89
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import type { Molecule } from 'openchemlib';
|
|
2
|
+
import { ConformerGenerator } from 'openchemlib';
|
|
3
|
+
|
|
4
|
+
import type {
|
|
5
|
+
ConformerOptions,
|
|
6
|
+
ConformerStrategy,
|
|
7
|
+
} from './conformerOptions.ts';
|
|
8
|
+
|
|
9
|
+
/** A generator, positioned after the conformers it has already handed back. */
|
|
10
|
+
export interface ConformerSession {
|
|
11
|
+
generator: ConformerGenerator;
|
|
12
|
+
/** Conformers handed back so far, kept or dropped. */
|
|
13
|
+
produced: number;
|
|
14
|
+
/**
|
|
15
|
+
* A conformer drawn from the generator but not yet processed, because the
|
|
16
|
+
* deadline passed while it was drawn. Not counted in `produced`.
|
|
17
|
+
*/
|
|
18
|
+
pending: Molecule | null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* A generator for a prepared structure, positioned after `produced` conformers.
|
|
23
|
+
*
|
|
24
|
+
* The generator is seeded, so the same structure and options always hand back
|
|
25
|
+
* the same sequence. The last session is kept, and resumed when it is exactly
|
|
26
|
+
* where the caller left it; otherwise a fresh generator is initialised and the
|
|
27
|
+
* first `produced` conformers are drawn and discarded, which yields the same
|
|
28
|
+
* position without their minimisation.
|
|
29
|
+
* @param prepared - The hydrogen-saturated copy the run embeds.
|
|
30
|
+
* @param options - The options that fixed the sequence: strategy, seed, torsion sets.
|
|
31
|
+
* @param produced - How far into the sequence the caller already is.
|
|
32
|
+
* @returns The session, to be handed back through {@link keepConformerSession}.
|
|
33
|
+
* @throws {Error} When OpenChemLib refuses to initialise the structure.
|
|
34
|
+
*/
|
|
35
|
+
export function openConformerSession(
|
|
36
|
+
prepared: Molecule,
|
|
37
|
+
options: ConformerOptions,
|
|
38
|
+
produced: number,
|
|
39
|
+
): ConformerSession {
|
|
40
|
+
const key = sessionKey(prepared, options);
|
|
41
|
+
if (produced > 0 && last?.key === key && last.session.produced === produced) {
|
|
42
|
+
const session = last.session;
|
|
43
|
+
last = null;
|
|
44
|
+
return session;
|
|
45
|
+
}
|
|
46
|
+
last = null;
|
|
47
|
+
const generator = new ConformerGenerator(options.seed);
|
|
48
|
+
const initialised = generator.initializeConformers(prepared, {
|
|
49
|
+
strategy: strategyConstant(options.strategy),
|
|
50
|
+
maxTorsionSets: options.maxTorsionSets,
|
|
51
|
+
use60degreeSteps: options.use60DegreeSteps,
|
|
52
|
+
});
|
|
53
|
+
if (!initialised) {
|
|
54
|
+
throw new Error(
|
|
55
|
+
`OpenChemLib could not set up conformer generation for ${prepared.getMolecularFormula().formula}. The structure has a problem the generator cannot resolve, such as an impossible valence or an over-constrained ring.`,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
let skipped = 0;
|
|
59
|
+
while (
|
|
60
|
+
skipped < produced &&
|
|
61
|
+
generator.getNextConformerAsMolecule() !== null
|
|
62
|
+
) {
|
|
63
|
+
skipped++;
|
|
64
|
+
}
|
|
65
|
+
return { generator, produced: skipped, pending: null };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Keep a session so the next continuation of the same run resumes it.
|
|
70
|
+
* @param prepared - The structure the session was opened on.
|
|
71
|
+
* @param options - The options it was opened with.
|
|
72
|
+
* @param session - The session, positioned where the run stopped.
|
|
73
|
+
*/
|
|
74
|
+
export function keepConformerSession(
|
|
75
|
+
prepared: Molecule,
|
|
76
|
+
options: ConformerOptions,
|
|
77
|
+
session: ConformerSession,
|
|
78
|
+
): void {
|
|
79
|
+
last = { key: sessionKey(prepared, options), session };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* OpenChemLib's estimate of the conformers a session can reach.
|
|
84
|
+
* @param session - A freshly opened session.
|
|
85
|
+
* @returns The estimate, or `-1` when the generator declines to make one.
|
|
86
|
+
*/
|
|
87
|
+
export function readPotentialCount(session: ConformerSession): number {
|
|
88
|
+
try {
|
|
89
|
+
return session.generator.getPotentialConformerCount();
|
|
90
|
+
} catch {
|
|
91
|
+
return -1;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Map one of our strategy ids onto the `ConformerGenerator` constant it stands
|
|
97
|
+
* for.
|
|
98
|
+
* @param strategy - The id stored in the preferences.
|
|
99
|
+
* @returns The numeric constant OpenChemLib expects.
|
|
100
|
+
*/
|
|
101
|
+
export function strategyConstant(strategy: ConformerStrategy): number {
|
|
102
|
+
return STRATEGY_CONSTANTS[strategy];
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const STRATEGY_CONSTANTS: Record<ConformerStrategy, number> = {
|
|
106
|
+
'adaptive-random': ConformerGenerator.STRATEGY_ADAPTIVE_RANDOM,
|
|
107
|
+
'likely-random': ConformerGenerator.STRATEGY_LIKELY_RANDOM,
|
|
108
|
+
'pure-random': ConformerGenerator.STRATEGY_PURE_RANDOM,
|
|
109
|
+
'likely-systematic': ConformerGenerator.STRATEGY_LIKELY_SYSTEMATIC,
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
let last: { key: string; session: ConformerSession } | null = null;
|
|
113
|
+
|
|
114
|
+
// The atom order matters as much as the structure, so the molfile is the key.
|
|
115
|
+
function sessionKey(prepared: Molecule, options: ConformerOptions): string {
|
|
116
|
+
return [
|
|
117
|
+
options.strategy,
|
|
118
|
+
options.seed,
|
|
119
|
+
options.maxTorsionSets,
|
|
120
|
+
options.use60DegreeSteps,
|
|
121
|
+
prepared.toMolfileV3(),
|
|
122
|
+
].join('\n');
|
|
123
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import type { Molecule } from 'openchemlib';
|
|
2
|
+
|
|
3
|
+
/** Principal second moments of a conformer's atoms, in increasing order. */
|
|
4
|
+
export type PrincipalMoments = readonly [number, number, number];
|
|
5
|
+
|
|
6
|
+
/** What tells two minimised conformers of one energy apart. */
|
|
7
|
+
export interface ConformerShape {
|
|
8
|
+
/** Principal second moments, smallest first. */
|
|
9
|
+
moments: PrincipalMoments;
|
|
10
|
+
/** Handedness in [-1, 1]: opposite for mirror images, 0 for a shape that is its own mirror image. */
|
|
11
|
+
chirality: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Shape of a conformer: the principal second moments of its atoms, weighted by
|
|
16
|
+
* atomic number, about their weighted centre, and the handedness of the atoms
|
|
17
|
+
* in that principal frame.
|
|
18
|
+
*
|
|
19
|
+
* Neither changes when the conformer is turned or has its symmetry-equivalent
|
|
20
|
+
* atoms numbered differently, which is how the generator hands back the same
|
|
21
|
+
* minimum twice, as with a cyclohexane chair and its flipped copy. A mirror
|
|
22
|
+
* image keeps the moments and flips the sign of the chirality, so gauche butane
|
|
23
|
+
* and its mirror image share the one and not the other.
|
|
24
|
+
*
|
|
25
|
+
* The chirality is Σ w·u₁u₂u₃ over Σ w·|u₁u₂u₃|, u being the coordinates along
|
|
26
|
+
* right-handed principal axes. A mirror plane or an inversion centre makes it
|
|
27
|
+
* vanish. It is 0 as well for a flat conformer, and when the principal axes
|
|
28
|
+
* cannot be drawn.
|
|
29
|
+
* @param molecule - A conformer with 3D coordinates.
|
|
30
|
+
* @returns Its moments, smallest first, and its chirality.
|
|
31
|
+
*/
|
|
32
|
+
export function conformerShape(molecule: Molecule): ConformerShape {
|
|
33
|
+
const atomCount = molecule.getAllAtoms();
|
|
34
|
+
let total = 0;
|
|
35
|
+
let centreX = 0;
|
|
36
|
+
let centreY = 0;
|
|
37
|
+
let centreZ = 0;
|
|
38
|
+
for (let atom = 0; atom < atomCount; atom++) {
|
|
39
|
+
const weight = molecule.getAtomicNo(atom);
|
|
40
|
+
total += weight;
|
|
41
|
+
centreX += weight * molecule.getAtomX(atom);
|
|
42
|
+
centreY += weight * molecule.getAtomY(atom);
|
|
43
|
+
centreZ += weight * molecule.getAtomZ(atom);
|
|
44
|
+
}
|
|
45
|
+
if (total === 0) return { moments: [0, 0, 0], chirality: 0 };
|
|
46
|
+
centreX /= total;
|
|
47
|
+
centreY /= total;
|
|
48
|
+
centreZ /= total;
|
|
49
|
+
const tensor: Tensor = { xx: 0, yy: 0, zz: 0, xy: 0, xz: 0, yz: 0 };
|
|
50
|
+
for (let atom = 0; atom < atomCount; atom++) {
|
|
51
|
+
const weight = molecule.getAtomicNo(atom);
|
|
52
|
+
const x = molecule.getAtomX(atom) - centreX;
|
|
53
|
+
const y = molecule.getAtomY(atom) - centreY;
|
|
54
|
+
const z = molecule.getAtomZ(atom) - centreZ;
|
|
55
|
+
tensor.xx += weight * x * x;
|
|
56
|
+
tensor.yy += weight * y * y;
|
|
57
|
+
tensor.zz += weight * z * z;
|
|
58
|
+
tensor.xy += weight * x * y;
|
|
59
|
+
tensor.xz += weight * x * z;
|
|
60
|
+
tensor.yz += weight * y * z;
|
|
61
|
+
}
|
|
62
|
+
const moments = symmetricEigenvalues(tensor);
|
|
63
|
+
const first = principalAxis(tensor, moments[0]);
|
|
64
|
+
const third = principalAxis(tensor, moments[2]);
|
|
65
|
+
if (first === null || third === null) return { moments, chirality: 0 };
|
|
66
|
+
const second = cross(third, first);
|
|
67
|
+
|
|
68
|
+
let signed = 0;
|
|
69
|
+
let absolute = 0;
|
|
70
|
+
for (let atom = 0; atom < atomCount; atom++) {
|
|
71
|
+
const weight = molecule.getAtomicNo(atom);
|
|
72
|
+
const x = molecule.getAtomX(atom) - centreX;
|
|
73
|
+
const y = molecule.getAtomY(atom) - centreY;
|
|
74
|
+
const z = molecule.getAtomZ(atom) - centreZ;
|
|
75
|
+
const product =
|
|
76
|
+
(x * first[0] + y * first[1] + z * first[2]) *
|
|
77
|
+
(x * second[0] + y * second[1] + z * second[2]) *
|
|
78
|
+
(x * third[0] + y * third[1] + z * third[2]);
|
|
79
|
+
signed += weight * product;
|
|
80
|
+
absolute += weight * Math.abs(product);
|
|
81
|
+
}
|
|
82
|
+
const radius = Math.sqrt((moments[0] + moments[1] + moments[2]) / total);
|
|
83
|
+
if (absolute <= FLAT_TOLERANCE * total * radius * radius * radius) {
|
|
84
|
+
return { moments, chirality: 0 };
|
|
85
|
+
}
|
|
86
|
+
return { moments, chirality: signed / absolute };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Whether every atom of a conformer sits at finite coordinates.
|
|
91
|
+
* @param conformer - A conformer with 3D coordinates.
|
|
92
|
+
* @returns `false` as soon as one coordinate is `NaN` or infinite.
|
|
93
|
+
*/
|
|
94
|
+
export function hasFiniteCoordinates(conformer: Molecule): boolean {
|
|
95
|
+
const atomCount = conformer.getAllAtoms();
|
|
96
|
+
for (let atom = 0; atom < atomCount; atom++) {
|
|
97
|
+
if (
|
|
98
|
+
!Number.isFinite(conformer.getAtomX(atom)) ||
|
|
99
|
+
!Number.isFinite(conformer.getAtomY(atom)) ||
|
|
100
|
+
!Number.isFinite(conformer.getAtomZ(atom))
|
|
101
|
+
) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Σ w·|u₁u₂u₃|, relative to the total weight times the cubed radius of
|
|
110
|
+
* gyration, under which a conformer is flat: its handedness is rounding noise.
|
|
111
|
+
*/
|
|
112
|
+
const FLAT_TOLERANCE = 1e-4;
|
|
113
|
+
|
|
114
|
+
type Vector = readonly [number, number, number];
|
|
115
|
+
|
|
116
|
+
/** Second moments of the atoms about their centre: a symmetric 3×3 matrix. */
|
|
117
|
+
interface Tensor {
|
|
118
|
+
xx: number;
|
|
119
|
+
yy: number;
|
|
120
|
+
zz: number;
|
|
121
|
+
xy: number;
|
|
122
|
+
xz: number;
|
|
123
|
+
yz: number;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Unit eigenvector of `moment`: the longest cross product of two rows of the tensor minus `moment`.
|
|
127
|
+
function principalAxis(tensor: Tensor, moment: number): Vector | null {
|
|
128
|
+
const rows: Vector[] = [
|
|
129
|
+
[tensor.xx - moment, tensor.xy, tensor.xz],
|
|
130
|
+
[tensor.xy, tensor.yy - moment, tensor.yz],
|
|
131
|
+
[tensor.xz, tensor.yz, tensor.zz - moment],
|
|
132
|
+
];
|
|
133
|
+
let best: Vector = [0, 0, 0];
|
|
134
|
+
let bestLength = 0;
|
|
135
|
+
for (let a = 0; a < 3; a++) {
|
|
136
|
+
for (let b = a + 1; b < 3; b++) {
|
|
137
|
+
const candidate = cross(rows[a] as Vector, rows[b] as Vector);
|
|
138
|
+
const length = Math.hypot(candidate[0], candidate[1], candidate[2]);
|
|
139
|
+
if (length > bestLength) {
|
|
140
|
+
best = candidate;
|
|
141
|
+
bestLength = length;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (bestLength === 0) return null;
|
|
146
|
+
return [best[0] / bestLength, best[1] / bestLength, best[2] / bestLength];
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function cross(a: Vector, b: Vector): Vector {
|
|
150
|
+
return [
|
|
151
|
+
a[1] * b[2] - a[2] * b[1],
|
|
152
|
+
a[2] * b[0] - a[0] * b[2],
|
|
153
|
+
a[0] * b[1] - a[1] * b[0],
|
|
154
|
+
];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Closed-form eigenvalues of a symmetric 3×3 matrix (Smith, 1961).
|
|
158
|
+
function symmetricEigenvalues(tensor: Tensor): PrincipalMoments {
|
|
159
|
+
const { xx, yy, zz, xy, xz, yz } = tensor;
|
|
160
|
+
const mean = (xx + yy + zz) / 3;
|
|
161
|
+
const offDiagonal = xy * xy + xz * xz + yz * yz;
|
|
162
|
+
const spread =
|
|
163
|
+
(xx - mean) * (xx - mean) +
|
|
164
|
+
(yy - mean) * (yy - mean) +
|
|
165
|
+
(zz - mean) * (zz - mean) +
|
|
166
|
+
2 * offDiagonal;
|
|
167
|
+
if (spread === 0) return [mean, mean, mean];
|
|
168
|
+
const p = Math.sqrt(spread / 6);
|
|
169
|
+
const a = (xx - mean) / p;
|
|
170
|
+
const b = (yy - mean) / p;
|
|
171
|
+
const c = (zz - mean) / p;
|
|
172
|
+
const d = xy / p;
|
|
173
|
+
const e = xz / p;
|
|
174
|
+
const f = yz / p;
|
|
175
|
+
const halfDeterminant =
|
|
176
|
+
(a * (b * c - f * f) - d * (d * c - f * e) + e * (d * f - b * e)) / 2;
|
|
177
|
+
const angle = Math.acos(Math.min(1, Math.max(-1, halfDeterminant))) / 3;
|
|
178
|
+
const largest = mean + 2 * p * Math.cos(angle);
|
|
179
|
+
const smallest = mean + 2 * p * Math.cos(angle + (2 * Math.PI) / 3);
|
|
180
|
+
return [smallest, 3 * mean - largest - smallest, largest];
|
|
181
|
+
}
|